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 @@
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![]);
}
}