fractal/identity_verification_view/
wait_for_other_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};
8
9mod imp {
10 use std::cell::RefCell;
11
12 use glib::subclass::InitializingObject;
13
14 use super::*;
15
16 #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
17 #[template(
18 resource = "/org/gnome/Fractal/ui/identity_verification_view/wait_for_other_page.ui"
19 )]
20 #[properties(wrapper_type = super::WaitForOtherPage)]
21 pub struct WaitForOtherPage {
22 #[property(get, set = Self::set_verification, explicit_notify, nullable)]
24 pub verification: glib::WeakRef<IdentityVerification>,
25 pub display_name_handler: RefCell<Option<glib::SignalHandlerId>>,
26 #[template_child]
27 pub title: TemplateChild<gtk::Label>,
28 #[template_child]
29 pub instructions: TemplateChild<gtk::Label>,
30 #[template_child]
31 pub trust: TemplateChild<gtk::Label>,
32 #[template_child]
33 pub cancel_btn: TemplateChild<LoadingButton>,
34 }
35
36 #[glib::object_subclass]
37 impl ObjectSubclass for WaitForOtherPage {
38 const NAME: &'static str = "IdentityVerificationWaitForOtherPage";
39 type Type = super::WaitForOtherPage;
40 type ParentType = adw::Bin;
41
42 fn class_init(klass: &mut Self::Class) {
43 Self::bind_template(klass);
44 Self::Type::bind_template_callbacks(klass);
45 }
46
47 fn instance_init(obj: &InitializingObject<Self>) {
48 obj.init_template();
49 }
50 }
51
52 #[glib::derived_properties]
53 impl ObjectImpl for WaitForOtherPage {
54 fn dispose(&self) {
55 if let Some(verification) = self.verification.upgrade()
56 && let Some(handler) = self.display_name_handler.take()
57 {
58 verification.user().disconnect(handler);
59 }
60 }
61 }
62
63 impl WidgetImpl for WaitForOtherPage {}
64 impl BinImpl for WaitForOtherPage {}
65
66 impl WaitForOtherPage {
67 fn set_verification(&self, verification: Option<&IdentityVerification>) {
69 let prev_verification = self.verification.upgrade();
70
71 if prev_verification.as_ref() == verification {
72 return;
73 }
74 let obj = self.obj();
75
76 if let Some(verification) = prev_verification
77 && let Some(handler) = self.display_name_handler.take()
78 {
79 verification.user().disconnect(handler);
80 }
81
82 if let Some(verification) = verification {
83 let display_name_handler = verification.user().connect_display_name_notify(clone!(
84 #[weak]
85 obj,
86 move |_| {
87 obj.update_labels();
88 }
89 ));
90 self.display_name_handler
91 .replace(Some(display_name_handler));
92 }
93
94 self.verification.set(verification);
95
96 obj.update_labels();
97 }
98 }
99}
100
101glib::wrapper! {
102 pub struct WaitForOtherPage(ObjectSubclass<imp::WaitForOtherPage>)
104 @extends gtk::Widget, adw::Bin,
105 @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
106}
107
108#[gtk::template_callbacks]
109impl WaitForOtherPage {
110 pub fn new(verification: &IdentityVerification) -> Self {
111 glib::Object::builder()
112 .property("verification", verification)
113 .build()
114 }
115
116 fn update_labels(&self) {
118 let Some(verification) = self.verification() else {
119 return;
120 };
121 let imp = self.imp();
122
123 if verification.is_self_verification() {
124 imp.title.set_label(&gettext("Get Another Device"));
125 imp.instructions.set_label(&gettext(
126 "Accept the verification request from another session or device.",
127 ));
128 imp.trust.set_visible(false);
129 } else {
130 let name = verification.user().display_name();
131 imp.title.set_markup(&gettext_f(
132 "Waiting for {user}",
135 &[("user", &name)],
136 ));
137 imp.instructions.set_markup(&gettext_f(
138 "Ask {user} to accept the verification request.",
141 &[("user", &format!("<b>{name}</b>"))],
142 ));
143 imp.trust.set_visible(true);
144 }
145 }
146
147 pub fn reset(&self) {
149 self.imp().cancel_btn.set_is_loading(false);
150 self.set_sensitive(true);
151 }
152
153 #[template_callback]
155 async fn cancel(&self) {
156 let Some(verification) = self.verification() else {
157 return;
158 };
159
160 self.imp().cancel_btn.set_is_loading(true);
161 self.set_sensitive(false);
162
163 if verification.cancel().await.is_err() {
164 toast!(self, gettext("Could not cancel the verification"));
165 self.reset();
166 }
167 }
168}