Skip to content

feat(player-controls): shared engine-agnostic controls layer (flag off) [1/7]#3

Closed
larsemig wants to merge 1 commit into
base/upstream-masterfrom
pr/01-player-controls-core
Closed

feat(player-controls): shared engine-agnostic controls layer (flag off) [1/7]#3
larsemig wants to merge 1 commit into
base/upstream-masterfrom
pr/01-player-controls-core

Conversation

@larsemig

@larsemig larsemig commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Note

Sidenote from the author: My review focus for this series was the architecture, not every implementation detail. If there are specific contribution guidelines I should follow (commit style, PR conventions, test expectations, etc.), please let me know and I will adapt the series accordingly.

Step 1 of the 7-PR series implementing the direction approved in (unified player-controls architecture).

What

A shared, engine-agnostic player-controls layer — pure additive library code, zero behavior change:

  • Contract (player-controls.model.ts): capabilities + reactive state + commands. Engines implement it via thin adapters.
  • One presentation component (app-player-controls): white controls, gradient scrim, popover menus, keyboard shortcuts.
  • Focused helpers (controls-*): visibility, volume, fullscreen, menus, feedback, formatting, shortcuts — each with its own spec.
  • WebVideoControlsAdapter + host: generic adapter over any HTMLVideoElement; engine specifics (hls.js/Video.js/ArtPlayer) are passed in via options, never imported.
  • WEB_PLAYER_SHARED_CONTROLS flag — default OFF. No player consumes this layer yet.
  • docs/architecture/player-controls-contract.md — describes the target architecture; the file map marks entries that land in later PRs of this series.

Why

Today every engine ships its own vendor skin (Video.js, HTML5, ArtPlayer, embedded MPV), so look, behavior and shortcuts differ per player. This layer makes the controls our component: build a feature once, every player inherits it.

Safety / review notes

  • 3769 insertions, 0 deletions — the only touched existing file is the lib barrel (+1 export line).
  • Roughly half the diff is specs (9 spec files) + the contract doc.
  • Lint (incl. max-lines rule) and full ui-playback test suite green.

🗺️ Series roadmap (proposal

Step Branch Purpose
➡️ 1 pr/01-player-controls-core Shared engine-agnostic controls layer (lib only, flag OFF)
2 pr/02-embedded-mpv-decompose Decompose embedded-MPV session controller (no behavior change)
3 pr/03-embedded-mpv-immersive Embedded MPV adopts shared controls + immersive overlay (macOS)
4 pr/04-embedded-mpv-native-fullscreen Real macOS native fullscreen for embedded MPV
5 pr/05-html5-shared-controls HTML5 player on shared controls (flag OFF)
6 pr/06-vjs-shared-controls Video.js on shared controls (flag OFF)
7 pr/07-art-player-shared-controls ArtPlayer on shared controls (flag OFF)

Stacked series: each PR is based on the previous one, so every diff shows only its own step.

🤖 Generated with Claude Code

@larsemig
larsemig force-pushed the pr/01-player-controls-core branch from 9cbf902 to 8010bc4 Compare July 7, 2026 19:00
Introduce a shared, engine-agnostic player-controls layer in libs/ui/playback
as pure additive library code with no consumers yet.

- Contract (player-controls.model.ts): PlayerControlsCapabilities,
  PlayerControlsState, and PlayerControlsCommands make up the
  PlayerController interface every engine adapter implements.
- Single presentation component (app-player-controls): one controls UI
  binding purely to a PlayerController, with focused helpers for
  visibility auto-hide, volume, fullscreen (built-in DOM path), menus,
  keyboard shortcuts, seek/volume feedback, and the controls surface.
- Web-video adapter (web-video-controls.adapter.ts + host directive):
  drives the contract from an HTMLVideoElement, including optional
  HLS.js quality/audio-track integration and series episode navigation.
- Feature flag WEB_PLAYER_SHARED_CONTROLS (web-player-controls.flag.ts)
  defaults to OFF; no player component consumes the new layer yet, so
  runtime behavior is unchanged.
- docs/architecture/player-controls-contract.md documents the target
  architecture (later PRs add the embedded-MPV adapter, immersive
  overlay, and host-supplied fullscreen delegate).

Review-driven hardening: the web-video adapter now holds the host
series-navigation signal reactively (updates after setContext are
reflected); the shared controls template is fully localized via
ngx-translate (reusing the EMBEDDED_MPV.PLAYER.* keys); single click on
the viewport toggles play/pause deferred so a double-click still
fullscreens; keyboard shortcuts are shadow-DOM-safe (composedPath) and
guard against duplicate-instance double-execution (defaultPrevented);
and hidden controls now also disable shortcuts.

Test coverage extended per Codecov patch report.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@larsemig
larsemig force-pushed the pr/01-player-controls-core branch from 8010bc4 to e3c8da6 Compare July 7, 2026 19:56
@larsemig

larsemig commented Jul 7, 2026

Copy link
Copy Markdown
Owner Author

Used as template only

@larsemig larsemig closed this Jul 7, 2026
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