mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-09 22:12:54 +01:00
Chore/tv interface scaling (#1591)
Signed-off-by: Lance Chant <13349722+lancechant@users.noreply.github.com>
This commit is contained in:
@@ -768,7 +768,7 @@ export default function page() {
|
|||||||
currentPlayStateInfo() as PlaybackProgressInfo,
|
currentPlayStateInfo() as PlaybackProgressInfo,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!Platform.isTV) await activateKeepAwakeAsync();
|
await activateKeepAwakeAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,7 +781,7 @@ export default function page() {
|
|||||||
currentPlayStateInfo() as PlaybackProgressInfo,
|
currentPlayStateInfo() as PlaybackProgressInfo,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!Platform.isTV) await deactivateKeepAwake();
|
await deactivateKeepAwake();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
} from "react";
|
} from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
|
Pressable,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
TVFocusGuideView,
|
TVFocusGuideView,
|
||||||
useWindowDimensions,
|
useWindowDimensions,
|
||||||
@@ -278,6 +279,9 @@ export const Controls: FC<Props> = ({
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Ref for the invisible focus-stealing overlay (prevents hidden buttons from receiving select events)
|
||||||
|
const focusOverlayRef = useRef<View>(null);
|
||||||
|
|
||||||
const audioTracks = useMemo(() => {
|
const audioTracks = useMemo(() => {
|
||||||
return mediaSource?.MediaStreams?.filter((s) => s.Type === "Audio") ?? [];
|
return mediaSource?.MediaStreams?.filter((s) => s.Type === "Audio") ?? [];
|
||||||
}, [mediaSource]);
|
}, [mediaSource]);
|
||||||
@@ -908,6 +912,19 @@ export const Controls: FC<Props> = ({
|
|||||||
setFocusPlayButton(false);
|
setFocusPlayButton(false);
|
||||||
}, [setShowControls]);
|
}, [setShowControls]);
|
||||||
|
|
||||||
|
// When controls hide (and no skip/countdown overlay is visible), move focus
|
||||||
|
// to the invisible overlay so hidden buttons can't receive select events.
|
||||||
|
useEffect(() => {
|
||||||
|
if (!showControls && !isSkipOrCountdownVisible) {
|
||||||
|
// Small delay to let the controls fade-out animation start and
|
||||||
|
// the focus engine settle before stealing focus
|
||||||
|
const t = setTimeout(() => {
|
||||||
|
focusOverlayRef.current?.focus();
|
||||||
|
}, 100);
|
||||||
|
return () => clearTimeout(t);
|
||||||
|
}
|
||||||
|
}, [showControls, isSkipOrCountdownVisible]);
|
||||||
|
|
||||||
const handleBack = useCallback(() => {
|
const handleBack = useCallback(() => {
|
||||||
router.back();
|
router.back();
|
||||||
}, [router]);
|
}, [router]);
|
||||||
@@ -1025,6 +1042,24 @@ export const Controls: FC<Props> = ({
|
|||||||
pointerEvents='none'
|
pointerEvents='none'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Invisible overlay that steals focus when controls are hidden.
|
||||||
|
Prevents hidden control buttons from receiving select/enter events
|
||||||
|
from the TV remote. Pressing center button here toggles play/pause. */}
|
||||||
|
<Pressable
|
||||||
|
ref={focusOverlayRef}
|
||||||
|
style={styles.focusStealingOverlay}
|
||||||
|
pointerEvents={
|
||||||
|
showControls || isSkipOrCountdownVisible ? "none" : "auto"
|
||||||
|
}
|
||||||
|
focusable={!showControls && !isSkipOrCountdownVisible}
|
||||||
|
hasTVPreferredFocus={!showControls && !isSkipOrCountdownVisible}
|
||||||
|
onPress={() => {
|
||||||
|
togglePlay();
|
||||||
|
setShowControls(true);
|
||||||
|
setFocusPlayButton(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
{getTechnicalInfo && (
|
{getTechnicalInfo && (
|
||||||
<TechnicalInfoOverlay
|
<TechnicalInfoOverlay
|
||||||
showControls={showControls}
|
showControls={showControls}
|
||||||
@@ -1177,6 +1212,7 @@ export const Controls: FC<Props> = ({
|
|||||||
<Animated.View
|
<Animated.View
|
||||||
style={[styles.bottomContainer, bottomAnimatedStyle]}
|
style={[styles.bottomContainer, bottomAnimatedStyle]}
|
||||||
pointerEvents={showControls ? "auto" : "none"}
|
pointerEvents={showControls ? "auto" : "none"}
|
||||||
|
focusable={showControls}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
@@ -1379,6 +1415,10 @@ const styles = StyleSheet.create({
|
|||||||
...StyleSheet.absoluteFillObject,
|
...StyleSheet.absoluteFillObject,
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
||||||
},
|
},
|
||||||
|
focusStealingOverlay: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
bottomContainer: {
|
bottomContainer: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
|
|||||||
@@ -79,10 +79,10 @@ export const TVAnimation = {
|
|||||||
* Applied to poster sizes and gaps.
|
* Applied to poster sizes and gaps.
|
||||||
*/
|
*/
|
||||||
const sizeScaleMultipliers: Record<TVTypographyScale, number> = {
|
const sizeScaleMultipliers: Record<TVTypographyScale, number> = {
|
||||||
[TVTypographyScale.Small]: 0.9,
|
[TVTypographyScale.Small]: 0.63,
|
||||||
[TVTypographyScale.Default]: 1.0,
|
[TVTypographyScale.Default]: 0.7,
|
||||||
[TVTypographyScale.Large]: 1.1,
|
[TVTypographyScale.Large]: 0.77,
|
||||||
[TVTypographyScale.ExtraLarge]: 1.2,
|
[TVTypographyScale.ExtraLarge]: 0.84,
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ export type TVTypographyKey = keyof typeof TVTypography;
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
const scaleMultipliers: Record<TVTypographyScale, number> = {
|
const scaleMultipliers: Record<TVTypographyScale, number> = {
|
||||||
[TVTypographyScale.Small]: 0.85,
|
[TVTypographyScale.Small]: 0.6,
|
||||||
[TVTypographyScale.Default]: 1.0,
|
[TVTypographyScale.Default]: 0.7,
|
||||||
[TVTypographyScale.Large]: 1.2,
|
[TVTypographyScale.Large]: 0.84,
|
||||||
[TVTypographyScale.ExtraLarge]: 1.4,
|
[TVTypographyScale.ExtraLarge]: 0.98,
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user