diff --git a/src/session/room/event/mod.rs b/src/session/room/event/mod.rs index d778c60e..f10ca70a 100644 --- a/src/session/room/event/mod.rs +++ b/src/session/room/event/mod.rs @@ -1,3 +1,5 @@ +use std::fmt; + use gtk::{glib, prelude::*, subclass::prelude::*}; use matrix_sdk::{ media::MediaEventContent, @@ -42,6 +44,15 @@ pub enum EventKey { EventId(OwnedEventId), } +impl fmt::Display for EventKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EventKey::TransactionId(txn_id) => write!(f, "transaction_id:{txn_id}"), + EventKey::EventId(event_id) => write!(f, "event_id:{event_id}"), + } + } +} + #[derive(Clone, Debug, glib::Boxed)] #[boxed_type(name = "BoxedEventTimelineItem")] pub struct BoxedEventTimelineItem(EventTimelineItem); @@ -130,6 +141,10 @@ mod imp { } impl TimelineItemImpl for Event { + fn id(&self) -> String { + format!("Event::{}", self.obj().key()) + } + fn is_visible(&self) -> bool { match self.obj().content() { TimelineItemContent::Message(message) => matches!( diff --git a/src/session/room/timeline/timeline_day_divider.rs b/src/session/room/timeline/timeline_day_divider.rs index d7537993..2fadb0f1 100644 --- a/src/session/room/timeline/timeline_day_divider.rs +++ b/src/session/room/timeline/timeline_day_divider.rs @@ -58,7 +58,17 @@ mod imp { } } - impl TimelineItemImpl for TimelineDayDivider {} + impl TimelineItemImpl for TimelineDayDivider { + fn id(&self) -> String { + format!( + "TimelineDayDivider::{}", + self.obj() + .date() + .map(|d| d.format("%F").unwrap()) + .unwrap_or_default() + ) + } + } } glib::wrapper! { diff --git a/src/session/room/timeline/timeline_item.rs b/src/session/room/timeline/timeline_item.rs index 71b7b5b0..255c47b8 100644 --- a/src/session/room/timeline/timeline_item.rs +++ b/src/session/room/timeline/timeline_item.rs @@ -17,6 +17,7 @@ mod imp { #[repr(C)] pub struct TimelineItemClass { pub parent_class: glib::object::ObjectClass, + pub id: fn(&super::TimelineItem) -> String, pub is_visible: fn(&super::TimelineItem) -> bool, pub selectable: fn(&super::TimelineItem) -> bool, pub can_hide_header: fn(&super::TimelineItem) -> bool, @@ -27,6 +28,11 @@ mod imp { type Type = TimelineItem; } + pub(super) fn timeline_item_id(this: &super::TimelineItem) -> String { + let klass = this.class(); + (klass.as_ref().id)(this) + } + pub(super) fn timeline_item_is_visible(this: &super::TimelineItem) -> bool { let klass = this.class(); (klass.as_ref().is_visible)(this) @@ -161,6 +167,11 @@ impl TimelineItem { /// To override the behavior of these methods, override the corresponding method /// of `TimelineItemImpl`. pub trait TimelineItemExt: 'static { + /// A unique ID for this `TimelineItem`. + /// + /// For debugging purposes. + fn id(&self) -> String; + /// Whether this `TimelineItem` is visible. /// /// Defaults to `true`. @@ -191,6 +202,10 @@ pub trait TimelineItemExt: 'static { } impl> TimelineItemExt for O { + fn id(&self) -> String { + imp::timeline_item_id(self.upcast_ref()) + } + fn is_visible(&self) -> bool { imp::timeline_item_is_visible(self.upcast_ref()) } @@ -229,6 +244,8 @@ impl> TimelineItemExt for O { /// Overriding a method from this Trait overrides also its behavior in /// `TimelineItemExt`. pub trait TimelineItemImpl: ObjectImpl { + fn id(&self) -> String; + fn is_visible(&self) -> bool { true } @@ -257,6 +274,7 @@ where let klass = class.as_mut(); + klass.id = id_trampoline::; klass.is_visible = is_visible_trampoline::; klass.selectable = selectable_trampoline::; klass.can_hide_header = can_hide_header_trampoline::; @@ -265,6 +283,15 @@ where } // Virtual method implementation trampolines. +fn id_trampoline(this: &TimelineItem) -> String +where + T: ObjectSubclass + TimelineItemImpl, + T::Type: IsA, +{ + let this = this.downcast_ref::().unwrap(); + this.imp().id() +} + fn is_visible_trampoline(this: &TimelineItem) -> bool where T: ObjectSubclass + TimelineItemImpl, diff --git a/src/session/room/timeline/timeline_new_messages_divider.rs b/src/session/room/timeline/timeline_new_messages_divider.rs index 2d7d3502..baf106da 100644 --- a/src/session/room/timeline/timeline_new_messages_divider.rs +++ b/src/session/room/timeline/timeline_new_messages_divider.rs @@ -16,7 +16,12 @@ mod imp { } impl ObjectImpl for TimelineNewMessagesDivider {} - impl TimelineItemImpl for TimelineNewMessagesDivider {} + + impl TimelineItemImpl for TimelineNewMessagesDivider { + fn id(&self) -> String { + "TimelineNewMessagesDivider".to_owned() + } + } } glib::wrapper! { diff --git a/src/session/room/timeline/timeline_placeholder.rs b/src/session/room/timeline/timeline_placeholder.rs index 9ffd2b64..563c66df 100644 --- a/src/session/room/timeline/timeline_placeholder.rs +++ b/src/session/room/timeline/timeline_placeholder.rs @@ -58,7 +58,16 @@ mod imp { } } - impl TimelineItemImpl for TimelinePlaceholder {} + impl TimelineItemImpl for TimelinePlaceholder { + fn id(&self) -> String { + match self.obj().kind() { + PlaceholderKind::Spinner => "TimelinePlaceholder::Spinner", + PlaceholderKind::Typing => "TimelinePlaceholder::Typing", + PlaceholderKind::TimelineStart => "TimelinePlaceholder::TimelineStart", + } + .to_owned() + } + } } glib::wrapper! {