Skip to content

Implement keyboard navigation shortcuts and refactor app navigation#324

Merged
rainxchzed merged 3 commits into
mainfrom
desktop-key-feat
Mar 13, 2026
Merged

Implement keyboard navigation shortcuts and refactor app navigation#324
rainxchzed merged 3 commits into
mainfrom
desktop-key-feat

Conversation

@rainxchzed
Copy link
Copy Markdown
Member

@rainxchzed rainxchzed commented Mar 13, 2026

  • Introduce KeyboardNavigation and KeyboardNavigationEvent to handle desktop-specific keyboard shortcuts.
  • Add support for Ctrl+F (or Meta+F) to navigate to the Search screen from anywhere in the application.
  • Rename navBackStack to navController in Main.kt and integrate ObserveAsEvents to handle keyboard navigation events.
  • Update DesktopApp.kt to capture key events and dispatch them through KeyboardNavigation.
  • Localize the application title in the desktop window using Res.string.app_name.
  • Refactor RateLimitDialog logic for better null safety and cleaner state handling.
  • Reorder initKoin() and deep link handling in the desktop entry point to ensure proper initialization.
  • Perform minor code formatting and organization in AppNavigation.kt.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added keyboard shortcuts (Ctrl+F on Windows/Linux, Cmd+F on Mac) to quickly access the search screen from anywhere in the app while preserving current state
    • Improved navigation flows for authentication and rate-limiting dialogs
    • Enhanced deep-link handling with better support for edge cases
  • Improvements

    • Refined state management in the navigation system for a more stable user experience

- Introduce `KeyboardNavigation` and `KeyboardNavigationEvent` to handle desktop-specific keyboard shortcuts.
- Add support for `Ctrl+F` (or `Meta+F`) to navigate to the Search screen from anywhere in the application.
- Rename `navBackStack` to `navController` in `Main.kt` and integrate `ObserveAsEvents` to handle keyboard navigation events.
- Update `DesktopApp.kt` to capture key events and dispatch them through `KeyboardNavigation`.
- Localize the application title in the desktop window using `Res.string.app_name`.
- Refactor `RateLimitDialog` logic for better null safety and cleaner state handling.
- Reorder `initKoin()` and deep link handling in the desktop entry point to ensure proper initialization.
- Perform minor code formatting and organization in `AppNavigation.kt`.
- Relocate the app icon from `composeApp` to the `core:presentation` module.
- Rename the resource file from `app-icon.png` to `app_icon.png`.
- Update the app icon image asset.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 13, 2026

Walkthrough

The pull request introduces a keyboard navigation system for the desktop app, enabling users to press Ctrl+F to navigate to the search screen. It refactors the navigation controller usage, integrates event-driven architecture for keyboard events, and improves resource localization in the desktop entry point.

Changes

Cohort / File(s) Summary
Keyboard Navigation System
composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/desktop/KeyboardNavigation.kt, composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/desktop/KeyboardNavigationEvent.kt, composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/DesktopApp.kt
Introduces KeyboardNavigationEvent sealed interface with OnCtrlFClick data object; implements KeyboardNavigation singleton using Channel-based Flow for event emission; adds Ctrl/Meta+F keyboard shortcut handling in DesktopApp to trigger navigation events.
Main Navigation Refactoring
composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt
Replaces navBackStack with navController; computes currentScreen from back stack entry; integrates ObserveAsEvents to listen for KeyboardNavigation and navigate to SearchScreen on Ctrl+F; refines rate-limit dialog logic requiring non-null rateLimitInfo; updates deep-link handling with DeepLinkDestination.None case.
Desktop App Infrastructure
composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/DesktopApp.kt
Updates resource access using stringResource for app name and painterResource for icon; moves initKoin() initialization earlier to ensure DI setup before deep-link and window creation logic.
Navigation Formatting
composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/AppNavigation.kt
Reformats multi-line parameter lists and chained calls for consistency; no logic changes.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DesktopApp
    participant KeyboardNavigation
    participant Main
    participant NavController
    participant SearchScreen

    User->>DesktopApp: Press Ctrl+F
    DesktopApp->>KeyboardNavigation: onKeyClicked(OnCtrlFClick)
    KeyboardNavigation->>KeyboardNavigation: emit event to Flow
    Main->>KeyboardNavigation: collect from events
    Main->>Main: ObserveAsEvents listens
    alt Not already on SearchScreen
        Main->>NavController: navigate to SearchScreen
        NavController->>SearchScreen: show screen
        SearchScreen-->>NavController: ready
    else Already on SearchScreen
        Main->>Main: skip navigation
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #242: Updates build mainClass configuration for DesktopApp entry point changes that reorganize desktop initialization logic.
  • PR #256: Modifies deep-link handling in Main.kt, specifically the DeepLinkDestination.None case that interacts with the navigation refactoring in this PR.

