mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
docs(playback): design shared controls setting
This commit is contained in:
1 parent
48e3736460
commit
2e13df4773
1 file changed
+210
@@ -0,0 +1,210 @@
|
||||
# Web-Player Shared Controls Setting Design
|
||||
|
||||
## Context
|
||||
|
||||
The shared `app-player-controls` presentation is already integrated with four
|
||||
playback paths:
|
||||
|
||||
- Embedded MPV frame-copy uses it unconditionally because its video is rendered
|
||||
into a DOM canvas.
|
||||
- HTML5, Video.js, and ArtPlayer can use it behind the default-off
|
||||
`WEB_PLAYER_SHARED_CONTROLS` rollout token.
|
||||
|
||||
The web-player token currently resolves from the compile-time
|
||||
`WEB_PLAYER_SHARED_CONTROLS_ENABLED = false` constant. Enabling the integrations
|
||||
therefore requires a code change, rebuild, and application restart. The
|
||||
integrations are ready for opt-in testing, so the rollout choice should be a
|
||||
persisted user setting instead.
|
||||
|
||||
The Settings route does not keep an active player mounted. The setting can
|
||||
therefore be applied when the next playback session is created; changing an
|
||||
already-running engine or preserving an active playback position is not
|
||||
required.
|
||||
|
||||
## Goals
|
||||
|
||||
- Add an experimental Playback checkbox for opting HTML5, Video.js, and
|
||||
ArtPlayer into the shared controls.
|
||||
- Persist the choice in the canonical `SettingsStore`.
|
||||
- Apply the saved choice to the next web-player session without restarting or
|
||||
reloading the application.
|
||||
- Keep the controls mode immutable for the lifetime of a player session.
|
||||
- Preserve default-off behavior and compatibility with existing stored
|
||||
settings.
|
||||
- Keep Embedded MPV and external-player behavior unchanged.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Make shared web controls the default.
|
||||
- Change an active player between legacy and shared controls.
|
||||
- Add separate preferences for HTML5, Video.js, and ArtPlayer.
|
||||
- Make Embedded MPV native-view use a DOM overlay.
|
||||
- Allow frame-copy Embedded MPV to fall back to the legacy controls dock.
|
||||
- Control the native UI of external MPV or VLC processes.
|
||||
|
||||
## Embedded MPV Semantics
|
||||
|
||||
The new checkbox is intentionally web-player-specific.
|
||||
|
||||
Embedded MPV has two rendering paths:
|
||||
|
||||
- **Frame-copy:** video is uploaded to a renderer canvas. It always uses
|
||||
`app-player-controls`; a second controls toggle would only duplicate an
|
||||
already-required part of this engine.
|
||||
- **Native-view:** video is hosted in a platform-native surface. DOM controls
|
||||
cannot reliably stack above that surface, so the compositor-safe legacy dock
|
||||
remains required.
|
||||
|
||||
The existing `embeddedMpvFrameCopy` setting continues to select the rendering
|
||||
engine and continues to require an application restart. It is independent from
|
||||
the new web-player controls preference.
|
||||
|
||||
External MPV and VLC processes continue to own their own controls UI.
|
||||
|
||||
## Considered Approaches
|
||||
|
||||
### 1. Conditional global web-player preference
|
||||
|
||||
Selected.
|
||||
|
||||
One setting controls HTML5, Video.js, and ArtPlayer together. Its checkbox is
|
||||
shown only while one of those players is selected. This matches the existing
|
||||
single rollout token, keeps the Settings UI relevant to the selected player,
|
||||
and avoids suggesting that the option changes Embedded MPV or external
|
||||
players.
|
||||
|
||||
### 2. Always-visible "shared controls where available" preference
|
||||
|
||||
Rejected because it would be a no-op for frame-copy Embedded MPV, unsupported
|
||||
for native-view, and outside the app for external players. The resulting
|
||||
conditional semantics would be harder to explain than a web-player-specific
|
||||
label.
|
||||
|
||||
### 3. Separate preference for every playback engine
|
||||
|
||||
Rejected because the three web integrations deliberately share one rollout
|
||||
contract. Per-engine preferences would add settings and test combinations
|
||||
without a current product requirement.
|
||||
|
||||
## Settings Contract
|
||||
|
||||
Add an optional boolean to the shared settings interface:
|
||||
|
||||
```ts
|
||||
webPlayerSharedControls?: boolean;
|
||||
```
|
||||
|
||||
The canonical default is `false`. Loading an older settings object without the
|
||||
field must normalize to `false`, and saving settings must write the complete
|
||||
resolved value back to storage.
|
||||
|
||||
The settings form adds a `webPlayerSharedControls` control with a `false`
|
||||
default. Form hydration, serialization, reset behavior, backup/export, and the
|
||||
existing Save workflow continue to use the normal complete `Settings` object.
|
||||
This is renderer-only state; Electron main-process behavior and preload IPC do
|
||||
not need a new command.
|
||||
|
||||
## Runtime Data Flow
|
||||
|
||||
The existing `WEB_PLAYER_SHARED_CONTROLS` injection token remains the
|
||||
immutable, test-overridable session seam used by the three engine components.
|
||||
The compile-time constant remains only as the default-off fallback for direct
|
||||
component use and focused tests.
|
||||
|
||||
Normal runtime resolution moves to `WebPlayerViewComponent`:
|
||||
|
||||
1. `SettingsStore` loads `webPlayerSharedControls`, defaulting to `false`.
|
||||
2. The Settings page updates and persists it through the existing Save action.
|
||||
3. Leaving Settings destroys that route; no player is active during the
|
||||
change.
|
||||
4. The next `WebPlayerViewComponent` resolves a component-scoped boolean
|
||||
snapshot from `SettingsStore`.
|
||||
5. HTML5, Video.js, or ArtPlayer receives that snapshot through
|
||||
`WEB_PLAYER_SHARED_CONTROLS` and constructs exactly one controls system.
|
||||
6. The snapshot does not change until that player host is destroyed and a new
|
||||
playback session is created.
|
||||
|
||||
This preserves the construction-time requirements of Video.js and ArtPlayer:
|
||||
vendor controls, hotkeys, gestures, plugins, source bridges, and the shared
|
||||
adapter are configured atomically. A reactive boolean must not flip only the
|
||||
template while leaving the engine configured for the other mode.
|
||||
|
||||
Embedded MPV does not consume the setting. Its component continues to choose
|
||||
shared controls for `engine === 'frame-copy'` and the legacy dock for the
|
||||
native-view engine.
|
||||
|
||||
## Settings UI
|
||||
|
||||
Add one standard `setting-item` to the Playback section, using the existing
|
||||
Material checkbox and layout styles.
|
||||
|
||||
- Label meaning: **Use unified controls for web players (experimental)**.
|
||||
- Description meaning: use IPTVnator's common controls in HTML5, Video.js, and
|
||||
ArtPlayer.
|
||||
- Visibility: selected player is `videojs`, `html5`, or `artplayer`.
|
||||
- Hidden for Embedded MPV, external MPV, and VLC.
|
||||
- Add a stable test selector to the row and checkbox.
|
||||
- Add the label and description keys to every locale file so the i18n key sets
|
||||
remain aligned.
|
||||
|
||||
No new colors, spacing rules, or one-off UI components are required.
|
||||
|
||||
## Failure and Compatibility Behavior
|
||||
|
||||
- Missing or malformed non-boolean stored values resolve to `false`.
|
||||
- A storage write failure is reported through the existing
|
||||
`SettingsStore.updateSettings()` rejection and must not require
|
||||
player-specific recovery.
|
||||
- Legacy mode remains the safe fallback whenever the setting cannot be
|
||||
resolved.
|
||||
- Direct engine tests can continue overriding
|
||||
`WEB_PLAYER_SHARED_CONTROLS` with `true` or `false`.
|
||||
- The setting does not relax Electron sandboxing and does not alter the
|
||||
frame-copy engine opt-in.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Shared interfaces and settings store
|
||||
|
||||
- Default is `false`.
|
||||
- Older stored settings without the field load as `false`.
|
||||
- A stored `true` value is restored.
|
||||
- `updateSettings()` persists the complete resolved value.
|
||||
|
||||
### Settings form and UI
|
||||
|
||||
- Form creation and serialization include the new field.
|
||||
- The checkbox hydrates from stored settings and is included in the Save
|
||||
payload.
|
||||
- The row is visible for HTML5, Video.js, and ArtPlayer.
|
||||
- The row is hidden for Embedded MPV, external MPV, and VLC.
|
||||
- Translation key parity remains valid across all locales.
|
||||
|
||||
### Playback host
|
||||
|
||||
- A newly created HTML5, Video.js, or ArtPlayer session receives the saved
|
||||
boolean snapshot.
|
||||
- `false` preserves the existing vendor/native UI.
|
||||
- `true` mounts the shared controls path.
|
||||
- Embedded MPV selection ignores the web-player preference.
|
||||
- One session never renders or initializes both controls systems.
|
||||
|
||||
### Validation
|
||||
|
||||
- Run focused Settings form/component and `SettingsStore` tests.
|
||||
- Run the complete `ui-playback` test target because all three web engines
|
||||
share the rollout seam.
|
||||
- Run affected lint targets and the workspace typecheck.
|
||||
- Run the settings E2E flow for checkbox visibility, persistence, and use after
|
||||
returning to playback.
|
||||
- Run the closest Electron playback smoke/E2E coverage because the same
|
||||
Settings surface is used in the desktop app.
|
||||
|
||||
## Documentation Impact
|
||||
|
||||
Update `docs/architecture/player-controls-contract.md` and the shared-controls
|
||||
sections of `AGENTS.md` and `CLAUDE.md` to replace the compile-time-only
|
||||
default-off rollout description with the persisted experimental preference.
|
||||
The Embedded MPV architecture documentation only needs clarification if its
|
||||
existing distinction between frame-copy shared controls and the native-view
|
||||
legacy dock would otherwise become ambiguous.
|
||||
Reference in new issue
Block a user