1use adw::{prelude::*, subclass::prelude::*};
2use gettextrs::gettext;
3use gtk::glib;
4
5use crate::{APP_ID, toast};
6
7#[derive(Debug, Clone, Copy, strum::AsRefStr)]
9#[strum(serialize_all = "kebab-case")]
10pub enum ErrorSubpage {
11 Secret,
13 Session,
15}
16
17mod imp {
18 use glib::subclass::InitializingObject;
19
20 use super::*;
21
22 #[derive(Debug, Default, gtk::CompositeTemplate)]
23 #[template(resource = "/org/gnome/Fractal/ui/error_page.ui")]
24 pub struct ErrorPage {
25 #[template_child]
26 stack: TemplateChild<gtk::Stack>,
27 #[template_child]
28 secret_error_page: TemplateChild<adw::StatusPage>,
29 #[template_child]
30 linux_secret_instructions: TemplateChild<adw::Clamp>,
31 #[template_child]
32 secret_service_override_command: TemplateChild<gtk::Label>,
33 #[template_child]
34 session_error_page: TemplateChild<adw::StatusPage>,
35 }
36
37 #[glib::object_subclass]
38 impl ObjectSubclass for ErrorPage {
39 const NAME: &'static str = "ErrorPage";
40 type Type = super::ErrorPage;
41 type ParentType = adw::Bin;
42
43 fn class_init(klass: &mut Self::Class) {
44 Self::bind_template(klass);
45 Self::bind_template_callbacks(klass);
46
47 klass.set_accessible_role(gtk::AccessibleRole::Group);
48 }
49
50 fn instance_init(obj: &InitializingObject<Self>) {
51 obj.init_template();
52 }
53 }
54
55 impl ObjectImpl for ErrorPage {}
56 impl WidgetImpl for ErrorPage {}
57 impl BinImpl for ErrorPage {}
58
59 #[gtk::template_callbacks]
60 impl ErrorPage {
61 pub(super) fn display_secret_error(&self, message: &str) {
63 #[cfg(not(target_os = "linux"))]
64 self.linux_secret_instructions.set_visible(false);
65
66 #[cfg(target_os = "linux")]
67 {
68 self.linux_secret_instructions.set_visible(true);
69
70 self.secret_service_override_command.set_markup(&format!(
71 "<tt>flatpak --user override --talk-name=org.freedesktop.secrets {APP_ID}</tt>",
72 ));
73 }
74
75 self.secret_error_page.set_description(Some(message));
76 self.stack
77 .set_visible_child_name(ErrorSubpage::Secret.as_ref());
78 }
79
80 pub(super) fn display_session_error(&self, message: &str) {
82 self.session_error_page.set_description(Some(message));
83 self.stack
84 .set_visible_child_name(ErrorSubpage::Session.as_ref());
85 }
86
87 #[template_callback]
89 fn copy_secret_service_override_command(&self) {
90 let obj = self.obj();
91 let command = self.secret_service_override_command.label();
92 obj.clipboard()
93 .set_text(command.trim_start_matches("<tt>").trim_end_matches("</tt>"));
94 toast!(obj, gettext("Command copied to clipboard"));
95 }
96 }
97}
98
99glib::wrapper! {
100 pub struct ErrorPage(ObjectSubclass<imp::ErrorPage>)
102 @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
103}
104
105impl ErrorPage {
106 pub fn new() -> Self {
107 glib::Object::new()
108 }
109
110 pub(crate) fn display_secret_error(&self, message: &str) {
112 self.imp().display_secret_error(message);
113 }
114
115 pub(crate) fn display_session_error(&self, message: &str) {
117 self.imp().display_session_error(message);
118 }
119}