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