Skip to main content

fractal/components/dialogs/
user_profile.rs

1use adw::{prelude::*, subclass::prelude::*};
2use gtk::{glib, glib::clone};
3use ruma::OwnedUserId;
4
5use super::ToastableDialog;
6use crate::{
7    components::UserPage,
8    prelude::*,
9    session::{Member, Session, User},
10    utils::LoadingState,
11};
12
13mod imp {
14    use std::cell::RefCell;
15
16    use glib::subclass::InitializingObject;
17
18    use super::*;
19
20    #[derive(Debug, Default, gtk::CompositeTemplate)]
21    #[template(resource = "/org/gnome/Fractal/ui/components/dialogs/user_profile.ui")]
22    pub struct UserProfileDialog {
23        #[template_child]
24        stack: TemplateChild<gtk::Stack>,
25        #[template_child]
26        user_page: TemplateChild<UserPage>,
27        user_loading_handler: RefCell<Option<glib::SignalHandlerId>>,
28    }
29
30    #[glib::object_subclass]
31    impl ObjectSubclass for UserProfileDialog {
32        const NAME: &'static str = "UserProfileDialog";
33        type Type = super::UserProfileDialog;
34        type ParentType = ToastableDialog;
35
36        fn class_init(klass: &mut Self::Class) {
37            Self::bind_template(klass);
38        }
39
40        fn instance_init(obj: &InitializingObject<Self>) {
41            obj.init_template();
42        }
43    }
44
45    impl ObjectImpl for UserProfileDialog {
46        fn dispose(&self) {
47            self.reset();
48        }
49    }
50
51    impl WidgetImpl for UserProfileDialog {}
52    impl AdwDialogImpl for UserProfileDialog {}
53    impl ToastableDialogImpl for UserProfileDialog {}
54
55    impl UserProfileDialog {
56        /// Show the details page.
57        fn show_details(&self) {
58            self.stack.set_visible_child_name("details");
59        }
60
61        /// Load the user with the given session and user ID.
62        pub(super) fn load_user(&self, session: &Session, user_id: OwnedUserId) {
63            self.reset();
64
65            let user = session.remote_cache().user(user_id);
66            self.user_page.set_user(Some(user.clone()));
67
68            if matches!(
69                user.loading_state(),
70                LoadingState::Initial | LoadingState::Loading
71            ) {
72                let user_loading_handler = user.connect_loading_state_notify(clone!(
73                    #[weak(rename_to = imp)]
74                    self,
75                    move |user| {
76                        if !matches!(
77                            user.loading_state(),
78                            LoadingState::Initial | LoadingState::Loading
79                        ) && let Some(handler) = imp.user_loading_handler.take()
80                        {
81                            user.disconnect(handler);
82                            imp.show_details();
83                        }
84                    }
85                ));
86                self.user_loading_handler
87                    .replace(Some(user_loading_handler));
88            } else {
89                self.show_details();
90            }
91        }
92
93        /// Set the member to present.
94        pub(super) fn set_room_member(&self, member: Member) {
95            self.reset();
96
97            self.user_page.set_user(Some(member.upcast::<User>()));
98            self.show_details();
99        }
100
101        /// Reset this dialog.
102        fn reset(&self) {
103            if let Some(handler) = self.user_loading_handler.take()
104                && let Some(user) = self.user_page.user()
105            {
106                user.disconnect(handler);
107            }
108        }
109    }
110}
111
112glib::wrapper! {
113    /// Dialog to view a user's profile.
114    pub struct UserProfileDialog(ObjectSubclass<imp::UserProfileDialog>)
115        @extends gtk::Widget, adw::Dialog, ToastableDialog,
116        @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::ShortcutManager;
117}
118
119impl UserProfileDialog {
120    /// Create a new `UserProfileDialog`.
121    pub fn new() -> Self {
122        glib::Object::new()
123    }
124
125    /// Load the user with the given session and user ID.
126    pub(crate) fn load_user(&self, session: &Session, user_id: OwnedUserId) {
127        self.imp().load_user(session, user_id);
128    }
129
130    /// Set the member to present.
131    pub(crate) fn set_room_member(&self, member: Member) {
132        self.imp().set_room_member(member);
133    }
134}