[fractal/fractal-next] content: Show media messages in replies in a compact format
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] content: Show media messages in replies in a compact format
- Date: Thu, 13 Jan 2022 19:46:49 +0000 (UTC)
commit 245e35de1033d9d443290c45b5ef9b2b36f76f4b
Author: Kévin Commaille <zecakeh tedomum fr>
Date: Thu Jan 13 14:32:09 2022 +0100
content: Show media messages in replies in a compact format
data/resources/ui/components-video-player.ui | 1 +
data/resources/ui/content-message-file.ui | 5 +-
src/components/video_player.rs | 57 ++++++++++++++++++++-
.../content/room_history/message_row/file.rs | 49 +++++++++++++-----
.../content/room_history/message_row/media.rs | 58 +++++++++++++++++-----
.../content/room_history/message_row/mod.rs | 20 +++++---
6 files changed, 153 insertions(+), 37 deletions(-)
---
diff --git a/data/resources/ui/components-video-player.ui b/data/resources/ui/components-video-player.ui
index 08fe5ca4..a1d664dc 100644
--- a/data/resources/ui/components-video-player.ui
+++ b/data/resources/ui/components-video-player.ui
@@ -12,6 +12,7 @@
<class name="osd"/>
<class name="timestamp"/>
</style>
+ <property name="visible" bind-source="ComponentsVideoPlayer" bind-property="compact"
bind-flags="sync-create | invert-boolean"/>
<property name="halign">GTK_ALIGN_START</property>
<property name="valign">GTK_ALIGN_START</property>
<property name="margin-start">5</property>
diff --git a/data/resources/ui/content-message-file.ui b/data/resources/ui/content-message-file.ui
index fc7dff38..afba9c9d 100644
--- a/data/resources/ui/content-message-file.ui
+++ b/data/resources/ui/content-message-file.ui
@@ -9,13 +9,12 @@
<child>
<object class="GtkLabel">
<property name="ellipsize">end</property>
- <binding name="label">
- <lookup name="filename">ContentMessageFile</lookup>
- </binding>
+ <property name="label" bind-source="ContentMessageFile" bind-property="filename"
bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="GtkBox">
+ <property name="visible" bind-source="ContentMessageFile" bind-property="compact"
bind-flags="sync-create | invert-boolean"/>
<child>
<object class="GtkButton" id="open">
<property name="icon-name">document-open-symbolic</property>
diff --git a/src/components/video_player.rs b/src/components/video_player.rs
index e417d8b7..4b57e293 100644
--- a/src/components/video_player.rs
+++ b/src/components/video_player.rs
@@ -4,11 +4,14 @@ use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate
mod imp {
use super::*;
use glib::subclass::InitializingObject;
- use std::cell::RefCell;
+ use once_cell::sync::Lazy;
+ use std::cell::{Cell, RefCell};
#[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/org/gnome/FractalNext/components-video-player.ui")]
pub struct VideoPlayer {
+ /// Whether this player should be displayed in a compact format.
+ pub compact: Cell<bool>,
pub duration_handler: RefCell<Option<glib::SignalHandlerId>>,
#[template_child]
pub video: TemplateChild<gtk::Picture>,
@@ -31,7 +34,41 @@ mod imp {
}
}
- impl ObjectImpl for VideoPlayer {}
+ impl ObjectImpl for VideoPlayer {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::new_boolean(
+ "compact",
+ "Compact",
+ "Whether this player should be displayed in a compact format",
+ false,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.name() {
+ "compact" => obj.set_compact(value.get().unwrap()),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "compact" => obj.compact().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+ }
impl WidgetImpl for VideoPlayer {}
@@ -50,6 +87,22 @@ impl VideoPlayer {
glib::Object::new(&[]).expect("Failed to create VideoPlayer")
}
+ pub fn compact(&self) -> bool {
+ let priv_ = imp::VideoPlayer::from_instance(self);
+ priv_.compact.get()
+ }
+
+ pub fn set_compact(&self, compact: bool) {
+ let priv_ = imp::VideoPlayer::from_instance(self);
+
+ if self.compact() == compact {
+ return;
+ }
+
+ priv_.compact.set(compact);
+ self.notify("compact");
+ }
+
/// Set the media_file to display.
pub fn set_media_file(&self, media_file: >k::MediaFile) {
let priv_ = imp::VideoPlayer::from_instance(self);
diff --git a/src/session/content/room_history/message_row/file.rs
b/src/session/content/room_history/message_row/file.rs
index 5466d4de..2ea65e8f 100644
--- a/src/session/content/room_history/message_row/file.rs
+++ b/src/session/content/room_history/message_row/file.rs
@@ -5,13 +5,15 @@ mod imp {
use super::*;
use glib::subclass::InitializingObject;
use once_cell::sync::Lazy;
- use std::cell::RefCell;
+ use std::cell::{Cell, RefCell};
#[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/org/gnome/FractalNext/content-message-file.ui")]
pub struct MessageFile {
/// The filename of the file
pub filename: RefCell<Option<String>>,
+ /// Whether this file should be displayed in a compact format.
+ pub compact: Cell<bool>,
}
#[glib::object_subclass]
@@ -32,13 +34,22 @@ mod imp {
impl ObjectImpl for MessageFile {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
- vec![glib::ParamSpec::new_string(
- "filename",
- "Filename",
- "The filename of the file",
- None,
- glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
- )]
+ vec![
+ glib::ParamSpec::new_string(
+ "filename",
+ "Filename",
+ "The filename of the file",
+ None,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ glib::ParamSpec::new_boolean(
+ "compact",
+ "Compact",
+ "Whether this file should be displayed in a compact format",
+ false,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ ]
});
PROPERTIES.as_ref()
@@ -53,6 +64,7 @@ mod imp {
) {
match pspec.name() {
"filename" => obj.set_filename(value.get().unwrap()),
+ "compact" => obj.set_compact(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -60,13 +72,10 @@ mod imp {
fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"filename" => obj.filename().to_value(),
+ "compact" => obj.compact().to_value(),
_ => unimplemented!(),
}
}
-
- fn constructed(&self, obj: &Self::Type) {
- self.parent_constructed(obj);
- }
}
impl WidgetImpl for MessageFile {}
@@ -102,6 +111,22 @@ impl MessageFile {
let priv_ = imp::MessageFile::from_instance(self);
priv_.filename.borrow().to_owned()
}
+
+ pub fn set_compact(&self, compact: bool) {
+ let priv_ = imp::MessageFile::from_instance(self);
+
+ if self.compact() == compact {
+ return;
+ }
+
+ priv_.compact.set(compact);
+ self.notify("compact");
+ }
+
+ pub fn compact(&self) -> bool {
+ let priv_ = imp::MessageFile::from_instance(self);
+ priv_.compact.get()
+ }
}
impl Default for MessageFile {
diff --git a/src/session/content/room_history/message_row/media.rs
b/src/session/content/room_history/message_row/media.rs
index b8cf64df..a167f88c 100644
--- a/src/session/content/room_history/message_row/media.rs
+++ b/src/session/content/room_history/message_row/media.rs
@@ -32,6 +32,8 @@ const MAX_THUMBNAIL_WIDTH: i32 = 600;
const MAX_THUMBNAIL_HEIGHT: i32 = 400;
const FALLBACK_WIDTH: i32 = 480;
const FALLBACK_HEIGHT: i32 = 360;
+const MAX_COMPACT_THUMBNAIL_WIDTH: i32 = 75;
+const MAX_COMPACT_THUMBNAIL_HEIGHT: i32 = 50;
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, glib::GEnum)]
#[repr(u32)]
@@ -75,6 +77,8 @@ mod imp {
pub height: Cell<i32>,
/// The state of the media.
pub state: Cell<MediaState>,
+ /// Whether to display this media in a compact format.
+ pub compact: Cell<bool>,
#[template_child]
pub media: TemplateChild<gtk::Overlay>,
#[template_child]
@@ -128,6 +132,13 @@ mod imp {
MediaState::default() as i32,
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
+ glib::ParamSpec::new_boolean(
+ "compact",
+ "Compact",
+ "Whether to display this media in a compact format",
+ false,
+ glib::ParamFlags::READABLE,
+ ),
]
});
@@ -160,6 +171,7 @@ mod imp {
"width" => obj.width().to_value(),
"height" => obj.height().to_value(),
"state" => obj.state().to_value(),
+ "compact" => obj.compact().to_value(),
_ => unimplemented!(),
}
}
@@ -172,29 +184,36 @@ mod imp {
impl WidgetImpl for MessageMedia {
fn measure(
&self,
- _obj: &Self::Type,
+ obj: &Self::Type,
orientation: gtk::Orientation,
for_size: i32,
) -> (i32, i32, i32, i32) {
let original_width = self.width.get();
let original_height = self.height.get();
+ let compact = obj.compact();
+ let (max_width, max_height) = if compact {
+ (MAX_COMPACT_THUMBNAIL_WIDTH, MAX_COMPACT_THUMBNAIL_HEIGHT)
+ } else {
+ (MAX_THUMBNAIL_WIDTH, MAX_THUMBNAIL_HEIGHT)
+ };
+
let (original, max, fallback, original_other, max_other) =
if orientation == gtk::Orientation::Vertical {
(
original_height,
- MAX_THUMBNAIL_HEIGHT,
+ max_height,
FALLBACK_HEIGHT,
original_width,
- MAX_THUMBNAIL_WIDTH,
+ max_width,
)
} else {
(
original_width,
- MAX_THUMBNAIL_WIDTH,
+ max_width,
FALLBACK_WIDTH,
original_height,
- MAX_THUMBNAIL_HEIGHT,
+ max_height,
)
};
@@ -212,7 +231,7 @@ mod imp {
fallback
};
- // Limit this size to 400 pixels.
+ // Limit this side to max size.
let size = nat.min(max);
(0, size, -1, -1)
}
@@ -316,19 +335,31 @@ impl MessageMedia {
self.notify("state");
}
- /// Display the given `image`.
- pub fn image(&self, image: ImageMessageEventContent, session: &Session) {
+ fn compact(&self) -> bool {
+ let priv_ = imp::MessageMedia::from_instance(self);
+ priv_.compact.get()
+ }
+
+ fn set_compact(&self, compact: bool) {
+ let priv_ = imp::MessageMedia::from_instance(self);
+ priv_.compact.set(compact);
+ self.notify("compact");
+ }
+
+ /// Display the given `image`, in a `compact` format or not.
+ pub fn image(&self, image: ImageMessageEventContent, session: &Session, compact: bool) {
let info = image.info.as_deref();
let width = uint_to_i32(info.and_then(|info| info.width));
let height = uint_to_i32(info.and_then(|info| info.height));
self.set_width(width);
self.set_height(height);
+ self.set_compact(compact);
self.build(image, None, MediaType::Image, session);
}
- /// Display the given `sticker`.
- pub fn sticker(&self, sticker: StickerEventContent, session: &Session) {
+ /// Display the given `sticker`, in a `compact` format or not.
+ pub fn sticker(&self, sticker: StickerEventContent, session: &Session, compact: bool) {
let info = &sticker.info;
let width = uint_to_i32(info.width);
let height = uint_to_i32(info.height);
@@ -336,11 +367,12 @@ impl MessageMedia {
self.set_width(width);
self.set_height(height);
+ self.set_compact(compact);
self.build(sticker, body, MediaType::Sticker, session);
}
- /// Display the given `video`.
- pub fn video(&self, video: VideoMessageEventContent, session: &Session) {
+ /// Display the given `video`, in a `compact` format or not.
+ pub fn video(&self, video: VideoMessageEventContent, session: &Session, compact: bool) {
let info = &video.info.as_deref();
let width = uint_to_i32(info.and_then(|info| info.width));
let height = uint_to_i32(info.and_then(|info| info.height));
@@ -348,6 +380,7 @@ impl MessageMedia {
self.set_width(width);
self.set_height(height);
+ self.set_compact(compact);
self.build(video, body, MediaType::Video, session);
}
@@ -446,6 +479,7 @@ impl MessageMedia {
priv_.media.set_child(Some(&child));
child
};
+ child.set_compact(obj.compact());
child.set_media_file(&media_file)
}
};
diff --git a/src/session/content/room_history/message_row/mod.rs
b/src/session/content/room_history/message_row/mod.rs
index f5a9b57d..8aa07981 100644
--- a/src/session/content/room_history/message_row/mod.rs
+++ b/src/session/content/room_history/message_row/mod.rs
@@ -200,16 +200,16 @@ impl MessageRow {
if let Ok(Some(related_event)) = event.reply_to_event().await {
let reply = MessageReply::new();
reply.set_related_content_sender(related_event.sender().upcast());
- build_content(reply.related_content(), &related_event);
- build_content(reply.content(), &event);
+ build_content(reply.related_content(), &related_event, true);
+ build_content(reply.content(), &event, false);
priv_.content.set_child(Some(&reply));
} else {
- build_content(&*priv_.content, &event);
+ build_content(&*priv_.content, &event, false);
}
})
);
} else {
- build_content(&*priv_.content, event);
+ build_content(&*priv_.content, event, false);
}
}
}
@@ -221,7 +221,10 @@ impl Default for MessageRow {
}
/// Build the content widget of `event` as a child of `parent`.
-fn build_content(parent: &adw::Bin, event: &Event) {
+///
+/// If `compact` is true, the content should appear in a smaller format without
+/// interactions, if possible.
+fn build_content(parent: &adw::Bin, event: &Event, compact: bool) {
// TODO: create widgets for all event types
// TODO: display reaction events from event.relates_to()
// TODO: we should reuse the already present child widgets when possible
@@ -267,6 +270,7 @@ fn build_content(parent: &adw::Bin, event: &Event) {
child
};
child.set_filename(Some(filename));
+ child.set_compact(compact);
}
MessageType::Image(message) => {
let child = if let Some(Ok(child)) =
@@ -278,7 +282,7 @@ fn build_content(parent: &adw::Bin, event: &Event) {
parent.set_child(Some(&child));
child
};
- child.image(message, &event.room().session());
+ child.image(message, &event.room().session(), compact);
}
MessageType::Location(_message) => {}
MessageType::Notice(message) => {
@@ -327,7 +331,7 @@ fn build_content(parent: &adw::Bin, event: &Event) {
parent.set_child(Some(&child));
child
};
- child.video(message, &event.room().session());
+ child.video(message, &event.room().session(), compact);
}
MessageType::VerificationRequest(_) => {
// TODO: show more information about the verification
@@ -366,7 +370,7 @@ fn build_content(parent: &adw::Bin, event: &Event) {
parent.set_child(Some(&child));
child
};
- child.sticker(content, &event.room().session());
+ child.sticker(content, &event.room().session(), compact);
}
Some(AnyMessageEventContent::RoomEncrypted(content)) => {
warn!("Couldn't decrypt event {:?}", content);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]