Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for initiating and responding to user verification requests #3759

Merged
merged 2 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ElementX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
7 changes: 7 additions & 0 deletions ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand All @@ -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.
}
Expand Down Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -464,7 +472,9 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
}
.store(in: &cancellables)

navigationSplitCoordinator.setSheetCoordinator(coordinator)
navigationStackCoordinator.setRootCoordinator(coordinator)

navigationSplitCoordinator.setSheetCoordinator(navigationStackCoordinator)
}

private func presentHomeScreen() {
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
112 changes: 91 additions & 21 deletions ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14105,68 +14105,138 @@ 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!
}
}
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!
}
}
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions ElementX/Sources/Other/Avatars.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ enum UserAvatarSizeOnScreen {
case knockingUserList
case mediaPreviewDetails
case sendInviteConfirmation
case sessionVerification

var value: CGFloat {
switch self {
Expand Down Expand Up @@ -116,6 +117,8 @@ enum UserAvatarSizeOnScreen {
return 32
case .sendInviteConfirmation:
return 64
case .sessionVerification:
return 52
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down
Loading
Loading