implement Common identity as trait for AlertDialog

This commit is contained in:
yggverse 2025-01-29 19:34:30 +02:00
parent a6d84908cc
commit fc8c967891
22 changed files with 131 additions and 175 deletions

View file

@ -14,8 +14,8 @@ pub fn common(
profile: &Rc<Profile>, profile: &Rc<Profile>,
request: &Uri, request: &Uri,
callback: &Rc<impl Fn(bool) + 'static>, callback: &Rc<impl Fn(bool) + 'static>,
) -> Common { ) -> AlertDialog {
Common::build(profile, request, callback) AlertDialog::common(profile, request, callback)
} }
/// Create new identity widget for unknown request /// Create new identity widget for unknown request

View file

@ -1,38 +1,144 @@
mod widget; mod action;
use widget::Widget; pub mod form;
use super::Profile; use action::Action as WidgetAction;
use gtk::{glib::Uri, prelude::IsA}; use form::{list::item::value::Value, Form};
use crate::Profile;
use adw::{
prelude::{AlertDialogExt, AlertDialogExtManual},
AlertDialog, ResponseAppearance,
};
use gtk::glib::Uri;
use std::rc::Rc; use std::rc::Rc;
pub struct Common { // Defaults
// profile: Rc<Profile>, const HEADING: &str = "Identity";
widget: Rc<Widget>, const BODY: &str = "Select identity certificate";
// Response variants
const RESPONSE_APPLY: (&str, &str) = ("apply", "Apply");
const RESPONSE_CANCEL: (&str, &str) = ("cancel", "Cancel");
// const RESPONSE_MANAGE: (&str, &str) = ("manage", "Manage");
// Select options
pub trait Common {
fn common(profile: &Rc<Profile>, request: &Uri, callback: &Rc<impl Fn(bool) + 'static>)
-> Self;
} }
impl Common { impl Common for AlertDialog {
// Construct // Constructors
/// Create new `Self` for given `Profile` /// Create new `Self`
pub fn build( fn common(
profile: &Rc<Profile>, profile: &Rc<Profile>,
request: &Uri, request: &Uri,
callback: &Rc<impl Fn(bool) + 'static>, callback: &Rc<impl Fn(bool) + 'static>,
) -> Self { ) -> Self {
// Init widget // Init actions
let widget = Rc::new(Widget::build(profile, request, callback)); let action = Rc::new(WidgetAction::new());
// Return activated `Self` // Init child container
Self { let form = Rc::new(Form::build(&action, profile, request));
// profile,
widget,
}
}
// Actions // Init main widget
let alert_dialog = AlertDialog::builder()
.heading(HEADING)
.body(BODY)
.close_response(RESPONSE_CANCEL.0)
.default_response(RESPONSE_APPLY.0)
.extra_child(&form.g_box)
.build();
/// Show dialog for parent [Widget](https://docs.gtk.org/gtk4/class.Widget.html) alert_dialog.add_responses(&[
pub fn present(&self, parent: Option<&impl IsA<gtk::Widget>>) { RESPONSE_CANCEL,
self.widget.present(parent); // RESPONSE_MANAGE,
RESPONSE_APPLY,
]);
alert_dialog.connect_response(Some(RESPONSE_APPLY.0), {
let callback = callback.clone();
let form = form.clone();
let profile = profile.clone();
let request = request.clone();
move |this, response| {
// Prevent double-click action
this.set_response_enabled(response, false);
// Get option match user choice
let option = match form.list.selected().value_enum() {
Value::ProfileIdentityId(value) => Some(value),
Value::GuestSession => None,
Value::GeneratePem => Some(
profile
.identity
.make(None, &form.name.value().unwrap())
.unwrap(), // @TODO handle
),
Value::ImportPem => Some(
profile
.identity
.add(&form.file.pem.take().unwrap())
.unwrap(), // @TODO handle
),
};
// Apply auth
match option {
// Activate identity for `scope`
Some(profile_identity_id) => {
if profile
.identity
.auth
.apply(profile_identity_id, &request.to_string())
.is_err()
{
panic!() // unexpected @TODO
}
}
// Remove all identity auths for `scope`
None => {
if profile.identity.auth.remove(&request.to_string()).is_err() {
panic!() // unexpected @TODO
}
}
}
// Run callback function
callback(true)
}
});
// Deactivate not implemented feature @TODO
// alert_dialog.set_response_enabled(RESPONSE_MANAGE.0, false);
// Decorate default response preset
alert_dialog.set_response_appearance(RESPONSE_APPLY.0, ResponseAppearance::Suggested);
/* contrast issue with Ubuntu orange accents
alert_dialog.set_response_appearance(RESPONSE_CANCEL.0, ResponseAppearance::Destructive); */
// Init events
action.update.connect_activate({
let form = form.clone();
let callback = callback.clone();
let alert_dialog = alert_dialog.clone();
move || {
// Update child components
form.update();
// Deactivate apply button if the form values could not be processed
alert_dialog.set_response_enabled(RESPONSE_APPLY.0, form.is_applicable());
callback(false);
}
});
// Make initial update
action.update.activate();
// Return new activated `Self`
alert_dialog
} }
} }

