fractal/session/view/content/room_history/
divider_row.rs

1use adw::{prelude::*, subclass::prelude::*};
2use gettextrs::gettext;
3use gtk::{glib, glib::clone, CompositeTemplate};
4
5use crate::{
6    session::model::{VirtualItem, VirtualItemKind},
7    utils::BoundObject,
8};
9
10mod imp {
11    use glib::subclass::InitializingObject;
12
13    use super::*;
14
15    #[derive(Debug, Default, CompositeTemplate, glib::Properties)]
16    #[template(resource = "/org/gnome/Fractal/ui/session/view/content/room_history/divider_row.ui")]
17    #[properties(wrapper_type = super::DividerRow)]
18    pub struct DividerRow {
19        #[template_child]
20        inner_label: TemplateChild<gtk::Label>,
21        /// The virtual item presented by this row.
22        #[property(get, set = Self::set_virtual_item, explicit_notify, nullable)]
23        virtual_item: BoundObject<VirtualItem>,
24    }
25
26    #[glib::object_subclass]
27    impl ObjectSubclass for DividerRow {
28        const NAME: &'static str = "ContentDividerRow";
29        type Type = super::DividerRow;
30        type ParentType = adw::Bin;
31
32        fn class_init(klass: &mut Self::Class) {
33            Self::bind_template(klass);
34
35            klass.set_css_name("divider-row");
36            klass.set_accessible_role(gtk::AccessibleRole::ListItem);
37        }
38
39        fn instance_init(obj: &InitializingObject<Self>) {
40            obj.init_template();
41        }
42    }
43
44    #[glib::derived_properties]
45    impl ObjectImpl for DividerRow {}
46
47    impl WidgetImpl for DividerRow {}
48    impl BinImpl for DividerRow {}
49
50    impl DividerRow {
51        /// Set the virtual item presented by this row.
52        fn set_virtual_item(&self, virtual_item: Option<VirtualItem>) {
53            if self.virtual_item.obj() == virtual_item {
54                return;
55            }
56
57            self.virtual_item.disconnect_signals();
58
59            if let Some(virtual_item) = virtual_item {
60                let kind_handler = virtual_item.connect_kind_changed(clone!(
61                    #[weak(rename_to = imp)]
62                    self,
63                    move |_| {
64                        imp.update();
65                    }
66                ));
67
68                self.virtual_item.set(virtual_item, vec![kind_handler]);
69            }
70
71            self.update();
72            self.obj().notify_virtual_item();
73        }
74
75        /// Update this row for the current kind.
76        ///
77        /// Panics if the kind is not `TimelineStart`, `DayDivider` or
78        /// `NewMessages`.
79        fn update(&self) {
80            let Some(kind) = self
81                .virtual_item
82                .obj()
83                .map(|virtual_item| virtual_item.kind())
84            else {
85                return;
86            };
87
88            let label = match &kind {
89                VirtualItemKind::TimelineStart => {
90                    gettext("This is the start of the visible history")
91                }
92                VirtualItemKind::DayDivider(date) => {
93                    let fmt = if date.year()
94                        == glib::DateTime::now_local()
95                            .expect("we should be able to get the local datetime")
96                            .year()
97                    {
98                        // Translators: This is a date format in the day divider without the
99                        // year. For example, "Friday, May 5".
100                        // Please use `-` before specifiers that add spaces on single
101                        // digits. See `man strftime` or the documentation of g_date_time_format for the available specifiers: <https://docs.gtk.org/glib/method.DateTime.format.html>
102                        gettext("%A, %B %-e")
103                    } else {
104                        // Translators: This is a date format in the day divider with the
105                        // year. For ex. "Friday, May 5, 2023".
106                        // Please use `-` before specifiers that add spaces on single
107                        // digits. See `man strftime` or the documentation of g_date_time_format for the available specifiers: <https://docs.gtk.org/glib/method.DateTime.format.html>
108                        gettext("%A, %B %-e, %Y")
109                    };
110
111                    date.format(&fmt)
112                        .expect("we should be able to format the datetime")
113                        .into()
114                }
115                VirtualItemKind::NewMessages => gettext("New Messages"),
116                _ => unimplemented!(),
117            };
118
119            let obj = self.obj();
120            if matches!(kind, VirtualItemKind::NewMessages) {
121                obj.add_css_class("new-messages");
122            } else {
123                obj.remove_css_class("new-messages");
124            }
125
126            self.inner_label.set_label(&label);
127        }
128    }
129}
130
131glib::wrapper! {
132    /// A row presenting a divider in the timeline.
133    pub struct DividerRow(ObjectSubclass<imp::DividerRow>)
134        @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
135}
136
137impl DividerRow {
138    pub fn new() -> Self {
139        glib::Object::new()
140    }
141}
142
143impl Default for DividerRow {
144    fn default() -> Self {
145        Self::new()
146    }
147}