use adw::subclass::prelude::*;
use gettextrs::gettext;
use gtk::{glib, glib::clone, prelude::*, CompositeTemplate};
use crate::{
components::LoadingButton,
gettext_f,
prelude::*,
session::model::{IdentityVerification, VerificationState},
toast,
utils::BoundObjectWeakRef,
Window,
};
mod imp {
use std::cell::RefCell;
use glib::subclass::InitializingObject;
use super::*;
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
#[template(
resource = "/org/gnome/Fractal/ui/session/view/content/room_history/verification_info_bar.ui"
)]
#[properties(wrapper_type = super::VerificationInfoBar)]
pub struct VerificationInfoBar {
#[template_child]
pub revealer: TemplateChild<gtk::Revealer>,
#[template_child]
pub label: TemplateChild<gtk::Label>,
#[template_child]
pub accept_btn: TemplateChild<LoadingButton>,
#[template_child]
pub cancel_btn: TemplateChild<LoadingButton>,
#[property(get, set = Self::set_verification, explicit_notify)]
pub verification: BoundObjectWeakRef<IdentityVerification>,
pub user_handler: RefCell<Option<glib::SignalHandlerId>>,
}
#[glib::object_subclass]
impl ObjectSubclass for VerificationInfoBar {
const NAME: &'static str = "ContentVerificationInfoBar";
type Type = super::VerificationInfoBar;
type ParentType = adw::Bin;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
klass.set_css_name("infobar");
klass.set_accessible_role(gtk::AccessibleRole::Group);
klass.install_action_async("verification.accept", None, |obj, _, _| async move {
let Some(window) = obj.root().and_downcast::<Window>() else {
return;
};
let Some(verification) = obj.verification() else {
return;
};
let imp = obj.imp();
if verification.state() == VerificationState::Requested {
imp.accept_btn.set_is_loading(true);
if verification.accept().await.is_err() {
toast!(obj, gettext("Could not accept verification"));
imp.accept_btn.set_is_loading(false);
return;
}
}
window
.session_view()
.select_identity_verification(verification);
imp.accept_btn.set_is_loading(false);
});
klass.install_action_async("verification.decline", None, |obj, _, _| async move {
let Some(verification) = obj.verification() else {
return;
};
let imp = obj.imp();
imp.cancel_btn.set_is_loading(true);
if verification.cancel().await.is_err() {
toast!(obj, gettext("Could not decline verification"));
}
imp.cancel_btn.set_is_loading(false);
});
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for VerificationInfoBar {
fn dispose(&self) {
if let Some(verification) = self.verification.obj() {
if let Some(handler) = self.user_handler.take() {
verification.user().disconnect(handler);
}
}
}
}
impl WidgetImpl for VerificationInfoBar {}
impl BinImpl for VerificationInfoBar {}
impl VerificationInfoBar {
fn set_verification(&self, verification: Option<IdentityVerification>) {
let prev_verification = self.verification.obj();
if prev_verification == verification {
return;
}
if let Some(verification) = prev_verification {
if let Some(handler) = self.user_handler.take() {
verification.user().disconnect(handler);
}
}
self.verification.disconnect_signals();
if let Some(verification) = &verification {
let user_handler = verification.user().connect_display_name_notify(clone!(
#[weak(rename_to = imp)]
self,
move |_| {
imp.update_bar();
}
));
self.user_handler.replace(Some(user_handler));
let state_handler = verification.connect_state_notify(clone!(
#[weak(rename_to = imp)]
self,
move |_| {
imp.update_bar();
}
));
self.verification.set(verification, vec![state_handler]);
}
self.update_bar();
self.obj().notify_verification();
}
fn update_bar(&self) {
let Some(verification) = self.verification.obj().filter(|v| !v.is_finished()) else {
self.revealer.set_reveal_child(false);
return;
};
if matches!(verification.state(), VerificationState::Requested) {
self.label.set_markup(&gettext_f(
"{user_name} wants to be verified",
&[(
"user_name",
&format!("<b>{}</b>", verification.user().display_name()),
)],
));
self.accept_btn.set_label(&gettext("Verify"));
self.cancel_btn.set_label(&gettext("Decline"));
} else {
self.label.set_label(&gettext("Verification in progress"));
self.accept_btn.set_label(&gettext("Continue"));
self.cancel_btn.set_label(&gettext("Cancel"));
}
self.revealer.set_reveal_child(true);
}
}
}
glib::wrapper! {
pub struct VerificationInfoBar(ObjectSubclass<imp::VerificationInfoBar>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
impl VerificationInfoBar {
pub fn new() -> Self {
glib::Object::new()
}
}