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:
lashman
2026-03-01 00:39:43 +02:00
parent 4b939f044a
commit d11546efc6
25 changed files with 1711 additions and 481 deletions

View File

@@ -38,6 +38,54 @@ pub fn build_dashboard_page(db: &Rc<Database>) -> adw::NavigationPage {
content.append(&banner);
}
// Getting Started checklist (shown for new users)
let records = db.get_all_appimages().unwrap_or_default();
let total_count = records.len();
let integrated_count = records.iter().filter(|r| r.integrated).count();
if total_count < 3 {
let started_group = adw::PreferencesGroup::builder()
.title("Getting Started")
.description("New to Driftwood? Here are three steps to get you up and running.")
.build();
let scan_row = adw::ActionRow::builder()
.title("Scan your system for apps")
.subtitle("Look for AppImage files in your configured folders")
.activatable(true)
.build();
scan_row.set_action_name(Some("win.scan"));
if total_count > 0 {
let check = widgets::status_badge_with_icon("emblem-ok-symbolic", "Done", "success");
check.set_valign(gtk::Align::Center);
scan_row.add_suffix(&check);
}
started_group.add(&scan_row);
let catalog_row = adw::ActionRow::builder()
.title("Browse the app catalog")
.subtitle("Discover and install apps from the AppImage ecosystem")
.activatable(true)
.build();
catalog_row.set_action_name(Some("win.catalog"));
let arrow1 = gtk::Image::from_icon_name("go-next-symbolic");
arrow1.set_valign(gtk::Align::Center);
catalog_row.add_suffix(&arrow1);
started_group.add(&catalog_row);
let menu_row = adw::ActionRow::builder()
.title("Add an app to your launcher")
.subtitle("Make an app findable in your application menu")
.build();
if integrated_count > 0 {
let check = widgets::status_badge_with_icon("emblem-ok-symbolic", "Done", "success");
check.set_valign(gtk::Align::Center);
menu_row.add_suffix(&check);
}
started_group.add(&menu_row);
content.append(&started_group);
}
// Section 1: System Status
content.append(&build_system_status_group());
@@ -89,6 +137,7 @@ fn build_system_status_group() -> adw::PreferencesGroup {
let session_row = adw::ActionRow::builder()
.title("Display server")
.subtitle(session.label())
.tooltip_text("How your system draws windows on screen")
.build();
let session_badge = widgets::status_badge(
session.label(),
@@ -107,15 +156,16 @@ fn build_system_status_group() -> adw::PreferencesGroup {
let de_row = adw::ActionRow::builder()
.title("Desktop environment")
.subtitle(&de)
.tooltip_text("Your desktop interface")
.build();
group.add(&de_row);
// FUSE status
let fuse_info = fuse::detect_system_fuse();
let fuse_row = adw::ActionRow::builder()
.title("FUSE")
.title("App compatibility")
.subtitle(&fuse_description(&fuse_info))
.tooltip_text("Filesystem in Userspace - required for mounting AppImages")
.tooltip_text("Most AppImages need a system component called FUSE to run. This shows whether it is set up correctly.")
.build();
let fuse_badge = widgets::status_badge(
fuse_info.status.label(),
@@ -128,7 +178,7 @@ fn build_system_status_group() -> adw::PreferencesGroup {
// Install hint if FUSE not functional
if let Some(ref hint) = fuse_info.install_hint {
let hint_row = adw::ActionRow::builder()
.title("Fix FUSE")
.title("Fix app compatibility")
.subtitle(hint)
.subtitle_selectable(true)
.build();
@@ -141,7 +191,7 @@ fn build_system_status_group() -> adw::PreferencesGroup {
let xwayland_row = adw::ActionRow::builder()
.title("XWayland")
.subtitle(if has_xwayland { "Running" } else { "Not detected" })
.tooltip_text("X11 compatibility layer for Wayland desktops")
.tooltip_text("Compatibility layer that lets older apps run on modern displays")
.build();
let xwayland_badge = widgets::status_badge(
if has_xwayland { "Available" } else { "Unavailable" },