From b56b190442c61a879ca905e1712bf351b78677fe Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Thu, 1 Jun 2023 18:08:34 +0200 Subject: [PATCH 1/2] Prompt the user when the invited MatrixId is not recognized --- Riot/Assets/en.lproj/Vector.strings | 5 +++ Riot/Generated/Strings.swift | 20 +++++++++++ .../Views/RoomTitle/MXKRoomTitleView.m | 2 +- .../ContactsPickerCoordinator.swift | 8 +++++ .../ContactsPickerViewModel.swift | 27 ++++++++++++--- .../ContactsPickerViewModelProtocol.swift | 2 ++ Riot/Modules/Room/RoomCoordinator.swift | 33 ++++++++++++++++--- Riot/Modules/Room/RoomViewController.m | 2 +- changelog.d/7558.change | 1 + 9 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 changelog.d/7558.change diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 563dc13b9..132e5dd25 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -366,6 +366,9 @@ "room_creation_error_invite_user_by_email_without_identity_server" = "No identity server is configured so you cannot add a participant with an email."; "room_creation_dm_error" = "We couldn't create your DM. Please check the users you want to invite and try again."; "room_creation_only_one_email_invite" = "You can only invite one email at a time"; +"room_creation_user_not_found_prompt_title" = "Confirmation"; +"room_creation_user_not_found_prompt_message" = "Unable to find profiles for this Matrix ID. Would you like to start a DM anyway?"; +"room_creation_user_not_found_prompt_invite_action" = "Start DM anyway"; // Room recents "room_recents_directory_section" = "ROOM DIRECTORY"; @@ -459,6 +462,8 @@ Tap the + to start adding people."; "room_participants_invite_prompt_title" = "Confirmation"; "room_participants_invite_prompt_msg" = "Are you sure you want to invite %@ to this chat?"; "room_participants_invite_prompt_to_msg" = "Are you sure you want to invite %@ to %@?"; +"room_participants_invite_unknown_participant_prompt_to_msg" = "Unable to find profiles for this Matrix ID. Are you sure you want to invite %@ to %@?"; +"room_participants_invite_anyway" = "Invite anyway"; "room_participants_filter_room_members" = "Filter room members"; "room_participants_filter_room_members_for_dm" = "Filter members"; "room_participants_invite_another_user" = "Search / invite by User ID, Name or email"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 2e23e0457..1c2516fe9 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -5371,6 +5371,18 @@ public class VectorL10n: NSObject { public static var roomCreationTitle: String { return VectorL10n.tr("Vector", "room_creation_title") } + /// Start DM anyway + public static var roomCreationUserNotFoundPromptInviteAction: String { + return VectorL10n.tr("Vector", "room_creation_user_not_found_prompt_invite_action") + } + /// Unable to find profiles for this Matrix ID. Would you like to start a DM anyway? + public static var roomCreationUserNotFoundPromptMessage: String { + return VectorL10n.tr("Vector", "room_creation_user_not_found_prompt_message") + } + /// Confirmation + public static var roomCreationUserNotFoundPromptTitle: String { + return VectorL10n.tr("Vector", "room_creation_user_not_found_prompt_title") + } /// A room is already being created. Please wait. public static var roomCreationWaitForCreation: String { return VectorL10n.tr("Vector", "room_creation_wait_for_creation") @@ -6375,6 +6387,10 @@ public class VectorL10n: NSObject { public static var roomParticipantsInviteAnotherUser: String { return VectorL10n.tr("Vector", "room_participants_invite_another_user") } + /// Invite anyway + public static var roomParticipantsInviteAnyway: String { + return VectorL10n.tr("Vector", "room_participants_invite_anyway") + } /// Malformed ID. Should be an email address or a Matrix ID like '@localpart:domain' public static var roomParticipantsInviteMalformedId: String { return VectorL10n.tr("Vector", "room_participants_invite_malformed_id") @@ -6395,6 +6411,10 @@ public class VectorL10n: NSObject { public static func roomParticipantsInvitePromptToMsg(_ p1: String, _ p2: String) -> String { return VectorL10n.tr("Vector", "room_participants_invite_prompt_to_msg", p1, p2) } + /// Unable to find profiles for this Matrix ID. Are you sure you want to invite %@ to %@? + public static func roomParticipantsInviteUnknownParticipantPromptToMsg(_ p1: String, _ p2: String) -> String { + return VectorL10n.tr("Vector", "room_participants_invite_unknown_participant_prompt_to_msg", p1, p2) + } /// INVITED public static var roomParticipantsInvitedSection: String { return VectorL10n.tr("Vector", "room_participants_invited_section") diff --git a/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleView.m b/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleView.m index 60a378221..01868a067 100644 --- a/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleView.m +++ b/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleView.m @@ -86,7 +86,7 @@ } else if (_mxUser) { - self.displayNameTextField.text = (_mxUser.displayname.length) ? _mxUser.displayname : nil; + self.displayNameTextField.text = (_mxUser.displayname.length) ? _mxUser.displayname : _mxUser.userId; } else { diff --git a/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerCoordinator.swift b/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerCoordinator.swift index 97f39d255..0028787e0 100644 --- a/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerCoordinator.swift +++ b/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerCoordinator.swift @@ -138,4 +138,12 @@ extension ContactsPickerCoordinator: ContactsPickerViewModelCoordinatorDelegate currentAlert = alert } + + func contactsPickerViewModelDidStartValidatingUser(_ coordinator: ContactsPickerViewModelProtocol) { + contactsPickerViewController?.startActivityIndicator() + } + + func contactsPickerViewModelDidEndValidatingUser(_ coordinator: ContactsPickerViewModelProtocol) { + contactsPickerViewController?.stopActivityIndicator() + } } diff --git a/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift b/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift index c57197992..a2e74edc7 100644 --- a/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift +++ b/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift @@ -201,12 +201,31 @@ extension ContactsPickerViewModel: ContactsTableViewControllerDelegate { return } + // Check for user + if MXTools.isMatrixUserIdentifier(contact.displayName) { + let user = MXUser(userId: contact.displayName) + coordinatorDelegate?.contactsPickerViewModelDidStartValidatingUser(self) + user?.update(fromHomeserverOfMatrixSession: self.room.mxSession, success: { [weak self] in + guard let self = self else { return } + self.coordinatorDelegate?.contactsPickerViewModelDidEndValidatingUser(self) + self.displayInvitePrompt(contact: contact) + }, failure: { [weak self] error in + guard let self = self else { return } + self.coordinatorDelegate?.contactsPickerViewModelDidEndValidatingUser(self) + self.displayInvitePrompt(contact: contact, contactFound: false) + }) + } else { + displayInvitePrompt(contact: contact) + } + } + + private func displayInvitePrompt(contact: MXKContact, contactFound: Bool = true) { let roomName = room.displayName ?? VectorL10n.spaceTag - let message = VectorL10n.roomParticipantsInvitePromptToMsg(contact.displayName, roomName) - + let message = contactFound ? VectorL10n.roomParticipantsInvitePromptToMsg(contact.displayName, roomName) : VectorL10n.roomParticipantsInviteUnknownParticipantPromptToMsg(contact.displayName, roomName) + let inviteActionTitle = contactFound ? VectorL10n.invite : VectorL10n.roomParticipantsInviteAnyway coordinatorDelegate?.contactsPickerViewModel(self, display: message, title: VectorL10n.roomParticipantsInvitePromptTitle, actions: [ - UIAlertAction(title: VectorL10n.cancel, style: .cancel, handler: nil), - UIAlertAction(title: VectorL10n.invite, style: .default, handler: { [weak self] action in + UIAlertAction(title: VectorL10n.cancel, style: .cancel), + UIAlertAction(title: VectorL10n.invite, style: .default, handler: { [weak self] _ in self?.invite(contact: contact) }) ]) diff --git a/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModelProtocol.swift b/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModelProtocol.swift index 3ffb6698a..688eaa34e 100644 --- a/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModelProtocol.swift +++ b/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModelProtocol.swift @@ -23,6 +23,8 @@ protocol ContactsPickerViewModelCoordinatorDelegate: AnyObject { func contactsPickerViewModelDidEndInvite(_ viewModel: ContactsPickerViewModelProtocol) func contactsPickerViewModel(_ viewModel: ContactsPickerViewModelProtocol, inviteFailedWithError error: Error?) func contactsPickerViewModel(_ viewModel: ContactsPickerViewModelProtocol, display message: String, title: String, actions: [UIAlertAction]) + func contactsPickerViewModelDidStartValidatingUser(_ coordinator: ContactsPickerViewModelProtocol) + func contactsPickerViewModelDidEndValidatingUser(_ coordinator: ContactsPickerViewModelProtocol) } protocol ContactsPickerViewModelProtocol { diff --git a/Riot/Modules/Room/RoomCoordinator.swift b/Riot/Modules/Room/RoomCoordinator.swift index f249b863c..aed8e27b1 100644 --- a/Riot/Modules/Room/RoomCoordinator.swift +++ b/Riot/Modules/Room/RoomCoordinator.swift @@ -276,7 +276,6 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol { self.stopLoading() self.parameters.session.store.store(user) - // Update RoomViewController with found target user self.roomViewController.displayNewDirectChat(withTargetUser: user, session: self.parameters.session) } failure: { [weak self] error in @@ -286,10 +285,18 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol { MXLog.error("[RoomCoordinator] User does not exist") // Alert user - self.displayError(message: VectorL10n.roomCreationDmError) { [weak self] in - guard let self = self else { return } - self.delegate?.roomCoordinatorDidCancelNewDirectChat(self) - } + self.displayUserNotFoundPrompt( + invite: { [weak self] in + guard let self = self else { return } + self.parameters.session.store.store(MXUser(userId: userId)) + // Update RoomViewController with target user anyway + self.roomViewController.displayNewDirectChat(withTargetUser: user, session: self.parameters.session) + }, + cancel: { [weak self] in + guard let self = self else { return } + self.delegate?.roomCoordinatorDidCancelNewDirectChat(self) + } + ) } } } else { @@ -525,6 +532,22 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol { alert.addAction(action) toPresentable().present(alert, animated: true) } + + private func displayUserNotFoundPrompt(invite: (() -> Void)? = nil, cancel: (() -> Void)? = nil) { + let title = VectorL10n.roomCreationUserNotFoundPromptTitle + let message = VectorL10n.roomCreationUserNotFoundPromptMessage + + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + let cancelAction = UIAlertAction(title: VectorL10n.cancel, style: .cancel) { _ in + cancel?() + } + let inviteAction = UIAlertAction(title: VectorL10n.roomCreationUserNotFoundPromptInviteAction, style: .default) { _ in + invite?() + } + alert.addAction(cancelAction) + alert.addAction(inviteAction) + toPresentable().present(alert, animated: true) + } } // MARK: - RoomIdentifiable diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 17253279b..01f9707d9 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -2056,7 +2056,7 @@ static CGSize kThreadListBarButtonItemImageSize; { [userPictureView vc_setRoomAvatarImageWith:self.directChatTargetUser.avatarUrl roomId:self.directChatTargetUser.userId - displayName:self.directChatTargetUser.displayname + displayName:self.directChatTargetUser.displayname ?: self.directChatTargetUser.userId mediaManager:self.mainSession.mediaManager]; } } diff --git a/changelog.d/7558.change b/changelog.d/7558.change new file mode 100644 index 000000000..b6eb15ae4 --- /dev/null +++ b/changelog.d/7558.change @@ -0,0 +1 @@ +Prompt the user when the invited MatrixId is not recognized From 054b8327ed09e69dddeb78e290b23682baa461f9 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Tue, 6 Jun 2023 09:55:33 +0200 Subject: [PATCH 2/2] Fix: renamed parameter for code clarity --- .../ContactsPicker/ContactsPickerViewModel.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift b/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift index a2e74edc7..f919a9037 100644 --- a/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift +++ b/Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift @@ -212,17 +212,17 @@ extension ContactsPickerViewModel: ContactsTableViewControllerDelegate { }, failure: { [weak self] error in guard let self = self else { return } self.coordinatorDelegate?.contactsPickerViewModelDidEndValidatingUser(self) - self.displayInvitePrompt(contact: contact, contactFound: false) + self.displayInvitePrompt(contact: contact, isUnknownUser: true) }) } else { displayInvitePrompt(contact: contact) } } - private func displayInvitePrompt(contact: MXKContact, contactFound: Bool = true) { + private func displayInvitePrompt(contact: MXKContact, isUnknownUser: Bool = false) { let roomName = room.displayName ?? VectorL10n.spaceTag - let message = contactFound ? VectorL10n.roomParticipantsInvitePromptToMsg(contact.displayName, roomName) : VectorL10n.roomParticipantsInviteUnknownParticipantPromptToMsg(contact.displayName, roomName) - let inviteActionTitle = contactFound ? VectorL10n.invite : VectorL10n.roomParticipantsInviteAnyway + let message = isUnknownUser ? VectorL10n.roomParticipantsInviteUnknownParticipantPromptToMsg(contact.displayName, roomName) : VectorL10n.roomParticipantsInvitePromptToMsg(contact.displayName, roomName) + let inviteActionTitle = isUnknownUser ? VectorL10n.roomParticipantsInviteAnyway : VectorL10n.invite coordinatorDelegate?.contactsPickerViewModel(self, display: message, title: VectorL10n.roomParticipantsInvitePromptTitle, actions: [ UIAlertAction(title: VectorL10n.cancel, style: .cancel), UIAlertAction(title: VectorL10n.invite, style: .default, handler: { [weak self] _ in