mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Move navigation coordination away from the SettingsScreenCoordinator and into the SettingsFlowCoordinator
This commit is contained in:
@@ -454,6 +454,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
let navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
|
let navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
|
||||||
let userSessionFlowCoordinator = UserSessionFlowCoordinator(userSession: userSession,
|
let userSessionFlowCoordinator = UserSessionFlowCoordinator(userSession: userSession,
|
||||||
navigationSplitCoordinator: navigationSplitCoordinator,
|
navigationSplitCoordinator: navigationSplitCoordinator,
|
||||||
|
windowManager: windowManager,
|
||||||
appLockService: appLockFlowCoordinator.appLockService,
|
appLockService: appLockFlowCoordinator.appLockService,
|
||||||
bugReportService: ServiceLocator.shared.bugReportService,
|
bugReportService: ServiceLocator.shared.bugReportService,
|
||||||
roomTimelineControllerFactory: RoomTimelineControllerFactory(),
|
roomTimelineControllerFactory: RoomTimelineControllerFactory(),
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import SwiftUI
|
||||||
|
|
||||||
enum SettingsFlowCoordinatorAction {
|
enum SettingsFlowCoordinatorAction {
|
||||||
case presentedSettings
|
case presentedSettings
|
||||||
@@ -28,6 +28,7 @@ enum SettingsFlowCoordinatorAction {
|
|||||||
|
|
||||||
struct SettingsFlowCoordinatorParameters {
|
struct SettingsFlowCoordinatorParameters {
|
||||||
let userSession: UserSessionProtocol
|
let userSession: UserSessionProtocol
|
||||||
|
let windowManager: WindowManager
|
||||||
let appLockService: AppLockServiceProtocol
|
let appLockService: AppLockServiceProtocol
|
||||||
let bugReportService: BugReportServiceProtocol
|
let bugReportService: BugReportServiceProtocol
|
||||||
let notificationSettings: NotificationSettingsProxyProtocol
|
let notificationSettings: NotificationSettingsProxyProtocol
|
||||||
@@ -44,6 +45,9 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
// periphery:ignore - retaining purpose
|
||||||
|
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
|
||||||
|
|
||||||
private let actionsSubject: PassthroughSubject<SettingsFlowCoordinatorAction, Never> = .init()
|
private let actionsSubject: PassthroughSubject<SettingsFlowCoordinatorAction, Never> = .init()
|
||||||
var actions: AnyPublisher<SettingsFlowCoordinatorAction, Never> {
|
var actions: AnyPublisher<SettingsFlowCoordinatorAction, Never> {
|
||||||
actionsSubject.eraseToAnyPublisher()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
@@ -79,14 +83,9 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
private func presentSettingsScreen(animated: Bool) {
|
private func presentSettingsScreen(animated: Bool) {
|
||||||
navigationStackCoordinator = NavigationStackCoordinator()
|
navigationStackCoordinator = NavigationStackCoordinator()
|
||||||
|
|
||||||
let parameters = SettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator,
|
let parameters = SettingsScreenCoordinatorParameters(userSession: parameters.userSession,
|
||||||
userIndicatorController: parameters.userIndicatorController,
|
|
||||||
userSession: parameters.userSession,
|
|
||||||
appLockService: parameters.appLockService,
|
|
||||||
bugReportService: parameters.bugReportService,
|
|
||||||
notificationSettings: parameters.userSession.clientProxy.notificationSettings,
|
|
||||||
secureBackupController: parameters.userSession.clientProxy.secureBackupController,
|
|
||||||
appSettings: parameters.appSettings)
|
appSettings: parameters.appSettings)
|
||||||
|
|
||||||
let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters)
|
let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters)
|
||||||
|
|
||||||
settingsScreenCoordinator.actions
|
settingsScreenCoordinator.actions
|
||||||
@@ -103,12 +102,30 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
self.actionsSubject.send(.runLogoutFlow)
|
self.actionsSubject.send(.runLogoutFlow)
|
||||||
}
|
}
|
||||||
case .clearCache:
|
|
||||||
actionsSubject.send(.clearCache)
|
|
||||||
case .secureBackup:
|
case .secureBackup:
|
||||||
presentSecureBackupScreen(animated: true)
|
presentSecureBackupScreen(animated: true)
|
||||||
case .forceLogout:
|
case .userDetails:
|
||||||
actionsSubject.send(.forceLogout)
|
presentUserDetailsEditScreen()
|
||||||
|
case .accountProfile:
|
||||||
|
presentAccountProfileURL()
|
||||||
|
case .analytics:
|
||||||
|
presentAnalyticsScreen()
|
||||||
|
case .appLock:
|
||||||
|
presentAppLockSetupFlow()
|
||||||
|
case .bugReport:
|
||||||
|
presentBugReportScreen()
|
||||||
|
case .about:
|
||||||
|
presentLegalInformationScreen()
|
||||||
|
case .sessionVerification:
|
||||||
|
presentSessionVerificationScreen()
|
||||||
|
case .accountSessions:
|
||||||
|
presentAccountSessionsListURL()
|
||||||
|
case .notifications:
|
||||||
|
presentNotificationSettings()
|
||||||
|
case .advancedSettings:
|
||||||
|
presentAdvancedSettings()
|
||||||
|
case .developerOptions:
|
||||||
|
presentDeveloperOptions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
@@ -133,4 +150,151 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
navigationStackCoordinator.push(coordinator, animated: animated)
|
navigationStackCoordinator.push(coordinator, animated: animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func presentUserDetailsEditScreen() {
|
||||||
|
let coordinator = UserDetailsEditScreenCoordinator(parameters: .init(clientProxy: parameters.userSession.clientProxy,
|
||||||
|
mediaProvider: parameters.userSession.mediaProvider,
|
||||||
|
navigationStackCoordinator: navigationStackCoordinator,
|
||||||
|
userIndicatorController: parameters.userIndicatorController))
|
||||||
|
|
||||||
|
navigationStackCoordinator?.push(coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentAnalyticsScreen() {
|
||||||
|
let coordinator = AnalyticsSettingsScreenCoordinator(parameters: .init(appSettings: parameters.appSettings,
|
||||||
|
analytics: ServiceLocator.shared.analytics))
|
||||||
|
navigationStackCoordinator?.push(coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentAppLockSetupFlow() {
|
||||||
|
let coordinator = AppLockSetupFlowCoordinator(presentingFlow: .settings,
|
||||||
|
appLockService: parameters.appLockService,
|
||||||
|
navigationStackCoordinator: navigationStackCoordinator)
|
||||||
|
coordinator.actions.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
switch action {
|
||||||
|
case .complete:
|
||||||
|
// The flow coordinator tidies up the stack, no need to do anything.
|
||||||
|
appLockSetupFlowCoordinator = nil
|
||||||
|
case .forceLogout:
|
||||||
|
actionsSubject.send(.forceLogout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
appLockSetupFlowCoordinator = coordinator
|
||||||
|
coordinator.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentBugReportScreen() {
|
||||||
|
let params = BugReportScreenCoordinatorParameters(bugReportService: parameters.bugReportService,
|
||||||
|
userID: parameters.userSession.userID,
|
||||||
|
deviceID: parameters.userSession.deviceID,
|
||||||
|
userIndicatorController: parameters.userIndicatorController,
|
||||||
|
screenshot: nil,
|
||||||
|
isModallyPresented: false)
|
||||||
|
let coordinator = BugReportScreenCoordinator(parameters: params)
|
||||||
|
coordinator.completion = { [weak self] result in
|
||||||
|
switch result {
|
||||||
|
case .finish:
|
||||||
|
self?.showSuccess(label: L10n.actionDone)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
self?.navigationStackCoordinator.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationStackCoordinator.push(coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentLegalInformationScreen() {
|
||||||
|
navigationStackCoordinator.push(LegalInformationScreenCoordinator(appSettings: parameters.appSettings))
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentSessionVerificationScreen() {
|
||||||
|
guard let sessionVerificationController = parameters.userSession.sessionVerificationController else {
|
||||||
|
fatalError("The sessionVerificationController should aways be valid at this point")
|
||||||
|
}
|
||||||
|
|
||||||
|
let verificationParameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController)
|
||||||
|
let coordinator = SessionVerificationScreenCoordinator(parameters: verificationParameters)
|
||||||
|
|
||||||
|
coordinator.actions
|
||||||
|
.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case .done:
|
||||||
|
navigationStackCoordinator.setSheetCoordinator(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
navigationStackCoordinator.setSheetCoordinator(coordinator) { [weak self] in
|
||||||
|
self?.navigationStackCoordinator.setSheetCoordinator(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentNotificationSettings() {
|
||||||
|
let notificationParameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator,
|
||||||
|
userSession: parameters.userSession,
|
||||||
|
userNotificationCenter: UNUserNotificationCenter.current(),
|
||||||
|
notificationSettings: parameters.notificationSettings,
|
||||||
|
isModallyPresented: false)
|
||||||
|
let coordinator = NotificationSettingsScreenCoordinator(parameters: notificationParameters)
|
||||||
|
navigationStackCoordinator.push(coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentAdvancedSettings() {
|
||||||
|
let coordinator = AdvancedSettingsScreenCoordinator()
|
||||||
|
navigationStackCoordinator.push(coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentDeveloperOptions() {
|
||||||
|
let coordinator = DeveloperOptionsScreenCoordinator()
|
||||||
|
|
||||||
|
coordinator.actions
|
||||||
|
.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case .clearCache:
|
||||||
|
actionsSubject.send(.clearCache)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
navigationStackCoordinator.push(coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showSuccess(label: String) {
|
||||||
|
parameters.userIndicatorController.submitIndicator(UserIndicator(title: label))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: OIDC Account Management
|
||||||
|
|
||||||
|
private func presentAccountProfileURL() {
|
||||||
|
guard let url = parameters.userSession.clientProxy.accountURL(action: .profile) else {
|
||||||
|
MXLog.error("Account URL is missing.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
presentAccountManagementURL(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentAccountSessionsListURL() {
|
||||||
|
guard let url = parameters.userSession.clientProxy.accountURL(action: .sessionsList) else {
|
||||||
|
MXLog.error("Account URL is missing.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
presentAccountManagementURL(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var accountSettingsPresenter: OIDCAccountSettingsPresenter?
|
||||||
|
private func presentAccountManagementURL(_ url: URL) {
|
||||||
|
// Note to anyone in the future if you come back here to make this open in Safari instead of a WAS.
|
||||||
|
// As of iOS 16, there is an issue on the simulator with accessing the cookie but it works on a device. 🤷♂️
|
||||||
|
accountSettingsPresenter = OIDCAccountSettingsPresenter(accountURL: url, presentationAnchor: parameters.windowManager.mainWindow)
|
||||||
|
accountSettingsPresenter?.start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
init(userSession: UserSessionProtocol,
|
init(userSession: UserSessionProtocol,
|
||||||
navigationSplitCoordinator: NavigationSplitCoordinator,
|
navigationSplitCoordinator: NavigationSplitCoordinator,
|
||||||
|
windowManager: WindowManager,
|
||||||
appLockService: AppLockServiceProtocol,
|
appLockService: AppLockServiceProtocol,
|
||||||
bugReportService: BugReportServiceProtocol,
|
bugReportService: BugReportServiceProtocol,
|
||||||
roomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol,
|
roomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol,
|
||||||
@@ -75,6 +76,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||||
|
|
||||||
settingsFlowCoordinator = SettingsFlowCoordinator(parameters: .init(userSession: userSession,
|
settingsFlowCoordinator = SettingsFlowCoordinator(parameters: .init(userSession: userSession,
|
||||||
|
windowManager: windowManager,
|
||||||
appLockService: appLockService,
|
appLockService: appLockService,
|
||||||
bugReportService: bugReportService,
|
bugReportService: bugReportService,
|
||||||
notificationSettings: userSession.clientProxy.notificationSettings,
|
notificationSettings: userSession.clientProxy.notificationSettings,
|
||||||
|
|||||||
@@ -18,32 +18,31 @@ import Combine
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SettingsScreenCoordinatorParameters {
|
struct SettingsScreenCoordinatorParameters {
|
||||||
weak var navigationStackCoordinator: NavigationStackCoordinator?
|
|
||||||
let userIndicatorController: UserIndicatorControllerProtocol
|
|
||||||
let userSession: UserSessionProtocol
|
let userSession: UserSessionProtocol
|
||||||
let appLockService: AppLockServiceProtocol
|
|
||||||
let bugReportService: BugReportServiceProtocol
|
|
||||||
let notificationSettings: NotificationSettingsProxyProtocol
|
|
||||||
let secureBackupController: SecureBackupControllerProtocol
|
|
||||||
let appSettings: AppSettings
|
let appSettings: AppSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SettingsScreenCoordinatorAction {
|
enum SettingsScreenCoordinatorAction {
|
||||||
case dismiss
|
case dismiss
|
||||||
case logout
|
case logout
|
||||||
case clearCache
|
|
||||||
case secureBackup
|
case secureBackup
|
||||||
/// Logout without a confirmation. The user forgot their PIN.
|
case userDetails
|
||||||
case forceLogout
|
case accountProfile
|
||||||
|
case analytics
|
||||||
|
case appLock
|
||||||
|
case bugReport
|
||||||
|
case about
|
||||||
|
case sessionVerification
|
||||||
|
case accountSessions
|
||||||
|
case notifications
|
||||||
|
case advancedSettings
|
||||||
|
case developerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SettingsScreenCoordinator: CoordinatorProtocol {
|
final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||||
private let parameters: SettingsScreenCoordinatorParameters
|
private let parameters: SettingsScreenCoordinatorParameters
|
||||||
private var viewModel: SettingsScreenViewModelProtocol
|
private var viewModel: SettingsScreenViewModelProtocol
|
||||||
|
|
||||||
// periphery:ignore - retaining purpose
|
|
||||||
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
|
|
||||||
|
|
||||||
private let actionsSubject: PassthroughSubject<SettingsScreenCoordinatorAction, Never> = .init()
|
private let actionsSubject: PassthroughSubject<SettingsScreenCoordinatorAction, Never> = .init()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
@@ -67,29 +66,29 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
|||||||
case .close:
|
case .close:
|
||||||
actionsSubject.send(.dismiss)
|
actionsSubject.send(.dismiss)
|
||||||
case .userDetails:
|
case .userDetails:
|
||||||
presentUserDetailsEditScreen()
|
actionsSubject.send(.userDetails)
|
||||||
case .accountProfile:
|
case .accountProfile:
|
||||||
presentAccountProfileURL()
|
actionsSubject.send(.accountProfile)
|
||||||
case .analytics:
|
case .analytics:
|
||||||
presentAnalyticsScreen()
|
actionsSubject.send(.analytics)
|
||||||
case .appLock:
|
case .appLock:
|
||||||
presentAppLockSetupFlow()
|
actionsSubject.send(.appLock)
|
||||||
case .reportBug:
|
case .reportBug:
|
||||||
presentBugReportScreen()
|
actionsSubject.send(.bugReport)
|
||||||
case .about:
|
case .about:
|
||||||
presentLegalInformationScreen()
|
actionsSubject.send(.about)
|
||||||
case .sessionVerification:
|
case .sessionVerification:
|
||||||
presentSessionVerificationScreen()
|
actionsSubject.send(.sessionVerification)
|
||||||
case .secureBackup:
|
case .secureBackup:
|
||||||
actionsSubject.send(.secureBackup)
|
actionsSubject.send(.secureBackup)
|
||||||
case .accountSessionsList:
|
case .accountSessionsList:
|
||||||
presentAccountSessionsListURL()
|
actionsSubject.send(.accountSessions)
|
||||||
case .notifications:
|
case .notifications:
|
||||||
presentNotificationSettings()
|
actionsSubject.send(.notifications)
|
||||||
case .advancedSettings:
|
case .advancedSettings:
|
||||||
self.presentAdvancedSettings()
|
actionsSubject.send(.advancedSettings)
|
||||||
case .developerOptions:
|
case .developerOptions:
|
||||||
presentDeveloperOptions()
|
actionsSubject.send(.developerOptions)
|
||||||
case .logout:
|
case .logout:
|
||||||
actionsSubject.send(.logout)
|
actionsSubject.send(.logout)
|
||||||
}
|
}
|
||||||
@@ -102,163 +101,4 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
|||||||
func toPresentable() -> AnyView {
|
func toPresentable() -> AnyView {
|
||||||
AnyView(SettingsScreen(context: viewModel.context))
|
AnyView(SettingsScreen(context: viewModel.context))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - OIDC Account Management
|
|
||||||
|
|
||||||
private func presentAccountProfileURL() {
|
|
||||||
guard let url = viewModel.context.viewState.accountProfileURL else {
|
|
||||||
MXLog.error("Account URL is missing.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
presentAccountManagementURL(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentAccountSessionsListURL() {
|
|
||||||
guard let url = viewModel.context.viewState.accountSessionsListURL else {
|
|
||||||
MXLog.error("Account URL is missing.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
presentAccountManagementURL(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var accountSettingsPresenter: OIDCAccountSettingsPresenter?
|
|
||||||
private func presentAccountManagementURL(_ url: URL) {
|
|
||||||
guard let window = viewModel.context.viewState.window else {
|
|
||||||
MXLog.error("The window is missing.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note to anyone in the future if you come back here to make this open in Safari instead of a WAS.
|
|
||||||
// As of iOS 16, there is an issue on the simulator with accessing the cookie but it works on a device. 🤷♂️
|
|
||||||
accountSettingsPresenter = OIDCAccountSettingsPresenter(accountURL: url, presentationAnchor: window)
|
|
||||||
accountSettingsPresenter?.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private
|
|
||||||
|
|
||||||
private func presentUserDetailsEditScreen() {
|
|
||||||
let coordinator = UserDetailsEditScreenCoordinator(parameters: .init(clientProxy: parameters.userSession.clientProxy,
|
|
||||||
mediaProvider: parameters.userSession.mediaProvider,
|
|
||||||
navigationStackCoordinator: parameters.navigationStackCoordinator,
|
|
||||||
userIndicatorController: parameters.userIndicatorController))
|
|
||||||
|
|
||||||
parameters.navigationStackCoordinator?.push(coordinator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentAnalyticsScreen() {
|
|
||||||
let coordinator = AnalyticsSettingsScreenCoordinator(parameters: .init(appSettings: parameters.appSettings,
|
|
||||||
analytics: ServiceLocator.shared.analytics))
|
|
||||||
parameters.navigationStackCoordinator?.push(coordinator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentAppLockSetupFlow() {
|
|
||||||
guard let navigationStackCoordinator = parameters.navigationStackCoordinator else {
|
|
||||||
MXLog.error("The navigation stack has gone! 🌫️")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let coordinator = AppLockSetupFlowCoordinator(presentingFlow: .settings,
|
|
||||||
appLockService: parameters.appLockService,
|
|
||||||
navigationStackCoordinator: navigationStackCoordinator)
|
|
||||||
coordinator.actions.sink { [weak self] action in
|
|
||||||
guard let self else { return }
|
|
||||||
switch action {
|
|
||||||
case .complete:
|
|
||||||
// The flow coordinator tidies up the stack, no need to do anything.
|
|
||||||
appLockSetupFlowCoordinator = nil
|
|
||||||
case .forceLogout:
|
|
||||||
actionsSubject.send(.forceLogout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
appLockSetupFlowCoordinator = coordinator
|
|
||||||
coordinator.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentBugReportScreen() {
|
|
||||||
let params = BugReportScreenCoordinatorParameters(bugReportService: parameters.bugReportService,
|
|
||||||
userID: parameters.userSession.userID,
|
|
||||||
deviceID: parameters.userSession.deviceID,
|
|
||||||
userIndicatorController: parameters.userIndicatorController,
|
|
||||||
screenshot: nil,
|
|
||||||
isModallyPresented: false)
|
|
||||||
let coordinator = BugReportScreenCoordinator(parameters: params)
|
|
||||||
coordinator.completion = { [weak self] result in
|
|
||||||
switch result {
|
|
||||||
case .finish:
|
|
||||||
self?.showSuccess(label: L10n.actionDone)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
self?.parameters.navigationStackCoordinator?.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
parameters.navigationStackCoordinator?.push(coordinator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentLegalInformationScreen() {
|
|
||||||
parameters.navigationStackCoordinator?.push(LegalInformationScreenCoordinator(appSettings: parameters.appSettings))
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentSessionVerificationScreen() {
|
|
||||||
guard let sessionVerificationController = parameters.userSession.sessionVerificationController else {
|
|
||||||
fatalError("The sessionVerificationController should aways be valid at this point")
|
|
||||||
}
|
|
||||||
|
|
||||||
let verificationParameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController)
|
|
||||||
let coordinator = SessionVerificationScreenCoordinator(parameters: verificationParameters)
|
|
||||||
|
|
||||||
coordinator.actions
|
|
||||||
.sink { [weak self] action in
|
|
||||||
guard let self else { return }
|
|
||||||
|
|
||||||
switch action {
|
|
||||||
case .done:
|
|
||||||
parameters.navigationStackCoordinator?.setSheetCoordinator(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
parameters.navigationStackCoordinator?.setSheetCoordinator(coordinator) { [weak self] in
|
|
||||||
self?.parameters.navigationStackCoordinator?.setSheetCoordinator(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentNotificationSettings() {
|
|
||||||
let notificationParameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: parameters.navigationStackCoordinator,
|
|
||||||
userSession: parameters.userSession,
|
|
||||||
userNotificationCenter: UNUserNotificationCenter.current(),
|
|
||||||
notificationSettings: parameters.notificationSettings,
|
|
||||||
isModallyPresented: false)
|
|
||||||
let coordinator = NotificationSettingsScreenCoordinator(parameters: notificationParameters)
|
|
||||||
parameters.navigationStackCoordinator?.push(coordinator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentAdvancedSettings() {
|
|
||||||
let coordinator = AdvancedSettingsScreenCoordinator()
|
|
||||||
parameters.navigationStackCoordinator?.push(coordinator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func presentDeveloperOptions() {
|
|
||||||
let coordinator = DeveloperOptionsScreenCoordinator()
|
|
||||||
|
|
||||||
coordinator.actions
|
|
||||||
.sink { [weak self] action in
|
|
||||||
guard let self else { return }
|
|
||||||
|
|
||||||
switch action {
|
|
||||||
case .clearCache:
|
|
||||||
actionsSubject.send(.clearCache)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
parameters.navigationStackCoordinator?.push(coordinator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func showSuccess(label: String) {
|
|
||||||
parameters.userIndicatorController.submitIndicator(UserIndicator(title: label))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,9 +44,6 @@ struct SettingsScreenViewState: BindableState {
|
|||||||
var isSessionVerified: Bool?
|
var isSessionVerified: Bool?
|
||||||
var showSecureBackupBadge = false
|
var showSecureBackupBadge = false
|
||||||
var showDeveloperOptions: Bool
|
var showDeveloperOptions: Bool
|
||||||
|
|
||||||
/// The presentation anchor used to display the OIDC account URL.
|
|
||||||
var window: UIWindow?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SettingsScreenViewAction {
|
enum SettingsScreenViewAction {
|
||||||
@@ -64,7 +61,4 @@ enum SettingsScreenViewAction {
|
|||||||
case developerOptions
|
case developerOptions
|
||||||
case advancedSettings
|
case advancedSettings
|
||||||
case logout
|
case logout
|
||||||
|
|
||||||
/// Updates the window used for the OIDC account URL anchor.
|
|
||||||
case updateWindow(UIWindow)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,12 +94,6 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
|
|||||||
actionsSubject.send(.advancedSettings)
|
actionsSubject.send(.advancedSettings)
|
||||||
case .developerOptions:
|
case .developerOptions:
|
||||||
actionsSubject.send(.developerOptions)
|
actionsSubject.send(.developerOptions)
|
||||||
|
|
||||||
case .updateWindow(let window):
|
|
||||||
Task {
|
|
||||||
guard state.window != window else { return }
|
|
||||||
state.window = window
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ struct SettingsScreen: View {
|
|||||||
.navigationTitle(L10n.commonSettings)
|
.navigationTitle(L10n.commonSettings)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.toolbar { toolbar }
|
.toolbar { toolbar }
|
||||||
.introspect(.window, on: .supportedVersions) { window in
|
|
||||||
context.send(viewAction: .updateWindow(window))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var userSection: some View {
|
private var userSection: some View {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate {
|
|||||||
func start() {
|
func start() {
|
||||||
guard let screenID = ProcessInfo.testScreenID else { fatalError("Unable to launch with unknown screen.") }
|
guard let screenID = ProcessInfo.testScreenID else { fatalError("Unable to launch with unknown screen.") }
|
||||||
|
|
||||||
let mockScreen = MockScreen(id: screenID)
|
let mockScreen = MockScreen(id: screenID, windowManager: windowManager)
|
||||||
navigationRootCoordinator.setRootCoordinator(mockScreen.coordinator)
|
navigationRootCoordinator.setRootCoordinator(mockScreen.coordinator)
|
||||||
self.mockScreen = mockScreen
|
self.mockScreen = mockScreen
|
||||||
}
|
}
|
||||||
@@ -79,12 +79,12 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate {
|
|||||||
@MainActor
|
@MainActor
|
||||||
class MockScreen: Identifiable {
|
class MockScreen: Identifiable {
|
||||||
let id: UITestsScreenIdentifier
|
let id: UITestsScreenIdentifier
|
||||||
let windowManager: WindowManager?
|
let windowManager: WindowManager
|
||||||
|
|
||||||
private var retainedState = [Any]()
|
private var retainedState = [Any]()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
init(id: UITestsScreenIdentifier, windowManager: WindowManager? = nil) {
|
init(id: UITestsScreenIdentifier, windowManager: WindowManager) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.windowManager = windowManager
|
self.windowManager = windowManager
|
||||||
}
|
}
|
||||||
@@ -209,10 +209,10 @@ class MockScreen: Identifiable {
|
|||||||
navigationCoordinator: navigationCoordinator,
|
navigationCoordinator: navigationCoordinator,
|
||||||
notificationCenter: notificationCenter)
|
notificationCenter: notificationCenter)
|
||||||
|
|
||||||
guard let windowManager else { fatalError("The window manager must be supplied.") }
|
|
||||||
|
|
||||||
coordinator.actions
|
coordinator.actions
|
||||||
.sink { action in
|
.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case .lockApp:
|
case .lockApp:
|
||||||
windowManager.switchToAlternate()
|
windowManager.switchToAlternate()
|
||||||
@@ -268,16 +268,9 @@ class MockScreen: Identifiable {
|
|||||||
case .settings:
|
case .settings:
|
||||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||||
let clientProxy = MockClientProxy(userID: "@mock:client.com")
|
let clientProxy = MockClientProxy(userID: "@mock:client.com")
|
||||||
let coordinator = SettingsScreenCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator,
|
let coordinator = SettingsScreenCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: clientProxy,
|
||||||
userIndicatorController: UserIndicatorControllerMock(),
|
|
||||||
userSession: MockUserSession(clientProxy: clientProxy,
|
|
||||||
mediaProvider: MockMediaProvider(),
|
mediaProvider: MockMediaProvider(),
|
||||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
||||||
appLockService: AppLockService(keychainController: KeychainControllerMock(),
|
|
||||||
appSettings: ServiceLocator.shared.settings),
|
|
||||||
bugReportService: BugReportServiceMock(),
|
|
||||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
|
||||||
secureBackupController: SecureBackupControllerMock(),
|
|
||||||
appSettings: ServiceLocator.shared.settings))
|
appSettings: ServiceLocator.shared.settings))
|
||||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||||
return navigationStackCoordinator
|
return navigationStackCoordinator
|
||||||
@@ -566,6 +559,7 @@ class MockScreen: Identifiable {
|
|||||||
|
|
||||||
let coordinator = UserSessionFlowCoordinator(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider(), voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
let coordinator = UserSessionFlowCoordinator(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider(), voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
||||||
navigationSplitCoordinator: navigationSplitCoordinator,
|
navigationSplitCoordinator: navigationSplitCoordinator,
|
||||||
|
windowManager: windowManager,
|
||||||
appLockService: AppLockService(keychainController: KeychainControllerMock(),
|
appLockService: AppLockService(keychainController: KeychainControllerMock(),
|
||||||
appSettings: ServiceLocator.shared.settings),
|
appSettings: ServiceLocator.shared.settings),
|
||||||
bugReportService: BugReportServiceMock(),
|
bugReportService: BugReportServiceMock(),
|
||||||
|
|||||||
Reference in New Issue
Block a user