use adw::subclass::prelude::*;
use gtk::{glib, glib::clone, prelude::*, CompositeTemplate};
mod accept_request_page;
mod cancelled_page;
mod choose_method_page;
mod completed_page;
mod confirm_qr_code_page;
mod no_supported_methods_page;
mod qr_code_scanned_page;
mod room_left_page;
mod sas_emoji;
mod sas_page;
mod scan_qr_code_page;
mod wait_for_other_page;
use self::{
accept_request_page::AcceptRequestPage, cancelled_page::CancelledPage,
choose_method_page::ChooseMethodPage, completed_page::CompletedPage,
confirm_qr_code_page::ConfirmQrCodePage, no_supported_methods_page::NoSupportedMethodsPage,
qr_code_scanned_page::QrCodeScannedPage, room_left_page::RoomLeftPage, sas_page::SasPage,
scan_qr_code_page::ScanQrCodePage, wait_for_other_page::WaitForOtherPage,
};
use crate::{
session::model::{IdentityVerification, VerificationState},
utils::BoundObject,
};
mod imp {
use glib::subclass::InitializingObject;
use super::*;
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
#[template(resource = "/org/gnome/Fractal/ui/identity_verification_view/mod.ui")]
#[properties(wrapper_type = super::IdentityVerificationView)]
pub struct IdentityVerificationView {
#[property(get, set = Self::set_verification, explicit_notify, nullable)]
pub verification: BoundObject<IdentityVerification>,
#[template_child]
pub main_stack: TemplateChild<gtk::Stack>,
#[template_child]
pub accept_request_page: TemplateChild<AcceptRequestPage>,
#[template_child]
pub wait_for_other_page: TemplateChild<WaitForOtherPage>,
#[template_child]
pub no_supported_methods_page: TemplateChild<NoSupportedMethodsPage>,
#[template_child]
pub choose_method_page: TemplateChild<ChooseMethodPage>,
#[template_child]
pub scan_qr_code_page: TemplateChild<ScanQrCodePage>,
#[template_child]
pub qr_code_scanned_page: TemplateChild<QrCodeScannedPage>,
#[template_child]
pub confirm_qr_code_page: TemplateChild<ConfirmQrCodePage>,
#[template_child]
pub sas_page: TemplateChild<SasPage>,
#[template_child]
pub completed_page: TemplateChild<CompletedPage>,
#[template_child]
pub cancelled_page: TemplateChild<CancelledPage>,
#[template_child]
pub room_left_page: TemplateChild<RoomLeftPage>,
}
#[glib::object_subclass]
impl ObjectSubclass for IdentityVerificationView {
const NAME: &'static str = "IdentityVerificationView";
type Type = super::IdentityVerificationView;
type ParentType = adw::Bin;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for IdentityVerificationView {
fn constructed(&self) {
self.parent_constructed();
self.main_stack.connect_transition_running_notify(clone!(
#[weak(rename_to = imp)]
self,
move |stack| if !stack.is_transition_running() {
imp.grab_focus();
}
));
}
}
impl WidgetImpl for IdentityVerificationView {
fn grab_focus(&self) -> bool {
let Some(name) = self.main_stack.visible_child_name() else {
return false;
};
match name.as_str() {
"accept-request" => self.accept_request_page.grab_focus(),
"no-supported-methods" => self.no_supported_methods_page.grab_focus(),
"choose-method" => self.choose_method_page.grab_focus(),
"confirm-qr-code" => self.confirm_qr_code_page.grab_focus(),
"sas" => self.sas_page.grab_focus(),
"completed" => self.completed_page.grab_focus(),
"cancelled" => self.cancelled_page.grab_focus(),
"room-left" => self.room_left_page.grab_focus(),
_ => false,
}
}
}
impl BinImpl for IdentityVerificationView {}
impl IdentityVerificationView {
fn set_verification(&self, verification: Option<IdentityVerification>) {
let prev_verification = self.verification.obj();
if prev_verification == verification {
return;
}
let obj = self.obj();
self.verification.disconnect_signals();
if let Some(verification) = verification {
let state_handler = verification.connect_state_notify(clone!(
#[weak]
obj,
move |_| {
obj.update_view();
}
));
verification.set_was_viewed(true);
self.verification.set(verification, vec![state_handler]);
}
obj.update_view();
obj.notify_verification();
}
}
}
glib::wrapper! {
pub struct IdentityVerificationView(ObjectSubclass<imp::IdentityVerificationView>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
impl IdentityVerificationView {
pub fn new(verification: &IdentityVerification) -> Self {
glib::Object::builder()
.property("verification", verification)
.build()
}
fn update_view(&self) {
let Some(verification) = self.verification() else {
return;
};
let imp = self.imp();
match verification.state() {
VerificationState::Created => {
imp.wait_for_other_page.reset();
imp.main_stack
.set_visible_child_name("wait-for-other-party");
}
VerificationState::Requested => {
imp.accept_request_page.reset();
imp.main_stack.set_visible_child_name("accept-request");
}
VerificationState::NoSupportedMethods => {
imp.no_supported_methods_page.reset();
imp.main_stack
.set_visible_child_name("no-supported-methods");
}
VerificationState::Ready => {
imp.choose_method_page.reset();
imp.main_stack.set_visible_child_name("choose-method");
}
VerificationState::QrScan => {
imp.scan_qr_code_page.reset();
imp.main_stack.set_visible_child_name("scan-qr-code");
}
VerificationState::QrScanned => {
imp.qr_code_scanned_page.reset();
imp.main_stack.set_visible_child_name("qr-code-scanned");
}
VerificationState::QrConfirm => {
imp.confirm_qr_code_page.reset();
imp.main_stack.set_visible_child_name("confirm-qr-code");
}
VerificationState::SasConfirm => {
imp.sas_page.reset();
imp.main_stack.set_visible_child_name("sas");
}
VerificationState::Done => {
imp.main_stack.set_visible_child_name("completed");
}
VerificationState::Cancelled | VerificationState::Error => {
imp.cancelled_page.reset();
imp.main_stack.set_visible_child_name("cancelled");
}
VerificationState::RoomLeft => {
imp.main_stack.set_visible_child_name("room-left");
}
VerificationState::Dismissed => {}
}
}
}