fractal/session/model/room/timeline/
virtual_item.rs1use gtk::{glib, glib::closure_local, prelude::*, subclass::prelude::*};
2use matrix_sdk_ui::timeline::VirtualTimelineItem;
3
4use super::{Timeline, TimelineItem, TimelineItemImpl};
5use crate::utils::matrix::timestamp_to_date;
6
7#[derive(Debug, Default, Clone, Eq, PartialEq)]
9pub(crate) enum VirtualItemKind {
10 #[default]
12 Spinner,
13 Typing,
15 TimelineStart,
17 DayDivider(glib::DateTime),
21 NewMessages,
23}
24
25impl VirtualItemKind {
26 fn with_item(item: &VirtualTimelineItem) -> Self {
28 match item {
29 VirtualTimelineItem::DateDivider(ts) => Self::DayDivider(timestamp_to_date(*ts)),
30 VirtualTimelineItem::ReadMarker => Self::NewMessages,
31 VirtualTimelineItem::TimelineStart => Self::TimelineStart,
32 }
33 }
34}
35
36mod imp {
37 use std::{cell::RefCell, sync::LazyLock};
38
39 use glib::subclass::Signal;
40
41 use super::*;
42
43 #[derive(Debug, Default)]
44 pub struct VirtualItem {
45 kind: RefCell<VirtualItemKind>,
47 }
48
49 #[glib::object_subclass]
50 impl ObjectSubclass for VirtualItem {
51 const NAME: &'static str = "TimelineVirtualItem";
52 type Type = super::VirtualItem;
53 type ParentType = TimelineItem;
54 }
55
56 impl ObjectImpl for VirtualItem {
57 fn signals() -> &'static [Signal] {
58 static SIGNALS: LazyLock<Vec<Signal>> =
59 LazyLock::new(|| vec![Signal::builder("kind-changed").build()]);
60 SIGNALS.as_ref()
61 }
62 }
63
64 impl TimelineItemImpl for VirtualItem {}
65
66 impl VirtualItem {
67 pub(super) fn set_kind(&self, kind: VirtualItemKind) {
69 self.kind.replace(kind);
70 self.obj().emit_by_name::<()>("kind-changed", &[]);
71 }
72
73 pub(super) fn kind(&self) -> VirtualItemKind {
75 self.kind.borrow().clone()
76 }
77 }
78}
79
80glib::wrapper! {
81 pub struct VirtualItem(ObjectSubclass<imp::VirtualItem>) @extends TimelineItem;
85}
86
87impl VirtualItem {
88 fn new(timeline: &Timeline, kind: VirtualItemKind, timeline_id: &str) -> Self {
90 let obj = glib::Object::builder::<Self>()
91 .property("timeline", timeline)
92 .property("timeline-id", timeline_id)
93 .build();
94 obj.imp().set_kind(kind);
95 obj
96 }
97
98 pub(crate) fn with_item(
100 timeline: &Timeline,
101 item: &VirtualTimelineItem,
102 timeline_id: &str,
103 ) -> Self {
104 let kind = VirtualItemKind::with_item(item);
105 Self::new(timeline, kind, timeline_id)
106 }
107
108 pub(crate) fn kind(&self) -> VirtualItemKind {
110 self.imp().kind()
111 }
112
113 pub(crate) fn update_with_item(&self, item: &VirtualTimelineItem) {
115 let kind = VirtualItemKind::with_item(item);
116 self.imp().set_kind(kind);
117 }
118
119 pub(crate) fn spinner(timeline: &Timeline) -> Self {
121 Self::new(
122 timeline,
123 VirtualItemKind::Spinner,
124 "VirtualItemKind::Spinner",
125 )
126 }
127
128 pub(crate) fn typing(timeline: &Timeline) -> Self {
130 Self::new(timeline, VirtualItemKind::Typing, "VirtualItemKind::Typing")
131 }
132
133 pub fn connect_kind_changed<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
135 self.connect_closure(
136 "kind-changed",
137 true,
138 closure_local!(move |obj: Self| {
139 f(&obj);
140 }),
141 )
142 }
143}