Re-introduce a basic UserSessionFlowCoordinator using the NavigationTabCoordinator.

This commit is contained in:
Doug
2025-07-29 15:55:27 +01:00
committed by Doug
parent 5658a30136
commit 1ca84c8c94
8 changed files with 160 additions and 52 deletions
@@ -46,7 +46,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
private let appLockFlowCoordinator: AppLockFlowCoordinator
// periphery:ignore - used to avoid deallocation
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
private var userSessionFlowCoordinator: ChatsFlowCoordinator?
private var userSessionFlowCoordinator: UserSessionFlowCoordinator?
private var softLogoutCoordinator: SoftLogoutScreenCoordinator?
private var appDelegateObserver: AnyCancellable?
private var userSessionObserver: AnyCancellable?
@@ -640,18 +640,18 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
fatalError("User session not setup")
}
let userSessionFlowCoordinator = ChatsFlowCoordinator(userSession: userSession,
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,
isNewLogin: isNewLogin)
let userSessionFlowCoordinator = UserSessionFlowCoordinator(userSession: userSession,
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,
isNewLogin: isNewLogin)
userSessionFlowCoordinator.actionsPublisher
.sink { [weak self] action in
@@ -20,7 +20,6 @@ enum ChatsFlowCoordinatorAction {
class ChatsFlowCoordinator: FlowCoordinatorProtocol {
private let userSession: UserSessionProtocol
private let navigationRootCoordinator: NavigationRootCoordinator
private let navigationSplitCoordinator: NavigationSplitCoordinator
private let bugReportService: BugReportServiceProtocol
private let elementCallService: ElementCallServiceProtocol
@@ -65,7 +64,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
var statePublisher: AnyPublisher<ChatsFlowCoordinatorStateMachine.State, Never> { stateMachine.statePublisher }
init(userSession: UserSessionProtocol,
navigationRootCoordinator: NavigationRootCoordinator,
navigationSplitCoordinator: NavigationSplitCoordinator,
appLockService: AppLockServiceProtocol,
bugReportService: BugReportServiceProtocol,
elementCallService: ElementCallServiceProtocol,
@@ -78,7 +77,7 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
isNewLogin: Bool) {
stateMachine = ChatsFlowCoordinatorStateMachine()
self.userSession = userSession
self.navigationRootCoordinator = navigationRootCoordinator
self.navigationSplitCoordinator = navigationSplitCoordinator
self.bugReportService = bugReportService
self.elementCallService = elementCallService
self.timelineControllerFactory = timelineControllerFactory
@@ -88,8 +87,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
self.analytics = analytics
self.notificationManager = notificationManager
navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
sidebarNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator)
detailNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator)
@@ -554,8 +551,6 @@ class ChatsFlowCoordinator: FlowCoordinatorProtocol {
.store(in: &cancellables)
sidebarNavigationStackCoordinator.setRootCoordinator(coordinator)
navigationRootCoordinator.setRootCoordinator(navigationSplitCoordinator)
}
private func presentReportRoom(for roomID: String) async {
@@ -0,0 +1,106 @@
//
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Combine
import Compound
import MatrixRustSDK
import SwiftUI
enum UserSessionFlowCoordinatorAction {
case logout
case clearCache
/// Logout without a confirmation. The user forgot their PIN.
case forceLogout
}
class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
private let userSession: UserSessionProtocol
private let navigationRootCoordinator: NavigationRootCoordinator
private let navigationTabCoordinator: NavigationTabCoordinator
private let chatsFlowCoordinator: ChatsFlowCoordinator
private let actionsSubject: PassthroughSubject<UserSessionFlowCoordinatorAction, Never> = .init()
var actionsPublisher: AnyPublisher<UserSessionFlowCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
private var cancellables: Set<AnyCancellable> = []
init(userSession: UserSessionProtocol,
navigationRootCoordinator: NavigationRootCoordinator,
appLockService: AppLockServiceProtocol,
bugReportService: BugReportServiceProtocol,
elementCallService: ElementCallServiceProtocol,
timelineControllerFactory: TimelineControllerFactoryProtocol,
appMediator: AppMediatorProtocol,
appSettings: AppSettings,
appHooks: AppHooks,
analytics: AnalyticsService,
notificationManager: NotificationManagerProtocol,
isNewLogin: Bool) {
self.userSession = userSession
self.navigationRootCoordinator = navigationRootCoordinator
navigationTabCoordinator = NavigationTabCoordinator()
navigationRootCoordinator.setRootCoordinator(navigationTabCoordinator)
let chatsSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
chatsFlowCoordinator = ChatsFlowCoordinator(userSession: userSession,
navigationSplitCoordinator: chatsSplitCoordinator,
appLockService: appLockService,
bugReportService: bugReportService,
elementCallService: elementCallService,
timelineControllerFactory: timelineControllerFactory,
appMediator: appMediator,
appSettings: appSettings,
appHooks: appHooks,
analytics: analytics,
notificationManager: notificationManager,
isNewLogin: isNewLogin)
navigationTabCoordinator.setTabs([
.init(coordinator: chatsSplitCoordinator, title: L10n.screenHomeTabChats, icon: \.chat, selectedIcon: \.chatSolid),
.init(coordinator: BlankFormCoordinator(), title: L10n.screenHomeTabSpaces, icon: \.space, selectedIcon: \.spaceSolid)
])
chatsFlowCoordinator.actionsPublisher
.sink { [weak self] action in
guard let self else { return }
switch action {
case .logout:
actionsSubject.send(.logout)
case .clearCache:
actionsSubject.send(.clearCache)
case .forceLogout:
actionsSubject.send(.forceLogout)
}
}
.store(in: &cancellables)
}
func start() {
chatsFlowCoordinator.start()
}
func stop() {
chatsFlowCoordinator.stop()
}
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
chatsFlowCoordinator.handleAppRoute(appRoute, animated: animated)
}
func clearRoute(animated: Bool) {
chatsFlowCoordinator.clearRoute(animated: animated)
}
#warning("Should this be a publisher instead??")
func isDisplayingRoomScreen(withRoomID roomID: String) -> Bool {
chatsFlowCoordinator.isDisplayingRoomScreen(withRoomID: roomID)
}
}
@@ -582,26 +582,25 @@ class MockScreen: Identifiable {
appSettings.hasRunIdentityConfirmationOnboarding = true
appSettings.hasRunNotificationPermissionsOnboarding = true
appSettings.analyticsConsentState = .optedOut
let navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
let clientProxy = ClientProxyMock(.init(userID: "@mock:client.com", deviceID: "MOCKCLIENT", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))))
let appMediator = AppMediatorMock.default
appMediator.underlyingWindowManager = windowManager
let flowCoordinator = ChatsFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
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(),
isNewLogin: false)
let flowCoordinator = UserSessionFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
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(),
isNewLogin: false)
flowCoordinator.start()
@@ -729,6 +728,7 @@ class MockScreen: Identifiable {
appSettings.hasRunNotificationPermissionsOnboarding = true
appSettings.analyticsConsentState = .optedOut
let navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
navigationRootCoordinator.setRootCoordinator(navigationSplitCoordinator)
let clientProxy = ClientProxyMock(.init(userID: "@mock:client.com", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))))
@@ -746,7 +746,7 @@ class MockScreen: Identifiable {
appSettings: ServiceLocator.shared.settings)
let flowCoordinator = ChatsFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
navigationRootCoordinator: navigationRootCoordinator,
navigationSplitCoordinator: navigationSplitCoordinator,
appLockService: AppLockService(keychainController: KeychainControllerMock(),
appSettings: ServiceLocator.shared.settings),
bugReportService: BugReportServiceMock(.init()),