Compare commits

..

95 Commits

Author SHA1 Message Date
lashman 6beca34f70 Add app icons, screenshots, and complete AppStream metainfo
- Add GNOME HIG-compliant app icon (scalable SVG) and symbolic variant
- Add 12 screenshots covering all major views and features
- Flesh out metainfo with screenshots, categories, URLs, content
  rating, system requirements, provides, translation, donation
  and contact links
- Update AppImage build script to bundle GTK plugin, symbolic
  icon, and metainfo
- Update meson.build with icon installation rules
- Remove About dialog from application menu
- Remove unused user guide and audit tool
2026-03-01 14:46:41 +02:00
lashman 09ef0f48e0 Rewrite README with better header and project framing 2026-03-01 13:12:45 +02:00
lashman 58d8b44866 Rewrite README with comprehensive feature documentation 2026-03-01 12:54:55 +02:00
lashman 99f60b8529 Change license to CC0-1.0 2026-03-01 12:49:17 +02:00
lashman da9568df61 Remove archived plan documents from tracking
Moved to .trash/ for reference - no longer needed in source tree.
2026-03-01 12:44:35 +02:00
lashman 7e55d5796f Add WCAG 2.2 AAA compliance and automated AT-SPI audit tool
- Bring all UI widgets to WCAG 2.2 AAA conformance across all views
- Add accessible labels, roles, descriptions, and announcements
- Bump focus outlines to 3px, target sizes to 44px AAA minimum
- Fix announce()/announce_result() to walk widget tree via parent()
- Add AT-SPI accessibility audit script (tools/a11y-audit.py) that
  checks SC 4.1.2, 1.1.1, 1.3.1, 2.1.1, 2.5.5, 2.5.8, 2.4.8,
  2.4.9, 2.4.10, 2.1.3 with JSON report output for CI
- Clean up project structure, archive old plan documents
2026-03-01 12:44:21 +02:00
lashman abb69dc753 Add tags, export/import, and changelog features
- Tag editor in detail view with add/remove pill chips
- Tag filter chips in library view for filtering by tag
- Shared backup module for app list export/import (JSON v2)
- CLI export/import refactored to use shared module
- GUI export/import via file picker dialogs in hamburger menu
- GitHub release history enrichment for catalog apps
- Changelog preview in updates view with expandable rows
- DB migration v19 for catalog release_history column
2026-03-01 01:01:43 +02:00
lashman 79519c500a Add design doc for tags, export/import, and changelog improvements 2026-03-01 00:47:14 +02:00
lashman d11546efc6 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
2026-03-01 00:39:43 +02:00
lashman 4b939f044a Add AppImageHub.com OCS API as primary catalog source
Integrate the Pling/OCS REST API (appimagehub.com) as the primary catalog
source with richer metadata than the existing appimage.github.io feed.

Backend:
- Add OCS API fetch with pagination, lenient JSON deserializers for loosely
  typed numeric fields, and non-AppImage file filtering (.dmg, .exe, etc.)
- Database migration v17 adds OCS-specific columns (ocs_id, downloads, score,
  typename, personid, description, summary, version, tags, etc.)
- Deduplicate secondary source apps against OCS entries
- Shrink OCS CDN icon URLs from 770x540 to 100x100 for faster loading
- Clear stale screenshot and icon caches on sync
- Extract GitHub repo links from OCS HTML descriptions
- Add fetch_ocs_download_files() to get all version files for an app
- Resolve fresh JWT download URLs per slot at install time

Detail page:
- Fetch OCS download files on page open and populate install SplitButton
  with version dropdown (newest first, filtered for AppImage only)
- Show OCS metadata: downloads, score, author, typename, tags, comments,
  created/updated dates, architecture, filename, file size, MD5
- Prefer ocs_description (full HTML with features/changelog) over short
  summary for the About section
- Add html_to_description() to preserve formatting (lists, paragraphs)
- Remove redundant Download link from Links section
- Escape ampersands in Pango markup subtitles (categories, typename, tags)

Catalog view:
- OCS source syncs first as primary, appimage.github.io as secondary
- Featured apps consider OCS download counts alongside GitHub stars

UI:
- Add pulldown-cmark for GitHub README markdown rendering in detail pages
- Add build_markdown_view() widget for rendered markdown content
2026-02-28 20:33:40 +02:00
lashman f89aafca6a Add GitHub metadata enrichment for catalog apps
Enrich catalog apps with GitHub API data (stars, version, downloads,
release date) via two strategies: background drip for repo-level info
and on-demand fetch when opening a detail page.

- Add github_enrichment module with API calls, asset filtering, and
  architecture auto-detection for AppImage downloads
- DB migrations v14/v15 for GitHub metadata and release asset columns
- Extract github_owner/repo from feed links during catalog sync
- Display colored stat cards (stars, version, downloads, released) on
  detail pages with on-demand enrichment
- Show stars and version on browse tiles and featured carousel cards
- Replace install button with SplitButton dropdown when multiple arch
  assets available, preferring detected architecture
- Disable install button until enrichment completes to prevent stale
  AppImageHub URL downloads
- Keep enrichment banner visible on catalog page until truly complete,
  showing paused state when rate-limited
