Browse Source

message-toolbar: Add a send guard

To prevent sending the same message several times.
fractal-9
Kévin Commaille 2 years ago
parent
commit
f1d2fce121
No known key found for this signature in database
GPG Key ID: C971D9DBC9D678D
  1. 86
      src/session/view/content/room_history/message_toolbar/mod.rs

86
src/session/view/content/room_history/message_toolbar/mod.rs

@ -1,7 +1,7 @@
use std::{collections::HashMap, fmt::Write};
use adw::{prelude::*, subclass::prelude::*};
use futures_util::{future, pin_mut, StreamExt};
use futures_util::{future, lock::Mutex, pin_mut, StreamExt};
use gettextrs::{gettext, pgettext};
use gtk::{
gdk, gio,
@ -72,7 +72,7 @@ mod imp {
/// The room to send messages in.
#[property(get, set = Self::set_room, explicit_notify, nullable)]
pub room: glib::WeakRef<Room>,
pub can_send_message_handler: RefCell<Option<glib::SignalHandlerId>>,
pub send_message_permission_handler: RefCell<Option<glib::SignalHandlerId>>,
/// Whether outgoing messages should be interpreted as markdown.
#[property(get, set)]
pub markdown_enabled: Cell<bool>,
@ -94,6 +94,8 @@ mod imp {
///
/// The fallback composer state has the `None` key.
pub composer_states: RefCell<ComposerStatesMap>,
/// A guard to avoid sending several messages at once.
pub(super) send_guard: Mutex<()>,
}
#[glib::object_subclass]
@ -160,7 +162,7 @@ mod imp {
#[weak]
obj,
move |entry| {
if !obj.imp().can_send_message() {
if !obj.imp().can_compose_message() {
return;
}
@ -253,7 +255,7 @@ mod imp {
self.completion.unparent();
if let Some(room) = self.room.upgrade() {
if let Some(handler) = self.can_send_message_handler.take() {
if let Some(handler) = self.send_message_permission_handler.take() {
room.permissions().disconnect(handler);
}
}
@ -273,43 +275,47 @@ mod imp {
let obj = self.obj();
if let Some(room) = &old_room {
if let Some(handler) = self.can_send_message_handler.take() {
if let Some(handler) = self.send_message_permission_handler.take() {
room.permissions().disconnect(handler);
}
}
if let Some(room) = &room {
let can_send_message_handler =
let send_message_permission_handler =
room.permissions().connect_can_send_message_notify(clone!(
#[weak(rename_to = imp)]
self,
move |_| {
imp.can_send_message_updated();
imp.send_message_permission_updated();
}
));
self.can_send_message_handler
.replace(Some(can_send_message_handler));
self.send_message_permission_handler
.replace(Some(send_message_permission_handler));
}
self.room.set(room.as_ref());
self.can_send_message_updated();
self.send_message_permission_updated();
self.message_entry.grab_focus();
obj.notify_room();
self.update_current_composer_state(old_room.as_ref());
}
/// Whether our own user can send a message in the current room.
pub(super) fn can_send_message(&self) -> bool {
/// Whether the user can compose a message.
///
/// It depends on whether our own user has the permission to send a
/// message in the current room.
pub(super) fn can_compose_message(&self) -> bool {
self.room
.upgrade()
.is_some_and(|r| r.permissions().can_send_message())
}
/// Update whether our own user can send a message in the current room.
fn can_send_message_updated(&self) {
let page = if self.can_send_message() {
/// Handle an update of the permission to send a message in the current
/// room.
fn send_message_permission_updated(&self) {
let page = if self.can_compose_message() {
"enabled"
} else {
"disabled"
@ -462,7 +468,12 @@ impl MessageToolbar {
/// Add a mention of the given member to the message composer.
pub fn mention_member(&self, member: &Member) {
let view = &*self.imp().message_entry;
let imp = self.imp();
if !imp.can_compose_message() {
return;
}
let view = &imp.message_entry;
let buffer = view.buffer();
let mut insert = buffer.iter_at_mark(&buffer.get_insert());
@ -476,7 +487,7 @@ impl MessageToolbar {
/// Set the event to reply to.
pub fn set_reply_to(&self, event: Event) {
let imp = self.imp();
if !imp.can_send_message() {
if !imp.can_compose_message() {
return;
}
@ -494,7 +505,7 @@ impl MessageToolbar {
/// Set the event to edit.
pub fn set_edit(&self, event: Event) {
let imp = self.imp();
if !imp.can_send_message() {
if !imp.can_compose_message() {
return;
}
@ -518,7 +529,10 @@ impl MessageToolbar {
/// Send the text message that is currently in the message entry.
async fn send_text_message(&self) {
let imp = self.imp();
if !imp.can_send_message() {
let Some(_send_guard) = imp.send_guard.try_lock() else {
return;
};
if !imp.can_compose_message() {
return;
}
let Some(room) = self.room() else {
@ -655,7 +669,7 @@ impl MessageToolbar {
/// Open the emoji chooser in the message entry.
fn open_emoji(&self) {
let imp = self.imp();
if !imp.can_send_message() {
if !imp.can_compose_message() {
return;
}
imp.message_entry.emit_insert_emoji();
@ -666,7 +680,11 @@ impl MessageToolbar {
/// Shows a preview of the location first and asks the user to confirm the
/// action.
async fn send_location(&self) {
if !self.imp().can_send_message() {
let imp = self.imp();
let Some(_send_guard) = imp.send_guard.try_lock() else {
return;
};
if !self.imp().can_compose_message() {
return;
}
let Some(room) = self.room() else {
@ -822,7 +840,11 @@ impl MessageToolbar {
/// Shows a preview of the image first and asks the user to confirm the
/// action.
async fn send_image(&self, image: gdk::Texture) {
if !self.imp().can_send_message() {
let imp = self.imp();
let Some(_send_guard) = imp.send_guard.try_lock() else {
return;
};
if !imp.can_compose_message() {
return;
}
@ -849,7 +871,11 @@ impl MessageToolbar {
/// Select a file to send.
pub async fn select_file(&self) {
if !self.imp().can_send_message() {
let imp = self.imp();
let Some(_send_guard) = imp.send_guard.try_lock() else {
return;
};
if !imp.can_compose_message() {
return;
}
@ -864,7 +890,7 @@ impl MessageToolbar {
.await
{
Ok(file) => {
self.send_file(file).await;
self.send_file_inner(file).await;
}
Err(error) => {
if error.matches(gtk::DialogError::Dismissed) {
@ -882,10 +908,18 @@ impl MessageToolbar {
/// Shows a preview of the file first, if possible, and asks the user to
/// confirm the action.
pub async fn send_file(&self, file: gio::File) {
if !self.imp().can_send_message() {
let imp = self.imp();
let Some(_send_guard) = imp.send_guard.try_lock() else {
return;
};
if !imp.can_compose_message() {
return;
}
self.send_file_inner(file).await;
}
async fn send_file_inner(&self, file: gio::File) {
let (bytes, file_info) = match load_file(&file).await {
Ok(data) => data,
Err(error) => {
@ -987,7 +1021,7 @@ impl MessageToolbar {
/// Handle a paste action.
pub fn handle_paste_action(&self) {
if !self.imp().can_send_message() {
if !self.imp().can_compose_message() {
return;
}

Loading…
Cancel
Save