[fractal/fractal-next] message-row: Reuse MessageText when possible
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] message-row: Reuse MessageText when possible
- Date: Sat, 25 Dec 2021 08:57:34 +0000 (UTC)
commit 45b481d41ad845ff446538fffe49b1fcc050d9f4
Author: Kévin Commaille <zecakeh tedomum fr>
Date: Sat Dec 18 11:11:37 2021 +0100
message-row: Reuse MessageText when possible
Fixes #887
.../content/room_history/message_row/mod.rs | 85 ++++++++--
.../content/room_history/message_row/text.rs | 183 ++++++---------------
2 files changed, 118 insertions(+), 150 deletions(-)
---
diff --git a/src/session/content/room_history/message_row/mod.rs
b/src/session/content/room_history/message_row/mod.rs
index 110525d1..e604d8fe 100644
--- a/src/session/content/room_history/message_row/mod.rs
+++ b/src/session/content/room_history/message_row/mod.rs
@@ -205,9 +205,16 @@ impl MessageRow {
match msgtype {
MessageType::Audio(_message) => {}
MessageType::Emote(message) => {
- let child =
- MessageText::emote(message.formatted, message.body, event.sender());
- priv_.content.set_child(Some(&child));
+ let child = if let Some(Ok(child)) =
+ priv_.content.child().map(|w| w.downcast::<MessageText>())
+ {
+ child
+ } else {
+ let child = MessageText::new();
+ priv_.content.set_child(Some(&child));
+ child
+ };
+ child.emote(message.formatted, message.body, event.sender());
}
MessageType::File(message) => {
let filename = message.filename.unwrap_or(message.body);
@@ -220,16 +227,40 @@ impl MessageRow {
}
MessageType::Location(_message) => {}
MessageType::Notice(message) => {
- let child = MessageText::markup(message.formatted, message.body);
- priv_.content.set_child(Some(&child));
+ let child = if let Some(Ok(child)) =
+ priv_.content.child().map(|w| w.downcast::<MessageText>())
+ {
+ child
+ } else {
+ let child = MessageText::new();
+ priv_.content.set_child(Some(&child));
+ child
+ };
+ child.markup(message.formatted, message.body);
}
MessageType::ServerNotice(message) => {
- let child = MessageText::text(message.body);
- priv_.content.set_child(Some(&child));
+ let child = if let Some(Ok(child)) =
+ priv_.content.child().map(|w| w.downcast::<MessageText>())
+ {
+ child
+ } else {
+ let child = MessageText::new();
+ priv_.content.set_child(Some(&child));
+ child
+ };
+ child.text(message.body);
}
MessageType::Text(message) => {
- let child = MessageText::markup(message.formatted, message.body);
- priv_.content.set_child(Some(&child));
+ let child = if let Some(Ok(child)) =
+ priv_.content.child().map(|w| w.downcast::<MessageText>())
+ {
+ child
+ } else {
+ let child = MessageText::new();
+ priv_.content.set_child(Some(&child));
+ child
+ };
+ child.markup(message.formatted, message.body);
}
MessageType::Video(message) => {
let child = MessageMedia::video(message, &event.room().session());
@@ -247,16 +278,40 @@ impl MessageRow {
}
Some(AnyMessageEventContent::RoomEncrypted(content)) => {
warn!("Couldn't decrypt event {:?}", content);
- let child = MessageText::text(gettext("Fractal couldn't decrypt this message."));
- priv_.content.set_child(Some(&child));
+ let child = if let Some(Ok(child)) =
+ priv_.content.child().map(|w| w.downcast::<MessageText>())
+ {
+ child
+ } else {
+ let child = MessageText::new();
+ priv_.content.set_child(Some(&child));
+ child
+ };
+ child.text(gettext("Fractal couldn't decrypt this message."));
}
Some(AnyMessageEventContent::RoomRedaction(_)) => {
- let child = MessageText::text(gettext("This message was removed."));
- priv_.content.set_child(Some(&child));
+ let child = if let Some(Ok(child)) =
+ priv_.content.child().map(|w| w.downcast::<MessageText>())
+ {
+ child
+ } else {
+ let child = MessageText::new();
+ priv_.content.set_child(Some(&child));
+ child
+ };
+ child.text(gettext("This message was removed."));
}
_ => {
- let child = MessageText::text(gettext("Unsupported event"));
- priv_.content.set_child(Some(&child));
+ let child = if let Some(Ok(child)) =
+ priv_.content.child().map(|w| w.downcast::<MessageText>())
+ {
+ child
+ } else {
+ let child = MessageText::new();
+ priv_.content.set_child(Some(&child));
+ child
+ };
+ child.text(gettext("Unsupported event"));
}
}
}
diff --git a/src/session/content/room_history/message_row/text.rs
b/src/session/content/room_history/message_row/text.rs
index e3f58ebe..d08ea060 100644
--- a/src/session/content/room_history/message_row/text.rs
+++ b/src/session/content/room_history/message_row/text.rs
@@ -13,32 +13,13 @@ use crate::session::{
UserExt,
};
-#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, glib::GEnum)]
-#[repr(u32)]
-#[genum(type_name = "TextFormat")]
-pub enum TextFormat {
- Text = 0,
- Markup = 1,
- Html = 2,
- Emote = 3,
- HtmlEmote = 4,
-}
-
-impl Default for TextFormat {
- fn default() -> Self {
- TextFormat::Text
- }
-}
-
mod imp {
use super::*;
use once_cell::sync::Lazy;
- use std::cell::{Cell, RefCell};
+ use std::cell::RefCell;
#[derive(Debug, Default)]
pub struct MessageText {
- /// The format of the text message.
- pub format: Cell<TextFormat>,
/// The displayed content of the message.
pub body: RefCell<Option<String>>,
/// The sender of the message(only used for emotes).
@@ -56,20 +37,12 @@ mod imp {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![
- glib::ParamSpec::new_enum(
- "format",
- "Format",
- "The format of the text message",
- TextFormat::static_type(),
- TextFormat::default() as i32,
- glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
- ),
glib::ParamSpec::new_string(
"body",
"Body",
"The displayed content of the message",
None,
- glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
glib::ParamSpec::new_object(
"sender",
@@ -92,7 +65,6 @@ mod imp {
pspec: &glib::ParamSpec,
) {
match pspec.name() {
- "format" => obj.set_format(value.get().unwrap()),
"body" => obj.set_body(value.get().unwrap()),
"sender" => obj.set_sender(value.get().unwrap()),
_ => unimplemented!(),
@@ -101,7 +73,6 @@ mod imp {
fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
- "format" => obj.format().to_value(),
"body" => obj.body().to_value(),
"sender" => obj.sender().to_value(),
_ => unimplemented!(),
@@ -125,13 +96,21 @@ glib::wrapper! {
}
impl MessageText {
- // Creates a widget that displays plain text.
- pub fn text(body: String) -> Self {
- glib::Object::new(&[("body", &body)]).expect("Failed to create MessageText")
+ /// Creates a text widget.
+ pub fn new() -> Self {
+ glib::Object::new(&[]).expect("Failed to create MessageText")
+ }
+
+ /// Display the given plain text.
+ pub fn text(&self, body: String) {
+ self.build_text(&body, false);
+ self.set_body(Some(body));
}
- // Creates a widget that displays text with markup. It will detect if it should display the body or the
formatted body.
- pub fn markup(formatted: Option<FormattedBody>, body: String) -> Self {
+ /// Display the given text with markup.
+ ///
+ /// It will detect if it should display the body or the formatted body.
+ pub fn markup(&self, formatted: Option<FormattedBody>, body: String) {
if let Some((html_blocks, body)) = formatted
.filter(|formatted| is_valid_formatted_body(formatted))
.and_then(|formatted| {
@@ -139,60 +118,13 @@ impl MessageText {
.and_then(|blocks| Some((blocks, formatted.body)))
})
{
- let self_: Self = glib::Object::new(&[("format", &TextFormat::Html), ("body", &body)])
- .expect("Failed to create MessageText");
-
- self_.build_html(html_blocks);
- self_
- } else {
- let self_: Self =
- glib::Object::new(&[("format", &TextFormat::Markup), ("body", &linkify(&body))])
- .expect("Failed to create MessageText");
-
- self_.build();
- self_
- }
- }
-
- // Creates a widget that displays an emote. It will detect if it should display the body or the
formatted body.
- pub fn emote(formatted: Option<FormattedBody>, body: String, sender: Member) -> Self {
- if let Some(body) = formatted
- .filter(|formatted| is_valid_formatted_body(formatted))
- .and_then(|formatted| {
- let body = format!("<b>{}</b> {}", sender.display_name(), formatted.body);
-
- parse_formatted_body(&body).and_then(|_| Some(formatted.body))
- })
- {
- glib::Object::new(&[
- ("format", &TextFormat::HtmlEmote),
- ("body", &body),
- ("sender", &Some(sender)),
- ])
- .expect("Failed to create MessageText")
+ self.build_html(html_blocks);
+ self.set_body(Some(body));
} else {
- glib::Object::new(&[
- ("format", &TextFormat::Emote),
- ("body", &linkify(&body)),
- ("sender", &Some(sender)),
- ])
- .expect("Failed to create MessageText")
- }
- }
-
- pub fn set_format(&self, format: TextFormat) {
- let priv_ = imp::MessageText::from_instance(self);
-
- if format == priv_.format.get() {
- return;
+ let body = linkify(&body);
+ self.build_text(&body, true);
+ self.set_body(Some(body));
}
-
- priv_.format.set(format);
- }
-
- pub fn format(&self) -> TextFormat {
- let priv_ = imp::MessageText::from_instance(self);
- priv_.format.get()
}
pub fn set_body(&self, body: Option<String>) {
@@ -218,11 +150,6 @@ impl MessageText {
}
priv_.sender.replace(sender);
-
- if self.format() == TextFormat::Emote || self.format() == TextFormat::HtmlEmote {
- self.build();
- }
-
self.notify("sender");
}
@@ -231,48 +158,34 @@ impl MessageText {
priv_.sender.borrow().to_owned()
}
- fn build(&self) {
- match self.format() {
- TextFormat::Text => {
- self.build_text(&self.body().unwrap(), false);
- }
- TextFormat::Markup => {
- self.build_text(&self.body().unwrap(), true);
- }
- TextFormat::Html => {
- let formatted = FormattedBody {
- body: self.body().unwrap(),
- format: MessageFormat::Html,
- };
-
- let html = parse_formatted_body(&formatted.body).unwrap();
- self.build_html(html);
- }
- TextFormat::Emote => {
- // TODO: we need to bind the display name to the sender
- self.build_text(
- &format!(
- "<b>{}</b> {}",
- self.sender().unwrap().display_name(),
- &self.body().unwrap()
- ),
- true,
- );
- }
- TextFormat::HtmlEmote => {
- // TODO: we need to bind the display name to the sender
- let formatted = FormattedBody {
- body: format!(
- "<b>{}</b> {}",
- self.sender().unwrap().display_name(),
- self.body().unwrap()
- ),
- format: MessageFormat::Html,
- };
+ /// Display the given emote for `sender`.
+ ///
+ /// It will detect if it should display the body or the formatted body.
+ pub fn emote(&self, formatted: Option<FormattedBody>, body: String, sender: Member) {
+ if let Some(body) = formatted
+ .filter(|formatted| is_valid_formatted_body(formatted))
+ .and_then(|formatted| {
+ let body = format!("<b>{}</b> {}", sender.display_name(), formatted.body);
- let html = parse_formatted_body(&formatted.body).unwrap();
- self.build_html(html);
- }
+ parse_formatted_body(&body).and_then(|_| Some(formatted.body))
+ })
+ {
+ // TODO: we need to bind the display name to the sender
+ let formatted = FormattedBody {
+ body: format!("<b>{}</b> {}", sender.display_name(), &body),
+ format: MessageFormat::Html,
+ };
+
+ let html = parse_formatted_body(&formatted.body).unwrap();
+ self.build_html(html);
+ self.set_body(Some(body));
+ self.set_sender(Some(sender));
+ } else {
+ // TODO: we need to bind the display name to the sender
+ let body = linkify(&body);
+ self.build_text(&format!("<b>{}</b> {}", sender.display_name(), &body), true);
+ self.set_body(Some(body));
+ self.set_sender(Some(sender));
}
}
@@ -408,6 +321,6 @@ fn create_widget_for_html_block(block: &HtmlBlock) -> gtk::Widget {
impl Default for MessageText {
fn default() -> Self {
- Self::text(format!(""))
+ Self::new()
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]