diff --git a/i18n/en/cosmic_ext_fprint.ftl b/i18n/en/cosmic_ext_fprint.ftl index d726dd4..0687ca8 100644 --- a/i18n/en/cosmic_ext_fprint.ftl +++ b/i18n/en/cosmic_ext_fprint.ftl @@ -6,6 +6,11 @@ welcome = Register and/or delete fingerprints git-description = Git commit {$hash} on {$date} register = Register delete = Delete +clear-device = Clear Device +confirm-clear = Are you sure? +clearing-device = Clearing all fingerprints from device for all known users... +device-cleared = Device cleared for all known users. +clear-device-confirm = Are you sure you want to clear fingerprints for ALL known users? Hardware-level orphaned prints may remain. deleting = Deleting fingerprint... deleted = Deleted fingerprint. cancel = Cancel diff --git a/src/app/fprint.rs b/src/app/fprint.rs index 89c49eb..054168e 100644 --- a/src/app/fprint.rs +++ b/src/app/fprint.rs @@ -39,19 +39,43 @@ pub async fn delete_fingerprint_dbus( res.and(rel_res) } -pub async fn delete_fingers( +pub async fn clear_all_fingers_dbus( connection: &zbus::Connection, path: zbus::zvariant::OwnedObjectPath, - username: String, + usernames: Vec, ) -> zbus::Result<()> { let device = DeviceProxy::builder(connection).path(path)?.build().await?; + let mut last_error = None; - device.claim(&username).await?; - let enrolled = device.list_enrolled_fingers(&username).await?; - for finger in enrolled { - device.delete_enrolled_finger(&finger).await?; + for username in usernames { + if let Err(e) = device.claim(&username).await { + last_error = Some(e); + continue; + } + + match device.list_enrolled_fingers(&username).await { + Ok(fingers) => { + for finger in fingers { + if let Err(e) = device.delete_enrolled_finger(&finger).await { + last_error = Some(e); + } + } + } + Err(e) => { + last_error = Some(e); + } + } + + if let Err(e) = device.release().await { + last_error = Some(e); + } + } + + if let Some(e) = last_error { + Err(e) + } else { + Ok(()) } - device.release().await } pub async fn enroll_fingerprint_process( diff --git a/src/app/message.rs b/src/app/message.rs index e9095b5..b83b465 100644 --- a/src/app/message.rs +++ b/src/app/message.rs @@ -22,6 +22,8 @@ pub enum Message { EnrollStatus(String, bool), EnrollStop, DeleteComplete, + ClearDevice, + ClearComplete(Result<(), AppError>), EnrolledFingers(Vec), UsersFound(Vec), UserSelected(UserOption), diff --git a/src/app/mod.rs b/src/app/mod.rs index 1cc3dec..a8ca04d 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -27,7 +27,7 @@ use page::{ContextPage, Page}; use message::{Message, UserOption}; use fprint::{ delete_fingerprint_dbus, delete_fingers, enroll_fingerprint_process, find_device, - list_enrolled_fingers_dbus, + clear_all_fingers_dbus,list_enrolled_fingers_dbus, }; use error::AppError; @@ -76,6 +76,8 @@ pub struct AppModel { selected_user: Option, // List of enrolled fingers enrolled_fingers: Vec, + // Confirmation state for clearing the device + confirm_clear: bool, } /// Create a COSMIC application from the app model @@ -151,6 +153,7 @@ impl cosmic::Application for AppModel { realname: Arc::new(u.gecos.to_string_lossy().into_owned()), }), enrolled_fingers: Vec::new(), + confirm_clear: false, }; // Create a startup command that sets the window title. @@ -352,6 +355,22 @@ impl cosmic::Application for AppModel { Message::Delete => self.on_delete(), + Message::ClearDevice => self.on_clear_device(), + + Message::ClearComplete(res) => { + match res { + Ok(_) => { + self.status = fl!("device-cleared"); + self.enrolled_fingers.clear(); + } + Err(e) => { + self.status = e.localized_message(); + } + } + self.busy = false; + Task::none() + } + Message::Register => self.on_register(), Message::OpenRepositoryUrl => { @@ -393,7 +412,7 @@ impl cosmic::Application for AppModel { if self.busy { return Task::none(); } - + self.confirm_clear = false; // Activate the page in the model. self.nav.activate(id); @@ -574,7 +593,7 @@ impl AppModel { if self.busy { return Task::none(); } - + self.confirm_clear = false; self.selected_user = Some(user.clone()); self.enrolled_fingers.clear(); self.list_fingers_task() @@ -659,6 +678,32 @@ impl AppModel { Task::none() } + fn on_clear_device(&mut self) -> Task> { + if !self.confirm_clear { + self.confirm_clear = true; + self.status = fl!("clear-device-confirm"); + return Task::none(); + } + + if let (Some(path), Some(conn)) = (self.device_path.clone(), self.connection.clone()) { + self.status = fl!("clearing-device"); + self.busy = true; + self.confirm_clear = false; + let path = (*path).clone(); + let usernames: Vec = self.users.iter().map(|u| (*u.username).clone()).collect(); + return Task::perform( + async move { + match clear_all_fingers_dbus(&conn, path, usernames).await { + Ok(_) => Message::ClearComplete(Ok(())), + Err(e) => Message::ClearComplete(Err(AppError::from(e))), + } + }, + cosmic::Action::App, + ); + } + Task::none() + } + fn on_delete(&mut self) -> Task> { if let Some(page) = self.nav.data::(self.nav.active()) && let (Some(path), Some(conn), Some(user)) = ( @@ -796,6 +841,12 @@ impl AppModel { let register_btn = widget::button::text(fl!("register")); let delete_btn = widget::button::text(fl!("delete")); + let clear_text = if self.confirm_clear { + fl!("confirm-clear") + } else { + fl!("clear-device") + }; + let clear_btn = widget::button::text(clear_text); let register_btn = if buttons_enabled && current_finger.is_some() { register_btn.on_press(Message::Register) @@ -809,6 +860,13 @@ impl AppModel { delete_btn }; + let clear_btn = if !self.busy && self.device_path.is_some() && self.enrolling_finger.is_none() + { + clear_btn.on_press(Message::ClearDevice) + } else { + clear_btn + }; + let mut cancel_btn = widget::button::text(fl!("cancel")); if self.enrolling_finger.is_some() { cancel_btn = cancel_btn.on_press(Message::EnrollStop); @@ -816,7 +874,8 @@ impl AppModel { let mut row = widget::row() .push(register_btn) - .push(delete_btn); + .push(delete_btn) + .push(clear_btn); if self.enrolling_finger.is_some() { row = row.push(cancel_btn);