From 99ec61e120bec0d3fefc5155a95a720325aaddcd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 15:11:27 +0200 Subject: [PATCH 1/3] Add action to report a user form the message detail bottom sheet. #8796 --- .../ui-strings/src/main/res/values/strings.xml | 3 +++ .../home/room/detail/RoomDetailAction.kt | 3 ++- .../home/room/detail/TimelineFragment.kt | 17 +++++++++++++++++ .../detail/timeline/action/EventSharedAction.kt | 3 +++ .../timeline/action/MessageActionsViewModel.kt | 6 ++++++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 577101b0d3..2a98069c2e 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -1953,8 +1953,11 @@ "This content was reported as spam.\n\nIf you don't want to see any more content from this user, you can ignore them to hide their messages." "Reported as inappropriate" "This content was reported as inappropriate.\n\nIf you don't want to see any more content from this user, you can ignore them to hide their messages." + "Reported user" + "The user has been reported.\n\nIf you don't want to see any more content from this user, you can ignore them to hide their messages." Ignore user + Report user "All messages (noisy)" "All messages" diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt index 478ed4a58d..30bcf7f8eb 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt @@ -61,7 +61,8 @@ sealed class RoomDetailAction : VectorViewModelAction { val senderId: String?, val reason: String, val spam: Boolean = false, - val inappropriate: Boolean = false + val inappropriate: Boolean = false, + val user: Boolean = false, ) : RoomDetailAction() data class IgnoreUser(val userId: String?) : RoomDetailAction() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index feaad386cb..f80855663f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -1345,6 +1345,16 @@ class TimelineFragment : } .show() } + data.user -> { + MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive) + .setTitle(R.string.user_reported_as_inappropriate_title) + .setMessage(R.string.user_reported_as_inappropriate_content) + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.block_user) { _, _ -> + timelineViewModel.handle(RoomDetailAction.IgnoreUser(data.senderId)) + } + .show() + } else -> { MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive) .setTitle(R.string.content_reported_title) @@ -1857,6 +1867,13 @@ class TimelineFragment : is EventSharedAction.IgnoreUser -> { action.senderId?.let { askConfirmationToIgnoreUser(it) } } + is EventSharedAction.ReportUser -> { + timelineViewModel.handle( + RoomDetailAction.ReportContent( + action.eventId, action.senderId, "Reporting user ${action.senderId}", user = true + ) + ) + } is EventSharedAction.OnUrlClicked -> { onUrlClicked(action.url, action.title) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/EventSharedAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/EventSharedAction.kt index 7bf9f536f2..18ff638390 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/EventSharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/EventSharedAction.kt @@ -98,6 +98,9 @@ sealed class EventSharedAction( data class IgnoreUser(val senderId: String?) : EventSharedAction(R.string.message_ignore_user, R.drawable.ic_alert_triangle, true) + data class ReportUser(val eventId: String, val senderId: String?) : + EventSharedAction(R.string.message_report_user, R.drawable.ic_flag, true) + data class QuickReact(val eventId: String, val clickedOn: String, val add: Boolean) : EventSharedAction(0, 0) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 62aed5c3c6..8809c4f0bf 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -430,6 +430,12 @@ class MessageActionsViewModel @AssistedInject constructor( add(EventSharedAction.Separator) add(EventSharedAction.IgnoreUser(timelineEvent.root.senderId)) + add( + EventSharedAction.ReportUser( + eventId = eventId, + senderId = timelineEvent.root.senderId, + ) + ) } } From b14cb81ece226161d12790b95a61ff68373a3234 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 15:44:25 +0200 Subject: [PATCH 2/3] Add action to report a user form the user profile view. EventId is not relevant, but requested by the API. --- .../RoomMemberProfileAction.kt | 1 + .../RoomMemberProfileController.kt | 17 ++++++++++++---- .../RoomMemberProfileFragment.kt | 13 ++++++++++++ .../RoomMemberProfileViewEvents.kt | 1 + .../RoomMemberProfileViewModel.kt | 20 +++++++++++++++++++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileAction.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileAction.kt index e2298d9b53..874f3c73b8 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileAction.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileAction.kt @@ -22,6 +22,7 @@ import im.vector.app.core.platform.VectorViewModelAction sealed class RoomMemberProfileAction : VectorViewModelAction { object RetryFetchingInfo : RoomMemberProfileAction() object IgnoreUser : RoomMemberProfileAction() + object ReportUser : RoomMemberProfileAction() data class BanOrUnbanUser(val reason: String?) : RoomMemberProfileAction() data class KickUser(val reason: String?) : RoomMemberProfileAction() object InviteUser : RoomMemberProfileAction() diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileController.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileController.kt index 9585e6aaa1..e74bad1acb 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileController.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileController.kt @@ -39,6 +39,7 @@ class RoomMemberProfileController @Inject constructor( interface Callback { fun onIgnoreClicked() + fun onReportClicked() fun onTapVerify() fun onShowDeviceList() fun onShowDeviceListNoCrossSigning() @@ -225,7 +226,7 @@ class RoomMemberProfileController @Inject constructor( title = stringProvider.getString(R.string.room_participants_action_invite), destructive = false, editable = false, - divider = ignoreActionTitle != null, + divider = true, action = { callback?.onInviteClicked() } ) } @@ -235,10 +236,18 @@ class RoomMemberProfileController @Inject constructor( title = ignoreActionTitle, destructive = true, editable = false, - divider = false, + divider = true, action = { callback?.onIgnoreClicked() } ) } + buildProfileAction( + id = "report", + title = stringProvider.getString(R.string.message_report_user), + destructive = true, + editable = false, + divider = false, + action = { callback?.onReportClicked() } + ) } } @@ -314,9 +323,9 @@ class RoomMemberProfileController @Inject constructor( private fun RoomMemberProfileViewState.buildIgnoreActionTitle(): String? { val isIgnored = isIgnored() ?: return null return if (isIgnored) { - stringProvider.getString(R.string.unignore) + stringProvider.getString(R.string.room_participants_action_unignore_title) } else { - stringProvider.getString(R.string.action_ignore) + stringProvider.getString(R.string.room_participants_action_ignore_title) } } } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt index 020512af36..7ac5bfea0c 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -140,11 +140,20 @@ class RoomMemberProfileFragment : is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit RoomMemberProfileViewEvents.GoBack -> handleGoBack() + RoomMemberProfileViewEvents.OnReportActionSuccess -> handleReportSuccess() } } setupLongClicks() } + private fun handleReportSuccess() { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.user_reported_as_inappropriate_title) + .setMessage(R.string.user_reported_as_inappropriate_content) + .setPositiveButton(R.string.ok, null) + .show() + } + private fun setupLongClicks() { headerViews.memberProfileNameView.copyOnLongClick() headerViews.memberProfileIdView.copyOnLongClick() @@ -301,6 +310,10 @@ class RoomMemberProfileFragment : } } + override fun onReportClicked() { + viewModel.handle(RoomMemberProfileAction.ReportUser) + } + override fun onTapVerify() { viewModel.handle(RoomMemberProfileAction.VerifyUser) } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewEvents.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewEvents.kt index d04de8b936..0bf8ef1b6e 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewEvents.kt @@ -26,6 +26,7 @@ sealed class RoomMemberProfileViewEvents : VectorViewEvents { data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents() object OnIgnoreActionSuccess : RoomMemberProfileViewEvents() + object OnReportActionSuccess : RoomMemberProfileViewEvents() object OnSetPowerLevelSuccess : RoomMemberProfileViewEvents() object OnInviteActionSuccess : RoomMemberProfileViewEvents() object OnKickActionSuccess : RoomMemberProfileViewEvents() diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt index d38b2a0a69..f688793f4b 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt @@ -161,6 +161,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor( when (action) { is RoomMemberProfileAction.RetryFetchingInfo -> handleRetryFetchProfileInfo() is RoomMemberProfileAction.IgnoreUser -> handleIgnoreAction() + is RoomMemberProfileAction.ReportUser -> handleReportAction() is RoomMemberProfileAction.VerifyUser -> prepareVerification() is RoomMemberProfileAction.ShareRoomMemberProfile -> handleShareRoomMemberProfile() is RoomMemberProfileAction.SetPowerLevel -> handleSetPowerLevel(action) @@ -172,6 +173,25 @@ class RoomMemberProfileViewModel @AssistedInject constructor( } } + private fun handleReportAction() { + viewModelScope.launch { + val event = try { + // The API need an Event, use the latest Event. + val latestEventId = room?.roomSummary()?.latestPreviewableEvent?.eventId ?: return@launch + room.reportingService() + .reportContent( + eventId = latestEventId, + score = -100, + reason = "Reporting user ${initialState.userId} (eventId is not relevant)" + ) + RoomMemberProfileViewEvents.OnReportActionSuccess + } catch (failure: Throwable) { + RoomMemberProfileViewEvents.Failure(failure) + } + _viewEvents.post(event) + } + } + private fun handleOpenOrCreateDm(action: RoomMemberProfileAction.OpenOrCreateDm) { viewModelScope.launch { _viewEvents.post(RoomMemberProfileViewEvents.Loading()) From 5ce080100671941bd0422b878918fb2986f30aad Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 15:56:28 +0200 Subject: [PATCH 3/3] towncrier. --- changelog.d/8796.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/8796.misc diff --git a/changelog.d/8796.misc b/changelog.d/8796.misc new file mode 100644 index 0000000000..ea630f0aa3 --- /dev/null +++ b/changelog.d/8796.misc @@ -0,0 +1 @@ + Add a report user action in the message bottom sheet and on the user profile page.