Add Phase 5 enhancements: security, i18n, analysis, backup, notifications
This commit is contained in:
@@ -7,6 +7,7 @@ use crate::core::database::Database;
|
||||
use crate::core::duplicates;
|
||||
use crate::core::footprint;
|
||||
use crate::core::orphan;
|
||||
use crate::i18n::{i18n, i18n_f};
|
||||
use super::widgets;
|
||||
|
||||
/// A reclaimable item discovered during analysis.
|
||||
@@ -28,11 +29,11 @@ enum ReclaimCategory {
|
||||
}
|
||||
|
||||
impl ReclaimCategory {
|
||||
fn label(&self) -> &'static str {
|
||||
fn label(&self) -> String {
|
||||
match self {
|
||||
ReclaimCategory::OrphanedDesktopEntry => "Orphaned desktop entries",
|
||||
ReclaimCategory::CacheData => "Cache data",
|
||||
ReclaimCategory::DuplicateAppImage => "Duplicate AppImages",
|
||||
ReclaimCategory::OrphanedDesktopEntry => i18n("Orphaned desktop entries"),
|
||||
ReclaimCategory::CacheData => i18n("Cache data"),
|
||||
ReclaimCategory::DuplicateAppImage => i18n("Duplicate AppImages"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +49,7 @@ impl ReclaimCategory {
|
||||
/// Show the disk space reclamation wizard as an AdwDialog.
|
||||
pub fn show_cleanup_wizard(parent: &impl IsA<gtk::Widget>, _db: &Rc<Database>) {
|
||||
let dialog = adw::Dialog::builder()
|
||||
.title("Disk Space Cleanup")
|
||||
.title(&i18n("Disk Space Cleanup"))
|
||||
.content_width(500)
|
||||
.content_height(550)
|
||||
.build();
|
||||
@@ -118,8 +119,8 @@ pub fn show_cleanup_wizard(parent: &impl IsA<gtk::Widget>, _db: &Rc<Database>) {
|
||||
Err(_) => {
|
||||
let error_page = adw::StatusPage::builder()
|
||||
.icon_name("dialog-error-symbolic")
|
||||
.title("Analysis Failed")
|
||||
.description("Could not analyze disk usage.")
|
||||
.title(&i18n("Analysis Failed"))
|
||||
.description(&i18n("Could not analyze disk usage."))
|
||||
.build();
|
||||
if let Some(child) = stack_ref.child_by_name("review") {
|
||||
stack_ref.remove(&child);
|
||||
@@ -148,13 +149,13 @@ fn build_analysis_step() -> gtk::Box {
|
||||
page.append(&spinner);
|
||||
|
||||
let label = gtk::Label::builder()
|
||||
.label("Analyzing disk usage...")
|
||||
.label(&i18n("Analyzing disk usage..."))
|
||||
.css_classes(["title-3"])
|
||||
.build();
|
||||
page.append(&label);
|
||||
|
||||
let subtitle = gtk::Label::builder()
|
||||
.label("Checking for orphaned files, cache data, and duplicates")
|
||||
.label(&i18n("Checking for orphaned files, cache data, and duplicates"))
|
||||
.css_classes(["dimmed"])
|
||||
.build();
|
||||
page.append(&subtitle);
|
||||
@@ -178,8 +179,8 @@ fn build_review_step(
|
||||
if items_ref.is_empty() {
|
||||
let empty = adw::StatusPage::builder()
|
||||
.icon_name("emblem-ok-symbolic")
|
||||
.title("All Clean")
|
||||
.description("No reclaimable disk space found.")
|
||||
.title(&i18n("All Clean"))
|
||||
.description(&i18n("No reclaimable disk space found."))
|
||||
.vexpand(true)
|
||||
.build();
|
||||
page.append(&empty);
|
||||
@@ -189,7 +190,7 @@ fn build_review_step(
|
||||
// Summary header
|
||||
let total_size: u64 = items_ref.iter().map(|i| i.size_bytes).sum();
|
||||
let summary_label = gtk::Label::builder()
|
||||
.label(&format!("Found {} reclaimable", widgets::format_size(total_size as i64)))
|
||||
.label(&i18n_f("Found {} reclaimable", &[("{}", &widgets::format_size(total_size as i64))]))
|
||||
.css_classes(["title-3"])
|
||||
.margin_top(12)
|
||||
.margin_start(18)
|
||||
@@ -199,7 +200,7 @@ fn build_review_step(
|
||||
page.append(&summary_label);
|
||||
|
||||
let desc_label = gtk::Label::builder()
|
||||
.label("Select items to remove")
|
||||
.label(&i18n("Select items to remove"))
|
||||
.css_classes(["dimmed"])
|
||||
.margin_start(18)
|
||||
.margin_end(18)
|
||||
@@ -251,8 +252,9 @@ fn build_review_step(
|
||||
let cat_icon = gtk::Image::from_icon_name(cat.icon_name());
|
||||
cat_icon.set_pixel_size(16);
|
||||
cat_header.append(&cat_icon);
|
||||
let cat_label_text = cat.label();
|
||||
let cat_label = gtk::Label::builder()
|
||||
.label(&format!("{} ({})", cat.label(), widgets::format_size(cat_size as i64)))
|
||||
.label(&format!("{} ({})", cat_label_text, widgets::format_size(cat_size as i64)))
|
||||
.css_classes(["title-4"])
|
||||
.halign(gtk::Align::Start)
|
||||
.build();
|
||||
@@ -263,7 +265,7 @@ fn build_review_step(
|
||||
list_box.add_css_class("boxed-list");
|
||||
list_box.set_selection_mode(gtk::SelectionMode::None);
|
||||
list_box.update_property(&[
|
||||
gtk::accessible::Property::Label(cat.label()),
|
||||
gtk::accessible::Property::Label(&cat_label_text),
|
||||
]);
|
||||
|
||||
for (idx, item) in &cat_items {
|
||||
@@ -305,11 +307,11 @@ fn build_review_step(
|
||||
.build();
|
||||
|
||||
let clean_button = gtk::Button::builder()
|
||||
.label("Clean Selected")
|
||||
.label(&i18n("Clean Selected"))
|
||||
.build();
|
||||
clean_button.add_css_class("destructive-action");
|
||||
clean_button.update_property(&[
|
||||
gtk::accessible::Property::Label("Clean selected items"),
|
||||
gtk::accessible::Property::Label(&i18n("Clean selected items")),
|
||||
]);
|
||||
|
||||
let items_clone = items.clone();
|
||||
@@ -337,17 +339,16 @@ fn build_review_step(
|
||||
}
|
||||
|
||||
let confirm = adw::AlertDialog::builder()
|
||||
.heading("Confirm Cleanup")
|
||||
.body(&format!(
|
||||
"Remove {} item{}?",
|
||||
count,
|
||||
if count == 1 { "" } else { "s" }
|
||||
.heading(&i18n("Confirm Cleanup"))
|
||||
.body(&i18n_f(
|
||||
"Remove {} items?",
|
||||
&[("{}", &count.to_string())],
|
||||
))
|
||||
.close_response("cancel")
|
||||
.default_response("clean")
|
||||
.build();
|
||||
confirm.add_response("cancel", "Cancel");
|
||||
confirm.add_response("clean", "Clean");
|
||||
confirm.add_response("cancel", &i18n("Cancel"));
|
||||
confirm.add_response("clean", &i18n("Clean"));
|
||||
confirm.set_response_appearance("clean", adw::ResponseAppearance::Destructive);
|
||||
|
||||
let on_confirm_inner = on_confirm_ref.clone();
|
||||
@@ -416,31 +417,32 @@ fn build_complete_step(count: usize, size: u64, dialog: &adw::Dialog) -> gtk::Bo
|
||||
if count == 0 {
|
||||
let status = adw::StatusPage::builder()
|
||||
.icon_name("emblem-ok-symbolic")
|
||||
.title("Nothing Selected")
|
||||
.description("No items were selected for cleanup.")
|
||||
.title(&i18n("Nothing Selected"))
|
||||
.description(&i18n("No items were selected for cleanup."))
|
||||
.build();
|
||||
page.append(&status);
|
||||
} else {
|
||||
let status = adw::StatusPage::builder()
|
||||
.icon_name("user-trash-symbolic")
|
||||
.title("Cleanup Complete")
|
||||
.description(&format!(
|
||||
"Removed {} item{}, freeing {}",
|
||||
count,
|
||||
if count == 1 { "" } else { "s" },
|
||||
widgets::format_size(size as i64),
|
||||
.title(&i18n("Cleanup Complete"))
|
||||
.description(&i18n_f(
|
||||
"Removed {count} items, freeing {size}",
|
||||
&[
|
||||
("{count}", &count.to_string()),
|
||||
("{size}", &widgets::format_size(size as i64)),
|
||||
],
|
||||
))
|
||||
.build();
|
||||
page.append(&status);
|
||||
}
|
||||
|
||||
let close_button = gtk::Button::builder()
|
||||
.label("Close")
|
||||
.label(&i18n("Close"))
|
||||
.halign(gtk::Align::Center)
|
||||
.build();
|
||||
close_button.add_css_class("pill");
|
||||
close_button.update_property(&[
|
||||
gtk::accessible::Property::Label("Close cleanup dialog"),
|
||||
gtk::accessible::Property::Label(&i18n("Close cleanup dialog")),
|
||||
]);
|
||||
|
||||
let dialog_ref = dialog.clone();
|
||||
|
||||
Reference in New Issue
Block a user