mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 20:09:04 +00:00
Handle in-timeline permalinks to spaces
This will continue the RoomFlow with a SpaceFlow, fetch the SpaceRoomList from the SpaceService and render its rooms.
This commit is contained in:
committed by
Stefan Ceriu
parent
27f7085dc1
commit
b0a2db8ed3
@@ -79,6 +79,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
private var mediaEventsTimelineFlowCoordinator: MediaEventsTimelineFlowCoordinator?
|
private var mediaEventsTimelineFlowCoordinator: MediaEventsTimelineFlowCoordinator?
|
||||||
// periphery:ignore - used to avoid deallocation
|
// periphery:ignore - used to avoid deallocation
|
||||||
private var childRoomFlowCoordinator: RoomFlowCoordinator?
|
private var childRoomFlowCoordinator: RoomFlowCoordinator?
|
||||||
|
// periphery:ignore - retaining purpose
|
||||||
|
private var spaceFlowCoordinator: SpaceFlowCoordinator?
|
||||||
|
|
||||||
private let stateMachine: StateMachine<State, Event> = .init(state: .initial)
|
private let stateMachine: StateMachine<State, Event> = .init(state: .initial)
|
||||||
|
|
||||||
@@ -257,24 +259,36 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
switch room {
|
switch room {
|
||||||
case .joined(let roomProxy):
|
case .joined(let roomProxy):
|
||||||
await storeAndSubscribeToRoomProxy(roomProxy)
|
if roomProxy.infoPublisher.value.isSpace {
|
||||||
guard case let .eventFocus(focusEvent) = presentationAction else {
|
switch await userSession.clientProxy.spaceService.spaceRoomList(spaceID: roomProxy.id, parent: nil) {
|
||||||
// If is not a focus event just handle the presentation action directly in `presentRoom`
|
case .success(let spaceRoomListProxy):
|
||||||
stateMachine.tryEvent(.presentRoom(presentationAction: presentationAction), userInfo: EventUserInfo(animated: animated))
|
actionsSubject.send(.continueWithSpaceFlow(spaceRoomListProxy))
|
||||||
return
|
case .failure:
|
||||||
}
|
showErrorIndicator()
|
||||||
// Otherwise check if the focussed event exists to handle a possible error or theaded event.
|
stateMachine.tryEvent(.dismissFlow)
|
||||||
switch await roomProxy.loadOrFetchEventDetails(for: focusEvent.eventID) {
|
}
|
||||||
case .success(let event):
|
} else {
|
||||||
if flowParameters.appSettings.threadsEnabled, let threadRootEventID = event.threadRootEventId() {
|
await storeAndSubscribeToRoomProxy(roomProxy)
|
||||||
stateMachine.tryEvent(.presentRoom(presentationAction: .eventFocus(.init(eventID: threadRootEventID, shouldSetPin: false))), userInfo: EventUserInfo(animated: animated))
|
|
||||||
stateMachine.tryEvent(.presentThread(threadRootEventID: threadRootEventID, focusEventID: focusEvent.eventID), userInfo: EventUserInfo(animated: false))
|
guard case let .eventFocus(focusEvent) = presentationAction else {
|
||||||
} else {
|
// If is not a focus event just handle the presentation action directly in `presentRoom`
|
||||||
stateMachine.tryEvent(.presentRoom(presentationAction: presentationAction), userInfo: EventUserInfo(animated: animated))
|
stateMachine.tryEvent(.presentRoom(presentationAction: presentationAction), userInfo: EventUserInfo(animated: animated))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise check if the focussed event exists to handle a possible error or theaded event.
|
||||||
|
switch await roomProxy.loadOrFetchEventDetails(for: focusEvent.eventID) {
|
||||||
|
case .success(let event):
|
||||||
|
if flowParameters.appSettings.threadsEnabled, let threadRootEventID = event.threadRootEventId() {
|
||||||
|
stateMachine.tryEvent(.presentRoom(presentationAction: .eventFocus(.init(eventID: threadRootEventID, shouldSetPin: false))), userInfo: EventUserInfo(animated: animated))
|
||||||
|
stateMachine.tryEvent(.presentThread(threadRootEventID: threadRootEventID, focusEventID: focusEvent.eventID), userInfo: EventUserInfo(animated: false))
|
||||||
|
} else {
|
||||||
|
stateMachine.tryEvent(.presentRoom(presentationAction: presentationAction), userInfo: EventUserInfo(animated: animated))
|
||||||
|
}
|
||||||
|
case .failure:
|
||||||
|
showErrorIndicator()
|
||||||
|
stateMachine.tryEvent(.presentRoom(presentationAction: nil), userInfo: EventUserInfo(animated: animated))
|
||||||
}
|
}
|
||||||
case .failure:
|
|
||||||
showErrorIndicator()
|
|
||||||
stateMachine.tryEvent(.presentRoom(presentationAction: nil), userInfo: EventUserInfo(animated: animated))
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
stateMachine.tryEvent(.presentJoinRoomScreen(via: via), userInfo: EventUserInfo(animated: animated))
|
stateMachine.tryEvent(.presentJoinRoomScreen(via: via), userInfo: EventUserInfo(animated: animated))
|
||||||
@@ -322,7 +336,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:disable:next function_body_length
|
// swiftlint:disable:next function_body_length cyclomatic_complexity
|
||||||
private func setupStateMachine() {
|
private func setupStateMachine() {
|
||||||
addRouteMapping(stateMachine: stateMachine)
|
addRouteMapping(stateMachine: stateMachine)
|
||||||
|
|
||||||
@@ -353,6 +367,14 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
// Thread + Room
|
// Thread + Room
|
||||||
|
|
||||||
|
case (_, .startSpaceFlow, .spaceFlow):
|
||||||
|
guard let spaceRoomListProxy = (context.userInfo as? EventUserInfo)?.spaceRoomListProxy else {
|
||||||
|
fatalError("The space room list proxy is required to present a space.")
|
||||||
|
}
|
||||||
|
startSpaceFlow(spaceRoomListProxy: spaceRoomListProxy, animated: animated)
|
||||||
|
case (.spaceFlow, .finishedSpaceFlow, _):
|
||||||
|
spaceFlowCoordinator = nil
|
||||||
|
|
||||||
case (_, .presentReportContent, .reportContent(let itemID, let senderID, _)):
|
case (_, .presentReportContent, .reportContent(let itemID, let senderID, _)):
|
||||||
presentReportContent(for: itemID, from: senderID)
|
presentReportContent(for: itemID, from: senderID)
|
||||||
|
|
||||||
@@ -1521,7 +1543,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
case .verifyUser(let userID):
|
case .verifyUser(let userID):
|
||||||
actionsSubject.send(.verifyUser(userID: userID))
|
actionsSubject.send(.verifyUser(userID: userID))
|
||||||
case .continueWithSpaceFlow(let spaceRoomListProxy):
|
case .continueWithSpaceFlow(let spaceRoomListProxy):
|
||||||
#warning("Present the space as a child.")
|
stateMachine.tryEvent(.startSpaceFlow, userInfo: EventUserInfo(animated: true, spaceRoomListProxy: spaceRoomListProxy))
|
||||||
case .finished:
|
case .finished:
|
||||||
stateMachine.tryEvent(.dismissChildFlow)
|
stateMachine.tryEvent(.dismissChildFlow)
|
||||||
}
|
}
|
||||||
@@ -1610,6 +1632,31 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
flowCoordinator.start()
|
flowCoordinator.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func startSpaceFlow(spaceRoomListProxy: SpaceRoomListProxyProtocol, animated: Bool) {
|
||||||
|
let coordinator = SpaceFlowCoordinator(entryPoint: .space(spaceRoomListProxy),
|
||||||
|
spaceServiceProxy: userSession.clientProxy.spaceService,
|
||||||
|
isChildFlow: true,
|
||||||
|
navigationStackCoordinator: navigationStackCoordinator,
|
||||||
|
flowParameters: flowParameters)
|
||||||
|
coordinator.actionsPublisher
|
||||||
|
.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
switch action {
|
||||||
|
case .presentCallScreen(let roomProxy):
|
||||||
|
actionsSubject.send(.presentCallScreen(roomProxy: roomProxy))
|
||||||
|
case .verifyUser(let userID):
|
||||||
|
actionsSubject.send(.verifyUser(userID: userID))
|
||||||
|
case .finished:
|
||||||
|
stateMachine.tryEvent(.finishedSpaceFlow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
spaceFlowCoordinator = coordinator
|
||||||
|
|
||||||
|
coordinator.start()
|
||||||
|
}
|
||||||
|
|
||||||
private static let loadingIndicatorID = "\(RoomFlowCoordinator.self)-Loading"
|
private static let loadingIndicatorID = "\(RoomFlowCoordinator.self)-Loading"
|
||||||
|
|
||||||
private func showLoadingIndicator(delay: Duration? = nil,
|
private func showLoadingIndicator(delay: Duration? = nil,
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ extension RoomFlowCoordinator {
|
|||||||
case presentingChild(childRoomID: String, previousState: State)
|
case presentingChild(childRoomID: String, previousState: State)
|
||||||
/// The flow is complete and is handing control of the stack back to its parent.
|
/// The flow is complete and is handing control of the stack back to its parent.
|
||||||
case complete
|
case complete
|
||||||
|
|
||||||
|
/// A space flow is in progress
|
||||||
|
case spaceFlow(previousState: State)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EventUserInfo {
|
struct EventUserInfo {
|
||||||
@@ -98,6 +101,9 @@ extension RoomFlowCoordinator {
|
|||||||
case presentThread(threadRootEventID: String, focusEventID: String?)
|
case presentThread(threadRootEventID: String, focusEventID: String?)
|
||||||
case dismissThread
|
case dismissThread
|
||||||
|
|
||||||
|
case startSpaceFlow
|
||||||
|
case finishedSpaceFlow
|
||||||
|
|
||||||
case presentReportContent(itemID: TimelineItemIdentifier, senderID: String)
|
case presentReportContent(itemID: TimelineItemIdentifier, senderID: String)
|
||||||
case dismissReportContent
|
case dismissReportContent
|
||||||
|
|
||||||
@@ -341,6 +347,11 @@ extension RoomFlowCoordinator {
|
|||||||
return .presentingChild(childRoomID: roomID, previousState: fromState)
|
return .presentingChild(childRoomID: roomID, previousState: fromState)
|
||||||
case (.presentingChild(_, let previousState), .dismissChildFlow):
|
case (.presentingChild(_, let previousState), .dismissChildFlow):
|
||||||
return previousState
|
return previousState
|
||||||
|
|
||||||
|
case (.presentingChild(_, let previousState), .startSpaceFlow):
|
||||||
|
return .spaceFlow(previousState: previousState)
|
||||||
|
case (.spaceFlow(let previousState), .finishedSpaceFlow):
|
||||||
|
return previousState
|
||||||
|
|
||||||
case (_, .presentRoomMemberDetails(userID: let userID)):
|
case (_, .presentRoomMemberDetails(userID: let userID)):
|
||||||
return .roomMemberDetails(userID: userID, previousState: fromState)
|
return .roomMemberDetails(userID: userID, previousState: fromState)
|
||||||
|
|||||||
Reference in New Issue
Block a user