chore: updated usage of tv scaling, alert text fix

Sweep across a few pages to ensure they use the scaling factors now
Added a plugin to fix the alert text on android tv

Signed-off-by: Lance Chant <13349722+lancechant@users.noreply.github.com>
This commit is contained in:
Lance Chant
2026-05-22 15:00:13 +02:00
parent 5fd8e40c44
commit 03f17a758f
47 changed files with 528 additions and 389 deletions

View File

@@ -4,6 +4,7 @@ import React from "react";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVActorCardProps {
@@ -40,23 +41,23 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
animatedStyle,
{
alignItems: "center",
width: 160,
width: scaleSize(160),
shadowColor: "#fff",
shadowOffset: { width: 0, height: 0 },
shadowOpacity: focused ? 0.5 : 0,
shadowRadius: focused ? 16 : 0,
shadowRadius: focused ? scaleSize(16) : 0,
},
]}
>
<View
style={{
width: 140,
height: 140,
borderRadius: 70,
width: scaleSize(140),
height: scaleSize(140),
borderRadius: scaleSize(70),
overflow: "hidden",
backgroundColor: "rgba(255,255,255,0.1)",
marginBottom: 14,
borderWidth: 2,
marginBottom: scaleSize(14),
borderWidth: scaleSize(2),
borderColor: focused ? "#FFFFFF" : "transparent",
}}
>
@@ -76,7 +77,7 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
>
<Ionicons
name='person'
size={56}
size={scaleSize(56)}
color='rgba(255,255,255,0.4)'
/>
</View>
@@ -89,9 +90,9 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
fontWeight: "600",
color: focused ? "#fff" : "rgba(255,255,255,0.9)",
textAlign: "center",
marginBottom: 4,
marginBottom: scaleSize(4),
}}
numberOfLines={1}
numberOfLines={2}
>
{person.Name}
</Text>
@@ -105,7 +106,7 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
: "rgba(255,255,255,0.5)",
textAlign: "center",
}}
numberOfLines={1}
numberOfLines={2}
>
{person.Role}
</Text>

View File

