room-history: Disable message toolbar when user is not allowed to send messages

This commit is contained in:
Kévin Commaille 2023-11-04 16:47:19 +01:00
parent 52c5f51280
commit 2d3a0560ea
No known key found for this signature in database
GPG Key ID: 29A48C1F03620416
1 changed files with 126 additions and 6 deletions

View File

@ -20,11 +20,14 @@ use matrix_sdk::{
},
};
use ruma::events::{
room::message::{
AddMentions, ForwardThread, LocationMessageEventContent, MessageFormat,
OriginalSyncRoomMessageEvent, RoomMessageEventContent,
room::{
message::{
AddMentions, ForwardThread, LocationMessageEventContent, MessageFormat,
OriginalSyncRoomMessageEvent, RoomMessageEventContent,
},
power_levels::PowerLevelAction,
},
AnyMessageLikeEventContent,
AnyMessageLikeEventContent, MessageLikeEventType,
};
use sourceview::prelude::*;
use tracing::{debug, error, warn};
@ -38,7 +41,7 @@ use crate::{
components::{CustomEntry, LabelWithWidgets, Pill},
gettext_f,
prelude::*,
session::model::{Event, EventKey, Room},
session::model::{Event, EventKey, Member, Membership, Room},
spawn, spawn_tokio, toast,
utils::{
matrix::extract_mentions,
@ -71,6 +74,10 @@ mod imp {
)]
pub struct MessageToolbar {
pub room: glib::WeakRef<Room>,
/// Whether our own user can send messages in the current room.
pub can_send_messages: Cell<bool>,
pub own_member: glib::WeakRef<Member>,
pub power_levels_handler: RefCell<Option<glib::SignalHandlerId>>,
pub md_enabled: Cell<bool>,
pub completion: CompletionPopover,
#[template_child]
@ -157,6 +164,9 @@ mod imp {
glib::ParamSpecObject::builder::<Room>("room")
.explicit_notify()
.build(),
glib::ParamSpecBoolean::builder("can-send-messages")
.read_only()
.build(),
glib::ParamSpecBoolean::builder("markdown-enabled")
.explicit_notify()
.build(),
@ -187,6 +197,7 @@ mod imp {
match pspec.name() {
"room" => obj.room().to_value(),
"can-send-messages" => obj.can_send_messages().to_value(),
"markdown-enabled" => obj.markdown_enabled().to_value(),
"related-event-type" => obj.related_event_type().to_value(),
"related-event" => obj.related_event().to_value(),
@ -201,6 +212,10 @@ mod imp {
// Clipboard.
self.message_entry
.connect_paste_clipboard(clone!(@weak obj => move |entry| {
if !obj.can_send_messages() {
return;
}
let formats = obj.clipboard().formats();
// We only handle files and supported images.
@ -273,6 +288,8 @@ mod imp {
// Tab auto-completion.
self.completion.set_parent(&*self.message_entry);
obj.set_sensitive(obj.can_send_messages());
}
fn dispose(&self) {
@ -303,21 +320,35 @@ impl MessageToolbar {
/// Set the room currently displayed.
pub fn set_room(&self, room: Option<&Room>) {
if self.room().as_ref() == room {
let old_room = self.room();
if old_room.as_ref() == room {
return;
}
let imp = self.imp();
if let Some(room) = old_room {
if let Some(handler) = imp.power_levels_handler.take() {
room.power_levels().disconnect(handler);
}
}
self.clear_related_event();
imp.room.set(room);
self.update_completion(room);
self.set_up_can_send_messages(room);
imp.message_entry.grab_focus();
self.notify("room");
}
/// The `Member` for our own user in the current room.
pub fn own_member(&self) -> Option<Member> {
self.imp().own_member.upgrade()
}
/// Whether outgoing messages should be interpreted as markdown.
pub fn markdown_enabled(&self) -> bool {
self.imp().md_enabled.get()
@ -485,6 +516,9 @@ impl MessageToolbar {
}
fn send_text_message(&self) {
if !self.can_send_messages() {
return;
}
let Some(room) = self.room() else {
return;
};
@ -599,10 +633,16 @@ impl MessageToolbar {
}
fn open_emoji(&self) {
if !self.can_send_messages() {
return;
}
self.imp().message_entry.emit_insert_emoji();
}
async fn send_location(&self) -> ashpd::Result<()> {
if !self.can_send_messages() {
return Ok(());
}
let Some(room) = self.room() else {
return Ok(());
};
@ -669,6 +709,10 @@ impl MessageToolbar {
}
async fn send_image(&self, image: gdk::Texture) {
if !self.can_send_messages() {
return;
}
let window = self.root().and_downcast::<gtk::Window>().unwrap();
let filename = filename_for_mime(Some(mime::IMAGE_PNG.as_ref()), None);
let dialog = AttachmentDialog::for_image(&window, &filename, &image);
@ -693,6 +737,10 @@ impl MessageToolbar {
}
pub async fn select_file(&self) {
if !self.can_send_messages() {
return;
}
let dialog = gtk::FileDialog::builder()
.title(gettext("Select File"))
.modal(true)
@ -814,6 +862,10 @@ impl MessageToolbar {
}
pub fn handle_paste_action(&self) {
if !self.can_send_messages() {
return;
}
spawn!(glib::clone!(@weak self as obj => async move {
obj.read_clipboard().await;
}));
@ -850,6 +902,74 @@ impl MessageToolbar {
room.send_typing_notification(typing);
}
}
/// Whether our own user can send messages in the current room.
pub fn can_send_messages(&self) -> bool {
self.imp().can_send_messages.get()
}
/// Update whether our own user can send messages in the current room.
fn update_can_send_messages(&self) {
let can_send = self.compute_can_send_messages();
if self.can_send_messages() == can_send {
return;
}
self.imp().can_send_messages.set(can_send);
self.set_sensitive(can_send);
self.notify("can-send-messages");
}
fn set_up_can_send_messages(&self, room: Option<&Room>) {
if let Some(room) = room {
if let Some(own_user_id) = room.session().user().map(|u| u.user_id().to_owned()) {
let imp = self.imp();
let own_member = room
.get_or_create_members()
.get_or_create(own_user_id.clone());
// We don't need to keep the handler around, the member should be dropped when
// switching rooms.
own_member.connect_notify_local(
Some("membership"),
clone!(@weak self as obj => move |_, _| {
obj.update_can_send_messages();
}),
);
imp.own_member.set(Some(&own_member));
let power_levels_handler = room.power_levels().connect_notify_local(
Some("power-levels"),
clone!(@weak self as obj => move |_, _| {
obj.update_can_send_messages();
}),
);
imp.power_levels_handler.replace(Some(power_levels_handler));
}
}
self.update_can_send_messages();
}
fn compute_can_send_messages(&self) -> bool {
let Some(room) = self.room() else {
return false;
};
let Some(member) = self.own_member() else {
return false;
};
if member.membership() != Membership::Join {
return false;
}
room.power_levels().member_is_allowed_to(
&member.user_id(),
PowerLevelAction::SendMessage(MessageLikeEventType::RoomMessage),
)
}
}
enum MentionChunk {