mirror of
https://github.com/element-hq/element-android
synced 2024-11-26 11:25:40 +03:00
Merge pull request #8797 from element-hq/feature/bma/reportUser
Report user
This commit is contained in:
commit
9aaf29d4cf
11 changed files with 80 additions and 5 deletions
1
changelog.d/8796.misc
Normal file
1
changelog.d/8796.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add a report user action in the message bottom sheet and on the user profile page.
|
|
@ -1953,8 +1953,11 @@
|
||||||
<string name="content_reported_as_spam_content">"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."</string>
|
<string name="content_reported_as_spam_content">"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."</string>
|
||||||
<string name="content_reported_as_inappropriate_title">"Reported as inappropriate"</string>
|
<string name="content_reported_as_inappropriate_title">"Reported as inappropriate"</string>
|
||||||
<string name="content_reported_as_inappropriate_content">"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."</string>
|
<string name="content_reported_as_inappropriate_content">"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."</string>
|
||||||
|
<string name="user_reported_as_inappropriate_title">"Reported user"</string>
|
||||||
|
<string name="user_reported_as_inappropriate_content">"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."</string>
|
||||||
|
|
||||||
<string name="message_ignore_user">Ignore user</string>
|
<string name="message_ignore_user">Ignore user</string>
|
||||||
|
<string name="message_report_user">Report user</string>
|
||||||
|
|
||||||
<string name="room_list_quick_actions_notifications_all_noisy">"All messages (noisy)"</string>
|
<string name="room_list_quick_actions_notifications_all_noisy">"All messages (noisy)"</string>
|
||||||
<string name="room_list_quick_actions_notifications_all">"All messages"</string>
|
<string name="room_list_quick_actions_notifications_all">"All messages"</string>
|
||||||
|
|
|
@ -61,7 +61,8 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
||||||
val senderId: String?,
|
val senderId: String?,
|
||||||
val reason: String,
|
val reason: String,
|
||||||
val spam: Boolean = false,
|
val spam: Boolean = false,
|
||||||
val inappropriate: Boolean = false
|
val inappropriate: Boolean = false,
|
||||||
|
val user: Boolean = false,
|
||||||
) : RoomDetailAction()
|
) : RoomDetailAction()
|
||||||
|
|
||||||
data class IgnoreUser(val userId: String?) : RoomDetailAction()
|
data class IgnoreUser(val userId: String?) : RoomDetailAction()
|
||||||
|
|
|
@ -1345,6 +1345,16 @@ class TimelineFragment :
|
||||||
}
|
}
|
||||||
.show()
|
.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 -> {
|
else -> {
|
||||||
MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive)
|
MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive)
|
||||||
.setTitle(R.string.content_reported_title)
|
.setTitle(R.string.content_reported_title)
|
||||||
|
@ -1857,6 +1867,13 @@ class TimelineFragment :
|
||||||
is EventSharedAction.IgnoreUser -> {
|
is EventSharedAction.IgnoreUser -> {
|
||||||
action.senderId?.let { askConfirmationToIgnoreUser(it) }
|
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 -> {
|
is EventSharedAction.OnUrlClicked -> {
|
||||||
onUrlClicked(action.url, action.title)
|
onUrlClicked(action.url, action.title)
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,9 @@ sealed class EventSharedAction(
|
||||||
data class IgnoreUser(val senderId: String?) :
|
data class IgnoreUser(val senderId: String?) :
|
||||||
EventSharedAction(R.string.message_ignore_user, R.drawable.ic_alert_triangle, true)
|
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) :
|
data class QuickReact(val eventId: String, val clickedOn: String, val add: Boolean) :
|
||||||
EventSharedAction(0, 0)
|
EventSharedAction(0, 0)
|
||||||
|
|
||||||
|
|
|
@ -430,6 +430,12 @@ class MessageActionsViewModel @AssistedInject constructor(
|
||||||
|
|
||||||
add(EventSharedAction.Separator)
|
add(EventSharedAction.Separator)
|
||||||
add(EventSharedAction.IgnoreUser(timelineEvent.root.senderId))
|
add(EventSharedAction.IgnoreUser(timelineEvent.root.senderId))
|
||||||
|
add(
|
||||||
|
EventSharedAction.ReportUser(
|
||||||
|
eventId = eventId,
|
||||||
|
senderId = timelineEvent.root.senderId,
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import im.vector.app.core.platform.VectorViewModelAction
|
||||||
sealed class RoomMemberProfileAction : VectorViewModelAction {
|
sealed class RoomMemberProfileAction : VectorViewModelAction {
|
||||||
object RetryFetchingInfo : RoomMemberProfileAction()
|
object RetryFetchingInfo : RoomMemberProfileAction()
|
||||||
object IgnoreUser : RoomMemberProfileAction()
|
object IgnoreUser : RoomMemberProfileAction()
|
||||||
|
object ReportUser : RoomMemberProfileAction()
|
||||||
data class BanOrUnbanUser(val reason: String?) : RoomMemberProfileAction()
|
data class BanOrUnbanUser(val reason: String?) : RoomMemberProfileAction()
|
||||||
data class KickUser(val reason: String?) : RoomMemberProfileAction()
|
data class KickUser(val reason: String?) : RoomMemberProfileAction()
|
||||||
object InviteUser : RoomMemberProfileAction()
|
object InviteUser : RoomMemberProfileAction()
|
||||||
|
|
|
@ -39,6 +39,7 @@ class RoomMemberProfileController @Inject constructor(
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun onIgnoreClicked()
|
fun onIgnoreClicked()
|
||||||
|
fun onReportClicked()
|
||||||
fun onTapVerify()
|
fun onTapVerify()
|
||||||
fun onShowDeviceList()
|
fun onShowDeviceList()
|
||||||
fun onShowDeviceListNoCrossSigning()
|
fun onShowDeviceListNoCrossSigning()
|
||||||
|
@ -225,7 +226,7 @@ class RoomMemberProfileController @Inject constructor(
|
||||||
title = stringProvider.getString(R.string.room_participants_action_invite),
|
title = stringProvider.getString(R.string.room_participants_action_invite),
|
||||||
destructive = false,
|
destructive = false,
|
||||||
editable = false,
|
editable = false,
|
||||||
divider = ignoreActionTitle != null,
|
divider = true,
|
||||||
action = { callback?.onInviteClicked() }
|
action = { callback?.onInviteClicked() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -235,10 +236,18 @@ class RoomMemberProfileController @Inject constructor(
|
||||||
title = ignoreActionTitle,
|
title = ignoreActionTitle,
|
||||||
destructive = true,
|
destructive = true,
|
||||||
editable = false,
|
editable = false,
|
||||||
divider = false,
|
divider = true,
|
||||||
action = { callback?.onIgnoreClicked() }
|
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? {
|
private fun RoomMemberProfileViewState.buildIgnoreActionTitle(): String? {
|
||||||
val isIgnored = isIgnored() ?: return null
|
val isIgnored = isIgnored() ?: return null
|
||||||
return if (isIgnored) {
|
return if (isIgnored) {
|
||||||
stringProvider.getString(R.string.unignore)
|
stringProvider.getString(R.string.room_participants_action_unignore_title)
|
||||||
} else {
|
} else {
|
||||||
stringProvider.getString(R.string.action_ignore)
|
stringProvider.getString(R.string.room_participants_action_ignore_title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,11 +140,20 @@ class RoomMemberProfileFragment :
|
||||||
is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit
|
is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit
|
||||||
is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit
|
is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit
|
||||||
RoomMemberProfileViewEvents.GoBack -> handleGoBack()
|
RoomMemberProfileViewEvents.GoBack -> handleGoBack()
|
||||||
|
RoomMemberProfileViewEvents.OnReportActionSuccess -> handleReportSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setupLongClicks()
|
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() {
|
private fun setupLongClicks() {
|
||||||
headerViews.memberProfileNameView.copyOnLongClick()
|
headerViews.memberProfileNameView.copyOnLongClick()
|
||||||
headerViews.memberProfileIdView.copyOnLongClick()
|
headerViews.memberProfileIdView.copyOnLongClick()
|
||||||
|
@ -301,6 +310,10 @@ class RoomMemberProfileFragment :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onReportClicked() {
|
||||||
|
viewModel.handle(RoomMemberProfileAction.ReportUser)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTapVerify() {
|
override fun onTapVerify() {
|
||||||
viewModel.handle(RoomMemberProfileAction.VerifyUser)
|
viewModel.handle(RoomMemberProfileAction.VerifyUser)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ sealed class RoomMemberProfileViewEvents : VectorViewEvents {
|
||||||
data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents()
|
data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents()
|
||||||
|
|
||||||
object OnIgnoreActionSuccess : RoomMemberProfileViewEvents()
|
object OnIgnoreActionSuccess : RoomMemberProfileViewEvents()
|
||||||
|
object OnReportActionSuccess : RoomMemberProfileViewEvents()
|
||||||
object OnSetPowerLevelSuccess : RoomMemberProfileViewEvents()
|
object OnSetPowerLevelSuccess : RoomMemberProfileViewEvents()
|
||||||
object OnInviteActionSuccess : RoomMemberProfileViewEvents()
|
object OnInviteActionSuccess : RoomMemberProfileViewEvents()
|
||||||
object OnKickActionSuccess : RoomMemberProfileViewEvents()
|
object OnKickActionSuccess : RoomMemberProfileViewEvents()
|
||||||
|
|
|
@ -161,6 +161,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
|
||||||
when (action) {
|
when (action) {
|
||||||
is RoomMemberProfileAction.RetryFetchingInfo -> handleRetryFetchProfileInfo()
|
is RoomMemberProfileAction.RetryFetchingInfo -> handleRetryFetchProfileInfo()
|
||||||
is RoomMemberProfileAction.IgnoreUser -> handleIgnoreAction()
|
is RoomMemberProfileAction.IgnoreUser -> handleIgnoreAction()
|
||||||
|
is RoomMemberProfileAction.ReportUser -> handleReportAction()
|
||||||
is RoomMemberProfileAction.VerifyUser -> prepareVerification()
|
is RoomMemberProfileAction.VerifyUser -> prepareVerification()
|
||||||
is RoomMemberProfileAction.ShareRoomMemberProfile -> handleShareRoomMemberProfile()
|
is RoomMemberProfileAction.ShareRoomMemberProfile -> handleShareRoomMemberProfile()
|
||||||
is RoomMemberProfileAction.SetPowerLevel -> handleSetPowerLevel(action)
|
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) {
|
private fun handleOpenOrCreateDm(action: RoomMemberProfileAction.OpenOrCreateDm) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
|
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
|
||||||
|
|
Loading…
Reference in a new issue