Skip to content

feat: add hotkey to toggle top row visibility#186

Merged
conventoangelo merged 2 commits intomainfrom
feat/toggle-top-row
Mar 28, 2026
Merged

feat: add hotkey to toggle top row visibility#186
conventoangelo merged 2 commits intomainfrom
feat/toggle-top-row

Conversation

@conventoangelo
Copy link
Copy Markdown
Owner

@conventoangelo conventoangelo commented Mar 28, 2026

This pull request adds a new global hotkey for toggling the visibility of the top row (number row) in the keyboard UI, along with full support for configuring and enabling/disabling this hotkey through the preferences and hotkey management systems. The implementation includes state management, serialization, UI integration, and test coverage for the new feature.

Hotkey System Enhancements:

  • Added a new toggleTopRowHotKey and its enable/disable flag to the AppState model, including initialization, serialization, deserialization, and copy methods.
  • Updated AppStateNotifier with methods to update the new hotkey and its enabled state.
  • Extended the HotKeyService to register and handle the new hotkey and its callback.
  • Modified MethodCallHandler to support updating the new hotkey and its enabled state from platform calls.

UI and Preferences Integration:

  • Added a HotKeyOption for "Toggle Top Row" in the hotkeys preferences tab, allowing users to change or enable/disable the hotkey.
  • Updated the default keybinding for Preferences to Ctrl+Alt+T and assigned Ctrl+Alt+R to the new "Toggle Top Row" action.
  • Implemented the _toggleTopRow method in the main app state, which toggles the top row, updates preferences, and notifies the preferences window.
  • Handled the updateShowTopRowFromMainWindow method in the preferences screen to synchronize state when triggered from the main window.

Testing:

  • Added and updated tests to cover the new hotkey and its enabled flag in the AppState model and JSON serialization.

Summary by CodeRabbit

  • New Features

    • Added a customizable "Toggle Top Row" hotkey in Preferences with an enable/disable option and transient on-screen feedback.
    • Hotkey settings now persist across sessions and sync between main and preference windows.
    • Reassigned the default "Open Preferences" hotkey from Alt+Ctrl+R to Alt+Ctrl+T.
  • Bug Fixes

    • Improved reliable propagation of top-row visibility changes across app windows.

Copilot AI review requested due to automatic review settings March 28, 2026 17:23
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

Adds a “toggle top row” feature: new AppState hotkey fields and persistence; hotkey registration and handler wiring; new _toggleTopRow() in app main that flips keyboard top-row visibility, updates other windows, shows overlay, and saves preferences; UI and method-call handlers updated; tests extended.

Changes

Cohort / File(s) Summary
State Management
lib/providers/app_state_provider.dart, test/providers/app_state_provider_test.dart, test/services/state_service_test.dart
Adds toggleTopRowHotKey and enableToggleTopRowHotKey to AppState (defaults, copyWith, toJson/fromJson). Adds notifier methods updateToggleTopRowHotKey() and updateEnableToggleTopRowHotKey(). Tests updated for defaults, copyWith, and JSON persistence.
Core Toggle Logic
lib/app.dart
Introduces _toggleTopRow() that flips keyboardProvider.showTopRow, calls keyboardProvider.notifier.updateShowTopRow(...), adjusts window size, shows transient overlay, iterates WindowController.getAll() to invoke updateShowTopRowFromMainWindow on preference windows, and calls _saveAllPreferences(). Wires hotkey callback into hotkey setup.
Hotkey Service & IPC
lib/services/hotkey_service.dart, lib/services/method_call_handler.dart
Extends HotKeyService.setupHotKeys() signature to accept toggleTopRowHotKey, enableToggleTopRowHotKey, and onToggleTopRowTriggered. Conditionally registers toggle hotkey. Adds method-call cases updateToggleTopRowHotKey and updateEnableToggleTopRowHotKey to update state, unregister/register hotkey, and re-run setupHotKeys().
Preferences UI
lib/screens/preferences_screen.dart, lib/widgets/tabs/hotkeys_tab.dart
Adds updateShowTopRowFromMainWindow handler in preferences screen to update keyboardProvider and persist keyboard state. Adds “Toggle Top Row” entry in hotkeys tab with enable toggle, display, and recording handlers. Changes default “Open Preferences” fallback from keyR to keyT.

Sequence Diagram

