From d248af475c75e609e6d36a4ccdd5a390917a2e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Tue, 2 May 2023 16:49:05 +0200 Subject: [PATCH] room-history: Allow to join or view the successor in a tombstone event --- data/resources/ui/content-state-tombstone.ui | 2 +- po/POTFILES.in | 1 + .../content/room_history/state_row/mod.rs | 8 +- .../room_history/state_row/tombstone.rs | 117 +++++++++++++++--- 4 files changed, 103 insertions(+), 25 deletions(-) diff --git a/data/resources/ui/content-state-tombstone.ui b/data/resources/ui/content-state-tombstone.ui index 2096b79c..494e7db4 100644 --- a/data/resources/ui/content-state-tombstone.ui +++ b/data/resources/ui/content-state-tombstone.ui @@ -16,7 +16,7 @@ - View + diff --git a/po/POTFILES.in b/po/POTFILES.in index 92c6e09b..b0569198 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -81,6 +81,7 @@ src/session/content/room_history/message_row/media.rs src/session/content/room_history/mod.rs src/session/content/room_history/state_row/creation.rs src/session/content/room_history/state_row/mod.rs +src/session/content/room_history/state_row/tombstone.rs src/session/content/room_history/typing_row.rs src/session/content/room_history/verification_info_bar.rs src/session/content/verification/identity_verification_widget.rs diff --git a/src/session/content/room_history/state_row/mod.rs b/src/session/content/room_history/state_row/mod.rs index dc1ba295..66589b17 100644 --- a/src/session/content/room_history/state_row/mod.rs +++ b/src/session/content/room_history/state_row/mod.rs @@ -77,7 +77,7 @@ impl StateRow { self.update_with_profile_change(&profile_change, &event.sender().display_name()) } TimelineItemContent::OtherState(other_state) => { - self.update_with_other_state(&other_state) + self.update_with_other_state(event, &other_state) } _ => unreachable!(), } @@ -85,7 +85,7 @@ impl StateRow { self.imp().read_receipts.set_list(event.read_receipts()); } - fn update_with_other_state(&self, other_state: &OtherState) { + fn update_with_other_state(&self, event: &Event, other_state: &OtherState) { let widget = match other_state.content() { AnyOtherFullStateEventContent::RoomCreate(content) => { WidgetType::Creation(StateCreation::new(content)) @@ -110,8 +110,8 @@ impl StateRow { &[("user", display_name)], )) } - AnyOtherFullStateEventContent::RoomTombstone(content) => { - WidgetType::Tombstone(StateTombstone::new(content)) + AnyOtherFullStateEventContent::RoomTombstone(_) => { + WidgetType::Tombstone(StateTombstone::new(&event.room())) } _ => { warn!( diff --git a/src/session/content/room_history/state_row/tombstone.rs b/src/session/content/room_history/state_row/tombstone.rs index 5d68dc76..087b46a4 100644 --- a/src/session/content/room_history/state_row/tombstone.rs +++ b/src/session/content/room_history/state_row/tombstone.rs @@ -1,10 +1,12 @@ use adw::{prelude::*, subclass::prelude::*}; -use gtk::{glib, CompositeTemplate}; -use matrix_sdk::ruma::events::room::tombstone::RoomTombstoneEventContent; -use ruma::events::FullStateEventContent; +use gettextrs::gettext; +use gtk::{glib, glib::clone, CompositeTemplate}; + +use crate::{session::Room, utils::BoundObjectWeakRef}; mod imp { use glib::subclass::InitializingObject; + use once_cell::sync::Lazy; use super::*; @@ -13,6 +15,8 @@ mod imp { pub struct StateTombstone { #[template_child] pub new_room_btn: TemplateChild, + /// The [`Room`] this event belongs to. + pub room: BoundObjectWeakRef, } #[glib::object_subclass] @@ -23,6 +27,7 @@ mod imp { fn class_init(klass: &mut Self::Class) { Self::bind_template(klass); + Self::Type::bind_template_callbacks(klass); } fn instance_init(obj: &InitializingObject) { @@ -30,7 +35,40 @@ mod imp { } } - impl ObjectImpl for StateTombstone {} + impl ObjectImpl for StateTombstone { + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy> = Lazy::new(|| { + vec![glib::ParamSpecObject::builder::("room") + .construct_only() + .build()] + }); + + PROPERTIES.as_ref() + } + + fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { + let obj = self.obj(); + + match pspec.name() { + "room" => obj.set_room(value.get().unwrap()), + _ => unimplemented!(), + } + } + + fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + let obj = self.obj(); + + match pspec.name() { + "room" => obj.room().to_value(), + _ => unimplemented!(), + } + } + + fn dispose(&self) { + self.room.disconnect_signals(); + } + } + impl WidgetImpl for StateTombstone {} impl BinImpl for StateTombstone {} } @@ -40,25 +78,64 @@ glib::wrapper! { @extends gtk::Widget, adw::Bin, @implements gtk::Accessible; } +#[gtk::template_callbacks] impl StateTombstone { - pub fn new(event: &FullStateEventContent) -> Self { - let obj: Self = glib::Object::new(); - obj.set_event(event); - obj + /// Construct a new `StateTombstone` with the given room. + pub fn new(room: &Room) -> Self { + glib::Object::builder().property("room", room).build() } - fn set_event(&self, event: &FullStateEventContent) { - let new_room_btn = &self.imp().new_room_btn; - let btn_visible = match event { - FullStateEventContent::Original { content, .. } => { - new_room_btn.set_detailed_action_name(&format!( - "session.show-room::{}", - content.replacement_room - )); - true - } - FullStateEventContent::Redacted(_) => false, + /// Set the room this event belongs to. + fn set_room(&self, room: Room) { + let imp = self.imp(); + + let successor_handler = room.connect_notify_local( + Some("successor"), + clone!(@weak self as obj => move |room, _| { + obj.imp().new_room_btn.set_visible(room.successor().is_some()); + }), + ); + imp.new_room_btn.set_visible(room.successor().is_some()); + + let successor_room_handler = room.connect_notify_local( + Some("successor-room"), + clone!(@weak self as obj => move |room, _| { + obj.update_button_label(room); + }), + ); + self.update_button_label(&room); + + imp.room + .set(&room, vec![successor_handler, successor_room_handler]); + } + + /// The room this event belongs to. + pub fn room(&self) -> Option { + self.imp().room.obj() + } + + /// Update the button of the label. + fn update_button_label(&self, room: &Room) { + let button = &self.imp().new_room_btn; + if room.successor_room().is_some() { + button.set_label(&gettext("View")); + } else { + button.set_label(&gettext("Join")); + } + } + + /// Join or view the successor of this event's room. + #[template_callback] + fn join_or_view_successor(&self) { + let Some(room) = self.room() else { + return; }; - new_room_btn.set_visible(btn_visible); + let Some(successor) = room.successor() else { + return; + }; + + room.session() + .room_list() + .join_or_view(successor.into(), vec![]); } }