Skip to content

refactor: add hotkeys prop to WSAudioPlayer and MediaRecord - #796

Merged
sarahentzel merged 4 commits into
developfrom
wsaudioplayer-hotkeys-prop
Oct 30, 2026
Merged

sarahentzel merged 4 commits into
developfrom
wsaudioplayer-hotkeys-prop

Conversation

@nabalone

@nabalone nabalone commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

This does NOT address TT-7748 in which we will split up the hotkeys. This is an intermediate step that I need to get the Internalize General Resource flow working, should cause no regressions. I don't want the General Resource flow to have to wait on TT-7748

Split out of the add-resource wizard refactor (#741). WSAudioPlayer gains a
`hotkeys` prop (default true) that enables/disables all of a player's
keyboard shortcuts together, so an off-screen player can yield them to the
visible one. MediaRecord forwards it. Default true keeps every existing
screen unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active issues remain after a full review that verified the hotkey-gating changes against the surrounding code.

No open issues 🎉

What changed in this PR

This PR adds an opt-out hotkeys prop (default true) to WSAudioPlayer, allowing a player to subscribe none of its keyboard shortcuts so that a second, off-screen player can yield all keys to the visible one. It's a low-risk refactor split out of the larger add-resource wizard PR (#741) to ease review. Because the default is true, all existing screens behave exactly as before; the only false caller arrives with #741.

Changes:

  • Added a hotkeys prop to WSAudioPlayer and gated every hotkey subscription effect (transport, record, region nav, copy/cut/paste) on it, including adding hotkeys to each effect's dependency array.
  • Forwarded the hotkeys prop from MediaRecord to its WSAudioPlayer.
  • Added two tests covering no subscriptions when hotkeys={false} and unsubscription when the prop transitions to false.
File Description
web/​src/​components/​WSAudioPlayer.tsx Adds the hotkeys prop (default true) and short-circuits all four hotkey subscription effects when it is false, with hotkeys added to their dependency arrays.
web/​src/​components/​MediaRecord.tsx Adds a hotkeys prop (default true) and forwards it to the embedded WSAudioPlayer.
web/​src/​components/​WSAudioPlayer.hotkeys.test.tsx Adds two tests verifying no subscriptions when hotkeys={false} and unsubscription when the prop turns false.

Verification notes: I confirmed via a content search that all subscribe(...) calls in WSAudioPlayer.tsx reside inside effects now guarded by hotkeys, that each affected effect's dependency array includes hotkeys, and that MediaRecord contains a single WSAudioPlayer instance which receives the forwarded prop. The new tests use defaultProps with allowRecord: true, so the assertions are meaningful.

Review effort: Balanced

Address Devin review on #796:
- Forward `hotkeys` to WSAudioPlayerRate/Zoom/Segment so a passive player
  doesn't claim the speed, zoom, or segment shortcuts.
- Remove the mount-only unsubscribe list from the device-listener cleanup.
  It predates TT-7283, which gave each hotkey effect its own cleanup, so it
  was redundant for active players — and for a passive player it removed
  keys owned by the active one (HotKeyContext tracks keys, not owners).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@nabalone

Copy link
Copy Markdown
Collaborator Author

Why the unmount unsubscribe list in the device-listener effect was deleted (17fc1b6)

That cleanup unsubscribed PLAY_PAUSE, ALT_PLAY_PAUSE, HOME, END, BACK, AHEAD, TIMER, RECORD, LEFT and RIGHT when the player unmounted. It is left over from before TT-7283 (20959ef9), when a single effect owned all the subscriptions. TT-7283 moved each group into its own effect with its own cleanup:

React runs those cleanups on unmount, so for an active player the deleted list unsubscribed keys that were already being unsubscribed. Nothing changes there.

For a passive player (hotkeys={false}), the list was harmful. Those effects return early and subscribe nothing, but the leftover list still unsubscribed every key. HotKeyContext.unsubscribe removes a key regardless of who registered it, so unmounting a passive player stripped the active player's shortcuts (Devin finding 2). Deleting the list fixes that with no ref or guard. It is covered by the new test "does not unsubscribe active keys when a passive player unmounts", which fails on the old code.

Possible follow-up (out of scope here): make HotKeyContext track ownership, e.g. unsubscribe(key, cb) only removes the key if cb is still the registered callback, so components sharing a key can't clobber each other.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

Every hotkey subscription is correctly gated on the new default-true prop with matching dependency arrays, the forced-unsubscribe removal is justified by per-effect cleanup, and Jest tests cover the new behavior, leaving no open issues.

No open issues 🎉

Review effort: Balanced

@nabalone
nabalone marked this pull request as ready for review October 30, 2026 13:08
nabalone and others added 2 commits October 30, 2026 09:16
PassageDetailGuidedPhraseRecord (Careful Speech and Phrase Back Translate)
mounts the source player above the CarefulSpeechControls recorder. Both
subscribed the shared transport keys, and the recorder (mounted second)
won. Pass hotkeys={!allowSourcePlayer} through CarefulSpeechControls so
the top source player keeps them.

hotkeys is all-or-nothing, so the recorder also drops F9 and Ctrl+C/X/V
while the source player is shown; TT-7748 tracks making the prop specify
which hotkeys a player claims.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Undo 28fc500 (the recorder in Careful Speech / PBT giving up all its
hotkeys to the source player) — not wanted as an all-off change. Instead
note on WSAudioPlayer's hotkeys prop that TT-7748 will let a player
specify which hotkeys it claims.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sarahentzel
sarahentzel merged commit d078495 into develop Oct 30, 2026
2 checks passed
@sarahentzel
sarahentzel deleted the wsaudioplayer-hotkeys-prop branch October 30, 2026 14:17
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