sequenceDiagram
    actor User
    participant HotKeyService
    participant AppWidget
    participant AppStateNotifier
    participant WindowController
    participant PreferencesScreen

    User->>HotKeyService: Press Toggle Top Row hotkey
    HotKeyService->>AppWidget: onToggleTopRowTriggered()
    AppWidget->>AppStateNotifier: notifier.updateShowTopRow(newState)
    AppStateNotifier-->>AppWidget: state published
    AppWidget->>AppWidget: _adjustWindowSize()
    AppWidget->>AppWidget: show transient overlay
    AppWidget->>WindowController: call updateShowTopRowFromMainWindow(bool)
    WindowController->>PreferencesScreen: deliver method call
    PreferencesScreen->>PreferencesScreen: updateShowTopRow + saveKeyboardState()
    AppWidget->>AppStateNotifier: _saveAllPreferences()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped a key, I nudged a row, Alt+Ctrl made it so,
A tiny flip, a window nudge, preferences saved in tow.
I drum a carrot tambourine—top row visible or lean,
A ribbon of keys, a rabbit cheer, hotkeys snug and keen! 🎹

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main feature added: a hotkey to toggle top row visibility.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/toggle-top-row

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new global hotkey to toggle the keyboard UI’s top (number) row, wiring it through persisted AppState, hotkey registration/handling, preferences UI, and cross-window synchronization between the main and preferences windows.

Changes:

  • Introduces toggleTopRowHotKey + enableToggleTopRowHotKey in AppState (defaults, copyWith, JSON serialize/deserialize) and notifier update methods.
  • Registers/handles the new hotkey via HotKeyService and platform method calls, and adds a Hotkeys preferences option to configure/enable it.
  • Implements main-window behavior to toggle the top row and notifies the preferences window; adds/updates tests for persistence/serialization flags.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
lib/providers/app_state_provider.dart Adds new hotkey + enabled flag to AppState, defaults, JSON, and notifier methods.
lib/services/hotkey_service.dart Registers the new hotkey and invokes a new callback on trigger.
lib/services/method_call_handler.dart Handles platform updates for the new hotkey and enabled flag and re-registers hotkeys.
lib/widgets/tabs/hotkeys_tab.dart Adds a preferences UI option for “Toggle Top Row”; updates default Preferences hotkey.
lib/app.dart Implements _toggleTopRow, wires callback into hotkey setup, and syncs state to preferences window.
lib/screens/preferences_screen.dart Receives updateShowTopRowFromMainWindow to keep preferences UI state in sync.
test/providers/app_state_provider_test.dart Adds assertions for the new enable flag and default hotkey presence.
test/services/state_service_test.dart Verifies persistence round-trip includes the new enable flag.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
lib/providers/app_state_provider.dart (2)

77-84: Minor formatting inconsistency.

The key: parameter lacks the leading space that other hotkey initializations have (compare line 79 with lines 67, 71, 75). Similarly for line 83.

🔧 Suggested formatting fix
         toggleTopRowHotKey = toggleTopRowHotKey ??
             HotKey(
-            key: PhysicalKeyboardKey.keyR,
+                key: PhysicalKeyboardKey.keyR,
                 modifiers: [HotKeyModifier.alt, HotKeyModifier.control]),
         preferencesHotKey = preferencesHotKey ??
             HotKey(
-            key: PhysicalKeyboardKey.keyT,
+                key: PhysicalKeyboardKey.keyT,
                 modifiers: [HotKeyModifier.alt, HotKeyModifier.control]),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/providers/app_state_provider.dart` around lines 77 - 84, The HotKey
initializers for toggleTopRowHotKey and preferencesHotKey have inconsistent
spacing before the named `key:` parameter; update the two HotKey constructions
(toggleTopRowHotKey and preferencesHotKey that use PhysicalKeyboardKey.keyR and
PhysicalKeyboardKey.keyT) to match the same formatting as the other HotKey
instances by adding the leading space before `key:` so all HotKey(...) calls are
consistently formatted.

193-202: Same formatting inconsistency as in constructor.

Lines 196-197 and 201 have inconsistent indentation for the key: parameter.

🔧 Suggested formatting fix
       toggleTopRowHotKey: json['toggleTopRowHotKey'] != null
           ? HotKey.fromJson(json['toggleTopRowHotKey'])
           : HotKey(
-            key: PhysicalKeyboardKey.keyR,
+              key: PhysicalKeyboardKey.keyR,
               modifiers: [HotKeyModifier.alt, HotKeyModifier.control]),
       preferencesHotKey: json['preferencesHotKey'] != null
           ? HotKey.fromJson(json['preferencesHotKey'])
           : HotKey(
-            key: PhysicalKeyboardKey.keyT,
+              key: PhysicalKeyboardKey.keyT,
               modifiers: [HotKeyModifier.alt, HotKeyModifier.control]),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/providers/app_state_provider.dart` around lines 193 - 202, The
