diff --git a/src/components/dialogs/message_dialogs.rs b/src/components/dialogs/message_dialogs.rs index a768c6a4..53285ba9 100644 --- a/src/components/dialogs/message_dialogs.rs +++ b/src/components/dialogs/message_dialogs.rs @@ -356,22 +356,35 @@ pub(crate) struct ConfirmRoomMemberDestructiveActionResponse { pub remove_events: bool, } -/// Show a dialog to confirm muting a room member. +/// Show a dialog to confirm muting one or several room members. pub(crate) async fn confirm_mute_room_member_dialog( - member: &Member, + members: &[Member], parent: &impl IsA, ) -> bool { - let heading = gettext_f( + if members.is_empty() { + return false; + } + + let first_member = members + .first() + .expect("there should be at least one member"); + let count = members.len() as u32; + + let heading = ngettext_f( // Translators: Do NOT translate the content between '{' and '}', - // this is a variable name. + // this is a variable name. The count cannot be zero. "Mute {user}?", - &[("user", &member.display_name())], + "Mute Members?", + count, + &[("user", &first_member.display_name())], ); - let body = gettext_f( + let body = ngettext_f( // Translators: Do NOT translate the content between '{' and '}', - // this is a variable name. - "Are you sure you want to mute {user_id}? They will not be able to send new messages.", - &[("user_id", member.user_id().as_str())], + // this is a variable name. The count cannot be zero. + "Are you sure you want to mute {user_id}? They will not be able to send new messages to this room.", + "Are you sure you want to mute these members? They will not be able to send new messages to this room.", + count, + &[("user_id", first_member.user_id().as_str())], ); // Ask for confirmation. @@ -390,23 +403,36 @@ pub(crate) async fn confirm_mute_room_member_dialog( confirm_dialog.choose_future(parent).await == "mute" } -/// Show a dialog to confirm setting the power level of a room member with the -/// same value as our own. +/// Show a dialog to confirm setting the power level of one or several room +/// members with the same value as our own. pub(crate) async fn confirm_set_room_member_power_level_same_as_own_dialog( - member: &Member, + members: &[Member], parent: &impl IsA, ) -> bool { - let heading = gettext_f( + if members.is_empty() { + return false; + } + + let first_member = members + .first() + .expect("there should be at least one member"); + let count = members.len() as u32; + + let heading = ngettext_f( // Translators: Do NOT translate the content between '{' and '}', - // this is a variable name. + // this is a variable name. The count cannot be zero. "Promote {user}?", - &[("user", &member.display_name())], + "Promote Members?", + count, + &[("user", &first_member.display_name())], ); - let body = gettext_f( + let body = ngettext_f( // Translators: Do NOT translate the content between '{' and '}', - // this is a variable name. + // this is a variable name. The count cannot be zero. "If you promote {user_id} to the same level as yours, you will not be able to demote them in the future.", - &[("user_id", member.user_id().as_str())], + "If you promote these members to the same level as yours, you will not be able to demote them in the future.", + count, + &[("user_id", first_member.user_id().as_str())], ); // Ask for confirmation. diff --git a/src/components/user_page.rs b/src/components/user_page.rs index 5bcaa85f..4116ada0 100644 --- a/src/components/user_page.rs +++ b/src/components/user_page.rs @@ -1,3 +1,5 @@ +use std::slice; + use adw::{prelude::*, subclass::prelude::*}; use gettextrs::{gettext, ngettext, pgettext}; use gtk::{ @@ -461,7 +463,9 @@ mod imp { let mute_power_level = permissions.mute_power_level(); let is_muted = power_level <= mute_power_level && old_power_level > mute_power_level; - if is_muted && !confirm_mute_room_member_dialog(&member, &*obj).await { + if is_muted + && !confirm_mute_room_member_dialog(slice::from_ref(&member), &*obj).await + { self.update_room(); return; } @@ -469,7 +473,11 @@ mod imp { // Warn if power level is set at same level as own power level. let is_own_power_level = power_level == permissions.own_power_level(); if is_own_power_level - && !confirm_set_room_member_power_level_same_as_own_dialog(&member, &*obj).await + && !confirm_set_room_member_power_level_same_as_own_dialog( + slice::from_ref(&member), + &*obj, + ) + .await { self.update_room(); return; diff --git a/src/session/view/content/room_details/permissions/add_members_subpage.rs b/src/session/view/content/room_details/permissions/add_members_subpage.rs index 5710b236..84deb269 100644 --- a/src/session/view/content/room_details/permissions/add_members_subpage.rs +++ b/src/session/view/content/room_details/permissions/add_members_subpage.rs @@ -8,7 +8,10 @@ use tracing::error; use super::{MemberPowerLevel, PermissionsSelectMemberRow, PrivilegedMembers}; use crate::{ - components::{PillSearchEntry, PowerLevelSelectionComboBox}, + components::{ + PillSearchEntry, PowerLevelSelectionComboBox, confirm_mute_room_member_dialog, + confirm_set_room_member_power_level_same_as_own_dialog, + }, prelude::*, session::model::{Member, Permissions}, utils::expression, @@ -218,7 +221,7 @@ mod imp { /// Add the selected members to the list of members with custom power /// levels. #[template_callback] - fn add_members(&self) { + async fn add_members(&self) { let Some(permissions) = self.permissions.upgrade() else { return; }; @@ -226,8 +229,30 @@ mod imp { return; }; + let obj = self.obj(); let power_level = self.power_level_combo.selected_power_level(); + let members = self + .selected_members + .borrow() + .values() + .cloned() + .collect::>(); + + // Warn if users are muted. + let is_muted = power_level <= permissions.mute_power_level(); + if is_muted && !confirm_mute_room_member_dialog(&members, &*obj).await { + return; + } + + // Warn if power level is set at same level as own power level. + let is_own_power_level = power_level == permissions.own_power_level(); + if is_own_power_level + && !confirm_set_room_member_power_level_same_as_own_dialog(&members, &*obj).await + { + return; + } + let members = self .selected_members .take() @@ -240,7 +265,6 @@ mod imp { }); privileged_members.add_members(members); - let obj = self.obj(); let _ = obj.activate_action("navigation.pop", None); self.search_entry.clear(); self.add_button.set_sensitive(false); 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 eb9d63de..0455444a 100644 --- a/src/session/view/content/room_history/sender_avatar/mod.rs +++ b/src/session/view/content/room_history/sender_avatar/mod.rs @@ -1,3 +1,5 @@ +use std::slice; + use adw::{prelude::*, subclass::prelude::*}; use gettextrs::{gettext, ngettext}; use gtk::{CompositeTemplate, gdk, glib, glib::clone}; @@ -629,7 +631,7 @@ mod imp { // Warn if user is muted but was not before. let mute_power_level = permissions.mute_power_level(); let mute = old_power_level > mute_power_level; - if mute && !confirm_mute_room_member_dialog(&sender, &*obj).await { + if mute && !confirm_mute_room_member_dialog(slice::from_ref(&sender), &*obj).await { return; }