[fractal/fractal-next] room-history: Handle room upgrades
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] room-history: Handle room upgrades
- Date: Wed, 1 Dec 2021 14:57:33 +0000 (UTC)
commit b068be5daef17b2d13a5c27bbc8b25172cd3d31a
Author: Julian Sparber <julian sparber net>
Date: Tue Nov 30 16:30:24 2021 +0100
room-history: Handle room upgrades
This adds a better widget for creation and tombstone events to the
room-history and shows buttons to allow users to navigate between
different version of a room.
data/resources/resources.gresource.xml | 2 +
data/resources/ui/content-state-creation.ui | 26 ++++++++
data/resources/ui/content-state-tombstone.ui | 26 ++++++++
po/POTFILES.in | 1 +
src/meson.build | 4 +-
.../content/room_history/state_row/creation.rs | 71 ++++++++++++++++++++
.../{state_row.rs => state_row/mod.rs} | 78 +++++++++++++++-------
.../content/room_history/state_row/tombstone.rs | 55 +++++++++++++++
8 files changed, 239 insertions(+), 24 deletions(-)
---
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index bfb305e4..8dd8a9e9 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -17,6 +17,8 @@
<file compressed="true" preprocess="xml-stripblanks"
alias="content-divider-row.ui">ui/content-divider-row.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="content-room-details.ui">ui/content-room-details.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="content-state-row.ui">ui/content-state-row.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks"
alias="content-state-tombstone.ui">ui/content-state-tombstone.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks"
alias="content-state-creation.ui">ui/content-state-creation.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="content-markdown-popover.ui">ui/content-markdown-popover.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="content-invite.ui">ui/content-invite.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="event-menu.ui">ui/event-menu.ui</file>
diff --git a/data/resources/ui/content-state-creation.ui b/data/resources/ui/content-state-creation.ui
new file mode 100644
index 00000000..17fc782b
--- /dev/null
+++ b/data/resources/ui/content-state-creation.ui
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ContentStateCreation" parent="AdwBin">
+ <property name="focusable">True</property>
+ <property name="valign">center</property>
+ <property name="halign">center</property>
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="description">
+ <property name="wrap">True</property>
+ <property name="wrap-mode">word-char</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="previous_room_btn">
+ <property name="action-name">session.show-room</property>
+ <property name="label" translatable="yes">Previous room</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+
diff --git a/data/resources/ui/content-state-tombstone.ui b/data/resources/ui/content-state-tombstone.ui
new file mode 100644
index 00000000..038522c2
--- /dev/null
+++ b/data/resources/ui/content-state-tombstone.ui
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ContentStateTombstone" parent="AdwBin">
+ <property name="focusable">True</property>
+ <property name="valign">center</property>
+ <property name="halign">center</property>
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="wrap">True</property>
+ <property name="wrap-mode">word-char</property>
+ <property name="label" translatable="yes">This room was upgraded.</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="new_room_btn">
+ <property name="label" translatable="yes">Switch to new Room</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bd618fcd..eabeb42a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -87,6 +87,7 @@ src/session/content/room_history/message_row/mod.rs
src/session/content/room_history/message_row/text.rs
src/session/content/room_history/mod.rs
src/session/content/room_history/state_row.rs
+src/session/content/room_history/state_row/mod.rs
src/session/media_viewer.rs
src/session/mod.rs
src/session/room_creation/mod.rs
diff --git a/src/meson.build b/src/meson.build
index 229e3a88..34e03aff 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -67,7 +67,9 @@ sources = files(
'session/content/room_history/message_row/mod.rs',
'session/content/room_history/message_row/text.rs',
'session/content/room_history/mod.rs',
- 'session/content/room_history/state_row.rs',
+ 'session/content/room_history/state_row/creation.rs',
+ 'session/content/room_history/state_row/mod.rs',
+ 'session/content/room_history/state_row/tombstone.rs',
'session/content/mod.rs',
'session/content/room_details/member_page.rs',
'session/content/room_details/mod.rs',
diff --git a/src/session/content/room_history/state_row/creation.rs
b/src/session/content/room_history/state_row/creation.rs
new file mode 100644
index 00000000..99f9467f
--- /dev/null
+++ b/src/session/content/room_history/state_row/creation.rs
@@ -0,0 +1,71 @@
+use adw::{prelude::*, subclass::prelude::*};
+use gettextrs::gettext;
+use gtk::{glib, subclass::prelude::*, CompositeTemplate};
+
+use matrix_sdk::ruma::events::room::create::RoomCreateEventContent;
+
+mod imp {
+ use super::*;
+ use glib::subclass::InitializingObject;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/FractalNext/content-state-creation.ui")]
+ pub struct StateCreation {
+ #[template_child]
+ pub previous_room_btn: TemplateChild<gtk::Button>,
+ #[template_child]
+ pub description: TemplateChild<gtk::Label>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for StateCreation {
+ const NAME: &'static str = "ContentStateCreation";
+ type Type = super::StateCreation;
+ type ParentType = adw::Bin;
+
+ fn class_init(klass: &mut Self::Class) {
+ Self::bind_template(klass);
+ }
+
+ fn instance_init(obj: &InitializingObject<Self>) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for StateCreation {}
+ impl WidgetImpl for StateCreation {}
+ impl BinImpl for StateCreation {}
+}
+
+glib::wrapper! {
+ pub struct StateCreation(ObjectSubclass<imp::StateCreation>)
+ @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
+}
+
+impl StateCreation {
+ pub fn new(event: &RoomCreateEventContent) -> Self {
+ let obj: Self = glib::Object::new(&[]).expect("Failed to create StateCreation");
+ obj.set_event(event);
+ obj
+ }
+
+ fn set_event(&self, event: &RoomCreateEventContent) {
+ let priv_ = imp::StateCreation::from_instance(self);
+ if let Some(predecessor) = &event.predecessor {
+ priv_.previous_room_btn.set_detailed_action_name(&format!(
+ "session.show-room::{}",
+ predecessor.room_id.as_str()
+ ));
+ priv_.previous_room_btn.show();
+ priv_
+ .description
+ .set_label(&gettext("This is the continuation of an upgraded room."));
+ } else {
+ priv_.previous_room_btn.hide();
+ priv_.previous_room_btn.set_action_name(None);
+ priv_
+ .description
+ .set_label(&gettext("The beginning of this room."));
+ }
+ }
+}
diff --git a/src/session/content/room_history/state_row.rs b/src/session/content/room_history/state_row/mod.rs
similarity index 74%
rename from src/session/content/room_history/state_row.rs
rename to src/session/content/room_history/state_row/mod.rs
index 0fbf711d..3c0803a8 100644
--- a/src/session/content/room_history/state_row.rs
+++ b/src/session/content/room_history/state_row/mod.rs
@@ -1,3 +1,9 @@
+mod creation;
+mod tombstone;
+
+use self::creation::StateCreation;
+use self::tombstone::StateTombstone;
+
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{glib, subclass::prelude::*, CompositeTemplate};
@@ -52,13 +58,16 @@ impl StateRow {
}
pub fn update(&self, state: &AnySyncStateEvent) {
- let _priv_ = imp::StateRow::from_instance(self);
// We may want to show more state events in the future
// For a full list of state events see:
// https://matrix-org.github.io/matrix-rust-sdk/matrix_sdk/events/enum.AnyStateEventContent.html
let message = match state.content() {
- AnyStateEventContent::RoomCreate(_event) => gettext("The beginning of this room."),
- AnyStateEventContent::RoomEncryption(_event) => gettext("This room is now encrypted."),
+ AnyStateEventContent::RoomCreate(event) => {
+ WidgetType::Creation(StateCreation::new(&event))
+ }
+ AnyStateEventContent::RoomEncryption(_event) => {
+ WidgetType::Text(gettext("This room is now encrypted."))
+ }
AnyStateEventContent::RoomMember(event) => {
let display_name = event
.displayname
@@ -108,14 +117,19 @@ impl StateRow {
_ => None,
};
- message.unwrap_or(gettext!("{} joined this room.", display_name))
+ WidgetType::Text(
+ message.unwrap_or(gettext!("{} joined this room.", display_name)),
+ )
}
MembershipState::Invite => {
- gettext!("{} was invited to this room.", display_name)
+ WidgetType::Text(gettext!("{} was invited to this room.", display_name))
}
MembershipState::Knock => {
// TODO: Add button to invite the user.
- gettext!("{} requested to be invited to this room.", display_name)
+ WidgetType::Text(gettext!(
+ "{} requested to be invited to this room.",
+ display_name
+ ))
}
MembershipState::Leave => {
let message = match state.prev_content() {
@@ -136,18 +150,20 @@ impl StateRow {
_ => None,
};
- message.unwrap_or_else(|| {
+ WidgetType::Text(message.unwrap_or_else(|| {
if state.state_key() == state.sender() {
gettext!("{} left the room.", display_name)
} else {
gettext!("{} was kicked out of the room.", display_name)
}
- })
+ }))
+ }
+ MembershipState::Ban => {
+ WidgetType::Text(gettext!("{} was banned.", display_name))
}
- MembershipState::Ban => gettext!("{} was banned.", display_name),
_ => {
warn!("Unsupported room member event: {:?}", state);
- gettext("An unsupported room member event was received.")
+ WidgetType::Text(gettext("An unsupported room member event was received."))
}
}
}
@@ -156,29 +172,45 @@ impl StateRow {
s if s.is_empty() => state.state_key().into(),
s => s,
};
- gettext!("{} was invited to this room.", display_name)
+ WidgetType::Text(gettext!("{} was invited to this room.", display_name))
}
AnyStateEventContent::RoomTombstone(event) => {
- gettext!("The room was upgraded: {}", event.body)
- // Todo: add button for new room with action session.show_room::room_id
+ WidgetType::Tombstone(StateTombstone::new(&event))
}
_ => {
warn!("Unsupported state event: {}", state.event_type());
- gettext("An unsupported state event was received.")
+ WidgetType::Text(gettext("An unsupported state event was received."))
}
};
- if let Some(Ok(child)) = self.child().map(|w| w.downcast::<gtk::Label>()) {
- child.set_text(&message);
- } else {
- let child = gtk::Label::new(Some(&message));
- child.set_css_classes(&["event-content", "dim-label"]);
- child.set_wrap(true);
- child.set_wrap_mode(gtk::pango::WrapMode::WordChar);
- self.set_child(Some(&child));
- };
+
+ match message {
+ WidgetType::Text(message) => {
+ if let Some(Ok(child)) = self.child().map(|w| w.downcast::<gtk::Label>()) {
+ child.set_text(&message);
+ } else {
+ self.set_child(Some(&text(message)));
+ };
+ }
+ WidgetType::Creation(widget) => self.set_child(Some(&widget)),
+ WidgetType::Tombstone(widget) => self.set_child(Some(&widget)),
+ }
}
}
+enum WidgetType {
+ Text(String),
+ Creation(StateCreation),
+ Tombstone(StateTombstone),
+}
+
+fn text(label: String) -> gtk::Label {
+ let child = gtk::Label::new(Some(&label));
+ child.set_css_classes(&["event-content", "dim-label"]);
+ child.set_wrap(true);
+ child.set_wrap_mode(gtk::pango::WrapMode::WordChar);
+ child
+}
+
impl Default for StateRow {
fn default() -> Self {
Self::new()
diff --git a/src/session/content/room_history/state_row/tombstone.rs
b/src/session/content/room_history/state_row/tombstone.rs
new file mode 100644
index 00000000..9574c0a6
--- /dev/null
+++ b/src/session/content/room_history/state_row/tombstone.rs
@@ -0,0 +1,55 @@
+use adw::{prelude::*, subclass::prelude::*};
+use gtk::{glib, subclass::prelude::*, CompositeTemplate};
+use matrix_sdk::ruma::events::room::tombstone::RoomTombstoneEventContent;
+
+mod imp {
+ use super::*;
+ use glib::subclass::InitializingObject;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/FractalNext/content-state-tombstone.ui")]
+ pub struct StateTombstone {
+ #[template_child]
+ pub new_room_btn: TemplateChild<gtk::Button>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for StateTombstone {
+ const NAME: &'static str = "ContentStateTombstone";
+ type Type = super::StateTombstone;
+ type ParentType = adw::Bin;
+
+ fn class_init(klass: &mut Self::Class) {
+ Self::bind_template(klass);
+ }
+
+ fn instance_init(obj: &InitializingObject<Self>) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for StateTombstone {}
+ impl WidgetImpl for StateTombstone {}
+ impl BinImpl for StateTombstone {}
+}
+
+glib::wrapper! {
+ pub struct StateTombstone(ObjectSubclass<imp::StateTombstone>)
+ @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
+}
+
+impl StateTombstone {
+ pub fn new(event: &RoomTombstoneEventContent) -> Self {
+ let obj: Self = glib::Object::new(&[]).expect("Failed to create StateTombstone");
+ obj.set_event(event);
+ obj
+ }
+
+ fn set_event(&self, event: &RoomTombstoneEventContent) {
+ let priv_ = imp::StateTombstone::from_instance(self);
+ priv_.new_room_btn.set_detailed_action_name(&format!(
+ "session.show-room::{}",
+ event.replacement_room.as_str()
+ ));
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]