Handle external links to a user. (#2690)

This commit is contained in:
Doug
2024-04-15 11:08:00 +01:00
committed by GitHub
parent e0138eeb35
commit e7af7fb59c
22 changed files with 450 additions and 154 deletions
@@ -129,7 +129,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
} else {
stateMachine.tryEvent(.presentRoomMemberDetails(userID: userID), userInfo: EventUserInfo(animated: animated))
}
case .genericCallLink, .oidcCallback, .settings, .chatBackupSettings:
case .userProfile, .genericCallLink, .oidcCallback, .settings, .chatBackupSettings:
break
}
}
@@ -875,7 +875,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
roomProxy: roomProxy,
clientProxy: userSession.clientProxy,
mediaProvider: userSession.mediaProvider,
userIndicatorController: userIndicatorController)
userIndicatorController: userIndicatorController,
analytics: analytics)
let coordinator = RoomMemberDetailsScreenCoordinator(parameters: params)
coordinator.actions.sink { [weak self] action in
@@ -883,8 +884,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
switch action {
case .openUserProfile:
stateMachine.tryEvent(.presentUserProfile(userID: userID))
case .openDirectChat(let displayName):
openDirectChat(with: userID, displayName: displayName)
case .openDirectChat(let roomID):
stateMachine.tryEvent(.presentChildRoom(roomID: roomID))
}
}
.store(in: &cancellables)
@@ -896,16 +897,20 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
private func replaceRoomMemberDetailsWithUserProfile(userID: String) {
let parameters = UserProfileScreenCoordinatorParameters(userID: userID,
isPresentedModally: false,
clientProxy: userSession.clientProxy,
mediaProvider: userSession.mediaProvider,
userIndicatorController: userIndicatorController)
userIndicatorController: userIndicatorController,
analytics: analytics)
let coordinator = UserProfileScreenCoordinator(parameters: parameters)
coordinator.actionsPublisher.sink { [weak self] action in
guard let self else { return }
switch action {
case .openDirectChat(let displayName):
openDirectChat(with: userID, displayName: displayName)
case .openDirectChat(let roomID):
stateMachine.tryEvent(.presentChildRoom(roomID: roomID))
case .dismiss:
break // Not supported when pushed.
}
}
.store(in: &cancellables)
@@ -917,37 +922,6 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
}
private func openDirectChat(with userID: String, displayName: String?) {
let loadingIndicatorIdentifier = "OpenDirectChatLoadingIndicator"
userIndicatorController.submitIndicator(UserIndicator(id: loadingIndicatorIdentifier,
type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false),
title: L10n.commonLoading,
persistent: true))
Task { [weak self] in
guard let self else { return }
let currentDirectRoom = await userSession.clientProxy.directRoomForUserID(userID)
switch currentDirectRoom {
case .success(.some(let roomID)):
stateMachine.tryEvent(.presentChildRoom(roomID: roomID))
case .success(nil):
switch await userSession.clientProxy.createDirectRoom(with: userID, expectedRoomName: displayName) {
case .success(let roomID):
analytics.trackCreatedRoom(isDM: true)
stateMachine.tryEvent(.presentChildRoom(roomID: roomID))
case .failure:
userIndicatorController.alertInfo = .init(id: UUID())
}
case .failure:
userIndicatorController.alertInfo = .init(id: UUID())
}
userIndicatorController.retractIndicatorWithId(loadingIndicatorIdentifier)
}
}
private func presentMessageForwarding(for itemID: TimelineItemIdentifier) {
guard let roomSummaryProvider = userSession.clientProxy.alternateRoomSummaryProvider, let eventID = itemID.eventID else {
fatalError()
@@ -195,6 +195,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
}
case .roomList, .roomMemberDetails:
self.roomFlowCoordinator?.handleAppRoute(appRoute, animated: animated)
case .userProfile(let userID):
stateMachine.processEvent(.showUserProfileScreen(userID: userID), userInfo: .init(animated: animated))
case .genericCallLink(let url):
self.navigationSplitCoordinator.setSheetCoordinator(GenericCallLinkCoordinator(parameters: .init(url: url)), animated: animated)
case .oidcCallback:
@@ -302,6 +304,11 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
presentRoomDirectorySearch()
case (.roomDirectorySearchScreen, .dismissedRoomDirectorySearchScreen, .roomList):
dismissRoomDirectorySearch()
case (_, .showUserProfileScreen(let userID), .userProfileScreen):
presentUserProfileScreen(userID: userID, animated: animated)
case (.userProfileScreen, .dismissedUserProfileScreen, .roomList):
break
default:
fatalError("Unknown transition: \(context)")
@@ -654,4 +661,36 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
private func dismissRoomDirectorySearch() {
navigationSplitCoordinator.setFullScreenCoverCoordinator(nil)
}
// MARK: User Profile
private func presentUserProfileScreen(userID: String, animated: Bool) {
clearRoute(animated: animated)
let navigationStackCoordinator = NavigationStackCoordinator()
let parameters = UserProfileScreenCoordinatorParameters(userID: userID,
isPresentedModally: true,
clientProxy: userSession.clientProxy,
mediaProvider: userSession.mediaProvider,
userIndicatorController: ServiceLocator.shared.userIndicatorController,
analytics: analytics)
let coordinator = UserProfileScreenCoordinator(parameters: parameters)
coordinator.actionsPublisher.sink { [weak self] action in
guard let self else { return }
switch action {
case .openDirectChat(let roomID):
navigationSplitCoordinator.setSheetCoordinator(nil)
stateMachine.processEvent(.selectRoom(roomID: roomID, showingRoomDetails: false))
case .dismiss:
navigationSplitCoordinator.setSheetCoordinator(nil)
}
}
.store(in: &cancellables)
navigationStackCoordinator.setRootCoordinator(coordinator, animated: false)
navigationSplitCoordinator.setSheetCoordinator(navigationStackCoordinator, animated: animated) { [weak self] in
self?.stateMachine.processEvent(.dismissedUserProfileScreen)
}
}
}
@@ -27,7 +27,7 @@ class UserSessionFlowCoordinatorStateMachine {
/// Showing the home screen. The `selectedRoomID` represents the timeline shown on the detail panel (if any)
case roomList(selectedRoomID: String?)
/// Showing the session verification flows
/// Showing the feedback screen.
case feedbackScreen(selectedRoomID: String?)
/// Showing the settings screen
@@ -45,10 +45,13 @@ class UserSessionFlowCoordinatorStateMachine {
/// Showing Room Directory Search screen
case roomDirectorySearchScreen(selectedRoomID: String?)
/// Showing the user profile screen. This screen clears the navigation.
case userProfileScreen
/// The selected room ID from the state if available.
var selectedRoomID: String? {
switch self {
case .initial:
case .initial, .userProfileScreen:
nil
case .roomList(let selectedRoomID),
.feedbackScreen(let selectedRoomID),
@@ -102,9 +105,15 @@ class UserSessionFlowCoordinatorStateMachine {
/// Logout has been cancelled
case dismissedLogoutConfirmationScreen
/// Request presentation of the room directory search screen.
case showRoomDirectorySearchScreen
/// The room directory search screen has been dismissed.
case dismissedRoomDirectorySearchScreen
/// Request presentation of the user profile screen.
case showUserProfileScreen(userID: String)
/// The user profile screen has been dismissed.
case dismissedUserProfileScreen
}
private let stateMachine: StateMachine<State, Event>
@@ -169,6 +178,11 @@ class UserSessionFlowCoordinatorStateMachine {
return .roomDirectorySearchScreen(selectedRoomID: selectedRoomID)
case (.roomDirectorySearchScreen(let selectedRoomID), .dismissedRoomDirectorySearchScreen):
return .roomList(selectedRoomID: selectedRoomID)
case (_, .showUserProfileScreen):
return .userProfileScreen
case (.userProfileScreen, .dismissedUserProfileScreen):
return .roomList(selectedRoomID: nil)
default:
return nil