- Add GitHub token and auto-enrich toggle to preferences
2026-02-28 16:49:13 +02:00
lashman 92c51dc39e Add Launch and Uninstall buttons to detail view header 2026-02-28 01:56:21 +02:00
lashman 86b047572a Use relative time for update_checked in detail view 2026-02-28 01:54:51 +02:00
lashman 7697983045 Use relative timestamps everywhere instead of raw date strings 2026-02-28 01:52:56 +02:00
lashman 5254de4a52 Use undo toast for integration removal instead of immediate action 2026-02-28 01:51:40 +02:00
lashman 91882abc3c Consolidate preferences into General and Updates pages 2026-02-28 01:50:38 +02:00
lashman 6a546396ed Show updates-available banner in Installed view 2026-02-28 01:48:50 +02:00
lashman 68918af00a Add Ctrl+1/2/3 keyboard shortcuts for view switching
Register show-installed, show-catalog, and show-updates actions
with Ctrl+1, Ctrl+2, Ctrl+3 accelerators. Update the keyboard
shortcuts dialog to show the new navigation shortcuts.
2026-02-28 01:45:32 +02:00
lashman 4596cce11d Default to Catalog tab when library is empty on first launch
When no AppImages are found in the database, switch the ViewStack
to the Catalog page so users see the discovery experience first.
2026-02-28 01:44:41 +02:00
lashman 7e93f1632e Replace technical jargon with user-friendly labels in detail view
Rename Digital signature to Verified by developer, StartupWMClass
to Window class (advanced), SHA256 to File checksum, and File Type
Associations to Opens these file types.
2026-02-28 01:44:09 +02:00
lashman e311f6b230 Consolidate detail view from 4 tabs to 2 (About + Details)
Merge Overview into About tab, combine System + Security + Storage
into a single Details tab. Map old GSettings tab names to new ones
for backward compatibility.
2026-02-28 01:42:35 +02:00
lashman 80a81191ab Simplify app card badges, remove colored status borders
Remove status-ok/status-attention colored border classes from cards.
Drop the verbose Wayland badge from cards (detail view handles it).
Merge extract_and_run into the OK FUSE statuses since it works.
2026-02-28 01:41:28 +02:00
lashman d0291caf75 Show update count badge on Updates tab in ViewSwitcherBar
Add updatable_count() database method and refresh_update_badge()
window method. The Updates tab now shows a numeric badge with the
number of available updates and highlights with needs_attention.
2026-02-28 01:40:22 +02:00
lashman 6adc47a8d3 Slim down hamburger menu, move Preferences to bottom section
Remove Scan, Check for Updates, and Browse Catalog from the hamburger
menu since they are now accessible via the library scan button, Updates
tab, and Catalog tab respectively. Group Preferences with Shortcuts
and About at the bottom.
2026-02-28 01:38:40 +02:00
lashman df186e74db Improve catalog view with relative timestamps, auto-refresh, and installed badges
Show app count with relative last-refreshed time in subtitle. Auto-refresh
catalog on first visit when empty. Show "Installed" badge on catalog entries
that match already-installed AppImages instead of the Install button.
2026-02-28 01:38:01 +02:00
lashman 46f46db98c Add scan button, sort dropdown, and improved empty state to library view
Add a scan button and sort dropdown (Name A-Z, Recently Added, Size)
to the library header bar. Change the empty state to friendlier text
with Scan and Browse Catalog buttons. Default view mode changed to
list. Sort preference persisted via GSettings.
2026-02-28 01:36:47 +02:00
lashman b23f9e14f8 Replace single NavigationView with ViewSwitcher (Installed, Catalog, Updates)
Restructure the app from a single NavigationView into an AdwViewStack
with 3 top-level pages: Installed, Catalog, and Updates. Each page
keeps its own header bar while an AdwViewSwitcherBar at the bottom
provides tab-style navigation between them. The Installed page retains
its own NavigationView for detail drill-down. The catalog action now
switches the ViewStack tab instead of pushing a page.
2026-02-28 01:33:43 +02:00
lashman 3eb15af2c6 Add dedicated Updates view with check-now and update-all 2026-02-28 01:26:10 +02:00
lashman cf8f072820 Add relative_time() helper for human-readable timestamps 2026-02-28 01:24:08 +02:00
lashman 582344ad48 Fix catalog refresh: handle null fields in AppImageHub feed JSON
The AppImageHub feed.json contains null values where arrays/strings are
expected (296 items with null links, 6 items with null inside categories
arrays). Changed AppImageHubItem deserialization to use Option types and
flatten nulls. Also fixed refresh handler to dynamically look up the
catalog source from DB instead of hardcoding id.
2026-02-28 00:46:39 +02:00
lashman 31da61f3da Clean up unused catalog function and wire source info into catalog view 2026-02-28 00:25:05 +02:00
lashman f12e74ba2b Add AppImageHub in-app catalog browser with search, categories, and install 2026-02-28 00:23:36 +02:00
lashman 2704ebb316 Add similar app recommendations from shared categories 2026-02-28 00:17:55 +02:00
lashman 2108b0f3d8 Add portable mode with removable media detection and scanning 2026-02-28 00:16:52 +02:00
lashman f2abfba753 Add update-all, autostart, purge, and verify CLI commands 2026-02-28 00:13:31 +02:00
lashman 27eb9f259d Add system-wide installation via pkexec with polkit policy 2026-02-28 00:11:57 +02:00
lashman c622057830 Add default application selector for browsers, email, and file managers 2026-02-28 00:10:39 +02:00
lashman 585320b363 Add first-run permission summary dialog before launch
Shows what access the AppImage will have on first launch. Lists file,
network, and display server access. Mentions firejail if available.
Tracks prompted status in DB so the dialog only appears once per app.
2026-02-28 00:07:49 +02:00
lashman 8cf71ae858 Add download verification with signature and SHA256 support
New verification module with GPG signature checking and SHA256 hash
computation. Security tab shows verification status, embedded signature
check button, and manual SHA256 input for verifying downloads.
2026-02-28 00:05:43 +02:00
lashman 97c7250666 Extract and apply StartupWMClass for proper taskbar icons
Parse StartupWMClass from embedded .desktop entries during analysis,
store in DB, include in generated .desktop files. Detail view shows
an editable WM class field with apply button for manual override.
2026-02-28 00:02:44 +02:00
lashman 01d453d329 Add file type association manager with MIME type support
Generated .desktop files now include MimeType and StartupWMClass when
available. Detail view system tab shows MIME types with per-type
"Set Default" buttons that use xdg-mime and track previous defaults
in system_modifications for reversal.
2026-02-28 00:00:42 +02:00
lashman 45b45c0724 Add FUSE fix wizard with pkexec installation
Dashboard shows a banner when FUSE is not functional. The wizard
detects the distro, shows the install command, and runs it via pkexec.
Verifies FUSE status after installation completes.
2026-02-27 23:59:26 +02:00
lashman 00a1ed3599 Add icon preview to drag-and-drop dialog
Fast icon extraction pulls .DirIcon from the squashfs without full
analysis. Single-file drops show a 64px preview in the dialog while
the user chooses an import option.
2026-02-27 23:58:09 +02:00
lashman 843af0a8a5 Add full uninstall dialog with data cleanup options
Storage tab now has an Uninstall button that shows checkboxes for the
AppImage file, desktop integration, and each discovered data path.
Removes selected items and cleans up the database on confirm.
2026-02-27 23:56:56 +02:00
lashman 1a6eb4ec99 Add one-click Update All with batch progress dialog
New batch_update_dialog shows all updatable AppImages with per-app
status badges and overall progress bar. Wired as win.update-all action
from dashboard when updates are available.
2026-02-27 23:55:04 +02:00
lashman c311fb27c3 Add background update checks with configurable interval
Schedule automatic update checks on startup based on elapsed time
since last check. Add interval SpinRow to preferences and show
'Last checked' timestamp on the dashboard updates section.
2026-02-27 23:52:28 +02:00
lashman c50b61fc83 Add per-app storage breakdown to detail view 2026-02-27 23:48:21 +02:00
lashman 0777ae1a26 Add system notification support for crashes and updates 2026-02-27 23:47:19 +02:00
lashman 9cf4f1126c Add autostart manager with XDG autostart support 2026-02-27 23:45:58 +02:00
lashman 730452072f Add batch selection and bulk operations to library view 2026-02-27 23:45:01 +02:00
lashman 5b668bd931 Wire auto-integrate setting to scan pipeline 2026-02-27 23:42:22 +02:00
lashman 8934e66f6d Add launch statistics to dashboard 2026-02-27 23:41:22 +02:00
lashman 78f004ff4f Add source URL tracking and display for AppImages 2026-02-27 23:40:18 +02:00
lashman f5685e03e3 Add version rollback support for AppImage updates 2026-02-27 23:38:36 +02:00
lashman e7a056c75a Add keep-in-place option for drag-and-drop imports 2026-02-27 23:37:03 +02:00
lashman 4173f33bbf Auto-fix executable permissions on discovered AppImages 2026-02-27 23:36:14 +02:00
lashman 8dd0dc71ed Add system modification tracking for reversible installs 2026-02-27 23:35:27 +02:00
lashman 6e2e7e8e36 Add detailed implementation plan for 26-task feature roadmap 2026-02-27 23:30:18 +02:00
lashman 5ef3789c7d Add feature roadmap design for 25 new features
Comprehensive design doc covering discovery-to-uninstall lifecycle:
- System modification tracking for clean reversible uninstalls
- Sorted by complexity from quick wins to major features
- Covers FUSE wizard, autostart, MIME types, catalog browser,
  portable mode, batch operations, and more
