From 91882abc3c1002cdbb81cf25c21823e5204b594a Mon Sep 17 00:00:00 2001 From: lashman Date: Sat, 28 Feb 2026 01:50:38 +0200 Subject: [PATCH] Consolidate preferences into General and Updates pages --- src/ui/preferences.rs | 259 +++++++++++++++++------------------------- 1 file changed, 105 insertions(+), 154 deletions(-) diff --git a/src/ui/preferences.rs b/src/ui/preferences.rs index 27fa269..7202a30 100644 --- a/src/ui/preferences.rs +++ b/src/ui/preferences.rs @@ -13,8 +13,7 @@ pub fn show_preferences_dialog(parent: &impl IsA) { let settings = gio::Settings::new(APP_ID); dialog.add(&build_general_page(&settings, &dialog)); - dialog.add(&build_behavior_page(&settings)); - dialog.add(&build_security_page(&settings)); + dialog.add(&build_updates_page(&settings)); dialog.present(Some(parent)); } @@ -30,7 +29,6 @@ fn build_general_page(settings: &gio::Settings, dialog: &adw::PreferencesDialog) // Appearance group let appearance_group = adw::PreferencesGroup::builder() .title(&i18n("Appearance")) - .description(&i18n("Visual preferences for the application")) .build(); let theme_row = adw::ComboRow::builder() @@ -155,7 +153,58 @@ fn build_general_page(settings: &gio::Settings, dialog: &adw::PreferencesDialog) scan_group.add(&add_button); page.add(&scan_group); - // Desktop Integration group - AppStream catalog for GNOME Software/Discover + // Automation group + let automation_group = adw::PreferencesGroup::builder() + .title(&i18n("Automation")) + .build(); + + let auto_scan_row = adw::SwitchRow::builder() + .title(&i18n("Scan on startup")) + .subtitle(&i18n("Automatically scan for new AppImages when the app starts")) + .active(settings.boolean("auto-scan-on-startup")) + .build(); + let settings_scan = settings.clone(); + auto_scan_row.connect_active_notify(move |row| { + settings_scan.set_boolean("auto-scan-on-startup", row.is_active()).ok(); + }); + automation_group.add(&auto_scan_row); + + let auto_integrate_row = adw::SwitchRow::builder() + .title(&i18n("Auto-integrate new AppImages")) + .subtitle(&i18n("Automatically add newly discovered AppImages to the desktop menu")) + .active(settings.boolean("auto-integrate")) + .build(); + let settings_int = settings.clone(); + auto_integrate_row.connect_active_notify(move |row| { + settings_int.set_boolean("auto-integrate", row.is_active()).ok(); + }); + automation_group.add(&auto_integrate_row); + + let removable_row = adw::SwitchRow::builder() + .title(&i18n("Watch removable media")) + .subtitle(&i18n("Scan USB drives and other removable media for AppImages")) + .active(settings.boolean("watch-removable-media")) + .build(); + let settings_rem = settings.clone(); + removable_row.connect_active_notify(move |row| { + settings_rem.set_boolean("watch-removable-media", row.is_active()).ok(); + }); + automation_group.add(&removable_row); + + let confirm_row = adw::SwitchRow::builder() + .title(&i18n("Confirm before delete")) + .subtitle(&i18n("Show a confirmation dialog before deleting files or cleaning up")) + .active(settings.boolean("confirm-before-delete")) + .build(); + let settings_confirm = settings.clone(); + confirm_row.connect_active_notify(move |row| { + settings_confirm.set_boolean("confirm-before-delete", row.is_active()).ok(); + }); + automation_group.add(&confirm_row); + + page.add(&automation_group); + + // Desktop Integration group let integration_group = adw::PreferencesGroup::builder() .title(&i18n("Desktop Integration")) .description(&i18n( @@ -199,31 +248,19 @@ fn build_general_page(settings: &gio::Settings, dialog: &adw::PreferencesDialog) page } -// --- Behavior page --- +// --- Updates page --- -fn build_behavior_page(settings: &gio::Settings) -> adw::PreferencesPage { +fn build_updates_page(settings: &gio::Settings) -> adw::PreferencesPage { let page = adw::PreferencesPage::builder() - .title(&i18n("Behavior")) - .icon_name("preferences-other-symbolic") + .title(&i18n("Updates")) + .icon_name("software-update-available-symbolic") .build(); - // Automation group - let automation_group = adw::PreferencesGroup::builder() - .title(&i18n("Automation")) - .description(&i18n("What Driftwood does automatically")) + // Update Checking group + let checking_group = adw::PreferencesGroup::builder() + .title(&i18n("Update Checking")) .build(); - let auto_scan_row = adw::SwitchRow::builder() - .title(&i18n("Scan on startup")) - .subtitle(&i18n("Automatically scan for new AppImages when the app starts")) - .active(settings.boolean("auto-scan-on-startup")) - .build(); - let settings_scan = settings.clone(); - auto_scan_row.connect_active_notify(move |row| { - settings_scan.set_boolean("auto-scan-on-startup", row.is_active()).ok(); - }); - automation_group.add(&auto_scan_row); - let auto_update_row = adw::SwitchRow::builder() .title(&i18n("Check for updates")) .subtitle(&i18n("Periodically check if newer versions of your AppImages are available")) @@ -233,7 +270,7 @@ fn build_behavior_page(settings: &gio::Settings) -> adw::PreferencesPage { auto_update_row.connect_active_notify(move |row| { settings_upd.set_boolean("auto-check-updates", row.is_active()).ok(); }); - automation_group.add(&auto_update_row); + checking_group.add(&auto_update_row); let interval_row = adw::SpinRow::builder() .title(&i18n("Update check interval")) @@ -252,86 +289,14 @@ fn build_behavior_page(settings: &gio::Settings) -> adw::PreferencesPage { interval_row.connect_value_notify(move |row| { settings_interval.set_int("update-check-interval-hours", row.value() as i32).ok(); }); - automation_group.add(&interval_row); + checking_group.add(&interval_row); - let auto_integrate_row = adw::SwitchRow::builder() - .title(&i18n("Auto-integrate new AppImages")) - .subtitle(&i18n("Automatically add newly discovered AppImages to the desktop menu")) - .active(settings.boolean("auto-integrate")) + page.add(&checking_group); + + // Update Behavior group + let behavior_group = adw::PreferencesGroup::builder() + .title(&i18n("Update Behavior")) .build(); - let settings_int = settings.clone(); - auto_integrate_row.connect_active_notify(move |row| { - settings_int.set_boolean("auto-integrate", row.is_active()).ok(); - }); - automation_group.add(&auto_integrate_row); - - let removable_row = adw::SwitchRow::builder() - .title(&i18n("Watch removable media")) - .subtitle(&i18n("Scan USB drives and other removable media for AppImages")) - .active(settings.boolean("watch-removable-media")) - .build(); - let settings_rem = settings.clone(); - removable_row.connect_active_notify(move |row| { - settings_rem.set_boolean("watch-removable-media", row.is_active()).ok(); - }); - automation_group.add(&removable_row); - - page.add(&automation_group); - - // Backup group - let backup_group = adw::PreferencesGroup::builder() - .title(&i18n("Backups")) - .description(&i18n("Config and data backup settings for updates")) - .build(); - - let auto_backup_row = adw::SwitchRow::builder() - .title(&i18n("Auto-backup before update")) - .subtitle(&i18n("Back up config and data files before updating an AppImage")) - .active(settings.boolean("auto-backup-before-update")) - .build(); - let settings_backup = settings.clone(); - auto_backup_row.connect_active_notify(move |row| { - settings_backup.set_boolean("auto-backup-before-update", row.is_active()).ok(); - }); - backup_group.add(&auto_backup_row); - - let retention_row = adw::SpinRow::builder() - .title(&i18n("Backup retention")) - .subtitle(&i18n("Days to keep config backups before auto-cleanup")) - .build(); - let adjustment = gtk::Adjustment::new( - settings.int("backup-retention-days") as f64, - 1.0, - 365.0, - 1.0, - 7.0, - 0.0, - ); - retention_row.set_adjustment(Some(&adjustment)); - let settings_ret = settings.clone(); - retention_row.connect_value_notify(move |row| { - settings_ret.set_int("backup-retention-days", row.value() as i32).ok(); - }); - backup_group.add(&retention_row); - - page.add(&backup_group); - - // Safety group - let safety_group = adw::PreferencesGroup::builder() - .title(&i18n("Safety")) - .description(&i18n("Confirmation and cleanup behavior")) - .build(); - - let confirm_row = adw::SwitchRow::builder() - .title(&i18n("Confirm before delete")) - .subtitle(&i18n("Show a confirmation dialog before deleting files or cleaning up")) - .active(settings.boolean("confirm-before-delete")) - .build(); - let settings_confirm = settings.clone(); - confirm_row.connect_active_notify(move |row| { - settings_confirm.set_boolean("confirm-before-delete", row.is_active()).ok(); - }); - safety_group.add(&confirm_row); let cleanup_row = adw::ComboRow::builder() .title(&i18n("After updating an AppImage")) @@ -356,23 +321,43 @@ fn build_behavior_page(settings: &gio::Settings) -> adw::PreferencesPage { }; settings_cleanup.set_string("update-cleanup", value).ok(); }); - safety_group.add(&cleanup_row); + behavior_group.add(&cleanup_row); - page.add(&safety_group); - - page -} - -// --- Security page --- - -fn build_security_page(settings: &gio::Settings) -> adw::PreferencesPage { - let page = adw::PreferencesPage::builder() - .title(&i18n("Security")) - .icon_name("security-medium-symbolic") + let auto_backup_row = adw::SwitchRow::builder() + .title(&i18n("Auto-backup before update")) + .subtitle(&i18n("Back up config and data files before updating an AppImage")) + .active(settings.boolean("auto-backup-before-update")) .build(); + let settings_backup = settings.clone(); + auto_backup_row.connect_active_notify(move |row| { + settings_backup.set_boolean("auto-backup-before-update", row.is_active()).ok(); + }); + behavior_group.add(&auto_backup_row); - let scan_group = adw::PreferencesGroup::builder() - .title(&i18n("Vulnerability Scanning")) + let retention_row = adw::SpinRow::builder() + .title(&i18n("Backup retention")) + .subtitle(&i18n("Days to keep config backups before auto-cleanup")) + .build(); + let adjustment = gtk::Adjustment::new( + settings.int("backup-retention-days") as f64, + 1.0, + 365.0, + 1.0, + 7.0, + 0.0, + ); + retention_row.set_adjustment(Some(&adjustment)); + let settings_ret = settings.clone(); + retention_row.connect_value_notify(move |row| { + settings_ret.set_int("backup-retention-days", row.value() as i32).ok(); + }); + behavior_group.add(&retention_row); + + page.add(&behavior_group); + + // Security Scanning group + let security_group = adw::PreferencesGroup::builder() + .title(&i18n("Security Scanning")) .description(&i18n("Check bundled libraries for known CVEs via OSV.dev")) .build(); @@ -385,21 +370,7 @@ fn build_security_page(settings: &gio::Settings) -> adw::PreferencesPage { auto_security_row.connect_active_notify(move |row| { settings_sec.set_boolean("auto-security-scan", row.is_active()).ok(); }); - scan_group.add(&auto_security_row); - - let info_row = adw::ActionRow::builder() - .title(&i18n("Data source")) - .subtitle(&i18n("OSV.dev - Open Source Vulnerability database")) - .build(); - scan_group.add(&info_row); - - page.add(&scan_group); - - // Notification settings - let notify_group = adw::PreferencesGroup::builder() - .title(&i18n("Notifications")) - .description(&i18n("Desktop notification settings for security alerts")) - .build(); + security_group.add(&auto_security_row); let notify_row = adw::SwitchRow::builder() .title(&i18n("Security notifications")) @@ -410,7 +381,7 @@ fn build_security_page(settings: &gio::Settings) -> adw::PreferencesPage { notify_row.connect_active_notify(move |row| { settings_notify.set_boolean("security-notifications", row.is_active()).ok(); }); - notify_group.add(¬ify_row); + security_group.add(¬ify_row); let threshold_row = adw::ComboRow::builder() .title(&i18n("Notification threshold")) @@ -438,29 +409,9 @@ fn build_security_page(settings: &gio::Settings) -> adw::PreferencesPage { }; settings_threshold.set_string("security-notification-threshold", value).ok(); }); - notify_group.add(&threshold_row); + security_group.add(&threshold_row); - page.add(¬ify_group); - - // About security scanning - let about_group = adw::PreferencesGroup::builder() - .title(&i18n("How It Works")) - .description(&i18n("Understanding Driftwood's security scanning")) - .build(); - - let about_row = adw::ActionRow::builder() - .title(&i18n("Bundled library detection")) - .subtitle(&i18n("Driftwood extracts the list of shared libraries (.so files) bundled inside each AppImage and checks them against the OSV vulnerability database.")) - .build(); - about_group.add(&about_row); - - let limits_row = adw::ActionRow::builder() - .title(&i18n("Limitations")) - .subtitle(&i18n("Not all bundled libraries can be identified. Version detection uses heuristics and may not always be accurate. Results should be treated as advisory.")) - .build(); - about_group.add(&limits_row); - - page.add(&about_group); + page.add(&security_group); page }