5b4e2c357283d2407175a0c71d76051fb7f6f715
9
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7cdf5a7069 |
feat(settings): even out dropdowns and tidy the About page (#754)
* feat(settings): even out dropdowns and tidy the About page Pin combos to a shared right-hand column so long labels cannot stretch a row. Fold the dictation-tone preview into a two-stage Start/Stop button, quiet the model status card, shorten Performance copy, and rebuild About with combined links, channel+Check, family platform tiles, and Talk to us moved up next to the license. * fix(settings): keep tone preview on start if the cue fails Do not flip Start/Stop when preview_tone_cue returns false, so a missing file or silent player cannot skip the start cue. Also annotate PreferenceRow.set_title / set_subtitle. * fix(settings): paint About icons for dark dialogs Dark ink on Adwaita/Yaru-dark buttons made the family tiles and Talk to us marks disappear. Pick a light foreground on dark themes (and keep the original ink on light ones) so the marks match the labels. * fix(settings): show Android and iOS marks on VocaPhone VocaPhone covers both, so the family tile now uses the Android robot and the Apple mark instead of a single phone icon. * fix(settings): cut repeated About copy Name the AGPL once on the License row. The VocaHQ blurb is just the private-dictation line. VocaPhone says TestFlight, not source-only, and Gateway is self-hosted and headless. * fix(settings): space About icons from their labels Talk-to-us buttons and the family tiles were packing the mark against the text. Give the image an end margin and a wider gap in the family tile. |
||
|
|
c337d8f56d |
feat(shortcuts): default to hold Right Alt (push-to-talk) for new installs (#648)
* feat(shortcuts): default to hold Right Alt push-to-talk on first install Double-tap Ctrl conflicts with many desktop and app shortcuts, so new installs now use hold Right Alt (Option) in push-to-talk mode. Existing config.json values are preserved unchanged. Updates README, user guide, AGENTS.md, first-run dialog, website copy, and tests to match the new defaults. * refactor(shortcuts): trim redundant default-change test and comments Drop the fresh-install assertion that duplicated DEFAULT_CONFIG coverage, remove the duplicated Right-Alt rationale from config_manager, and drop a vacuous source-string check from the settings shortcuts test. * fix(shortcuts): align install.sh seeds and preserve legacy toggle mode install.sh still wrote ctrl+ctrl without mode, so merges with the new push_to_talk default became hold-Ctrl. Seed right_alt + push_to_talk for new installs, and migrate existing shortcut-only configs to mode=toggle so prior behavior is unchanged. * style(config): fix black formatting after shortcuts migration * fix(shortcuts): preserve legacy defaults when shortcuts section is missing Existing config files without a shortcuts section previously inherited ctrl+ctrl toggle from DEFAULT_CONFIG. Pin those historical defaults on upgrade so the new first-install Right Alt push-to-talk defaults do not silently change behavior. * docs(agents): unwrap hard-broken dictation control paragraph Keep the AGENTS.md paragraph as a single line like the surrounding prose. |
||
|
|
27ecf880a8 |
fix(settings): restore custom shortcut Record/Set controls (#619)
* fix(settings): restore custom shortcut Record/Set controls Gtk.Widget.show_all() is a no-op while no_show_all is True, so the contextual Custom Shortcut row never appeared after selecting it in the searchable settings UI. Clear the flag before showing and restore it on hide. Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com> * fix(settings): sync custom row when reverting shortcut separators Selecting Custom Shortcut then a combo group separator restored the preset id but left Record/Set visible. Reuse _sync_shortcut_selection_ui so combo and custom-row visibility stay aligned. Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com> * fix(settings): clear stale Record/Set hint on separator revert Selecting Custom Shortcut sets a temporary info hint; clicking a combo separator already restored the row visibility but left that hint in place. Refresh the mode description after syncing. Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com> |
||
|
|
e7022f83dd |
feat(settings): searchable sidebar settings instead of seven tabs (#601)
* feat(settings): replace tab navigation with searchable sidebar and topic pages - Sidebar (icon + label) with Gtk.Stack replaces the 7-tab notebook - Live settings search (Ctrl+F): filters rows in place, per-page match counts, dims pages without hits, empty-results state - Topic-based pages per GNOME HIG: Dictation, Speech Model, Audio, Performance, Application, Advanced - Persistent bottom status strip: recognition state, shared mic level bar, and Test Dictation with inline transcription output - GPU device selection moves out of the power-user gate onto the Performance page; Reset to Defaults moves into the Advanced page - Consolidated model info card (info + warning + legend in one surface) - Contextual custom-shortcut row, in-list auto-pause empty state, uniform control widths, aligned group descriptions - Esc clears search, Ctrl+W closes * test(settings): update source-inspection tests for sidebar redesign, add search coverage * fix(settings): index unlocked advanced controls in search Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com> * fix(settings): restore selected page after clearing search Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com> --------- Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com> |
||
|
|
f456160c45 |
fix(ui): keep preset and custom shortcut selection exclusive (#509)
Selecting a preset after recording a custom combo left the custom entry filled, so both looked active. Sync the dropdown to "Custom Shortcut" when a non-preset is set, and clear the custom field when a preset wins. |
||
|
|
be0614010d |
refactor: systematic code quality improvements across 20 dimensions (#377)
* refactor: improve code quality across multiple dimensions Code quality improvements identified and driven by desloppify analysis: **action_handler.py** - Replace 9 repetitive shortcut forwarding methods with data-driven _SHORTCUT_ACTIONS class-level dispatch table - Add _make_shortcut_handler() factory for shortcut closures - Add explicit type annotation for action_handlers dict **config_manager.py** - Move 'import copy' from __init__ to module level (stdlib best practice) - Add _VALID_SECTIONS frozenset for section name validation in set() - Narrow broad Exception catch to (KeyError, TypeError) in set() - Add deprecation warning to save_settings() guiding toward save_config() **tray_indicator.py** - Consolidate all imports at module top level - Remove noqa E402 suppressions for mid-file imports - Move ResourceManager import alongside other local imports **recognition_manager.py** - Narrow broad 'except Exception' to 'except OSError' for audio device enumeration errors - Narrow 'except Exception' to 'except (FileNotFoundError, OSError)' for notification subprocess errors **Tests** - Update test assertions to use specific exception types matching narrowed catches (OSError, FileNotFoundError instead of Exception/RuntimeError) * refactor: improve type safety, callback contracts, and method decomposition **main.py** — Mid-level elegance - Document callback wiring contract: text_callback, action_callback, state_callback with threading context, argument types, and behavior - Add return type annotations to nested callback functions - Reorder: define callbacks before registration for readability **config_manager.py** — Type safety, error consistency - Add typed accessors: get_str(), get_bool(), get_int(), get_float(), get_optional_int() eliminating Any returns for common access patterns - Narrow load_config exception to (json.JSONDecodeError, OSError) - Narrow save_config exception to (OSError, TypeError) **recognition_manager.py** — Low-level elegance - Decompose _init_whispercpp (141 lines) into three focused methods: - _init_whispercpp: validation and download gating (35 lines) - _load_whispercpp_model: backend detection and model loading (55 lines) - _handle_gpu_fallback: GPU incompatibility recovery (40 lines) - Narrow exception catch from broad Exception to specific types **tray_indicator.py, settings_dialog.py** — Type safety - Migrate config access from untyped get() to typed get_str(), get_bool(), get_optional_int() across 8 call sites * refactor: narrow 11 more broad Exception catches to specific types Systematically replaced broad 'except Exception' with specific exception types across recognition_manager.py: - test_audio_input: (OSError, ValueError) for audio read errors - test_audio_input outer: (OSError, ValueError, RuntimeError) for unexpected - _init_whisper: (RuntimeError, OSError) for engine init failures - _transcribe_with_whisper: (RuntimeError, OSError, ValueError) for transcription - _download_whispercpp_model: (OSError, RuntimeError, ValueError) for downloads - _download_vosk_model: (OSError, RuntimeError, ValueError) for downloads - _download_whisper_model: (OSError, RuntimeError, ValueError) for downloads This brings the total narrowed exception catches to 18+ across the codebase, improving error consistency and making failure modes more predictable. * style: fix black formatting issues Auto-format with black to fix CI lint failures in recognition_manager.py, settings_dialog.py, and test_settings_shortcuts.py. * test: add coverage for typed config accessors Add TestTypedAccessors class with 15 tests covering: - get_str(): string values, defaults, non-string conversion, None handling - get_bool(): boolean values, defaults - get_int(): integer values, invalid input fallback, missing key defaults - get_float(): float values, invalid input fallback - get_optional_int(): int values, None values, missing keys, invalid input Fixes codecov/patch coverage requirement for new typed accessor methods. |
||
|
|
80108c3456 |
feat(shortcuts): add left/right modifier key distinction for keyboard shortcuts (#308)
Allow users to bind voice commands to specific modifier key sides (e.g., Right Ctrl only), preventing conflicts with common left-side shortcuts like Alt+Tab or Ctrl+C. - Expand SUPPORTED_SHORTCUTS from 3 to 9 entries (either/left/right) - Add SHORTCUT_GROUPS for grouped display in settings UI - Implement side-aware key matching in pynput and evdev backends - Update settings dialog with grouped shortcut selector - Add comprehensive tests for side-specific shortcuts Closes #306 |
||
|
|
86ca22ff5c |
feat(shortcuts): add push-to-talk mode and improve shortcut reliability (#278)
* feat(shortcuts): add push-to-talk mode as alternative to toggle This commit implements push-to-talk functionality (Issue #252) as an alternative to the existing double-tap toggle mode: - Add keyboard shortcut mode setting (toggle vs push_to_talk) - In push-to-talk mode: hold key to speak, release to stop - Update both pynput and evdev backends to support press/release callbacks - Add UI controls in settings dialog for mode selection - Maintain backward compatibility with existing toggle mode as default Closes #252 Related: Closes #185 (superseded by push-to-talk approach) * fix(shortcuts): remove duplicate code blocks that broke settings dialog The previous push-to-talk implementation had duplicate code blocks in tray_indicator.py and settings_dialog.py that caused the settings dialog to fail silently. This commit cleans up the duplicate code while preserving the push-to-talk functionality. Fixes issue where settings dialog would not open. * fix(ui): add set_subtitle method to PreferenceRow class The PreferenceRow class was missing a set_subtitle method, which is called by _update_shortcut_ui_for_mode when switching between toggle and push-to-talk modes. This caused an AttributeError that silently crashed the settings dialog during initialization. Also stores subtitle_label as instance variable for later updates. * fix(keyboard): remove duplicate code and fix mode handling Critical fixes for keyboard backends: - evdev_backend.py: Removed duplicate __init__ and _handle_key_event methods - pynput_backend.py: Removed duplicate __init__, _on_press, _on_release methods - Both backends now properly handle toggle and push-to-talk modes Fixed first_run_dialog.py: - Added do_response() override to properly close dialog - Added explicit destroy() call in show_first_run_dialog() Fixed tray_indicator.py: - Added _unregister_keyboard_callbacks() method - Updated _setup_keyboard_shortcuts() to properly clean up old callbacks - Updated update_shortcut() to properly handle mode switching Fixed settings_dialog.py: - Added set_subtitle() method to PreferenceRow class - Updated UI text for push-to-talk mode - Fixed _on_shortcut_changed to properly pass mode to callback All 547 tests pass locally. * feat(shortcuts): improve mode switching and add mode-aware display names Key improvements: - Add SHORTCUT_MODE_DISPLAY_NAMES for mode-specific shortcut names - Add get_shortcut_display_name() function for mode-aware display - Fix restart_with_shortcut() to properly save and restore all callbacks - Fix update_shortcut() to properly handle mode changes - Fix _setup_keyboard_shortcuts() to clear old callbacks before registering new ones - Ensure only one type of callback is active at a time This fixes issues where: - Old callbacks remained registered after mode switch - Single-tap triggered action after switching from push-to-talk to toggle - Display names weren't appropriate for the selected mode * fix(shortcuts): stabilize live mode switching callback lifecycle * test(shortcuts): cover callback reset on mode transitions * fix(shortcuts): remove super preset and migrate legacy config * test(shortcuts): update coverage for super preset removal |
||
|
|
7a1c42aae6 |
feat(shortcuts): add customizable keyboard shortcuts via GUI (#137)
* feat(shortcuts): add customizable keyboard shortcuts via GUI Implement configurable keyboard shortcuts for toggling voice recognition, allowing users to choose between Ctrl+Ctrl, Alt+Alt, Shift+Shift, or Super+Super (Windows key) double-tap shortcuts. Changes: - Add shortcuts configuration section to settings dialog with dropdown - Update keyboard backends (pynput and evdev) to support configurable modifier keys for double-tap detection - Add SUPPORTED_SHORTCUTS, SHORTCUT_DISPLAY_NAMES constants in base module - Update KeyboardShortcutManager to accept and pass shortcut configuration - TrayIndicator now reads shortcut from config on startup - Add comprehensive tests for shortcut configuration and parsing The default shortcut remains Ctrl+Ctrl for backward compatibility. Changes take effect after app restart (noted in UI). Closes #16 * feat(shortcuts): enable live shortcut switching without app restart Add restart_with_shortcut() method to KeyboardShortcutManager that stops the listener, updates the shortcut configuration, and restarts with the new shortcut. The settings dialog now applies shortcut changes immediately with visual feedback indicating success. - Add restart_with_shortcut() to KeyboardShortcutManager - Add update_shortcut() to TrayIndicator for exposing live updates - Update SettingsDialog to use callback for immediate shortcut changes - Show green success message when live switching succeeds - Add 7 new tests for restart_with_shortcut functionality * fix: use Python 3.8 compatible context manager syntax Convert parenthesized context manager (Python 3.10+) to nested with statements for Python 3.8 compatibility in test_keyboard_shortcuts.py |