Add Phase 5 enhancements: security, i18n, analysis, backup, notifications
- Database v8 migration: tags, pinned, avg_startup_ms columns - Security scanning with CVE matching and batch scan - Bundled library extraction and vulnerability reports - Desktop notification system for security alerts - Backup/restore system for AppImage configurations - i18n framework with gettext support - Runtime analysis and Wayland compatibility detection - AppStream metadata and Flatpak-style build support - File watcher module for live directory monitoring - Preferences panel with GSettings integration - CLI interface for headless operation - Detail view: tabbed layout with ViewSwitcher in title bar, health score, sandbox controls, changelog links - Library view: sort dropdown, context menu enhancements - Dashboard: system status, disk usage, launch history - Security report page with scan and export - Packaging: meson build, PKGBUILD, metainfo
This commit is contained in:
@@ -96,9 +96,28 @@ impl LibraryView {
|
||||
.title("Driftwood")
|
||||
.build();
|
||||
|
||||
// Add button (shows drop overlay)
|
||||
let add_button_icon = gtk::Image::from_icon_name("list-add-symbolic");
|
||||
let add_button_label = gtk::Label::new(Some(&i18n("Add app")));
|
||||
let add_button_content = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Horizontal)
|
||||
.spacing(6)
|
||||
.build();
|
||||
add_button_content.append(&add_button_icon);
|
||||
add_button_content.append(&add_button_label);
|
||||
|
||||
let add_button = gtk::Button::builder()
|
||||
.child(&add_button_content)
|
||||
.tooltip_text(&i18n("Add AppImage"))
|
||||
.build();
|
||||
add_button.add_css_class("flat");
|
||||
add_button.set_action_name(Some("win.show-drop-hint"));
|
||||
add_button.update_property(&[AccessibleProperty::Label("Add AppImage")]);
|
||||
|
||||
let header_bar = adw::HeaderBar::builder()
|
||||
.title_widget(&title_widget)
|
||||
.build();
|
||||
header_bar.pack_start(&add_button);
|
||||
header_bar.pack_end(&menu_button);
|
||||
header_bar.pack_end(&search_button);
|
||||
header_bar.pack_end(&view_toggle_box);
|
||||
@@ -175,8 +194,8 @@ impl LibraryView {
|
||||
.description(&i18n(
|
||||
"Driftwood manages your AppImage collection - scanning for apps, \
|
||||
integrating them into your desktop, and keeping them up to date.\n\n\
|
||||
Add AppImages to ~/Applications or ~/Downloads, or configure \
|
||||
custom scan locations in Preferences.",
|
||||
Drag AppImage files here, or add them to ~/Applications or ~/Downloads, \
|
||||
then use Scan Now to find them.",
|
||||
))
|
||||
.child(&empty_button_box)
|
||||
.build();
|
||||
@@ -196,13 +215,13 @@ impl LibraryView {
|
||||
.selection_mode(gtk::SelectionMode::None)
|
||||
.homogeneous(true)
|
||||
.min_children_per_line(2)
|
||||
.max_children_per_line(4)
|
||||
.row_spacing(14)
|
||||
.column_spacing(14)
|
||||
.margin_top(14)
|
||||
.margin_bottom(14)
|
||||
.margin_start(14)
|
||||
.margin_end(14)
|
||||
.max_children_per_line(5)
|
||||
.row_spacing(12)
|
||||
.column_spacing(12)
|
||||
.margin_top(12)
|
||||
.margin_bottom(12)
|
||||
.margin_start(12)
|
||||
.margin_end(12)
|
||||
.build();
|
||||
flow_box.update_property(&[AccessibleProperty::Label("AppImage library grid")]);
|
||||
|
||||
@@ -463,9 +482,14 @@ impl LibraryView {
|
||||
let name = record.app_name.as_deref().unwrap_or(&record.filename);
|
||||
|
||||
// Structured two-line subtitle:
|
||||
// Line 1: Description snippet or file path
|
||||
// Line 1: Description snippet or file path (or "Analyzing..." if pending)
|
||||
// Line 2: Version + size
|
||||
let line1 = if let Some(ref desc) = record.description {
|
||||
let is_analyzing = record.app_name.is_none()
|
||||
&& record.analysis_status.as_deref() != Some("complete");
|
||||
|
||||
let line1 = if is_analyzing {
|
||||
i18n("Analyzing...")
|
||||
} else if let Some(ref desc) = record.description {
|
||||
if !desc.is_empty() {
|
||||
let snippet: String = desc.chars().take(60).collect();
|
||||
if snippet.len() < desc.len() {
|
||||
@@ -496,7 +520,7 @@ impl LibraryView {
|
||||
.activatable(true)
|
||||
.build();
|
||||
|
||||
// Icon prefix (48x48 with rounded clipping and letter fallback)
|
||||
// Icon prefix with rounded clipping and letter fallback
|
||||
let icon = widgets::app_icon(
|
||||
record.icon_path.as_deref(),
|
||||
name,
|
||||
@@ -583,19 +607,19 @@ fn build_context_menu(record: &AppImageRecord) -> gtk::gio::Menu {
|
||||
// Section 2: Actions
|
||||
let section2 = gtk::gio::Menu::new();
|
||||
section2.append(Some("Check for Updates"), Some(&format!("win.check-update(int64 {})", record.id)));
|
||||
section2.append(Some("Scan for Vulnerabilities"), Some(&format!("win.scan-security(int64 {})", record.id)));
|
||||
section2.append(Some("Security check"), Some(&format!("win.scan-security(int64 {})", record.id)));
|
||||
menu.append_section(None, §ion2);
|
||||
|
||||
// Section 3: Integration + folder
|
||||
let section3 = gtk::gio::Menu::new();
|
||||
let integrate_label = if record.integrated { "Remove Integration" } else { "Integrate" };
|
||||
let integrate_label = if record.integrated { "Remove from app menu" } else { "Add to app menu" };
|
||||
section3.append(Some(integrate_label), Some(&format!("win.toggle-integration(int64 {})", record.id)));
|
||||
section3.append(Some("Open Containing Folder"), Some(&format!("win.open-folder(int64 {})", record.id)));
|
||||
section3.append(Some("Show in file manager"), Some(&format!("win.open-folder(int64 {})", record.id)));
|
||||
menu.append_section(None, §ion3);
|
||||
|
||||
// Section 4: Clipboard
|
||||
let section4 = gtk::gio::Menu::new();
|
||||
section4.append(Some("Copy Path"), Some(&format!("win.copy-path(int64 {})", record.id)));
|
||||
section4.append(Some("Copy file location"), Some(&format!("win.copy-path(int64 {})", record.id)));
|
||||
menu.append_section(None, §ion4);
|
||||
|
||||
menu
|
||||
|
||||
Reference in New Issue
Block a user