diff --git a/src/session/view/content/room_history/mod.ui b/src/session/view/content/room_history/mod.ui index b10c3bfe..f7aadd50 100644 --- a/src/session/view/content/room_history/mod.ui +++ b/src/session/view/content/room_history/mod.ui @@ -93,6 +93,11 @@ sender-avatar.unban action-disabled + + _Remove Messages + sender-avatar.remove-messages + action-disabled + I_gnore sender-avatar.ignore diff --git a/src/session/view/content/room_history/sender_avatar/mod.rs b/src/session/view/content/room_history/sender_avatar/mod.rs index 74716f34..062edfbf 100644 --- a/src/session/view/content/room_history/sender_avatar/mod.rs +++ b/src/session/view/content/room_history/sender_avatar/mod.rs @@ -5,7 +5,7 @@ use ruma::events::room::power_levels::PowerLevelUserAction; use crate::{ components::{Avatar, UserProfileDialog}, - gettext_f, + gettext_f, ngettext_f, prelude::*, session::{ model::{Member, Membership, User}, @@ -131,6 +131,14 @@ mod imp { widget.unban().await; }); + klass.install_action_async( + "sender-avatar.remove-messages", + None, + |widget, _, _| async move { + widget.remove_messages().await; + }, + ); + klass.install_action_async("sender-avatar.ignore", None, |widget, _, _| async move { widget.toggle_ignored().await; }); @@ -313,6 +321,11 @@ mod imp { && permissions.can_do_to_user(sender_id, PowerLevelUserAction::Unban), ); + obj.action_set_enabled( + "sender-avatar.remove-messages", + !is_own_user && permissions.can_redact_other(), + ); + obj.action_set_enabled("sender-avatar.ignore", !is_own_user && !sender.is_ignored()); obj.action_set_enabled( @@ -579,6 +592,59 @@ impl SenderAvatar { } } + /// Remove the known events of the room member. + async fn remove_messages(&self) { + let Some(sender) = self.sender() else { + return; + }; + let Some(window) = self.root().and_downcast::() else { + return; + }; + + let redactable_events = sender.redactable_events(); + let count = redactable_events.len(); + + let (confirmed, reason) = confirm_room_member_destructive_action( + &sender, + RoomMemberDestructiveAction::RemoveMessages(count), + &window, + ) + .await; + if !confirmed { + return; + } + + let n = u32::try_from(count).unwrap_or(u32::MAX); + toast!( + self, + ngettext_f( + // Translators: Do NOT translate the content between '{' and '}', + // this is a variable name. + "Removing 1 message sent by the user…", + "Removing {n} messages sent by the user…", + n, + &[("n", &n.to_string())] + ) + ); + + let room = sender.room(); + + if let Err(events) = room.redact(&redactable_events, reason).await { + let n = u32::try_from(events.len()).unwrap_or(u32::MAX); + toast!( + self, + ngettext_f( + // Translators: Do NOT translate the content between '{' and '}', + // this is a variable name. + "Failed to remove 1 message sent by the user", + "Failed to remove {n} messages sent by the user", + n, + &[("n", &n.to_string())] + ) + ); + } + } + /// Toggle whether the user is ignored or not. async fn toggle_ignored(&self) { let Some(sender) = self.sender().and_upcast::() else {