From 84ec5a37ff0eddc66c64796f185ec15f711a146d Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 29 Nov 2023 13:57:32 +0200 Subject: [PATCH] Fixes #2179 - Open direct chat directly from the room member details screen --- .../en.lproj/Localizable.strings | 1 + .../RoomFlowCoordinator.swift | 40 ++++++++++++++++++- ElementX/Sources/Generated/Strings.swift | 2 + .../Other/AccessibilityIdentifiers.swift | 1 + .../RoomMemberDetailsScreenCoordinator.swift | 18 +++++++-- .../RoomMemberDetailsScreenModels.swift | 5 ++- .../RoomMemberDetailsScreenViewModel.swift | 2 + .../View/RoomMemberDetailsScreen.swift | 12 ++++++ changelog.d/2179.feature | 1 + 9 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 changelog.d/2179.feature diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index 205f80735..980903fe0 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -108,6 +108,7 @@ "common_dark" = "Dark"; "common_decryption_error" = "Decryption error"; "common_developer_options" = "Developer options"; +"common_direct_chat" = "Direct chat"; "common_edited_suffix" = "(edited)"; "common_editing" = "Editing"; "common_emote" = "* %1$@ %2$@"; diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index b4200b765..4f1458a95 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -86,8 +86,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { func handleAppRoute(_ appRoute: AppRoute, animated: Bool) { switch appRoute { case .room(let roomID): - if case .room(let identifier) = stateMachine.state, - roomID == identifier { + if case .room(let roomID) = stateMachine.state, + roomID == roomID { return } @@ -853,6 +853,42 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { mediaProvider: userSession.mediaProvider, userIndicatorController: userIndicatorController) let coordinator = RoomMemberDetailsScreenCoordinator(parameters: params) + + coordinator.actions.sink { [weak self] action in + guard let self else { return } + switch action { + case .openDirectChat: + 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(member.userID) + switch currentDirectRoom { + case .success(.some(let roomID)): + stateMachine.tryEvent(.presentRoom(roomID: roomID)) + case .success(nil): + switch await userSession.clientProxy.createDirectRoom(with: member.userID, expectedRoomName: member.displayName) { + case .success(let roomID): + analytics.trackCreatedRoom(isDM: true) + stateMachine.tryEvent(.presentRoom(roomID: roomID)) + case .failure: + userIndicatorController.alertInfo = .init(id: UUID()) + } + case .failure: + userIndicatorController.alertInfo = .init(id: UUID()) + } + + userIndicatorController.retractIndicatorWithId(loadingIndicatorIdentifier) + } + } + } + .store(in: &cancellables) navigationStackCoordinator.push(coordinator) { [weak self] in self?.stateMachine.tryEvent(.dismissRoomMemberDetails) diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index 119b7f777..ac2924610 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -250,6 +250,8 @@ public enum L10n { public static var commonDecryptionError: String { return L10n.tr("Localizable", "common_decryption_error") } /// Developer options public static var commonDeveloperOptions: String { return L10n.tr("Localizable", "common_developer_options") } + /// Direct chat + public static var commonDirectChat: String { return L10n.tr("Localizable", "common_direct_chat") } /// (edited) public static var commonEditedSuffix: String { return L10n.tr("Localizable", "common_edited_suffix") } /// Editing diff --git a/ElementX/Sources/Other/AccessibilityIdentifiers.swift b/ElementX/Sources/Other/AccessibilityIdentifiers.swift index ce485fd95..dcdba7607 100644 --- a/ElementX/Sources/Other/AccessibilityIdentifiers.swift +++ b/ElementX/Sources/Other/AccessibilityIdentifiers.swift @@ -175,6 +175,7 @@ enum A11yIdentifiers { struct RoomMemberDetailsScreen { let ignore = "room_member_details-ignore" let unignore = "room_member_details-unignore" + let directChat = "room_member_details-direct_chat" } struct RoomNotificationSettingsScreen { diff --git a/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenCoordinator.swift b/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenCoordinator.swift index 0a1d7727e..a7f149f5f 100644 --- a/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenCoordinator.swift @@ -24,7 +24,9 @@ struct RoomMemberDetailsScreenCoordinatorParameters { let userIndicatorController: UserIndicatorControllerProtocol } -enum RoomMemberDetailsScreenCoordinatorAction { } +enum RoomMemberDetailsScreenCoordinatorAction { + case openDirectChat +} final class RoomMemberDetailsScreenCoordinator: CoordinatorProtocol { private let parameters: RoomMemberDetailsScreenCoordinatorParameters @@ -45,8 +47,18 @@ final class RoomMemberDetailsScreenCoordinator: CoordinatorProtocol { mediaProvider: parameters.mediaProvider, userIndicatorController: parameters.userIndicatorController) } - - func start() { } + + func start() { + viewModel.actions.sink { [weak self] action in + guard let self else { return } + + switch action { + case .openDirectChat: + actionsSubject.send(.openDirectChat) + } + } + .store(in: &cancellables) + } func stop() { viewModel.stop() } diff --git a/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenModels.swift b/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenModels.swift index a60eda7cf..668583363 100644 --- a/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenModels.swift +++ b/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenModels.swift @@ -16,7 +16,9 @@ import Foundation -enum RoomMemberDetailsScreenViewModelAction { } +enum RoomMemberDetailsScreenViewModelAction { + case openDirectChat +} struct RoomMemberDetailsScreenViewState: BindableState { var details: RoomMemberDetails @@ -77,6 +79,7 @@ enum RoomMemberDetailsScreenViewAction { case ignoreConfirmed case unignoreConfirmed case displayAvatar + case openDirectChat } enum RoomMemberDetailsScreenError: Hashable { diff --git a/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenViewModel.swift b/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenViewModel.swift index 786e947fe..7043c729f 100644 --- a/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenViewModel.swift @@ -65,6 +65,8 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro Task { await unignoreUser() } case .displayAvatar: displayFullScreenAvatar() + case .openDirectChat: + actionsSubject.send(.openDirectChat) } } diff --git a/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift b/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift index e6fd6d783..0221efab5 100644 --- a/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift +++ b/ElementX/Sources/Screens/RoomMemberDetailsScreen/View/RoomMemberDetailsScreen.swift @@ -25,6 +25,7 @@ struct RoomMemberDetailsScreen: View { headerSection if !context.viewState.details.isAccountOwner { + directChatSection blockUserSection } } @@ -58,6 +59,17 @@ struct RoomMemberDetailsScreen: View { } } } + + private var directChatSection: some View { + Section { + ListRow(label: .default(title: L10n.commonDirectChat, + icon: \.chat), + kind: .button { + context.send(viewAction: .openDirectChat) + }) + .accessibilityIdentifier(A11yIdentifiers.roomMemberDetailsScreen.directChat) + } + } private var blockUserSection: some View { Section { diff --git a/changelog.d/2179.feature b/changelog.d/2179.feature new file mode 100644 index 000000000..9c9bde267 --- /dev/null +++ b/changelog.d/2179.feature @@ -0,0 +1 @@ +Open direct chat directly from the room member details screen \ No newline at end of file