mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
Add support for initiating and responding to user verification requests (#3759)
This commit is contained in:
parent
22d0fae423
commit
8680d8437b
@ -8509,7 +8509,7 @@
|
||||
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 25.02.06;
|
||||
version = 25.02.07;
|
||||
};
|
||||
};
|
||||
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
|
||||
|
@ -149,8 +149,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
|
||||
"state" : {
|
||||
"revision" : "355364952fdd14a3e26b317180af89c79f9e03a5",
|
||||
"version" : "25.2.6"
|
||||
"revision" : "bc819f09ac66bbe1adc2fde2afeb7ab023d1b909",
|
||||
"version" : "25.2.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -278,7 +278,9 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
|
||||
let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController,
|
||||
flow: .initiator)
|
||||
flow: .deviceInitiator,
|
||||
appSettings: appSettings,
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
let coordinator = SessionVerificationScreenCoordinator(parameters: parameters)
|
||||
|
||||
|
@ -12,6 +12,7 @@ import UserNotifications
|
||||
|
||||
enum RoomFlowCoordinatorAction: Equatable {
|
||||
case presentCallScreen(roomProxy: JoinedRoomProxyProtocol)
|
||||
case verifyUser(userID: String)
|
||||
case finished
|
||||
|
||||
static func == (lhs: RoomFlowCoordinatorAction, rhs: RoomFlowCoordinatorAction) -> Bool {
|
||||
@ -1247,6 +1248,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
stateMachine.tryEvent(.startChildFlow(roomID: roomID, via: [], entryPoint: .room))
|
||||
case .startCall(let roomID):
|
||||
Task { await self.presentCallScreen(roomID: roomID) }
|
||||
case .verifyUser(let userID):
|
||||
actionsSubject.send(.verifyUser(userID: userID))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
@ -1272,6 +1275,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
stateMachine.tryEvent(.startChildFlow(roomID: roomID, via: [], entryPoint: .room))
|
||||
case .startCall(let roomID):
|
||||
Task { await self.presentCallScreen(roomID: roomID) }
|
||||
case .verifyUser(let userID):
|
||||
actionsSubject.send(.verifyUser(userID: userID))
|
||||
case .dismiss:
|
||||
break // Not supported when pushed.
|
||||
}
|
||||
@ -1530,6 +1535,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
switch action {
|
||||
case .presentCallScreen(let roomProxy):
|
||||
actionsSubject.send(.presentCallScreen(roomProxy: roomProxy))
|
||||
case .verifyUser(let userID):
|
||||
actionsSubject.send(.verifyUser(userID: userID))
|
||||
case .finished:
|
||||
stateMachine.tryEvent(.dismissChildFlow)
|
||||
}
|
||||
|
@ -440,18 +440,26 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
MXLog.info("Received session verification request")
|
||||
|
||||
presentSessionVerificationScreen(details: details)
|
||||
if details.senderProfile.userID == userSession.clientProxy.userID {
|
||||
presentSessionVerificationScreen(flow: .deviceResponder(requestDetails: details))
|
||||
} else {
|
||||
presentSessionVerificationScreen(flow: .userResponder(requestDetails: details))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func presentSessionVerificationScreen(details: SessionVerificationRequestDetails) {
|
||||
private func presentSessionVerificationScreen(flow: SessionVerificationScreenFlow) {
|
||||
guard let sessionVerificationController = userSession.clientProxy.sessionVerificationController else {
|
||||
fatalError("The sessionVerificationController should aways be valid at this point")
|
||||
}
|
||||
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
|
||||
let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController,
|
||||
flow: .responder(details: details))
|
||||
flow: flow,
|
||||
appSettings: appSettings,
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
let coordinator = SessionVerificationScreenCoordinator(parameters: parameters)
|
||||
|
||||
@ -464,7 +472,9 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(coordinator)
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(navigationStackCoordinator)
|
||||
}
|
||||
|
||||
private func presentHomeScreen() {
|
||||
@ -590,6 +600,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case .presentCallScreen(let roomProxy):
|
||||
// Here we assume that the app is running and the call state is already up to date
|
||||
presentCallScreen(roomProxy: roomProxy, notifyOtherParticipants: !roomProxy.infoPublisher.value.hasRoomCall)
|
||||
case .verifyUser(let userID):
|
||||
presentSessionVerificationScreen(flow: .userIntiator(userID: userID))
|
||||
case .finished:
|
||||
stateMachine.processEvent(.deselectRoom)
|
||||
}
|
||||
@ -911,6 +923,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
stateMachine.processEvent(.selectRoom(roomID: roomID, via: [], entryPoint: .room))
|
||||
case .startCall(let roomID):
|
||||
Task { await self.presentCallScreen(roomID: roomID, notifyOtherParticipants: false) }
|
||||
case .verifyUser(let userID):
|
||||
presentSessionVerificationScreen(flow: .userIntiator(userID: userID))
|
||||
case .dismiss:
|
||||
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
}
|
||||
|
@ -14105,17 +14105,17 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy
|
||||
return acceptVerificationRequestReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - requestVerification
|
||||
//MARK: - requestDeviceVerification
|
||||
|
||||
var requestVerificationUnderlyingCallsCount = 0
|
||||
var requestVerificationCallsCount: Int {
|
||||
var requestDeviceVerificationUnderlyingCallsCount = 0
|
||||
var requestDeviceVerificationCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return requestVerificationUnderlyingCallsCount
|
||||
return requestDeviceVerificationUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = requestVerificationUnderlyingCallsCount
|
||||
returnValue = requestDeviceVerificationUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
@ -14123,27 +14123,27 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
requestVerificationUnderlyingCallsCount = newValue
|
||||
requestDeviceVerificationUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
requestVerificationUnderlyingCallsCount = newValue
|
||||
requestDeviceVerificationUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var requestVerificationCalled: Bool {
|
||||
return requestVerificationCallsCount > 0
|
||||
var requestDeviceVerificationCalled: Bool {
|
||||
return requestDeviceVerificationCallsCount > 0
|
||||
}
|
||||
|
||||
var requestVerificationUnderlyingReturnValue: Result<Void, SessionVerificationControllerProxyError>!
|
||||
var requestVerificationReturnValue: Result<Void, SessionVerificationControllerProxyError>! {
|
||||
var requestDeviceVerificationUnderlyingReturnValue: Result<Void, SessionVerificationControllerProxyError>!
|
||||
var requestDeviceVerificationReturnValue: Result<Void, SessionVerificationControllerProxyError>! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return requestVerificationUnderlyingReturnValue
|
||||
return requestDeviceVerificationUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: Result<Void, SessionVerificationControllerProxyError>? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = requestVerificationUnderlyingReturnValue
|
||||
returnValue = requestDeviceVerificationUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
@ -14151,22 +14151,92 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
requestVerificationUnderlyingReturnValue = newValue
|
||||
requestDeviceVerificationUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
requestVerificationUnderlyingReturnValue = newValue
|
||||
requestDeviceVerificationUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var requestVerificationClosure: (() async -> Result<Void, SessionVerificationControllerProxyError>)?
|
||||
var requestDeviceVerificationClosure: (() async -> Result<Void, SessionVerificationControllerProxyError>)?
|
||||
|
||||
func requestVerification() async -> Result<Void, SessionVerificationControllerProxyError> {
|
||||
requestVerificationCallsCount += 1
|
||||
if let requestVerificationClosure = requestVerificationClosure {
|
||||
return await requestVerificationClosure()
|
||||
func requestDeviceVerification() async -> Result<Void, SessionVerificationControllerProxyError> {
|
||||
requestDeviceVerificationCallsCount += 1
|
||||
if let requestDeviceVerificationClosure = requestDeviceVerificationClosure {
|
||||
return await requestDeviceVerificationClosure()
|
||||
} else {
|
||||
return requestVerificationReturnValue
|
||||
return requestDeviceVerificationReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - requestUserVerification
|
||||
|
||||
var requestUserVerificationUnderlyingCallsCount = 0
|
||||
var requestUserVerificationCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return requestUserVerificationUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = requestUserVerificationUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
requestUserVerificationUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
requestUserVerificationUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var requestUserVerificationCalled: Bool {
|
||||
return requestUserVerificationCallsCount > 0
|
||||
}
|
||||
var requestUserVerificationReceivedUserID: String?
|
||||
var requestUserVerificationReceivedInvocations: [String] = []
|
||||
|
||||
var requestUserVerificationUnderlyingReturnValue: Result<Void, SessionVerificationControllerProxyError>!
|
||||
var requestUserVerificationReturnValue: Result<Void, SessionVerificationControllerProxyError>! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return requestUserVerificationUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: Result<Void, SessionVerificationControllerProxyError>? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = requestUserVerificationUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
requestUserVerificationUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
requestUserVerificationUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var requestUserVerificationClosure: ((String) async -> Result<Void, SessionVerificationControllerProxyError>)?
|
||||
|
||||
func requestUserVerification(_ userID: String) async -> Result<Void, SessionVerificationControllerProxyError> {
|
||||
requestUserVerificationCallsCount += 1
|
||||
requestUserVerificationReceivedUserID = userID
|
||||
DispatchQueue.main.async {
|
||||
self.requestUserVerificationReceivedInvocations.append(userID)
|
||||
}
|
||||
if let requestUserVerificationClosure = requestUserVerificationClosure {
|
||||
return await requestUserVerificationClosure(userID)
|
||||
} else {
|
||||
return requestUserVerificationReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - startSasVerification
|
||||
|
@ -24,7 +24,7 @@ extension SessionVerificationControllerProxyMock {
|
||||
|
||||
mock.acknowledgeVerificationRequestDetailsReturnValue = .success(())
|
||||
|
||||
mock.requestVerificationClosure = { [unowned mock] in
|
||||
mock.requestDeviceVerificationClosure = { [unowned mock] in
|
||||
Task.detached {
|
||||
try await Task.sleep(for: requestDelay)
|
||||
mock.actions.send(.acceptedVerificationRequest)
|
||||
|
@ -77,6 +77,7 @@ enum UserAvatarSizeOnScreen {
|
||||
case knockingUserList
|
||||
case mediaPreviewDetails
|
||||
case sendInviteConfirmation
|
||||
case sessionVerification
|
||||
|
||||
var value: CGFloat {
|
||||
switch self {
|
||||
@ -116,6 +117,8 @@ enum UserAvatarSizeOnScreen {
|
||||
return 32
|
||||
case .sendInviteConfirmation:
|
||||
return 64
|
||||
case .sessionVerification:
|
||||
return 52
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,13 +14,26 @@ enum SessionVerificationScreenCoordinatorAction {
|
||||
}
|
||||
|
||||
enum SessionVerificationScreenFlow {
|
||||
case initiator
|
||||
case responder(details: SessionVerificationRequestDetails)
|
||||
case deviceInitiator
|
||||
case deviceResponder(requestDetails: SessionVerificationRequestDetails)
|
||||
case userIntiator(userID: String)
|
||||
case userResponder(requestDetails: SessionVerificationRequestDetails)
|
||||
|
||||
var isResponder: Bool {
|
||||
switch self {
|
||||
case .deviceInitiator, .userIntiator:
|
||||
false
|
||||
case .deviceResponder, .userResponder:
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SessionVerificationScreenCoordinatorParameters {
|
||||
let sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol
|
||||
let flow: SessionVerificationScreenFlow
|
||||
let appSettings: AppSettings
|
||||
let mediaProvider: MediaProviderProtocol
|
||||
}
|
||||
|
||||
final class SessionVerificationScreenCoordinator: CoordinatorProtocol {
|
||||
@ -35,7 +48,9 @@ final class SessionVerificationScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
init(parameters: SessionVerificationScreenCoordinatorParameters) {
|
||||
viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: parameters.sessionVerificationControllerProxy,
|
||||
flow: parameters.flow)
|
||||
flow: parameters.flow,
|
||||
appSettings: parameters.appSettings,
|
||||
mediaProvider: parameters.mediaProvider)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
@ -20,17 +20,25 @@ enum SessionVerificationScreenViewAction {
|
||||
case restart
|
||||
case accept
|
||||
case decline
|
||||
case cancel
|
||||
case done
|
||||
}
|
||||
|
||||
struct SessionVerificationScreenViewState: BindableState {
|
||||
let flow: SessionVerificationScreenFlow
|
||||
let learnMoreURL: URL
|
||||
|
||||
var verificationState: SessionVerificationScreenStateMachine.State
|
||||
|
||||
var headerIcon: (keyPath: KeyPath<CompoundIcons, Image>, style: BigIcon.Style) {
|
||||
switch verificationState {
|
||||
case .initial:
|
||||
return (\.devices, .defaultSolid)
|
||||
switch flow {
|
||||
case .deviceInitiator, .deviceResponder:
|
||||
return (\.devices, .defaultSolid)
|
||||
case .userIntiator, .userResponder:
|
||||
return (\.userProfileSolid, .defaultSolid)
|
||||
}
|
||||
case .acceptingVerificationRequest:
|
||||
return (\.devices, .defaultSolid)
|
||||
case .requestingVerification:
|
||||
@ -56,25 +64,31 @@ struct SessionVerificationScreenViewState: BindableState {
|
||||
}
|
||||
}
|
||||
|
||||
var titleAccessibilityIdentifier: String {
|
||||
verificationState == .verified ? A11yIdentifiers.sessionVerificationScreen.verificationComplete : ""
|
||||
}
|
||||
|
||||
var title: String? {
|
||||
switch verificationState {
|
||||
case .initial:
|
||||
switch flow {
|
||||
case .initiator:
|
||||
case .deviceInitiator:
|
||||
return L10n.screenSessionVerificationUseAnotherDeviceTitle
|
||||
case .responder:
|
||||
case .userIntiator:
|
||||
return L10n.screenSessionVerificationUserInitiatorTitle
|
||||
case .deviceResponder, .userResponder:
|
||||
return L10n.screenSessionVerificationRequestTitle
|
||||
}
|
||||
case .acceptingVerificationRequest:
|
||||
return L10n.screenSessionVerificationWaitingAnotherDeviceTitle
|
||||
return waitingTitle
|
||||
case .requestingVerification:
|
||||
return L10n.screenSessionVerificationWaitingToAcceptTitle
|
||||
return waitingTitle
|
||||
case .verificationRequestAccepted:
|
||||
return L10n.screenSessionVerificationCompareEmojisTitle
|
||||
case .startingSasVerification:
|
||||
return nil
|
||||
return waitingTitle
|
||||
case .sasVerificationStarted:
|
||||
return nil
|
||||
return waitingTitle
|
||||
case .showingChallenge:
|
||||
return L10n.screenSessionVerificationCompareEmojisTitle
|
||||
case .acceptingChallenge:
|
||||
@ -84,47 +98,71 @@ struct SessionVerificationScreenViewState: BindableState {
|
||||
case .verified:
|
||||
return L10n.commonVerificationComplete
|
||||
case .cancelling:
|
||||
return nil
|
||||
return waitingTitle
|
||||
case .cancelled:
|
||||
return L10n.commonVerificationFailed
|
||||
}
|
||||
}
|
||||
|
||||
var titleAccessibilityIdentifier: String {
|
||||
verificationState == .verified ? A11yIdentifiers.sessionVerificationScreen.verificationComplete : ""
|
||||
private var waitingTitle: String {
|
||||
switch flow {
|
||||
case .deviceInitiator, .deviceResponder:
|
||||
return L10n.screenSessionVerificationWaitingOtherDeviceTitle
|
||||
case .userIntiator, .userResponder:
|
||||
return L10n.screenSessionVerificationWaitingOtherUserTitle
|
||||
}
|
||||
}
|
||||
|
||||
var message: String {
|
||||
switch verificationState {
|
||||
case .initial:
|
||||
switch flow {
|
||||
case .initiator:
|
||||
case .deviceInitiator:
|
||||
return L10n.screenSessionVerificationUseAnotherDeviceSubtitle
|
||||
case .responder:
|
||||
case .userIntiator:
|
||||
return L10n.screenSessionVerificationUserInitiatorSubtitle
|
||||
case .deviceResponder:
|
||||
return L10n.screenSessionVerificationRequestSubtitle
|
||||
case .userResponder:
|
||||
return L10n.screenSessionVerificationUserResponderSubtitle
|
||||
}
|
||||
case .acceptingVerificationRequest:
|
||||
return L10n.screenSessionVerificationWaitingAnotherDeviceSubtitle
|
||||
return waitingMessage
|
||||
case .requestingVerification:
|
||||
return L10n.screenSessionVerificationWaitingToAcceptSubtitle
|
||||
return waitingMessage
|
||||
case .verificationRequestAccepted:
|
||||
return L10n.screenSessionVerificationRequestAcceptedSubtitle
|
||||
case .startingSasVerification:
|
||||
return L10n.commonWaiting
|
||||
return waitingMessage
|
||||
case .sasVerificationStarted:
|
||||
return L10n.commonWaiting
|
||||
return waitingMessage
|
||||
case .acceptingChallenge:
|
||||
return L10n.screenSessionVerificationCompareEmojisSubtitle
|
||||
case .decliningChallenge:
|
||||
return L10n.screenSessionVerificationCompareEmojisSubtitle
|
||||
case .cancelling:
|
||||
return L10n.commonWaiting
|
||||
return waitingMessage
|
||||
case .showingChallenge:
|
||||
return L10n.screenSessionVerificationCompareEmojisSubtitle
|
||||
switch flow {
|
||||
case .deviceInitiator, .deviceResponder:
|
||||
return L10n.screenSessionVerificationCompareEmojisSubtitle
|
||||
case .userIntiator, .userResponder:
|
||||
return L10n.screenSessionVerificationCompareEmojisUserSubtitle
|
||||
}
|
||||
case .verified:
|
||||
return L10n.screenSessionVerificationCompleteSubtitle
|
||||
switch flow {
|
||||
case .deviceInitiator, .deviceResponder:
|
||||
return L10n.screenSessionVerificationCompleteSubtitle
|
||||
case .userIntiator, .userResponder:
|
||||
return L10n.screenSessionVerificationCompleteUserSubtitle
|
||||
}
|
||||
|
||||
case .cancelled:
|
||||
return L10n.screenSessionVerificationFailedSubtitle
|
||||
}
|
||||
}
|
||||
|
||||
private var waitingMessage: String {
|
||||
L10n.screenSessionVerificationWaitingSubtitle
|
||||
}
|
||||
}
|
||||
|
@ -24,13 +24,18 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess
|
||||
|
||||
init(sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol,
|
||||
flow: SessionVerificationScreenFlow,
|
||||
appSettings: AppSettings,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
verificationState: SessionVerificationScreenStateMachine.State = .initial) {
|
||||
self.sessionVerificationControllerProxy = sessionVerificationControllerProxy
|
||||
self.flow = flow
|
||||
|
||||
stateMachine = SessionVerificationScreenStateMachine(state: verificationState)
|
||||
|
||||
super.init(initialViewState: .init(flow: flow, verificationState: verificationState))
|
||||
super.init(initialViewState: .init(flow: flow,
|
||||
learnMoreURL: appSettings.encryptionURL,
|
||||
verificationState: verificationState),
|
||||
mediaProvider: mediaProvider)
|
||||
|
||||
setupStateMachine()
|
||||
|
||||
@ -63,10 +68,13 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
if case .responder(let details) = flow {
|
||||
switch flow {
|
||||
case .deviceResponder(let details), .userResponder(let details):
|
||||
Task {
|
||||
await self.sessionVerificationControllerProxy.acknowledgeVerificationRequest(details: details)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,6 +94,9 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess
|
||||
stateMachine.processEvent(.acceptChallenge)
|
||||
case .decline:
|
||||
stateMachine.processEvent(.declineChallenge)
|
||||
case .cancel:
|
||||
stateMachine.processEvent(.cancel)
|
||||
actionsSubject.send(.finished)
|
||||
case .done:
|
||||
actionsSubject.send(.finished)
|
||||
}
|
||||
@ -112,7 +123,15 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess
|
||||
case (.initial, .acceptVerificationRequest, .acceptingVerificationRequest):
|
||||
acceptVerificationRequest()
|
||||
case (.initial, .requestVerification, .requestingVerification):
|
||||
requestVerification()
|
||||
Task {
|
||||
switch await self.requestVerification() {
|
||||
case .success:
|
||||
// Need to wait for the callback from the remote
|
||||
break
|
||||
case .failure:
|
||||
self.stateMachine.processEvent(.didFail)
|
||||
}
|
||||
}
|
||||
case (.verificationRequestAccepted, .startSasVerification, .startingSasVerification):
|
||||
startSasVerification()
|
||||
case (.showingChallenge, .acceptChallenge, .acceptingChallenge):
|
||||
@ -124,8 +143,11 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess
|
||||
case (_, _, .verified):
|
||||
actionsSubject.send(.finished)
|
||||
case (.initial, _, .cancelled):
|
||||
if case .responder = flow {
|
||||
switch flow {
|
||||
case .deviceResponder, .userResponder:
|
||||
actionsSubject.send(.finished)
|
||||
default:
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -139,7 +161,7 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess
|
||||
|
||||
private func acceptVerificationRequest() {
|
||||
Task {
|
||||
guard case .responder = flow else {
|
||||
guard flow.isResponder else {
|
||||
fatalError("Incorrect API usage.")
|
||||
}
|
||||
|
||||
@ -152,15 +174,14 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess
|
||||
}
|
||||
}
|
||||
|
||||
private func requestVerification() {
|
||||
Task {
|
||||
switch await sessionVerificationControllerProxy.requestVerification() {
|
||||
case .success:
|
||||
// Need to wait for the callback from the remote
|
||||
break
|
||||
case .failure:
|
||||
stateMachine.processEvent(.didFail)
|
||||
}
|
||||
private func requestVerification() async -> Result<Void, SessionVerificationControllerProxyError> {
|
||||
switch flow {
|
||||
case .deviceInitiator:
|
||||
return await sessionVerificationControllerProxy.requestDeviceVerification()
|
||||
case .userIntiator(let userID):
|
||||
return await sessionVerificationControllerProxy.requestUserVerification(userID)
|
||||
default:
|
||||
fatalError("Incorrect API usage.")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,44 @@ struct SessionVerificationRequestDetailsView: View {
|
||||
private let outerShape = RoundedRectangle(cornerRadius: 8)
|
||||
|
||||
let details: SessionVerificationRequestDetails
|
||||
let isUserVerification: Bool
|
||||
let mediaProvider: MediaProviderProtocol?
|
||||
|
||||
var body: some View {
|
||||
if isUserVerification {
|
||||
userRequestDetails
|
||||
} else {
|
||||
deviceRequestDetails
|
||||
}
|
||||
}
|
||||
|
||||
private var userRequestDetails: some View {
|
||||
HStack(spacing: 12) {
|
||||
LoadableAvatarImage(url: details.senderProfile.avatarURL,
|
||||
name: details.senderProfile.displayName,
|
||||
contentID: details.senderProfile.userID,
|
||||
avatarSize: .user(on: .sessionVerification),
|
||||
mediaProvider: mediaProvider)
|
||||
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text(details.senderProfile.displayName ?? details.senderProfile.userID)
|
||||
.font(.compound.bodySM)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
|
||||
if details.senderProfile.displayName != nil {
|
||||
Text(details.senderProfile.userID)
|
||||
.font(.compound.bodyMD)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(12)
|
||||
.background(.compound.bgSubtleSecondary)
|
||||
.clipShape(outerShape)
|
||||
}
|
||||
|
||||
private var deviceRequestDetails: some View {
|
||||
VStack(spacing: 24) {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack(spacing: 16) {
|
||||
@ -26,7 +62,8 @@ struct SessionVerificationRequestDetailsView: View {
|
||||
.background(.compound.bgSubtleSecondary)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
|
||||
Text(details.displayName ?? details.senderID)
|
||||
let displayName = isUserVerification ? details.senderProfile.displayName : details.deviceDisplayName
|
||||
Text(displayName ?? details.senderProfile.userID)
|
||||
.font(.compound.bodyMDSemibold)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@ -60,6 +97,8 @@ struct SessionVerificationRequestDetailsView: View {
|
||||
.stroke(.compound.borderDisabled)
|
||||
}
|
||||
|
||||
.font(.compound.bodyMDSemibold)
|
||||
|
||||
Text(L10n.screenSessionVerificationRequestFooter)
|
||||
.font(.compound.bodyMDSemibold)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
@ -68,13 +107,25 @@ struct SessionVerificationRequestDetailsView: View {
|
||||
}
|
||||
|
||||
struct SessionVerificationRequestDetailsView_Previews: PreviewProvider, TestablePreview {
|
||||
static let details = SessionVerificationRequestDetails(senderProfile: UserProfileProxy(userID: "@bob:matrix.org",
|
||||
displayName: "Billy bob",
|
||||
avatarURL: .mockMXCUserAvatar),
|
||||
flowID: "123",
|
||||
deviceID: "CODEMISTAKE",
|
||||
deviceDisplayName: "Bob's Element X iOS",
|
||||
firstSeenDate: .init(timeIntervalSince1970: 0))
|
||||
|
||||
static var previews: some View {
|
||||
let details = SessionVerificationRequestDetails(senderID: "@bob:matrix.org",
|
||||
flowID: "123",
|
||||
deviceID: "CODEMISTAKE",
|
||||
displayName: "Bob's Element X iOS",
|
||||
firstSeenDate: .init(timeIntervalSince1970: 0))
|
||||
SessionVerificationRequestDetailsView(details: details,
|
||||
isUserVerification: true,
|
||||
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||
.padding()
|
||||
.previewDisplayName("User")
|
||||
|
||||
SessionVerificationRequestDetailsView(details: details)
|
||||
SessionVerificationRequestDetailsView(details: details,
|
||||
isUserVerification: false,
|
||||
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||
.padding()
|
||||
.previewDisplayName("Device")
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +25,24 @@ struct SessionVerificationScreen: View {
|
||||
.backgroundStyle(.compound.bgCanvasDefault)
|
||||
.interactiveDismissDisabled()
|
||||
.navigationBarBackButtonHidden(context.viewState.verificationState == .verified)
|
||||
.toolbar { toolbar }
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private var toolbar: some ToolbarContent {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
switch context.viewState.flow {
|
||||
case .userIntiator, .userResponder:
|
||||
Button(L10n.actionCancel) {
|
||||
context.send(viewAction: .cancel)
|
||||
}
|
||||
default:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var screenHeader: some View {
|
||||
VStack(spacing: 0) {
|
||||
@ -55,11 +69,23 @@ struct SessionVerificationScreen: View {
|
||||
switch context.viewState.verificationState {
|
||||
case .initial:
|
||||
switch context.viewState.flow {
|
||||
case .responder(let details):
|
||||
SessionVerificationRequestDetailsView(details: details)
|
||||
case .deviceResponder(let details):
|
||||
SessionVerificationRequestDetailsView(details: details,
|
||||
isUserVerification: false,
|
||||
mediaProvider: context.mediaProvider)
|
||||
case .userResponder(let details):
|
||||
SessionVerificationRequestDetailsView(details: details,
|
||||
isUserVerification: true,
|
||||
mediaProvider: context.mediaProvider)
|
||||
case .userIntiator:
|
||||
Button(L10n.actionLearnMore) {
|
||||
UIApplication.shared.open(context.viewState.learnMoreURL)
|
||||
}
|
||||
.buttonStyle(.compound(.plain))
|
||||
default:
|
||||
EmptyView()
|
||||
}
|
||||
|
||||
case .showingChallenge(let emojis), .acceptingChallenge(let emojis), .decliningChallenge(let emojis):
|
||||
emojisPanel(with: emojis)
|
||||
.accessibilityIdentifier(A11yIdentifiers.sessionVerificationScreen.emojiWrapper)
|
||||
@ -89,13 +115,13 @@ struct SessionVerificationScreen: View {
|
||||
switch context.viewState.verificationState {
|
||||
case .initial:
|
||||
switch context.viewState.flow {
|
||||
case .initiator:
|
||||
case .deviceInitiator, .userIntiator:
|
||||
Button(L10n.actionStartVerification) {
|
||||
context.send(viewAction: .requestVerification)
|
||||
}
|
||||
.buttonStyle(.compound(.primary))
|
||||
.accessibilityIdentifier(A11yIdentifiers.sessionVerificationScreen.requestVerification)
|
||||
case .responder:
|
||||
case .deviceResponder, .userResponder:
|
||||
VStack(spacing: 16) {
|
||||
Button(L10n.actionStart) {
|
||||
context.send(viewAction: .acceptVerificationRequest)
|
||||
@ -112,12 +138,12 @@ struct SessionVerificationScreen: View {
|
||||
}
|
||||
case .cancelled:
|
||||
switch context.viewState.flow {
|
||||
case .initiator:
|
||||
case .deviceInitiator, .userIntiator:
|
||||
Button(L10n.actionRetry) {
|
||||
context.send(viewAction: .restart)
|
||||
}
|
||||
.buttonStyle(.compound(.primary))
|
||||
case .responder:
|
||||
case .deviceResponder, .userResponder:
|
||||
Button(L10n.actionDone) {
|
||||
context.send(viewAction: .done)
|
||||
}
|
||||
@ -146,11 +172,6 @@ struct SessionVerificationScreen: View {
|
||||
.accessibilityIdentifier(A11yIdentifiers.sessionVerificationScreen.declineChallenge)
|
||||
}
|
||||
|
||||
case .acceptingVerificationRequest, .acceptingChallenge, .decliningChallenge, .requestingVerification:
|
||||
Button(L10n.screenIdentityWaitingOnOtherDevice) { }
|
||||
.buttonStyle(.compound(.primary))
|
||||
.disabled(true)
|
||||
|
||||
default:
|
||||
EmptyView()
|
||||
}
|
||||
@ -174,16 +195,25 @@ struct SessionVerificationScreen: View {
|
||||
|
||||
struct SessionVerification_Previews: PreviewProvider, TestablePreview {
|
||||
static var previews: some View {
|
||||
sessionVerificationScreen(state: .initial)
|
||||
.previewDisplayName("Initial - Initiator")
|
||||
sessionVerificationScreen(state: .initial, flow: .deviceInitiator)
|
||||
.previewDisplayName("Initial - Device Initiator")
|
||||
|
||||
let details = SessionVerificationRequestDetails(senderID: "@bob:matrix.org",
|
||||
sessionVerificationScreen(state: .initial, flow: .userIntiator(userID: "@bob:matrix.org"))
|
||||
.previewDisplayName("Initial - User Initiator")
|
||||
|
||||
let details = SessionVerificationRequestDetails(senderProfile: UserProfileProxy(userID: "@bob:matrix.org",
|
||||
displayName: "Billy Bob",
|
||||
avatarURL: .mockMXCUserAvatar),
|
||||
flowID: "123",
|
||||
deviceID: "CODEMISTAKE",
|
||||
displayName: "Bob's Element X iOS",
|
||||
deviceDisplayName: "Bob's Element X iOS",
|
||||
firstSeenDate: .init(timeIntervalSince1970: 0))
|
||||
sessionVerificationScreen(state: .initial, flow: .responder(details: details))
|
||||
.previewDisplayName("Initial - Responder")
|
||||
|
||||
sessionVerificationScreen(state: .initial, flow: .deviceResponder(requestDetails: details))
|
||||
.previewDisplayName("Initial - Device Responder")
|
||||
|
||||
sessionVerificationScreen(state: .initial, flow: .userResponder(requestDetails: details))
|
||||
.previewDisplayName("Initial - User Responder")
|
||||
|
||||
sessionVerificationScreen(state: .acceptingVerificationRequest)
|
||||
.previewDisplayName("Accepting Verification Request")
|
||||
@ -213,9 +243,11 @@ struct SessionVerification_Previews: PreviewProvider, TestablePreview {
|
||||
}
|
||||
|
||||
static func sessionVerificationScreen(state: SessionVerificationScreenStateMachine.State,
|
||||
flow: SessionVerificationScreenFlow = .initiator) -> some View {
|
||||
flow: SessionVerificationScreenFlow = .deviceInitiator) -> some View {
|
||||
let viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: SessionVerificationControllerProxyMock.configureMock(),
|
||||
flow: flow,
|
||||
appSettings: AppSettings(),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
verificationState: state)
|
||||
|
||||
return SessionVerificationScreen(context: viewModel.context)
|
||||
|
@ -21,6 +21,7 @@ enum RoomMemberDetailsScreenCoordinatorAction {
|
||||
case openUserProfile
|
||||
case openDirectChat(roomID: String)
|
||||
case startCall(roomID: String)
|
||||
case verifyUser(userID: String)
|
||||
}
|
||||
|
||||
final class RoomMemberDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
@ -53,6 +54,8 @@ final class RoomMemberDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.send(.openDirectChat(roomID: roomID))
|
||||
case .startCall(let roomID):
|
||||
actionsSubject.send(.startCall(roomID: roomID))
|
||||
case .verifyUser(let userID):
|
||||
actionsSubject.send(.verifyUser(userID: userID))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
@ -11,6 +11,7 @@ enum RoomMemberDetailsScreenViewModelAction {
|
||||
case openUserProfile
|
||||
case openDirectChat(roomID: String)
|
||||
case startCall(roomID: String)
|
||||
case verifyUser(userID: String)
|
||||
}
|
||||
|
||||
struct RoomMemberDetailsScreenViewState: BindableState {
|
||||
@ -88,6 +89,7 @@ enum RoomMemberDetailsScreenViewAction {
|
||||
case openDirectChat
|
||||
case createDirectChat
|
||||
case startCall(roomID: String)
|
||||
case verifyUser
|
||||
}
|
||||
|
||||
enum RoomMemberDetailsScreenAlertType: Hashable {
|
||||
|
@ -75,6 +75,8 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro
|
||||
Task { await createDirectChat() }
|
||||
case .startCall(let roomID):
|
||||
actionsSubject.send(.startCall(roomID: roomID))
|
||||
case .verifyUser:
|
||||
actionsSubject.send(.verifyUser(userID: state.userID))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,11 +91,10 @@ struct RoomMemberDetailsScreen: View {
|
||||
var verificationSection: some View {
|
||||
if context.viewState.showVerificationSection {
|
||||
Section {
|
||||
ListRow(label: .default(title: L10n.commonVerifyIdentity,
|
||||
description: L10n.screenRoomMemberDetailsVerifyButtonSubtitle,
|
||||
icon: \.lock),
|
||||
kind: .button { })
|
||||
.disabled(true)
|
||||
ListRow(label: .default(title: L10n.commonVerifyUser, icon: \.lock),
|
||||
kind: .button {
|
||||
context.send(viewAction: .verifyUser)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ struct UserProfileScreenCoordinatorParameters {
|
||||
enum UserProfileScreenCoordinatorAction {
|
||||
case openDirectChat(roomID: String)
|
||||
case startCall(roomID: String)
|
||||
case verifyUser(userID: String)
|
||||
case dismiss
|
||||
}
|
||||
|
||||
@ -51,6 +52,8 @@ final class UserProfileScreenCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.send(.openDirectChat(roomID: roomID))
|
||||
case .startCall(let roomID):
|
||||
actionsSubject.send(.startCall(roomID: roomID))
|
||||
case .verifyUser(let userID):
|
||||
actionsSubject.send(.verifyUser(userID: userID))
|
||||
case .dismiss:
|
||||
actionsSubject.send(.dismiss)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import Foundation
|
||||
enum UserProfileScreenViewModelAction {
|
||||
case openDirectChat(roomID: String)
|
||||
case startCall(roomID: String)
|
||||
case verifyUser(userID: String)
|
||||
case dismiss
|
||||
}
|
||||
|
||||
@ -47,6 +48,7 @@ enum UserProfileScreenViewAction {
|
||||
case openDirectChat
|
||||
case createDirectChat
|
||||
case startCall(roomID: String)
|
||||
case verifyUser
|
||||
case dismiss
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,8 @@ class UserProfileScreenViewModel: UserProfileScreenViewModelType, UserProfileScr
|
||||
Task { await createDirectChat() }
|
||||
case .startCall(let roomID):
|
||||
actionsSubject.send(.startCall(roomID: roomID))
|
||||
case .verifyUser:
|
||||
actionsSubject.send(.verifyUser(userID: state.userID))
|
||||
case .dismiss:
|
||||
actionsSubject.send(.dismiss)
|
||||
}
|
||||
|
@ -88,11 +88,10 @@ struct UserProfileScreen: View {
|
||||
var verificationSection: some View {
|
||||
if context.viewState.showVerificationSection {
|
||||
Section {
|
||||
ListRow(label: .default(title: L10n.commonVerifyIdentity,
|
||||
description: L10n.screenRoomMemberDetailsVerifyButtonSubtitle,
|
||||
icon: \.lock),
|
||||
kind: .button { })
|
||||
.disabled(true)
|
||||
ListRow(label: .default(title: L10n.commonVerifyUser, icon: \.lock),
|
||||
kind: .button {
|
||||
context.send(viewAction: .verifyUser)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt
|
||||
MXLog.info("Acknowledging verification request")
|
||||
|
||||
do {
|
||||
try await sessionVerificationController.acknowledgeVerificationRequest(senderId: details.senderID, flowId: details.flowID)
|
||||
try await sessionVerificationController.acknowledgeVerificationRequest(senderId: details.senderProfile.userID, flowId: details.flowID)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed requesting session verification with error: \(error)")
|
||||
@ -91,14 +91,26 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt
|
||||
}
|
||||
}
|
||||
|
||||
func requestVerification() async -> Result<Void, SessionVerificationControllerProxyError> {
|
||||
MXLog.info("Requesting session verification")
|
||||
func requestDeviceVerification() async -> Result<Void, SessionVerificationControllerProxyError> {
|
||||
MXLog.info("Requesting device verification")
|
||||
|
||||
do {
|
||||
try await sessionVerificationController.requestDeviceVerification()
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed requesting session verification with error: \(error)")
|
||||
MXLog.error("Failed requesting device verification with error: \(error)")
|
||||
return .failure(.failedRequestingVerification)
|
||||
}
|
||||
}
|
||||
|
||||
func requestUserVerification(_ userID: String) async -> Result<Void, SessionVerificationControllerProxyError> {
|
||||
MXLog.info("Requesting user verification")
|
||||
|
||||
do {
|
||||
try await sessionVerificationController.requestUserVerification(userId: userID)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed requesting verification for user \(userID) with error: \(error)")
|
||||
return .failure(.failedRequestingVerification)
|
||||
}
|
||||
}
|
||||
@ -156,10 +168,10 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt
|
||||
fileprivate func didReceiveVerificationRequest(details: MatrixRustSDK.SessionVerificationRequestDetails) {
|
||||
MXLog.info("Received verification request \(details)")
|
||||
|
||||
let details = SessionVerificationRequestDetails(senderID: details.senderId,
|
||||
let details = SessionVerificationRequestDetails(senderProfile: UserProfileProxy(sdkUserProfile: details.senderProfile),
|
||||
flowID: details.flowId,
|
||||
deviceID: details.deviceId,
|
||||
displayName: details.deviceDisplayName,
|
||||
deviceDisplayName: details.deviceDisplayName,
|
||||
firstSeenDate: Date(timeIntervalSince1970: TimeInterval(details.firstSeenTimestamp / 1000)))
|
||||
|
||||
actions.send(.receivedVerificationRequest(details: details))
|
||||
|
@ -30,10 +30,10 @@ enum SessionVerificationControllerProxyAction {
|
||||
}
|
||||
|
||||
struct SessionVerificationRequestDetails {
|
||||
let senderID: String
|
||||
let senderProfile: UserProfileProxy
|
||||
let flowID: String
|
||||
let deviceID: String
|
||||
let displayName: String?
|
||||
let deviceDisplayName: String?
|
||||
let firstSeenDate: Date
|
||||
}
|
||||
|
||||
@ -54,7 +54,9 @@ protocol SessionVerificationControllerProxyProtocol {
|
||||
|
||||
func acceptVerificationRequest() async -> Result<Void, SessionVerificationControllerProxyError>
|
||||
|
||||
func requestVerification() async -> Result<Void, SessionVerificationControllerProxyError>
|
||||
func requestDeviceVerification() async -> Result<Void, SessionVerificationControllerProxyError>
|
||||
|
||||
func requestUserVerification(_ userID: String) async -> Result<Void, SessionVerificationControllerProxyError>
|
||||
|
||||
func startSasVerification() async -> Result<Void, SessionVerificationControllerProxyError>
|
||||
|
||||
|
@ -533,7 +533,9 @@ class MockScreen: Identifiable {
|
||||
case .sessionVerification:
|
||||
var sessionVerificationControllerProxy = SessionVerificationControllerProxyMock.configureMock(requestDelay: .seconds(5))
|
||||
let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationControllerProxy,
|
||||
flow: .initiator)
|
||||
flow: .deviceInitiator,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||
return SessionVerificationScreenCoordinator(parameters: parameters)
|
||||
case .userSessionScreen, .userSessionScreenReply:
|
||||
let appSettings: AppSettings = ServiceLocator.shared.settings
|
||||
|
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomMemberDetailsScreen-iPad-en-GB.Ignored-User.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomMemberDetailsScreen-iPad-en-GB.Ignored-User.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomMemberDetailsScreen-iPad-en-GB.Other-User.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomMemberDetailsScreen-iPad-en-GB.Other-User.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomMemberDetailsScreen-iPad-pseudo.Other-User.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomMemberDetailsScreen-iPad-pseudo.Other-User.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Initial-User-Initiator.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Initial-User-Initiator.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Initial-User-Responder.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Initial-User-Responder.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Initial-User-Initiator.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Initial-User-Initiator.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Initial-User-Responder.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Initial-User-Responder.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-16-en-GB.Initial-User-Initiator.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-16-en-GB.Initial-User-Initiator.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-16-en-GB.Initial-User-Responder.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-16-en-GB.Initial-User-Responder.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-16-pseudo.Initial-User-Initiator.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-16-pseudo.Initial-User-Initiator.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-16-pseudo.Initial-User-Responder.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-16-pseudo.Initial-User-Responder.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPad-en-GB.Device.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPad-en-GB.Device.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPad-en-GB.User.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPad-en-GB.User.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPad-pseudo.Device.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPad-pseudo.Device.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPad-pseudo.User.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPad-pseudo.User.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPhone-16-en-GB.Device.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPhone-16-en-GB.Device.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPhone-16-en-GB.User.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPhone-16-en-GB.User.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPhone-16-pseudo.Device.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPhone-16-pseudo.Device.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPhone-16-pseudo.User.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_sessionVerificationRequestDetailsView-iPhone-16-pseudo.User.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPad-en-GB.Account-Owner.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPad-en-GB.Account-Owner.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPad-en-GB.Other-User.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPad-en-GB.Other-User.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPad-pseudo.Account-Owner.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPad-pseudo.Account-Owner.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPad-pseudo.Other-User.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPad-pseudo.Other-User.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPhone-16-en-GB.Account-Owner.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPhone-16-en-GB.Account-Owner.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPhone-16-en-GB.Other-User.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPhone-16-en-GB.Other-User.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPhone-16-pseudo.Other-User.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_userProfileScreen-iPhone-16-pseudo.Other-User.png
(Stored with Git LFS)
Binary file not shown.
@ -18,7 +18,10 @@ class SessionVerificationViewModelTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
sessionVerificationController = SessionVerificationControllerProxyMock.configureMock()
|
||||
viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: sessionVerificationController, flow: .initiator)
|
||||
viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: sessionVerificationController,
|
||||
flow: .deviceInitiator,
|
||||
appSettings: AppSettings(),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()))
|
||||
context = viewModel.context
|
||||
}
|
||||
|
||||
@ -28,7 +31,7 @@ class SessionVerificationViewModelTests: XCTestCase {
|
||||
context.send(viewAction: .requestVerification)
|
||||
|
||||
try await Task.sleep(for: .milliseconds(100))
|
||||
XCTAssert(sessionVerificationController.requestVerificationCallsCount == 1)
|
||||
XCTAssert(sessionVerificationController.requestDeviceVerificationCallsCount == 1)
|
||||
XCTAssertEqual(context.viewState.verificationState, .requestingVerification)
|
||||
}
|
||||
|
||||
@ -53,7 +56,7 @@ class SessionVerificationViewModelTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(context.viewState.verificationState, .initial)
|
||||
|
||||
XCTAssert(sessionVerificationController.requestVerificationCallsCount == 1)
|
||||
XCTAssert(sessionVerificationController.requestDeviceVerificationCallsCount == 1)
|
||||
XCTAssert(sessionVerificationController.cancelVerificationCallsCount == 1)
|
||||
}
|
||||
|
||||
@ -154,7 +157,7 @@ class SessionVerificationViewModelTests: XCTestCase {
|
||||
wait(for: [verificationDataReceivalExpectation], timeout: 10.0)
|
||||
XCTAssertEqual(context.viewState.verificationState, .showingChallenge(emojis: SessionVerificationControllerProxyMock.emojis))
|
||||
|
||||
XCTAssert(sessionVerificationController.requestVerificationCallsCount == 1)
|
||||
XCTAssert(sessionVerificationController.requestDeviceVerificationCallsCount == 1)
|
||||
XCTAssert(sessionVerificationController.startSasVerificationCallsCount == 1)
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ packages:
|
||||
# Element/Matrix dependencies
|
||||
MatrixRustSDK:
|
||||
url: https://github.com/element-hq/matrix-rust-components-swift
|
||||
exactVersion: 25.02.06
|
||||
exactVersion: 25.02.07
|
||||
# path: ../matrix-rust-sdk
|
||||
Compound:
|
||||
url: https://github.com/element-hq/compound-ios
|
||||
|
Loading…
x
Reference in New Issue
Block a user