toggleTopRowHotKey and preferencesHotKey default HotKey constructors have
inconsistent indentation for the key: parameter (lines showing
PhysicalKeyboardKey.keyR and PhysicalKeyboardKey.keyT); update the formatting so
the key: lines align with the modifiers: line and match the constructor
indentation style used elsewhere in HotKey(...) for both toggleTopRowHotKey and
preferencesHotKey to keep consistent code style (refer to symbols HotKey,
toggleTopRowHotKey, preferencesHotKey, PhysicalKeyboardKey.keyR,
PhysicalKeyboardKey.keyT).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/providers/app_state_provider.dart`:
- Around line 77-84: The HotKey initializers for toggleTopRowHotKey and
preferencesHotKey have inconsistent spacing before the named `key:` parameter;
update the two HotKey constructions (toggleTopRowHotKey and preferencesHotKey
that use PhysicalKeyboardKey.keyR and PhysicalKeyboardKey.keyT) to match the
same formatting as the other HotKey instances by adding the leading space before
`key:` so all HotKey(...) calls are consistently formatted.
- Around line 193-202: The toggleTopRowHotKey and preferencesHotKey default
HotKey constructors have inconsistent indentation for the key: parameter (lines
showing PhysicalKeyboardKey.keyR and PhysicalKeyboardKey.keyT); update the
formatting so the key: lines align with the modifiers: line and match the
constructor indentation style used elsewhere in HotKey(...) for both
toggleTopRowHotKey and preferencesHotKey to keep consistent code style (refer to
symbols HotKey, toggleTopRowHotKey, preferencesHotKey, PhysicalKeyboardKey.keyR,
PhysicalKeyboardKey.keyT).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: be3e1524-ad7a-4e52-83a6-cc0e6165abde

📥 Commits

Reviewing files that changed from the base of the PR and between 6dda406 and 4e3df4a.

📒 Files selected for processing (8)
  • lib/app.dart
  • lib/providers/app_state_provider.dart
  • lib/screens/preferences_screen.dart
  • lib/services/hotkey_service.dart
  • lib/services/method_call_handler.dart
  • lib/widgets/tabs/hotkeys_tab.dart
  • test/providers/app_state_provider_test.dart
  • test/services/state_service_test.dart

@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 73.33333% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
lib/providers/app_state_provider.dart 73.33% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/app.dart`:
- Around line 241-243: Toggling the top row currently calls
keyboardNotifier.updateShowTopRow(...) then _adjustWindowSize(), but
_adjustWindowSize() (via its call to _fadeIn()) forces the keyboard to become
visible; change the flow so a top-row toggle does not force a fade-in: add a
parameter to _adjustWindowSize (e.g., forceFade or preserveVisibility)
defaulting to the current behavior, update the toggle call site (where
keyboardNotifier.updateShowTopRow is used) to call _adjustWindowSize(false) (or
preserveVisibility=true), and update _adjustWindowSize to skip calling _fadeIn()
when that flag indicates preservation; ensure any calls to _adjustWindowSize
that must still show the keyboard keep the default/true behavior and update
usages accordingly (referenced symbols: keyboardNotifier.updateShowTopRow,
_adjustWindowSize, _fadeIn, _autoHideManager.showOverlay).
- Around line 251-261: The current top-row toggle flow calls
WindowController.getAll(), controller.invokeMethod(...), and
_saveAllPreferences() as fire-and-forget; make the side effects explicit by
awaiting the async operations and adding per-call error handling: await
WindowController.getAll(), iterate controllers and await each
controller.invokeMethod('updateShowTopRowFromMainWindow', newShowTopRow) inside
a try/catch to log or handle failures, and then await _saveAllPreferences()
(also wrapped in try/catch) so persistence happens deterministically after
window updates and errors aren’t dropped silently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ef83ac56-a8c8-436f-8a96-be20678a18df

📥 Commits

Reviewing files that changed from the base of the PR and between 4e3df4a and e80a570.

📒 Files selected for processing (4)
  • lib/app.dart
  • lib/providers/app_state_provider.dart
  • test/providers/app_state_provider_test.dart
  • test/services/state_service_test.dart
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/services/state_service_test.dart
  • lib/providers/app_state_provider.dart

@conventoangelo conventoangelo merged commit da2f6b9 into main Mar 28, 2026
5 checks passed
@conventoangelo conventoangelo deleted the feat/toggle-top-row branch March 28, 2026 17:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants