mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
dd support for deeplinking/navigating into the same room multiple times
- fix bugs around the view <-> view models going out of sync - unwind the stack if the room is already presented
This commit is contained in:
parent
f9163094ba
commit
d949b17448
@ -19,6 +19,7 @@ import SwiftState
|
||||
import SwiftUI
|
||||
import UserNotifications
|
||||
|
||||
// swiftlint:disable file_length
|
||||
enum RoomFlowCoordinatorAction: Equatable {
|
||||
case presentRoom(roomID: String)
|
||||
case presentCallScreen(roomProxy: RoomProxyProtocol)
|
||||
@ -38,7 +39,7 @@ enum RoomFlowCoordinatorAction: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable file_length
|
||||
// swiftlint:disable:next type_body_length
|
||||
class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let roomID: String
|
||||
private let userSession: UserSessionProtocol
|
||||
@ -104,6 +105,10 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
|
||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||
guard stateMachine.state != .complete else {
|
||||
fatalError("This flow coordinator is `finished` ☠️")
|
||||
}
|
||||
|
||||
switch appRoute {
|
||||
case .room(let roomID):
|
||||
Task {
|
||||
@ -324,7 +329,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
dismissFlow(animated: animated)
|
||||
|
||||
case (_, .presentRoom, .room):
|
||||
Task { await self.presentRoom(animated: animated) }
|
||||
Task { await self.presentRoom(fromState: context.fromState, animated: animated) }
|
||||
case (_, .dismissFlow, .complete):
|
||||
dismissFlow(animated: animated)
|
||||
|
||||
@ -463,11 +468,25 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
/// Updates the navigation stack so it displays the timeline for the given room
|
||||
/// - Parameters:
|
||||
/// - animated: whether it should animate the transition
|
||||
private func presentRoom(animated: Bool) async {
|
||||
private func presentRoom(fromState: State, animated: Bool) async {
|
||||
// If any sheets are presented dismiss them, rely on their dismissal callbacks to transition the state machine
|
||||
// through the correct states before presenting the room
|
||||
navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
|
||||
// Handle selecting the same room again
|
||||
if !isChildFlow {
|
||||
// First unwind the navigation stack
|
||||
navigationStackCoordinator.popToRoot(animated: animated)
|
||||
|
||||
// And then decide if the room actually needs to be presented again
|
||||
switch fromState {
|
||||
case .initial, .roomDetails(isRoot: true), .joinRoomScreen:
|
||||
break
|
||||
default:
|
||||
return // The room is already on the stack, no need to present it again
|
||||
}
|
||||
}
|
||||
|
||||
Task {
|
||||
// Flag the room as read on entering, the timeline will take care of the read receipts
|
||||
await roomProxy.flagAsUnread(false)
|
||||
@ -649,7 +668,10 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
if isRoot {
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator, animated: animated) { [weak self] in
|
||||
self?.stateMachine.tryEvent(.dismissFlow)
|
||||
guard let self else { return }
|
||||
if stateMachine.state != .room { // The root has been replaced by a room
|
||||
stateMachine.tryEvent(.dismissFlow)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
navigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in
|
||||
|
@ -267,8 +267,14 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
presentHomeScreen()
|
||||
attemptStartingOnboarding()
|
||||
|
||||
case(.roomList, .selectRoom(let roomID, let showingRoomDetails), .roomList):
|
||||
Task { await self.startRoomFlow(roomID: roomID, showingRoomDetails: showingRoomDetails, animated: animated) }
|
||||
case(.roomList(let selectedRoomID), .selectRoom(let roomID, let showingRoomDetails), .roomList):
|
||||
if selectedRoomID == roomID {
|
||||
if let roomFlowCoordinator {
|
||||
roomFlowCoordinator.handleAppRoute(.room(roomID: roomID), animated: animated)
|
||||
}
|
||||
} else {
|
||||
Task { await self.startRoomFlow(roomID: roomID, showingRoomDetails: showingRoomDetails, animated: animated) }
|
||||
}
|
||||
case(.roomList, .deselectRoom, .roomList):
|
||||
dismissRoomFlow(animated: animated)
|
||||
|
||||
|
@ -162,6 +162,8 @@ class RoomFlowCoordinatorTests: XCTestCase {
|
||||
try await clearRoute(expectedActions: [.finished])
|
||||
XCTAssertNil(navigationStackCoordinator.rootCoordinator)
|
||||
|
||||
await setupRoomFlowCoordinator(roomType: .invited(roomID: "InvitedRoomID"))
|
||||
|
||||
try await process(route: .room(roomID: "InvitedRoomID"))
|
||||
XCTAssert(navigationStackCoordinator.rootCoordinator is JoinRoomScreenCoordinator)
|
||||
XCTAssertEqual(navigationStackCoordinator.stackCoordinators.count, 0)
|
||||
@ -188,7 +190,8 @@ class RoomFlowCoordinatorTests: XCTestCase {
|
||||
try await clearRoute(expectedActions: [.finished])
|
||||
XCTAssertNil(navigationStackCoordinator.stackCoordinators.last, "A child room flow should remove the join room scren on dismissal")
|
||||
|
||||
navigationStackCoordinator.popToRoot()
|
||||
await setupRoomFlowCoordinator(asChildFlow: true, roomType: .invited(roomID: "InvitedRoomID"))
|
||||
navigationStackCoordinator.setRootCoordinator(BlankFormCoordinator())
|
||||
|
||||
try await process(route: .room(roomID: "InvitedRoomID"))
|
||||
XCTAssertTrue(navigationStackCoordinator.rootCoordinator is BlankFormCoordinator, "A child room flow should push onto the stack, leaving the root alone.")
|
||||
|
1
changelog.d/2653.bugfix
Normal file
1
changelog.d/2653.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fix deeplinking/navigating into the same room multiple times
|
Loading…
x
Reference in New Issue
Block a user