* fix: Add browserPickerViewMode persistence to settings spec
The BrowserPickerModal (used by xdg-open feature) was not persisting
view mode selection between sessions. While the modal had code to save
the view mode preference, the browserPickerViewMode property was not
registered in SettingsSpec.js, preventing it from being saved to disk.
Added browserPickerViewMode and browserUsageHistory to SettingsSpec.js
to ensure user's view preference (list/grid) is properly persisted.
Fixes view mode reverting to grid after restarting DMS/QuickShell.
* fix: Add view mode persistence for both browser and file pickers
Extended the fix to include both picker modals used by xdg-open:
BrowserPickerModal (URLs):
- Added browserPickerViewMode and browserUsageHistory to SettingsSpec.js
- Already had save logic in BrowserPickerModal.qml
AppPickerModal/filePickerModal (files):
- Added appPickerViewMode and filePickerUsageHistory to SettingsSpec.js
- Added appPickerViewMode and filePickerUsageHistory properties to SettingsData.qml
- Added viewMode binding and onViewModeChanged handler to filePickerModal
Both modals now properly persist user's view preference (list/grid) and
usage history between sessions.
Fixes view mode reverting to default grid after restarting DMS/QuickShell
for both 'dms open https://...' and 'dms open file.pdf' workflows.
* feat: add workspace rename dialog
- Adds a modal dialog to rename the current workspace
- Supports both Niri (via IPC socket) and Hyprland (via hyprctl dispatch)
- Default keybinding: Ctrl+Shift+R to open the dialog
- Pre-fills with current workspace name
- Allows setting empty name to reset to default
* refactor: wrap WorkspaceRenameModal in LazyLoader
Reduces memory footprint when the modal is not in use.
- Aggregate plugins/extensions in new "all" tab
- Quick tab actions
- New tile mode for results
- Plugins can enforce/require view mode, or set preferred default
- Danksearch under "files" category
* 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