fractal/session/view/content/room_history/message_row/reaction/
reaction_popover.rs

1use adw::{prelude::*, subclass::prelude::*};
2use gtk::{
3    gio,
4    glib::{self, clone},
5    CompositeTemplate,
6};
7
8use crate::{
9    components::UserProfileDialog,
10    session::view::content::room_history::member_timestamp::{
11        row::MemberTimestampRow, MemberTimestamp,
12    },
13};
14
15mod imp {
16    use glib::subclass::InitializingObject;
17
18    use super::*;
19
20    #[derive(Debug, Default, CompositeTemplate, glib::Properties)]
21    #[template(
22        resource = "/org/gnome/Fractal/ui/session/view/content/room_history/message_row/reaction/reaction_popover.ui"
23    )]
24    #[properties(wrapper_type = super::ReactionPopover)]
25    pub struct ReactionPopover {
26        #[template_child]
27        list: TemplateChild<gtk::ListView>,
28        /// The reaction senders to display.
29        #[property(get, set = Self::set_senders, construct_only)]
30        senders: glib::WeakRef<gio::ListStore>,
31    }
32
33    #[glib::object_subclass]
34    impl ObjectSubclass for ReactionPopover {
35        const NAME: &'static str = "ContentMessageReactionPopover";
36        type Type = super::ReactionPopover;
37        type ParentType = gtk::Popover;
38
39        fn class_init(klass: &mut Self::Class) {
40            MemberTimestampRow::ensure_type();
41
42            Self::bind_template(klass);
43        }
44
45        fn instance_init(obj: &InitializingObject<Self>) {
46            obj.init_template();
47        }
48    }
49
50    #[glib::derived_properties]
51    impl ObjectImpl for ReactionPopover {}
52
53    impl WidgetImpl for ReactionPopover {}
54    impl PopoverImpl for ReactionPopover {}
55
56    impl ReactionPopover {
57        /// Set the reaction senders to display.
58        fn set_senders(&self, senders: gio::ListStore) {
59            self.senders.set(Some(&senders));
60            self.list
61                .set_model(Some(&gtk::NoSelection::new(Some(senders))));
62            self.list.connect_activate(clone!(
63                #[weak(rename_to = imp)]
64                self,
65                move |_, pos| {
66                    let Some(member) = imp
67                        .senders
68                        .upgrade()
69                        .and_then(|list| list.item(pos))
70                        .and_downcast::<MemberTimestamp>()
71                        .and_then(|ts| ts.member())
72                    else {
73                        return;
74                    };
75
76                    let obj = imp.obj();
77
78                    let dialog = UserProfileDialog::new();
79                    dialog.set_room_member(member);
80                    dialog.present(Some(&*obj));
81
82                    obj.popdown();
83                }
84            ));
85        }
86    }
87}
88
89glib::wrapper! {
90    /// A popover to display the senders of a reaction.
91    pub struct ReactionPopover(ObjectSubclass<imp::ReactionPopover>)
92        @extends gtk::Widget, gtk::Popover;
93}
94
95impl ReactionPopover {
96    /// Constructs a new `ReactionPopover` with the given reaction senders.
97    pub fn new(senders: &gio::ListStore) -> Self {
98        glib::Object::builder().property("senders", senders).build()
99    }
100}