* feat: add browser picker for opening URLs
- Introduce a QML modal allowing users to select a web browser to open a given URL.
- Add a CLI command `dms open <url>` that sends a `browser.open` request to the DMS server.
- Implement server‑side Browser manager, request handling, and subscription handling to propagate open events to clients.
- Extend router and server initialization to register the new “browser” capability and include it in advertised capabilities.
- Expose `openUrlRequested` signal in DMSService.qml and connect it to the modal for seamless UI activation.
- Add a desktop entry for the Browser Picker and update the active subscriptions list to include the browser service.
* fix(browser-picker): resolve QML errors in BrowserPickerModal and DMSShell
* fix(browser-picker): fix socket discovery in dms open command
* feat: add keyboard navigation and dynamic model to browser picker
- Replace the static browsers array with a ListModel built from AppSearchService, ensuring robust iteration and future‑proofing of the browser list.
- Introduce keyboard navigation (arrow keys and Enter) using selectedIndex and gridColumns, allowing users to select a browser without a mouse.
- Reset URL, selected index, and navigation flag when the modal closes to avoid stale state.
- Redesign the grid layout to compute cell width from columns, improve focus handling, and use AppLauncherGridDelegate for a consistent UI.
- Enhance delegate behavior to update selection on hover and reset keyboard navigation state appropriately.
* feat: add searchable list/grid view to browser picker
- Introduce view mode setting (list or grid) saved in SettingsData for persistent user preference
- Add search field with real‑time filtering to quickly locate a browser by name
- Sort browsers by usage frequency from AppUsageHistoryData, falling back to alphabetical order
- Provide UI toggle buttons to switch between list and grid layouts, updating the stored setting
- Adjust keyboard navigation logic to support both layouts and improve focus handling
- Refine modal dimensions and header layout for better visual consistency
- Record launched browser usage to keep usage rankings up‑to‑date.
* feat(browser-picker): improve UX with search, view persistence, and usage tracking
Enhance BrowserPickerModal to match AppLauncher design and functionality:
UI/UX Improvements:
- Add search bar with DankTextField for filtering browsers
- Move view mode switcher (list/grid) to header next to title
- Persist view mode preference to SettingsData.browserPickerViewMode
- Match AppLauncher dimensions (520x500)
- Add proper spacing between list items
- Improve URL display with truncation (single line, elide middle)
- Remove redundant close button
Functionality:
- Implement separate browser usage tracking in SettingsData.browserUsageHistory
- Sort browsers by most recently used (independent from app launcher stats)
- Add keyboard navigation auto-scrolling for list and grid views
- Track usage count, last used timestamp, and browser name
- Filter browsers by search query
Technical:
- Add ensureVisible() functions to DankListView and DankGridView
- Store browser usage with count, lastUsed, and name fields
- Update browser list reactively on search query changes
* feat(browser-picker): use appLauncherGridColumns setting for grid layout
Make browser picker grid view respect the same column setting as the app launcher
for consistent UI across both components.
* refactor: make browser picker extensible for any MIME type/category
Refactor browser picker into a generic, reusable application picker
system that can handle any MIME type or application category, similar
to Junction. This addresses the maintainer feedback about making the
functionality "as re-usable as possible."
Frontend (QML):
- Create generic AppPickerModal component (~450 lines)
- Configurable filtering by application categories
- Customizable title, view modes, and usage tracking
- Emits applicationSelected signal for flexibility
- Refactor BrowserPickerModal as thin wrapper (473 → 46 lines)
- Demonstrates how to create specialized pickers
- Maintains all existing browser picker functionality
Backend (Go):
- Rename browser package to apppicker for clarity
- Enhance event model to support:
- MIME types (for future file associations)
- Application categories (WebBrowser, Office, Graphics, etc.)
- Request types (url, file, custom)
- Maintain backward compatibility with browser.open method
- Add new apppicker.open method for generic usage
CLI:
- Rename commands_browser.go to commands_open.go
- Add extensibility flags:
--mime/-m: Filter by MIME type
--category/-c: Filter by category (repeatable)
--type/-t: Specify request type
- Examples:
dms open file.pdf --category Office
dms open image.png --category Graphics
DMSService:
- Add appPickerRequested signal for generic events
- Smart routing between URL and generic app picker events
- Fully backward compatible
Benefits:
- Easy to create new pickers (~15 lines of wrapper code)
- Foundation for universal file handling system
- Consistent UX across all picker types
- Ready for MIME type associations
Future extensions:
- PDF picker, image viewer picker, text editor picker
- Default application management
- File association UI in settings
- Multi-MIME type desktop file integration
* fix(cli): remove all shorthands from open command flags for consistency
Remove shorthands from --mime, --category, and --type flags to maintain
consistency and avoid conflicts with global flags.
Flags now (all long-form only):
- --category: Application categories
- --mime: MIME type
- --type: Request type
Global flags still available:
- --config, -c: Config directory path
* style: apply gofmt formatting to apppicker files
Fix formatting issues caught by CI:
- Align struct field spacing in OpenEvent
- Align variable declaration spacing
- Fix Args field alignment in cobra.Command
* feat(apppicker): add generic file opener with auto MIME detection
Implements Junction-style generic file opening capabilities:
**Backend (Go):**
- Enhanced CLI to parse file:// URIs and extract file paths
- Auto-detect MIME types from file extensions using Go's mime package
- Auto-map MIME types to desktop categories:
- Images → Graphics, Viewer
- Videos → Video, AudioVideo
- Audio → Audio, AudioVideo
- Text → TextEditor, Office (or WebBrowser for HTML)
- PDFs → Office, Viewer
- Office docs → Office
- Archives → Archiving, Utility
- Added debug logging to CLI and server handler for troubleshooting
**Frontend (QML):**
- Added generic AppPickerModal (filePickerModal) for file selection
- Connected to DMSService.appPickerRequested signal
- Implemented onApplicationSelected handler with desktop entry field code support:
- %f/%F for file paths
- %u/%U for file:// URIs
- Fallback to appending path if no field codes
- Separate usage tracking: filePickerUsageHistory
**Desktop Integration:**
- Updated dms-open.desktop to handle x-scheme-handler/file
- Changed category from Network;WebBrowser to Utility (more generic)
- Added text/html to MIME types
**Usage:**
Set DMS as default for specific MIME types in ~/.config/mimeapps.list:
text/plain=dms-open.desktop
image/png=dms-open.desktop
application/pdf=dms-open.desktop
Then use:
xdg-open file.txt
xdg-open image.png
dms open document.pdf
The picker will show appropriate apps based on auto-detected categories.
Related to #815
* fix: resolve relative path handling by converting to absolute paths
- Convert file:// URIs to absolute filesystem paths for reliable file resolution
- Convert plain local file arguments to absolute paths to ensure consistent processing
- Update log messages to display absolute paths, improving traceability
- Retain request type detection while using absolute path extensions for MIME type inference
* feat(app-picker): add Tab key view toggle and fix targetData binding
- Add Tab key to toggle between grid and list views for better keyboard UX
- Fix bug where targetData binding broke after first modal close
- Removed targetData reset from onDialogClosed
- Parent components (BrowserPickerModal, filePickerModal) now manage targetData
- Fixes issue where URL/file path disappeared on subsequent opens
* fix(app-picker): properly escape URLs and file paths for shell execution
- Add shellEscape() function to wrap arguments in single quotes
- Prevents shell interpretation of special characters (&, ?, =, spaces, etc.)
- Fixes bug where URLs with query parameters were truncated at first &
- Example: http://localhost:36275/vnc.html?autoconnect=true&reconnect=true
now properly passes the full URL instead of cutting at first &
- Applied to both BrowserPickerModal (URLs) and filePickerModal (file paths)
* fix: check error return from InitializeAppPickerManager