[fractal/fractal-next] mentions: Add initial support for sending mentions
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] mentions: Add initial support for sending mentions
- Date: Mon, 13 Dec 2021 11:53:20 +0000 (UTC)
commit 978e048500634a752aa059e6c21e18f5ab3560ad
Author: Enterprisey <59171-enterprisey users noreply gitlab gnome org>
Date: Sat Dec 4 21:54:10 2021 -0800
mentions: Add initial support for sending mentions
A Pill in the message field will now result in a ping. There is
currently no way to add a Pill; you'll have to hack one in.
src/session/content/room_history/mod.rs | 93 +++++++++++++++++++++++++++++++--
src/session/room/mod.rs | 39 +++-----------
2 files changed, 95 insertions(+), 37 deletions(-)
---
diff --git a/src/session/content/room_history/mod.rs b/src/session/content/room_history/mod.rs
index 9dc7dbd9..dec58d4e 100644
--- a/src/session/content/room_history/mod.rs
+++ b/src/session/content/room_history/mod.rs
@@ -12,11 +12,16 @@ use gtk::{
gdk, glib, glib::clone, glib::signal::Inhibit, prelude::*, subclass::prelude::*,
CompositeTemplate,
};
+use matrix_sdk::ruma::events::room::message::{
+ EmoteMessageEventContent, FormattedBody, MessageType, RoomMessageEventContent,
+ TextMessageEventContent,
+};
use sourceview::prelude::*;
-use crate::components::{CustomEntry, RoomTitle};
+use crate::components::{CustomEntry, Pill, RoomTitle};
use crate::session::content::{MarkdownPopover, RoomDetails};
use crate::session::room::{Item, Room, RoomType};
+use crate::session::user::UserExt;
mod imp {
use super::*;
@@ -373,12 +378,92 @@ impl RoomHistory {
let priv_ = imp::RoomHistory::from_instance(self);
let buffer = priv_.message_entry.buffer();
let (start_iter, end_iter) = buffer.bounds();
- let body = buffer.text(&start_iter, &end_iter, true);
+ let body_len = buffer.text(&start_iter, &end_iter, true).len();
+
+ let is_markdown = priv_.md_enabled.get();
+ let mut has_mentions = false;
+ let mut plain_body = String::with_capacity(body_len);
+ // formatted_body is Markdown if is_markdown is true, and HTML if false.
+ let mut formatted_body = String::with_capacity(body_len);
+ // uncopied_text_location is the start of the text we haven't copied to plain_body and
formatted_body.
+ let mut uncopied_text_location = start_iter.clone();
+
+ let mut iter = start_iter;
+ loop {
+ if let Some(anchor) = iter.child_anchor() {
+ let widgets = anchor.widgets();
+ let pill = widgets.first().unwrap().downcast_ref::<Pill>().unwrap();
+ let (url, label) = pill
+ .user()
+ .map(|user| {
+ (
+ user.user_id().matrix_to_url().to_string(),
+ user.display_name(),
+ )
+ })
+ .or(pill.room().map(|room| {
+ (
+ // No server name needed. matrix.to URIs for mentions aren't routable
+ room.room_id().matrix_to_url([]).to_string(),
+ room.display_name(),
+ )
+ }))
+ .unwrap();
+
+ // Add more uncopied characters from message
+ let some_text = buffer.text(&uncopied_text_location, &iter, false);
+ plain_body.push_str(&some_text);
+ formatted_body.push_str(&some_text);
+ uncopied_text_location = iter.clone();
+
+ // Add mention
+ has_mentions = true;
+ plain_body.push_str(&label);
+ formatted_body.push_str(&if is_markdown {
+ format!("[{}]({})", label, url)
+ } else {
+ format!("<a href='{}'>{}</a>", url, label)
+ });
+ }
+ if !iter.forward_char() {
+ // Add remaining uncopied characters
+ let some_text = buffer.text(&uncopied_text_location, &iter, false);
+ plain_body.push_str(&some_text);
+ formatted_body.push_str(&some_text);
+ break;
+ }
+ }
- if let Some(room) = &*priv_.room.borrow() {
- room.send_text_message(body.as_str(), priv_.md_enabled.get());
+ let is_emote = plain_body.starts_with("/me ");
+ if is_emote {
+ plain_body.replace_range(.."/me ".len(), "");
+ formatted_body.replace_range(.."/me ".len(), "");
}
+ let html_body = if is_markdown {
+ FormattedBody::markdown(formatted_body).map(|b| b.body)
+ } else if has_mentions {
+ // Already formatted with HTML
+ Some(formatted_body)
+ } else {
+ None
+ };
+
+ let content = RoomMessageEventContent::new(if is_emote {
+ MessageType::Emote(if let Some(html_body) = html_body {
+ EmoteMessageEventContent::html(plain_body, html_body)
+ } else {
+ EmoteMessageEventContent::plain(plain_body)
+ })
+ } else {
+ MessageType::Text(if let Some(html_body) = html_body {
+ TextMessageEventContent::html(plain_body, html_body)
+ } else {
+ TextMessageEventContent::plain(plain_body)
+ })
+ });
+
+ self.room().unwrap().send_message(content);
buffer.set_text("");
}
diff --git a/src/session/room/mod.rs b/src/session/room/mod.rs
index 085536d8..c3f601c8 100644
--- a/src/session/room/mod.rs
+++ b/src/session/room/mod.rs
@@ -33,13 +33,8 @@ use matrix_sdk::{
api::client::r0::sync::sync_events::InvitedRoom,
events::{
room::{
- member::MembershipState,
- message::{
- EmoteMessageEventContent, MessageType, RoomMessageEventContent,
- TextMessageEventContent,
- },
- name::RoomNameEventContent,
- topic::RoomTopicEventContent,
+ member::MembershipState, message::RoomMessageEventContent,
+ name::RoomNameEventContent, topic::RoomTopicEventContent,
},
tag::TagName,
AnyRoomAccountDataEvent, AnyStateEventContent, AnyStrippedStateEvent,
@@ -846,40 +841,18 @@ impl Room {
);
}
- pub fn send_text_message(&self, body: &str, markdown_enabled: bool) {
- let content = if let Some(body) = body.strip_prefix("/me ") {
- let emote = if markdown_enabled {
- EmoteMessageEventContent::markdown(body)
- } else {
- EmoteMessageEventContent::plain(body)
- };
- RoomMessageEventContent::new(MessageType::Emote(emote))
- } else {
- let text = if markdown_enabled {
- TextMessageEventContent::markdown(body)
- } else {
- TextMessageEventContent::plain(body)
- };
- RoomMessageEventContent::new(MessageType::Text(text))
- };
+ pub fn send_message(&self, content: RoomMessageEventContent) {
+ let priv_ = imp::Room::from_instance(self);
let txn_id = Uuid::new_v4();
-
- let pending_event = AnySyncMessageEvent::RoomMessage(SyncMessageEvent {
- content,
+ let event = AnySyncMessageEvent::RoomMessage(SyncMessageEvent {
+ content: content.clone(),
event_id: EventId::try_from(format!("${}:fractal.gnome.org", txn_id)).unwrap(),
sender: self.session().user().unwrap().user_id().clone(),
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
unsigned: Unsigned::default(),
});
- self.send_message(txn_id, pending_event);
- }
-
- pub fn send_message(&self, txn_id: Uuid, event: AnySyncMessageEvent) {
- let priv_ = imp::Room::from_instance(self);
- let content = event.content();
-
if let MatrixRoom::Joined(matrix_room) = self.matrix_room() {
let json = serde_json::to_string(&AnySyncRoomEvent::Message(event)).unwrap();
let raw_event: Raw<AnySyncRoomEvent> =
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]