2026-02-27 23:24:34 +02:00
lashman 830c3cad9d Fix second audit findings and restore crash detection dialog
Address 29 issues found in comprehensive API/spec audit:
- Fix .desktop Exec key path escaping per Desktop Entry spec
- Fix update dialog double-dispatch with connect_response
- Fix version comparison total ordering with lexicographic fallback
- Use RETURNING id for reliable upsert in database
- Replace tilde-based path fallbacks with proper XDG helpers
- Fix backup create/restore path asymmetry for non-home paths
- HTML-escape severity class in security reports
- Use AppStream <custom> element instead of <metadata>
- Fix has_appimage_update_tool to check .is_ok() not .success()
- Use ListBoxRow instead of ActionRow::set_child in ExpanderRow
- Add ELF magic validation to architecture detection
- Add timeout to extract_update_info_runtime
- Skip symlinks in dir_size calculation
- Use Condvar instead of busy-wait in analysis thread pool
- Restore crash detection to single blocking call architecture
2026-02-27 22:48:43 +02:00
lashman e9343da249 Fix 29 audit findings across all severity tiers
Critical: fix unsquashfs arg order, quote Exec paths with spaces,
fix compare_versions antisymmetry, chunk-based signature detection,
bounded ELF header reads.

High: handle NULL CVE severity, prevent pipe deadlock in inspector,
fix glob_match edge case, fix backup archive path collisions, async
crash detection with stderr capture.

