diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 78d1f920e..a225fe842 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -640,19 +640,23 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg fatalError("User session not setup") } - let userSessionFlowCoordinator = UserSessionFlowCoordinator(userSession: userSession, - isNewLogin: isNewLogin, + let flowParameters = CommonFlowParameters(userSession: userSession, + bugReportService: ServiceLocator.shared.bugReportService, + elementCallService: elementCallService, + timelineControllerFactory: TimelineControllerFactory(), + emojiProvider: EmojiProvider(appSettings: appSettings), + appMediator: appMediator, + appSettings: appSettings, + appHooks: appHooks, + analytics: ServiceLocator.shared.analytics, + userIndicatorController: ServiceLocator.shared.userIndicatorController, + notificationManager: notificationManager, + stateMachineFactory: StateMachineFactory()) + + let userSessionFlowCoordinator = UserSessionFlowCoordinator(isNewLogin: isNewLogin, navigationRootCoordinator: navigationRootCoordinator, appLockService: appLockFlowCoordinator.appLockService, - bugReportService: ServiceLocator.shared.bugReportService, - elementCallService: elementCallService, - timelineControllerFactory: TimelineControllerFactory(), - appMediator: appMediator, - appSettings: appSettings, - appHooks: appHooks, - analytics: ServiceLocator.shared.analytics, - notificationManager: notificationManager, - stateMachineFactory: StateMachineFactory()) + flowParameters: flowParameters) userSessionFlowCoordinator.actionsPublisher .sink { [weak self] action in diff --git a/ElementX/Sources/Application/FlowCoordinatorProtocol.swift b/ElementX/Sources/Application/FlowCoordinatorProtocol.swift index 48b05606b..e460813f6 100644 --- a/ElementX/Sources/Application/FlowCoordinatorProtocol.swift +++ b/ElementX/Sources/Application/FlowCoordinatorProtocol.swift @@ -14,3 +14,25 @@ protocol FlowCoordinatorProtocol { func handleAppRoute(_ appRoute: AppRoute, animated: Bool) func clearRoute(animated: Bool) } + +/// Core parameters that are shared across the main flows for easy dependency injection. +/// +/// Please do **not** pass this type directly to screen coordinators/view models. +@MainActor +struct CommonFlowParameters { + let userSession: UserSessionProtocol + let bugReportService: BugReportServiceProtocol + let elementCallService: ElementCallServiceProtocol + let timelineControllerFactory: TimelineControllerFactoryProtocol + let emojiProvider: EmojiProviderProtocol + let appMediator: AppMediatorProtocol + let appSettings: AppSettings + let appHooks: AppHooks + let analytics: AnalyticsService + let userIndicatorController: UserIndicatorControllerProtocol + let notificationManager: NotificationManagerProtocol + let stateMachineFactory: StateMachineFactoryProtocol + + var windowManager: WindowManagerProtocol { appMediator.windowManager } + var ongoingCallRoomIDPublisher: CurrentValuePublisher { elementCallService.ongoingCallRoomIDPublisher } +} diff --git a/ElementX/Sources/FlowCoordinators/ChatsFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/ChatsFlowCoordinator.swift index 503cad8c1..e6758418c 100644 --- a/ElementX/Sources/FlowCoordinators/ChatsFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/ChatsFlowCoordinator.swift @@ -19,21 +19,15 @@ enum ChatsFlowCoordinatorAction { } class ChatsFlowCoordinator: FlowCoordinatorProtocol { - private let userSession: UserSessionProtocol private let navigationSplitCoordinator: NavigationSplitCoordinator - private let bugReportService: BugReportServiceProtocol - private let elementCallService: ElementCallServiceProtocol - private let appMediator: AppMediatorProtocol - private let appSettings: AppSettings - private let appHooks: AppHooks - private let analytics: AnalyticsService - private let notificationManager: NotificationManagerProtocol + private let flowParameters: CommonFlowParameters + + private var userSession: UserSessionProtocol { flowParameters.userSession } private let stateMachine: ChatsFlowCoordinatorStateMachine // periphery:ignore - retaining purpose private var roomFlowCoordinator: RoomFlowCoordinator? - private let timelineControllerFactory: TimelineControllerFactoryProtocol // periphery:ignore - retaining purpose private var bugReportFlowCoordinator: BugReportFlowCoordinator? @@ -56,30 +50,12 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { actionsSubject.eraseToAnyPublisher() } - init(userSession: UserSessionProtocol, - isNewLogin: Bool, + init(isNewLogin: Bool, navigationSplitCoordinator: NavigationSplitCoordinator, - appLockService: AppLockServiceProtocol, - bugReportService: BugReportServiceProtocol, - elementCallService: ElementCallServiceProtocol, - timelineControllerFactory: TimelineControllerFactoryProtocol, - appMediator: AppMediatorProtocol, - appSettings: AppSettings, - appHooks: AppHooks, - analytics: AnalyticsService, - notificationManager: NotificationManagerProtocol, - stateMachineFactory: StateMachineFactoryProtocol) { - stateMachine = stateMachineFactory.makeChatsFlowStateMachine() - self.userSession = userSession + flowParameters: CommonFlowParameters) { + stateMachine = flowParameters.stateMachineFactory.makeChatsFlowStateMachine() self.navigationSplitCoordinator = navigationSplitCoordinator - self.bugReportService = bugReportService - self.elementCallService = elementCallService - self.timelineControllerFactory = timelineControllerFactory - self.appMediator = appMediator - self.appSettings = appSettings - self.appHooks = appHooks - self.analytics = analytics - self.notificationManager = notificationManager + self.flowParameters = flowParameters sidebarNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator) detailNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator) @@ -230,8 +206,8 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { case (.roomList, .feedbackScreen, .feedbackScreen): bugReportFlowCoordinator = BugReportFlowCoordinator(parameters: .init(presentationMode: .sheet(sidebarNavigationStackCoordinator), - userIndicatorController: ServiceLocator.shared.userIndicatorController, - bugReportService: bugReportService, + userIndicatorController: flowParameters.userIndicatorController, + bugReportService: flowParameters.bugReportService, userSession: userSession)) bugReportFlowCoordinator?.start() case (.feedbackScreen, .dismissedFeedbackScreen, .roomList): @@ -319,7 +295,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { case .receivedSyncUpdate: Task { let roomSummaries = self.userSession.clientProxy.staticRoomSummaryProvider.roomListPublisher.value - await self.notificationManager.removeDeliveredNotificationsForFullyReadRooms(roomSummaries) + await self.flowParameters.notificationManager.removeDeliveredNotificationsForFullyReadRooms(roomSummaries) } default: break @@ -327,7 +303,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { } .store(in: &cancellables) - elementCallService.actions + flowParameters.elementCallService.actions .receive(on: DispatchQueue.main) .sink { [weak self] action in switch action { @@ -358,25 +334,25 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { case .withheldBySender: .OlmKeysNotSentError } - analytics.trackError(context: nil, - domain: .E2EE, - name: errorName, - timeToDecryptMillis: timeToDecryptMs, - eventLocalAgeMillis: Int(truncatingIfNeeded: info.eventLocalAgeMillis), - isFederated: info.ownHomeserver != info.senderHomeserver, - isMatrixDotOrg: info.ownHomeserver == "matrix.org", - userTrustsOwnIdentity: info.userTrustsOwnIdentity, - wasVisibleToUser: nil) + flowParameters.analytics.trackError(context: nil, + domain: .E2EE, + name: errorName, + timeToDecryptMillis: timeToDecryptMs, + eventLocalAgeMillis: Int(truncatingIfNeeded: info.eventLocalAgeMillis), + isFederated: info.ownHomeserver != info.senderHomeserver, + isMatrixDotOrg: info.ownHomeserver == "matrix.org", + userTrustsOwnIdentity: info.userTrustsOwnIdentity, + wasVisibleToUser: nil) } private func presentHomeScreen() { let parameters = HomeScreenCoordinatorParameters(userSession: userSession, - bugReportService: bugReportService, + bugReportService: flowParameters.bugReportService, selectedRoomPublisher: selectedRoomSubject.asCurrentValuePublisher(), - appSettings: appSettings, - analyticsService: analytics, - notificationManager: notificationManager, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + appSettings: flowParameters.appSettings, + analyticsService: flowParameters.analytics, + notificationManager: flowParameters.notificationManager, + userIndicatorController: flowParameters.userIndicatorController) let coordinator = HomeScreenCoordinator(parameters: parameters) coordinator.actions @@ -431,7 +407,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { let navigationStackCoordinator = NavigationStackCoordinator() let coordinator = ReportRoomScreenCoordinator(parameters: .init(roomProxy: roomProxy, - userIndicatorController: ServiceLocator.shared.userIndicatorController)) + userIndicatorController: flowParameters.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } switch action { @@ -456,7 +432,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { let coordinator = DeclineAndBlockScreenCoordinator(parameters: .init(userID: userID, roomID: roomID, clientProxy: userSession.clientProxy, - userIndicatorController: ServiceLocator.shared.userIndicatorController)) + userIndicatorController: flowParameters.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } @@ -480,17 +456,9 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { entryPoint: RoomFlowCoordinatorEntryPoint, animated: Bool) { let coordinator = RoomFlowCoordinator(roomID: roomID, - userSession: userSession, isChildFlow: false, - timelineControllerFactory: timelineControllerFactory, navigationStackCoordinator: detailNavigationStackCoordinator, - emojiProvider: EmojiProvider(appSettings: appSettings), - ongoingCallRoomIDPublisher: elementCallService.ongoingCallRoomIDPublisher, - appMediator: appMediator, - appSettings: appSettings, - appHooks: appHooks, - analytics: analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + flowParameters: flowParameters) coordinator.actions.sink { [weak self] action in guard let self else { return } @@ -528,7 +496,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { Task { let _ = await userSession.clientProxy.trackRecentlyVisitedRoom(roomID) - await notificationManager.removeDeliveredMessageNotifications(for: roomID) + await flowParameters.notificationManager.removeDeliveredMessageNotifications(for: roomID) } } @@ -544,13 +512,13 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { let startChatNavigationStackCoordinator = NavigationStackCoordinator() let userDiscoveryService = UserDiscoveryService(clientProxy: userSession.clientProxy) - let parameters = StartChatScreenCoordinatorParameters(orientationManager: appMediator.windowManager, + let parameters = StartChatScreenCoordinatorParameters(orientationManager: flowParameters.windowManager, userSession: userSession, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: flowParameters.userIndicatorController, navigationStackCoordinator: startChatNavigationStackCoordinator, userDiscoveryService: userDiscoveryService, - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings), - appSettings: appSettings) + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: flowParameters.appSettings), + appSettings: flowParameters.appSettings) let coordinator = StartChatScreenCoordinator(parameters: parameters) coordinator.actions.sink { [weak self] action in @@ -590,27 +558,27 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { } private func presentCallScreen(roomProxy: JoinedRoomProxyProtocol) { - let colorScheme: ColorScheme = appMediator.windowManager.mainWindow.traitCollection.userInterfaceStyle == .light ? .light : .dark + let colorScheme: ColorScheme = flowParameters.windowManager.mainWindow.traitCollection.userInterfaceStyle == .light ? .light : .dark presentCallScreen(configuration: .init(roomProxy: roomProxy, clientProxy: userSession.clientProxy, clientID: InfoPlistReader.main.bundleIdentifier, - elementCallBaseURL: appSettings.elementCallBaseURL, - elementCallBaseURLOverride: appSettings.elementCallBaseURLOverride, + elementCallBaseURL: flowParameters.appSettings.elementCallBaseURL, + elementCallBaseURLOverride: flowParameters.appSettings.elementCallBaseURLOverride, colorScheme: colorScheme)) } private var callScreenPictureInPictureController: AVPictureInPictureController? private func presentCallScreen(configuration: ElementCallConfiguration) { - guard elementCallService.ongoingCallRoomIDPublisher.value != configuration.callRoomID else { + guard flowParameters.ongoingCallRoomIDPublisher.value != configuration.callRoomID else { MXLog.info("Returning to existing call.") callScreenPictureInPictureController?.stopPictureInPicture() return } - let callScreenCoordinator = CallScreenCoordinator(parameters: .init(elementCallService: elementCallService, + let callScreenCoordinator = CallScreenCoordinator(parameters: .init(elementCallService: flowParameters.elementCallService, configuration: configuration, allowPictureInPicture: true, - appHooks: appHooks)) + appHooks: flowParameters.appHooks)) callScreenCoordinator.actions .sink { [weak self] action in @@ -633,7 +601,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { navigationSplitCoordinator.setOverlayCoordinator(callScreenCoordinator, animated: true) - analytics.track(screen: .RoomCall) + flowParameters.analytics.track(screen: .RoomCall) } private func hideCallScreenOverlay() { @@ -661,7 +629,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { private func presentRecoveryKeyScreen(animated: Bool) { let sheetNavigationStackCoordinator = NavigationStackCoordinator() let parameters = SecureBackupRecoveryKeyScreenCoordinatorParameters(secureBackupController: userSession.clientProxy.secureBackupController, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: flowParameters.userIndicatorController, isModallyPresented: true) let coordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: parameters) @@ -684,9 +652,9 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { private func startEncryptionResetFlow(animated: Bool) { let sheetNavigationStackCoordinator = NavigationStackCoordinator() let parameters = EncryptionResetFlowCoordinatorParameters(userSession: userSession, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: flowParameters.userIndicatorController, navigationStackCoordinator: sheetNavigationStackCoordinator, - windowManger: appMediator.windowManager) + windowManger: flowParameters.windowManager) let coordinator = EncryptionResetFlowCoordinator(parameters: parameters) coordinator.actionsPublisher.sink { [weak self] action in @@ -736,14 +704,14 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { let hostingController = UIHostingController(rootView: coordinator.toPresentable()) hostingController.view.backgroundColor = .clear - appMediator.windowManager.globalSearchWindow.rootViewController = hostingController + flowParameters.windowManager.globalSearchWindow.rootViewController = hostingController - appMediator.windowManager.showGlobalSearch() + flowParameters.windowManager.showGlobalSearch() } private func dismissGlobalSearch() { - appMediator.windowManager.globalSearchWindow.rootViewController = nil - appMediator.windowManager.hideGlobalSearch() + flowParameters.windowManager.globalSearchWindow.rootViewController = nil + flowParameters.windowManager.hideGlobalSearch() globalSearchScreenCoordinator = nil } @@ -753,7 +721,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { private func presentRoomDirectorySearch() { let coordinator = RoomDirectorySearchScreenCoordinator(parameters: .init(clientProxy: userSession.clientProxy, mediaProvider: userSession.mediaProvider, - userIndicatorController: ServiceLocator.shared.userIndicatorController)) + userIndicatorController: flowParameters.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } @@ -788,8 +756,8 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { isPresentedModally: true, clientProxy: userSession.clientProxy, mediaProvider: userSession.mediaProvider, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: analytics) + userIndicatorController: flowParameters.userIndicatorController, + analytics: flowParameters.analytics) let coordinator = UserProfileScreenCoordinator(parameters: parameters) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } @@ -864,21 +832,21 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol { private static let failureIndicatorIdentifier = "\(ChatsFlowCoordinator.self)-Failure" private func showLoadingIndicator(delay: Duration? = nil) { - ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, - type: .modal, - title: L10n.commonLoading, - persistent: true), - delay: delay) + flowParameters.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: L10n.commonLoading, + persistent: true), + delay: delay) } private func hideLoadingIndicator() { - ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) + flowParameters.userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) } private func showFailureIndicator() { - ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.failureIndicatorIdentifier, - type: .toast, - title: L10n.errorUnknown, - iconName: "xmark")) + flowParameters.userIndicatorController.submitIndicator(UserIndicator(id: Self.failureIndicatorIdentifier, + type: .toast, + title: L10n.errorUnknown, + iconName: "xmark")) } } diff --git a/ElementX/Sources/FlowCoordinators/MediaEventsTimelineFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/MediaEventsTimelineFlowCoordinator.swift index ae184039f..6fe225823 100644 --- a/ElementX/Sources/FlowCoordinators/MediaEventsTimelineFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/MediaEventsTimelineFlowCoordinator.swift @@ -14,13 +14,11 @@ enum MediaEventsTimelineFlowCoordinatorAction { } class MediaEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { - private let navigationStackCoordinator: NavigationStackCoordinator - private let userSession: UserSessionProtocol - private let timelineControllerFactory: TimelineControllerFactoryProtocol private let roomProxy: JoinedRoomProxyProtocol - private let userIndicatorController: UserIndicatorControllerProtocol - private let appMediator: AppMediatorProtocol - private let emojiProvider: EmojiProviderProtocol + private let navigationStackCoordinator: NavigationStackCoordinator + private let flowParameters: CommonFlowParameters + + private var userSession: UserSessionProtocol { flowParameters.userSession } private let actionsSubject: PassthroughSubject = .init() var actionsPublisher: AnyPublisher { @@ -29,20 +27,12 @@ class MediaEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { private var cancellables = Set() - init(navigationStackCoordinator: NavigationStackCoordinator, - userSession: UserSessionProtocol, - timelineControllerFactory: TimelineControllerFactoryProtocol, - roomProxy: JoinedRoomProxyProtocol, - userIndicatorController: UserIndicatorControllerProtocol, - appMediator: AppMediatorProtocol, - emojiProvider: EmojiProviderProtocol) { - self.navigationStackCoordinator = navigationStackCoordinator - self.userSession = userSession - self.timelineControllerFactory = timelineControllerFactory + init(roomProxy: JoinedRoomProxyProtocol, + navigationStackCoordinator: NavigationStackCoordinator, + flowParameters: CommonFlowParameters) { self.roomProxy = roomProxy - self.userIndicatorController = userIndicatorController - self.appMediator = appMediator - self.emojiProvider = emojiProvider + self.navigationStackCoordinator = navigationStackCoordinator + self.flowParameters = flowParameters } func start() { @@ -64,22 +54,22 @@ class MediaEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), stateEventStringBuilder: RoomStateEventStringBuilder(userID: userSession.clientProxy.userID)) - guard case let .success(mediaTimelineController) = await timelineControllerFactory.buildMessageFilteredTimelineController(focus: .live, - allowedMessageTypes: [.image, .video], - presentation: .mediaFilesScreen, - roomProxy: roomProxy, - timelineItemFactory: timelineItemFactory, - mediaProvider: userSession.mediaProvider) else { + guard case let .success(mediaTimelineController) = await flowParameters.timelineControllerFactory.buildMessageFilteredTimelineController(focus: .live, + allowedMessageTypes: [.image, .video], + presentation: .mediaFilesScreen, + roomProxy: roomProxy, + timelineItemFactory: timelineItemFactory, + mediaProvider: userSession.mediaProvider) else { MXLog.error("Failed presenting media timeline") return } - guard case let .success(filesTimelineController) = await timelineControllerFactory.buildMessageFilteredTimelineController(focus: .live, - allowedMessageTypes: [.file, .audio], - presentation: .mediaFilesScreen, - roomProxy: roomProxy, - timelineItemFactory: timelineItemFactory, - mediaProvider: userSession.mediaProvider) else { + guard case let .success(filesTimelineController) = await flowParameters.timelineControllerFactory.buildMessageFilteredTimelineController(focus: .live, + allowedMessageTypes: [.file, .audio], + presentation: .mediaFilesScreen, + roomProxy: roomProxy, + timelineItemFactory: timelineItemFactory, + mediaProvider: userSession.mediaProvider) else { MXLog.error("Failed presenting media timeline") return } @@ -90,10 +80,10 @@ class MediaEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { mediaProvider: userSession.mediaProvider, mediaPlayerProvider: MediaPlayerProvider(), voiceMessageMediaManager: userSession.voiceMessageMediaManager, - appMediator: appMediator, - emojiProvider: emojiProvider, - userIndicatorController: userIndicatorController, - timelineControllerFactory: timelineControllerFactory, + appMediator: flowParameters.appMediator, + emojiProvider: flowParameters.emojiProvider, + userIndicatorController: flowParameters.userIndicatorController, + timelineControllerFactory: flowParameters.timelineControllerFactory, clientProxy: userSession.clientProxy) let coordinator = MediaEventsTimelineScreenCoordinator(parameters: parameters) diff --git a/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift index 13c538457..ea7f1dada 100644 --- a/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift @@ -57,23 +57,18 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol { private var verificationStateCancellable: AnyCancellable? - init(userSession: UserSessionProtocol, + init(isNewLogin: Bool, appLockService: AppLockServiceProtocol, - analyticsService: AnalyticsService, - appSettings: AppSettings, - notificationManager: NotificationManagerProtocol, navigationStackCoordinator: NavigationStackCoordinator, - userIndicatorController: UserIndicatorControllerProtocol, - windowManager: WindowManagerProtocol, - isNewLogin: Bool) { - self.userSession = userSession - self.appLockService = appLockService - self.analyticsService = analyticsService - self.appSettings = appSettings - self.notificationManager = notificationManager - self.userIndicatorController = userIndicatorController - self.windowManager = windowManager + flowParameters: CommonFlowParameters) { self.isNewLogin = isNewLogin + userSession = flowParameters.userSession + self.appLockService = appLockService + analyticsService = flowParameters.analytics + appSettings = flowParameters.appSettings + notificationManager = flowParameters.notificationManager + userIndicatorController = flowParameters.userIndicatorController + windowManager = flowParameters.windowManager self.navigationStackCoordinator = navigationStackCoordinator @@ -298,7 +293,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol { private func presentRecoveryKeyScreen() { let parameters = SecureBackupRecoveryKeyScreenCoordinatorParameters(secureBackupController: userSession.clientProxy.secureBackupController, - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, isModallyPresented: false) let coordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: parameters) diff --git a/ElementX/Sources/FlowCoordinators/PinnedEventsTimelineFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/PinnedEventsTimelineFlowCoordinator.swift index 2d41074a4..a42750d35 100644 --- a/ElementX/Sources/FlowCoordinators/PinnedEventsTimelineFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/PinnedEventsTimelineFlowCoordinator.swift @@ -16,14 +16,11 @@ enum PinnedEventsTimelineFlowCoordinatorAction { } class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { - private let navigationStackCoordinator: NavigationStackCoordinator - private let userSession: UserSessionProtocol - private let timelineControllerFactory: TimelineControllerFactoryProtocol private let roomProxy: JoinedRoomProxyProtocol - private let userIndicatorController: UserIndicatorControllerProtocol - private let appSettings: AppSettings - private let appMediator: AppMediatorProtocol - private let emojiProvider: EmojiProviderProtocol + private let navigationStackCoordinator: NavigationStackCoordinator + private let flowParameters: CommonFlowParameters + + private var userSession: UserSessionProtocol { flowParameters.userSession } private let actionsSubject: PassthroughSubject = .init() var actionsPublisher: AnyPublisher { @@ -32,22 +29,12 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { private var cancellables = Set() - init(navigationStackCoordinator: NavigationStackCoordinator, - userSession: UserSessionProtocol, - timelineControllerFactory: TimelineControllerFactoryProtocol, - roomProxy: JoinedRoomProxyProtocol, - userIndicatorController: UserIndicatorControllerProtocol, - appSettings: AppSettings, - appMediator: AppMediatorProtocol, - emojiProvider: EmojiProviderProtocol) { - self.navigationStackCoordinator = navigationStackCoordinator - self.userSession = userSession - self.timelineControllerFactory = timelineControllerFactory + init(roomProxy: JoinedRoomProxyProtocol, + navigationStackCoordinator: NavigationStackCoordinator, + flowParameters: CommonFlowParameters) { self.roomProxy = roomProxy - self.userIndicatorController = userIndicatorController - self.appSettings = appSettings - self.appMediator = appMediator - self.emojiProvider = emojiProvider + self.navigationStackCoordinator = navigationStackCoordinator + self.flowParameters = flowParameters } func start() { @@ -68,9 +55,9 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID)) - guard case let .success(timelineController) = await timelineControllerFactory.buildPinnedEventsTimelineController(roomProxy: roomProxy, - timelineItemFactory: timelineItemFactory, - mediaProvider: userSession.mediaProvider) else { + guard case let .success(timelineController) = await flowParameters.timelineControllerFactory.buildPinnedEventsTimelineController(roomProxy: roomProxy, + timelineItemFactory: timelineItemFactory, + mediaProvider: userSession.mediaProvider) else { fatalError("This can never fail because we allow this view to be presented only when the timeline is fully loaded and not nil") } @@ -79,9 +66,9 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { mediaProvider: userSession.mediaProvider, mediaPlayerProvider: MediaPlayerProvider(), voiceMessageMediaManager: userSession.voiceMessageMediaManager, - appMediator: appMediator, - emojiProvider: emojiProvider, - timelineControllerFactory: timelineControllerFactory, + appMediator: flowParameters.appMediator, + emojiProvider: flowParameters.emojiProvider, + timelineControllerFactory: flowParameters.timelineControllerFactory, clientProxy: userSession.clientProxy)) coordinator.actions @@ -110,8 +97,8 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { let stackCoordinator = NavigationStackCoordinator() let params = StaticLocationScreenCoordinatorParameters(interactionMode: .viewOnly(geoURI: geoURI, description: description), - mapURLBuilder: appSettings.mapTilerConfiguration, - appMediator: appMediator) + mapURLBuilder: flowParameters.appSettings.mapTilerConfiguration, + appMediator: flowParameters.appMediator) let coordinator = StaticLocationScreenCoordinator(parameters: params) coordinator.actions.sink { [weak self] action in @@ -140,7 +127,7 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { clientProxy: userSession.clientProxy, roomSummaryProvider: roomSummaryProvider, mediaProvider: userSession.mediaProvider, - userIndicatorController: userIndicatorController) + userIndicatorController: flowParameters.userIndicatorController) let coordinator = MessageForwardingScreenCoordinator(parameters: parameters) coordinator.actions.sink { [weak self] action in diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index 76cf4bb60..a54888d56 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -56,17 +56,11 @@ struct FocusEvent: Hashable { // swiftlint:disable:next type_body_length class RoomFlowCoordinator: FlowCoordinatorProtocol { private let roomID: String - private let userSession: UserSessionProtocol private let isChildFlow: Bool - private let timelineControllerFactory: TimelineControllerFactoryProtocol private let navigationStackCoordinator: NavigationStackCoordinator - private let emojiProvider: EmojiProviderProtocol - private let ongoingCallRoomIDPublisher: CurrentValuePublisher - private let appMediator: AppMediatorProtocol - private let appSettings: AppSettings - private let appHooks: AppHooks - private let analytics: AnalyticsService - private let userIndicatorController: UserIndicatorControllerProtocol + private let flowParameters: CommonFlowParameters + + private var userSession: UserSessionProtocol { flowParameters.userSession } private var roomProxy: JoinedRoomProxyProtocol! @@ -94,33 +88,17 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private var timelineController: TimelineControllerProtocol? init(roomID: String, - userSession: UserSessionProtocol, isChildFlow: Bool, - timelineControllerFactory: TimelineControllerFactoryProtocol, navigationStackCoordinator: NavigationStackCoordinator, - emojiProvider: EmojiProviderProtocol, - ongoingCallRoomIDPublisher: CurrentValuePublisher, - appMediator: AppMediatorProtocol, - appSettings: AppSettings, - appHooks: AppHooks, - analytics: AnalyticsService, - userIndicatorController: UserIndicatorControllerProtocol) { + flowParameters: CommonFlowParameters) { self.roomID = roomID - self.userSession = userSession self.isChildFlow = isChildFlow - self.timelineControllerFactory = timelineControllerFactory self.navigationStackCoordinator = navigationStackCoordinator - self.emojiProvider = emojiProvider - self.ongoingCallRoomIDPublisher = ongoingCallRoomIDPublisher - self.appMediator = appMediator - self.appSettings = appSettings - self.appHooks = appHooks - self.analytics = analytics - self.userIndicatorController = userIndicatorController + self.flowParameters = flowParameters setupStateMachine() - analytics.signpost.beginRoomFlow(roomID) + flowParameters.analytics.signpost.beginRoomFlow(roomID) } // MARK: - FlowCoordinatorProtocol @@ -220,8 +198,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let parameters = RoomChangeRolesScreenCoordinatorParameters(mode: .owner, roomProxy: roomProxy, mediaProvider: userSession.mediaProvider, - userIndicatorController: userIndicatorController, - analytics: analytics) + userIndicatorController: flowParameters.userIndicatorController, + analytics: flowParameters.analytics) let stackCoordinator = NavigationStackCoordinator() let coordinator = RoomChangeRolesScreenCoordinator(parameters: parameters) coordinator.actionsPublisher.sink { [weak self] action in @@ -519,7 +497,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { // Flag the room as read on entering, the timeline will take care of the read receipts Task { await roomProxy.flagAsUnread(false) } - analytics.trackViewRoom(isDM: roomProxy.infoPublisher.value.isDirect, isSpace: roomProxy.infoPublisher.value.isSpace) + flowParameters.analytics.trackViewRoom(isDM: roomProxy.infoPublisher.value.isDirect, isSpace: roomProxy.infoPublisher.value.isSpace) let coordinator = makeRoomScreenCoordinator(presentationAction: presentationAction, animated: animated) roomScreenCoordinator = coordinator @@ -554,10 +532,10 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let timelineItemFactory = RoomTimelineItemFactory(userID: userID, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID)) - let timelineController = timelineControllerFactory.buildTimelineController(roomProxy: roomProxy, - initialFocussedEventID: presentationAction?.focusedEvent?.eventID, - timelineItemFactory: timelineItemFactory, - mediaProvider: userSession.mediaProvider) + let timelineController = flowParameters.timelineControllerFactory.buildTimelineController(roomProxy: roomProxy, + initialFocussedEventID: presentationAction?.focusedEvent?.eventID, + timelineItemFactory: timelineItemFactory, + mediaProvider: userSession.mediaProvider) self.timelineController = timelineController let completionSuggestionService = CompletionSuggestionService(roomProxy: roomProxy, @@ -574,14 +552,14 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { mediaProvider: userSession.mediaProvider, mediaPlayerProvider: MediaPlayerProvider(), voiceMessageMediaManager: userSession.voiceMessageMediaManager, - emojiProvider: emojiProvider, + emojiProvider: flowParameters.emojiProvider, completionSuggestionService: completionSuggestionService, - ongoingCallRoomIDPublisher: ongoingCallRoomIDPublisher, - appMediator: appMediator, - appSettings: appSettings, - appHooks: appHooks, + ongoingCallRoomIDPublisher: flowParameters.ongoingCallRoomIDPublisher, + appMediator: flowParameters.appMediator, + appSettings: flowParameters.appSettings, + appHooks: flowParameters.appHooks, composerDraftService: composerDraftService, - timelineControllerFactory: timelineControllerFactory) + timelineControllerFactory: flowParameters.timelineControllerFactory) let coordinator = RoomScreenCoordinator(parameters: parameters) coordinator.actions @@ -650,10 +628,10 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { fatalError("Invalid thread event ID") } - guard case let .success(timelineController) = await timelineControllerFactory.buildThreadTimelineController(eventID: threadRootEventID, - roomProxy: roomProxy, - timelineItemFactory: timelineItemFactory, - mediaProvider: userSession.mediaProvider) else { + guard case let .success(timelineController) = await flowParameters.timelineControllerFactory.buildThreadTimelineController(eventID: threadRootEventID, + roomProxy: roomProxy, + timelineItemFactory: timelineItemFactory, + mediaProvider: userSession.mediaProvider) else { MXLog.error("Failed presenting media timeline") return } @@ -670,12 +648,12 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { mediaProvider: userSession.mediaProvider, mediaPlayerProvider: MediaPlayerProvider(), voiceMessageMediaManager: userSession.voiceMessageMediaManager, - emojiProvider: emojiProvider, + emojiProvider: flowParameters.emojiProvider, completionSuggestionService: completionSuggestionService, - appMediator: appMediator, - appSettings: appSettings, + appMediator: flowParameters.appMediator, + appSettings: flowParameters.appSettings, composerDraftService: composerDraftService, - timelineControllerFactory: timelineControllerFactory)) + timelineControllerFactory: flowParameters.timelineControllerFactory)) coordinator.actions.sink { [weak self] action in guard let self else { return } @@ -723,8 +701,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { via: via, clientProxy: userSession.clientProxy, mediaProvider: userSession.mediaProvider, - userIndicatorController: userIndicatorController, - appSettings: appSettings)) + userIndicatorController: flowParameters.userIndicatorController, + appSettings: flowParameters.appSettings)) joinRoomScreenCoordinator = coordinator @@ -742,9 +720,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { await storeAndSubscribeToRoomProxy(roomProxy) stateMachine.tryEvent(.presentRoom(presentationAction: nil), userInfo: EventUserInfo(animated: animated)) - analytics.trackJoinedRoom(isDM: roomProxy.infoPublisher.value.isDirect, - isSpace: roomProxy.infoPublisher.value.isSpace, - activeMemberCount: UInt(roomProxy.infoPublisher.value.activeMembersCount)) + flowParameters.analytics.trackJoinedRoom(isDM: roomProxy.infoPublisher.value.isDirect, + isSpace: roomProxy.infoPublisher.value.isSpace, + activeMemberCount: UInt(roomProxy.infoPublisher.value.activeMembersCount)) } else { stateMachine.tryEvent(.dismissFlow, userInfo: EventUserInfo(animated: animated)) } @@ -790,18 +768,18 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { timelineController = nil actionsSubject.send(.finished) - analytics.signpost.endRoomFlow() + flowParameters.analytics.signpost.endRoomFlow() } private func presentRoomDetails(isRoot: Bool, animated: Bool) async { let params = RoomDetailsScreenCoordinatorParameters(roomProxy: roomProxy, clientProxy: userSession.clientProxy, mediaProvider: userSession.mediaProvider, - analyticsService: analytics, - userIndicatorController: userIndicatorController, + analyticsService: flowParameters.analytics, + userIndicatorController: flowParameters.userIndicatorController, notificationSettings: userSession.clientProxy.notificationSettings, attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), - appMediator: appMediator) + appMediator: flowParameters.appMediator) let coordinator = RoomDetailsScreenCoordinator(parameters: params) coordinator.actions.sink { [weak self] action in guard let self else { return } @@ -862,8 +840,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let parameters = RoomMembersListScreenCoordinatorParameters(clientProxy: userSession.clientProxy, roomProxy: roomProxy, mediaProvider: userSession.mediaProvider, - userIndicatorController: userIndicatorController, - analytics: analytics) + userIndicatorController: flowParameters.userIndicatorController, + analytics: flowParameters.analytics) let coordinator = RoomMembersListScreenCoordinator(parameters: parameters) coordinator.actions @@ -887,7 +865,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private func presentKnockRequestsList() { let parameters = KnockRequestsListScreenCoordinatorParameters(roomProxy: roomProxy, mediaProvider: userSession.mediaProvider, - userIndicatorController: userIndicatorController) + userIndicatorController: flowParameters.userIndicatorController) let coordinator = KnockRequestsListScreenCoordinator(parameters: parameters) navigationStackCoordinator.push(coordinator) { [weak self] in @@ -901,11 +879,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let roomDetailsEditParameters = RoomDetailsEditScreenCoordinatorParameters(roomProxy: roomProxy, clientProxy: userSession.clientProxy, mediaProvider: userSession.mediaProvider, - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings), + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: flowParameters.appSettings), navigationStackCoordinator: stackCoordinator, - userIndicatorController: userIndicatorController, - orientationManager: appMediator.windowManager, - appSettings: appSettings) + userIndicatorController: flowParameters.userIndicatorController, + orientationManager: flowParameters.appMediator.windowManager, + appSettings: flowParameters.appSettings) let roomDetailsEditCoordinator = RoomDetailsEditScreenCoordinator(parameters: roomDetailsEditParameters) roomDetailsEditCoordinator.actions.sink { [weak self] action in @@ -933,7 +911,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { senderID: senderID, roomProxy: roomProxy, clientProxy: userSession.clientProxy, - userIndicatorController: userIndicatorController) + userIndicatorController: flowParameters.userIndicatorController) let coordinator = ReportContentScreenCoordinator(parameters: parameters) coordinator.actions @@ -946,7 +924,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { case .cancel: break case .finish: - userIndicatorController.submitIndicator(UserIndicator(title: L10n.commonReportSubmitted, iconName: "checkmark")) + flowParameters.userIndicatorController.submitIndicator(UserIndicator(title: L10n.commonReportSubmitted, iconName: "checkmark")) } } .store(in: &cancellables) @@ -963,8 +941,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let stackCoordinator = NavigationStackCoordinator() let mediaPickerCoordinator = MediaPickerScreenCoordinator(mode: mode, - userIndicatorController: userIndicatorController, - orientationManager: appMediator.windowManager) { [weak self] action in + userIndicatorController: flowParameters.userIndicatorController, + orientationManager: flowParameters.appMediator.windowManager) { [weak self] action in guard let self else { return } @@ -1000,11 +978,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let parameters = MediaUploadPreviewScreenCoordinatorParameters(mediaURLs: mediaURLs, title: title, isRoomEncrypted: roomProxy.infoPublisher.value.isEncrypted, - shouldShowCaptionWarning: appSettings.shouldShowMediaCaptionWarning, - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings), + shouldShowCaptionWarning: flowParameters.appSettings.shouldShowMediaCaptionWarning, + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: flowParameters.appSettings), timelineController: timelineController, clientProxy: userSession.clientProxy, - userIndicatorController: userIndicatorController) + userIndicatorController: flowParameters.userIndicatorController) let mediaUploadPreviewScreenCoordinator = MediaUploadPreviewScreenCoordinator(parameters: parameters) @@ -1030,7 +1008,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { selectedEmoji: Set, timelineController: TimelineControllerProtocol, animated: Bool) { - let params = EmojiPickerScreenCoordinatorParameters(emojiProvider: emojiProvider, + let params = EmojiPickerScreenCoordinatorParameters(emojiProvider: flowParameters.emojiProvider, itemID: itemID, selectedEmojis: selectedEmoji) let coordinator = EmojiPickerScreenCoordinator(parameters: params) @@ -1065,8 +1043,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let stackCoordinator = NavigationStackCoordinator() let params = StaticLocationScreenCoordinatorParameters(interactionMode: interactionMode, - mapURLBuilder: appSettings.mapTilerConfiguration, - appMediator: appMediator) + mapURLBuilder: flowParameters.appSettings.mapTilerConfiguration, + appMediator: flowParameters.appMediator) let coordinator = StaticLocationScreenCoordinator(parameters: params) coordinator.actions.sink { [weak self] action in @@ -1082,11 +1060,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { self.navigationStackCoordinator.setSheetCoordinator(nil) } - self.analytics.trackComposer(inThread: false, - isEditing: false, - isReply: false, - messageType: isUserLocation ? .LocationUser : .LocationPin, - startsThread: nil) + self.flowParameters.analytics.trackComposer(inThread: false, + isEditing: false, + isReply: false, + messageType: isUserLocation ? .LocationUser : .LocationPin, + startsThread: nil) case .close: self.navigationStackCoordinator.setSheetCoordinator(nil) } @@ -1145,19 +1123,19 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { Task { let result = await timelineController.createPoll(question: question, answers: options, pollKind: pollKind) - self.analytics.trackComposer(inThread: false, - isEditing: false, - isReply: false, - messageType: .Poll, - startsThread: nil) + self.flowParameters.analytics.trackComposer(inThread: false, + isEditing: false, + isReply: false, + messageType: .Poll, + startsThread: nil) - self.analytics.trackPollCreated(isUndisclosed: pollKind == .undisclosed, numberOfAnswers: options.count) + self.flowParameters.analytics.trackPollCreated(isUndisclosed: pollKind == .undisclosed, numberOfAnswers: options.count) switch result { case .success: break case .failure: - self.userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown)) + self.flowParameters.userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown)) } } } @@ -1170,7 +1148,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { case .success: break case .failure: - self.userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown)) + self.flowParameters.userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown)) } } } @@ -1178,7 +1156,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private func deletePoll(mode: PollFormMode) { Task { guard case .edit(let pollStartID, _) = mode else { - self.userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown)) + self.flowParameters.userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown)) return } @@ -1188,7 +1166,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { case .success: break case .failure: - self.userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown)) + self.flowParameters.userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown)) } } } @@ -1200,12 +1178,12 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()), stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID)) - let timelineController = timelineControllerFactory.buildTimelineController(roomProxy: roomProxy, - initialFocussedEventID: nil, - timelineItemFactory: timelineItemFactory, - mediaProvider: userSession.mediaProvider) + let timelineController = flowParameters.timelineControllerFactory.buildTimelineController(roomProxy: roomProxy, + initialFocussedEventID: nil, + timelineItemFactory: timelineItemFactory, + mediaProvider: userSession.mediaProvider) - let parameters = RoomPollsHistoryScreenCoordinatorParameters(pollInteractionHandler: PollInteractionHandler(analyticsService: analytics, + let parameters = RoomPollsHistoryScreenCoordinatorParameters(pollInteractionHandler: PollInteractionHandler(analyticsService: flowParameters.analytics, timelineController: timelineController), timelineController: timelineController) let coordinator = RoomPollsHistoryScreenCoordinator(parameters: parameters) @@ -1231,8 +1209,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { roomProxy: roomProxy, clientProxy: userSession.clientProxy, mediaProvider: userSession.mediaProvider, - userIndicatorController: userIndicatorController, - analytics: analytics) + userIndicatorController: flowParameters.userIndicatorController, + analytics: flowParameters.analytics) let coordinator = RoomMemberDetailsScreenCoordinator(parameters: params) coordinator.actions.sink { [weak self] action in @@ -1260,8 +1238,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { isPresentedModally: false, clientProxy: userSession.clientProxy, mediaProvider: userSession.mediaProvider, - userIndicatorController: userIndicatorController, - analytics: analytics) + userIndicatorController: flowParameters.userIndicatorController, + analytics: flowParameters.analytics) let coordinator = UserProfileScreenCoordinator(parameters: parameters) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } @@ -1296,7 +1274,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { clientProxy: userSession.clientProxy, roomSummaryProvider: roomSummaryProvider, mediaProvider: userSession.mediaProvider, - userIndicatorController: userIndicatorController) + userIndicatorController: flowParameters.userIndicatorController) let coordinator = MessageForwardingScreenCoordinator(parameters: parameters) coordinator.actions.sink { [weak self] action in @@ -1344,7 +1322,6 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let parameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: stackCoordinator, userSession: userSession, userNotificationCenter: UNUserNotificationCenter.current(), - notificationSettings: userSession.clientProxy.notificationSettings, isModallyPresented: true) let coordinator = NotificationSettingsScreenCoordinator(parameters: parameters) coordinator.actions.sink { [weak self] action in @@ -1370,7 +1347,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { roomType: .room(roomProxy: roomProxy), mediaProvider: userSession.mediaProvider, userDiscoveryService: UserDiscoveryService(clientProxy: userSession.clientProxy), - userIndicatorController: userIndicatorController) + userIndicatorController: flowParameters.userIndicatorController) let coordinator = InviteUsersScreenCoordinator(parameters: inviteParameters) stackCoordinator.setRootCoordinator(coordinator) @@ -1424,9 +1401,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { return } - userIndicatorController.alertInfo = .init(id: .init(), - title: L10n.commonUnableToInviteTitle, - message: L10n.commonUnableToInviteMessage) + flowParameters.userIndicatorController.alertInfo = .init(id: .init(), + title: L10n.commonUnableToInviteTitle, + message: L10n.commonUnableToInviteMessage) } } @@ -1434,8 +1411,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let parameters = RoomRolesAndPermissionsFlowCoordinatorParameters(roomProxy: roomProxy, mediaProvider: userSession.mediaProvider, navigationStackCoordinator: navigationStackCoordinator, - userIndicatorController: userIndicatorController, - analytics: analytics) + userIndicatorController: flowParameters.userIndicatorController, + analytics: flowParameters.analytics) let coordinator = RoomRolesAndPermissionsFlowCoordinator(parameters: parameters) coordinator.actionsPublisher.sink { [weak self] action in switch action { @@ -1453,7 +1430,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let coordinator = ResolveVerifiedUserSendFailureScreenCoordinator(parameters: .init(failure: failure, sendHandle: sendHandle, roomProxy: roomProxy, - userIndicatorController: userIndicatorController)) + userIndicatorController: flowParameters.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } @@ -1472,7 +1449,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private func presentSecurityAndPrivacyScreen() { let coordinator = SecurityAndPrivacyScreenCoordinator(parameters: .init(roomProxy: roomProxy, clientProxy: userSession.clientProxy, - userIndicatorController: userIndicatorController)) + userIndicatorController: flowParameters.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } @@ -1493,7 +1470,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let stackCoordinator = NavigationStackCoordinator() let coordinator = EditRoomAddressScreenCoordinator(parameters: .init(roomProxy: roomProxy, clientProxy: userSession.clientProxy, - userIndicatorController: userIndicatorController)) + userIndicatorController: flowParameters.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in switch action { @@ -1510,7 +1487,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private func presentReportRoom() { let stackCoordinator = NavigationStackCoordinator() let coordinator = ReportRoomScreenCoordinator(parameters: .init(roomProxy: roomProxy, - userIndicatorController: userIndicatorController)) + userIndicatorController: flowParameters.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } @@ -1535,7 +1512,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { let coordinator = DeclineAndBlockScreenCoordinator(parameters: .init(userID: userID, roomID: roomID, clientProxy: userSession.clientProxy, - userIndicatorController: userIndicatorController)) + userIndicatorController: flowParameters.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } switch action { @@ -1558,17 +1535,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private func startChildFlow(for roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint) { let coordinator = RoomFlowCoordinator(roomID: roomID, - userSession: userSession, isChildFlow: true, - timelineControllerFactory: timelineControllerFactory, navigationStackCoordinator: navigationStackCoordinator, - emojiProvider: emojiProvider, - ongoingCallRoomIDPublisher: ongoingCallRoomIDPublisher, - appMediator: appMediator, - appSettings: appSettings, - appHooks: appHooks, - analytics: analytics, - userIndicatorController: userIndicatorController) + flowParameters: flowParameters) coordinator.actions.sink { [weak self] action in guard let self else { return } @@ -1601,14 +1570,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private func startPinnedEventsTimelineFlow() { let stackCoordinator = NavigationStackCoordinator() - let flowCoordinator = PinnedEventsTimelineFlowCoordinator(navigationStackCoordinator: stackCoordinator, - userSession: userSession, - timelineControllerFactory: timelineControllerFactory, - roomProxy: roomProxy, - userIndicatorController: userIndicatorController, - appSettings: appSettings, - appMediator: appMediator, - emojiProvider: emojiProvider) + let flowCoordinator = PinnedEventsTimelineFlowCoordinator(roomProxy: roomProxy, + navigationStackCoordinator: stackCoordinator, + flowParameters: flowParameters) flowCoordinator.actionsPublisher.sink { [weak self] action in guard let self else { @@ -1641,13 +1605,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { } private func startMediaEventsTimelineFlow() async { - let flowCoordinator = MediaEventsTimelineFlowCoordinator(navigationStackCoordinator: navigationStackCoordinator, - userSession: userSession, - timelineControllerFactory: timelineControllerFactory, - roomProxy: roomProxy, - userIndicatorController: userIndicatorController, - appMediator: appMediator, - emojiProvider: emojiProvider) + let flowCoordinator = MediaEventsTimelineFlowCoordinator(roomProxy: roomProxy, + navigationStackCoordinator: navigationStackCoordinator, + flowParameters: flowParameters) flowCoordinator.actionsPublisher.sink { [weak self] action in guard let self else { return } @@ -1674,15 +1634,15 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { private static let loadingIndicatorID = "\(RoomFlowCoordinator.self)-Loading" private func showLoadingIndicator(delay: Duration? = nil) { - userIndicatorController.submitIndicator(.init(id: Self.loadingIndicatorID, - type: .modal(progress: .indeterminate, - interactiveDismissDisabled: false, - allowsInteraction: false), - title: L10n.commonLoading, persistent: true), - delay: delay) + flowParameters.userIndicatorController.submitIndicator(.init(id: Self.loadingIndicatorID, + type: .modal(progress: .indeterminate, + interactiveDismissDisabled: false, + allowsInteraction: false), + title: L10n.commonLoading, persistent: true), + delay: delay) } private func hideLoadingIndicator() { - userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorID) + flowParameters.userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorID) } } diff --git a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift index ed0278425..34549eb28 100644 --- a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift @@ -16,22 +16,10 @@ enum SettingsFlowCoordinatorAction { case forceLogout } -struct SettingsFlowCoordinatorParameters { - let userSession: UserSessionProtocol - let windowManager: WindowManagerProtocol - let appLockService: AppLockServiceProtocol - let bugReportService: BugReportServiceProtocol - let notificationSettings: NotificationSettingsProxyProtocol - let secureBackupController: SecureBackupControllerProtocol - let appSettings: AppSettings - let navigationStackCoordinator: NavigationStackCoordinator - let userIndicatorController: UserIndicatorControllerProtocol - let analytics: AnalyticsService -} - class SettingsFlowCoordinator: FlowCoordinatorProtocol { - private let parameters: SettingsFlowCoordinatorParameters - private var navigationStackCoordinator: NavigationStackCoordinator { parameters.navigationStackCoordinator } + private let appLockService: AppLockServiceProtocol + private let navigationStackCoordinator: NavigationStackCoordinator + private let flowParameters: CommonFlowParameters // periphery:ignore - retaining purpose private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator? @@ -47,8 +35,12 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { actionsSubject.eraseToAnyPublisher() } - init(parameters: SettingsFlowCoordinatorParameters) { - self.parameters = parameters + init(appLockService: AppLockServiceProtocol, + navigationStackCoordinator: NavigationStackCoordinator, + flowParameters: CommonFlowParameters) { + self.appLockService = appLockService + self.navigationStackCoordinator = navigationStackCoordinator + self.flowParameters = flowParameters } func start() { @@ -73,9 +65,9 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { // MARK: - Private private func presentSettingsScreen(animated: Bool) { - let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: .init(userSession: parameters.userSession, - appSettings: parameters.appSettings, - isBugReportServiceEnabled: parameters.bugReportService.isEnabled)) + let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: .init(userSession: flowParameters.userSession, + appSettings: flowParameters.appSettings, + isBugReportServiceEnabled: flowParameters.bugReportService.isEnabled)) settingsScreenCoordinator.actions .sink { [weak self] action in @@ -98,9 +90,9 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { presentAppLockSetupFlow() case .bugReport: bugReportFlowCoordinator = BugReportFlowCoordinator(parameters: .init(presentationMode: .push(navigationStackCoordinator), - userIndicatorController: parameters.userIndicatorController, - bugReportService: parameters.bugReportService, - userSession: parameters.userSession)) + userIndicatorController: flowParameters.userIndicatorController, + bugReportService: flowParameters.bugReportService, + userSession: flowParameters.userSession)) bugReportFlowCoordinator?.start() case .about: presentLegalInformationScreen() @@ -122,9 +114,9 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { } private func startEncryptionSettingsFlow(animated: Bool) { - let coordinator = EncryptionSettingsFlowCoordinator(parameters: .init(userSession: parameters.userSession, - appSettings: parameters.appSettings, - userIndicatorController: parameters.userIndicatorController, + let coordinator = EncryptionSettingsFlowCoordinator(parameters: .init(userSession: flowParameters.userSession, + appSettings: flowParameters.appSettings, + userIndicatorController: flowParameters.userIndicatorController, navigationStackCoordinator: navigationStackCoordinator)) coordinator.actionsPublisher.sink { [weak self] action in switch action { @@ -140,26 +132,26 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { } private func presentUserDetailsEditScreen() { - let coordinator = UserDetailsEditScreenCoordinator(parameters: .init(orientationManager: parameters.windowManager, - clientProxy: parameters.userSession.clientProxy, - mediaProvider: parameters.userSession.mediaProvider, - mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: parameters.appSettings), + let coordinator = UserDetailsEditScreenCoordinator(parameters: .init(orientationManager: flowParameters.windowManager, + clientProxy: flowParameters.userSession.clientProxy, + mediaProvider: flowParameters.userSession.mediaProvider, + mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: flowParameters.appSettings), navigationStackCoordinator: navigationStackCoordinator, - userIndicatorController: parameters.userIndicatorController, - appSettings: parameters.appSettings)) + userIndicatorController: flowParameters.userIndicatorController, + appSettings: flowParameters.appSettings)) navigationStackCoordinator.push(coordinator) } private func presentAnalyticsScreen() { - let coordinator = AnalyticsSettingsScreenCoordinator(parameters: .init(appSettings: parameters.appSettings, - analytics: parameters.analytics)) + let coordinator = AnalyticsSettingsScreenCoordinator(parameters: .init(appSettings: flowParameters.appSettings, + analytics: flowParameters.analytics)) navigationStackCoordinator.push(coordinator) } private func presentAppLockSetupFlow() { let coordinator = AppLockSetupFlowCoordinator(presentingFlow: .settings, - appLockService: parameters.appLockService, + appLockService: appLockService, navigationStackCoordinator: navigationStackCoordinator) coordinator.actions.sink { [weak self] action in guard let self else { return } @@ -178,32 +170,31 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { } private func presentLegalInformationScreen() { - navigationStackCoordinator.push(LegalInformationScreenCoordinator(appSettings: parameters.appSettings)) + navigationStackCoordinator.push(LegalInformationScreenCoordinator(appSettings: flowParameters.appSettings)) } private func presentBlockedUsersScreen() { - let coordinator = BlockedUsersScreenCoordinator(parameters: .init(hideProfiles: parameters.appSettings.hideIgnoredUserProfiles, - clientProxy: parameters.userSession.clientProxy, - mediaProvider: parameters.userSession.mediaProvider, - userIndicatorController: parameters.userIndicatorController)) + let coordinator = BlockedUsersScreenCoordinator(parameters: .init(hideProfiles: flowParameters.appSettings.hideIgnoredUserProfiles, + clientProxy: flowParameters.userSession.clientProxy, + mediaProvider: flowParameters.userSession.mediaProvider, + userIndicatorController: flowParameters.userIndicatorController)) navigationStackCoordinator.push(coordinator) } private func presentNotificationSettings() { let notificationParameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator, - userSession: parameters.userSession, + userSession: flowParameters.userSession, userNotificationCenter: UNUserNotificationCenter.current(), - notificationSettings: parameters.notificationSettings, isModallyPresented: false) let coordinator = NotificationSettingsScreenCoordinator(parameters: notificationParameters) navigationStackCoordinator.push(coordinator) } private func presentAdvancedSettings() { - let coordinator = AdvancedSettingsScreenCoordinator(parameters: .init(appSettings: parameters.appSettings, - analytics: parameters.analytics, - clientProxy: parameters.userSession.clientProxy, - userIndicatorController: parameters.userIndicatorController)) + let coordinator = AdvancedSettingsScreenCoordinator(parameters: .init(appSettings: flowParameters.appSettings, + analytics: flowParameters.analytics, + clientProxy: flowParameters.userSession.clientProxy, + userIndicatorController: flowParameters.userIndicatorController)) navigationStackCoordinator.push(coordinator) } @@ -225,8 +216,8 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { } private func presentDeactivateAccount() { - let parameters = DeactivateAccountScreenCoordinatorParameters(clientProxy: parameters.userSession.clientProxy, - userIndicatorController: parameters.userIndicatorController) + let parameters = DeactivateAccountScreenCoordinatorParameters(clientProxy: flowParameters.userSession.clientProxy, + userIndicatorController: flowParameters.userIndicatorController) let coordinator = DeactivateAccountScreenCoordinator(parameters: parameters) coordinator.actionsPublisher @@ -249,7 +240,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { 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 = OIDCAccountSettingsPresenter(accountURL: url, presentationAnchor: flowParameters.windowManager.mainWindow) accountSettingsPresenter?.start() } } diff --git a/ElementX/Sources/FlowCoordinators/SpaceExplorerFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SpaceExplorerFlowCoordinator.swift index 4fc9c30b4..72c655dae 100644 --- a/ElementX/Sources/FlowCoordinators/SpaceExplorerFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SpaceExplorerFlowCoordinator.swift @@ -16,12 +16,11 @@ enum SpaceExplorerFlowCoordinatorAction: Equatable { class SpaceExplorerFlowCoordinator: FlowCoordinatorProtocol { private let userSession: UserSessionProtocol + private var flowParameters: CommonFlowParameters private let navigationSplitCoordinator: NavigationSplitCoordinator private let sidebarNavigationStackCoordinator: NavigationStackCoordinator private let detailNavigationStackCoordinator: NavigationStackCoordinator - private let userIndicatorController: UserIndicatorControllerProtocol - private var spaceFlowCoordinator: SpaceFlowCoordinator? enum State: StateType { @@ -52,12 +51,10 @@ class SpaceExplorerFlowCoordinator: FlowCoordinatorProtocol { actionsSubject.eraseToAnyPublisher() } - init(userSession: UserSessionProtocol, - navigationSplitCoordinator: NavigationSplitCoordinator, - userIndicatorController: UserIndicatorControllerProtocol) { - self.userSession = userSession + init(navigationSplitCoordinator: NavigationSplitCoordinator, flowParameters: CommonFlowParameters) { + userSession = flowParameters.userSession self.navigationSplitCoordinator = navigationSplitCoordinator - self.userIndicatorController = userIndicatorController + self.flowParameters = flowParameters sidebarNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator) detailNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator) @@ -117,7 +114,7 @@ class SpaceExplorerFlowCoordinator: FlowCoordinatorProtocol { private func presentSpaceList() { let parameters = SpaceListScreenCoordinatorParameters(userSession: userSession, selectedSpaceSubject: selectedSpaceSubject.asCurrentValuePublisher(), - userIndicatorController: userIndicatorController) + userIndicatorController: flowParameters.userIndicatorController) let coordinator = SpaceListScreenCoordinator(parameters: parameters) coordinator.actionsPublisher .sink { [weak self] action in @@ -138,9 +135,8 @@ class SpaceExplorerFlowCoordinator: FlowCoordinatorProtocol { let coordinator = SpaceFlowCoordinator(spaceRoomListProxy: spaceRoomListProxy, spaceServiceProxy: userSession.clientProxy.spaceService, isChildFlow: false, - mediaProvider: userSession.mediaProvider, navigationStackCoordinator: detailNavigationStackCoordinator, - userIndicatorController: userIndicatorController) + flowParameters: flowParameters) coordinator.actionsPublisher .sink { [weak self] action in diff --git a/ElementX/Sources/FlowCoordinators/SpaceFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SpaceFlowCoordinator.swift index ac250961b..5f3c60e4e 100644 --- a/ElementX/Sources/FlowCoordinators/SpaceFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SpaceFlowCoordinator.swift @@ -18,13 +18,12 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol { private let spaceServiceProxy: SpaceServiceProxyProtocol private let isChildFlow: Bool - private let mediaProvider: MediaProviderProtocol - private let navigationStackCoordinator: NavigationStackCoordinator - private let userIndicatorController: UserIndicatorControllerProtocol private var childSpaceFlowCoordinator: SpaceFlowCoordinator? + private let flowParameters: CommonFlowParameters + indirect enum State: StateType { /// The state machine hasn't started. case initial @@ -57,17 +56,14 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol { init(spaceRoomListProxy: SpaceRoomListProxyProtocol, spaceServiceProxy: SpaceServiceProxyProtocol, isChildFlow: Bool, - mediaProvider: MediaProviderProtocol, navigationStackCoordinator: NavigationStackCoordinator, - userIndicatorController: UserIndicatorControllerProtocol) { + flowParameters: CommonFlowParameters) { self.spaceRoomListProxy = spaceRoomListProxy self.spaceServiceProxy = spaceServiceProxy self.isChildFlow = isChildFlow - - self.mediaProvider = mediaProvider + self.flowParameters = flowParameters self.navigationStackCoordinator = navigationStackCoordinator - self.userIndicatorController = userIndicatorController stateMachine = .init(state: .initial) configureStateMachine() @@ -130,8 +126,8 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol { private func presentSpace() { let parameters = SpaceScreenCoordinatorParameters(spaceRoomListProxy: spaceRoomListProxy, spaceServiceProxy: spaceServiceProxy, - mediaProvider: mediaProvider, - userIndicatorController: userIndicatorController) + mediaProvider: flowParameters.userSession.mediaProvider, + userIndicatorController: flowParameters.userIndicatorController) let coordinator = SpaceScreenCoordinator(parameters: parameters) coordinator.actionsPublisher .sink { [weak self] action in @@ -160,9 +156,8 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol { let coordinator = SpaceFlowCoordinator(spaceRoomListProxy: spaceRoomListProxy, spaceServiceProxy: spaceServiceProxy, isChildFlow: true, - mediaProvider: mediaProvider, navigationStackCoordinator: navigationStackCoordinator, - userIndicatorController: userIndicatorController) + flowParameters: flowParameters) coordinator.actionsPublisher .sink { [weak self] action in diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index d81570fe7..220e7e0c7 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -21,14 +21,12 @@ enum UserSessionFlowCoordinatorAction { class UserSessionFlowCoordinator: FlowCoordinatorProtocol { enum HomeTab: Hashable { case chats, spaces } - private let userSession: UserSessionProtocol private let navigationRootCoordinator: NavigationRootCoordinator private let navigationTabCoordinator: NavigationTabCoordinator private let appLockService: AppLockServiceProtocol - private let bugReportService: BugReportServiceProtocol - private let appMediator: AppMediatorProtocol - private let appSettings: AppSettings - private let analytics: AnalyticsService + private let flowParameters: CommonFlowParameters + + private var userSession: UserSessionProtocol { flowParameters.userSession } private let onboardingFlowCoordinator: OnboardingFlowCoordinator private let onboardingStackCoordinator: NavigationStackCoordinator @@ -67,75 +65,46 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { actionsSubject.eraseToAnyPublisher() } - init(userSession: UserSessionProtocol, - isNewLogin: Bool, + init(isNewLogin: Bool, navigationRootCoordinator: NavigationRootCoordinator, appLockService: AppLockServiceProtocol, - bugReportService: BugReportServiceProtocol, - elementCallService: ElementCallServiceProtocol, - timelineControllerFactory: TimelineControllerFactoryProtocol, - appMediator: AppMediatorProtocol, - appSettings: AppSettings, - appHooks: AppHooks, - analytics: AnalyticsService, - notificationManager: NotificationManagerProtocol, - stateMachineFactory: StateMachineFactoryProtocol) { - self.userSession = userSession + flowParameters: CommonFlowParameters) { self.navigationRootCoordinator = navigationRootCoordinator self.appLockService = appLockService - self.bugReportService = bugReportService - self.appMediator = appMediator - self.appSettings = appSettings - self.analytics = analytics + self.flowParameters = flowParameters navigationTabCoordinator = NavigationTabCoordinator() navigationRootCoordinator.setRootCoordinator(navigationTabCoordinator) let chatsSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator()) - chatsFlowCoordinator = ChatsFlowCoordinator(userSession: userSession, - isNewLogin: isNewLogin, + chatsFlowCoordinator = ChatsFlowCoordinator(isNewLogin: isNewLogin, navigationSplitCoordinator: chatsSplitCoordinator, - appLockService: appLockService, - bugReportService: bugReportService, - elementCallService: elementCallService, - timelineControllerFactory: timelineControllerFactory, - appMediator: appMediator, - appSettings: appSettings, - appHooks: appHooks, - analytics: analytics, - notificationManager: notificationManager, - stateMachineFactory: stateMachineFactory) + flowParameters: flowParameters) chatsTabDetails = .init(tag: HomeTab.chats, title: L10n.screenHomeTabChats, icon: \.chat, selectedIcon: \.chatSolid) chatsTabDetails.navigationSplitCoordinator = chatsSplitCoordinator - if !appSettings.spacesEnabled { + if !flowParameters.appSettings.spacesEnabled { chatsTabDetails.barVisibilityOverride = .hidden } let spacesSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator()) - spaceExplorerFlowCoordinator = SpaceExplorerFlowCoordinator(userSession: userSession, - navigationSplitCoordinator: spacesSplitCoordinator, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + spaceExplorerFlowCoordinator = SpaceExplorerFlowCoordinator(navigationSplitCoordinator: spacesSplitCoordinator, + flowParameters: flowParameters) spacesTabDetails = .init(tag: HomeTab.spaces, title: L10n.screenHomeTabSpaces, icon: \.space, selectedIcon: \.spaceSolid) spacesTabDetails.navigationSplitCoordinator = spacesSplitCoordinator onboardingStackCoordinator = NavigationStackCoordinator() - onboardingFlowCoordinator = OnboardingFlowCoordinator(userSession: userSession, + onboardingFlowCoordinator = OnboardingFlowCoordinator(isNewLogin: isNewLogin, appLockService: appLockService, - analyticsService: analytics, - appSettings: appSettings, - notificationManager: notificationManager, navigationStackCoordinator: onboardingStackCoordinator, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - windowManager: appMediator.windowManager, - isNewLogin: isNewLogin) + flowParameters: flowParameters) navigationTabCoordinator.setTabs([ .init(coordinator: chatsSplitCoordinator, details: chatsTabDetails), .init(coordinator: spacesSplitCoordinator, details: spacesTabDetails) ]) - stateMachine = stateMachineFactory.makeUserSessionFlowStateMachine(state: .initial) + stateMachine = flowParameters.stateMachineFactory.makeUserSessionFlowStateMachine(state: .initial) configureStateMachine() setupObservers() @@ -272,7 +241,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { } .store(in: &cancellables) - appSettings.$spacesEnabled + flowParameters.appSettings.$spacesEnabled .combineLatest(userSession.clientProxy.spaceService.joinedSpacesPublisher) .map { $0 && !$1.isEmpty ? nil : .hidden } .weakAssign(to: \.chatsTabDetails.barVisibilityOverride, on: self) @@ -294,16 +263,9 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { private func startSettingsFlow() { let navigationStackCoordinator = NavigationStackCoordinator() - let coordinator = SettingsFlowCoordinator(parameters: .init(userSession: userSession, - windowManager: appMediator.windowManager, - appLockService: appLockService, - bugReportService: bugReportService, - notificationSettings: userSession.clientProxy.notificationSettings, - secureBackupController: userSession.clientProxy.secureBackupController, - appSettings: appSettings, - navigationStackCoordinator: navigationStackCoordinator, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - analytics: analytics)) + let coordinator = SettingsFlowCoordinator(appLockService: appLockService, + navigationStackCoordinator: navigationStackCoordinator, + flowParameters: flowParameters) coordinator.actions.sink { [weak self] action in guard let self else { return } @@ -365,7 +327,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController, flow: flow, - appSettings: appSettings, + appSettings: flowParameters.appSettings, mediaProvider: userSession.mediaProvider) let coordinator = SessionVerificationScreenCoordinator(parameters: parameters) @@ -390,7 +352,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { let secureBackupController = userSession.clientProxy.secureBackupController guard case let .success(isLastDevice) = await userSession.clientProxy.isOnlyDeviceLeft() else { - ServiceLocator.shared.userIndicatorController.alertInfo = .init(id: .init()) + flowParameters.userIndicatorController.alertInfo = .init(id: .init()) return } @@ -400,26 +362,26 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { } 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) - }) + flowParameters.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) - }) + flowParameters.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 } @@ -427,17 +389,17 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { } 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) - }) + flowParameters.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)) + appMediator: flowParameters.appMediator)) coordinator.actions .sink { [weak self] action in diff --git a/ElementX/Sources/Mocks/ClientProxyMock.swift b/ElementX/Sources/Mocks/ClientProxyMock.swift index d98f4b044..09c3b88d7 100644 --- a/ElementX/Sources/Mocks/ClientProxyMock.swift +++ b/ElementX/Sources/Mocks/ClientProxyMock.swift @@ -18,6 +18,8 @@ struct ClientProxyMockConfiguration { var recoveryState: SecureBackupRecoveryState = .enabled + var notificationSettings = NotificationSettingsProxyMock(with: .init()) + var timelineMediaVisibility = TimelineMediaVisibility.always var hideInviteAvatars = false @@ -54,7 +56,7 @@ extension ClientProxyMock { ignoredUsersPublisher = CurrentValueSubject<[String]?, Never>([RoomMemberProxyMock].allMembers.map(\.userID)).asCurrentValuePublisher() - notificationSettings = NotificationSettingsProxyMock(with: .init()) + notificationSettings = configuration.notificationSettings isOnlyDeviceLeftReturnValue = .success(false) accountURLActionReturnValue = "https://matrix.org/account" diff --git a/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/NotificationSettingsEditScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/NotificationSettingsEditScreenCoordinator.swift index cf0471585..b75c5cd56 100644 --- a/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/NotificationSettingsEditScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/NotificationSettingsEditScreenCoordinator.swift @@ -12,7 +12,6 @@ struct NotificationSettingsEditScreenCoordinatorParameters { weak var navigationStackCoordinator: NavigationStackCoordinator? let chatType: NotificationSettingsChatType let userSession: UserSessionProtocol - let notificationSettings: NotificationSettingsProxyProtocol } final class NotificationSettingsEditScreenCoordinator: CoordinatorProtocol { @@ -24,8 +23,7 @@ final class NotificationSettingsEditScreenCoordinator: CoordinatorProtocol { self.parameters = parameters viewModel = NotificationSettingsEditScreenViewModel(chatType: parameters.chatType, - userSession: parameters.userSession, - notificationSettingsProxy: parameters.notificationSettings) + userSession: parameters.userSession) } func start() { @@ -51,7 +49,7 @@ final class NotificationSettingsEditScreenCoordinator: CoordinatorProtocol { guard case let .joined(roomProxy) = await parameters.userSession.clientProxy.roomForIdentifier(roomID) else { return } let roomNotificationSettingsParameters = RoomNotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: parameters.navigationStackCoordinator, - notificationSettingsProxy: parameters.notificationSettings, + notificationSettingsProxy: parameters.userSession.clientProxy.notificationSettings, roomProxy: roomProxy, displayAsUserDefinedRoomSettings: true) let roomNotificationSettingsCoordinator = RoomNotificationSettingsScreenCoordinator(parameters: roomNotificationSettingsParameters) diff --git a/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/NotificationSettingsEditScreenViewModel.swift b/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/NotificationSettingsEditScreenViewModel.swift index 80f5eb1e9..52ad3e72e 100644 --- a/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/NotificationSettingsEditScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/NotificationSettingsEditScreenViewModel.swift @@ -26,11 +26,11 @@ class NotificationSettingsEditScreenViewModel: NotificationSettingsEditScreenVie actionsSubject.eraseToAnyPublisher() } - init(chatType: NotificationSettingsChatType, userSession: UserSessionProtocol, notificationSettingsProxy: NotificationSettingsProxyProtocol) { + init(chatType: NotificationSettingsChatType, userSession: UserSessionProtocol) { let bindings = NotificationSettingsEditScreenViewStateBindings() self.chatType = chatType self.userSession = userSession - self.notificationSettingsProxy = notificationSettingsProxy + notificationSettingsProxy = userSession.clientProxy.notificationSettings roomSummaryProvider = userSession.clientProxy.roomSummaryProvider super.init(initialViewState: NotificationSettingsEditScreenViewState(bindings: bindings, diff --git a/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/View/NotificationSettingsEditScreen.swift b/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/View/NotificationSettingsEditScreen.swift index 7f8c11520..8bb50443c 100644 --- a/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/View/NotificationSettingsEditScreen.swift +++ b/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/View/NotificationSettingsEditScreen.swift @@ -65,10 +65,10 @@ struct NotificationSettingsEditScreen_Previews: PreviewProvider, TestablePreview notificationSettingsProxy.getRoomsWithUserDefinedRulesReturnValue = [RoomSummary].mockRooms.map(\.id) let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@alice:example.com", - roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))))))) + roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))), + notificationSettings: notificationSettingsProxy)))) var viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + userSession: userSession) viewModel.fetchInitialContent() return viewModel }() @@ -78,10 +78,10 @@ struct NotificationSettingsEditScreen_Previews: PreviewProvider, TestablePreview notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly notificationSettingsProxy.getRoomsWithUserDefinedRulesReturnValue = [] let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@alice:example.com", - roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))))))) + roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))), + notificationSettings: notificationSettingsProxy)))) var viewModel = NotificationSettingsEditScreenViewModel(chatType: .oneToOneChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + userSession: userSession) viewModel.fetchInitialContent() return viewModel }() @@ -90,11 +90,11 @@ struct NotificationSettingsEditScreen_Previews: PreviewProvider, TestablePreview let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init()) notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly notificationSettingsProxy.getRoomsWithUserDefinedRulesReturnValue = [] - let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "John Doe")))) + let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "John Doe", + notificationSettings: notificationSettingsProxy)))) var viewModel = NotificationSettingsEditScreenViewModel(chatType: .oneToOneChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + userSession: userSession) viewModel.state.pendingMode = .mentionsAndKeywordsOnly viewModel.fetchInitialContent() return viewModel @@ -106,10 +106,10 @@ struct NotificationSettingsEditScreen_Previews: PreviewProvider, TestablePreview notificationSettingsProxy.getRoomsWithUserDefinedRulesReturnValue = [RoomSummary].mockRooms.map(\.id) let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@alice:example.com", - roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))))))) + roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))), + notificationSettings: notificationSettingsProxy)))) var viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + userSession: userSession) viewModel.fetchInitialContent() return viewModel }() diff --git a/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/View/NotificationSettingsEditScreenRoomCell.swift b/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/View/NotificationSettingsEditScreenRoomCell.swift index ac4e46654..8c30541a6 100644 --- a/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/View/NotificationSettingsEditScreenRoomCell.swift +++ b/ElementX/Sources/Screens/Settings/NotificationSettingsEditScreen/View/NotificationSettingsEditScreenRoomCell.swift @@ -50,13 +50,14 @@ struct NotificationSettingsEditScreenRoomCell_Previews: PreviewProvider, Testabl static var previews: some View { let summaryProvider = RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))) - let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "John Doe", roomSummaryProvider: summaryProvider)))) - let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init()) notificationSettingsProxy.getRoomsWithUserDefinedRulesReturnValue = [] + + let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "John Doe", + roomSummaryProvider: summaryProvider, + notificationSettings: notificationSettingsProxy)))) let viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + userSession: userSession) let rooms: [NotificationSettingsEditScreenRoom] = summaryProvider.roomListPublisher.value.compactMap { summary -> NotificationSettingsEditScreenRoom? in NotificationSettingsEditScreenRoom(id: UUID().uuidString, diff --git a/ElementX/Sources/Screens/Settings/NotificationSettingsScreen/NotificationSettingsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/NotificationSettingsScreen/NotificationSettingsScreenCoordinator.swift index 785a7bf70..48fcda51a 100644 --- a/ElementX/Sources/Screens/Settings/NotificationSettingsScreen/NotificationSettingsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/NotificationSettingsScreen/NotificationSettingsScreenCoordinator.swift @@ -12,7 +12,6 @@ struct NotificationSettingsScreenCoordinatorParameters { weak var navigationStackCoordinator: NavigationStackCoordinator? let userSession: UserSessionProtocol let userNotificationCenter: UserNotificationCenterProtocol - let notificationSettings: NotificationSettingsProxyProtocol let isModallyPresented: Bool } @@ -39,7 +38,7 @@ final class NotificationSettingsScreenCoordinator: CoordinatorProtocol { viewModel = NotificationSettingsScreenViewModel(appSettings: ServiceLocator.shared.settings, userNotificationCenter: parameters.userNotificationCenter, - notificationSettingsProxy: parameters.notificationSettings, + notificationSettingsProxy: parameters.userSession.clientProxy.notificationSettings, isModallyPresented: parameters.isModallyPresented) } @@ -67,8 +66,7 @@ final class NotificationSettingsScreenCoordinator: CoordinatorProtocol { private func presentEditScreen(chatType: NotificationSettingsChatType) { let editSettingsParameters = NotificationSettingsEditScreenCoordinatorParameters(navigationStackCoordinator: parameters.navigationStackCoordinator, chatType: chatType, - userSession: parameters.userSession, - notificationSettings: parameters.notificationSettings) + userSession: parameters.userSession) let editSettingsCoordinator = NotificationSettingsEditScreenCoordinator(parameters: editSettingsParameters) navigationStackCoordinator?.push(editSettingsCoordinator) } diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index b37fbe368..4e7e17de5 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -592,22 +592,24 @@ class MockScreen: Identifiable { let appMediator = AppMediatorMock.default appMediator.underlyingWindowManager = windowManager - - let flowCoordinator = UserSessionFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)), - isNewLogin: false, + + let flowCoordinator = UserSessionFlowCoordinator(isNewLogin: false, navigationRootCoordinator: navigationRootCoordinator, appLockService: AppLockService(keychainController: KeychainControllerMock(), appSettings: ServiceLocator.shared.settings), - bugReportService: BugReportServiceMock(.init()), - elementCallService: ElementCallServiceMock(.init()), - timelineControllerFactory: TimelineControllerFactoryMock(.init()), - appMediator: appMediator, - appSettings: appSettings, - appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, - notificationManager: NotificationManagerMock(), - stateMachineFactory: StateMachineFactory()) - + flowParameters: CommonFlowParameters(userSession: UserSessionMock(.init(clientProxy: clientProxy)), + bugReportService: BugReportServiceMock(.init()), + elementCallService: ElementCallServiceMock(.init()), + timelineControllerFactory: TimelineControllerFactoryMock(.init()), + emojiProvider: EmojiProvider(appSettings: appSettings), + appMediator: appMediator, + appSettings: appSettings, + appHooks: AppHooks(), + analytics: ServiceLocator.shared.analytics, + userIndicatorController: UserIndicatorControllerMock(), + notificationManager: NotificationManagerMock(), + stateMachineFactory: StateMachineFactory())) + flowCoordinator.start() retainedState.append(flowCoordinator) @@ -751,21 +753,21 @@ class MockScreen: Identifiable { mediaProvider: MediaProviderMock(configuration: .init()), appSettings: ServiceLocator.shared.settings) - let flowCoordinator = ChatsFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)), - isNewLogin: false, + let flowCoordinator = ChatsFlowCoordinator(isNewLogin: false, navigationSplitCoordinator: navigationSplitCoordinator, - appLockService: AppLockService(keychainController: KeychainControllerMock(), - appSettings: ServiceLocator.shared.settings), - bugReportService: BugReportServiceMock(.init()), - elementCallService: ElementCallServiceMock(.init()), - timelineControllerFactory: TimelineControllerFactoryMock(.init(timelineController: timelineController)), - appMediator: AppMediatorMock.default, - appSettings: appSettings, - appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, - notificationManager: NotificationManagerMock(), - stateMachineFactory: StateMachineFactory()) - + flowParameters: CommonFlowParameters(userSession: UserSessionMock(.init(clientProxy: clientProxy)), + bugReportService: BugReportServiceMock(.init()), + elementCallService: ElementCallServiceMock(.init()), + timelineControllerFactory: TimelineControllerFactoryMock(.init(timelineController: timelineController)), + emojiProvider: EmojiProvider(appSettings: appSettings), + appMediator: AppMediatorMock.default, + appSettings: appSettings, + appHooks: AppHooks(), + analytics: ServiceLocator.shared.analytics, + userIndicatorController: UserIndicatorControllerMock(), + notificationManager: NotificationManagerMock(), + stateMachineFactory: StateMachineFactory())) + flowCoordinator.start() retainedState.append(flowCoordinator) diff --git a/UnitTests/Sources/ChatsFlowCoordinatorTests.swift b/UnitTests/Sources/ChatsFlowCoordinatorTests.swift index a14fa8f00..44207f009 100644 --- a/UnitTests/Sources/ChatsFlowCoordinatorTests.swift +++ b/UnitTests/Sources/ChatsFlowCoordinatorTests.swift @@ -33,19 +33,21 @@ class ChatsFlowCoordinatorTests: XCTestCase { notificationManager = NotificationManagerMock() - chatsFlowCoordinator = ChatsFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)), - isNewLogin: false, + let flowParameters = CommonFlowParameters(userSession: UserSessionMock(.init(clientProxy: clientProxy)), + bugReportService: BugReportServiceMock(.init()), + elementCallService: ElementCallServiceMock(.init()), + timelineControllerFactory: timelineControllerFactory, + emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appMediator: AppMediatorMock.default, + appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), + analytics: ServiceLocator.shared.analytics, + userIndicatorController: UserIndicatorControllerMock(), + notificationManager: notificationManager, + stateMachineFactory: stateMachineFactory) + chatsFlowCoordinator = ChatsFlowCoordinator(isNewLogin: false, navigationSplitCoordinator: splitCoordinator, - appLockService: AppLockServiceMock(), - bugReportService: BugReportServiceMock(.init()), - elementCallService: ElementCallServiceMock(.init()), - timelineControllerFactory: timelineControllerFactory, - appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, - notificationManager: notificationManager, - stateMachineFactory: stateMachineFactory) + flowParameters: flowParameters) let deferred = deferFulfillment(stateMachineFactory.chatsFlowStatePublisher) { $0 == .roomList(roomListSelectedRoomID: nil) } chatsFlowCoordinator.start() diff --git a/UnitTests/Sources/NotificationSettingsEditScreenViewModelTests.swift b/UnitTests/Sources/NotificationSettingsEditScreenViewModelTests.swift index fb67bc56f..f841460a8 100644 --- a/UnitTests/Sources/NotificationSettingsEditScreenViewModelTests.swift +++ b/UnitTests/Sources/NotificationSettingsEditScreenViewModelTests.swift @@ -14,17 +14,19 @@ import XCTest class NotificationSettingsEditScreenViewModelTests: XCTestCase { private var viewModel: NotificationSettingsEditScreenViewModelProtocol! private var notificationSettingsProxy: NotificationSettingsProxyMock! - private var userSession: UserSessionProtocol! + private var userSession: UserSessionMock! + private var clientProxy: ClientProxyMock! private var context: NotificationSettingsEditScreenViewModelType.Context { viewModel.context } @MainActor override func setUpWithError() throws { - let clientProxy = ClientProxyMock(.init(userID: "@a:b.com")) - userSession = UserSessionMock(.init(clientProxy: clientProxy)) notificationSettingsProxy = NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration()) notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .allMessages + + clientProxy = ClientProxyMock(.init(userID: "@a:b.com", notificationSettings: notificationSettingsProxy)) + userSession = UserSessionMock(.init(clientProxy: clientProxy)) } func testFetchSettings() async throws { @@ -36,9 +38,7 @@ class NotificationSettingsEditScreenViewModelTests: XCTestCase { return .mentionsAndKeywordsOnly } } - viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, userSession: userSession) let deferred = deferFulfillment(viewModel.context.observe(\.viewState.defaultMode)) { $0 != nil } @@ -75,9 +75,7 @@ class NotificationSettingsEditScreenViewModelTests: XCTestCase { notificationSettingsProxy.canPushEncryptedEventsToDeviceClosure = { true } - viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, userSession: userSession) let deferred = deferFulfillment(viewModel.context.observe(\.viewState.defaultMode)) { $0 != nil } @@ -104,9 +102,7 @@ class NotificationSettingsEditScreenViewModelTests: XCTestCase { func testSetModeAllMessages() async throws { notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly - viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, userSession: userSession) let deferred = deferFulfillment(viewModel.context.observe(\.viewState.defaultMode)) { $0 != nil } viewModel.fetchInitialContent() @@ -142,9 +138,7 @@ class NotificationSettingsEditScreenViewModelTests: XCTestCase { } func testSetModeMentions() async throws { - viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + viewModel = NotificationSettingsEditScreenViewModel(chatType: .groupChat, userSession: userSession) let deferred = deferFulfillment(viewModel.context.observe(\.viewState.defaultMode)) { $0 != nil } @@ -183,9 +177,7 @@ class NotificationSettingsEditScreenViewModelTests: XCTestCase { func testSetModeDirectChats() async throws { notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly // Initialize for direct chats - viewModel = NotificationSettingsEditScreenViewModel(chatType: .oneToOneChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + viewModel = NotificationSettingsEditScreenViewModel(chatType: .oneToOneChat, userSession: userSession) let deferred = deferFulfillment(viewModel.context.observe(\.viewState.defaultMode)) { $0 != nil } @@ -216,9 +208,7 @@ class NotificationSettingsEditScreenViewModelTests: XCTestCase { func testSetModeFailure() async throws { notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly notificationSettingsProxy.setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeThrowableError = NotificationSettingsError.Generic(msg: "error") - viewModel = NotificationSettingsEditScreenViewModel(chatType: .oneToOneChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + viewModel = NotificationSettingsEditScreenViewModel(chatType: .oneToOneChat, userSession: userSession) let deferred = deferFulfillment(viewModel.context.observe(\.viewState.defaultMode)) { $0 != nil } @@ -238,9 +228,7 @@ class NotificationSettingsEditScreenViewModelTests: XCTestCase { func testSelectRoom() async throws { let roomID = "!roomidentifier:matrix.org" - viewModel = NotificationSettingsEditScreenViewModel(chatType: .oneToOneChat, - userSession: userSession, - notificationSettingsProxy: notificationSettingsProxy) + viewModel = NotificationSettingsEditScreenViewModel(chatType: .oneToOneChat, userSession: userSession) let deferredActions = deferFulfillment(viewModel.actions) { action in switch action { diff --git a/UnitTests/Sources/RoomFlowCoordinatorTests.swift b/UnitTests/Sources/RoomFlowCoordinatorTests.swift index 083ace2fd..30553e32f 100644 --- a/UnitTests/Sources/RoomFlowCoordinatorTests.swift +++ b/UnitTests/Sources/RoomFlowCoordinatorTests.swift @@ -358,18 +358,23 @@ class RoomFlowCoordinatorTests: XCTestCase { "1" } - roomFlowCoordinator = RoomFlowCoordinator(roomID: roomID, - userSession: UserSessionMock(.init(clientProxy: clientProxy)), - isChildFlow: asChildFlow, + let flowParameters = CommonFlowParameters(userSession: UserSessionMock(.init(clientProxy: clientProxy)), + bugReportService: BugReportServiceMock(.init()), + elementCallService: ElementCallServiceMock(.init()), timelineControllerFactory: timelineControllerFactory, - navigationStackCoordinator: navigationStackCoordinator, emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), - ongoingCallRoomIDPublisher: .init(.init(nil)), appMediator: AppMediatorMock.default, appSettings: ServiceLocator.shared.settings, appHooks: AppHooks(), analytics: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController) + userIndicatorController: ServiceLocator.shared.userIndicatorController, + notificationManager: NotificationManagerMock(), + stateMachineFactory: StateMachineFactory()) + + roomFlowCoordinator = RoomFlowCoordinator(roomID: roomID, + isChildFlow: asChildFlow, + navigationStackCoordinator: navigationStackCoordinator, + flowParameters: flowParameters) } } diff --git a/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift b/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift index e511ead19..6f4e061e2 100644 --- a/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift +++ b/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift @@ -35,19 +35,23 @@ class UserSessionFlowCoordinatorTests: XCTestCase { notificationManager = NotificationManagerMock() - userSessionFlowCoordinator = UserSessionFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)), - isNewLogin: false, + let flowParameters = CommonFlowParameters(userSession: UserSessionMock(.init(clientProxy: clientProxy)), + bugReportService: BugReportServiceMock(.init()), + elementCallService: ElementCallServiceMock(.init()), + timelineControllerFactory: timelineControllerFactory, + emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings), + appMediator: AppMediatorMock.default, + appSettings: ServiceLocator.shared.settings, + appHooks: AppHooks(), + analytics: ServiceLocator.shared.analytics, + userIndicatorController: UserIndicatorControllerMock(), + notificationManager: notificationManager, + stateMachineFactory: stateMachineFactory) + + userSessionFlowCoordinator = UserSessionFlowCoordinator(isNewLogin: false, navigationRootCoordinator: rootCoordinator, appLockService: AppLockServiceMock(), - bugReportService: BugReportServiceMock(.init()), - elementCallService: ElementCallServiceMock(.init()), - timelineControllerFactory: timelineControllerFactory, - appMediator: AppMediatorMock.default, - appSettings: ServiceLocator.shared.settings, - appHooks: AppHooks(), - analytics: ServiceLocator.shared.analytics, - notificationManager: notificationManager, - stateMachineFactory: stateMachineFactory) + flowParameters: flowParameters) userSessionFlowCoordinator.start() }