From 36d4673d44e231dc231d252b5c2522db3616a94e Mon Sep 17 00:00:00 2001 From: yggverse Date: Thu, 5 Dec 2024 20:26:42 +0200 Subject: [PATCH] draft identity exit feature --- .../tab/item/identity/gemini/widget/form.rs | 9 ++ .../item/identity/gemini/widget/form/exit.rs | 141 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 src/app/browser/window/tab/item/identity/gemini/widget/form/exit.rs diff --git a/src/app/browser/window/tab/item/identity/gemini/widget/form.rs b/src/app/browser/window/tab/item/identity/gemini/widget/form.rs index bf0e542f..e6de1b2c 100644 --- a/src/app/browser/window/tab/item/identity/gemini/widget/form.rs +++ b/src/app/browser/window/tab/item/identity/gemini/widget/form.rs @@ -1,10 +1,12 @@ mod drop; +mod exit; mod file; pub mod list; mod name; mod save; use drop::Drop; +use exit::Exit; use file::File; use list::{item::value::Value, List}; use name::Name; @@ -18,6 +20,7 @@ use std::rc::Rc; pub struct Form { // pub action: Rc, // pub drop: Rc, + // pub exit: Rc, pub file: Rc, pub list: Rc, pub name: Rc, @@ -36,6 +39,7 @@ impl Form { let name = Rc::new(Name::new(action.clone())); let save = Rc::new(Save::new(profile.clone())); let drop = Rc::new(Drop::new(profile.clone(), action.clone(), list.clone())); + let exit = Rc::new(Exit::new(profile.clone(), action.clone(), list.clone())); // Init main container let g_box = Box::builder().orientation(Orientation::Vertical).build(); @@ -43,12 +47,14 @@ impl Form { g_box.append(&list.dropdown); g_box.append(&name.entry); g_box.append(&file.button); + g_box.append(&exit.button); g_box.append(&drop.button); g_box.append(&save.button); // Connect events list.on_select({ let drop = drop.clone(); + let exit = exit.clone(); let file = file.clone(); let name = name.clone(); let save = save.clone(); @@ -64,10 +70,12 @@ impl Form { match item { Value::ProfileIdentityGeminiId(value) => { drop.update(Some(value)); + exit.update(Some(value)); save.update(Some(value)); } _ => { drop.update(None); + exit.update(None); save.update(None); } } @@ -81,6 +89,7 @@ impl Form { Self { // action, // drop, + // exit, file, list, name, diff --git a/src/app/browser/window/tab/item/identity/gemini/widget/form/exit.rs b/src/app/browser/window/tab/item/identity/gemini/widget/form/exit.rs new file mode 100644 index 00000000..fd4b38f6 --- /dev/null +++ b/src/app/browser/window/tab/item/identity/gemini/widget/form/exit.rs @@ -0,0 +1,141 @@ +use super::Action; +use super::List; +use crate::profile::Profile; +use adw::{ + prelude::{AdwDialogExt, AlertDialogExt, AlertDialogExtManual}, + AlertDialog, ResponseAppearance, +}; +use gtk::{ + prelude::{ButtonExt, WidgetExt}, + Button, +}; +use std::{cell::RefCell, rc::Rc}; + +// Defaults + +const LABEL: &str = "Disconnect"; +const TOOLTIP_TEXT: &str = "Stop use selected identity everywhere"; +const MARGIN: i32 = 8; + +const HEADING: &str = "Disconnect"; +const BODY: &str = "Stop use selected identity for all scopes?"; +const RESPONSE_CANCEL: (&str, &str) = ("cancel", "Cancel"); +const RESPONSE_CONFIRM: (&str, &str) = ("confirm", "Confirm"); + +pub struct Exit { + profile_identity_gemini_id: Rc>>, + pub button: Button, +} + +impl Exit { + // Constructors + + /// Create new `Self` + pub fn new(profile: Rc, action: Rc, list: Rc) -> Self { + // Init selected option holder + let profile_identity_gemini_id = Rc::new(RefCell::new(None::)); + + // Init main widget + let button = Button::builder() + .label(LABEL) + .margin_top(MARGIN) + .tooltip_text(TOOLTIP_TEXT) + .visible(false) + .build(); + + // Init events + button.connect_clicked({ + let action = action.clone(); + let button = button.clone(); + let profile_identity_gemini_id = profile_identity_gemini_id.clone(); + move |_| { + // Get selected identity from holder + match profile_identity_gemini_id.borrow().as_ref() { + Some(profile_identity_gemini_id) => { + // Init sub-widget + let alert_dialog = AlertDialog::builder() + .heading(HEADING) + .body(BODY) + .close_response(RESPONSE_CANCEL.0) + .default_response(RESPONSE_CANCEL.0) + .build(); + + // Set response variants + alert_dialog.add_responses(&[RESPONSE_CANCEL, RESPONSE_CONFIRM]); + + // Decorate default response preset + alert_dialog.set_response_appearance( + RESPONSE_CONFIRM.0, + ResponseAppearance::Suggested, + ); + + alert_dialog.set_response_appearance( + RESPONSE_CANCEL.0, + ResponseAppearance::Destructive, + ); + + // Connect confirmation event + alert_dialog.connect_response(Some(RESPONSE_CONFIRM.0), { + let action = action.clone(); + let button = button.clone(); + let list = list.clone(); + let profile = profile.clone(); + let profile_identity_gemini_id = *profile_identity_gemini_id; + move |_, _| { + match profile + .identity + .gemini + .auth + .remove_ref(profile_identity_gemini_id) + { + Ok(_) => { + if list.remove(profile_identity_gemini_id).is_some() { + button.set_css_classes(&["success"]); + button.set_label("Identity successfully disconnected") + } else { + button.set_css_classes(&["error"]); + button.set_label("List item not found") + // @TODO unexpected + } + } + Err(e) => { + button.set_css_classes(&["error"]); + button.set_label(&e.to_string()) + } + } + action.update.activate() + } + }); + + // Show dialog + alert_dialog.present(Some(&button)) + } + None => todo!(), // unexpected + } + } + }); + + // Return activated `Self` + Self { + profile_identity_gemini_id, + button, + } + } + + // Actions + + /// Update `profile_identity_gemini_id` holder, + /// toggle visibility depending on given value + pub fn update(&self, profile_identity_gemini_id: Option) { + self.button.set_visible(match profile_identity_gemini_id { + Some(value) => { + self.profile_identity_gemini_id.replace(Some(value)); + true + } + None => { + self.profile_identity_gemini_id.replace(None); + false + } + }) + } +}