fractal/identity_verification_view/
wait_for_other_page.rs1use adw::subclass::prelude::*;
2use gettextrs::gettext;
3use gtk::{glib, glib::clone, prelude::*, CompositeTemplate};
4
5use crate::{
6 components::LoadingButton, gettext_f, prelude::*, session::model::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, 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 if let Some(handler) = self.display_name_handler.take() {
57 verification.user().disconnect(handler);
58 }
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 if let Some(handler) = self.display_name_handler.take() {
78 verification.user().disconnect(handler);
79 }
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, @implements gtk::Accessible;
105}
106
107#[gtk::template_callbacks]
108impl WaitForOtherPage {
109 pub fn new(verification: &IdentityVerification) -> Self {
110 glib::Object::builder()
111 .property("verification", verification)
112 .build()
113 }
114
115 fn update_labels(&self) {
117 let Some(verification) = self.verification() else {
118 return;
119 };
120 let imp = self.imp();
121
122 if verification.is_self_verification() {
123 imp.title.set_label(&gettext("Get Another Device"));
124 imp.instructions.set_label(&gettext(
125 "Accept the verification request from another session or device.",
126 ));
127 imp.trust.set_visible(false);
128 } else {
129 let name = verification.user().display_name();
130 imp.title.set_markup(&gettext_f(
131 "Waiting for {user}",
134 &[("user", &name)],
135 ));
136 imp.instructions.set_markup(&gettext_f(
137 "Ask {user} to accept the verification request.",
140 &[("user", &format!("<b>{name}</b>"))],
141 ));
142 imp.trust.set_visible(true);
143 }
144 }
145
146 pub fn reset(&self) {
148 self.imp().cancel_btn.set_is_loading(false);
149 self.set_sensitive(true);
150 }
151
152 #[template_callback]
154 async fn cancel(&self) {
155 let Some(verification) = self.verification() else {
156 return;
157 };
158
159 self.imp().cancel_btn.set_is_loading(true);
160 self.set_sensitive(false);
161
162 if verification.cancel().await.is_err() {
163 toast!(self, gettext("Could not cancel the verification"));
164 self.reset();
165 }
166 }
167}