mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Move session related responsibilities from ChatsFlowFlowCoordinator to UserSessionFlowCoordinator.
Specifically: onboarding, session verification and logout.
This commit is contained in:
@@ -13,8 +13,9 @@ import SwiftUI
|
||||
|
||||
enum ChatsFlowCoordinatorAction {
|
||||
case logout
|
||||
case sessionVerification(SessionVerificationScreenFlow)
|
||||
case clearCache
|
||||
/// Logout without a confirmation. The user forgot their PIN.
|
||||
/// Logout and disable App Lock without any confirmation. The user forgot their PIN.
|
||||
case forceLogout
|
||||
}
|
||||
|
||||
@@ -37,8 +38,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
private let settingsFlowCoordinator: SettingsFlowCoordinator
|
||||
|
||||
private let onboardingFlowCoordinator: OnboardingFlowCoordinator
|
||||
|
||||
// periphery:ignore - retaining purpose
|
||||
private var bugReportFlowCoordinator: BugReportFlowCoordinator?
|
||||
|
||||
@@ -103,16 +102,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
analytics: analytics))
|
||||
|
||||
onboardingFlowCoordinator = OnboardingFlowCoordinator(userSession: userSession,
|
||||
appLockService: appLockService,
|
||||
analyticsService: analytics,
|
||||
appSettings: appSettings,
|
||||
notificationManager: notificationManager,
|
||||
navigationStackCoordinator: detailNavigationStackCoordinator,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
windowManager: appMediator.windowManager,
|
||||
isNewLogin: isNewLogin)
|
||||
|
||||
setupStateMachine()
|
||||
|
||||
setupObservers()
|
||||
@@ -216,15 +205,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func attemptStartingOnboarding() {
|
||||
MXLog.info("Attempting to start onboarding")
|
||||
|
||||
if onboardingFlowCoordinator.shouldStart {
|
||||
clearRoute(animated: false)
|
||||
onboardingFlowCoordinator.start()
|
||||
}
|
||||
}
|
||||
|
||||
private func clearPresentedSheets(animated: Bool) async {
|
||||
if navigationSplitCoordinator.sheetCoordinator == nil {
|
||||
return
|
||||
@@ -243,7 +223,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
switch (context.fromState, context.event, context.toState) {
|
||||
case (.initial, .start, .roomList):
|
||||
presentHomeScreen()
|
||||
attemptStartingOnboarding()
|
||||
case(.roomList(let roomListSelectedRoomID), .selectRoom(let roomID, let via, let entryPoint), .roomList):
|
||||
if roomListSelectedRoomID == roomID,
|
||||
!entryPoint.isEventID, // Don't reuse the existing room so the live timeline is hidden while the detached timeline is loading.
|
||||
@@ -291,11 +270,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case (.startChatScreen, .dismissedStartChatScreen, .roomList):
|
||||
break
|
||||
|
||||
case (.roomList, .showLogoutConfirmationScreen, .logoutConfirmationScreen):
|
||||
presentSecureBackupLogoutConfirmationScreen()
|
||||
case (.logoutConfirmationScreen, .dismissedLogoutConfirmationScreen, .roomList):
|
||||
break
|
||||
|
||||
case (.roomList, .showRoomDirectorySearchScreen, .roomDirectorySearchScreen):
|
||||
presentRoomDirectorySearch()
|
||||
case (.roomDirectorySearchScreen, .dismissedRoomDirectorySearchScreen, .roomList):
|
||||
@@ -352,19 +326,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
|
||||
private func setupObservers() {
|
||||
userSession.sessionSecurityStatePublisher
|
||||
.map(\.verificationState)
|
||||
.filter { $0 != .unknown }
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
|
||||
attemptStartingOnboarding()
|
||||
|
||||
setupSessionVerificationRequestsObserver()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
settingsFlowCoordinator.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
@@ -374,7 +335,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case .dismissedSettings:
|
||||
stateMachine.processEvent(.dismissedSettingsScreen)
|
||||
case .runLogoutFlow:
|
||||
Task { await self.runLogoutFlow() }
|
||||
actionsSubject.send(.logout)
|
||||
case .clearCache:
|
||||
actionsSubject.send(.clearCache)
|
||||
case .forceLogout:
|
||||
@@ -413,17 +374,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
onboardingFlowCoordinator.actions
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .logout:
|
||||
logout()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func processDecryptionError(_ info: UnableToDecryptInfo) {
|
||||
@@ -455,53 +405,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
wasVisibleToUser: nil)
|
||||
}
|
||||
|
||||
private func setupSessionVerificationRequestsObserver() {
|
||||
userSession.clientProxy.sessionVerificationController?.actions
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] action in
|
||||
guard let self, case .receivedVerificationRequest(let details) = action else {
|
||||
return
|
||||
}
|
||||
|
||||
MXLog.info("Received session verification request")
|
||||
|
||||
if details.senderProfile.userID == userSession.clientProxy.userID {
|
||||
presentSessionVerificationScreen(flow: .deviceResponder(requestDetails: details))
|
||||
} else {
|
||||
presentSessionVerificationScreen(flow: .userResponder(requestDetails: details))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
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: flow,
|
||||
appSettings: appSettings,
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
let coordinator = SessionVerificationScreenCoordinator(parameters: parameters)
|
||||
|
||||
coordinator.actions
|
||||
.sink { [weak self] action in
|
||||
switch action {
|
||||
case .done:
|
||||
self?.navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(navigationStackCoordinator)
|
||||
}
|
||||
|
||||
private func presentHomeScreen() {
|
||||
let parameters = HomeScreenCoordinatorParameters(userSession: userSession,
|
||||
bugReportService: bugReportService,
|
||||
@@ -543,7 +446,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case .presentGlobalSearch:
|
||||
presentGlobalSearch()
|
||||
case .logout:
|
||||
Task { await self.runLogoutFlow() }
|
||||
actionsSubject.send(.logout)
|
||||
case .presentDeclineAndBlock(let userID, let roomID):
|
||||
stateMachine.processEvent(.presentDeclineAndBlockScreen(userID: userID, roomID: roomID))
|
||||
}
|
||||
@@ -604,55 +507,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private func runLogoutFlow() async {
|
||||
let secureBackupController = userSession.clientProxy.secureBackupController
|
||||
|
||||
guard case let .success(isLastDevice) = await userSession.clientProxy.isOnlyDeviceLeft() else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init())
|
||||
return
|
||||
}
|
||||
|
||||
guard isLastDevice else {
|
||||
logout()
|
||||
return
|
||||
}
|
||||
|
||||
guard secureBackupController.recoveryState.value == .enabled else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutRecoveryDisabledTitle,
|
||||
message: L10n.screenSignoutRecoveryDisabledSubtitle,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
}, secondaryButton: .init(title: L10n.commonSettings, role: .cancel) { [weak self] in
|
||||
self?.settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
guard secureBackupController.keyBackupState.value == .enabled else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutKeyBackupDisabledTitle,
|
||||
message: L10n.screenSignoutKeyBackupDisabledSubtitle,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
}, secondaryButton: .init(title: L10n.commonSettings, role: .cancel) { [weak self] in
|
||||
self?.settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
presentSecureBackupLogoutConfirmationScreen()
|
||||
}
|
||||
|
||||
private func logout() {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutConfirmationDialogTitle,
|
||||
message: L10n.screenSignoutConfirmationDialogContent,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
})
|
||||
}
|
||||
|
||||
// MARK: Room Flow
|
||||
|
||||
private func startRoomFlow(roomID: String,
|
||||
@@ -680,7 +534,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
// 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))
|
||||
actionsSubject.send(.sessionVerification(.userInitiator(userID: userID)))
|
||||
case .finished:
|
||||
stateMachine.processEvent(.deselectRoom)
|
||||
}
|
||||
@@ -890,28 +744,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private func presentSecureBackupLogoutConfirmationScreen() {
|
||||
let coordinator = SecureBackupLogoutConfirmationScreenCoordinator(parameters: .init(secureBackupController: userSession.clientProxy.secureBackupController,
|
||||
appMediator: appMediator))
|
||||
|
||||
coordinator.actions
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .cancel:
|
||||
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
case .settings:
|
||||
settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
case .logout:
|
||||
actionsSubject.send(.logout)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(coordinator, animated: true)
|
||||
}
|
||||
|
||||
// MARK: Global search
|
||||
|
||||
private func presentGlobalSearch() {
|
||||
|
||||
@@ -110,11 +110,6 @@ class ChatsFlowCoordinatorStateMachine {
|
||||
case showStartChatScreen
|
||||
/// Start chat has been dismissed
|
||||
case dismissedStartChatScreen
|
||||
|
||||
/// Logout has been requested and this is the last session
|
||||
case showLogoutConfirmationScreen
|
||||
/// Logout has been cancelled
|
||||
case dismissedLogoutConfirmationScreen
|
||||
|
||||
/// Request presentation of the room directory search screen.
|
||||
case showRoomDirectorySearchScreen
|
||||
@@ -186,11 +181,6 @@ class ChatsFlowCoordinatorStateMachine {
|
||||
return .startChatScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||
case (.startChatScreen(let roomListSelectedRoomID), .dismissedStartChatScreen):
|
||||
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||
|
||||
case (.roomList(let roomListSelectedRoomID), .showLogoutConfirmationScreen):
|
||||
return .logoutConfirmationScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||
case (.logoutConfirmationScreen(let roomListSelectedRoomID), .dismissedLogoutConfirmationScreen):
|
||||
return .roomList(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||
|
||||
case (.roomList(let roomListSelectedRoomID), .showRoomDirectorySearchScreen):
|
||||
return .roomDirectorySearchScreen(roomListSelectedRoomID: roomListSelectedRoomID)
|
||||
|
||||
@@ -10,6 +10,8 @@ import Foundation
|
||||
import SwiftState
|
||||
|
||||
enum OnboardingFlowCoordinatorAction {
|
||||
case requestPresentation(animated: Bool)
|
||||
case dismiss
|
||||
case logout
|
||||
}
|
||||
|
||||
@@ -19,7 +21,6 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let analyticsService: AnalyticsService
|
||||
private let appSettings: AppSettings
|
||||
private let notificationManager: NotificationManagerProtocol
|
||||
private let rootNavigationStackCoordinator: NavigationStackCoordinator
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let windowManager: WindowManagerProtocol
|
||||
private let isNewLogin: Bool
|
||||
@@ -74,8 +75,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
self.windowManager = windowManager
|
||||
self.isNewLogin = isNewLogin
|
||||
|
||||
rootNavigationStackCoordinator = navigationStackCoordinator
|
||||
self.navigationStackCoordinator = NavigationStackCoordinator()
|
||||
self.navigationStackCoordinator = navigationStackCoordinator
|
||||
|
||||
stateMachine = .init(state: .initial)
|
||||
|
||||
@@ -112,7 +112,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
fatalError("This flow coordinator shouldn't have been started")
|
||||
}
|
||||
|
||||
rootNavigationStackCoordinator.setFullScreenCoverCoordinator(navigationStackCoordinator, animated: !isNewLogin)
|
||||
actionsSubject.send(.requestPresentation(animated: !isNewLogin))
|
||||
|
||||
stateMachine.tryEvent(.next)
|
||||
}
|
||||
@@ -224,7 +224,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case (_, _, .notificationPermissions):
|
||||
presentNotificationPermissionsScreen()
|
||||
case (_, _, .finished):
|
||||
rootNavigationStackCoordinator.setFullScreenCoverCoordinator(nil)
|
||||
actionsSubject.send(.dismiss)
|
||||
stateMachine.tryState(.initial)
|
||||
case (.finished, _, .initial):
|
||||
break
|
||||
|
||||
@@ -13,7 +13,7 @@ import SwiftUI
|
||||
enum UserSessionFlowCoordinatorAction {
|
||||
case logout
|
||||
case clearCache
|
||||
/// Logout without a confirmation. The user forgot their PIN.
|
||||
/// Logout and disable App Lock without any confirmation. The user forgot their PIN.
|
||||
case forceLogout
|
||||
}
|
||||
|
||||
@@ -21,7 +21,11 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let userSession: UserSessionProtocol
|
||||
private let navigationRootCoordinator: NavigationRootCoordinator
|
||||
private let navigationTabCoordinator: NavigationTabCoordinator
|
||||
private let appMediator: AppMediatorProtocol
|
||||
private let appSettings: AppSettings
|
||||
|
||||
private let onboardingFlowCoordinator: OnboardingFlowCoordinator
|
||||
private let onboardingStackCoordinator: NavigationStackCoordinator
|
||||
private let chatsFlowCoordinator: ChatsFlowCoordinator
|
||||
|
||||
private let actionsSubject: PassthroughSubject<UserSessionFlowCoordinatorAction, Never> = .init()
|
||||
@@ -45,6 +49,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
isNewLogin: Bool) {
|
||||
self.userSession = userSession
|
||||
self.navigationRootCoordinator = navigationRootCoordinator
|
||||
self.appMediator = appMediator
|
||||
self.appSettings = appSettings
|
||||
|
||||
navigationTabCoordinator = NavigationTabCoordinator()
|
||||
navigationRootCoordinator.setRootCoordinator(navigationTabCoordinator)
|
||||
@@ -63,28 +69,31 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
notificationManager: notificationManager,
|
||||
isNewLogin: isNewLogin)
|
||||
|
||||
onboardingStackCoordinator = NavigationStackCoordinator()
|
||||
onboardingFlowCoordinator = OnboardingFlowCoordinator(userSession: userSession,
|
||||
appLockService: appLockService,
|
||||
analyticsService: analytics,
|
||||
appSettings: appSettings,
|
||||
notificationManager: notificationManager,
|
||||
navigationStackCoordinator: onboardingStackCoordinator,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
windowManager: appMediator.windowManager,
|
||||
isNewLogin: isNewLogin)
|
||||
|
||||
navigationTabCoordinator.setTabs([
|
||||
.init(coordinator: chatsSplitCoordinator, title: L10n.screenHomeTabChats, icon: \.chat, selectedIcon: \.chatSolid),
|
||||
.init(coordinator: BlankFormCoordinator(), title: L10n.screenHomeTabSpaces, icon: \.space, selectedIcon: \.spaceSolid)
|
||||
])
|
||||
|
||||
chatsFlowCoordinator.actionsPublisher
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .logout:
|
||||
actionsSubject.send(.logout)
|
||||
case .clearCache:
|
||||
actionsSubject.send(.clearCache)
|
||||
case .forceLogout:
|
||||
actionsSubject.send(.forceLogout)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
setupObservers()
|
||||
}
|
||||
|
||||
func start() {
|
||||
#warning("This flow still needs a state machine.")
|
||||
|
||||
chatsFlowCoordinator.start()
|
||||
|
||||
attemptStartingOnboarding()
|
||||
}
|
||||
|
||||
func stop() {
|
||||
@@ -92,6 +101,9 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
|
||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||
// There aren't any routes that directly target this flow yet, so pass them directly to the
|
||||
// chats flow coordinator.
|
||||
#warning("This should switch tabs to make sure the route is visible.")
|
||||
chatsFlowCoordinator.handleAppRoute(appRoute, animated: animated)
|
||||
}
|
||||
|
||||
@@ -99,8 +111,189 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
chatsFlowCoordinator.clearRoute(animated: animated)
|
||||
}
|
||||
|
||||
#warning("Should this be a publisher instead??")
|
||||
#warning("This should use a publisher, combining it with the active tab.")
|
||||
func isDisplayingRoomScreen(withRoomID roomID: String) -> Bool {
|
||||
chatsFlowCoordinator.isDisplayingRoomScreen(withRoomID: roomID)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupObservers() {
|
||||
chatsFlowCoordinator.actionsPublisher
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .logout:
|
||||
Task { await self.runLogoutFlow() }
|
||||
case .sessionVerification(let flow):
|
||||
presentSessionVerificationScreen(flow: flow)
|
||||
case .clearCache:
|
||||
actionsSubject.send(.clearCache)
|
||||
case .forceLogout:
|
||||
actionsSubject.send(.forceLogout)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
userSession.sessionSecurityStatePublisher
|
||||
.map(\.verificationState)
|
||||
.filter { $0 != .unknown }
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
|
||||
attemptStartingOnboarding()
|
||||
setupSessionVerificationRequestsObserver()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
onboardingFlowCoordinator.actions
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .requestPresentation(let animated):
|
||||
navigationTabCoordinator.setFullScreenCoverCoordinator(onboardingStackCoordinator, animated: animated)
|
||||
case .dismiss:
|
||||
navigationTabCoordinator.setFullScreenCoverCoordinator(nil)
|
||||
case .logout:
|
||||
logout()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
// MARK: - Onboarding
|
||||
|
||||
func attemptStartingOnboarding() {
|
||||
MXLog.info("Attempting to start onboarding")
|
||||
|
||||
if onboardingFlowCoordinator.shouldStart {
|
||||
clearRoute(animated: false)
|
||||
onboardingFlowCoordinator.start()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Session Verification
|
||||
|
||||
private func setupSessionVerificationRequestsObserver() {
|
||||
userSession.clientProxy.sessionVerificationController?.actions
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] action in
|
||||
guard let self, case .receivedVerificationRequest(let details) = action else {
|
||||
return
|
||||
}
|
||||
|
||||
MXLog.info("Received session verification request")
|
||||
|
||||
if details.senderProfile.userID == userSession.clientProxy.userID {
|
||||
presentSessionVerificationScreen(flow: .deviceResponder(requestDetails: details))
|
||||
} else {
|
||||
presentSessionVerificationScreen(flow: .userResponder(requestDetails: details))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
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: flow,
|
||||
appSettings: appSettings,
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
let coordinator = SessionVerificationScreenCoordinator(parameters: parameters)
|
||||
|
||||
coordinator.actions
|
||||
.sink { [weak self] action in
|
||||
switch action {
|
||||
case .done:
|
||||
self?.navigationTabCoordinator.setSheetCoordinator(nil)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
|
||||
navigationTabCoordinator.setSheetCoordinator(navigationStackCoordinator)
|
||||
}
|
||||
|
||||
// MARK: - Logout
|
||||
|
||||
private func runLogoutFlow() async {
|
||||
let secureBackupController = userSession.clientProxy.secureBackupController
|
||||
|
||||
guard case let .success(isLastDevice) = await userSession.clientProxy.isOnlyDeviceLeft() else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init())
|
||||
return
|
||||
}
|
||||
|
||||
guard isLastDevice else {
|
||||
logout()
|
||||
return
|
||||
}
|
||||
|
||||
guard secureBackupController.recoveryState.value == .enabled else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutRecoveryDisabledTitle,
|
||||
message: L10n.screenSignoutRecoveryDisabledSubtitle,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
}, secondaryButton: .init(title: L10n.commonSettings, role: .cancel) { [weak self] in
|
||||
self?.chatsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
guard secureBackupController.keyBackupState.value == .enabled else {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutKeyBackupDisabledTitle,
|
||||
message: L10n.screenSignoutKeyBackupDisabledSubtitle,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
}, secondaryButton: .init(title: L10n.commonSettings, role: .cancel) { [weak self] in
|
||||
self?.chatsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
presentSecureBackupLogoutConfirmationScreen()
|
||||
}
|
||||
|
||||
private func logout() {
|
||||
ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenSignoutConfirmationDialogTitle,
|
||||
message: L10n.screenSignoutConfirmationDialogContent,
|
||||
primaryButton: .init(title: L10n.screenSignoutConfirmationDialogSubmit, role: .destructive) { [weak self] in
|
||||
self?.actionsSubject.send(.logout)
|
||||
})
|
||||
}
|
||||
|
||||
private func presentSecureBackupLogoutConfirmationScreen() {
|
||||
let coordinator = SecureBackupLogoutConfirmationScreenCoordinator(parameters: .init(secureBackupController: userSession.clientProxy.secureBackupController,
|
||||
appMediator: appMediator))
|
||||
|
||||
coordinator.actions
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .cancel:
|
||||
navigationTabCoordinator.setSheetCoordinator(nil)
|
||||
case .settings:
|
||||
chatsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
|
||||
navigationTabCoordinator.setSheetCoordinator(nil)
|
||||
case .logout:
|
||||
actionsSubject.send(.logout)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationTabCoordinator.setSheetCoordinator(coordinator, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user