Browse Source

Merge branch 'dont-send-unchanged-edits' into 'main'

message toolbar: don't send identical edits

Closes #1630

See merge request World/fractal!2003
merge-requests/2003/merge
Eric Daigle 10 months ago
parent
commit
eaa772a593
  1. 50
      src/session/view/content/room_history/message_toolbar/composer_state.rs
  2. 50
      src/session/view/content/room_history/message_toolbar/mod.rs

50
src/session/view/content/room_history/message_toolbar/composer_state.rs

@ -5,7 +5,7 @@ use gtk::{
subclass::prelude::*,
};
use matrix_sdk::{deserialized_responses::TimelineEvent, ComposerDraft, ComposerDraftType};
use matrix_sdk_ui::timeline::Message;
use matrix_sdk_ui::timeline::TimelineItemContent;
use ruma::{
events::{
room::message::{MessageFormat, MessageType, OriginalSyncRoomMessageEvent},
@ -340,11 +340,27 @@ mod imp {
}
/// Update the buffer for the given edit source.
pub(super) fn set_edit_source(&self, event_id: OwnedEventId, message: &Message) {
pub(super) fn set_edit_source(&self, message_event: &MessageEventSource) {
let Some(room) = self.room.upgrade() else {
return;
};
let MessageEventSource::Event(event) = message_event else {
warn!("Unsupported event type for edit");
return;
};
let item = event.item();
let TimelineItemContent::MsgLike(msg_like) = item.content() else {
warn!("Unsupported event type for edit");
return;
};
let Some(message) = msg_like.as_message() else {
warn!("Unsupported event type for edit");
return;
};
// We don't support editing non-text messages.
let (text, formatted) = match message.msgtype() {
MessageType::Emote(emote) => {
@ -354,7 +370,7 @@ mod imp {
_ => return,
};
self.set_related_to(Some(RelationInfo::Edit(event_id)));
self.set_related_to(Some(RelationInfo::Edit(message_event.clone())));
// Try to detect rich mentions.
let mut mentions = if let Some(html) =
@ -484,8 +500,8 @@ impl ComposerState {
}
/// Update the buffer for the given edit source.
pub(crate) fn set_edit_source(&self, event_id: OwnedEventId, message: &Message) {
self.imp().set_edit_source(event_id, message);
pub(crate) fn set_edit_source(&self, message_event: &MessageEventSource) {
self.imp().set_edit_source(message_event);
}
/// Add the given widget at the position of the given iter to this state.
@ -519,16 +535,16 @@ pub(crate) enum RelationInfo {
/// Send a reply to the given event.
Reply(MessageEventSource),
/// Send an edit to the event with the given ID.
Edit(OwnedEventId),
/// Send an edit to the given event.
Edit(MessageEventSource),
}
impl RelationInfo {
/// Construct a relation info from a composer draft, if possible.
pub(crate) async fn from_draft(room: &Room, draft_type: ComposerDraftType) -> Option<Self> {
match draft_type {
match &draft_type {
ComposerDraftType::NewMessage => None,
ComposerDraftType::Reply { event_id } => {
ComposerDraftType::Reply { event_id } | ComposerDraftType::Edit { event_id } => {
// We need to fetch the event and extract its content, so we can display it.
let matrix_room = room.matrix_room().clone();
let event_id_clone = event_id.clone();
@ -551,17 +567,21 @@ impl RelationInfo {
return None;
};
Some(RelationInfo::Reply(message_event))
match draft_type {
ComposerDraftType::Reply { .. } => Some(RelationInfo::Reply(message_event)),
ComposerDraftType::Edit { .. } => Some(RelationInfo::Edit(message_event)),
ComposerDraftType::NewMessage { .. } => None,
}
}
ComposerDraftType::Edit { event_id } => Some(RelationInfo::Edit(event_id)),
}
}
/// The unique global identifier of the related event.
pub(crate) fn event_id(&self) -> OwnedEventId {
match self {
RelationInfo::Reply(message_event) => message_event.event_id(),
RelationInfo::Edit(event_id) => event_id.clone(),
RelationInfo::Reply(message_event) | RelationInfo::Edit(message_event) => {
message_event.event_id()
}
}
}
@ -571,8 +591,8 @@ impl RelationInfo {
Self::Reply(message_event) => ComposerDraftType::Reply {
event_id: message_event.event_id(),
},
Self::Edit(event_id) => ComposerDraftType::Edit {
event_id: event_id.clone(),
Self::Edit(message_event) => ComposerDraftType::Edit {
event_id: message_event.event_id(),
},
}
}

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

@ -448,7 +448,38 @@ mod imp {
move |_| {
let is_empty = imp.is_buffer_empty();
imp.send_button.set_sensitive(!is_empty);
imp.send_typing_notification(!is_empty);
if is_empty {
return;
}
// If we're editing, disable the send button while the body is unchanged
if let Some(RelationInfo::Edit(message)) =
imp.current_composer_state().related_to()
{
if let Some(message_type) = message.msgtype() {
let original_body = match &message_type {
MessageType::Text(text) => text.body.clone(),
MessageType::Emote(emote) => emote.body.clone(),
_ => return,
};
let body = match &message_type {
MessageType::Emote(_) => {
ComposerParser::new(&imp.current_composer_state(), None)
.into_plain_text()
.replace("/me ", "")
}
MessageType::Text(_) => {
ComposerParser::new(&imp.current_composer_state(), None)
.into_plain_text()
}
_ => return,
};
let unchanged = original_body == body;
imp.send_button.set_sensitive(!unchanged);
imp.send_typing_notification(!unchanged);
}
}
}
));
@ -586,21 +617,22 @@ mod imp {
let item = event.item();
let Some(event_id) = item.event_id() else {
warn!("Cannot send edit for event that is not sent yet");
let TimelineItemContent::MsgLike(msg_like) = item.content() else {
warn!("Unsupported event type for edit");
return;
};
let TimelineItemContent::MsgLike(msg_like) = item.content() else {
let Some(_message) = msg_like.as_message() else {
warn!("Unsupported event type for edit");
return;
};
let Some(message) = msg_like.as_message() else {
let Some(message_event) = MessageEventSource::from_event(event.clone()) else {
warn!("Unsupported event type for edit");
return;
};
self.current_composer_state()
.set_edit_source(event_id.to_owned(), &message);
.set_edit_source(&message_event);
self.message_entry.grab_focus();
}
@ -669,6 +701,9 @@ mod imp {
if !self.can_compose_message() {
return;
}
if !self.send_button.is_sensitive() {
return;
}
let Some(timeline) = self.timeline.upgrade() else {
return;
};
@ -703,8 +738,9 @@ mod imp {
toast!(self.obj(), gettext("Could not send reply"));
}
}
Some(RelationInfo::Edit(event_id)) => {
Some(RelationInfo::Edit(message_event)) => {
let matrix_room = timeline.room().matrix_room().clone();
let event_id = message_event.event_id();
let handle = spawn_tokio!(async move {
let full_content = matrix_room
.make_edit_event(&event_id, EditedContent::RoomMessage(content))

Loading…
Cancel
Save