fractal/identity_verification_view/
cancelled_page.rsuse adw::subclass::prelude::*;
use gettextrs::gettext;
use gtk::{glib, glib::clone, prelude::*, CompositeTemplate};
use matrix_sdk::crypto::CancelInfo;
use ruma::events::key::verification::cancel::CancelCode;
use crate::{
components::LoadingButton, gettext_f, prelude::*, session::model::IdentityVerification, toast,
utils::BoundObjectWeakRef,
};
mod imp {
use std::cell::RefCell;
use glib::subclass::InitializingObject;
use super::*;
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
#[template(resource = "/org/gnome/Fractal/ui/identity_verification_view/cancelled_page.ui")]
#[properties(wrapper_type = super::CancelledPage)]
pub struct CancelledPage {
#[property(get, set = Self::set_verification, explicit_notify, nullable)]
pub verification: BoundObjectWeakRef<IdentityVerification>,
pub display_name_handler: RefCell<Option<glib::SignalHandlerId>>,
#[template_child]
pub title: TemplateChild<gtk::Label>,
#[template_child]
pub message: TemplateChild<gtk::Label>,
#[template_child]
pub try_again_btn: TemplateChild<LoadingButton>,
}
#[glib::object_subclass]
impl ObjectSubclass for CancelledPage {
const NAME: &'static str = "IdentityVerificationCancelledPage";
type Type = super::CancelledPage;
type ParentType = adw::Bin;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
Self::Type::bind_template_callbacks(klass);
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for CancelledPage {
fn dispose(&self) {
if let Some(verification) = self.verification.obj() {
if let Some(handler) = self.display_name_handler.take() {
verification.user().disconnect(handler);
}
}
}
}
impl WidgetImpl for CancelledPage {
fn grab_focus(&self) -> bool {
self.try_again_btn.grab_focus()
}
}
impl BinImpl for CancelledPage {}
impl CancelledPage {
fn set_verification(&self, verification: Option<IdentityVerification>) {
let prev_verification = self.verification.obj();
if prev_verification == verification {
return;
}
let obj = self.obj();
if let Some(verification) = prev_verification {
if let Some(handler) = self.display_name_handler.take() {
verification.user().disconnect(handler);
}
}
self.verification.disconnect_signals();
if let Some(verification) = verification {
let display_name_handler = verification.user().connect_display_name_notify(clone!(
#[weak]
obj,
move |_| {
obj.update_message();
}
));
self.display_name_handler
.replace(Some(display_name_handler));
let cancel_info_changed_handler = verification.connect_cancel_info_changed(clone!(
#[weak]
obj,
move |_| {
obj.update_message();
}
));
self.verification
.set(&verification, vec![cancel_info_changed_handler]);
}
obj.update_message();
obj.notify_verification();
}
}
}
glib::wrapper! {
pub struct CancelledPage(ObjectSubclass<imp::CancelledPage>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
#[gtk::template_callbacks]
impl CancelledPage {
pub fn new() -> Self {
glib::Object::new()
}
fn update_message(&self) {
let Some(verification) = self.verification() else {
return;
};
let cancel_info = verification.cancel_info();
let imp = self.imp();
let message = match cancel_info.as_ref().map(CancelInfo::cancel_code) {
Some(CancelCode::User) => {
if verification.is_self_verification() {
gettext("The verification was cancelled from the other session.")
} else {
let name = verification.user().display_name();
gettext_f(
"The verification was cancelled by {user}.",
&[("user", &format!("<b>{name}</b>"))],
)
}
}
Some(CancelCode::Timeout) => {
gettext("The verification process failed because it reached a timeout.")
}
Some(CancelCode::Accepted) => gettext("You accepted the request from another session."),
Some(CancelCode::MismatchedSas) => {
if verification.sas_supports_emoji() {
gettext("The emoji did not match.")
} else {
gettext("The numbers did not match.")
}
}
_ => gettext("An unexpected error happened during the verification process."),
};
imp.message.set_markup(&message);
let title = if cancel_info.is_some() {
gettext("Verification Cancelled")
} else {
gettext("Verification Error")
};
imp.title.set_text(&title);
}
pub fn reset(&self) {
self.imp().try_again_btn.set_is_loading(false);
self.set_sensitive(true);
}
#[template_callback]
async fn try_again(&self) {
let Some(verification) = self.verification() else {
return;
};
self.imp().try_again_btn.set_is_loading(true);
self.set_sensitive(false);
if verification.restart().await.is_err() {
toast!(self, gettext("Could not send a new verification request"));
self.reset();
}
}
#[template_callback]
fn dismiss(&self) {
let Some(verification) = self.verification() else {
return;
};
verification.dismiss();
}
}