View file

@ -1,150 +0,0 @@
mod action;
pub mod form;
use action::Action as WidgetAction;
use form::{list::item::value::Value, Form};
use crate::Profile;
use adw::{
prelude::{AdwDialogExt, AlertDialogExt, AlertDialogExtManual},
AlertDialog, ResponseAppearance,
};
use gtk::{glib::Uri, prelude::IsA};
use std::rc::Rc;
// Defaults
const HEADING: &str = "Identity";
const BODY: &str = "Select identity certificate";
// Response variants
const RESPONSE_APPLY: (&str, &str) = ("apply", "Apply");
const RESPONSE_CANCEL: (&str, &str) = ("cancel", "Cancel");
// const RESPONSE_MANAGE: (&str, &str) = ("manage", "Manage");
// Select options
pub struct Widget {
alert_dialog: AlertDialog,
}
impl Widget {
// Constructors
/// Create new `Self`
pub fn build(
profile: &Rc<Profile>,
request: &Uri,
callback: &Rc<impl Fn(bool) + 'static>,
) -> Self {
// Init actions
let action = Rc::new(WidgetAction::new());
// Init child container
let form = Rc::new(Form::build(&action, profile, request));
// Init main widget
let alert_dialog = AlertDialog::builder()
.heading(HEADING)
.body(BODY)
.close_response(RESPONSE_CANCEL.0)
.default_response(RESPONSE_APPLY.0)
.extra_child(&form.g_box)
.build();
alert_dialog.add_responses(&[
RESPONSE_CANCEL,
// RESPONSE_MANAGE,
RESPONSE_APPLY,
]);
alert_dialog.connect_response(Some(RESPONSE_APPLY.0), {
let callback = callback.clone();
let form = form.clone();
let profile = profile.clone();
let request = request.clone();
move |this, response| {
// Prevent double-click action
this.set_response_enabled(response, false);
// Get option match user choice
let option = match form.list.selected().value_enum() {
Value::ProfileIdentityId(value) => Some(value),
Value::GuestSession => None,
Value::GeneratePem => Some(
profile
.identity
.make(None, &form.name.value().unwrap())
.unwrap(), // @TODO handle
),
Value::ImportPem => Some(
profile
.identity
.add(&form.file.pem.take().unwrap())
.unwrap(), // @TODO handle
),
};
// Apply auth
match option {
// Activate identity for `scope`
Some(profile_identity_id) => {
if profile
.identity
.auth
.apply(profile_identity_id, &request.to_string())
.is_err()
{
panic!() // unexpected @TODO
}
}
// Remove all identity auths for `scope`
None => {
if profile.identity.auth.remove(&request.to_string()).is_err() {
panic!() // unexpected @TODO
}
}
}
// Run callback function
callback(true)
}
});
// Deactivate not implemented feature @TODO
// alert_dialog.set_response_enabled(RESPONSE_MANAGE.0, false);
// Decorate default response preset
alert_dialog.set_response_appearance(RESPONSE_APPLY.0, ResponseAppearance::Suggested);
/* contrast issue with Ubuntu orange accents
alert_dialog.set_response_appearance(RESPONSE_CANCEL.0, ResponseAppearance::Destructive); */
// Init events
action.update.connect_activate({
let form = form.clone();
let callback = callback.clone();
let alert_dialog = alert_dialog.clone();
move || {
// Update child components
form.update();
// Deactivate apply button if the form values could not be processed
alert_dialog.set_response_enabled(RESPONSE_APPLY.0, form.is_applicable());
callback(false);
}
});
// Make initial update
action.update.activate();
// Return new activated `Self`
Self { alert_dialog }
}
// Actions
/// Show dialog with new preset
pub fn present(&self, parent: Option<&impl IsA<gtk::Widget>>) {
self.alert_dialog.present(parent)
}
}