Medium: gate scan on auto-scan setting, fix window size persistence,
fix announce() for Stack containers, claim lightbox gesture, use
serde_json for CLI output, remove dead CSS @media blocks, add
detail-tab persistence, remove invalid metainfo categories, byte-level
fuse signature search.

Low: tighten Wayland env var detection, ELF magic validation,
timeout for update info extraction, quoted arg parsing, stop watcher
timer on window destroy, GSettings choices/range constraints, remove
unused CSS classes, define status-ok/status-attention CSS.
2026-02-27 22:08:53 +02:00
lashman f87403794e Remove module-wide dead_code allows, annotate individual items instead 2026-02-27 21:05:56 +02:00
lashman c9f032292a Wire backup, notification, report export, and file watcher modules into UI
- Add export button to security report page (HTML/JSON/CSV via FileDialog)
- Send desktop notifications after security scans when enabled in settings
- Add backup section to storage tab with create/restore/delete and toast feedback
- Start file watcher on launch to auto-refresh library on AppImage changes
- Fix detail view tabs requesting tallest tab height (set vhomogeneous=false)
- Disable tab transitions to avoid visual glitch with variable-height tabs
2026-02-27 21:03:19 +02:00
lashman df3efa3b51 Switch crash dialog from AlertDialog to Dialog for proper sizing
AlertDialog has an internal width cap that ignores content_width. Use
adw::Dialog instead with a ToolbarView layout for full control over the
900x550 dimensions.
2026-02-27 20:31:03 +02:00
lashman bb71f5d4d5 Enlarge crash error dialog for better readability
Widen dialog to 700px, increase height to 500px, use wide layout, and
expand the error output scroll area (250-500px) so more of the stderr
text is visible without scrolling.
2026-02-27 20:25:09 +02:00
lashman d493516efa Add launch crash detection with detailed error dialog, fix all warnings
Detect AppImages that crash immediately after spawning (within 1.5s) by
capturing stderr and using try_wait(). Show a full AlertDialog with a
plain-text explanation, scrollable error output, and a copy-to-clipboard
button. Covers Qt plugin errors, missing libraries, segfaults, permission
issues, and display connection failures.

Move launch operations to background threads in both the detail view and
context menu to avoid blocking the UI during the 1.5s crash detection
window.

Suppress all 57 compiler warnings across future-use modules (backup,
notification, report, watcher) and individual unused fields/variants in
other core modules.
2026-02-27 20:23:10 +02:00
lashman c9c9c0341b Rewrite detail view copy for beginners, add tab transitions and lightbox fixes
- Replace technical jargon with plain language across all 4 detail tabs
- Friendly titles/subtitles with technical details available in tooltips
- Soften terminal commands ("Install with one command" instead of raw commands)
- Rename sections: Desktop Integration -> App Menu, Sandboxing -> App Isolation,
  Vulnerability Scanning -> Security Check, Capabilities -> Features
- Rewrite Wayland/FUSE explanations to avoid acronyms and dev terminology
- Update security report page with beginner-friendly descriptions
- Enable libadwaita 1.7 ViewStack crossfade transitions between detail tabs
- Rewrite screenshot lightbox as separate gtk::Window (fixes scroll jump on
  close, adds click-outside-to-close, rounded corners via CSS)
- Add prev/next navigation arrows and keyboard support to lightbox
2026-02-27 19:48:59 +02:00
lashman 65a1ea78fe Stop executing AppImages during analysis, add screenshot lightbox and favicons
- fuse.rs: Replace Command::new(appimage_path) with 256KB binary scan for
  runtime detection - prevents apps like Affinity from launching on tile click
- fuse.rs: Read only 12 bytes for Type 2 magic check instead of entire file
- security.rs: Use find_squashfs_offset_for() instead of executing AppImages
  with --appimage-offset flag
- updater.rs: Read only first 1MB for update info instead of entire file
- detail_view.rs: Click screenshots to open in lightbox dialog
- detail_view.rs: Fetch favicons from Google favicon service for link rows
2026-02-27 18:58:12 +02:00
lashman 8362e066f7 Fix performance, add screenshots, make banner scrollable
- Make detail view banner scroll with content instead of staying fixed,
  preventing tall banners from eating screen space
- Optimize squashfs offset scanning with buffered 256KB chunk reading
  instead of loading entire file into memory (critical for 1.5GB+ files)
- Add screenshot URL parsing from AppStream XML and async image display
  with carousel in the overview tab
- Fix infinite re-analysis bug: has_appstream check caused every app
  without AppStream data to be re-analyzed on every startup. Now handled
  via one-time migration reset in v10
- Database migration v10: add screenshot_urls column, reset analysis
  status for one-time re-scan with new parser
2026-02-27 18:44:50 +02:00
lashman 1bb7a3bdc0 Add comprehensive AppImage metadata extraction, display, and bug fixes
- Add AppStream XML parser (quick-xml) to extract rich metadata from bundled
  metainfo/appdata files: description, developer, license, URLs, keywords,
  categories, content rating, release history, and MIME types
- Database migration v9: 16 new columns for extended metadata storage
- Extended inspector to parse AppStream XML, desktop entry extended fields,
  and detect binary signatures without executing AppImages
- Redesigned detail view overview tab with 8 conditional groups: About,
  Description, Links, Release History, Usage, Capabilities, File Info
