Rename UserSessionFlowCoordinator to ChatsFlowCoordinator.

This commit is contained in:
Doug
2025-07-29 15:03:32 +01:00
committed by Doug
parent 4943db841a
commit 5658a30136
5 changed files with 77 additions and 77 deletions
@@ -46,7 +46,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
private let appLockFlowCoordinator: AppLockFlowCoordinator private let appLockFlowCoordinator: AppLockFlowCoordinator
// periphery:ignore - used to avoid deallocation // periphery:ignore - used to avoid deallocation
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator? private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
private var userSessionFlowCoordinator: UserSessionFlowCoordinator? private var userSessionFlowCoordinator: ChatsFlowCoordinator?
private var softLogoutCoordinator: SoftLogoutScreenCoordinator? private var softLogoutCoordinator: SoftLogoutScreenCoordinator?
private var appDelegateObserver: AnyCancellable? private var appDelegateObserver: AnyCancellable?
private var userSessionObserver: AnyCancellable? private var userSessionObserver: AnyCancellable?
@@ -640,18 +640,18 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
fatalError("User session not setup") fatalError("User session not setup")
} }
let userSessionFlowCoordinator = UserSessionFlowCoordinator(userSession: userSession, let userSessionFlowCoordinator = ChatsFlowCoordinator(userSession: userSession,
navigationRootCoordinator: navigationRootCoordinator, navigationRootCoordinator: navigationRootCoordinator,
appLockService: appLockFlowCoordinator.appLockService, appLockService: appLockFlowCoordinator.appLockService,
bugReportService: ServiceLocator.shared.bugReportService, bugReportService: ServiceLocator.shared.bugReportService,
elementCallService: elementCallService, elementCallService: elementCallService,
timelineControllerFactory: TimelineControllerFactory(), timelineControllerFactory: TimelineControllerFactory(),
appMediator: appMediator, appMediator: appMediator,
appSettings: appSettings, appSettings: appSettings,
appHooks: appHooks, appHooks: appHooks,
analytics: ServiceLocator.shared.analytics, analytics: ServiceLocator.shared.analytics,
notificationManager: notificationManager, notificationManager: notificationManager,
isNewLogin: isNewLogin) isNewLogin: isNewLogin)
userSessionFlowCoordinator.actionsPublisher userSessionFlowCoordinator.actionsPublisher
.sink { [weak self] action in .sink { [weak self] action in
@@ -11,14 +11,14 @@ import Combine
import MatrixRustSDK import MatrixRustSDK
import SwiftUI import SwiftUI
enum UserSessionFlowCoordinatorAction { enum ChatsFlowCoordinatorAction {
case logout case logout
case clearCache case clearCache
/// Logout without a confirmation. The user forgot their PIN. /// Logout without a confirmation. The user forgot their PIN.
case forceLogout case forceLogout
} }
class UserSessionFlowCoordinator: FlowCoordinatorProtocol { class ChatsFlowCoordinator: FlowCoordinatorProtocol {
private let userSession: UserSessionProtocol private let userSession: UserSessionProtocol
private let navigationRootCoordinator: NavigationRootCoordinator private let navigationRootCoordinator: NavigationRootCoordinator
private let navigationSplitCoordinator: NavigationSplitCoordinator private let navigationSplitCoordinator: NavigationSplitCoordinator
@@ -30,7 +30,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
private let analytics: AnalyticsService private let analytics: AnalyticsService
private let notificationManager: NotificationManagerProtocol private let notificationManager: NotificationManagerProtocol
private let stateMachine: UserSessionFlowCoordinatorStateMachine private let stateMachine: ChatsFlowCoordinatorStateMachine
// periphery:ignore - retaining purpose // periphery:ignore - retaining purpose
private var roomFlowCoordinator: RoomFlowCoordinator? private var roomFlowCoordinator: RoomFlowCoordinator?
@@ -56,13 +56,13 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
private let selectedRoomSubject = CurrentValueSubject<String?, Never>(nil) private let selectedRoomSubject = CurrentValueSubject<String?, Never>(nil)
private let actionsSubject: PassthroughSubject<UserSessionFlowCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<ChatsFlowCoordinatorAction, Never> = .init()
var actionsPublisher: AnyPublisher<UserSessionFlowCoordinatorAction, Never> { var actionsPublisher: AnyPublisher<ChatsFlowCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
/// For testing purposes. /// For testing purposes.
var statePublisher: AnyPublisher<UserSessionFlowCoordinatorStateMachine.State, Never> { stateMachine.statePublisher } var statePublisher: AnyPublisher<ChatsFlowCoordinatorStateMachine.State, Never> { stateMachine.statePublisher }
init(userSession: UserSessionProtocol, init(userSession: UserSessionProtocol,
navigationRootCoordinator: NavigationRootCoordinator, navigationRootCoordinator: NavigationRootCoordinator,
@@ -76,7 +76,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
analytics: AnalyticsService, analytics: AnalyticsService,
notificationManager: NotificationManagerProtocol, notificationManager: NotificationManagerProtocol,
isNewLogin: Bool) { isNewLogin: Bool) {
stateMachine = UserSessionFlowCoordinatorStateMachine() stateMachine = ChatsFlowCoordinatorStateMachine()
self.userSession = userSession self.userSession = userSession
self.navigationRootCoordinator = navigationRootCoordinator self.navigationRootCoordinator = navigationRootCoordinator
self.bugReportService = bugReportService self.bugReportService = bugReportService
@@ -242,7 +242,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
private func setupStateMachine() { private func setupStateMachine() {
stateMachine.addTransitionHandler { [weak self] context in stateMachine.addTransitionHandler { [weak self] context in
guard let self else { return } guard let self else { return }
let animated = (context.userInfo as? UserSessionFlowCoordinatorStateMachine.EventUserInfo)?.animated ?? true let animated = (context.userInfo as? ChatsFlowCoordinatorStateMachine.EventUserInfo)?.animated ?? true
switch (context.fromState, context.event, context.toState) { switch (context.fromState, context.event, context.toState) {
case (.initial, .start, .roomList): case (.initial, .start, .roomList):
presentHomeScreen() presentHomeScreen()
@@ -1067,8 +1067,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
// MARK: Toasts and loading indicators // MARK: Toasts and loading indicators
private static let loadingIndicatorIdentifier = "\(UserSessionFlowCoordinator.self)-Loading" private static let loadingIndicatorIdentifier = "\(ChatsFlowCoordinator.self)-Loading"
private static let failureIndicatorIdentifier = "\(UserSessionFlowCoordinator.self)-Failure" private static let failureIndicatorIdentifier = "\(ChatsFlowCoordinator.self)-Failure"
private func showLoadingIndicator(delay: Duration? = nil) { private func showLoadingIndicator(delay: Duration? = nil) {
ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier,
@@ -9,7 +9,7 @@ import Combine
import Foundation import Foundation
import SwiftState import SwiftState
class UserSessionFlowCoordinatorStateMachine { class ChatsFlowCoordinatorStateMachine {
/// States the AppCoordinator can find itself in /// States the AppCoordinator can find itself in
enum State: StateType { enum State: StateType {
/// The initial state, used before the coordinator starts /// The initial state, used before the coordinator starts
@@ -138,7 +138,7 @@ class UserSessionFlowCoordinatorStateMachine {
private let stateMachine: StateMachine<State, Event> private let stateMachine: StateMachine<State, Event>
var state: UserSessionFlowCoordinatorStateMachine.State { var state: ChatsFlowCoordinatorStateMachine.State {
stateMachine.state stateMachine.state
} }
@@ -589,19 +589,19 @@ class MockScreen: Identifiable {
let appMediator = AppMediatorMock.default let appMediator = AppMediatorMock.default
appMediator.underlyingWindowManager = windowManager appMediator.underlyingWindowManager = windowManager
let flowCoordinator = UserSessionFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)), let flowCoordinator = ChatsFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
navigationRootCoordinator: navigationRootCoordinator, navigationRootCoordinator: navigationRootCoordinator,
appLockService: AppLockService(keychainController: KeychainControllerMock(), appLockService: AppLockService(keychainController: KeychainControllerMock(),
appSettings: ServiceLocator.shared.settings), appSettings: ServiceLocator.shared.settings),
bugReportService: BugReportServiceMock(.init()), bugReportService: BugReportServiceMock(.init()),
elementCallService: ElementCallServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()),
timelineControllerFactory: TimelineControllerFactoryMock(.init()), timelineControllerFactory: TimelineControllerFactoryMock(.init()),
appMediator: appMediator, appMediator: appMediator,
appSettings: appSettings, appSettings: appSettings,
appHooks: AppHooks(), appHooks: AppHooks(),
analytics: ServiceLocator.shared.analytics, analytics: ServiceLocator.shared.analytics,
notificationManager: NotificationManagerMock(), notificationManager: NotificationManagerMock(),
isNewLogin: false) isNewLogin: false)
flowCoordinator.start() flowCoordinator.start()
@@ -745,19 +745,19 @@ class MockScreen: Identifiable {
mediaProvider: MediaProviderMock(configuration: .init()), mediaProvider: MediaProviderMock(configuration: .init()),
appSettings: ServiceLocator.shared.settings) appSettings: ServiceLocator.shared.settings)
let flowCoordinator = UserSessionFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)), let flowCoordinator = ChatsFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
navigationRootCoordinator: navigationRootCoordinator, navigationRootCoordinator: navigationRootCoordinator,
appLockService: AppLockService(keychainController: KeychainControllerMock(), appLockService: AppLockService(keychainController: KeychainControllerMock(),
appSettings: ServiceLocator.shared.settings), appSettings: ServiceLocator.shared.settings),
bugReportService: BugReportServiceMock(.init()), bugReportService: BugReportServiceMock(.init()),
elementCallService: ElementCallServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()),
timelineControllerFactory: TimelineControllerFactoryMock(.init(timelineController: timelineController)), timelineControllerFactory: TimelineControllerFactoryMock(.init(timelineController: timelineController)),
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: appSettings, appSettings: appSettings,
appHooks: AppHooks(), appHooks: AppHooks(),
analytics: ServiceLocator.shared.analytics, analytics: ServiceLocator.shared.analytics,
notificationManager: NotificationManagerMock(), notificationManager: NotificationManagerMock(),
isNewLogin: false) isNewLogin: false)
flowCoordinator.start() flowCoordinator.start()
@@ -11,10 +11,10 @@ import Combine
@testable import ElementX @testable import ElementX
@MainActor @MainActor
class UserSessionFlowCoordinatorTests: XCTestCase { class ChatsFlowCoordinatorTests: XCTestCase {
var clientProxy: ClientProxyMock! var clientProxy: ClientProxyMock!
var timelineControllerFactory: TimelineControllerFactoryMock! var timelineControllerFactory: TimelineControllerFactoryMock!
var userSessionFlowCoordinator: UserSessionFlowCoordinator! var chatsFlowCoordinator: ChatsFlowCoordinator!
var navigationRootCoordinator: NavigationRootCoordinator! var navigationRootCoordinator: NavigationRootCoordinator!
var notificationManager: NotificationManagerMock! var notificationManager: NotificationManagerMock!
@@ -33,21 +33,21 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
notificationManager = NotificationManagerMock() notificationManager = NotificationManagerMock()
userSessionFlowCoordinator = UserSessionFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)), chatsFlowCoordinator = ChatsFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
navigationRootCoordinator: navigationRootCoordinator, navigationRootCoordinator: navigationRootCoordinator,
appLockService: AppLockServiceMock(), appLockService: AppLockServiceMock(),
bugReportService: BugReportServiceMock(.init()), bugReportService: BugReportServiceMock(.init()),
elementCallService: ElementCallServiceMock(.init()), elementCallService: ElementCallServiceMock(.init()),
timelineControllerFactory: timelineControllerFactory, timelineControllerFactory: timelineControllerFactory,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
appHooks: AppHooks(), appHooks: AppHooks(),
analytics: ServiceLocator.shared.analytics, analytics: ServiceLocator.shared.analytics,
notificationManager: notificationManager, notificationManager: notificationManager,
isNewLogin: false) isNewLogin: false)
let deferred = deferFulfillment(userSessionFlowCoordinator.statePublisher) { $0 == .roomList(roomListSelectedRoomID: nil) } let deferred = deferFulfillment(chatsFlowCoordinator.statePublisher) { $0 == .roomList(roomListSelectedRoomID: nil) }
userSessionFlowCoordinator.start() chatsFlowCoordinator.start()
try await deferred.fulfill() try await deferred.fulfill()
} }
@@ -128,8 +128,8 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator) XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
XCTAssertNotNil(detailCoordinator) XCTAssertNotNil(detailCoordinator)
let unexpectedFulfillment = deferFailure(userSessionFlowCoordinator.statePublisher, timeout: 1) { _ in true } let unexpectedFulfillment = deferFailure(chatsFlowCoordinator.statePublisher, timeout: 1) { _ in true }
userSessionFlowCoordinator.handleAppRoute(.roomDetails(roomID: "1"), animated: true) chatsFlowCoordinator.handleAppRoute(.roomDetails(roomID: "1"), animated: true)
try await unexpectedFulfillment.fulfill() try await unexpectedFulfillment.fulfill()
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator) XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
@@ -151,8 +151,8 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator) XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
XCTAssertNotNil(detailCoordinator) XCTAssertNotNil(detailCoordinator)
let unexpectedFulfillment = deferFailure(userSessionFlowCoordinator.statePublisher, timeout: 1) { _ in true } let unexpectedFulfillment = deferFailure(chatsFlowCoordinator.statePublisher, timeout: 1) { _ in true }
userSessionFlowCoordinator.handleAppRoute(.roomDetails(roomID: "1"), animated: true) chatsFlowCoordinator.handleAppRoute(.roomDetails(roomID: "1"), animated: true)
try await unexpectedFulfillment.fulfill() try await unexpectedFulfillment.fulfill()
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator) XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
@@ -192,7 +192,7 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0) XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
XCTAssertNotNil(detailCoordinator) XCTAssertNotNil(detailCoordinator)
userSessionFlowCoordinator.handleAppRoute(.childRoom(roomID: "2", via: []), animated: true) chatsFlowCoordinator.handleAppRoute(.childRoom(roomID: "2", via: []), animated: true)
try await Task.sleep(for: .milliseconds(100)) try await Task.sleep(for: .milliseconds(100))
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator) XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 1) XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 1)
@@ -215,7 +215,7 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "1") XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "1")
// A child event route should push a new room screen onto the stack and focus on the event. // A child event route should push a new room screen onto the stack and focus on the event.
userSessionFlowCoordinator.handleAppRoute(.childEvent(eventID: "2", roomID: "2", via: []), animated: true) chatsFlowCoordinator.handleAppRoute(.childEvent(eventID: "2", roomID: "2", via: []), animated: true)
try await Task.sleep(for: .milliseconds(100)) try await Task.sleep(for: .milliseconds(100))
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator) XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 1) XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 1)
@@ -290,12 +290,12 @@ class UserSessionFlowCoordinatorTests: XCTestCase {
// MARK: - Private // MARK: - Private
private func process(route: AppRoute, expectedState: UserSessionFlowCoordinatorStateMachine.State) async throws { private func process(route: AppRoute, expectedState: ChatsFlowCoordinatorStateMachine.State) async throws {
// Sometimes the state machine's state changes before the coordinators have updated the stack. // Sometimes the state machine's state changes before the coordinators have updated the stack.
let delayedPublisher = userSessionFlowCoordinator.statePublisher.delay(for: .milliseconds(100), scheduler: DispatchQueue.main) let delayedPublisher = chatsFlowCoordinator.statePublisher.delay(for: .milliseconds(100), scheduler: DispatchQueue.main)
let deferred = deferFulfillment(delayedPublisher) { $0 == expectedState } let deferred = deferFulfillment(delayedPublisher) { $0 == expectedState }
userSessionFlowCoordinator.handleAppRoute(route, animated: true) chatsFlowCoordinator.handleAppRoute(route, animated: true)
try await deferred.fulfill() try await deferred.fulfill()
} }
} }