fractal/identity_verification_view/
no_supported_methods_page.rs1use adw::{prelude::*, subclass::prelude::*};
2use gettextrs::gettext;
3use gtk::{glib, glib::clone};
4
5use crate::{
6 components::LoadingButton, gettext_f, prelude::*, session::IdentityVerification, toast,
7 utils::BoundObjectWeakRef,
8};
9
10mod imp {
11 use std::cell::RefCell;
12
13 use glib::subclass::InitializingObject;
14
15 use super::*;
16
17 #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
18 #[template(
19 resource = "/org/gnome/Fractal/ui/identity_verification_view/no_supported_methods_page.ui"
20 )]
21 #[properties(wrapper_type = super::NoSupportedMethodsPage)]
22 pub struct NoSupportedMethodsPage {
23 #[property(get, set = Self::set_verification, explicit_notify, nullable)]
25 pub verification: BoundObjectWeakRef<IdentityVerification>,
26 pub display_name_handler: RefCell<Option<glib::SignalHandlerId>>,
27 #[template_child]
28 pub message: TemplateChild<gtk::Label>,
29 #[template_child]
30 pub instructions: TemplateChild<gtk::Label>,
31 #[template_child]
32 pub cancel_btn: TemplateChild<LoadingButton>,
33 }
34
35 #[glib::object_subclass]
36 impl ObjectSubclass for NoSupportedMethodsPage {
37 const NAME: &'static str = "IdentityVerificationNoSupportedMethodsPage";
38 type Type = super::NoSupportedMethodsPage;
39 type ParentType = adw::Bin;
40
41 fn class_init(klass: &mut Self::Class) {
42 Self::bind_template(klass);
43 Self::Type::bind_template_callbacks(klass);
44 }
45
46 fn instance_init(obj: &InitializingObject<Self>) {
47 obj.init_template();
48 }
49 }
50
51 #[glib::derived_properties]
52 impl ObjectImpl for NoSupportedMethodsPage {
53 fn dispose(&self) {
54 if let Some(verification) = self.verification.obj()
55 && let Some(handler) = self.display_name_handler.take()
56 {
57 verification.user().disconnect(handler);
58 }
59 }
60 }
61
62 impl WidgetImpl for NoSupportedMethodsPage {
63 fn grab_focus(&self) -> bool {
64 self.cancel_btn.grab_focus()
65 }
66 }
67
68 impl BinImpl for NoSupportedMethodsPage {}
69
70 impl NoSupportedMethodsPage {
71 fn set_verification(&self, verification: Option<&IdentityVerification>) {
73 let prev_verification = self.verification.obj();
74
75 if prev_verification.as_ref() == verification {
76 return;
77 }
78 let obj = self.obj();
79
80 if let Some(verification) = prev_verification
81 && let Some(handler) = self.display_name_handler.take()
82 {
83 verification.user().disconnect(handler);
84 }
85 self.verification.disconnect_signals();
86
87 if let Some(verification) = verification {
88 let display_name_handler = verification.user().connect_display_name_notify(clone!(
89 #[weak]
90 obj,
91 move |_| {
92 obj.update_page();
93 }
94 ));
95 self.display_name_handler
96 .replace(Some(display_name_handler));
97
98 let was_accepted_handler = verification.connect_was_accepted_notify(clone!(
99 #[weak]
100 obj,
101 move |_| {
102 obj.update_page();
103 }
104 ));
105
106 self.verification
107 .set(verification, vec![was_accepted_handler]);
108 }
109
110 obj.update_page();
111 obj.notify_verification();
112 }
113 }
114}
115
116glib::wrapper! {
117 pub struct NoSupportedMethodsPage(ObjectSubclass<imp::NoSupportedMethodsPage>)
119 @extends gtk::Widget, adw::Bin,
120 @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
121}
122
123#[gtk::template_callbacks]
124impl NoSupportedMethodsPage {
125 pub fn new() -> Self {
126 glib::Object::new()
127 }
128
129 fn update_page(&self) {
131 let Some(verification) = self.verification() else {
132 return;
133 };
134 let imp = self.imp();
135 let was_accepted = verification.was_accepted();
136
137 let message = if verification.is_self_verification() {
138 if was_accepted {
139 gettext("None of the methods offered by the other client are supported by Fractal.")
140 } else {
141 gettext(
142 "A login request was received, but none of the methods offered by the other client are supported by Fractal.",
143 )
144 }
145 } else {
146 let name = verification.user().display_name();
147 if was_accepted {
148 gettext_f(
149 "None of the methods offered by {user}’s client are supported by Fractal.",
152 &[("user", &format!("<b>{name}</b>"))],
153 )
154 } else {
155 gettext_f(
156 "{user} sent a verification request, but none of the methods offered by the other client are supported by Fractal.",
159 &[("user", &format!("<b>{name}</b>"))],
160 )
161 }
162 };
163 imp.message.set_markup(&message);
164
165 imp.instructions.set_visible(!was_accepted);
166
167 let cancel_label = if was_accepted {
168 gettext("Cancel Verification")
169 } else {
170 gettext("Decline Verification")
171 };
172 imp.cancel_btn.set_content_label(cancel_label);
173 }
174
175 pub fn reset(&self) {
177 self.imp().cancel_btn.set_is_loading(false);
178 self.set_sensitive(true);
179 }
180
181 #[template_callback]
183 async fn cancel(&self) {
184 let Some(verification) = self.verification() else {
185 return;
186 };
187
188 self.imp().cancel_btn.set_is_loading(true);
189 self.set_sensitive(false);
190
191 if verification.cancel().await.is_err() {
192 toast!(self, gettext("Could not decline the verification"));
193 self.reset();
194 }
195 }
196}