fractal/account_chooser_dialog/
mod.rs1use adw::{prelude::*, subclass::prelude::*};
2use gtk::glib;
3
4mod account_row;
5
6use self::account_row::AccountRow;
7use crate::{
8 session_list::{SessionInfo, SessionList},
9 utils::OneshotNotifier,
10};
11
12mod imp {
13 use std::cell::OnceCell;
14
15 use glib::subclass::InitializingObject;
16
17 use super::*;
18
19 #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
20 #[template(resource = "/org/gnome/Fractal/ui/account_chooser_dialog/mod.ui")]
21 #[properties(wrapper_type = super::AccountChooserDialog)]
22 pub struct AccountChooserDialog {
23 #[template_child]
24 pub accounts: TemplateChild<gtk::ListBox>,
25 #[property(get, set = Self::set_session_list, construct)]
27 pub session_list: glib::WeakRef<SessionList>,
28 notifier: OnceCell<OneshotNotifier<Option<String>>>,
29 }
30
31 #[glib::object_subclass]
32 impl ObjectSubclass for AccountChooserDialog {
33 const NAME: &'static str = "AccountChooserDialog";
34 type Type = super::AccountChooserDialog;
35 type ParentType = adw::Dialog;
36
37 fn class_init(klass: &mut Self::Class) {
38 Self::bind_template(klass);
39 Self::Type::bind_template_callbacks(klass);
40 }
41
42 fn instance_init(obj: &InitializingObject<Self>) {
43 obj.init_template();
44 }
45 }
46
47 #[glib::derived_properties]
48 impl ObjectImpl for AccountChooserDialog {}
49
50 impl WidgetImpl for AccountChooserDialog {}
51
52 impl AdwDialogImpl for AccountChooserDialog {
53 fn closed(&self) {
54 if let Some(notifier) = self.notifier.get() {
55 notifier.notify();
56 }
57 }
58 }
59
60 impl AccountChooserDialog {
61 pub(super) fn notifier(&self) -> &OneshotNotifier<Option<String>> {
63 self.notifier
64 .get_or_init(|| OneshotNotifier::new("AccountChooserDialog"))
65 }
66
67 fn set_session_list(&self, session_list: &SessionList) {
69 self.accounts.bind_model(Some(session_list), |session| {
70 let row = AccountRow::new(session.downcast_ref().unwrap());
71 row.upcast()
72 });
73
74 self.session_list.set(Some(session_list));
75 }
76 }
77}
78
79glib::wrapper! {
80 pub struct AccountChooserDialog(ObjectSubclass<imp::AccountChooserDialog>)
84 @extends gtk::Widget, adw::Dialog,
85 @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::ShortcutManager;
86}
87
88#[gtk::template_callbacks]
89impl AccountChooserDialog {
90 pub fn new(session_list: &SessionList) -> Self {
91 glib::Object::builder()
92 .property("session-list", session_list)
93 .build()
94 }
95
96 pub async fn choose_account(&self, parent: &impl IsA<gtk::Widget>) -> Option<String> {
98 let receiver = self.imp().notifier().listen();
99
100 self.present(Some(parent));
101
102 receiver.await
103 }
104
105 #[template_callback]
107 fn select_row(&self, row: >k::ListBoxRow) {
108 let index = row
109 .index()
110 .try_into()
111 .expect("selected row should have an index");
112
113 let session_id = self
114 .session_list()
115 .and_then(|l| l.item(index))
116 .and_downcast::<SessionInfo>()
117 .map(|s| s.session_id());
118
119 self.imp().notifier().notify_value(session_id);
120 self.close();
121 }
122}