Skip to main content

fractal/components/dialogs/auth/
in_browser_page.rs

1use std::fmt::Debug;
2
3use adw::{prelude::*, subclass::prelude::*};
4use gtk::glib;
5use tracing::error;
6
7use crate::components::LoadingButton;
8
9mod imp {
10    use std::cell::OnceCell;
11
12    use glib::subclass::InitializingObject;
13
14    use super::*;
15
16    #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
17    #[template(resource = "/org/gnome/Fractal/ui/components/dialogs/auth/in_browser_page.ui")]
18    #[properties(wrapper_type = super::AuthDialogInBrowserPage)]
19    pub struct AuthDialogInBrowserPage {
20        #[template_child]
21        pub(super) confirm_button: TemplateChild<LoadingButton>,
22        /// The URL to launch.
23        #[property(get, construct_only)]
24        url: OnceCell<String>,
25    }
26
27    #[glib::object_subclass]
28    impl ObjectSubclass for AuthDialogInBrowserPage {
29        const NAME: &'static str = "AuthDialogInBrowserPage";
30        type Type = super::AuthDialogInBrowserPage;
31        type ParentType = adw::Bin;
32
33        fn class_init(klass: &mut Self::Class) {
34            Self::bind_template(klass);
35            Self::bind_template_callbacks(klass);
36        }
37
38        fn instance_init(obj: &InitializingObject<Self>) {
39            obj.init_template();
40        }
41    }
42
43    #[glib::derived_properties]
44    impl ObjectImpl for AuthDialogInBrowserPage {}
45
46    impl WidgetImpl for AuthDialogInBrowserPage {}
47    impl BinImpl for AuthDialogInBrowserPage {}
48
49    #[gtk::template_callbacks]
50    impl AuthDialogInBrowserPage {
51        /// Open the URL in the browser.
52        #[template_callback]
53        async fn launch_url(&self) {
54            let url = self
55                .url
56                .get()
57                .expect("URL should be set during construction");
58
59            if let Err(error) = gtk::UriLauncher::new(url)
60                .launch_future(self.obj().root().and_downcast_ref::<gtk::Window>())
61                .await
62            {
63                error!("Could not launch authentication URI: {error}");
64            }
65
66            self.confirm_button.set_sensitive(true);
67        }
68
69        /// Proceed to authentication with the current password.
70        #[template_callback]
71        fn proceed(&self) {
72            self.confirm_button.set_is_loading(true);
73            let _ = self.obj().activate_action("auth-dialog.continue", None);
74        }
75
76        /// Retry this stage.
77        pub(super) fn retry(&self) {
78            self.confirm_button.set_is_loading(false);
79        }
80    }
81}
82
83glib::wrapper! {
84    /// Page to pass a stage in the browser for the [`AuthDialog`].
85    pub struct AuthDialogInBrowserPage(ObjectSubclass<imp::AuthDialogInBrowserPage>)
86        @extends gtk::Widget, adw::Bin,
87        @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
88}
89
90impl AuthDialogInBrowserPage {
91    /// Construct an `AuthDialogInBrowserPage` that will launch the given URL.
92    pub fn new(url: String) -> Self {
93        glib::Object::builder().property("url", url).build()
94    }
95
96    /// Get the default widget of this page.
97    pub fn default_widget(&self) -> &gtk::Widget {
98        self.imp().confirm_button.upcast_ref()
99    }
100
101    /// Retry this stage.
102    pub fn retry(&self) {
103        self.imp().retry();
104    }
105}