- Fix crash on exit caused by stale GLib SourceId removal in debounce timers
- Fix wayland.rs executing AppImages directly to detect squashfs offset,
  replaced with safe binary scan via find_squashfs_offset_for()
- Fix scan skipping re-analysis of apps missing new metadata fields
2026-02-27 18:31:07 +02:00
lashman 39b773fed5 Add implementation plan for comprehensive AppImage metadata extraction
Seven tasks covering: quick-xml dependency, AppStream XML parser, DB
migration v9, extended desktop entry parsing, analysis pipeline updates,
and redesigned overview tab with 8 metadata groups.
2026-02-27 18:12:33 +02:00
lashman fc3ee9ba8f Add comprehensive AppImage metadata extraction design document
Covers all metadata sources from Type 1/2 ELF headers through desktop
entries to AppStream XML, with schema, parser, and UI display plans.
2026-02-27 18:08:24 +02:00
lashman 6526f92a6f Fix icon extraction, drop overlay styling, and card padding
- Fix upsert_appimage returning 0 for existing records by falling
  back to a SELECT query when last_insert_rowid is 0
- Replace --appimage-offset execution with binary squashfs magic scan
  to avoid hanging on AppImages with custom AppRun scripts
- Add 5-second timeout fallback if binary scan fails
- Extract desktop files from usr/share/applications/ for reverse-DNS
  named entries that root-level *.desktop glob misses
- Add root-level png/svg fallback in icon search
- Add CSS for drop overlay scrim, drop zone card, and drop zone icon
- Add card padding (24px 20px) so content does not touch card edges
- Always scan on startup to discover new AppImages
2026-02-27 17:49:04 +02:00
lashman 423323d5a9 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
2026-02-27 17:16:41 +02:00
lashman a7ed3742fb Fix GTK CSS warnings and popover cleanup on widget destroy
Remove overflow property from .icon-rounded (not valid in GTK CSS).
Remove prefers-reduced-motion media query (not supported by GTK CSS
engine - reduced motion is handled by gtk-enable-animations setting).
Unparent PopoverMenu on widget destroy to prevent finalization warnings
when library view refreshes.
2026-02-27 11:14:14 +02:00
lashman 33cc8a757a Implement UI/UX overhaul - cards, list, tabbed detail, context menu
Card view: 200px cards with 72px icons, .title-3 names, version+size
combined line, single priority badge, libadwaita .card class replacing
custom .app-card CSS.

List view: 48px rounded icons, .rich-list class, structured two-line
subtitle (description + version/size), single priority badge.

Detail view: restructured into ViewStack/ViewSwitcher with 4 tabs
(Overview, System, Security, Storage). 96px hero banner with gradient
background. Rows distributed logically across tabs.

Context menu: right-click (GestureClick button 3) and long-press on
cards and list rows. Menu items: Launch, Check for Updates, Scan for
Vulnerabilities, Integrate/Remove Integration, Open Containing Folder,
Copy Path. All backed by parameterized window actions.

CSS: removed custom .app-card rules (replaced by .card), added
.icon-rounded for list icons, .detail-banner gradient, and
.detail-view-switcher positioning.
2026-02-27 11:10:23 +02:00
lashman 4f7d8560f1 Add UI/UX overhaul design document 2026-02-27 10:56:02 +02:00
lashman 2f56439b6e Suppress unused warning on announce() accessibility helper 2026-02-27 10:10:21 +02:00
lashman 4b8592801b Update window title dynamically for WCAG 2.4.8 Location compliance 2026-02-27 10:09:31 +02:00
lashman 9c60dfb252 Add WCAG accessible labels and confirmation dialog to duplicate removal 2026-02-27 10:07:34 +02:00
lashman fae87a753a Add WCAG accessible labels and confirmation dialog to cleanup wizard 2026-02-27 10:07:17 +02:00
lashman 2ea85ac700 Add WCAG accessible labels to preferences buttons and directory list 2026-02-27 10:06:37 +02:00
lashman 1a608c0109 Add WCAG accessible labels to integration dialog list boxes 2026-02-27 10:06:33 +02:00
lashman 1bafb135f0 Rewrite update dialog text to plain language for WCAG readability 2026-02-27 10:06:30 +02:00
lashman 3642fbd542 Add WCAG tooltips and expanded abbreviations to security report 2026-02-27 10:06:21 +02:00
lashman 0aeb445554 Add WCAG tooltips, plain language, busy states, and banner role to detail view 2026-02-27 10:04:46 +02:00
lashman 1ac5f41d69 Add WCAG accessible labels to library view buttons, list box, and search bar 2026-02-27 10:03:28 +02:00
lashman 66fc582cce Add WCAG tooltips for technical terms on dashboard 2026-02-27 10:03:16 +02:00
lashman 7852e7ab4b Add accessible label to integration emblem overlay in app cards 2026-02-27 10:02:53 +02:00
lashman 19791168f3 Add WCAG accessibility helpers: labeled badges, live announcements, copy button label 2026-02-27 10:01:37 +02:00
lashman df533dda0a Add WCAG AAA focus indicators, high-contrast mode, and reduced-motion coverage 2026-02-27 09:59:44 +02:00
lashman dc97a6cbbc Add WCAG 2.2 AAA compliance design document
Comprehensive accessibility design covering all four WCAG principles
(Perceivable, Operable, Understandable, Robust) for the Driftwood
GTK4/libadwaita AppImage manager.
2026-02-27 09:35:35 +02:00
lashman fa28955919 Implement Driftwood AppImage manager - Phases 1 and 2
Phase 1 - Application scaffolding:
- GTK4/libadwaita application window with AdwNavigationView
- GSettings-backed window state persistence
- GResource-compiled CSS and schema
- Library view with grid/list toggle, search, sorting, filtering
- Detail view with file info, desktop integration controls
- Preferences window with scan directories, theme, behavior settings
- CLI with list, scan, integrate, remove, clean, inspect commands
- AppImage discovery, metadata extraction, desktop integration
- Orphaned desktop entry detection and cleanup
- AppImage packaging script

