fractal/identity_verification_view/
accept_request_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/accept_request_page.ui"
19 )]
20 #[properties(wrapper_type = super::AcceptRequestPage)]
21 pub struct AcceptRequestPage {
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 decline_btn: TemplateChild<LoadingButton>,
32 #[template_child]
33 pub accept_btn: TemplateChild<LoadingButton>,
34 }
35
36 #[glib::object_subclass]
37 impl ObjectSubclass for AcceptRequestPage {
38 const NAME: &'static str = "IdentityVerificationAcceptRequestPage";
39 type Type = super::AcceptRequestPage;
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 AcceptRequestPage {
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 AcceptRequestPage {
64 fn grab_focus(&self) -> bool {
65 self.accept_btn.grab_focus()
66 }
67 }
68
69 impl BinImpl for AcceptRequestPage {}
70
71 impl AcceptRequestPage {
72 fn set_verification(&self, verification: Option<&IdentityVerification>) {
74 let prev_verification = self.verification.upgrade();
75
76 if prev_verification.as_ref() == verification {
77 return;
78 }
79 let obj = self.obj();
80
81 obj.reset();
82
83 if let Some(verification) = prev_verification {
84 if let Some(handler) = self.display_name_handler.take() {
85 verification.user().disconnect(handler);
86 }
87 }
88
89 if let Some(verification) = verification {
90 let display_name_handler = verification.user().connect_display_name_notify(clone!(
91 #[weak]
92 obj,
93 move |_| {
94 obj.update_labels();
95 }
96 ));
97 self.display_name_handler
98 .replace(Some(display_name_handler));
99 }
100
101 self.verification.set(verification);
102 obj.update_labels();
103 obj.notify_verification();
104 }
105 }
106}
107
108glib::wrapper! {
109 pub struct AcceptRequestPage(ObjectSubclass<imp::AcceptRequestPage>)
111 @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
112}
113
114#[gtk::template_callbacks]
115impl AcceptRequestPage {
116 pub fn new() -> Self {
117 glib::Object::new()
118 }
119
120 fn update_labels(&self) {
122 let Some(verification) = self.verification() else {
123 return;
124 };
125 let imp = self.imp();
126
127 if verification.is_self_verification() {
128 imp.title
129 .set_label(&gettext("Login Request From Another Session"));
130 imp.instructions
131 .set_label(&gettext("Verify the new session from the current session."));
132 } else {
133 let name = verification.user().display_name();
134 imp.title.set_markup(&gettext("Verification Request"));
135 imp.instructions
136 .set_markup(&gettext_f("{user} asked to be verified. Verifying a user increases the security of the conversation.", &[("user", &format!("<b>{name}</b>"))]));
139 }
140 }
141
142 pub fn reset(&self) {
144 let imp = self.imp();
145 imp.accept_btn.set_is_loading(false);
146 imp.decline_btn.set_is_loading(false);
147 self.set_sensitive(true);
148 }
149
150 #[template_callback]
152 async fn decline(&self) {
153 let Some(verification) = self.verification() else {
154 return;
155 };
156
157 self.imp().decline_btn.set_is_loading(true);
158 self.set_sensitive(false);
159
160 if verification.cancel().await.is_err() {
161 toast!(self, gettext("Could not decline verification request"));
162 self.reset();
163 }
164 }
165
166 #[template_callback]
168 async fn accept(&self) {
169 let Some(verification) = self.verification() else {
170 return;
171 };
172
173 self.imp().accept_btn.set_is_loading(true);
174 self.set_sensitive(false);
175
176 if verification.accept().await.is_err() {
177 toast!(self, gettext("Could not accept verification request"));
178 self.reset();
179 }
180 }
181}
182
183impl Default for AcceptRequestPage {
184 fn default() -> Self {
185 Self::new()
186 }
187}