Fix some app route navigation bugs. (#4415)

- Opening a notification would update the stack with an animated pop.
- Opening a permalink from the timeline wouldn't push the room as a child.
This commit is contained in:
Doug
2025-08-15 10:34:01 +01:00
committed by GitHub
parent f1f6cace77
commit 3f6fc03ffd
4 changed files with 43 additions and 5 deletions
@@ -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 {
@@ -5,7 +5,6 @@
// Please see LICENSE files in the repository root for full details.
//
import Algorithms
import Combine
import Foundation
import MatrixRustSDK
@@ -5,6 +5,7 @@
// Please see LICENSE files in the repository root for full details.
//
import Algorithms
import Combine
import Foundation
import MatrixRustSDK
@@ -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)