diff --git a/changelog.d/8998.misc b/changelog.d/8998.misc new file mode 100644 index 0000000000..f6744ff12f --- /dev/null +++ b/changelog.d/8998.misc @@ -0,0 +1 @@ +Add action to report room. diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 54d783fc85..803510ed76 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -2369,6 +2369,8 @@ Poll history Uploads + Report Room + The room has been successfully reported. Leave Room Leave "Leaving the room…" diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt index 6afe5f8aa7..a11d8afbfc 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt @@ -18,4 +18,5 @@ sealed class RoomProfileAction : VectorViewModelAction { object CreateShortcut : RoomProfileAction() object RestoreEncryptionState : RoomProfileAction() data class SetEncryptToVerifiedDeviceOnly(val enabled: Boolean) : RoomProfileAction() + data class ReportRoom(val reason: String) : RoomProfileAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt index 0ce243e810..7dd11c281c 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt @@ -52,6 +52,7 @@ class RoomProfileController @Inject constructor( fun onUploadsClicked() fun createShortcut() fun onSettingsClicked() + fun onReportRoomClicked() fun onLeaveRoomClicked() fun onRoomAliasesClicked() fun onRoomPermissionsClicked() @@ -279,6 +280,13 @@ class RoomProfileController @Inject constructor( action = { callback?.createShortcut() } ) } + buildProfileAction( + id = "Report", + title = stringProvider.getString(CommonStrings.room_profile_section_more_report), + icon = R.drawable.ic_report_spam, + editable = false, + action = { callback?.onReportRoomClicked() } + ) buildProfileAction( id = "leave", title = stringProvider.getString( diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 13f02d9f05..1a56de9fab 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -33,6 +33,7 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.startSharePlainTextIntent +import im.vector.app.databinding.DialogReportContentBinding import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding import im.vector.app.features.analytics.plan.Interaction @@ -123,6 +124,7 @@ class RoomProfileFragment : is RoomProfileViewEvents.ShareRoomProfile -> onShareRoomProfile(it.permalink) is RoomProfileViewEvents.OnShortcutReady -> addShortcut(it) RoomProfileViewEvents.DismissLoading -> dismissLoadingDialog() + is RoomProfileViewEvents.Success -> dismissSuccessDialog(it.message) } } roomListQuickActionsSharedActionViewModel @@ -133,6 +135,17 @@ class RoomProfileFragment : setupLongClicks() } + private fun dismissSuccessDialog(message: CharSequence) { + MaterialAlertDialogBuilder( + requireActivity(), + im.vector.lib.ui.styles.R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive + ) + .setTitle(CommonStrings.room_profile_section_more_report) + .setMessage(message) + .setPositiveButton(CommonStrings.ok, null) + .show() + } + private fun setupWaitingView() { views.waitingView.waitingStatusText.setText(CommonStrings.please_wait) views.waitingView.waitingStatusText.isVisible = true @@ -286,6 +299,26 @@ class RoomProfileFragment : ShortcutManagerCompat.requestPinShortcut(requireContext(), onShortcutReady.shortcutInfo, null) } + override fun onReportRoomClicked() { + promptReasonToReportRoom() + } + + private fun promptReasonToReportRoom() { + val inflater = requireActivity().layoutInflater + val layout = inflater.inflate(R.layout.dialog_report_content, null) + val views = DialogReportContentBinding.bind(layout) + + MaterialAlertDialogBuilder(requireActivity()) + .setTitle(CommonStrings.room_profile_section_more_report) + .setView(layout) + .setPositiveButton(CommonStrings.report_content_custom_submit) { _, _ -> + val reason = views.dialogReportContentInput.text.toString() + roomProfileViewModel.handle(RoomProfileAction.ReportRoom(reason)) + } + .setNegativeButton(CommonStrings.action_cancel, null) + .show() + } + override fun onLeaveRoomClicked() { val isPublicRoom = roomProfileViewModel.isPublicRoom() val message = buildString { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewEvents.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewEvents.kt index 12a0b327d2..1b12085663 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewEvents.kt @@ -17,6 +17,7 @@ sealed class RoomProfileViewEvents : VectorViewEvents { data class Loading(val message: CharSequence? = null) : RoomProfileViewEvents() object DismissLoading : RoomProfileViewEvents() data class Failure(val throwable: Throwable) : RoomProfileViewEvents() + data class Success(val message: CharSequence) : RoomProfileViewEvents() data class ShareRoomProfile(val permalink: String) : RoomProfileViewEvents() data class OnShortcutReady(val shortcutInfo: ShortcutInfoCompat) : RoomProfileViewEvents() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt index 7e18b327f1..f54f7314ad 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt @@ -176,6 +176,36 @@ class RoomProfileViewModel @AssistedInject constructor( RoomProfileAction.CreateShortcut -> handleCreateShortcut() RoomProfileAction.RestoreEncryptionState -> restoreEncryptionState() is RoomProfileAction.SetEncryptToVerifiedDeviceOnly -> setEncryptToVerifiedDeviceOnly(action.enabled) + is RoomProfileAction.ReportRoom -> handleReportRoom(action.reason) + } + } + + private fun handleReportRoom(reason: String) { + _viewEvents.post(RoomProfileViewEvents.Loading()) + session.coroutineScope.launch { + try { + // When reporting a user, use the user state event if available (it should always be available) + val createStateEventId = room.stateService() + .getStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty) + ?.eventId + ?: throw IllegalStateException("Failure: m.room.create event not found.") + room.reportingService() + .reportContent( + eventId = createStateEventId, + score = -100, + reason = reason, + ) + _viewEvents.post( + RoomProfileViewEvents.Success( + stringProvider.getString(CommonStrings.room_profile_section_more_report_success_content) + ) + ) + } catch (failure: Throwable) { + Timber.e(failure, "Failed to report room ${room.roomId}") + _viewEvents.post(RoomProfileViewEvents.Failure(failure)) + } finally { + _viewEvents.post(RoomProfileViewEvents.DismissLoading) + } } }