From e339ee2c4a14077cf8869e4aeea79180966fa858 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:30:35 +0000 Subject: [PATCH] Implement confirmation dialog for "Clear Device" and fix missing bulk deletion logic. - Added `delete_fingers` to `src/app/fprint.rs` for user-specific bulk fingerprint deletion. - Added `Message::CancelClear` to handle dialog dismissal. - Implemented `Application::dialog` in `src/app/mod.rs` to provide a modal confirmation for the "Clear Device" action. - Updated `AppModel::update` and `AppModel::view_controls` to support the new dialog-based workflow. - Bumped version to `0.3.11` and updated `CHANGES`. --- CHANGES | 3 + Cargo.toml | 2 +- cargo_check.log | 322 ++++++++++++++++++ flatpak/fi.joonastuomi.Fprint.yml | 4 +- i18n/en/cosmic_ext_fprint.ftl | 6 + justfile | 6 +- ....desktop => fi.joonastuomi.Fprint.desktop} | 0 ...xml => fi.joonastuomi.Fprint.metainfo.xml} | 0 src/app/fprint.rs | 56 +++ src/app/message.rs | 3 + src/app/mod.rs | 156 +++++++-- src/app/page.rs | 51 +-- test_dialog.rs | 2 + 13 files changed, 557 insertions(+), 54 deletions(-) create mode 100644 cargo_check.log rename resources/{app.desktop => fi.joonastuomi.Fprint.desktop} (100%) rename resources/{app.metainfo.xml => fi.joonastuomi.Fprint.metainfo.xml} (100%) create mode 100644 test_dialog.rs diff --git a/CHANGES b/CHANGES index bfafc6a..58eff22 100644 --- a/CHANGES +++ b/CHANGES @@ -23,3 +23,6 @@ - Fallback to finding user with libc instead of enviroment variable - Swedish translation thanks to @bittin - Finnish translation +0.3.11: + - Implement a confirmation dialog for "Clear Device" operation + - Fix missing bulk deletion logic for all fingerprints of a user diff --git a/Cargo.toml b/Cargo.toml index a75fcf1..aab6fa8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmic-ext-fprint" -version = "0.3.10" +version = "0.3.11" edition = "2024" license = "MPL-2.0" description = "GUI for fprintd fingerprint enrolling" diff --git a/cargo_check.log b/cargo_check.log new file mode 100644 index 0000000..81aee02 --- /dev/null +++ b/cargo_check.log @@ -0,0 +1,322 @@ + Checking x11rb v0.13.2 + Checking atspi-proxies v0.3.0 + Checking accesskit_atspi_common v0.9.0 (https://github.com/wash2/accesskit?tag=iced-xdg-surface-0.13-rc#c46afc04) + Compiling smithay-client-toolkit v0.20.0 + Compiling generic-array v0.14.7 + Checking calloop-wayland-source v0.4.1 + Checking concurrent-queue v2.5.0 + Checking dnd v0.1.0 (https://github.com/pop-os/window_clipboard.git?tag=pop-0.13-2#6b9faab8) + Compiling phf_macros v0.11.3 + Checking slotmap v1.1.1 + Checking phf_shared v0.11.3 + Checking xkbcommon v0.8.0 + Checking wayland-protocols-misc v0.3.10 + Checking wayland-protocols-experimental v20250721.0.1 + Checking roxmltree v0.20.0 + Checking atspi-connection v0.3.0 + Checking winit v0.30.5 (https://github.com/pop-os/winit.git?tag=iced-xdg-surface-0.13-rc#dd46a149) + Checking tinyvec_macros v0.1.1 + Compiling palette v0.7.6 + Checking atspi v0.19.0 + Checking accesskit_unix v0.12.0 (https://github.com/wash2/accesskit?tag=iced-xdg-surface-0.13-rc#c46afc04) + Compiling by_address v1.2.1 + Compiling winnow v0.7.14 + Compiling palette_derive v0.7.6 + Checking fontconfig-parser v0.5.8 + Checking tinyvec v1.10.0 + Checking clipboard_x11 v0.4.2 (https://github.com/pop-os/window_clipboard.git?tag=pop-0.13-2#6b9faab8) + Checking phf v0.11.3 + Checking clipboard_wayland v0.2.2 (https://github.com/pop-os/window_clipboard.git?tag=pop-0.13-2#6b9faab8) + Compiling rustversion v1.0.22 + Checking cosmic-protocols v0.1.0 (https://github.com/pop-os/cosmic-protocols?rev=d0e95be#d0e95be2) + Checking approx v0.5.1 + Checking fast-srgb8 v1.0.0 + Checking accesskit_winit v0.22.0 (https://github.com/wash2/accesskit?tag=iced-xdg-surface-0.13-rc#c46afc04) + Checking iced_accessibility v0.1.0 (https://github.com/pop-os/libcosmic.git#dc3c194f) + Checking window_clipboard v0.4.1 (https://github.com/pop-os/window_clipboard.git?tag=pop-0.13-2#6b9faab8) + Compiling toml_parser v1.0.9+spec-1.1.0 + Compiling crypto-common v0.1.7 + Compiling block-buffer v0.10.4 + Checking futures-executor v0.3.32 + Checking font-types v0.11.0 + Checking font-types v0.10.1 + Checking web-time v1.1.0 + Checking equivalent v1.0.2 + Checking cosmic-client-toolkit v0.1.0 (https://github.com/pop-os/cosmic-protocols?rev=d0e95be#d0e95be2) + Checking rustc-hash v1.1.0 + Checking unicode-script v0.5.8 + Compiling toml_datetime v0.7.5+spec-1.1.0 + Compiling libc v0.2.180 + Checking glam v0.25.0 + Checking hashbrown v0.16.1 + Compiling toml_edit v0.23.10+spec-1.0.0 + Checking indexmap v2.13.0 + Checking read-fonts v0.35.0 + Checking read-fonts v0.37.0 + Checking futures v0.3.32 + Compiling digest v0.10.7 + Checking lyon_geom v1.0.18 + Compiling thiserror v1.0.69 + Checking unicode-bidi v0.3.18 + Checking unicode-ident v1.0.24 + Compiling cpufeatures v0.2.17 + Compiling same-file v1.0.6 + Compiling walkdir v2.5.0 + Compiling sha2 v0.10.9 + Checking lyon_path v1.0.16 + Compiling proc-macro-crate v3.4.0 + Checking iced_core v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Compiling zvariant_utils v3.3.0 + Checking iced_futures v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Checking skrifa v0.37.0 + Checking event-listener v5.4.1 + Compiling naga v22.1.0 + Checking unic-langid-impl v0.9.6 + Compiling khronos-egl v6.0.0 + Checking yazi v0.2.1 + Compiling ash v0.38.0+1.3.281 + Checking foldhash v0.1.5 + Compiling rustc-hash v2.1.1 + Checking bit-vec v0.7.0 + Compiling smallvec v1.15.1 + Checking zeno v0.3.3 + Checking unicode-width v0.1.14 + Checking termcolor v1.4.1 + Checking sys-locale v0.3.2 + Checking bit-set v0.6.0 + Checking codespan-reporting v0.11.1 + Compiling type-map v0.5.1 + Checking hashbrown v0.15.5 + Checking event-listener-strategy v0.5.4 + Checking unic-langid v0.9.6 + Compiling zvariant_derive v5.9.2 + Checking harfrust v0.5.0 + Checking skrifa v0.40.0 + Checking swash v0.2.6 + Compiling rust-embed-utils v8.11.0 + Checking proc-macro2 v1.0.106 + Checking fontdb v0.23.0 + Compiling wgpu-hal v22.0.0 + Checking futures-lite v2.6.1 + Checking pxfm v0.1.27 + Checking gpu-alloc-types v0.3.0 + Checking spirv v0.3.0+sdk-1.3.268.0 + Checking gpu-descriptor-types v0.2.0 + Checking hexf-parse v0.2.1 + Compiling drm-sys v0.6.1 + Checking ttf-parser v0.21.1 + Checking smol_str v0.3.5 + Checking linebender_resource_handle v0.1.1 + Compiling self_cell v1.2.2 + Checking zune-core v0.5.1 + Checking unicode-xid v0.2.6 + Checking unicode-linebreak v0.1.5 + Checking rangemap v1.7.1 + Checking unicode-segmentation v1.12.0 + Checking zune-jpeg v0.5.12 + Checking cosmic-text v0.17.1 (https://github.com/pop-os/cosmic-text.git#d7dc22dd) + Checking moxcms v0.7.11 + Checking gpu-descriptor v0.3.2 + Checking gpu-alloc v0.6.0 + Checking quote v1.0.44 + Compiling rust-embed-impl v8.11.0 + Compiling intl-memoizer v0.5.3 + Compiling fluent-langneg v0.13.1 + Compiling intl_pluralrules v7.0.2 + Compiling wgpu-core v22.1.0 + Checking png v0.18.1 + Compiling toml v0.5.11 + Compiling basic-toml v0.1.10 + Checking kurbo v0.11.3 + Compiling tiny-xlib v0.2.4 + Compiling async-io v2.6.0 + Checking wgpu-types v22.0.0 + Compiling uncased v0.9.10 + Compiling drm-fourcc v2.2.0 + Checking mutate_once v0.1.2 + Compiling litrs v1.0.0 + Checking unicode-bidi-mirroring v0.2.0 + Checking unicode-ccc v0.2.0 + Checking profiling v1.0.17 + Checking byteorder-lite v0.1.0 + Compiling log v0.4.29 + Checking linux-raw-sys v0.6.5 + Checking glow v0.13.1 + Checking unicode-properties v0.1.4 + Checking renderdoc-sys v1.1.0 + Checking rustybuzz v0.14.1 + Compiling i18n-config v0.4.8 + Compiling document-features v0.2.12 + Checking image v0.25.9 + Checking kamadak-exif v0.5.5 + Checking svgtypes v0.15.3 + Compiling find-crate v0.6.3 + Checking syn v2.0.116 + Checking fontdb v0.18.0 + Compiling wgpu v22.1.0 + Checking half v2.7.1 + Compiling enumflags2 v0.7.12 + Checking simplecss v0.2.2 + Checking xmlwriter v0.1.0 + Checking data-url v0.3.2 + Checking weezl v0.1.12 + Checking litemap v0.8.1 + Checking color_quant v1.1.0 + Checking async-task v4.7.1 + Checking pico-args v0.5.0 + Compiling endi v1.1.1 + Checking base64 v0.22.1 + Checking ctor-lite v0.1.2 + Checking svg_fmt v0.4.5 + Checking writeable v0.6.2 + Checking imagesize v0.12.0 + Checking unicode-vo v0.1.0 + Checking usvg v0.42.0 + Checking icu_locale_core v2.1.1 + Compiling zvariant v5.9.2 + Checking gif v0.13.3 + Checking iced_graphics v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Compiling i18n-embed-impl v0.8.4 + Checking drm-ffi v0.7.1 + Checking async-channel v2.5.0 + Checking potential_utf v0.1.4 + Compiling softbuffer v0.4.1 (https://github.com/pop-os/softbuffer?tag=cosmic-4.0#a3f77e25) + Checking zerotrie v0.2.3 + Checking aho-corasick v1.1.4 + Checking rgb v0.8.52 + Compiling proc-macro2-diagnostics v0.10.1 + Checking atomic-waker v1.1.2 + Compiling icu_normalizer_data v2.1.1 + Checking float_next_after v1.0.0 + Compiling icu_properties_data v2.1.2 + Compiling scopeguard v1.2.0 + Compiling strsim v0.11.1 + Checking regex-syntax v0.8.9 + Compiling getrandom v0.4.1 + Checking jpeg-decoder v0.3.2 + Compiling lock_api v0.4.14 + Checking lyon_tessellation v1.0.16 + Checking resvg v0.42.0 + Compiling zbus_names v4.3.1 + Checking piper v0.2.4 + Checking regex-automata v0.4.14 + Checking icu_provider v2.1.1 + Checking icu_collections v2.1.1 + Checking drm v0.11.1 + Checking async-signal v0.2.13 + Compiling phf_shared v0.13.1 + Checking etagere v0.2.15 + Checking async-lock v3.4.2 + Compiling parking_lot_core v0.9.12 + Checking lyon_algorithms v1.0.16 + Compiling thiserror v2.0.18 + Compiling typeid v1.0.3 + Compiling yansi v1.0.1 + Compiling fastrand v2.3.0 + Checking lru v0.12.5 + Compiling phf_generator v0.13.1 + Checking lyon v1.0.16 + Compiling fluent-syntax v0.12.0 + Checking async-process v2.5.0 + Compiling parking_lot v0.12.5 + Compiling zbus_macros v5.13.2 + Checking blocking v1.6.2 + Checking guillotiere v0.6.2 + Checking async-executor v1.14.0 + Compiling rust-embed v8.11.0 + Checking async-broadcast v0.7.2 + Compiling arc-swap v1.8.2 + Checking kurbo v0.10.4 + Checking inotify-sys v0.1.5 + Checking uuid v1.21.0 + Compiling powerfmt v0.2.0 + Compiling fnv v1.0.7 + Compiling zmij v1.0.21 + Compiling ident_case v1.0.1 + Compiling anyhow v1.0.101 + Compiling heck v0.4.1 + Checking option-ext v0.2.0 + Compiling ouroboros_macro v0.18.5 + Checking dirs-sys v0.5.0 + Compiling darling_core v0.21.3 + Checking zbus v5.13.2 + Checking iced_tiny_skia v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Compiling deranged v0.5.6 + Checking inotify v0.11.0 + Checking tempfile v3.25.0 + Checking icu_properties v2.1.2 + Checking icu_normalizer v2.1.1 + Compiling fluent-bundle v0.16.0 + Compiling phf_macros v0.13.1 + Compiling self_cell v0.10.3 + Checking iced_runtime v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Checking iced_glyphon v0.6.0 (https://github.com/pop-os/glyphon.git?tag=iced-0.14-dev#6ef9d12a) + Checking iced_wgpu v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Compiling fluent-syntax v0.11.1 + Compiling vergen v8.3.2 + Checking memmap2 v0.8.0 + Checking notify-types v2.1.0 + Compiling proc-macro-error-attr2 v2.0.0 + Checking aliasable v0.1.3 + Compiling num_threads v0.1.7 + Compiling time-core v0.1.8 + Compiling num-conv v0.2.0 + Compiling itoa v1.0.17 + Checking xdg v3.0.0 + Compiling serde_json v1.0.149 + Compiling time v0.3.47 + Compiling fluent-bundle v0.15.3 + Compiling proc-macro-error2 v2.0.1 + Checking iced_renderer v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Checking cosmic-settings-daemon v0.1.0 (https://github.com/pop-os/dbus-settings-bindings#0fa672f8) + Checking ouroboros v0.18.5 + Checking notify v8.2.0 + Checking xkbcommon v0.7.0 + Checking phf v0.13.1 + Checking ron v0.12.0 + Checking idna_adapter v1.2.1 + Compiling fluent v0.17.0 + Checking atomicwrites v0.4.2 (https://github.com/jackpot51/rust-atomicwrites#043ab485) + Compiling darling_macro v0.21.3 + Checking dirs v6.0.0 + Compiling cosmic-config-derive v1.0.0 (https://github.com/pop-os/libcosmic.git#dc3c194f) + Checking utf8_iter v1.0.4 + Checking idna v1.1.0 + Checking cosmic-config v1.0.0 (https://github.com/pop-os/libcosmic.git#dc3c194f) + Compiling darling v0.21.3 + Checking iced_winit v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Compiling i18n-embed v0.16.0 + Checking csscolorparser v0.8.2 + Checking iced_widget v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Compiling fluent v0.16.1 + Checking bstr v1.12.1 + Checking regex v1.12.3 + Checking form_urlencoded v1.2.2 + Compiling nix v0.31.1 + Checking btoi v0.5.0 + Checking is-docker v0.2.0 + Compiling derive_utils v0.15.0 + Checking lazy_static v1.5.0 + Checking grid v1.0.0 + Checking almost v0.2.0 + Compiling libcosmic v1.0.0 (https://github.com/pop-os/libcosmic.git#dc3c194f) + Checking configparser v3.1.0 + Compiling auto_enums v0.8.7 + Checking cosmic-theme v1.0.0 (https://github.com/pop-os/libcosmic.git#dc3c194f) + Checking taffy v0.9.2 + Checking locale_config v0.3.0 + Checking is-wsl v0.4.0 + Checking cosmic-freedesktop-icons v0.4.0 (https://github.com/pop-os/freedesktop-icons#7a61a704) + Checking url v2.5.8 + Compiling i18n-embed-fl v0.10.0 + Compiling i18n-embed v0.15.4 + Checking iced v0.14.0-dev (https://github.com/pop-os/libcosmic.git#dc3c194f) + Compiling cosmic-ext-fprint v0.3.10 (/app) + Compiling derive_setters v0.1.9 + Checking css-color v0.2.8 + Checking apply v0.3.0 + Checking pathdiff v0.2.3 + Checking jiff v0.2.20 + Checking open v5.3.3 + Compiling i18n-embed-fl v0.9.4 + Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 17s diff --git a/flatpak/fi.joonastuomi.Fprint.yml b/flatpak/fi.joonastuomi.Fprint.yml index 4449570..14849b9 100644 --- a/flatpak/fi.joonastuomi.Fprint.yml +++ b/flatpak/fi.joonastuomi.Fprint.yml @@ -33,10 +33,10 @@ modules: - install -Dm0755 target/release/cosmic-ext-fprint /app/bin/cosmic-ext-fprint # Install the desktop file - - install -Dm0644 resources/app.desktop /app/share/applications/fi.joonastuomi.Fprint.desktop + - install -Dm0644 resources/fi.joonastuomi.Fprint.desktop /app/share/applications/fi.joonastuomi.Fprint.desktop # Install the AppStream metadata - - install -Dm0644 resources/app.metainfo.xml /app/share/appdata/fi.joonastuomi.Fprint.metainfo.xml + - install -Dm0644 resources/fi.joonastuomi.Fprint.metainfo.xml /app/share/appdata/fi.joonastuomi.Fprint.metainfo.xml # Install the icon - install -Dm0644 resources/icons/hicolor/scalable/apps/icon.svg /app/share/icons/hicolor/scalable/apps/fi.joonastuomi.Fprint.svg diff --git a/i18n/en/cosmic_ext_fprint.ftl b/i18n/en/cosmic_ext_fprint.ftl index 96b4dc4..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 @@ -20,6 +25,7 @@ page-left-index-finger = Left Index Finger page-left-middle-finger = Left Middle Finger page-left-ring-finger = Left Ring Finger page-left-little-finger = Left Little Finger +page-delete-all-users-prints = Delete All User's Prints status-connecting = Connecting to system bus... status-searching-device = Searching for fingerprint reader... diff --git a/justfile b/justfile index 13a4adc..ad3cc29 100644 --- a/justfile +++ b/justfile @@ -1,5 +1,5 @@ name := 'cosmic-ext-fprint' -appid := 'fi.joonastuomi.CosmicFprint' +appid := 'fi.joonastuomi.Fprint' rootdir := '' prefix := '/usr' @@ -61,8 +61,8 @@ run *args: # Installs files install: install -Dm0755 {{bin-src}} {{bin-dst}} - install -Dm0644 resources/app.desktop {{desktop-dst}} - install -Dm0644 resources/app.metainfo.xml {{appdata-dst}} + install -Dm0644 {{desktop-src}} {{desktop-dst}} + install -Dm0644 {{appdata-src}} {{appdata-dst}} install -Dm0644 {{icon-svg-src}} {{icon-svg-dst}} # Uninstalls installed files diff --git a/resources/app.desktop b/resources/fi.joonastuomi.Fprint.desktop similarity index 100% rename from resources/app.desktop rename to resources/fi.joonastuomi.Fprint.desktop diff --git a/resources/app.metainfo.xml b/resources/fi.joonastuomi.Fprint.metainfo.xml similarity index 100% rename from resources/app.metainfo.xml rename to resources/fi.joonastuomi.Fprint.metainfo.xml diff --git a/src/app/fprint.rs b/src/app/fprint.rs index 51c02a7..0cb1b86 100644 --- a/src/app/fprint.rs +++ b/src/app/fprint.rs @@ -39,6 +39,62 @@ pub async fn delete_fingerprint_dbus( res.and(rel_res) } +pub async fn delete_fingers( + connection: &zbus::Connection, + path: zbus::zvariant::OwnedObjectPath, + username: String, +) -> zbus::Result<()> { + let device = DeviceProxy::builder(connection).path(path)?.build().await?; + device.claim(&username).await?; + + let fingers = device.list_enrolled_fingers(&username).await?; + for finger in fingers { + device.delete_enrolled_finger(&finger).await?; + } + + device.release().await?; + Ok(()) +} + +pub async fn clear_all_fingers_dbus( + connection: &zbus::Connection, + path: zbus::zvariant::OwnedObjectPath, + usernames: Vec, +) -> zbus::Result<()> { + let device = DeviceProxy::builder(connection).path(path)?.build().await?; + let mut last_error = None; + + 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(()) + } +} + pub async fn enroll_fingerprint_process( connection: zbus::Connection, path: zbus::zvariant::OwnedObjectPath, diff --git a/src/app/message.rs b/src/app/message.rs index e9095b5..d65f3b2 100644 --- a/src/app/message.rs +++ b/src/app/message.rs @@ -22,6 +22,9 @@ pub enum Message { EnrollStatus(String, bool), EnrollStop, DeleteComplete, + ClearDevice, + CancelClear, + ClearComplete(Result<(), AppError>), EnrolledFingers(Vec), UsersFound(Vec), UserSelected(UserOption), diff --git a/src/app/mod.rs b/src/app/mod.rs index e0ae5fa..9ef3072 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -10,7 +10,7 @@ use cosmic::iced::alignment::{Horizontal, Vertical}; use cosmic::iced::widget::pick_list; use cosmic::iced::{Alignment, Length, Subscription}; use cosmic::prelude::*; -use cosmic::widget::{self, icon, menu, nav_bar, text}; +use cosmic::widget::{self, icon, menu, nav_bar, text, dialog}; use cosmic::{cosmic_theme, theme}; use futures_util::stream::{self, StreamExt}; use futures_util::SinkExt; @@ -26,7 +26,8 @@ pub mod error; use page::{ContextPage, Page}; use message::{Message, UserOption}; use fprint::{ - delete_fingerprint_dbus, enroll_fingerprint_process, find_device, list_enrolled_fingers_dbus, + delete_fingerprint_dbus, delete_fingers, enroll_fingerprint_process, find_device, + clear_all_fingers_dbus,list_enrolled_fingers_dbus, }; use error::AppError; @@ -75,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 @@ -150,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. @@ -202,6 +206,27 @@ impl cosmic::Application for AppModel { }) } + /// Display a dialog in the center of the application window when `Some`. + fn dialog(&self) -> Option> { + if self.confirm_clear { + Some( + dialog::dialog() + .title(fl!("clear-device")) + .body(fl!("clear-device-confirm")) + .primary_action( + widget::button::destructive(fl!("clear-device")) + .on_press(Message::ClearDevice), + ) + .secondary_action( + widget::button::standard(fl!("cancel")).on_press(Message::CancelClear), + ) + .into(), + ) + } else { + None + } + } + /// Describes the interface based on the current state of the application model. /// /// Application events will be processed through the view. Any messages emitted by @@ -339,18 +364,39 @@ impl cosmic::Application for AppModel { Message::DeleteComplete => { self.status = fl!("deleted"); self.busy = false; - self.enrolled_fingers.retain(|f| { - f != self - .nav - .data::(self.nav.active()) - .map(|p| p.as_finger_id()) - .unwrap_or_default() - }); + if let Some(page) = self.nav.data::(self.nav.active()) { + if let Some(finger_id) = page.as_finger_id() { + self.enrolled_fingers.retain(|f| f != finger_id); + } else { + self.enrolled_fingers.clear(); + } + } Task::none() } Message::Delete => self.on_delete(), + Message::ClearDevice => self.on_clear_device(), + + Message::CancelClear => { + self.confirm_clear = false; + Task::none() + } + + 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 => { @@ -389,6 +435,10 @@ impl cosmic::Application for AppModel { /// Called when a nav item is selected. fn on_nav_select(&mut self, id: nav_bar::Id) -> Task> { + if self.busy { + return Task::none(); + } + self.confirm_clear = false; // Activate the page in the model. self.nav.activate(id); @@ -566,6 +616,10 @@ impl AppModel { } fn on_user_selected(&mut self, user: UserOption) -> Task> { + if self.busy { + return Task::none(); + } + self.confirm_clear = false; self.selected_user = Some(user.clone()); self.enrolled_fingers.clear(); self.list_fingers_task() @@ -650,6 +704,31 @@ impl AppModel { Task::none() } + fn on_clear_device(&mut self) -> Task> { + if !self.confirm_clear { + self.confirm_clear = true; + 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)) = ( @@ -660,29 +739,43 @@ impl AppModel { { self.status = fl!("deleting"); self.busy = true; - let finger_name = page.as_finger_id().to_string(); let path = (*path).clone(); let username = (*user.username).clone(); - return Task::perform( - async move { - match delete_fingerprint_dbus(&conn, path, finger_name, username).await { - Ok(_) => Message::DeleteComplete, - Err(e) => Message::OperationError(AppError::from(e)), - } - }, - cosmic::Action::App, - ); + + if let Some(finger_name) = page.as_finger_id() { + let finger_name = finger_name.to_string(); + return Task::perform( + async move { + match delete_fingerprint_dbus(&conn, path, finger_name, username).await { + Ok(_) => Message::DeleteComplete, + Err(e) => Message::OperationError(AppError::from(e)), + } + }, + cosmic::Action::App, + ); + } else { + return Task::perform( + async move { + match delete_fingers(&conn, path, username).await { + Ok(_) => Message::DeleteComplete, + Err(e) => Message::OperationError(AppError::from(e)), + } + }, + cosmic::Action::App, + ); + } } Task::none() } fn on_register(&mut self) -> Task> { if let Some(page) = self.nav.data::(self.nav.active()) + && let Some(finger_id) = page.as_finger_id() && self.device_path.is_some() && self.selected_user.is_some() { self.busy = true; - self.enrolling_finger = Some(Arc::new(page.as_finger_id().to_string())); + self.enrolling_finger = Some(Arc::new(finger_id.to_string())); self.status = fl!("status-starting-enrollment"); } Task::none() @@ -764,15 +857,18 @@ impl AppModel { !self.busy && self.device_path.is_some() && self.enrolling_finger.is_none(); let current_page = self.nav.data::(self.nav.active()); - let current_finger = current_page.map(|p| p.as_finger_id()); - let is_enrolled = current_finger - .map(|f| self.enrolled_fingers.iter().any(|ef| ef == f)) - .unwrap_or(false); + let current_finger = current_page.and_then(|p| p.as_finger_id()); + let is_enrolled = if let Some(f) = current_finger { + self.enrolled_fingers.iter().any(|ef| ef == f) + } else { + !self.enrolled_fingers.is_empty() + }; let register_btn = widget::button::text(fl!("register")); let delete_btn = widget::button::text(fl!("delete")); + let clear_btn = widget::button::text(fl!("clear-device")); - let register_btn = if buttons_enabled { + let register_btn = if buttons_enabled && current_finger.is_some() { register_btn.on_press(Message::Register) } else { register_btn @@ -784,6 +880,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); @@ -791,7 +894,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); diff --git a/src/app/page.rs b/src/app/page.rs index 5103f64..c8782e0 100644 --- a/src/app/page.rs +++ b/src/app/page.rs @@ -16,6 +16,7 @@ pub enum Page { LeftMiddle, LeftRing, LeftPinky, + DeleteAllUsersPrints, } impl Page { @@ -31,6 +32,7 @@ impl Page { Self::LeftMiddle, Self::LeftRing, Self::LeftPinky, + Self::DeleteAllUsersPrints, ] } @@ -46,21 +48,23 @@ impl Page { Self::LeftMiddle => fl!("page-left-middle-finger"), Self::LeftRing => fl!("page-left-ring-finger"), Self::LeftPinky => fl!("page-left-little-finger"), + Self::DeleteAllUsersPrints => fl!("page-delete-all-users-prints"), } } - pub fn as_finger_id(&self) -> &'static str { + pub fn as_finger_id(&self) -> Option<&'static str> { match self { - Page::RightThumb => "right-thumb", - Page::RightIndex => "right-index-finger", - Page::RightMiddle => "right-middle-finger", - Page::RightRing => "right-ring-finger", - Page::RightPinky => "right-little-finger", - Page::LeftThumb => "left-thumb", - Page::LeftIndex => "left-index-finger", - Page::LeftMiddle => "left-middle-finger", - Page::LeftRing => "left-ring-finger", - Page::LeftPinky => "left-little-finger", + Page::RightThumb => Some("right-thumb"), + Page::RightIndex => Some("right-index-finger"), + Page::RightMiddle => Some("right-middle-finger"), + Page::RightRing => Some("right-ring-finger"), + Page::RightPinky => Some("right-little-finger"), + Page::LeftThumb => Some("left-thumb"), + Page::LeftIndex => Some("left-index-finger"), + Page::LeftMiddle => Some("left-middle-finger"), + Page::LeftRing => Some("left-ring-finger"), + Page::LeftPinky => Some("left-little-finger"), + Page::DeleteAllUsersPrints => None, } } } @@ -79,7 +83,7 @@ mod tests { #[test] fn test_page_all() { let pages = Page::all(); - assert_eq!(pages.len(), 10); + assert_eq!(pages.len(), 11); assert_eq!(pages[0], Page::RightThumb); assert_eq!(pages[1], Page::RightIndex); assert_eq!(pages[2], Page::RightMiddle); @@ -90,6 +94,7 @@ mod tests { assert_eq!(pages[7], Page::LeftMiddle); assert_eq!(pages[8], Page::LeftRing); assert_eq!(pages[9], Page::LeftPinky); + assert_eq!(pages[10], Page::DeleteAllUsersPrints); } #[test] @@ -106,19 +111,21 @@ mod tests { assert!(!Page::LeftMiddle.localized_name().is_empty()); assert!(!Page::LeftRing.localized_name().is_empty()); assert!(!Page::LeftPinky.localized_name().is_empty()); + assert!(!Page::DeleteAllUsersPrints.localized_name().is_empty()); } #[test] fn test_page_as_finger_id() { - assert_eq!(Page::RightThumb.as_finger_id(), "right-thumb"); - assert_eq!(Page::RightIndex.as_finger_id(), "right-index-finger"); - assert_eq!(Page::RightMiddle.as_finger_id(), "right-middle-finger"); - assert_eq!(Page::RightRing.as_finger_id(), "right-ring-finger"); - assert_eq!(Page::RightPinky.as_finger_id(), "right-little-finger"); - assert_eq!(Page::LeftThumb.as_finger_id(), "left-thumb"); - assert_eq!(Page::LeftIndex.as_finger_id(), "left-index-finger"); - assert_eq!(Page::LeftMiddle.as_finger_id(), "left-middle-finger"); - assert_eq!(Page::LeftRing.as_finger_id(), "left-ring-finger"); - assert_eq!(Page::LeftPinky.as_finger_id(), "left-little-finger"); + assert_eq!(Page::RightThumb.as_finger_id(), Some("right-thumb")); + assert_eq!(Page::RightIndex.as_finger_id(), Some("right-index-finger")); + assert_eq!(Page::RightMiddle.as_finger_id(), Some("right-middle-finger")); + assert_eq!(Page::RightRing.as_finger_id(), Some("right-ring-finger")); + assert_eq!(Page::RightPinky.as_finger_id(), Some("right-little-finger")); + assert_eq!(Page::LeftThumb.as_finger_id(), Some("left-thumb")); + assert_eq!(Page::LeftIndex.as_finger_id(), Some("left-index-finger")); + assert_eq!(Page::LeftMiddle.as_finger_id(), Some("left-middle-finger")); + assert_eq!(Page::LeftRing.as_finger_id(), Some("left-ring-finger")); + assert_eq!(Page::LeftPinky.as_finger_id(), Some("left-little-finger")); + assert_eq!(Page::DeleteAllUsersPrints.as_finger_id(), None); } } diff --git a/test_dialog.rs b/test_dialog.rs new file mode 100644 index 0000000..ac2465d --- /dev/null +++ b/test_dialog.rs @@ -0,0 +1,2 @@ +use libcosmic::widget::dialog; +fn main() {}