diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index d15520eb5..775cd31fd 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -157,20 +157,32 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { .roomDetails, .roomMemberDetails, .userProfile, .event, .eventOnRoomAlias, .childEvent, .childEventOnRoomAlias, .call, .genericCallLink, .share, .transferOwnership: - clearRoute(animated: animated) // Make sure the presented route is visible. + clearPresentedSheets(animated: animated) // Make sure the presented route is visible. chatsFlowCoordinator.handleAppRoute(appRoute, animated: animated) - navigationTabCoordinator.selectedTab = .chats + if navigationTabCoordinator.selectedTab != .chats { + navigationTabCoordinator.selectedTab = .chats + } } } func clearRoute(animated: Bool) { + clearPresentedSheets(animated: animated) + chatsFlowCoordinator.clearRoute(animated: animated) + } + + // Clearing routes is more complicated than it first seems. When passing routes + // to the chats flow we can't clear all routes as e.g. childRoom/childEvent etc + // expect to push into the existing stack. But we do need to hide any sheets that + // might cover up the presented route. BUT! We probably shouldn't dismiss onboarding + // or verification flows until they're complete… This needs more thought before we + // codify it all into the state machine. + private func clearPresentedSheets(animated: Bool) { switch stateMachine.state { case .initial, .tabBar: break case .settingsScreen: navigationTabCoordinator.setSheetCoordinator(nil, animated: animated) } - chatsFlowCoordinator.clearRoute(animated: animated) } func isDisplayingRoomScreen(withRoomID roomID: String) -> Bool { @@ -258,7 +270,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { // MARK: - Onboarding - func attemptStartingOnboarding() { + private func attemptStartingOnboarding() { MXLog.info("Attempting to start onboarding") if onboardingFlowCoordinator.shouldStart { diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 6366de349..8bbcb3132 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -5,7 +5,6 @@ // Please see LICENSE files in the repository root for full details. // -import Algorithms import Combine import Foundation import MatrixRustSDK diff --git a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift index 31f632515..a9b28c239 100644 --- a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift @@ -5,6 +5,7 @@ // Please see LICENSE files in the repository root for full details. // +import Algorithms import Combine import Foundation import MatrixRustSDK diff --git a/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift b/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift index c1c34ff58..e511ead19 100644 --- a/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift +++ b/UnitTests/Sources/UserSessionFlowCoordinatorTests.swift @@ -68,6 +68,32 @@ class UserSessionFlowCoordinatorTests: XCTestCase { XCTAssertNotNil(detailCoordinator) } + func testRoomPresentationClearsSettings() async throws { + try await process(route: .settings, expectedUserSessionState: .settingsScreen) + XCTAssertTrue((tabCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is SettingsScreenCoordinator) + XCTAssertNil(detailCoordinator) + + try await process(route: .room(roomID: "1", via: []), expectedChatsState: .roomList(roomListSelectedRoomID: "1")) + XCTAssertNil((tabCoordinator?.sheetCoordinator)) + XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator) + XCTAssertNotNil(detailCoordinator) + } + + func testChildRoomPresentation() async throws { + try await process(route: .room(roomID: "1", via: []), expectedChatsState: .roomList(roomListSelectedRoomID: "1")) + let detailNavigationStack = try XCTUnwrap(detailNavigationStack, "There must be a navigation stack.") + XCTAssertTrue(detailNavigationStack.rootCoordinator is RoomScreenCoordinator) + XCTAssertNotNil(detailCoordinator) + + let deferred = deferFulfillment(detailNavigationStack.observe(\.stackCoordinators.count)) { $0 == 1 } + try await process(route: .childRoom(roomID: "2", via: [])) + try await deferred.fulfill() + XCTAssertTrue(detailNavigationStack.rootCoordinator is RoomScreenCoordinator) + XCTAssertNotNil(detailCoordinator) + XCTAssertEqual(detailNavigationStack.stackCoordinators.count, 1) + XCTAssertTrue(detailNavigationStack.stackCoordinators.first is RoomScreenCoordinator) + } + func testShareMediaRouteWithoutRoom() async throws { try await process(route: .settings, expectedUserSessionState: .settingsScreen) XCTAssertTrue((tabCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is SettingsScreenCoordinator)