Phase 2 - Intelligence layer:
- Database schema v2 with migration for status tracking columns
- FUSE detection engine (libfuse2/3, fusermount, /dev/fuse, AppImageLauncher)
- Wayland awareness engine (session type, toolkit detection, XWayland)
- Update info parsing from AppImage ELF sections (.upd_info)
- GitHub/GitLab Releases API integration for update checking
- Update download with progress tracking and atomic apply
- Launch wrapper with FUSE auto-detection and usage tracking
- Duplicate and multi-version detection with recommendations
- Dashboard with system health, library stats, disk usage
- Update check dialog (single and batch)
- Duplicate resolution dialog
- Status badges on library cards and detail view
- Extended CLI: status, check-updates, duplicates, launch commands

49 tests passing across all modules.
2026-02-26 23:04:27 +02:00
lashman 588b1b1525 Remove design document from tracking 2026-02-26 20:53:41 +02:00
lashman cd61b480ad Add Driftwood design document - modern AppImage manager for Wayland-era Linux desktops 2026-02-26 20:51:46 +02:00
7 changed files with 175 additions and 33 deletions
+137
View File
@@ -0,0 +1,137 @@
# Contributing to Driftwood
## Building from source
### Dependencies
- Rust 1.75+ and Cargo
- GTK 4.16+ development headers (`libgtk-4-dev` or `gtk4-devel`)
- libadwaita 1.6+ development headers (`libadwaita-1-dev` or `libadwaita-devel`)
- SQLite 3 development headers
- gettext development headers
- `glib-compile-resources` and `glib-compile-schemas` (from `libglib2.0-dev-bin`)
### Quick start
```sh
git clone https://github.com/driftwood-app/driftwood
cd driftwood
cargo build
cargo run
```
### Running tests
```sh
cargo test
```
## Project structure
```
driftwood/
Cargo.toml # Rust package manifest
build.rs # GResource and GSettings compilation
meson.build # Meson build system for installation
src/
main.rs # Entry point, GResource init, CLI dispatch
application.rs # GtkApplication subclass, CSS loading, app actions
window.rs # Main window, navigation, scanning orchestration
config.rs # App ID and version constants
cli.rs # Command-line interface (clap)
i18n.rs # Internationalization (gettext wrappers)
core/ # Backend logic (no GTK dependencies)
database.rs # SQLite database (rusqlite), all queries
discovery.rs # Filesystem scanning, AppImage detection, SHA256
inspector.rs # AppImage metadata extraction (icon, desktop entry)
integrator.rs # Desktop integration (.desktop files, icons)
launcher.rs # AppImage launching with FUSE/sandbox support
updater.rs # Update checking and applying (GitHub, zsync)
fuse.rs # FUSE status detection
wayland.rs # Wayland compatibility analysis
security.rs # CVE scanning via OSV.dev API
duplicates.rs # Duplicate and multi-version detection
footprint.rs # Disk footprint analysis (config/data/cache)
orphan.rs # Orphaned desktop entry detection and cleanup
ui/ # GTK4/libadwaita UI components
library_view.rs # Main grid/list view of AppImages
app_card.rs # Individual AppImage card widget
detail_view.rs # Full detail page for a single AppImage
dashboard.rs # System health dashboard
preferences.rs # Preferences dialog
update_dialog.rs # Update check and apply dialog
duplicate_dialog.rs # Duplicate resolution dialog
cleanup_wizard.rs # Disk space reclamation wizard
security_report.rs # Security scan results view
integration_dialog.rs # Desktop integration confirmation
widgets.rs # Shared utility widgets (badges, sections)
data/
app.driftwood.Driftwood.gschema.xml # GSettings schema
app.driftwood.Driftwood.desktop # Desktop entry for Driftwood itself
app.driftwood.Driftwood.metainfo.xml # AppStream metadata
resources.gresource.xml # GResource manifest
resources/style.css # Application CSS
po/ # Translation files
POTFILES.in # Files with translatable strings
LINGUAS # Available translations
build-aux/ # Build helpers
app.driftwood.Driftwood.json # Flatpak manifest
build-appimage.sh # AppImage build script
packaging/
PKGBUILD # Arch Linux AUR package
```
## Architecture
The codebase is split into three layers:
1. **core/** - Pure Rust business logic. No GTK dependencies. Can be tested
independently. Each module handles one concern.
2. **ui/** - GTK4/libadwaita widgets. Each view is a function that builds a
widget tree. Uses `Rc<Database>` for shared database access.
3. **window.rs / application.rs** - Orchestration layer. Connects UI to core,
handles navigation, spawns background threads for scanning.
Background work (scanning, update checks, security scans) runs on
`gio::spawn_blocking` threads. Results are sent back to the main thread
via `glib::spawn_future_local`.
## Coding conventions
- Follow standard Rust formatting (`cargo fmt`)
- All new code must compile with zero warnings
- Add tests for core/ modules (81+ tests currently)
- Use `log::info!`, `log::warn!`, `log::error!` for diagnostics
- User-facing strings should be wrapped in `i18n()` for translation
- Use `adw::` widgets over raw `gtk::` when an Adwaita equivalent exists
- Status badges use CSS classes: `badge-success`, `badge-warning`, `badge-error`
## Database
SQLite database stored at `~/.local/share/driftwood/driftwood.db`. Schema
migrates automatically (v1 through v4). All queries are in `core/database.rs`.
## Testing
```sh
# Run all tests
cargo test
# Run tests for a specific module
cargo test core::database
cargo test core::updater
# Run with output
cargo test -- --nocapture
```
Tests use `Database::open_in_memory()` for isolation.
+1 -1
View File
@@ -5,7 +5,7 @@
<policyconfig>
<vendor>Driftwood</vendor>
<vendor_url>https://git.lashman.live/lashman/driftwood</vendor_url>
<vendor_url>https://github.com/driftwood-appimage</vendor_url>
<action id="app.driftwood.Driftwood.system-install">
<description>Install AppImage system-wide</description>
+2 -2
View File
@@ -5,8 +5,8 @@ pkgver=0.1.0
pkgrel=1
pkgdesc='Modern AppImage manager for GNOME desktops'
arch=('x86_64')
url='https://git.lashman.live/lashman/driftwood'
license=('CC0-1.0')
url='https://github.com/driftwood-app/driftwood'
license=('GPL-3.0-or-later')
depends=(
'gtk4'
'libadwaita'
+24 -19
View File
@@ -29,6 +29,7 @@ pub struct AppImageRecord {
pub first_seen: String,
pub last_scanned: String,
pub file_modified: Option<String>,
// Phase 2 fields
pub fuse_status: Option<String>,
pub wayland_status: Option<String>,
pub update_info: Option<String>,
@@ -37,17 +38,20 @@ pub struct AppImageRecord {
pub update_checked: Option<String>,
pub update_url: Option<String>,
pub notes: Option<String>,
// Phase 3 fields
pub sandbox_mode: Option<String>,
// Phase 5 fields
pub runtime_wayland_status: Option<String>,
pub runtime_wayland_checked: Option<String>,
// Async analysis pipeline
pub analysis_status: Option<String>,
// Custom launch arguments
pub launch_args: Option<String>,
// Phase 6 fields
pub tags: Option<String>,
pub pinned: bool,
pub avg_startup_ms: Option<i64>,
// extended metadata
// Phase 9 fields - comprehensive metadata
pub appstream_id: Option<String>,
pub appstream_description: Option<String>,
pub generic_name: Option<String>,
@@ -65,7 +69,7 @@ pub struct AppImageRecord {
pub desktop_actions: Option<String>,
pub has_signature: bool,
pub screenshot_urls: Option<String>,
// system modification tracking
// Phase 11 fields - system modification tracking
pub previous_version_path: Option<String>,
pub source_url: Option<String>,
pub autostart: bool,
@@ -342,7 +346,7 @@ impl Database {
}
fn init_schema(&self) -> SqlResult<()> {
// base tables
// Phase 1 base tables
self.conn.execute_batch(
"CREATE TABLE IF NOT EXISTS schema_version (
version INTEGER NOT NULL
@@ -531,8 +535,8 @@ impl Database {
}
fn migrate_to_v2(&self) -> SqlResult<()> {
// Add columns to appimages table
let extra_columns = [
// Add Phase 2 columns to appimages table
let phase2_columns = [
"fuse_status TEXT",
"wayland_status TEXT",
"update_info TEXT",
@@ -542,11 +546,12 @@ impl Database {
"update_url TEXT",
"notes TEXT",
];
for col in &extra_columns {
for col in &phase2_columns {
let sql = format!("ALTER TABLE appimages ADD COLUMN {}", col);
self.conn.execute_batch(&sql).ok();
}
// Phase 2 tables
self.conn.execute_batch(
"CREATE TABLE IF NOT EXISTS launch_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -590,7 +595,7 @@ impl Database {
}
fn migrate_to_v3(&self) -> SqlResult<()> {
// security scanning
// Phase 3 tables: security scanning
self.conn.execute_batch(
"CREATE TABLE IF NOT EXISTS bundled_libraries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -1707,7 +1712,7 @@ impl Database {
self.conn.query_row("SELECT COUNT(*) FROM appimages", [], |row| row.get(0))
}
// --- Status updates ---
// --- Phase 2: Status updates ---
pub fn update_fuse_status(&self, id: i64, status: &str) -> SqlResult<()> {
self.conn.execute(
@@ -1806,7 +1811,7 @@ impl Database {
rows.collect()
}
// --- Launch tracking ---
// --- Phase 2: Launch tracking ---
pub fn record_launch(&self, appimage_id: i64, source: &str) -> SqlResult<()> {
self.conn.execute(
@@ -1849,7 +1854,7 @@ impl Database {
rows.collect()
}
// --- Update history ---
// --- Phase 2: Update history ---
pub fn record_update(
&self,
@@ -1869,7 +1874,7 @@ impl Database {
Ok(())
}
// --- Security scanning ---
// --- Phase 3: Security scanning ---
pub fn clear_bundled_libraries(&self, appimage_id: i64) -> SqlResult<()> {
self.conn.execute(
@@ -2021,7 +2026,7 @@ impl Database {
Ok(summary)
}
// --- App data paths ---
// --- Phase 3: App data paths ---
pub fn insert_app_data_path(
&self,
@@ -2101,7 +2106,7 @@ impl Database {
Ok(())
}
// --- Runtime Wayland ---
// --- Phase 5: Runtime Wayland ---
pub fn update_runtime_wayland_status(&self, id: i64, status: &str) -> SqlResult<()> {
self.conn.execute(
@@ -2111,7 +2116,7 @@ impl Database {
Ok(())
}
// --- Config Backups ---
// --- Phase 5: Config Backups ---
pub fn insert_config_backup(
&self,
@@ -2181,7 +2186,7 @@ impl Database {
Ok(())
}
// --- CVE Notifications ---
// --- Phase 5: CVE Notifications ---
pub fn has_cve_been_notified(&self, appimage_id: i64, cve_id: &str) -> SqlResult<bool> {
let count: i32 = self.conn.query_row(
@@ -2206,7 +2211,7 @@ impl Database {
Ok(())
}
// --- Sandbox Profiles ---
// --- Phase 5: Sandbox Profiles ---
pub fn insert_sandbox_profile(
&self,
@@ -2276,7 +2281,7 @@ impl Database {
rows.collect()
}
// --- Tags, Pin, Startup Time ---
// --- Phase 6: Tags, Pin, Startup Time ---
pub fn update_tags(&self, id: i64, tags: Option<&str>) -> SqlResult<()> {
self.conn.execute(
@@ -2350,7 +2355,7 @@ impl Database {
}
}
// --- Runtime Updates ---
// --- Phase 5: Runtime Updates ---
pub fn record_runtime_update(
&self,
@@ -3254,7 +3259,7 @@ mod tests {
}
#[test]
fn test_status_updates() {
fn test_phase2_status_updates() {
let db = Database::open_in_memory().unwrap();
let id = db.upsert_appimage("/path/app.AppImage", "app.AppImage", Some(2), 1000, true, None).unwrap();
+2 -2
View File
@@ -87,7 +87,7 @@ pub fn detect_duplicates(db: &Database) -> Vec<DuplicateGroup> {
let mut groups = Vec::new();
// Find exact duplicates by SHA256 hash
// Phase 1: Find exact duplicates by SHA256 hash
let hash_groups = group_by_hash(&records);
for (hash, members) in &hash_groups {
if members.len() > 1 {
@@ -95,7 +95,7 @@ pub fn detect_duplicates(db: &Database) -> Vec<DuplicateGroup> {
}
}
// Find same app name groups (excluding already-found exact dupes)
// Phase 2: Find same app name groups (excluding already-found exact dupes)
let exact_dupe_ids: std::collections::HashSet<i64> = groups
.iter()
.flat_map(|g| g.members.iter().map(|m| m.record.id))
+2 -2
View File
@@ -117,7 +117,7 @@ pub fn show_drop_dialog(
let on_complete_ref = on_complete.clone();
glib::spawn_future_local(async move {
// Fast registration (copy + DB upsert only)
// Phase 1: Fast registration (copy + DB upsert only)
let result = gio::spawn_blocking(move || {
register_dropped_files(&files, copy)
})
@@ -143,7 +143,7 @@ pub fn show_drop_dialog(
toast_ref.add_toast(widgets::info_toast(&msg));
}
// Background analysis for each file
// Phase 2: Background analysis for each file
let on_complete_bg = on_complete_ref.clone();
for reg in registered {
let on_complete_inner = on_complete_bg.clone();
+7 -7
View File
@@ -1571,11 +1571,11 @@ impl DriftwoodWindow {
let toast_overlay = self.imp().toast_overlay.get().unwrap().clone();
let window_weak = self.downgrade();
// Two-pass scan:
// Fast pass: discover files, upsert into DB, mark pending analysis
// Background pass: heavy analysis per file
// Two-phase scan:
// Phase 1 (fast): discover files, upsert into DB, mark pending analysis
// Phase 2 (background): heavy analysis per file
glib::spawn_future_local(async move {
// Fast registration
// Phase 1: Fast registration
let result = gio::spawn_blocking(move || {
let bg_db = Database::open().expect("Failed to open database for scan");
let start = Instant::now();
@@ -1646,7 +1646,7 @@ impl DriftwoodWindow {
}
log::info!(
"Scan: {} files, {} new, {} removed, {} skipped (unchanged), took {}ms",
"Scan phase 1: {} files, {} new, {} removed, {} skipped (unchanged), took {}ms",
total, new_count, removed_count, skipped_count, start.elapsed().as_millis()
);
@@ -1665,7 +1665,7 @@ impl DriftwoodWindow {
.await;
if let Ok((total, new_count, needs_analysis)) = result {
// Dismiss the "Scanning..." toast now that fast scan is done
// Dismiss the "Scanning..." toast now that Phase 1 is done
if let Some(ref toast) = scan_toast {
toast.dismiss();
}
@@ -1689,7 +1689,7 @@ impl DriftwoodWindow {
};
toast_overlay.add_toast(widgets::info_toast(&msg));
// Background analysis per file with debounced UI refresh
// Phase 2: Background analysis per file with debounced UI refresh
let running = analysis::running_count();
if running > 0 {
log::info!("Analyzing {} AppImage(s) in background ({} already running)", needs_analysis.len(), running);