Add UX enhancements: carousel, filter chips, command palette, and more
- Replace featured section Stack with AdwCarousel + indicator dots - Convert category grid to horizontal scrollable filter chips - Add grid/list view toggle for catalog with compact row layout - Add quick launch button on library list rows - Add stale catalog banner when data is older than 7 days - Add command palette (Ctrl+K) for quick app search and launch - Show specific app names in update notifications - Add per-app auto-update toggle (skip updates switch) - Add keyboard shortcut hints to button tooltips - Add source trust badges (AppImageHub/Community) on catalog tiles - Add undo-based uninstall with toast and record restoration - Add type-to-search in library view - Use human-readable catalog source labels - Show Launch button for installed apps in catalog detail - Replace external browser link with inline AppImage explainer dialog
This commit is contained in:
@@ -89,7 +89,7 @@ impl LibraryView {
|
||||
|
||||
let search_button = gtk::ToggleButton::builder()
|
||||
.icon_name("system-search-symbolic")
|
||||
.tooltip_text(&i18n("Search"))
|
||||
.tooltip_text(&i18n("Search (Ctrl+F)"))
|
||||
.build();
|
||||
search_button.add_css_class("flat");
|
||||
search_button.update_property(&[AccessibleProperty::Label("Toggle search")]);
|
||||
@@ -124,7 +124,7 @@ impl LibraryView {
|
||||
// Scan button
|
||||
let scan_button = gtk::Button::builder()
|
||||
.icon_name("view-refresh-symbolic")
|
||||
.tooltip_text(&i18n("Scan for AppImages"))
|
||||
.tooltip_text(&i18n("Scan for AppImages (Ctrl+R)"))
|
||||
.build();
|
||||
scan_button.add_css_class("flat");
|
||||
scan_button.set_action_name(Some("win.scan"));
|
||||
@@ -244,14 +244,44 @@ impl LibraryView {
|
||||
browse_catalog_btn.set_action_name(Some("win.catalog"));
|
||||
browse_catalog_btn.update_property(&[AccessibleProperty::Label("Browse app catalog")]);
|
||||
|
||||
let learn_btn = gtk::Button::builder()
|
||||
.label(&i18n("What is an AppImage?"))
|
||||
.build();
|
||||
learn_btn.add_css_class("flat");
|
||||
learn_btn.add_css_class("pill");
|
||||
learn_btn.connect_clicked(|btn| {
|
||||
let dialog = adw::AlertDialog::builder()
|
||||
.heading(&i18n("What is an AppImage?"))
|
||||
.body(&i18n(
|
||||
"AppImages are self-contained app files for Linux, similar to .exe files on Windows or .dmg files on Mac.\n\n\
|
||||
Key differences from traditional Linux packages:\n\
|
||||
- No installation needed - just download and run\n\
|
||||
- One file per app - easy to back up and share\n\
|
||||
- Works on most Linux distributions\n\
|
||||
- Does not require admin/root access\n\n\
|
||||
Driftwood helps you discover, organize, and keep your AppImages up to date."
|
||||
))
|
||||
.build();
|
||||
dialog.add_response("learn-more", &i18n("Learn More Online"));
|
||||
dialog.add_response("ok", &i18n("Got It"));
|
||||
dialog.set_default_response(Some("ok"));
|
||||
dialog.set_close_response("ok");
|
||||
dialog.connect_response(Some("learn-more"), |_, _| {
|
||||
gtk::UriLauncher::new("https://appimage.org")
|
||||
.launch(gtk::Window::NONE, gtk::gio::Cancellable::NONE, |_| {});
|
||||
});
|
||||
dialog.present(Some(btn));
|
||||
});
|
||||
|
||||
empty_button_box.append(&scan_now_btn);
|
||||
empty_button_box.append(&browse_catalog_btn);
|
||||
empty_button_box.append(&learn_btn);
|
||||
|
||||
let empty_page = adw::StatusPage::builder()
|
||||
.icon_name("application-x-executable-symbolic")
|
||||
.title(&i18n("No AppImages Yet"))
|
||||
.description(&i18n(
|
||||
"Drag and drop AppImage files here, or scan your system to find them.",
|
||||
"AppImages are portable apps for Linux - like .exe files, but they run without installation. Drag one here, scan your system, or browse the catalog to get started.",
|
||||
))
|
||||
.child(&empty_button_box)
|
||||
.build();
|
||||
@@ -361,6 +391,9 @@ impl LibraryView {
|
||||
toolbar_view.set_content(Some(&content_box));
|
||||
widgets::apply_pointer_cursors(&toolbar_view);
|
||||
|
||||
// Enable type-to-search: any keypress in the view opens the search bar
|
||||
search_bar.set_key_capture_widget(Some(&toolbar_view));
|
||||
|
||||
let page = adw::NavigationPage::builder()
|
||||
.title("Driftwood")
|
||||
.tag("library")
|
||||
@@ -670,6 +703,18 @@ impl LibraryView {
|
||||
icon.add_css_class("icon-rounded");
|
||||
row.add_prefix(&icon);
|
||||
|
||||
// Quick launch button
|
||||
let launch_btn = gtk::Button::builder()
|
||||
.icon_name("media-playback-start-symbolic")
|
||||
.tooltip_text(&i18n("Launch"))
|
||||
.css_classes(["flat", "circular"])
|
||||
.valign(gtk::Align::Center)
|
||||
.build();
|
||||
launch_btn.set_action_name(Some("win.launch-appimage"));
|
||||
launch_btn.set_action_target_value(Some(&record.id.to_variant()));
|
||||
widgets::set_pointer_cursor(&launch_btn);
|
||||
row.add_suffix(&launch_btn);
|
||||
|
||||
// Single most important badge as suffix (same priority as cards)
|
||||
if let Some(badge) = app_card::build_priority_badge(record) {
|
||||
badge.set_valign(gtk::Align::Center);
|
||||
@@ -792,7 +837,7 @@ fn build_context_menu(record: &AppImageRecord) -> gtk::gio::Menu {
|
||||
|
||||
// Section 1: Launch
|
||||
let section1 = gtk::gio::Menu::new();
|
||||
section1.append(Some("Launch"), Some(&format!("win.launch-appimage(int64 {})", record.id)));
|
||||
section1.append(Some("Open"), Some(&format!("win.launch-appimage(int64 {})", record.id)));
|
||||
menu.append_section(None, §ion1);
|
||||
|
||||
// Section 2: Actions
|
||||
@@ -803,7 +848,7 @@ fn build_context_menu(record: &AppImageRecord) -> gtk::gio::Menu {
|
||||
|
||||
// Section 3: Integration + folder
|
||||
let section3 = gtk::gio::Menu::new();
|
||||
let integrate_label = if record.integrated { "Remove from app menu" } else { "Add to app menu" };
|
||||
let integrate_label = if record.integrated { "Remove from launcher" } else { "Add to launcher" };
|
||||
section3.append(Some(integrate_label), Some(&format!("win.toggle-integration(int64 {})", record.id)));
|
||||
section3.append(Some("Show in file manager"), Some(&format!("win.open-folder(int64 {})", record.id)));
|
||||
menu.append_section(None, §ion3);
|
||||
|
||||
Reference in New Issue
Block a user