User verification state indicators (#3793)

* Introduce a `UserIdentityProxy` and have it combine upstream methods into an easy to digest  `UserIdentityVerificationState`. Use it in a dedicated `VerificationBadge` UI component

* Show a DMs counterpart verification state in the room header

* Show a warning on the room details `People` entry when there are identity verification state violations on any of the members.

* Show verification badges in the room member list

* Show a withdraw verification section on the room member details for users that have pinning violations.

* Remove the verification section from the profile screen as there's no reliable way to keep it up to date
- the underlying Rust SDK Olm Machine can be rebuilt without notice which would break any existing user identity change streams.

* Update preview test snapshots
This commit is contained in:
Stefan Ceriu
2025-02-18 08:37:34 +02:00
committed by GitHub
parent b71c93dfaa
commit f77faee981
101 changed files with 722 additions and 305 deletions
@@ -31,6 +31,7 @@ enum RoomScreenViewAction {
struct RoomScreenViewState: BindableState {
var roomTitle = ""
var roomAvatar: RoomAvatar
var dmRecipientVerificationState: UserIdentityVerificationState?
var lastScrollDirection: ScrollDirection?
// This is used to control the banner
@@ -77,6 +77,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
Task {
await handleRoomInfoUpdate(roomProxy.infoPublisher.value)
await updateVerificationBadge()
}
setupSubscriptions(ongoingCallRoomIDPublisher: ongoingCallRoomIDPublisher)
@@ -182,6 +184,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
await self?.processIdentityStatusChanges(changes)
await self?.updateVerificationBadge()
}
}
.store(in: &cancellables)
@@ -262,6 +265,23 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
}
private func updateVerificationBadge() async {
guard roomProxy.isDirectOneToOneRoom,
let dmRecipient = roomProxy.membersPublisher.value.first(where: { $0.userID != roomProxy.ownUserID }),
case let .success(userIdentity) = await clientProxy.userIdentity(for: dmRecipient.userID) else {
state.dmRecipientVerificationState = .notVerified
return
}
guard let userIdentity else {
MXLog.failure("User identity should be known at this point")
state.dmRecipientVerificationState = .notVerified
return
}
state.dmRecipientVerificationState = userIdentity.verificationState
}
private func resolveIdentityPinningViolation(_ userID: String) async {
defer {
hideLoadingIndicator()
@@ -204,6 +204,7 @@ struct RoomScreen: View {
ToolbarItem(placement: .principal) {
RoomHeaderView(roomName: roomContext.viewState.roomTitle,
roomAvatar: roomContext.viewState.roomAvatar,
dmRecipientVerificationState: roomContext.viewState.dmRecipientVerificationState,
mediaProvider: roomContext.mediaProvider)
// Using a button stops it from getting truncated in the navigation bar
.contentShape(.rect)