Poem

🐰 A whisper of Ctrl+F, the rabbit did send,
Through channels and flows, where events ascend,
From desktop to search, the journey so bright,
Navigation takes flight with a keystroke's might! 🔍✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main changes: implementing keyboard navigation shortcuts and refactoring app navigation, which aligns with the primary objectives of adding KeyboardNavigation support, Ctrl+F shortcuts, and renaming navBackStack to navController.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch desktop-key-feat
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link
Copy Markdown
Contributor

@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 (1)
composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/desktop/KeyboardNavigation.kt (1)

7-12: Best practice: Add explicit buffering or check trySend result to prevent potential event loss.

Channel<KeyboardNavigationEvent>() is unbuffered and trySend failure is not checked. While the current usage pattern (subscription established before user interaction) mitigates real-world risk, this code pattern is fragile and could silently drop events if the composition lifecycle changes.

Suggested improvement
 object KeyboardNavigation {
-    private val _events = Channel<KeyboardNavigationEvent>()
+    private val _events = Channel<KeyboardNavigationEvent>(capacity = Channel.BUFFERED)
     val events = _events.receiveAsFlow()
 
     fun onKeyClicked(event: KeyboardNavigationEvent) {
-        _events.trySend(event)
+        _events.trySend(event).onFailure {
+            // Log dropped event if needed
+        }
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/desktop/KeyboardNavigation.kt`
around lines 7 - 12, The _events Channel is unbuffered and onKeyClicked uses
trySend without checking the result, risking silent event loss; fix by creating
_events with an explicit buffer (e.g., Channel.BUFFERED or Channel(capacity =
N)) instead of Channel<KeyboardNavigationEvent>(), and/or check the
ChannelResult returned by _events.trySend(event) inside onKeyClicked (use
isSuccess/isFailure or onFailure to log or handle the dropped event) so events
are not silently dropped; update references to _events, events =
_events.receiveAsFlow(), and the onKeyClicked(event: KeyboardNavigationEvent)
function accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/desktop/KeyboardNavigation.kt`:
- Around line 7-12: The _events Channel is unbuffered and onKeyClicked uses
trySend without checking the result, risking silent event loss; fix by creating
_events with an explicit buffer (e.g., Channel.BUFFERED or Channel(capacity =
N)) instead of Channel<KeyboardNavigationEvent>(), and/or check the
ChannelResult returned by _events.trySend(event) inside onKeyClicked (use
isSuccess/isFailure or onFailure to log or handle the dropped event) so events
are not silently dropped; update references to _events, events =
_events.receiveAsFlow(), and the onKeyClicked(event: KeyboardNavigationEvent)
function accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: acf5a88d-3ac8-4639-b3b4-16af56356646

📥 Commits

Reviewing files that changed from the base of the PR and between f2b45cb and 5fec24a.

⛔ Files ignored due to path filters (2)
  • composeApp/src/commonMain/composeResources/drawable/app-icon.png is excluded by !**/*.png
  • core/presentation/src/commonMain/composeResources/drawable/app_icon.png is excluded by !**/*.png
📒 Files selected for processing (5)
  • composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt
  • composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/desktop/KeyboardNavigation.kt
  • composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/desktop/KeyboardNavigationEvent.kt
  • composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/AppNavigation.kt
  • composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/DesktopApp.kt

@rainxchzed rainxchzed merged commit ba8e27f into main Mar 13, 2026
1 check passed
@rainxchzed rainxchzed deleted the desktop-key-feat branch March 13, 2026 05:01
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.

1 participant