chore: updated usage of tv scaling, alert text fix (#1587)

Signed-off-by: Lance Chant <13349722+lancechant@users.noreply.github.com>
This commit is contained in:
lance chant
2026-05-22 15:28:03 +02:00
committed by GitHub
parent 5fd8e40c44
commit f1140927a8
53 changed files with 575 additions and 424 deletions

View File

@@ -15,6 +15,7 @@ import {
View,
} from "react-native";
import { useHaptic } from "@/hooks/useHaptic";
import { scaleSize } from "@/utils/scaleSize";
import { Loader } from "./Loader";
const getColorClasses = (
@@ -135,16 +136,26 @@ export const Button: React.FC<PropsWithChildren<ButtonProps>> = ({
shadowColor: "#ffffff",
shadowOffset: { width: 0, height: 0 },
shadowOpacity: focused ? 0.5 : 0,
shadowRadius: focused ? 10 : 0,
shadowRadius: focused ? scaleSize(10) : 0,
elevation: focused ? 12 : 0, // Android glow
}}
>
<View
className={`rounded-2xl py-5 items-center justify-center
${colorClasses}
${className}`}
style={{
borderRadius: scaleSize(16),
paddingVertical: scaleSize(14),
alignItems: "center",
justifyContent: "center",
}}
className={`${colorClasses} ${className}`}
>
<Text className={`${textColorClass} text-xl font-bold`}>
<Text
style={{
fontSize: scaleSize(20),
fontWeight: "bold",
}}
className={textColorClass}
>
{children}
</Text>
</View>

View File

@@ -3,6 +3,7 @@ import React, { useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Animated, Easing, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { scaleSize } from "@/utils/scaleSize";
import type { SavedServerAccount } from "@/utils/secureCredentials";
interface TVAccountCardProps {
@@ -97,9 +98,9 @@ export const TVAccountCard: React.FC<TVAccountCardProps> = ({
backgroundColor: isFocused ? "#2a2a2a" : "#262626",
borderWidth: 2,
borderColor: isFocused ? "#FFFFFF" : "transparent",
borderRadius: 16,
paddingHorizontal: 24,
paddingVertical: 20,
borderRadius: scaleSize(16),
paddingHorizontal: scaleSize(24),
paddingVertical: scaleSize(20),
flexDirection: "row",
alignItems: "center",
}}
@@ -107,23 +108,23 @@ export const TVAccountCard: React.FC<TVAccountCardProps> = ({
{/* Avatar */}
<View
style={{
width: 56,
height: 56,
width: scaleSize(56),
height: scaleSize(56),
backgroundColor: "#404040",
borderRadius: 28,
borderRadius: scaleSize(28),
alignItems: "center",
justifyContent: "center",
marginRight: 20,
marginRight: scaleSize(20),
}}
>
<Ionicons name='person' size={28} color='white' />
<Ionicons name='person' size={scaleSize(28)} color='white' />
</View>
{/* Account Info */}
<View style={{ flex: 1 }}>
<Text
style={{
fontSize: 22,
fontSize: scaleSize(22),
fontWeight: "600",
color: "#FFFFFF",
}}
@@ -132,9 +133,9 @@ export const TVAccountCard: React.FC<TVAccountCardProps> = ({
</Text>
<Text
style={{
fontSize: 16,
fontSize: scaleSize(16),
color: "#9CA3AF",
marginTop: 4,
marginTop: scaleSize(4),
}}
>
{getSecurityText()}
@@ -142,7 +143,11 @@ export const TVAccountCard: React.FC<TVAccountCardProps> = ({
</View>
{/* Security Icon */}
<Ionicons name={getSecurityIcon()} size={24} color='#fff' />
<Ionicons
name={getSecurityIcon()}
size={scaleSize(24)}
color='#fff'
/>
</View>
</Animated.View>
</Pressable>

View File

@@ -4,6 +4,7 @@ import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
export interface TVAddIconProps {
label: string;
@@ -33,24 +34,24 @@ export const TVAddIcon = React.forwardRef<View, TVAddIconProps>(
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),
backgroundColor: focused
? "rgba(255,255,255,0.15)"
: "rgba(255,255,255,0.05)",
marginBottom: 14,
borderWidth: 2,
marginBottom: scaleSize(14),
borderWidth: scaleSize(2),
borderColor: focused ? "#fff" : "rgba(255,255,255,0.3)",
borderStyle: "dashed",
justifyContent: "center",
@@ -59,7 +60,7 @@ export const TVAddIcon = React.forwardRef<View, TVAddIconProps>(
>
<Ionicons
name='add'
size={56}
size={scaleSize(56)}
color={focused ? "#fff" : "rgba(255,255,255,0.5)"}
/>
</View>

View File

@@ -5,6 +5,7 @@ import { Button } from "@/components/Button";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { useTVBackPress } from "@/hooks/useTVBackPress";
import { scaleSize } from "@/utils/scaleSize";
import { TVInput } from "./TVInput";
interface TVAddServerFormProps {
@@ -48,7 +49,7 @@ export const TVAddServerForm: React.FC<TVAddServerFormProps> = ({
flexGrow: 1,
justifyContent: "center",
alignItems: "center",
paddingVertical: 60,
paddingVertical: scaleSize(60),
}}
showsVerticalScrollIndicator={false}
>
@@ -56,7 +57,7 @@ export const TVAddServerForm: React.FC<TVAddServerFormProps> = ({
style={{
width: "100%",
maxWidth: 800,
paddingHorizontal: 60,
paddingHorizontal: scaleSize(60),
}}
>
{/* Title */}
@@ -66,15 +67,20 @@ export const TVAddServerForm: React.FC<TVAddServerFormProps> = ({
fontWeight: "bold",
color: "#FFFFFF",
textAlign: "left",
marginBottom: 24,
paddingHorizontal: 8,
marginBottom: scaleSize(24),
paddingHorizontal: scaleSize(8),
}}
>
{t("server.enter_url_to_jellyfin_server")}
</Text>
{/* Server URL Input */}
<View style={{ marginBottom: 24, paddingHorizontal: 8 }}>
<View
style={{
marginBottom: scaleSize(24),
paddingHorizontal: scaleSize(8),
}}
>
<TVInput
placeholder={t("server.server_url_placeholder")}
value={serverURL}
@@ -89,7 +95,7 @@ export const TVAddServerForm: React.FC<TVAddServerFormProps> = ({
</View>
{/* Connect Button */}
<View style={{ marginBottom: 24 }}>
<View style={{ marginBottom: scaleSize(24) }}>
<Button
onPress={handleConnect}
loading={loading}

View File

@@ -5,6 +5,7 @@ import { Button } from "@/components/Button";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { useTVBackPress } from "@/hooks/useTVBackPress";
import { scaleSize } from "@/utils/scaleSize";
import { TVInput } from "./TVInput";
import { TVSaveAccountToggle } from "./TVSaveAccountToggle";
@@ -61,7 +62,7 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
flexGrow: 1,
justifyContent: "center",
alignItems: "center",
paddingVertical: 60,
paddingVertical: scaleSize(60),
}}
showsVerticalScrollIndicator={false}
>
@@ -69,7 +70,7 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
style={{
width: "100%",
maxWidth: 800,
paddingHorizontal: 60,
paddingHorizontal: scaleSize(60),
}}
>
{/* Title */}
@@ -78,7 +79,7 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
fontSize: typography.title,
fontWeight: "bold",
color: "#FFFFFF",
marginBottom: 8,
marginBottom: scaleSize(8),
}}
>
{serverName ? (
@@ -94,14 +95,19 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
style={{
fontSize: typography.callout,
color: "#9CA3AF",
marginBottom: 40,
marginBottom: scaleSize(40),
}}
>
{serverAddress}
</Text>
{/* Username Input */}
<View style={{ marginBottom: 24, paddingHorizontal: 8 }}>
<View
style={{
marginBottom: scaleSize(24),
paddingHorizontal: scaleSize(8),
}}
>
<TVInput
placeholder={t("login.username_placeholder")}
value={credentials.username}
@@ -118,7 +124,12 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
</View>
{/* Password Input */}
<View style={{ marginBottom: 32, paddingHorizontal: 8 }}>
<View
style={{
marginBottom: scaleSize(32),
paddingHorizontal: scaleSize(8),
}}
>
<TVInput
placeholder={t("login.password_placeholder")}
value={credentials.password}
@@ -134,7 +145,12 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
</View>
{/* Save Account Toggle */}
<View style={{ marginBottom: 40, paddingHorizontal: 8 }}>
<View
style={{
marginBottom: scaleSize(40),
paddingHorizontal: scaleSize(8),
}}
>
<TVSaveAccountToggle
value={saveAccount}
onValueChange={setSaveAccount}
@@ -144,7 +160,7 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
</View>
{/* Login Button */}
<View style={{ marginBottom: 16 }}>
<View style={{ marginBottom: scaleSize(16) }}>
<Button
onPress={handleLogin}
loading={loading}

View File

@@ -4,6 +4,7 @@ import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
export interface TVBackIconProps {
label: string;
@@ -33,24 +34,24 @@ export const TVBackIcon = React.forwardRef<View, TVBackIconProps>(
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),
backgroundColor: focused
? "rgba(255,255,255,0.15)"
: "rgba(255,255,255,0.05)",
marginBottom: 14,
borderWidth: 2,
marginBottom: scaleSize(14),
borderWidth: scaleSize(2),
borderColor: focused ? "#fff" : "rgba(255,255,255,0.3)",
borderStyle: "dashed",
justifyContent: "center",
@@ -59,7 +60,7 @@ export const TVBackIcon = React.forwardRef<View, TVBackIconProps>(
>
<Ionicons
name='arrow-back'
size={56}
size={scaleSize(56)}
color={focused ? "#fff" : "rgba(255,255,255,0.5)"}
/>
</View>

View File

@@ -6,6 +6,7 @@ import {
TextInput,
type TextInputProps,
} from "react-native";
import { scaleSize } from "@/utils/scaleSize";
interface TVInputProps extends TextInputProps {
label?: string;
@@ -58,7 +59,7 @@ export const TVInput: React.FC<TVInputProps> = ({
<Animated.View
style={{
transform: [{ scale }],
borderRadius: 12,
borderRadius: scaleSize(12),
backgroundColor: isFocused
? "rgba(255,255,255,0.15)"
: "rgba(255,255,255,0.08)",
@@ -73,10 +74,10 @@ export const TVInput: React.FC<TVInputProps> = ({
allowFontScaling={false}
style={[
{
height: 64,
fontSize: 22,
height: scaleSize(64),
fontSize: scaleSize(22),
color: "#FFFFFF",
paddingHorizontal: 20,
paddingHorizontal: scaleSize(20),
},
style,
]}

View File

@@ -15,6 +15,7 @@ import {
type PairingCredentials,
startPairingListener,
} from "@/utils/pairingService";
import { scaleSize } from "@/utils/scaleSize";
import {
type AccountSecurityType,
getPreviousServers,
@@ -700,17 +701,17 @@ export const TVLogin: React.FC = () => {
>
<Text
style={{
fontSize: 24,
fontSize: scaleSize(24),
fontWeight: "bold",
color: "#FFFFFF",
marginBottom: 12,
marginBottom: scaleSize(12),
}}
>
{t("pairing.logging_in")}
</Text>
<Text
style={{
fontSize: 16,
fontSize: scaleSize(16),
color: "#9CA3AF",
}}
>

View File

@@ -12,6 +12,7 @@ import {
View,
} from "react-native";
import { Text } from "@/components/common/Text";
import { scaleSize } from "@/utils/scaleSize";
import { verifyAccountPIN } from "@/utils/secureCredentials";
interface TVPINEntryModalProps {
@@ -130,15 +131,15 @@ const ForgotPINLink: React.FC<{
<Animated.View
style={{
transform: [{ scale }],
paddingHorizontal: 16,
paddingVertical: 10,
borderRadius: 8,
paddingHorizontal: scaleSize(16),
paddingVertical: scaleSize(10),
borderRadius: scaleSize(8),
backgroundColor: focused ? "rgba(255,255,255,0.15)" : "transparent",
}}
>
<Text
style={{
fontSize: 16,
fontSize: scaleSize(16),
color: focused ? "#fff" : "rgba(255,255,255,0.5)",
}}
>
@@ -417,36 +418,36 @@ const styles = StyleSheet.create({
maxWidth: 400,
},
blurContainer: {
borderRadius: 24,
borderRadius: scaleSize(24),
overflow: "hidden",
},
content: {
padding: 40,
padding: scaleSize(40),
alignItems: "center",
},
title: {
fontSize: 28,
fontSize: scaleSize(28),
fontWeight: "bold",
color: "#fff",
marginBottom: 8,
marginBottom: scaleSize(8),
textAlign: "center",
},
subtitle: {
fontSize: 18,
fontSize: scaleSize(18),
color: "rgba(255,255,255,0.6)",
marginBottom: 32,
marginBottom: scaleSize(32),
textAlign: "center",
},
pinDotsContainer: {
flexDirection: "row",
gap: 16,
marginBottom: 32,
gap: scaleSize(16),
marginBottom: scaleSize(32),
},
pinDot: {
width: 20,
height: 20,
borderRadius: 10,
borderWidth: 2,
width: scaleSize(20),
height: scaleSize(20),
borderRadius: scaleSize(10),
borderWidth: scaleSize(2),
borderColor: "rgba(255,255,255,0.4)",
backgroundColor: "transparent",
},
@@ -459,26 +460,26 @@ const styles = StyleSheet.create({
backgroundColor: "#ef4444",
},
numberPad: {
gap: 12,
marginBottom: 24,
gap: scaleSize(12),
marginBottom: scaleSize(24),
},
numberRow: {
flexDirection: "row",
gap: 12,
gap: scaleSize(12),
},
numberButton: {
width: 72,
height: 72,
borderRadius: 36,
width: scaleSize(72),
height: scaleSize(72),
borderRadius: scaleSize(36),
justifyContent: "center",
alignItems: "center",
},
numberButtonPlaceholder: {
width: 72,
height: 72,
width: scaleSize(72),
height: scaleSize(72),
},
numberText: {
fontSize: 28,
fontSize: scaleSize(28),
fontWeight: "600",
},
forgotContainer: {

View File

@@ -14,6 +14,7 @@ import {
} from "react-native";
import { Text } from "@/components/common/Text";
import { useTVFocusAnimation } from "@/components/tv";
import { scaleSize } from "@/utils/scaleSize";
interface TVPasswordEntryModalProps {
visible: boolean;
@@ -51,14 +52,14 @@ const TVSubmitButton: React.FC<{
: isDisabled
? "#4a4a4a"
: "rgba(255,255,255,0.15)",
paddingHorizontal: 24,
paddingVertical: 14,
borderRadius: 10,
paddingHorizontal: scaleSize(24),
paddingVertical: scaleSize(14),
borderRadius: scaleSize(10),
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: 8,
minWidth: 120,
gap: scaleSize(8),
minWidth: scaleSize(120),
opacity: isDisabled ? 0.5 : 1,
},
]}
@@ -69,12 +70,12 @@ const TVSubmitButton: React.FC<{
<>
<Ionicons
name='log-in-outline'
size={20}
size={scaleSize(20)}
color={focused ? "#000" : "#fff"}
/>
<Text
style={{
fontSize: 16,
fontSize: scaleSize(16),
color: focused ? "#000" : "#fff",
fontWeight: "600",
}}
@@ -121,11 +122,11 @@ const TVPasswordInput: React.FC<{
animatedStyle,
{
backgroundColor: "#1F2937",
borderRadius: 12,
borderWidth: 2,
borderRadius: scaleSize(12),
borderWidth: scaleSize(2),
borderColor: focused ? "#fff" : "#374151",
paddingHorizontal: 16,
paddingVertical: 14,
paddingHorizontal: scaleSize(16),
paddingVertical: scaleSize(14),
},
]}
>
@@ -140,7 +141,7 @@ const TVPasswordInput: React.FC<{
autoCorrect={false}
style={{
color: "#fff",
fontSize: 18,
fontSize: scaleSize(18),
}}
onSubmitEditing={onSubmitEditing}
returnKeyType='done'
@@ -299,45 +300,45 @@ const styles = StyleSheet.create({
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",
},
header: {
paddingHorizontal: 48,
marginBottom: 24,
paddingHorizontal: scaleSize(48),
marginBottom: scaleSize(24),
},
title: {
fontSize: 28,
fontSize: scaleSize(28),
fontWeight: "bold",
color: "#fff",
marginBottom: 4,
marginBottom: scaleSize(4),
},
subtitle: {
fontSize: 16,
fontSize: scaleSize(16),
color: "rgba(255,255,255,0.6)",
},
inputContainer: {
paddingHorizontal: 48,
marginBottom: 20,
paddingHorizontal: scaleSize(48),
marginBottom: scaleSize(20),
},
inputLabel: {
fontSize: 14,
fontSize: scaleSize(14),
color: "rgba(255,255,255,0.6)",
marginBottom: 8,
marginBottom: scaleSize(8),
},
errorText: {
color: "#ef4444",
fontSize: 14,
marginTop: 8,
fontSize: scaleSize(14),
marginTop: scaleSize(8),
},
buttonContainer: {
paddingHorizontal: 48,
paddingHorizontal: scaleSize(48),
alignItems: "flex-start",
},
});

View File

@@ -57,7 +57,7 @@ export const TVQRCodeDisplay: React.FC<TVQRCodeDisplayProps> = ({
alignItems: "center",
paddingVertical: sectionPadding,
paddingHorizontal: cardPadding,
borderRadius: 16,
borderRadius: scaleSize(16),
backgroundColor: "rgba(255, 255, 255, 0.05)",
}}
>
@@ -66,7 +66,7 @@ export const TVQRCodeDisplay: React.FC<TVQRCodeDisplayProps> = ({
fontSize: typography.heading,
fontWeight: "bold",
color: "#FFFFFF",
marginBottom: 8,
marginBottom: scaleSize(8),
}}
>
{t("pairing.waiting_for_phone")}
@@ -75,7 +75,7 @@ export const TVQRCodeDisplay: React.FC<TVQRCodeDisplayProps> = ({
<View
style={{
padding: cardPadding,
borderRadius: 12,
borderRadius: scaleSize(12),
backgroundColor: "#FFFFFF",
}}
>

View File

@@ -14,6 +14,7 @@ import {
import { Text } from "@/components/common/Text";
import { TVPinInput, type TVPinInputRef } from "@/components/inputs/TVPinInput";
import { TVOptionCard, useTVFocusAnimation } from "@/components/tv";
import { scaleSize } from "@/utils/scaleSize";
import type { AccountSecurityType } from "@/utils/secureCredentials";
interface TVSaveAccountModalProps {
@@ -79,24 +80,24 @@ const TVSaveButton: React.FC<{
: disabled
? "#4a4a4a"
: "rgba(255,255,255,0.15)",
paddingHorizontal: 24,
paddingVertical: 14,
borderRadius: 10,
paddingHorizontal: scaleSize(24),
paddingVertical: scaleSize(14),
borderRadius: scaleSize(10),
flexDirection: "row",
alignItems: "center",
gap: 8,
gap: scaleSize(8),
opacity: disabled ? 0.5 : 1,
},
]}
>
<Ionicons
name='checkmark'
size={20}
size={scaleSize(20)}
color={focused ? "#000" : "#fff"}
/>
<Text
style={{
fontSize: 16,
fontSize: scaleSize(16),
color: focused ? "#000" : "#fff",
fontWeight: "600",
}}
@@ -129,23 +130,23 @@ const TVBackButton: React.FC<{
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='chevron-back'
size={20}
size={scaleSize(20)}
color={focused ? "#000" : "rgba(255,255,255,0.8)"}
/>
<Text
style={{
fontSize: 16,
fontSize: scaleSize(16),
color: focused ? "#000" : "rgba(255,255,255,0.8)",
fontWeight: "500",
}}
@@ -378,35 +379,35 @@ const styles = StyleSheet.create({
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",
},
header: {
paddingHorizontal: 48,
marginBottom: 20,
paddingHorizontal: scaleSize(48),
marginBottom: scaleSize(20),
},
title: {
fontSize: 28,
fontSize: scaleSize(28),
fontWeight: "bold",
color: "#fff",
marginBottom: 4,
marginBottom: scaleSize(4),
},
subtitle: {
fontSize: 16,
fontSize: scaleSize(16),
color: "rgba(255,255,255,0.6)",
},
sectionTitle: {
fontSize: 16,
fontSize: scaleSize(16),
fontWeight: "500",
color: "rgba(255,255,255,0.6)",
marginBottom: 16,
paddingHorizontal: 48,
marginBottom: scaleSize(16),
paddingHorizontal: scaleSize(48),
textTransform: "uppercase",
letterSpacing: 1,
},
@@ -414,26 +415,26 @@ const styles = StyleSheet.create({
overflow: "visible",
},
scrollContent: {
paddingHorizontal: 48,
paddingVertical: 10,
gap: 12,
paddingHorizontal: scaleSize(48),
paddingVertical: scaleSize(10),
gap: scaleSize(12),
},
buttonRow: {
marginTop: 20,
paddingHorizontal: 48,
marginTop: scaleSize(20),
paddingHorizontal: scaleSize(48),
flexDirection: "row",
gap: 16,
gap: scaleSize(16),
alignItems: "center",
},
pinContainer: {
paddingHorizontal: 48,
paddingHorizontal: scaleSize(48),
alignItems: "center",
marginBottom: 10,
marginBottom: scaleSize(10),
},
errorText: {
color: "#ef4444",
fontSize: 14,
marginTop: 12,
fontSize: scaleSize(14),
marginTop: scaleSize(12),
textAlign: "center",
},
});

View File

@@ -1,6 +1,7 @@
import React, { useRef, useState } from "react";
import { Animated, Easing, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { scaleSize } from "@/utils/scaleSize";
interface TVSaveAccountToggleProps {
value: boolean;
@@ -74,9 +75,9 @@ export const TVSaveAccountToggle: React.FC<TVSaveAccountToggleProps> = ({
backgroundColor: isFocused ? "#2a2a2a" : "#1a1a1a",
borderWidth: 2,
borderColor: isFocused ? "#FFFFFF" : "transparent",
borderRadius: 16,
paddingHorizontal: 24,
paddingVertical: 20,
borderRadius: scaleSize(16),
paddingHorizontal: scaleSize(24),
paddingVertical: scaleSize(20),
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -84,7 +85,7 @@ export const TVSaveAccountToggle: React.FC<TVSaveAccountToggleProps> = ({
>
<Text
style={{
fontSize: 20,
fontSize: scaleSize(20),
color: "#FFFFFF",
}}
>
@@ -93,19 +94,19 @@ export const TVSaveAccountToggle: React.FC<TVSaveAccountToggleProps> = ({
<View
pointerEvents='none'
style={{
width: 60,
height: 34,
borderRadius: 17,
width: scaleSize(60),
height: scaleSize(34),
borderRadius: scaleSize(17),
backgroundColor: value ? "#fff" : "#3f3f46",
justifyContent: "center",
paddingHorizontal: 3,
paddingHorizontal: scaleSize(3),
}}
>
<View
style={{
width: 28,
height: 28,
borderRadius: 14,
width: scaleSize(28),
height: scaleSize(28),
borderRadius: scaleSize(14),
backgroundColor: value ? "#000" : "#fff",
alignSelf: value ? "flex-end" : "flex-start",
}}

View File

@@ -4,6 +4,7 @@ import { Animated, Pressable, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
// Sci-fi gradient color pairs (from, to) - cyberpunk/neon vibes
const SERVER_GRADIENTS: [string, string][] = [
@@ -131,22 +132,22 @@ export const TVServerIcon = React.forwardRef<View, TVServerIconProps>(
animatedStyle,
{
alignItems: "center",
width: 160,
width: scaleSize(160),
shadowColor: gradientStart,
shadowOffset: { width: 0, height: 0 },
shadowOpacity: focused ? 0.7 : 0,
shadowRadius: focused ? 24 : 0,
shadowRadius: focused ? scaleSize(24) : 0,
},
]}
>
<View
style={{
width: 140,
height: 140,
borderRadius: 70,
width: scaleSize(140),
height: scaleSize(140),
borderRadius: scaleSize(70),
overflow: "hidden",
marginBottom: 14,
borderWidth: focused ? 3 : 0,
marginBottom: scaleSize(14),
borderWidth: focused ? scaleSize(3) : 0,
borderColor: "#fff",
}}
>
@@ -164,7 +165,7 @@ export const TVServerIcon = React.forwardRef<View, TVServerIconProps>(
>
<Text
style={{
fontSize: 48,
fontSize: scaleSize(48),
fontWeight: "bold",
color: "#fff",
textShadowColor: "rgba(0,0,0,0.3)",
@@ -183,9 +184,9 @@ export const TVServerIcon = React.forwardRef<View, TVServerIconProps>(
fontWeight: "600",
color: focused ? "#fff" : "rgba(255,255,255,0.9)",
textAlign: "center",
marginBottom: 4,
marginBottom: scaleSize(4),
}}
numberOfLines={2}
numberOfLines={3}
>
{displayName}
</Text>
@@ -199,7 +200,7 @@ export const TVServerIcon = React.forwardRef<View, TVServerIconProps>(
: "rgba(255,255,255,0.5)",
textAlign: "center",
}}
numberOfLines={1}
numberOfLines={3}
>
{address.replace(/^https?:\/\//, "")}
</Text>

View File

@@ -5,6 +5,7 @@ import { Alert, ScrollView, View } from "react-native";
import { useMMKVString } from "react-native-mmkv";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import type { SavedServer } from "@/utils/secureCredentials";
import { TVAddIcon } from "./TVAddIcon";
import { TVServerIcon } from "./TVServerIcon";
@@ -56,7 +57,7 @@ export const TVServerSelectionScreen: React.FC<
flexGrow: 1,
justifyContent: "center",
alignItems: "center",
paddingVertical: 60,
paddingVertical: scaleSize(60),
}}
showsVerticalScrollIndicator={false}
>
@@ -64,14 +65,14 @@ export const TVServerSelectionScreen: React.FC<
style={{
width: "100%",
alignItems: "center",
paddingHorizontal: 60,
paddingHorizontal: scaleSize(60),
}}
>
{/* Logo */}
<View style={{ alignItems: "center", marginBottom: 16 }}>
<View style={{ alignItems: "center", marginBottom: scaleSize(16) }}>
<Image
source={require("@/assets/images/icon-ios-plain.png")}
style={{ width: 150, height: 150 }}
style={{ width: scaleSize(150), height: scaleSize(150) }}
contentFit='contain'
/>
</View>
@@ -83,7 +84,7 @@ export const TVServerSelectionScreen: React.FC<
fontWeight: "bold",
color: "#FFFFFF",
textAlign: "center",
marginBottom: 8,
marginBottom: scaleSize(8),
}}
>
Streamyfin
@@ -93,7 +94,7 @@ export const TVServerSelectionScreen: React.FC<
fontSize: typography.body,
color: "#9CA3AF",
textAlign: "center",
marginBottom: 48,
marginBottom: scaleSize(48),
}}
>
{hasServers
@@ -106,8 +107,8 @@ export const TVServerSelectionScreen: React.FC<
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
paddingHorizontal: 20,
gap: 24,
paddingHorizontal: scaleSize(20),
gap: scaleSize(24),
}}
style={{ overflow: "visible" }}
>

View File

@@ -6,6 +6,7 @@ import { Text } from "@/components/common/Text";
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { getUserImageUrl } from "@/utils/jellyfin/image/getUserImageUrl";
import { scaleSize } from "@/utils/scaleSize";
import type { AccountSecurityType } from "@/utils/secureCredentials";
export interface TVUserIconProps {
@@ -76,27 +77,27 @@ export const TVUserIcon = React.forwardRef<View, TVUserIconProps>(
animatedStyle,
{
alignItems: "center",
width: 160,
width: scaleSize(160),
overflow: "visible",
shadowColor: "#fff",
shadowOffset: { width: 0, height: 0 },
shadowOpacity: focused ? 0.5 : 0,
shadowRadius: focused ? 16 : 0,
shadowRadius: focused ? scaleSize(16) : 0,
},
]}
>
<View style={{ position: "relative" }}>
<View
style={{
width: 140,
height: 140,
borderRadius: 70,
width: scaleSize(140),
height: scaleSize(140),
borderRadius: scaleSize(70),
overflow: "hidden",
backgroundColor: focused
? "rgba(255,255,255,0.2)"
: "rgba(255,255,255,0.1)",
marginBottom: 14,
borderWidth: focused ? 3 : 0,
marginBottom: scaleSize(14),
borderWidth: focused ? scaleSize(3) : 0,
borderColor: "#fff",
justifyContent: "center",
alignItems: "center",
@@ -105,14 +106,14 @@ export const TVUserIcon = React.forwardRef<View, TVUserIconProps>(
{imageUrl ? (
<Image
source={{ uri: imageUrl }}
style={{ width: 140, height: 140 }}
style={{ width: scaleSize(140), height: scaleSize(140) }}
contentFit='cover'
onError={() => setImageError(true)}
/>
) : (
<Ionicons
name='person'
size={56}
size={scaleSize(56)}
color={
focused ? "rgba(255,255,255,0.6)" : "rgba(255,255,255,0.4)"
}
@@ -125,21 +126,25 @@ export const TVUserIcon = React.forwardRef<View, TVUserIconProps>(
<View
style={{
position: "absolute",
bottom: 10,
right: 10,
width: 32,
height: 32,
borderRadius: 16,
bottom: scaleSize(10),
right: scaleSize(10),
width: scaleSize(32),
height: scaleSize(32),
borderRadius: scaleSize(16),
backgroundColor: focused ? "#fff" : "rgba(255,255,255,0.9)",
justifyContent: "center",
alignItems: "center",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOffset: { width: 0, height: scaleSize(2) },
shadowOpacity: 0.3,
shadowRadius: 4,
shadowRadius: scaleSize(4),
}}
>
<Ionicons name={getSecurityIcon()} size={16} color='#000' />
<Ionicons
name={getSecurityIcon()}
size={scaleSize(16)}
color='#000'
/>
</View>
)}
</View>

View File

@@ -4,6 +4,7 @@ import { ScrollView, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { useTVBackPress } from "@/hooks/useTVBackPress";
import { scaleSize } from "@/utils/scaleSize";
import type {
SavedServer,
SavedServerAccount,
@@ -47,7 +48,7 @@ export const TVUserSelectionScreen: React.FC<TVUserSelectionScreenProps> = ({
flexGrow: 1,
justifyContent: "center",
alignItems: "center",
paddingVertical: 60,
paddingVertical: scaleSize(60),
}}
showsVerticalScrollIndicator={false}
>
@@ -55,18 +56,18 @@ export const TVUserSelectionScreen: React.FC<TVUserSelectionScreenProps> = ({
style={{
width: "100%",
alignItems: "center",
paddingHorizontal: 60,
paddingHorizontal: scaleSize(60),
}}
>
{/* Server Info Header */}
<View style={{ marginBottom: 48, alignItems: "center" }}>
<View style={{ marginBottom: scaleSize(48), alignItems: "center" }}>
<Text
style={{
fontSize: typography.title,
fontWeight: "bold",
color: "#FFFFFF",
textAlign: "center",
marginBottom: 8,
marginBottom: scaleSize(8),
}}
>
{server.name || server.address}
@@ -87,7 +88,7 @@ export const TVUserSelectionScreen: React.FC<TVUserSelectionScreenProps> = ({
fontSize: typography.body,
color: "#6B7280",
textAlign: "center",
marginTop: 16,
marginTop: scaleSize(16),
}}
>
{hasAccounts
@@ -101,8 +102,8 @@ export const TVUserSelectionScreen: React.FC<TVUserSelectionScreenProps> = ({
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
paddingHorizontal: 20,
gap: 24,
paddingHorizontal: scaleSize(20),
gap: scaleSize(24),
}}
style={{ overflow: "visible" }}
>

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 { FlatList, ScrollView, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVSizes } from "@/constants/TVSizes";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
interface TVHorizontalListProps<T> {
/** Data items to render */
@@ -94,7 +95,7 @@ export function TVHorizontalList<T>({
fontSize: typography.heading,
fontWeight: "700",
color: "#FFFFFF",
marginBottom: 20,
marginBottom: scaleSize(20),
marginLeft: sizes.padding.scale,
letterSpacing: 0.5,
}}
@@ -125,7 +126,7 @@ export function TVHorizontalList<T>({
fontSize: typography.heading,
fontWeight: "700",
color: "#FFFFFF",
marginBottom: 20,
marginBottom: scaleSize(20),
marginLeft: sizes.padding.scale,
letterSpacing: 0.5,
}}
@@ -167,7 +168,7 @@ export function TVHorizontalList<T>({
fontSize: typography.heading,
fontWeight: "700",
color: "#FFFFFF",
marginBottom: 20,
marginBottom: scaleSize(20),
marginLeft: sizes.padding.scale,
letterSpacing: 0.5,
}}

View File

@@ -3,6 +3,7 @@ import React from "react";
import { View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
export interface TVItemCardTextProps {
item: BaseItemDto;
@@ -12,7 +13,7 @@ export const TVItemCardText: React.FC<TVItemCardTextProps> = ({ item }) => {
const typography = useScaledTVTypography();
return (
<View style={{ marginTop: 12 }}>
<View style={{ marginTop: scaleSize(12) }}>
<Text
numberOfLines={1}
style={{ fontSize: typography.callout, color: "#FFFFFF" }}
@@ -23,7 +24,7 @@ export const TVItemCardText: React.FC<TVItemCardTextProps> = ({ item }) => {
style={{
fontSize: typography.callout - 2,
color: "#9CA3AF",
marginTop: 2,
marginTop: scaleSize(2),
}}
>
{item.ProductionYear}

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,
@@ -90,11 +91,11 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
},
languageCardCode: {
fontSize: typography.callout,
marginTop: 2,
marginTop: scaleSize(2),
},
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 {
@@ -44,8 +45,8 @@ export interface TVNextEpisodeCountdownProps {
}
// Position constants
const BOTTOM_WITH_CONTROLS = 300;
const BOTTOM_WITHOUT_CONTROLS = 120;
const BOTTOM_WITH_CONTROLS = scaleSize(300);
const BOTTOM_WITHOUT_CONTROLS = scaleSize(120);
export const TVNextEpisodeCountdown: FC<TVNextEpisodeCountdownProps> = ({
nextItem,
@@ -74,7 +75,7 @@ export const TVNextEpisodeCountdown: FC<TVNextEpisodeCountdownProps> = ({
const imageUrl = getPrimaryImageUrl({
api,
item: nextItem,
width: 360,
width: scaleSize(360),
quality: 80,
});
@@ -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,42 +217,42 @@ 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,
height: scaleSize(4),
backgroundColor: "rgba(255,255,255,0.2)",
borderRadius: 2,
borderRadius: scaleSize(2),
overflow: "hidden",
},
progressBar: {
height: "100%",
backgroundColor: "#fff",
borderRadius: 2,
borderRadius: scaleSize(2),
},
returnFocusGuide: {
height: 1,

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 TVOptionButtonProps {
@@ -42,12 +43,12 @@ export const TVOptionButton = React.forwardRef<View, TVOptionButtonProps>(
<View
style={{
backgroundColor: "#fff",
borderRadius: 8,
paddingVertical: 10,
paddingHorizontal: 16,
borderRadius: scaleSize(8),
paddingVertical: scaleSize(10),
paddingHorizontal: scaleSize(16),
flexDirection: "row",
alignItems: "center",
gap: 8,
gap: scaleSize(8),
maxWidth,
}}
>

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),
},
]}
>
@@ -75,7 +78,7 @@ export const TVOptionCard = React.forwardRef<View, TVOptionCardProps>(
fontSize: typography.callout,
color: focused ? "rgba(0,0,0,0.6)" : "rgba(255,255,255,0.5)",
textAlign: "center",
marginTop: 2,
marginTop: scaleSize(2),
}}
numberOfLines={1}
>

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

@@ -1,5 +1,6 @@
import React from "react";
import { View } from "react-native";
import { scaleSize } from "@/utils/scaleSize";
export interface TVProgressBarProps {
/** Progress value between 0 and 1 */
@@ -23,14 +24,16 @@ export const TVProgressBar: React.FC<TVProgressBarProps> = React.memo(
height = 4,
}) => {
const clampedProgress = Math.max(0, Math.min(1, progress));
const scaledMaxWidth = scaleSize(maxWidth);
const scaledHeight = scaleSize(height);
return (
<View style={{ maxWidth, marginBottom: 24 }}>
<View style={{ maxWidth: scaledMaxWidth, marginBottom: scaleSize(24) }}>
<View
style={{
height,
height: scaledHeight,
backgroundColor: trackColor,
borderRadius: height / 2,
borderRadius: scaledHeight / 2,
overflow: "hidden",
}}
>
@@ -39,7 +42,7 @@ export const TVProgressBar: React.FC<TVProgressBarProps> = React.memo(
width: `${clampedProgress * 100}%`,
height: "100%",
backgroundColor: fillColor,
borderRadius: height / 2,
borderRadius: scaledHeight / 2,
}}
/>
</View>

View File

@@ -5,6 +5,7 @@ import { ScrollView, View } from "react-native";
import { Text } from "@/components/common/Text";
import { useScaledTVSizes } from "@/constants/TVSizes";
import { useScaledTVTypography } from "@/constants/TVTypography";
import { scaleSize } from "@/utils/scaleSize";
import { TVSeriesSeasonCard } from "./TVSeriesSeasonCard";
export interface TVSeriesNavigationProps {
@@ -33,7 +34,7 @@ export const TVSeriesNavigation: React.FC<TVSeriesNavigationProps> = React.memo(
fontSize: typography.heading,
fontWeight: "700",
color: "#FFFFFF",
marginBottom: 20,
marginBottom: scaleSize(20),
letterSpacing: 0.5,
}}
>

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,
@@ -239,22 +240,22 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
ratingContainer: {
flexDirection: "row",
alignItems: "center",
gap: 3,
gap: scaleSize(3),
},
downloadCountContainer: {
flexDirection: "row",
alignItems: "center",
gap: 3,
gap: scaleSize(3),
},
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

@@ -2,6 +2,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 TVTabButtonProps {
@@ -48,10 +49,10 @@ export const TVTabButton: React.FC<TVTabButtonProps> = ({
? "rgba(255,255,255,0.2)"
: "transparent",
borderBottomColor: active ? "#fff" : "transparent",
borderBottomWidth: 2,
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 8,
borderBottomWidth: scaleSize(2),
paddingHorizontal: scaleSize(20),
paddingVertical: scaleSize(12),
borderRadius: scaleSize(8),
},
]}
>

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,24 +52,24 @@ 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
color='#FFFFFF'
barWidth={3}
barWidth={scaleSize(3)}
barCount={3}
height={18}
gap={2}
height={scaleSize(18)}
gap={scaleSize(2)}
/>
</View>
)}

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,
@@ -95,11 +96,11 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
},
trackCardSublabel: {
fontSize: typography.callout,
marginTop: 2,
marginTop: scaleSize(2),
},
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,36 +90,44 @@ 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 */}
<View style={{ gap: 4 }}>
<View style={{ gap: scaleSize(4) }}>
{/* Username */}
<View
style={{ flexDirection: "row", alignItems: "center", gap: 8 }}
style={{
flexDirection: "row",
alignItems: "center",
gap: scaleSize(8),
}}
>
<Text
style={{
@@ -148,12 +157,12 @@ export const TVUserCard = React.forwardRef<View, TVUserCardProps>(
style={{
flexDirection: "row",
alignItems: "center",
gap: 4,
gap: scaleSize(4),
}}
>
<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",
}}