@@ -1,5 +1,6 @@
import React from "react";
import { Animated, Pressable, View, type ViewStyle } from "react-native";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVButtonProps {
@@ -98,13 +99,13 @@ export const TVButton: React.FC<TVButtonProps> = ({
backgroundColor: buttonStyles.backgroundColor,
borderWidth: buttonStyles.borderWidth,
borderColor: buttonStyles.borderColor,
borderRadius: 12,
paddingVertical: 18,
paddingHorizontal: square ? 18 : 32,
borderRadius: scaleSize(12),
paddingVertical: scaleSize(18),
paddingHorizontal: square ? scaleSize(18) : scaleSize(32),
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
minWidth: square ? undefined : 180,
minWidth: square ? undefined : scaleSize(180),
}}
>
{children}

View File

@@ -3,6 +3,7 @@ import React from "react";
import { Animated, Pressable } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVCancelButtonProps {
@@ -33,18 +34,18 @@ export const TVCancelButton: React.FC<TVCancelButtonProps> = ({
animatedStyle,
{
backgroundColor: focused ? "#fff" : "rgba(255,255,255,0.15)",
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 10,
paddingHorizontal: scaleSize(20),
paddingVertical: scaleSize(12),
borderRadius: scaleSize(10),
flexDirection: "row",
alignItems: "center",
gap: 8,
gap: scaleSize(8),
},
]}
>
<Ionicons
name='close'
size={20}
size={scaleSize(20)}
color={focused ? "#000" : "rgba(255,255,255,0.8)"}
/>
<Text

View File

@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import { View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
export interface TVCastCrewTextProps {
director?: BaseItemPerson | null;
@@ -22,18 +23,18 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
}
return (
<View style={{ marginBottom: 32 }}>
<View style={{ marginBottom: scaleSize(32) }}>
<Text
style={{
fontSize: typography.heading,
fontWeight: "600",
color: "#FFFFFF",
marginBottom: 16,
marginBottom: scaleSize(16),
}}
>
{t("item_card.cast_and_crew")}
</Text>
<View style={{ flexDirection: "row", gap: 40 }}>
<View style={{ flexDirection: "row", gap: scaleSize(40) }}>
{director && (
<View>
<Text
@@ -42,7 +43,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
color: "#6B7280",
textTransform: "uppercase",
letterSpacing: 1,
marginBottom: 4,
marginBottom: scaleSize(4),
}}
>
{t("item_card.director")}
@@ -60,7 +61,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
color: "#6B7280",
textTransform: "uppercase",
letterSpacing: 1,
marginBottom: 4,
marginBottom: scaleSize(4),
}}
>
{t("item_card.cast")}

View File

@@ -6,6 +6,7 @@ import {
StyleSheet,
type View,
} from "react-native";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVControlButtonProps {
@@ -63,7 +64,7 @@ export const TVControlButton: FC<TVControlButtonProps> = ({
},
]}
>
<Ionicons name={icon} size={size} color='#fff' />
<Ionicons name={icon} size={scaleSize(size)} color='#fff' />
</RNAnimated.View>
</Pressable>
);
@@ -71,10 +72,10 @@ export const TVControlButton: FC<TVControlButtonProps> = ({
const styles = StyleSheet.create({
button: {
width: 64,
height: 64,
borderRadius: 32,
borderWidth: 2,
width: scaleSize(64),
height: scaleSize(64),
borderRadius: scaleSize(32),
borderWidth: scaleSize(2),
justifyContent: "center",
alignItems: "center",
},

View File

@@ -2,6 +2,7 @@ import React from "react";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVFilterButtonProps {
@@ -42,13 +43,13 @@ export const TVFilterButton: React.FC<TVFilterButtonProps> = ({
: hasActiveFilter
? "rgba(255, 255, 255, 0.25)"
: "rgba(255,255,255,0.1)",
borderRadius: 10,
paddingVertical: 10,
paddingHorizontal: 16,
borderRadius: scaleSize(10),
paddingVertical: scaleSize(10),
paddingHorizontal: scaleSize(16),
flexDirection: "row",
alignItems: "center",
gap: 8,
borderWidth: hasActiveFilter && !focused ? 1 : 0,
gap: scaleSize(8),
borderWidth: hasActiveFilter && !focused ? scaleSize(1) : 0,
borderColor: "rgba(255, 255, 255, 0.4)",
}}
>

View File

@@ -8,6 +8,7 @@ import {
} from "react-native";
import type { SharedValue } from "react-native-reanimated";
import ReanimatedModule, { useAnimatedStyle } from "react-native-reanimated";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
const ReanimatedView = ReanimatedModule.View;
@@ -35,7 +36,7 @@ export interface TVFocusableProgressBarProps {
style?: ViewStyle;
}
const PROGRESS_BAR_HEIGHT = 14;
const PROGRESS_BAR_HEIGHT = scaleSize(14);
export const TVFocusableProgressBar: React.FC<TVFocusableProgressBarProps> =
React.memo(
@@ -124,21 +125,21 @@ export const TVFocusableProgressBar: React.FC<TVFocusableProgressBarProps> =
const styles = StyleSheet.create({
pressableContainer: {
// Add padding for focus scale animation to not clip
paddingVertical: 8,
paddingHorizontal: 4,
paddingVertical: scaleSize(8),
paddingHorizontal: scaleSize(4),
},
animatedContainer: {
height: PROGRESS_BAR_HEIGHT + 8,
height: PROGRESS_BAR_HEIGHT + scaleSize(8),
justifyContent: "center",
borderRadius: 12,
paddingHorizontal: 4,
borderRadius: scaleSize(12),
paddingHorizontal: scaleSize(4),
},
animatedContainerFocused: {
// Subtle glow effect when focused
shadowColor: "#fff",
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0.5,
shadowRadius: 12,
shadowRadius: scaleSize(12),
},
progressTrackWrapper: {
position: "relative",
@@ -147,7 +148,7 @@ const styles = StyleSheet.create({
progressTrack: {
height: PROGRESS_BAR_HEIGHT,
backgroundColor: "rgba(255,255,255,0.2)",
borderRadius: 8,
borderRadius: scaleSize(8),
overflow: "hidden",
},
progressTrackFocused: {
@@ -160,7 +161,7 @@ const styles = StyleSheet.create({
left: 0,
height: "100%",
backgroundColor: "rgba(255,255,255,0.3)",
borderRadius: 8,
borderRadius: scaleSize(8),
},
progressFill: {
position: "absolute",
@@ -168,7 +169,7 @@ const styles = StyleSheet.create({
left: 0,
height: "100%",
backgroundColor: "#fff",
borderRadius: 8,
borderRadius: scaleSize(8),
},
chapterMarkersContainer: {
position: "absolute",
@@ -179,11 +180,11 @@ const styles = StyleSheet.create({
},
chapterMarker: {
position: "absolute",
width: 2,
height: PROGRESS_BAR_HEIGHT + 5,
width: scaleSize(2),
height: PROGRESS_BAR_HEIGHT + scaleSize(5),
bottom: 0,
backgroundColor: "rgba(255, 255, 255, 0.6)",
borderRadius: 1,
transform: [{ translateX: -1 }],
borderRadius: scaleSize(1),
transform: [{ translateX: -scaleSize(1) }],
},
});

View File

@@ -3,6 +3,7 @@ import React from "react";
import { Animated, Pressable, StyleSheet, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVLanguageCardProps {
@@ -63,7 +64,7 @@ export const TVLanguageCard = React.forwardRef<View, TVLanguageCardProps>(
<View style={styles.checkmark}>
<Ionicons
name='checkmark'
size={16}
size={scaleSize(16)}
color='rgba(255,255,255,0.8)'
/>
</View>
@@ -77,12 +78,12 @@ export const TVLanguageCard = React.forwardRef<View, TVLanguageCardProps>(
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
StyleSheet.create({
languageCard: {
width: 120,
height: 60,
borderRadius: 12,
width: scaleSize(120),
height: scaleSize(60),
borderRadius: scaleSize(12),
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 12,
paddingHorizontal: scaleSize(12),
},
languageCardText: {
fontSize: typography.callout,
@@ -94,7 +95,7 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
},
checkmark: {
position: "absolute",
top: 8,
right: 8,
top: scaleSize(8),
right: scaleSize(8),
},
});

View File

@@ -4,6 +4,7 @@ import { View } from "react-native";
import { Badge } from "@/components/Badge";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
export interface TVMetadataBadgesProps {
year?: number | null;
@@ -22,8 +23,8 @@ export const TVMetadataBadges: React.FC<TVMetadataBadgesProps> = React.memo(
flexDirection: "row",
alignItems: "center",
flexWrap: "wrap",
gap: 16,
marginBottom: 24,
gap: scaleSize(16),
marginBottom: scaleSize(24),
}}
>
{year != null && (

View File

@@ -23,6 +23,7 @@ import Animated, {
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVNextEpisodeCountdownProps {
@@ -198,17 +199,17 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
StyleSheet.create({
container: {
position: "absolute",
right: 80,
right: scaleSize(80),
zIndex: 100,
},
focusedCard: {
shadowColor: "#fff",
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0.6,
shadowRadius: 16,
shadowRadius: scaleSize(16),
},
blur: {
borderRadius: 16,
borderRadius: scaleSize(16),
overflow: "hidden",
},
innerContainer: {
@@ -216,31 +217,31 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
alignItems: "stretch",
},
thumbnail: {
width: 180,
width: scaleSize(180),
backgroundColor: "rgba(0,0,0,0.3)",
},
content: {
padding: 16,
padding: scaleSize(16),
justifyContent: "center",
width: 280,
width: scaleSize(280),
},
label: {
fontSize: typography.callout,
color: "rgba(255,255,255,0.5)",
textTransform: "uppercase",
letterSpacing: 1,
marginBottom: 4,
marginBottom: scaleSize(4),
},
seriesName: {
fontSize: typography.callout,
color: "rgba(255,255,255,0.7)",
marginBottom: 2,
marginBottom: scaleSize(2),
},
episodeInfo: {
fontSize: typography.body,
color: "#fff",
fontWeight: "600",
marginBottom: 12,
marginBottom: scaleSize(12),
},
progressContainer: {
height: 4,

View File

@@ -3,6 +3,7 @@ import React from "react";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVOptionCardProps {
@@ -49,12 +50,14 @@ export const TVOptionCard = React.forwardRef<View, TVOptionCardProps>(
backgroundColor: focused
? "#fff"
: selected
? "rgba(255,255,255,0.2)"
? "rgba(255,255,255,0.15)"
: "rgba(255,255,255,0.08)",
borderRadius: 14,
borderRadius: scaleSize(14),
borderWidth: focused ? 0 : selected ? scaleSize(2) : 0,
borderColor: "rgba(255,255,255,0.6)",
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 12,
paddingHorizontal: scaleSize(12),
},
]}
>

View File

@@ -10,6 +10,7 @@ import {
} from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { TVCancelButton } from "./TVCancelButton";
import { TVOptionCard } from "./TVOptionCard";
@@ -170,21 +171,21 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
width: "100%",
},
blurContainer: {
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
borderTopLeftRadius: scaleSize(24),
borderTopRightRadius: scaleSize(24),
overflow: "hidden",
},
content: {
paddingTop: 24,
paddingBottom: 50,
paddingTop: scaleSize(24),
paddingBottom: scaleSize(50),
overflow: "visible",
},
title: {
fontSize: typography.callout,
fontWeight: "500",
color: "rgba(255,255,255,0.6)",
marginBottom: 16,
paddingHorizontal: 48,
marginBottom: scaleSize(16),
paddingHorizontal: scaleSize(48),
textTransform: "uppercase",
letterSpacing: 1,
},
@@ -192,13 +193,13 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
overflow: "visible",
},
scrollContent: {
paddingHorizontal: 48,
paddingVertical: 20,
gap: 12,
paddingHorizontal: scaleSize(48),
paddingVertical: scaleSize(20),
gap: scaleSize(12),
},
cancelButtonContainer: {
marginTop: 16,
paddingHorizontal: 48,
marginTop: scaleSize(16),
paddingHorizontal: scaleSize(48),
alignItems: "flex-start",
},
});

View File

@@ -9,6 +9,7 @@ import {
GlassPosterView,
isGlassEffectAvailable,
} from "@/modules/glass-poster";
import { scaleSize } from "@/utils/scaleSize";
export interface TVSeriesSeasonCardProps {
title: string;
@@ -66,10 +67,10 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
style={{
width: sizes.posters.poster,
aspectRatio: 10 / 15,
borderRadius: 24,
borderRadius: scaleSize(24),
overflow: "hidden",
backgroundColor: "rgba(255,255,255,0.1)",
borderWidth: 2,
borderWidth: scaleSize(2),
borderColor: focused ? "#FFFFFF" : "transparent",
}}
>
@@ -87,7 +88,11 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
alignItems: "center",
}}
>
<Ionicons name='film' size={56} color='rgba(255,255,255,0.4)' />
<Ionicons
name='film'
size={scaleSize(56)}
color='rgba(255,255,255,0.4)'
/>
</View>
)}
</View>
@@ -129,7 +134,7 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
</Animated.View>
</Pressable>
<View style={{ marginTop: 12 }}>
<View style={{ marginTop: scaleSize(12) }}>
<Text
style={{
fontSize: typography.body,
@@ -145,7 +150,7 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
style={{
fontSize: typography.callout,
color: "#9CA3AF",
marginTop: 4,
marginTop: scaleSize(4),
}}
numberOfLines={1}
>

View File

@@ -16,6 +16,7 @@ import Animated, {
withTiming,
} from "react-native-reanimated";
import { Text } from "@/components/common/Text";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVSkipSegmentCardProps {
@@ -102,7 +103,7 @@ export const TVSkipSegmentCard: FC<TVSkipSegmentCardProps> = ({
},
]}
>
<Ionicons name='play-forward' size={20} color='#fff' />
<Ionicons name='play-forward' size={scaleSize(20)} color='#fff' />
<Text style={styles.label}>{labelText}</Text>
</RNAnimated.View>
</Pressable>
@@ -119,20 +120,20 @@ export const TVSkipSegmentCard: FC<TVSkipSegmentCardProps> = ({
const styles = StyleSheet.create({
container: {
position: "absolute",
right: 80,
right: scaleSize(80),
zIndex: 100,
},
button: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 10,
paddingHorizontal: 18,
borderRadius: 12,
borderWidth: 2,
gap: 8,
paddingVertical: scaleSize(10),
paddingHorizontal: scaleSize(18),
borderRadius: scaleSize(12),
borderWidth: scaleSize(2),
gap: scaleSize(8),
},
label: {
fontSize: 20,
fontSize: scaleSize(20),
color: "#fff",
fontWeight: "600",
},

View File

@@ -10,6 +10,7 @@ import {
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import type { SubtitleSearchResult } from "@/hooks/useRemoteSubtitles";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVSubtitleResultCardProps {
@@ -202,18 +203,18 @@ export const TVSubtitleResultCard = React.forwardRef<
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
StyleSheet.create({
resultCard: {
width: 220,
minHeight: 120,
borderRadius: 14,
padding: 14,
borderWidth: 1,
width: scaleSize(220),
minHeight: scaleSize(120),
borderRadius: scaleSize(14),
padding: scaleSize(14),
borderWidth: scaleSize(1),
},
providerBadge: {
alignSelf: "flex-start",
paddingHorizontal: 8,
paddingVertical: 3,
borderRadius: 6,
marginBottom: 8,
paddingHorizontal: scaleSize(8),
paddingVertical: scaleSize(3),
borderRadius: scaleSize(6),
marginBottom: scaleSize(8),
},
providerText: {
fontSize: typography.callout,
@@ -224,14 +225,14 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
resultName: {
fontSize: typography.callout,
fontWeight: "500",
marginBottom: 8,
lineHeight: 18,
marginBottom: scaleSize(8),
lineHeight: scaleSize(18),
},
resultMeta: {
flexDirection: "row",
alignItems: "center",
gap: 12,
marginBottom: 8,
gap: scaleSize(12),
marginBottom: scaleSize(8),
},
resultMetaText: {
fontSize: typography.callout,
@@ -248,13 +249,13 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
},
flagsContainer: {
flexDirection: "row",
gap: 6,
gap: scaleSize(6),
flexWrap: "wrap",
},
flag: {
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 4,
paddingHorizontal: scaleSize(6),
paddingVertical: scaleSize(2),
borderRadius: scaleSize(4),
},
flagText: {
fontSize: typography.callout,
@@ -264,7 +265,7 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
downloadingOverlay: {
...StyleSheet.absoluteFillObject,
backgroundColor: "rgba(0,0,0,0.5)",
borderRadius: 14,
borderRadius: scaleSize(14),
justifyContent: "center",
alignItems: "center",
},

View File

@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import { View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
export interface TVTechnicalDetailsProps {
mediaStreams: MediaStream[];
@@ -22,18 +23,18 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
}
return (
<View style={{ marginBottom: 32 }}>
<View style={{ marginBottom: scaleSize(32) }}>
<Text
style={{
fontSize: typography.heading,
fontWeight: "600",
color: "#FFFFFF",
marginBottom: 20,
marginBottom: scaleSize(20),
}}
>
{t("item_card.technical_details")}
</Text>
<View style={{ flexDirection: "row", gap: 40 }}>
<View style={{ flexDirection: "row", gap: scaleSize(40) }}>
{videoStream && (
<View>
<Text
@@ -42,7 +43,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
color: "#6B7280",
textTransform: "uppercase",
letterSpacing: 1,
marginBottom: 4,
marginBottom: scaleSize(4),
}}
>
{t("common.video")}
@@ -61,7 +62,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
color: "#6B7280",
textTransform: "uppercase",
letterSpacing: 1,
marginBottom: 4,
marginBottom: scaleSize(4),
}}
>
{t("common.audio")}

View File

@@ -2,6 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
import React, { useRef, useState } from "react";
import { Animated, Easing, Pressable, View } from "react-native";
import { AnimatedEqualizer } from "@/components/music/AnimatedEqualizer";
import { scaleSize } from "@/utils/scaleSize";
interface TVThemeMusicIndicatorProps {
isPlaying: boolean;
@@ -51,16 +52,16 @@ export const TVThemeMusicIndicator: React.FC<TVThemeMusicIndicatorProps> = ({
backgroundColor: focused
? "rgba(255,255,255,0.25)"
: "rgba(255,255,255,0.1)",
borderRadius: 12,
padding: 12,
borderRadius: scaleSize(12),
padding: scaleSize(12),
alignItems: "center",
justifyContent: "center",
width: 48,
height: 48,
width: scaleSize(48),
height: scaleSize(48),
}}
>
{isMuted ? (
<Ionicons name='volume-mute' size={22} color='#FFFFFF' />
<Ionicons name='volume-mute' size={scaleSize(22)} color='#FFFFFF' />
) : (
<View style={{ marginRight: 0 }}>
<AnimatedEqualizer

View File

@@ -3,6 +3,7 @@ import React from "react";
import { Animated, Pressable, StyleSheet, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
export interface TVTrackCardProps {
@@ -68,7 +69,7 @@ export const TVTrackCard = React.forwardRef<View, TVTrackCardProps>(
<View style={styles.checkmark}>
<Ionicons
name='checkmark'
size={16}
size={scaleSize(16)}
color='rgba(255,255,255,0.8)'
/>
</View>
@@ -82,12 +83,12 @@ export const TVTrackCard = React.forwardRef<View, TVTrackCardProps>(
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
StyleSheet.create({
trackCard: {
width: 180,
height: 80,
borderRadius: 14,
width: scaleSize(180),
height: scaleSize(80),
borderRadius: scaleSize(14),
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 12,
paddingHorizontal: scaleSize(12),
},
trackCardText: {
fontSize: typography.callout,
@@ -99,7 +100,7 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
},
checkmark: {
position: "absolute",
top: 8,
right: 8,
top: scaleSize(8),
right: scaleSize(8),
},
});

View File

@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import type { AccountSecurityType } from "@/utils/secureCredentials";
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
@@ -89,29 +90,33 @@ export const TVUserCard = React.forwardRef<View, TVUserCardProps>(
flexDirection: "row",
alignItems: "center",
backgroundColor: getBackgroundColor(),
borderRadius: 14,
paddingHorizontal: 16,
paddingVertical: 14,
gap: 14,
borderRadius: scaleSize(14),
paddingHorizontal: scaleSize(16),
paddingVertical: scaleSize(14),
gap: scaleSize(14),
},
]}
>
{/* User Avatar */}
<View
style={{
width: 44,
height: 44,
width: scaleSize(44),
height: scaleSize(44),
backgroundColor: isCurrent
? "rgba(255,255,255,0.08)"
: focused
? "rgba(0,0,0,0.1)"
: "rgba(255,255,255,0.15)",
borderRadius: 22,
borderRadius: scaleSize(22),
alignItems: "center",
justifyContent: "center",
}}
>
<Ionicons name='person' size={24} color={getTextColor()} />
<Ionicons
name='person'
size={scaleSize(24)}
color={getTextColor()}
/>
</View>
{/* Text column */}
@@ -153,7 +158,7 @@ export const TVUserCard = React.forwardRef<View, TVUserCardProps>(
>
<Ionicons
name={getSecurityIcon()}
size={12}
size={scaleSize(12)}
color={getSecondaryColor()}
/>
<Text

View File

@@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
export interface TVLogoutButtonProps {
@@ -41,9 +42,9 @@ export const TVLogoutButton: React.FC<TVLogoutButtonProps> = ({
<View
style={{
backgroundColor: focused ? "#ef4444" : "rgba(239, 68, 68, 0.8)",
borderRadius: 12,
paddingVertical: 18,
paddingHorizontal: 48,
borderRadius: scaleSize(12),
paddingVertical: scaleSize(18),
paddingHorizontal: scaleSize(48),
alignItems: "center",
justifyContent: "center",
}}

View File

@@ -3,6 +3,7 @@ import React from "react";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
export interface TVSettingsOptionButtonProps {
@@ -40,10 +41,10 @@ export const TVSettingsOptionButton: React.FC<TVSettingsOptionButtonProps> = ({
backgroundColor: focused
? "rgba(255, 255, 255, 0.15)"
: "rgba(255, 255, 255, 0.05)",
borderRadius: 12,
paddingVertical: 16,
paddingHorizontal: 24,
marginBottom: 8,
borderRadius: scaleSize(12),
paddingVertical: scaleSize(16),
paddingHorizontal: scaleSize(24),
marginBottom: scaleSize(8),
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -59,12 +60,16 @@ export const TVSettingsOptionButton: React.FC<TVSettingsOptionButtonProps> = ({
style={{
fontSize: typography.callout,
color: "#9CA3AF",
marginRight: 12,
marginRight: scaleSize(12),
}}
>
{value}
</Text>
<Ionicons name='chevron-forward' size={20} color='#6B7280' />
<Ionicons
name='chevron-forward'
size={scaleSize(20)}
color='#6B7280'
/>
</View>
</Animated.View>
</Pressable>

View File

@@ -3,6 +3,7 @@ import React from "react";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
export interface TVSettingsRowProps {
@@ -42,10 +43,10 @@ export const TVSettingsRow: React.FC<TVSettingsRowProps> = ({
backgroundColor: focused
? "rgba(255, 255, 255, 0.15)"
: "rgba(255, 255, 255, 0.05)",
borderRadius: 12,
paddingVertical: 16,
paddingHorizontal: 24,
marginBottom: 8,
borderRadius: scaleSize(12),
paddingVertical: scaleSize(16),
paddingHorizontal: scaleSize(24),
marginBottom: scaleSize(8),
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -60,13 +61,17 @@ export const TVSettingsRow: React.FC<TVSettingsRowProps> = ({
style={{
fontSize: typography.callout,
color: "#9CA3AF",
marginRight: showChevron ? 12 : 0,
marginRight: showChevron ? scaleSize(12) : 0,
}}
>
{value}
</Text>
{showChevron && (
<Ionicons name='chevron-forward' size={20} color='#6B7280' />
<Ionicons
name='chevron-forward'
size={scaleSize(20)}
color='#6B7280'
/>
)}
</View>
</Animated.View>

View File

@@ -3,6 +3,7 @@ import React from "react";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
export interface TVSettingsStepperProps {
@@ -38,10 +39,10 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
labelAnim.focused || minusAnim.focused || plusAnim.focused
? "rgba(255, 255, 255, 0.15)"
: "rgba(255, 255, 255, 0.05)",
borderRadius: 12,
paddingVertical: 16,
paddingHorizontal: 24,
marginBottom: 8,
borderRadius: scaleSize(12),
paddingVertical: scaleSize(16),
paddingHorizontal: scaleSize(24),
marginBottom: scaleSize(8),
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -72,9 +73,9 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
style={[
minusAnim.animatedStyle,
{
width: 40,
height: 40,
borderRadius: 10,
width: scaleSize(40),
height: scaleSize(40),
borderRadius: scaleSize(10),
backgroundColor: minusAnim.focused ? "#FFFFFF" : "#4B5563",
justifyContent: "center",
alignItems: "center",
@@ -83,7 +84,7 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
>
<Ionicons
name='remove'
size={24}
size={scaleSize(24)}
color={minusAnim.focused ? "#000000" : "#FFFFFF"}
/>
</Animated.View>
@@ -92,9 +93,9 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
style={{
fontSize: typography.callout,
color: "#FFFFFF",
minWidth: 60,
minWidth: scaleSize(60),
textAlign: "center",
marginHorizontal: 16,
marginHorizontal: scaleSize(16),
}}
>
{displayValue}
@@ -110,9 +111,9 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
style={[
plusAnim.animatedStyle,
{
width: 40,
height: 40,
borderRadius: 10,
width: scaleSize(40),
height: scaleSize(40),
borderRadius: scaleSize(10),
backgroundColor: plusAnim.focused ? "#FFFFFF" : "#4B5563",
justifyContent: "center",
alignItems: "center",
@@ -121,7 +122,7 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
>
<Ionicons
name='add'
size={24}
size={scaleSize(24)}
color={plusAnim.focused ? "#000000" : "#FFFFFF"}
/>
</Animated.View>

View File

@@ -2,6 +2,7 @@ import React, { useRef } from "react";
import { Animated, Pressable, TextInput } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
export interface TVSettingsTextInputProps {
@@ -48,10 +49,10 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
backgroundColor: focused
? "rgba(255, 255, 255, 0.15)"
: "rgba(255, 255, 255, 0.05)",
borderRadius: 12,
paddingVertical: 16,
paddingHorizontal: 24,
marginBottom: 8,
borderRadius: scaleSize(12),
paddingVertical: scaleSize(16),
paddingHorizontal: scaleSize(24),
marginBottom: scaleSize(8),
},
]}
>
@@ -59,7 +60,7 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
style={{
fontSize: typography.callout,
color: "#9CA3AF",
marginBottom: 8,
marginBottom: scaleSize(8),
}}
>
{label}
@@ -78,10 +79,10 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
fontSize: typography.body,
color: "#FFFFFF",
backgroundColor: "rgba(255, 255, 255, 0.05)",
borderRadius: 8,
paddingVertical: 12,
paddingHorizontal: 16,
borderWidth: focused ? 2 : 1,
borderRadius: scaleSize(8),
paddingVertical: scaleSize(12),
paddingHorizontal: scaleSize(16),
borderWidth: focused ? scaleSize(2) : scaleSize(1),
borderColor: focused ? "#FFFFFF" : "#4B5563",
}}
/>

View File

@@ -2,6 +2,7 @@ import React from "react";
import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
export interface TVSettingsToggleProps {
@@ -39,10 +40,10 @@ export const TVSettingsToggle: React.FC<TVSettingsToggleProps> = ({
backgroundColor: focused
? "rgba(255, 255, 255, 0.15)"
: "rgba(255, 255, 255, 0.05)",
borderRadius: 12,
paddingVertical: 16,
paddingHorizontal: 24,
marginBottom: 8,
borderRadius: scaleSize(12),
paddingVertical: scaleSize(16),
paddingHorizontal: scaleSize(24),
marginBottom: scaleSize(8),
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -54,19 +55,19 @@ export const TVSettingsToggle: React.FC<TVSettingsToggleProps> = ({
</Text>
<View
style={{
width: 56,
height: 32,
borderRadius: 16,
width: scaleSize(56),
height: scaleSize(32),
borderRadius: scaleSize(16),
backgroundColor: value ? "#FFFFFF" : "#4B5563",
justifyContent: "center",
paddingHorizontal: 2,
paddingHorizontal: scaleSize(2),
}}
>
<View
style={{
width: 28,
height: 28,
borderRadius: 14,
width: scaleSize(28),
height: scaleSize(28),
borderRadius: scaleSize(14),
backgroundColor: value ? "#000000" : "#FFFFFF",
alignSelf: value ? "flex-end" : "flex-start",
}}