fractal/session/model/room/timeline/
timeline_item.rs1use gtk::{glib, prelude::*, subclass::prelude::*};
2use matrix_sdk_ui::timeline::{TimelineItem as SdkTimelineItem, TimelineItemKind};
3use tracing::error;
4
5use super::{Event, Timeline, VirtualItem};
6use crate::session::model::Room;
7
8mod imp {
9 use std::cell::{OnceCell, RefCell};
10
11 use super::*;
12
13 #[repr(C)]
14 pub struct TimelineItemClass {
15 parent_class: glib::object::ObjectClass,
16 }
17
18 unsafe impl ClassStruct for TimelineItemClass {
19 type Type = TimelineItem;
20 }
21
22 #[derive(Debug, Default, glib::Properties)]
23 #[properties(wrapper_type = super::TimelineItem)]
24 pub struct TimelineItem {
25 #[property(get, construct_only)]
27 timeline: OnceCell<Timeline>,
28 #[property(get, construct_only)]
30 timeline_id: RefCell<String>,
31 }
32
33 #[glib::object_subclass]
34 impl ObjectSubclass for TimelineItem {
35 const NAME: &'static str = "TimelineItem";
36 const ABSTRACT: bool = true;
37 type Type = super::TimelineItem;
38 type Class = TimelineItemClass;
39 }
40
41 #[glib::derived_properties]
42 impl ObjectImpl for TimelineItem {}
43}
44
45glib::wrapper! {
46 pub struct TimelineItem(ObjectSubclass<imp::TimelineItem>);
48}
49
50impl TimelineItem {
51 pub fn new(item: &SdkTimelineItem, timeline: &Timeline) -> Self {
55 let timeline_id = &item.unique_id().0;
56
57 match item.kind() {
58 TimelineItemKind::Event(event_item) => {
59 Event::new(timeline, event_item.clone(), timeline_id).upcast()
60 }
61 TimelineItemKind::Virtual(virtual_item) => {
62 VirtualItem::with_item(timeline, virtual_item, timeline_id).upcast()
63 }
64 }
65 }
66
67 pub(crate) fn update_with(&self, item: &SdkTimelineItem) {
72 if self.timeline_id() != item.unique_id().0 {
73 error!("Should not update an item with a different timeline ID");
74 }
75
76 match item.kind() {
77 TimelineItemKind::Event(new_event) => {
78 if let Some(event) = self.downcast_ref::<Event>() {
79 event.update_with(new_event.clone());
80 } else {
81 error!("Could not update a TimelineItem that is not an Event with an event SDK item");
82 }
83 }
84 TimelineItemKind::Virtual(new_item) => {
85 if let Some(virtual_item) = self.downcast_ref::<VirtualItem>() {
86 virtual_item.update_with_item(new_item);
87 } else {
88 error!("Could not update a TimelineItem that is not a VirtualItem with a virtual SDK item");
89 }
90 }
91 }
92 }
93}
94
95#[allow(dead_code)]
101pub(crate) trait TimelineItemExt: 'static {
102 fn timeline(&self) -> Timeline;
104
105 fn room(&self) -> Room {
107 self.timeline().room()
108 }
109
110 fn timeline_id(&self) -> String;
112}
113
114impl<O: IsA<TimelineItem>> TimelineItemExt for O {
115 fn timeline(&self) -> Timeline {
116 self.upcast_ref().timeline()
117 }
118
119 fn timeline_id(&self) -> String {
120 self.upcast_ref().timeline_id()
121 }
122}
123
124pub(crate) trait TimelineItemImpl: ObjectImpl {}
130
131unsafe impl<T> IsSubclassable<T> for TimelineItem
133where
134 T: TimelineItemImpl,
135 T::Type: IsA<TimelineItem>,
136{
137 fn class_init(class: &mut glib::Class<Self>) {
138 Self::parent_class_init::<T>(class.upcast_ref_mut());
139 }
140}