Skip to content

Add remote controls input modal#130

Merged
wizzomafizzo merged 4 commits into
mainfrom
feature/remote-controls-inputs
May 24, 2026
Merged

Add remote controls input modal#130
wizzomafizzo merged 4 commits into
mainfrom
feature/remote-controls-inputs

Conversation

@wizzomafizzo
Copy link
Copy Markdown
Member

@wizzomafizzo wizzomafizzo commented May 24, 2026

Summary

  • Add a gated Controls entry point on the Zap page for remote input
  • Add remote D-pad controls, keyboard input, and inline screenshot capture/download/clear
  • Add Core API methods/types for input.keyboard, input.gamepad, and screenshot
  • Add feature gating, translations, and unit coverage

Verification

  • npm run test -- src/tests/unit/components/home/ScanControls.test.tsx
  • npm run test -- src/tests/unit/components/RemoteKeyboardModal.test.tsx
  • npm run typecheck
  • npm run format:check
  • npm run lint

Summary by CodeRabbit

  • New Features

    • Remote keyboard and control pad UI with directional/actions and on-screen keyboard (multiple layouts), platform-specific mappings, keyboard macros, and screenshot capture/preview/download.
    • Feature gate for remote input availability.
  • Tests

    • Added unit and integration tests covering remote keyboard, input sending, screenshot flows, and disconnected behavior.
  • Documentation

    • Added UI text/translations for remote controls and errors.
  • Chores

    • Added on-screen keyboard dependency and supporting API methods.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR adds a remote keyboard/gamepad control modal with platform-specific actions and screenshot capture, implements CoreAPI methods for keyboard/gamepad input and screenshot retrieval with connection checks and runtime validation, exposes a remoteInput feature gate, integrates the modal into ScanControls/Index, and adds styles, translations, and tests.

Changes

Remote Keyboard Feature

Layer / File(s) Summary
Core API types and input methods
src/lib/models.ts, src/lib/coreApi.ts, src/__tests__/unit/lib/coreApi.test.ts
New InputKeyboardRequest, InputGamepadRequest, and ScreenshotResponse types. CoreAPI gains inputKeyboard(), inputGamepad(), and screenshot() methods that enforce active connection via callConnected helper and validate screenshot responses. Unit tests verify JSON-RPC payloads, response validation, and connection enforcement.
Feature gates, package dependency, and translations
package.json, src/lib/featureGates.ts, src/translations/en-US.json
Adds react-simple-keyboard dependency. New remoteInput feature gate registered for Core 2.10.0+. Adds translations for remote controls, keyboard modes, screenshot actions, and disconnected messaging.
RemoteKeyboardModal component, styling, and test suite
src/components/RemoteKeyboardModal.tsx, src/index.css, src/__tests__/unit/components/RemoteKeyboardModal.test.tsx
New RemoteKeyboardModal that provides remote D-pad and an on-screen keyboard with multiple layouts, macro escaping, serialized sends to CoreAPI, screenshot capture/display/download/clear, and error/disconnection handling. CSS supplies grid-based pad layout and screenshot UI. Tests cover UI structure, remote and keyboard interactions, platform-specific mappings, screenshot workflows (success, loading, failure), and disconnected behavior.
ScanControls and Index page integration
src/components/home/ScanControls.tsx, src/routes/-pages/Index.tsx, src/__tests__/unit/components/home/ScanControls.test.tsx, src/__tests__/integration/index-route.test.tsx
ScanControls now accepts connected and onRemoteKeyboard props, renders a gated remote-keyboard button disabled when disconnected or feature-unavailable. Index wires RemoteKeyboardModal open state and handler. Unit and integration tests validate button rendering, disabled state, and modal opening.
Segmented control labelHidden prop
src/components/wui/Segmented.tsx
Adds optional labelHidden?: boolean prop to conditionally apply sr-only to the control label while keeping accessibility.

Sequence Diagram

sequenceDiagram
  participant User
  participant Modal as RemoteKeyboardModal
  participant API as CoreAPI
  participant Store as Zustand Store
  
  User->>Modal: click remote/keyboard mode
  Modal->>Modal: toggle mode
  
  alt Remote mode
    User->>Modal: click directional/action button
    Modal->>Store: read connected status
    alt connected
      Modal->>API: inputKeyboard({key macro})
      API-->>Modal: success
    else disconnected
      Modal->>Modal: show error toast
    end
  else Keyboard mode
    User->>Modal: press key/macro/layout-switch
    Modal->>Modal: compute key macro
    alt layout-switch key
      Modal->>Modal: change keyboard layout
    else regular key
      Modal->>API: inputKeyboard({key})
    end
  end
  
  User->>Modal: click screenshot
  Modal->>API: screenshot()
  API-->>Modal: {path, data, size}
  Modal->>Modal: display image + download link
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • ZaparooProject/zaparoo-app#96: Provides core feature-gating infrastructure (useCoreFeature, GatedFeature) used by this PR's remoteInput gate and ScanControls integration.

Poem

