mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 13:16:16 -08:00
* feat(player-controls): shared engine-agnostic controls layer (flag off) 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> * fix(player-controls): harden shared controls foundation * fix(player-controls): restore detached adapter state * fix(player-controls): harden keyboard and adapter state * fix(player-controls): refresh readiness and hide timers * fix(player-controls): keep controls root inside surface * fix(player-controls): hide seek controls for live streams * fix(player-controls): harden multi-engine control state * fix(player-controls): respect runtime interaction availability * fix(player-controls): gate loading toggles and localize mute * fix(player-controls): harden surface and error states * fix(player-controls): preserve volume and cursor state --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: 4gray <serega05@gmail.com>
44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
export function formatTime(value: number | null | undefined): string {
|
||
const safeValue = Math.max(0, Math.floor(value ?? 0));
|
||
const hours = Math.floor(safeValue / 3600);
|
||
const minutes = Math.floor((safeValue % 3600) / 60);
|
||
const seconds = safeValue % 60;
|
||
|
||
if (hours > 0) {
|
||
return `${hours}:${String(minutes).padStart(2, '0')}:${String(
|
||
seconds
|
||
).padStart(2, '0')}`;
|
||
}
|
||
|
||
return `${minutes}:${String(seconds).padStart(2, '0')}`;
|
||
}
|
||
|
||
export function volumeIcon(value: number): string {
|
||
if (value <= 0) {
|
||
return 'volume_off';
|
||
}
|
||
return value < 0.5 ? 'volume_down' : 'volume_up';
|
||
}
|
||
|
||
export function volumeLabel(value: number): string {
|
||
return `Volume ${Math.round(value * 100)}%`;
|
||
}
|
||
|
||
/** Rounds and formats a playback rate as e.g. `1.5×` for tooltips. */
|
||
export function speedLabel(speed: number): string {
|
||
const value = Math.round(speed * 100) / 100;
|
||
return `${value}×`;
|
||
}
|
||
|
||
export function readStoredVolume(): number {
|
||
const rawValue = Number(localStorage.getItem('volume') ?? '1');
|
||
if (Number.isNaN(rawValue)) {
|
||
return 1;
|
||
}
|
||
return Math.max(0, Math.min(1, rawValue));
|
||
}
|
||
|
||
export function persistVolume(value: number): void {
|
||
localStorage.setItem('volume', String(value));
|
||
}
|