6.6 KiB
6.6 KiB
Final UX Improvements Design: Tags, Export/Import, Changelog
Overview
Three remaining UX improvements from the 30-item enhancement list:
- #12 App grouping with tags + grouped library sections
- #13 Unified export/import (shared core for CLI + GUI) with extended fields
- #14 Bridge changelog gap (GitHub release notes -> release_history) + updates view preview
#12: Tags + Grouped Library Sections
Current State
tags: Option<String>field exists inAppImageRecord(database.rs:50)update_tags(id, tags)DB method exists (database.rs:2069)- No UI for viewing, editing, or filtering by tags
- Library view is flat (grid or list mode, no sections)
Design
Detail view - tag editor:
- Add a "Tags" row in the detail view info section
- Display existing tags as pill-shaped chips with "x" remove buttons
- A "+" button at the end opens an inline text entry to add a new tag
- Tags stored as comma-separated string in the existing
tagscolumn - On add/remove, call
db.update_tags()immediately (no save button)
Library view - tag filter chips:
- Add a horizontal scrollable chip bar at the top of the library view (same pattern as catalog category chips)
- "All" chip selected by default, plus one chip per unique tag found across all apps
- Selecting a tag filters the view to only apps with that tag
- Chip bar is only visible when at least one app has tags
Library view - grouped sections:
- When no search is active and no tag filter is selected, group apps by their first tag under collapsible section headers
- Apps with no tags go under an "Uncategorized" section at the bottom
- Sort dropdown still works within each group
- In search mode or tag-filter mode, grouping is disabled (flat list)
Data model: No schema changes. Comma-separated tags in existing column.
Files Modified
| File | Changes |
|---|---|
src/ui/detail_view.rs |
Add tag editor chips row in info section |
src/ui/library_view.rs |
Add tag filter chip bar, grouped section headers |
src/core/database.rs |
Add get_all_tags() query to collect distinct tags |
#13: Unified Export/Import (CLI + GUI)
Current State
- CLI-only export/import in
cli.rs(lines 887-1000+) - JSON format v1 with limited fields: path, app_name, app_version, integrated, notes, categories
- No GUI file picker dialogs for export/import
- No shared module - logic is inline in CLI handlers
Design
Shared core module: src/core/backup.rs
New module with two public functions:
pub fn export_app_list(db: &Database, path: &Path) -> Result<usize, BackupError>
pub fn import_app_list(db: &Database, path: &Path) -> Result<ImportResult, BackupError>
Where ImportResult contains:
matched: usize- apps found and metadata mergedmissing: Vec<String>- app names/paths not found on disk
JSON format v2:
{
"version": 2,
"exported_at": "2026-03-01T10:00:00Z",
"appimages": [
{
"path": "/home/user/Applications/MyApp.AppImage",
"app_name": "MyApp",
"app_version": "1.0.0",
"integrated": true,
"notes": "user notes",
"categories": "Graphics;Utility;",
"tags": "work,design",
"pinned": false,
"launch_args": "--no-sandbox",
"sandbox_mode": "permissive",
"autostart": false
}
]
}
Graceful v1 handling: missing fields default to None (not overwritten on import).
Import merge semantics:
- Match apps by path (exact match)
- For matched apps, merge each field: only overwrite if the import value is non-empty/non-null AND the existing value is empty/null (preserve user's current data)
- Tags: merge (union of existing + imported tags, no duplicates)
- For unmatched paths: collect into
missinglist
CLI (cli.rs):
cmd_export()andcmd_import()become thin wrappers callingbackup::export_app_list()/backup::import_app_list()- Same CLI flags and output messages
GUI (window.rs):
- Add "Export app list" and "Import app list" items to the hamburger menu
- Export:
gtk::FileDialogsave picker, default filenamedriftwood-apps.json, callsbackup::export_app_list(), toast on success - Import:
gtk::FileDialogopen picker with.jsonfilter, callsbackup::import_app_list(), toast showing "Imported N apps" + dialog listing missing apps if any - Refresh library view after import
Files Modified
| File | Changes |
|---|---|
src/core/backup.rs |
New module: export/import logic, JSON v2 format |
src/core/mod.rs |
Add pub mod backup; |
src/cli.rs |
Refactor cmd_export/cmd_import to call backup module |
src/window.rs |
Add menu items + file picker dialogs for export/import |
#14: Bridge Changelog Gap + Updates View Preview
Current State
release_history: Option<String>field exists in AppImageRecord (JSON array)- Detail view already renders release history when data exists (detail_view.rs:760-820)
- AppStream parsing populates release_history for local metainfo (rare)
- GitHub enrichment fetches release info but does NOT write to release_history
- Updates view shows update-available cards but no changelog preview
Design
Enrichment bridge (github_enrichment.rs):
- After
enrich_app_release_info()fetches the latest release, also fetch up to 10 recent releases from the GitHub releases API - Convert each release to
ReleaseInfo { version, date, description }format - Serialize as JSON array and write to
release_historycolumn - Only update if the field is currently empty (don't overwrite AppStream data which may be more authoritative)
- The existing detail view Release History section will then automatically display this data for all GitHub-enriched apps
New DB method:
update_release_history(id: i64, history_json: &str)- simple UPDATE on the release_history column
Updates view changelog preview (updates_view.rs):
- Each update card gets an
adw::ExpanderRow"What's new" section below the existing content - If
release_historyis populated, find the entry matchinglatest_versionand show its description - If no matching entry or no release_history data: show "Release notes not available" in dim text
- Collapsed by default to keep the view compact
Files Modified
| File | Changes |
|---|---|
src/core/github_enrichment.rs |
Fetch recent releases, write to release_history |
src/core/database.rs |
Add update_release_history() method |
src/ui/updates_view.rs |
Add expandable "What's new" section to update cards |
Implementation Order
- #14 first - Smallest scope, self-contained enrichment + UI change
- #12 second - Tags are self-contained, no dependency on other features
- #13 last - Export should include tags (depends on #12 being functional)