I’m a rabbit with a tiny key,
Hopping arrows, Enter, and Fn for thee,
I snap a pic, then hand you a link,
Press remote, press keys — no need to think,
🐰✨ Tap-tap-go, control set free.

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Add remote controls input modal' directly describes the main change: implementing a new remote keyboard input modal component with associated remote controls functionality.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/remote-controls-inputs

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

@codecov
Copy link
Copy Markdown

codecov Bot commented May 24, 2026

Codecov Report

❌ Patch coverage is 86.07595% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/components/RemoteKeyboardModal.tsx 87.00% 13 Missing ⚠️
src/lib/coreApi.ts 80.48% 8 Missing ⚠️
src/routes/-pages/Index.tsx 66.66% 1 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: 3

🧹 Nitpick comments (1)
src/components/wui/Segmented.tsx (1)

58-58: ⚡ Quick win

Use classnames for the conditional label class.

Please switch this ternary class assignment to classNames(...) for guideline consistency.

Suggested patch
-      <label className={labelHidden ? "sr-only" : "mb-1 block"}>{label}</label>
+      <label
+        className={classNames({
+          "sr-only": labelHidden,
+          "mb-1 block": !labelHidden,
+        })}
+      >
+        {label}
+      </label>

As per coding guidelines, "Use classnames for conditional Tailwind classes in components".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/wui/Segmented.tsx` at line 58, Replace the ternary class
assignment on the label element in the Segmented component with the classnames
helper: import classNames from "classnames" at the top of
src/components/wui/Segmented.tsx and change the label's className to use
classNames({ "sr-only": labelHidden }, "mb-1 block") (or equivalent ordering) so
the conditional "sr-only" is applied when labelHidden is true and "mb-1 block"
remains otherwise; update any existing imports to avoid duplicates.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/unit/components/home/ScanControls.test.tsx`:
- Around line 74-95: The test relies on store-driven feature availability
(useStatusStore) and can inherit state from other tests; reset the status store
state before this test by calling useStatusStore.setState({...}) in a beforeEach
(or at the start of this test's Arrange) to set the required default flags so
the remote keyboard feature is deterministic; update the test file to call
useStatusStore.setState with the appropriate baseline state prior to rendering
<ScanControls ... onRemoteKeyboard={onRemoteKeyboard}>.

In `@src/__tests__/unit/components/RemoteKeyboardModal.test.tsx`:
- Around line 51-54: The test setup's beforeEach currently calls
vi.clearAllMocks() and sets useStatusStore state but doesn't reset CoreAPI;
modify the beforeEach block in RemoteKeyboardModal.test.tsx to call
CoreAPI.reset() (ensure CoreAPI is exported from the module mock and included in
the test mock setup) so tests are isolated—keep the existing vi.clearAllMocks()
and useStatusStore.setState({ connected: true, corePlatform: null }) and add
CoreAPI.reset() alongside them.

In `@src/components/RemoteKeyboardModal.tsx`:
- Around line 233-237: The catch handlers in RemoteKeyboardModal (the .catch(()
=> { ... }) blocks around the remote keyboard send logic) currently only set UI
state and toast errors; update both catch blocks (the one at 233-237 and the one
at 267-271) to accept the error parameter (e.g., err), call
logger.error(message, err, { category: "remoteKeyboard", action: "send",
severity: "error" }) before calling setError(message) and toast.error(message),
and keep existing UI behaviors intact; ensure the logger import/instance used
matches the component (logger) and that the message variable is reused for the
log call.

---

Nitpick comments:
In `@src/components/wui/Segmented.tsx`:
- Line 58: Replace the ternary class assignment on the label element in the
Segmented component with the classnames helper: import classNames from
"classnames" at the top of src/components/wui/Segmented.tsx and change the
label's className to use classNames({ "sr-only": labelHidden }, "mb-1 block")
(or equivalent ordering) so the conditional "sr-only" is applied when
labelHidden is true and "mb-1 block" remains otherwise; update any existing
imports to avoid duplicates.
🪄 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: 03720cf6-04ba-4634-9592-c0b968f45bcd

📥 Commits

Reviewing files that changed from the base of the PR and between 9a2b547 and 5e2f4ef.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (13)
  • package.json
  • src/__tests__/unit/components/RemoteKeyboardModal.test.tsx
  • src/__tests__/unit/components/home/ScanControls.test.tsx
  • src/__tests__/unit/lib/coreApi.test.ts
  • src/components/RemoteKeyboardModal.tsx
  • src/components/home/ScanControls.tsx
  • src/components/wui/Segmented.tsx
  • src/index.css
  • src/lib/coreApi.ts
  • src/lib/featureGates.ts
  • src/lib/models.ts
  • src/routes/-pages/Index.tsx
  • src/translations/en-US.json

Comment thread src/__tests__/unit/components/home/ScanControls.test.tsx
Comment thread src/__tests__/unit/components/RemoteKeyboardModal.test.tsx
Comment thread src/components/RemoteKeyboardModal.tsx Outdated
@wizzomafizzo wizzomafizzo merged commit 4a65336 into main May 24, 2026
5 of 6 checks passed
@wizzomafizzo wizzomafizzo deleted the feature/remote-controls-inputs branch May 24, 2026 07:22
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