fix(plex): the player's stage follows the tablet toolbar, and its bands stay out of a double-tap
- The stage is sized in dvh (80dvh × 1.25 windowed, 100dvh fullscreen); the viewport-units contract no longer exempts the player. - A tap that reveals the bands keeps them pointer-events-none for the double-tap window, so the second tap of a skip at the bottom is not a seek. - An arrow on the volume slider wakes the bands, and a keyboard focus in a band holds them (`holdOnFocus`, `:focus-visible` only, so a clicked button does not pin the bar). - Next stays mounted (disabled) while the next episode's detail loads, keeping the focus.
This commit is contained in:
@@ -72,7 +72,8 @@ export function useFullscreen(wrapRef: RefObject<HTMLElement | null>): {
|
||||
// bar up so it can't vanish mid-choice), and the <video> paused state (a paused video keeps the bar).
|
||||
// `holdOnHover` is the pointer resting on the chrome: the bar stays while it is there (as on YouTube
|
||||
// and Plex Web — E28 F22, it used to fade out from under a mouse parked on Next), and leaving it
|
||||
// starts a fresh 3 s.
|
||||
// starts a fresh 3 s. `holdOnFocus` is the same for a KEYBOARD focus in the chrome (E28 review E6): the
|
||||
// bar must not fade from under the control a key user is on.
|
||||
//
|
||||
// On touch (C3) nothing moves a mouse, so the timer is also armed by PLAYBACK starting — before, the
|
||||
// bar stayed up until the first tap however long the video played — and a tap on the picture only
|
||||
@@ -86,6 +87,7 @@ export function useControlsVisibility(opts: {
|
||||
uiVisible: boolean;
|
||||
wake: () => void;
|
||||
holdOnHover: (over: boolean) => void;
|
||||
holdOnFocus: (on: boolean) => void;
|
||||
toggle: () => void;
|
||||
show: (visible: boolean) => void;
|
||||
} {
|
||||
@@ -94,6 +96,7 @@ export function useControlsVisibility(opts: {
|
||||
const visibleRef = useRef(true);
|
||||
const hideTimer = useRef<number | null>(null);
|
||||
const hovered = useRef(false);
|
||||
const focused = useRef(false);
|
||||
const setVisible = useCallback((v: boolean) => {
|
||||
visibleRef.current = v;
|
||||
setUiVisible(v);
|
||||
@@ -104,7 +107,8 @@ export function useControlsVisibility(opts: {
|
||||
if (!barAutoHideRef.current) return; // per-user setting: never auto-hide the control bar
|
||||
hideTimer.current = window.setTimeout(() => {
|
||||
// Keep the controls up while the audio/subtitle menu is open, else it would vanish mid-choice.
|
||||
if (!videoRef.current?.paused && !menuOpenRef.current && !hovered.current) setVisible(false);
|
||||
if (!videoRef.current?.paused && !menuOpenRef.current && !hovered.current && !focused.current)
|
||||
setVisible(false);
|
||||
}, 3000);
|
||||
}, [barAutoHideRef, menuOpenRef, videoRef, setVisible]);
|
||||
const show = useCallback(
|
||||
@@ -124,6 +128,13 @@ export function useControlsVisibility(opts: {
|
||||
},
|
||||
[wake],
|
||||
);
|
||||
const holdOnFocus = useCallback(
|
||||
(on: boolean) => {
|
||||
focused.current = on;
|
||||
if (!on) wake();
|
||||
},
|
||||
[wake],
|
||||
);
|
||||
useEffect(() => {
|
||||
const video = videoRef.current;
|
||||
if (!video) return;
|
||||
@@ -136,7 +147,7 @@ export function useControlsVisibility(opts: {
|
||||
},
|
||||
[],
|
||||
);
|
||||
return { uiVisible, wake, holdOnHover, toggle, show };
|
||||
return { uiVisible, wake, holdOnHover, holdOnFocus, toggle, show };
|
||||
}
|
||||
|
||||
// Periodic + on-unmount progress checkpoint. Reads live position/duration through refs (owned by the
|
||||
|
||||
Reference in New Issue
Block a user