mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-05-30 02:28:26 +01:00
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:
1
app.json
1
app.json
@@ -136,6 +136,7 @@
|
|||||||
"expo-web-browser",
|
"expo-web-browser",
|
||||||
["./plugins/with-runtime-framework-headers.js"],
|
["./plugins/with-runtime-framework-headers.js"],
|
||||||
["./plugins/withChangeNativeAndroidTextToWhite.js"],
|
["./plugins/withChangeNativeAndroidTextToWhite.js"],
|
||||||
|
["./plugins/withAndroidAlertColors.js"],
|
||||||
["./plugins/withAndroidManifest.js"],
|
["./plugins/withAndroidManifest.js"],
|
||||||
["./plugins/withTrustLocalCerts.js"],
|
["./plugins/withTrustLocalCerts.js"],
|
||||||
["./plugins/withGradleProperties.js"],
|
["./plugins/withGradleProperties.js"],
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
View,
|
View,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { useHaptic } from "@/hooks/useHaptic";
|
import { useHaptic } from "@/hooks/useHaptic";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { Loader } from "./Loader";
|
import { Loader } from "./Loader";
|
||||||
|
|
||||||
const getColorClasses = (
|
const getColorClasses = (
|
||||||
@@ -135,16 +136,26 @@ export const Button: React.FC<PropsWithChildren<ButtonProps>> = ({
|
|||||||
shadowColor: "#ffffff",
|
shadowColor: "#ffffff",
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: focused ? 0.5 : 0,
|
shadowOpacity: focused ? 0.5 : 0,
|
||||||
shadowRadius: focused ? 10 : 0,
|
shadowRadius: focused ? scaleSize(10) : 0,
|
||||||
elevation: focused ? 12 : 0, // Android glow
|
elevation: focused ? 12 : 0, // Android glow
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
className={`rounded-2xl py-5 items-center justify-center
|
style={{
|
||||||
${colorClasses}
|
borderRadius: scaleSize(16),
|
||||||
${className}`}
|
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}
|
{children}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React, { useRef, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Animated, Easing, Pressable, View } from "react-native";
|
import { Animated, Easing, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import type { SavedServerAccount } from "@/utils/secureCredentials";
|
import type { SavedServerAccount } from "@/utils/secureCredentials";
|
||||||
|
|
||||||
interface TVAccountCardProps {
|
interface TVAccountCardProps {
|
||||||
@@ -97,9 +98,9 @@ export const TVAccountCard: React.FC<TVAccountCardProps> = ({
|
|||||||
backgroundColor: isFocused ? "#2a2a2a" : "#262626",
|
backgroundColor: isFocused ? "#2a2a2a" : "#262626",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
borderColor: isFocused ? "#FFFFFF" : "transparent",
|
borderColor: isFocused ? "#FFFFFF" : "transparent",
|
||||||
borderRadius: 16,
|
borderRadius: scaleSize(16),
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
paddingVertical: 20,
|
paddingVertical: scaleSize(20),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
@@ -107,23 +108,23 @@ export const TVAccountCard: React.FC<TVAccountCardProps> = ({
|
|||||||
{/* Avatar */}
|
{/* Avatar */}
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 56,
|
width: scaleSize(56),
|
||||||
height: 56,
|
height: scaleSize(56),
|
||||||
backgroundColor: "#404040",
|
backgroundColor: "#404040",
|
||||||
borderRadius: 28,
|
borderRadius: scaleSize(28),
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
marginRight: 20,
|
marginRight: scaleSize(20),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name='person' size={28} color='white' />
|
<Ionicons name='person' size={scaleSize(28)} color='white' />
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Account Info */}
|
{/* Account Info */}
|
||||||
<View style={{ flex: 1 }}>
|
<View style={{ flex: 1 }}>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 22,
|
fontSize: scaleSize(22),
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
}}
|
}}
|
||||||
@@ -132,9 +133,9 @@ export const TVAccountCard: React.FC<TVAccountCardProps> = ({
|
|||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
color: "#9CA3AF",
|
color: "#9CA3AF",
|
||||||
marginTop: 4,
|
marginTop: scaleSize(4),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{getSecurityText()}
|
{getSecurityText()}
|
||||||
@@ -142,7 +143,11 @@ export const TVAccountCard: React.FC<TVAccountCardProps> = ({
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Security Icon */}
|
{/* Security Icon */}
|
||||||
<Ionicons name={getSecurityIcon()} size={24} color='#fff' />
|
<Ionicons
|
||||||
|
name={getSecurityIcon()}
|
||||||
|
size={scaleSize(24)}
|
||||||
|
color='#fff'
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Animated, Pressable, View } from "react-native";
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
export interface TVAddIconProps {
|
export interface TVAddIconProps {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -33,24 +34,24 @@ export const TVAddIcon = React.forwardRef<View, TVAddIconProps>(
|
|||||||
animatedStyle,
|
animatedStyle,
|
||||||
{
|
{
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
width: 160,
|
width: scaleSize(160),
|
||||||
shadowColor: "#fff",
|
shadowColor: "#fff",
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: focused ? 0.5 : 0,
|
shadowOpacity: focused ? 0.5 : 0,
|
||||||
shadowRadius: focused ? 16 : 0,
|
shadowRadius: focused ? scaleSize(16) : 0,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 140,
|
width: scaleSize(140),
|
||||||
height: 140,
|
height: scaleSize(140),
|
||||||
borderRadius: 70,
|
borderRadius: scaleSize(70),
|
||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "rgba(255,255,255,0.15)"
|
? "rgba(255,255,255,0.15)"
|
||||||
: "rgba(255,255,255,0.05)",
|
: "rgba(255,255,255,0.05)",
|
||||||
marginBottom: 14,
|
marginBottom: scaleSize(14),
|
||||||
borderWidth: 2,
|
borderWidth: scaleSize(2),
|
||||||
borderColor: focused ? "#fff" : "rgba(255,255,255,0.3)",
|
borderColor: focused ? "#fff" : "rgba(255,255,255,0.3)",
|
||||||
borderStyle: "dashed",
|
borderStyle: "dashed",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
@@ -59,7 +60,7 @@ export const TVAddIcon = React.forwardRef<View, TVAddIconProps>(
|
|||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='add'
|
name='add'
|
||||||
size={56}
|
size={scaleSize(56)}
|
||||||
color={focused ? "#fff" : "rgba(255,255,255,0.5)"}
|
color={focused ? "#fff" : "rgba(255,255,255,0.5)"}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Button } from "@/components/Button";
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
import { useTVBackPress } from "@/hooks/useTVBackPress";
|
import { useTVBackPress } from "@/hooks/useTVBackPress";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { TVInput } from "./TVInput";
|
import { TVInput } from "./TVInput";
|
||||||
|
|
||||||
interface TVAddServerFormProps {
|
interface TVAddServerFormProps {
|
||||||
@@ -48,7 +49,7 @@ export const TVAddServerForm: React.FC<TVAddServerFormProps> = ({
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingVertical: 60,
|
paddingVertical: scaleSize(60),
|
||||||
}}
|
}}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
@@ -56,7 +57,7 @@ export const TVAddServerForm: React.FC<TVAddServerFormProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
maxWidth: 800,
|
maxWidth: 800,
|
||||||
paddingHorizontal: 60,
|
paddingHorizontal: scaleSize(60),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
@@ -66,15 +67,20 @@ export const TVAddServerForm: React.FC<TVAddServerFormProps> = ({
|
|||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
marginBottom: 24,
|
marginBottom: scaleSize(24),
|
||||||
paddingHorizontal: 8,
|
paddingHorizontal: scaleSize(8),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("server.enter_url_to_jellyfin_server")}
|
{t("server.enter_url_to_jellyfin_server")}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{/* Server URL Input */}
|
{/* Server URL Input */}
|
||||||
<View style={{ marginBottom: 24, paddingHorizontal: 8 }}>
|
<View
|
||||||
|
style={{
|
||||||
|
marginBottom: scaleSize(24),
|
||||||
|
paddingHorizontal: scaleSize(8),
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TVInput
|
<TVInput
|
||||||
placeholder={t("server.server_url_placeholder")}
|
placeholder={t("server.server_url_placeholder")}
|
||||||
value={serverURL}
|
value={serverURL}
|
||||||
@@ -89,7 +95,7 @@ export const TVAddServerForm: React.FC<TVAddServerFormProps> = ({
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Connect Button */}
|
{/* Connect Button */}
|
||||||
<View style={{ marginBottom: 24 }}>
|
<View style={{ marginBottom: scaleSize(24) }}>
|
||||||
<Button
|
<Button
|
||||||
onPress={handleConnect}
|
onPress={handleConnect}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Button } from "@/components/Button";
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
import { useTVBackPress } from "@/hooks/useTVBackPress";
|
import { useTVBackPress } from "@/hooks/useTVBackPress";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { TVInput } from "./TVInput";
|
import { TVInput } from "./TVInput";
|
||||||
import { TVSaveAccountToggle } from "./TVSaveAccountToggle";
|
import { TVSaveAccountToggle } from "./TVSaveAccountToggle";
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingVertical: 60,
|
paddingVertical: scaleSize(60),
|
||||||
}}
|
}}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
@@ -69,7 +70,7 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
maxWidth: 800,
|
maxWidth: 800,
|
||||||
paddingHorizontal: 60,
|
paddingHorizontal: scaleSize(60),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
@@ -78,7 +79,7 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
|
|||||||
fontSize: typography.title,
|
fontSize: typography.title,
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{serverName ? (
|
{serverName ? (
|
||||||
@@ -94,14 +95,19 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
color: "#9CA3AF",
|
color: "#9CA3AF",
|
||||||
marginBottom: 40,
|
marginBottom: scaleSize(40),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{serverAddress}
|
{serverAddress}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{/* Username Input */}
|
{/* Username Input */}
|
||||||
<View style={{ marginBottom: 24, paddingHorizontal: 8 }}>
|
<View
|
||||||
|
style={{
|
||||||
|
marginBottom: scaleSize(24),
|
||||||
|
paddingHorizontal: scaleSize(8),
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TVInput
|
<TVInput
|
||||||
placeholder={t("login.username_placeholder")}
|
placeholder={t("login.username_placeholder")}
|
||||||
value={credentials.username}
|
value={credentials.username}
|
||||||
@@ -118,7 +124,12 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Password Input */}
|
{/* Password Input */}
|
||||||
<View style={{ marginBottom: 32, paddingHorizontal: 8 }}>
|
<View
|
||||||
|
style={{
|
||||||
|
marginBottom: scaleSize(32),
|
||||||
|
paddingHorizontal: scaleSize(8),
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TVInput
|
<TVInput
|
||||||
placeholder={t("login.password_placeholder")}
|
placeholder={t("login.password_placeholder")}
|
||||||
value={credentials.password}
|
value={credentials.password}
|
||||||
@@ -134,7 +145,12 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Save Account Toggle */}
|
{/* Save Account Toggle */}
|
||||||
<View style={{ marginBottom: 40, paddingHorizontal: 8 }}>
|
<View
|
||||||
|
style={{
|
||||||
|
marginBottom: scaleSize(40),
|
||||||
|
paddingHorizontal: scaleSize(8),
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TVSaveAccountToggle
|
<TVSaveAccountToggle
|
||||||
value={saveAccount}
|
value={saveAccount}
|
||||||
onValueChange={setSaveAccount}
|
onValueChange={setSaveAccount}
|
||||||
@@ -144,7 +160,7 @@ export const TVAddUserForm: React.FC<TVAddUserFormProps> = ({
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Login Button */}
|
{/* Login Button */}
|
||||||
<View style={{ marginBottom: 16 }}>
|
<View style={{ marginBottom: scaleSize(16) }}>
|
||||||
<Button
|
<Button
|
||||||
onPress={handleLogin}
|
onPress={handleLogin}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Animated, Pressable, View } from "react-native";
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
export interface TVBackIconProps {
|
export interface TVBackIconProps {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -33,24 +34,24 @@ export const TVBackIcon = React.forwardRef<View, TVBackIconProps>(
|
|||||||
animatedStyle,
|
animatedStyle,
|
||||||
{
|
{
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
width: 160,
|
width: scaleSize(160),
|
||||||
shadowColor: "#fff",
|
shadowColor: "#fff",
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: focused ? 0.5 : 0,
|
shadowOpacity: focused ? 0.5 : 0,
|
||||||
shadowRadius: focused ? 16 : 0,
|
shadowRadius: focused ? scaleSize(16) : 0,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 140,
|
width: scaleSize(140),
|
||||||
height: 140,
|
height: scaleSize(140),
|
||||||
borderRadius: 70,
|
borderRadius: scaleSize(70),
|
||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "rgba(255,255,255,0.15)"
|
? "rgba(255,255,255,0.15)"
|
||||||
: "rgba(255,255,255,0.05)",
|
: "rgba(255,255,255,0.05)",
|
||||||
marginBottom: 14,
|
marginBottom: scaleSize(14),
|
||||||
borderWidth: 2,
|
borderWidth: scaleSize(2),
|
||||||
borderColor: focused ? "#fff" : "rgba(255,255,255,0.3)",
|
borderColor: focused ? "#fff" : "rgba(255,255,255,0.3)",
|
||||||
borderStyle: "dashed",
|
borderStyle: "dashed",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
@@ -59,7 +60,7 @@ export const TVBackIcon = React.forwardRef<View, TVBackIconProps>(
|
|||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='arrow-back'
|
name='arrow-back'
|
||||||
size={56}
|
size={scaleSize(56)}
|
||||||
color={focused ? "#fff" : "rgba(255,255,255,0.5)"}
|
color={focused ? "#fff" : "rgba(255,255,255,0.5)"}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
type TextInputProps,
|
type TextInputProps,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
interface TVInputProps extends TextInputProps {
|
interface TVInputProps extends TextInputProps {
|
||||||
label?: string;
|
label?: string;
|
||||||
@@ -58,7 +59,7 @@ export const TVInput: React.FC<TVInputProps> = ({
|
|||||||
<Animated.View
|
<Animated.View
|
||||||
style={{
|
style={{
|
||||||
transform: [{ scale }],
|
transform: [{ scale }],
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
backgroundColor: isFocused
|
backgroundColor: isFocused
|
||||||
? "rgba(255,255,255,0.15)"
|
? "rgba(255,255,255,0.15)"
|
||||||
: "rgba(255,255,255,0.08)",
|
: "rgba(255,255,255,0.08)",
|
||||||
@@ -73,10 +74,10 @@ export const TVInput: React.FC<TVInputProps> = ({
|
|||||||
allowFontScaling={false}
|
allowFontScaling={false}
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
height: 64,
|
height: scaleSize(64),
|
||||||
fontSize: 22,
|
fontSize: scaleSize(22),
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: scaleSize(20),
|
||||||
},
|
},
|
||||||
style,
|
style,
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
type PairingCredentials,
|
type PairingCredentials,
|
||||||
startPairingListener,
|
startPairingListener,
|
||||||
} from "@/utils/pairingService";
|
} from "@/utils/pairingService";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import {
|
import {
|
||||||
type AccountSecurityType,
|
type AccountSecurityType,
|
||||||
getPreviousServers,
|
getPreviousServers,
|
||||||
@@ -700,17 +701,17 @@ export const TVLogin: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: scaleSize(24),
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
marginBottom: 12,
|
marginBottom: scaleSize(12),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("pairing.logging_in")}
|
{t("pairing.logging_in")}
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
color: "#9CA3AF",
|
color: "#9CA3AF",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
View,
|
View,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { verifyAccountPIN } from "@/utils/secureCredentials";
|
import { verifyAccountPIN } from "@/utils/secureCredentials";
|
||||||
|
|
||||||
interface TVPINEntryModalProps {
|
interface TVPINEntryModalProps {
|
||||||
@@ -130,15 +131,15 @@ const ForgotPINLink: React.FC<{
|
|||||||
<Animated.View
|
<Animated.View
|
||||||
style={{
|
style={{
|
||||||
transform: [{ scale }],
|
transform: [{ scale }],
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: scaleSize(16),
|
||||||
paddingVertical: 10,
|
paddingVertical: scaleSize(10),
|
||||||
borderRadius: 8,
|
borderRadius: scaleSize(8),
|
||||||
backgroundColor: focused ? "rgba(255,255,255,0.15)" : "transparent",
|
backgroundColor: focused ? "rgba(255,255,255,0.15)" : "transparent",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
color: focused ? "#fff" : "rgba(255,255,255,0.5)",
|
color: focused ? "#fff" : "rgba(255,255,255,0.5)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -417,36 +418,36 @@ const styles = StyleSheet.create({
|
|||||||
maxWidth: 400,
|
maxWidth: 400,
|
||||||
},
|
},
|
||||||
blurContainer: {
|
blurContainer: {
|
||||||
borderRadius: 24,
|
borderRadius: scaleSize(24),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
padding: 40,
|
padding: scaleSize(40),
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 28,
|
fontSize: scaleSize(28),
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
fontSize: 18,
|
fontSize: scaleSize(18),
|
||||||
color: "rgba(255,255,255,0.6)",
|
color: "rgba(255,255,255,0.6)",
|
||||||
marginBottom: 32,
|
marginBottom: scaleSize(32),
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
},
|
},
|
||||||
pinDotsContainer: {
|
pinDotsContainer: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
gap: 16,
|
gap: scaleSize(16),
|
||||||
marginBottom: 32,
|
marginBottom: scaleSize(32),
|
||||||
},
|
},
|
||||||
pinDot: {
|
pinDot: {
|
||||||
width: 20,
|
width: scaleSize(20),
|
||||||
height: 20,
|
height: scaleSize(20),
|
||||||
borderRadius: 10,
|
borderRadius: scaleSize(10),
|
||||||
borderWidth: 2,
|
borderWidth: scaleSize(2),
|
||||||
borderColor: "rgba(255,255,255,0.4)",
|
borderColor: "rgba(255,255,255,0.4)",
|
||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
},
|
},
|
||||||
@@ -459,26 +460,26 @@ const styles = StyleSheet.create({
|
|||||||
backgroundColor: "#ef4444",
|
backgroundColor: "#ef4444",
|
||||||
},
|
},
|
||||||
numberPad: {
|
numberPad: {
|
||||||
gap: 12,
|
gap: scaleSize(12),
|
||||||
marginBottom: 24,
|
marginBottom: scaleSize(24),
|
||||||
},
|
},
|
||||||
numberRow: {
|
numberRow: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
gap: 12,
|
gap: scaleSize(12),
|
||||||
},
|
},
|
||||||
numberButton: {
|
numberButton: {
|
||||||
width: 72,
|
width: scaleSize(72),
|
||||||
height: 72,
|
height: scaleSize(72),
|
||||||
borderRadius: 36,
|
borderRadius: scaleSize(36),
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
numberButtonPlaceholder: {
|
numberButtonPlaceholder: {
|
||||||
width: 72,
|
width: scaleSize(72),
|
||||||
height: 72,
|
height: scaleSize(72),
|
||||||
},
|
},
|
||||||
numberText: {
|
numberText: {
|
||||||
fontSize: 28,
|
fontSize: scaleSize(28),
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
},
|
},
|
||||||
forgotContainer: {
|
forgotContainer: {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useTVFocusAnimation } from "@/components/tv";
|
import { useTVFocusAnimation } from "@/components/tv";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
interface TVPasswordEntryModalProps {
|
interface TVPasswordEntryModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -51,14 +52,14 @@ const TVSubmitButton: React.FC<{
|
|||||||
: isDisabled
|
: isDisabled
|
||||||
? "#4a4a4a"
|
? "#4a4a4a"
|
||||||
: "rgba(255,255,255,0.15)",
|
: "rgba(255,255,255,0.15)",
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
paddingVertical: 14,
|
paddingVertical: scaleSize(14),
|
||||||
borderRadius: 10,
|
borderRadius: scaleSize(10),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
gap: 8,
|
gap: scaleSize(8),
|
||||||
minWidth: 120,
|
minWidth: scaleSize(120),
|
||||||
opacity: isDisabled ? 0.5 : 1,
|
opacity: isDisabled ? 0.5 : 1,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
@@ -69,12 +70,12 @@ const TVSubmitButton: React.FC<{
|
|||||||
<>
|
<>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='log-in-outline'
|
name='log-in-outline'
|
||||||
size={20}
|
size={scaleSize(20)}
|
||||||
color={focused ? "#000" : "#fff"}
|
color={focused ? "#000" : "#fff"}
|
||||||
/>
|
/>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
color: focused ? "#000" : "#fff",
|
color: focused ? "#000" : "#fff",
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
}}
|
}}
|
||||||
@@ -121,11 +122,11 @@ const TVPasswordInput: React.FC<{
|
|||||||
animatedStyle,
|
animatedStyle,
|
||||||
{
|
{
|
||||||
backgroundColor: "#1F2937",
|
backgroundColor: "#1F2937",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
borderWidth: 2,
|
borderWidth: scaleSize(2),
|
||||||
borderColor: focused ? "#fff" : "#374151",
|
borderColor: focused ? "#fff" : "#374151",
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: scaleSize(16),
|
||||||
paddingVertical: 14,
|
paddingVertical: scaleSize(14),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
@@ -140,7 +141,7 @@ const TVPasswordInput: React.FC<{
|
|||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
style={{
|
style={{
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
fontSize: 18,
|
fontSize: scaleSize(18),
|
||||||
}}
|
}}
|
||||||
onSubmitEditing={onSubmitEditing}
|
onSubmitEditing={onSubmitEditing}
|
||||||
returnKeyType='done'
|
returnKeyType='done'
|
||||||
@@ -299,45 +300,45 @@ const styles = StyleSheet.create({
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
blurContainer: {
|
blurContainer: {
|
||||||
borderTopLeftRadius: 24,
|
borderTopLeftRadius: scaleSize(24),
|
||||||
borderTopRightRadius: 24,
|
borderTopRightRadius: scaleSize(24),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
paddingTop: 24,
|
paddingTop: scaleSize(24),
|
||||||
paddingBottom: 50,
|
paddingBottom: scaleSize(50),
|
||||||
overflow: "visible",
|
overflow: "visible",
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
marginBottom: 24,
|
marginBottom: scaleSize(24),
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 28,
|
fontSize: scaleSize(28),
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
color: "rgba(255,255,255,0.6)",
|
color: "rgba(255,255,255,0.6)",
|
||||||
},
|
},
|
||||||
inputContainer: {
|
inputContainer: {
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
marginBottom: 20,
|
marginBottom: scaleSize(20),
|
||||||
},
|
},
|
||||||
inputLabel: {
|
inputLabel: {
|
||||||
fontSize: 14,
|
fontSize: scaleSize(14),
|
||||||
color: "rgba(255,255,255,0.6)",
|
color: "rgba(255,255,255,0.6)",
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
},
|
},
|
||||||
errorText: {
|
errorText: {
|
||||||
color: "#ef4444",
|
color: "#ef4444",
|
||||||
fontSize: 14,
|
fontSize: scaleSize(14),
|
||||||
marginTop: 8,
|
marginTop: scaleSize(8),
|
||||||
},
|
},
|
||||||
buttonContainer: {
|
buttonContainer: {
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
alignItems: "flex-start",
|
alignItems: "flex-start",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export const TVQRCodeDisplay: React.FC<TVQRCodeDisplayProps> = ({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingVertical: sectionPadding,
|
paddingVertical: sectionPadding,
|
||||||
paddingHorizontal: cardPadding,
|
paddingHorizontal: cardPadding,
|
||||||
borderRadius: 16,
|
borderRadius: scaleSize(16),
|
||||||
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -66,7 +66,7 @@ export const TVQRCodeDisplay: React.FC<TVQRCodeDisplayProps> = ({
|
|||||||
fontSize: typography.heading,
|
fontSize: typography.heading,
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("pairing.waiting_for_phone")}
|
{t("pairing.waiting_for_phone")}
|
||||||
@@ -75,7 +75,7 @@ export const TVQRCodeDisplay: React.FC<TVQRCodeDisplayProps> = ({
|
|||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
padding: cardPadding,
|
padding: cardPadding,
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { TVPinInput, type TVPinInputRef } from "@/components/inputs/TVPinInput";
|
import { TVPinInput, type TVPinInputRef } from "@/components/inputs/TVPinInput";
|
||||||
import { TVOptionCard, useTVFocusAnimation } from "@/components/tv";
|
import { TVOptionCard, useTVFocusAnimation } from "@/components/tv";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import type { AccountSecurityType } from "@/utils/secureCredentials";
|
import type { AccountSecurityType } from "@/utils/secureCredentials";
|
||||||
|
|
||||||
interface TVSaveAccountModalProps {
|
interface TVSaveAccountModalProps {
|
||||||
@@ -79,24 +80,24 @@ const TVSaveButton: React.FC<{
|
|||||||
: disabled
|
: disabled
|
||||||
? "#4a4a4a"
|
? "#4a4a4a"
|
||||||
: "rgba(255,255,255,0.15)",
|
: "rgba(255,255,255,0.15)",
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
paddingVertical: 14,
|
paddingVertical: scaleSize(14),
|
||||||
borderRadius: 10,
|
borderRadius: scaleSize(10),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: 8,
|
gap: scaleSize(8),
|
||||||
opacity: disabled ? 0.5 : 1,
|
opacity: disabled ? 0.5 : 1,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='checkmark'
|
name='checkmark'
|
||||||
size={20}
|
size={scaleSize(20)}
|
||||||
color={focused ? "#000" : "#fff"}
|
color={focused ? "#000" : "#fff"}
|
||||||
/>
|
/>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
color: focused ? "#000" : "#fff",
|
color: focused ? "#000" : "#fff",
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
}}
|
}}
|
||||||
@@ -129,23 +130,23 @@ const TVBackButton: React.FC<{
|
|||||||
animatedStyle,
|
animatedStyle,
|
||||||
{
|
{
|
||||||
backgroundColor: focused ? "#fff" : "rgba(255,255,255,0.15)",
|
backgroundColor: focused ? "#fff" : "rgba(255,255,255,0.15)",
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: scaleSize(20),
|
||||||
paddingVertical: 12,
|
paddingVertical: scaleSize(12),
|
||||||
borderRadius: 10,
|
borderRadius: scaleSize(10),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: 8,
|
gap: scaleSize(8),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='chevron-back'
|
name='chevron-back'
|
||||||
size={20}
|
size={scaleSize(20)}
|
||||||
color={focused ? "#000" : "rgba(255,255,255,0.8)"}
|
color={focused ? "#000" : "rgba(255,255,255,0.8)"}
|
||||||
/>
|
/>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
color: focused ? "#000" : "rgba(255,255,255,0.8)",
|
color: focused ? "#000" : "rgba(255,255,255,0.8)",
|
||||||
fontWeight: "500",
|
fontWeight: "500",
|
||||||
}}
|
}}
|
||||||
@@ -378,35 +379,35 @@ const styles = StyleSheet.create({
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
blurContainer: {
|
blurContainer: {
|
||||||
borderTopLeftRadius: 24,
|
borderTopLeftRadius: scaleSize(24),
|
||||||
borderTopRightRadius: 24,
|
borderTopRightRadius: scaleSize(24),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
paddingTop: 24,
|
paddingTop: scaleSize(24),
|
||||||
paddingBottom: 50,
|
paddingBottom: scaleSize(50),
|
||||||
overflow: "visible",
|
overflow: "visible",
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
marginBottom: 20,
|
marginBottom: scaleSize(20),
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 28,
|
fontSize: scaleSize(28),
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
color: "rgba(255,255,255,0.6)",
|
color: "rgba(255,255,255,0.6)",
|
||||||
},
|
},
|
||||||
sectionTitle: {
|
sectionTitle: {
|
||||||
fontSize: 16,
|
fontSize: scaleSize(16),
|
||||||
fontWeight: "500",
|
fontWeight: "500",
|
||||||
color: "rgba(255,255,255,0.6)",
|
color: "rgba(255,255,255,0.6)",
|
||||||
marginBottom: 16,
|
marginBottom: scaleSize(16),
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
},
|
},
|
||||||
@@ -414,26 +415,26 @@ const styles = StyleSheet.create({
|
|||||||
overflow: "visible",
|
overflow: "visible",
|
||||||
},
|
},
|
||||||
scrollContent: {
|
scrollContent: {
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
paddingVertical: 10,
|
paddingVertical: scaleSize(10),
|
||||||
gap: 12,
|
gap: scaleSize(12),
|
||||||
},
|
},
|
||||||
buttonRow: {
|
buttonRow: {
|
||||||
marginTop: 20,
|
marginTop: scaleSize(20),
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
gap: 16,
|
gap: scaleSize(16),
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
pinContainer: {
|
pinContainer: {
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
marginBottom: 10,
|
marginBottom: scaleSize(10),
|
||||||
},
|
},
|
||||||
errorText: {
|
errorText: {
|
||||||
color: "#ef4444",
|
color: "#ef4444",
|
||||||
fontSize: 14,
|
fontSize: scaleSize(14),
|
||||||
marginTop: 12,
|
marginTop: scaleSize(12),
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { Animated, Easing, Pressable, View } from "react-native";
|
import { Animated, Easing, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
interface TVSaveAccountToggleProps {
|
interface TVSaveAccountToggleProps {
|
||||||
value: boolean;
|
value: boolean;
|
||||||
@@ -74,9 +75,9 @@ export const TVSaveAccountToggle: React.FC<TVSaveAccountToggleProps> = ({
|
|||||||
backgroundColor: isFocused ? "#2a2a2a" : "#1a1a1a",
|
backgroundColor: isFocused ? "#2a2a2a" : "#1a1a1a",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
borderColor: isFocused ? "#FFFFFF" : "transparent",
|
borderColor: isFocused ? "#FFFFFF" : "transparent",
|
||||||
borderRadius: 16,
|
borderRadius: scaleSize(16),
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
paddingVertical: 20,
|
paddingVertical: scaleSize(20),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
@@ -84,7 +85,7 @@ export const TVSaveAccountToggle: React.FC<TVSaveAccountToggleProps> = ({
|
|||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 20,
|
fontSize: scaleSize(20),
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -93,19 +94,19 @@ export const TVSaveAccountToggle: React.FC<TVSaveAccountToggleProps> = ({
|
|||||||
<View
|
<View
|
||||||
pointerEvents='none'
|
pointerEvents='none'
|
||||||
style={{
|
style={{
|
||||||
width: 60,
|
width: scaleSize(60),
|
||||||
height: 34,
|
height: scaleSize(34),
|
||||||
borderRadius: 17,
|
borderRadius: scaleSize(17),
|
||||||
backgroundColor: value ? "#fff" : "#3f3f46",
|
backgroundColor: value ? "#fff" : "#3f3f46",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
paddingHorizontal: 3,
|
paddingHorizontal: scaleSize(3),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 28,
|
width: scaleSize(28),
|
||||||
height: 28,
|
height: scaleSize(28),
|
||||||
borderRadius: 14,
|
borderRadius: scaleSize(14),
|
||||||
backgroundColor: value ? "#000" : "#fff",
|
backgroundColor: value ? "#000" : "#fff",
|
||||||
alignSelf: value ? "flex-end" : "flex-start",
|
alignSelf: value ? "flex-end" : "flex-start",
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Animated, Pressable, View } from "react-native";
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
// Sci-fi gradient color pairs (from, to) - cyberpunk/neon vibes
|
// Sci-fi gradient color pairs (from, to) - cyberpunk/neon vibes
|
||||||
const SERVER_GRADIENTS: [string, string][] = [
|
const SERVER_GRADIENTS: [string, string][] = [
|
||||||
@@ -131,22 +132,22 @@ export const TVServerIcon = React.forwardRef<View, TVServerIconProps>(
|
|||||||
animatedStyle,
|
animatedStyle,
|
||||||
{
|
{
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
width: 160,
|
width: scaleSize(160),
|
||||||
shadowColor: gradientStart,
|
shadowColor: gradientStart,
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: focused ? 0.7 : 0,
|
shadowOpacity: focused ? 0.7 : 0,
|
||||||
shadowRadius: focused ? 24 : 0,
|
shadowRadius: focused ? scaleSize(24) : 0,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 140,
|
width: scaleSize(140),
|
||||||
height: 140,
|
height: scaleSize(140),
|
||||||
borderRadius: 70,
|
borderRadius: scaleSize(70),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
marginBottom: 14,
|
marginBottom: scaleSize(14),
|
||||||
borderWidth: focused ? 3 : 0,
|
borderWidth: focused ? scaleSize(3) : 0,
|
||||||
borderColor: "#fff",
|
borderColor: "#fff",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -164,7 +165,7 @@ export const TVServerIcon = React.forwardRef<View, TVServerIconProps>(
|
|||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: 48,
|
fontSize: scaleSize(48),
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
textShadowColor: "rgba(0,0,0,0.3)",
|
textShadowColor: "rgba(0,0,0,0.3)",
|
||||||
@@ -183,9 +184,9 @@ export const TVServerIcon = React.forwardRef<View, TVServerIconProps>(
|
|||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
color: focused ? "#fff" : "rgba(255,255,255,0.9)",
|
color: focused ? "#fff" : "rgba(255,255,255,0.9)",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
}}
|
}}
|
||||||
numberOfLines={2}
|
numberOfLines={3}
|
||||||
>
|
>
|
||||||
{displayName}
|
{displayName}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -199,7 +200,7 @@ export const TVServerIcon = React.forwardRef<View, TVServerIconProps>(
|
|||||||
: "rgba(255,255,255,0.5)",
|
: "rgba(255,255,255,0.5)",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
}}
|
}}
|
||||||
numberOfLines={1}
|
numberOfLines={3}
|
||||||
>
|
>
|
||||||
{address.replace(/^https?:\/\//, "")}
|
{address.replace(/^https?:\/\//, "")}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Alert, ScrollView, View } from "react-native";
|
|||||||
import { useMMKVString } from "react-native-mmkv";
|
import { useMMKVString } from "react-native-mmkv";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import type { SavedServer } from "@/utils/secureCredentials";
|
import type { SavedServer } from "@/utils/secureCredentials";
|
||||||
import { TVAddIcon } from "./TVAddIcon";
|
import { TVAddIcon } from "./TVAddIcon";
|
||||||
import { TVServerIcon } from "./TVServerIcon";
|
import { TVServerIcon } from "./TVServerIcon";
|
||||||
@@ -56,7 +57,7 @@ export const TVServerSelectionScreen: React.FC<
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingVertical: 60,
|
paddingVertical: scaleSize(60),
|
||||||
}}
|
}}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
@@ -64,14 +65,14 @@ export const TVServerSelectionScreen: React.FC<
|
|||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingHorizontal: 60,
|
paddingHorizontal: scaleSize(60),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<View style={{ alignItems: "center", marginBottom: 16 }}>
|
<View style={{ alignItems: "center", marginBottom: scaleSize(16) }}>
|
||||||
<Image
|
<Image
|
||||||
source={require("@/assets/images/icon-ios-plain.png")}
|
source={require("@/assets/images/icon-ios-plain.png")}
|
||||||
style={{ width: 150, height: 150 }}
|
style={{ width: scaleSize(150), height: scaleSize(150) }}
|
||||||
contentFit='contain'
|
contentFit='contain'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -83,7 +84,7 @@ export const TVServerSelectionScreen: React.FC<
|
|||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Streamyfin
|
Streamyfin
|
||||||
@@ -93,7 +94,7 @@ export const TVServerSelectionScreen: React.FC<
|
|||||||
fontSize: typography.body,
|
fontSize: typography.body,
|
||||||
color: "#9CA3AF",
|
color: "#9CA3AF",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginBottom: 48,
|
marginBottom: scaleSize(48),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{hasServers
|
{hasServers
|
||||||
@@ -106,8 +107,8 @@ export const TVServerSelectionScreen: React.FC<
|
|||||||
horizontal
|
horizontal
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
contentContainerStyle={{
|
contentContainerStyle={{
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: scaleSize(20),
|
||||||
gap: 24,
|
gap: scaleSize(24),
|
||||||
}}
|
}}
|
||||||
style={{ overflow: "visible" }}
|
style={{ overflow: "visible" }}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Text } from "@/components/common/Text";
|
|||||||
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
import { getUserImageUrl } from "@/utils/jellyfin/image/getUserImageUrl";
|
import { getUserImageUrl } from "@/utils/jellyfin/image/getUserImageUrl";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import type { AccountSecurityType } from "@/utils/secureCredentials";
|
import type { AccountSecurityType } from "@/utils/secureCredentials";
|
||||||
|
|
||||||
export interface TVUserIconProps {
|
export interface TVUserIconProps {
|
||||||
@@ -76,27 +77,27 @@ export const TVUserIcon = React.forwardRef<View, TVUserIconProps>(
|
|||||||
animatedStyle,
|
animatedStyle,
|
||||||
{
|
{
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
width: 160,
|
width: scaleSize(160),
|
||||||
overflow: "visible",
|
overflow: "visible",
|
||||||
shadowColor: "#fff",
|
shadowColor: "#fff",
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: focused ? 0.5 : 0,
|
shadowOpacity: focused ? 0.5 : 0,
|
||||||
shadowRadius: focused ? 16 : 0,
|
shadowRadius: focused ? scaleSize(16) : 0,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<View style={{ position: "relative" }}>
|
<View style={{ position: "relative" }}>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 140,
|
width: scaleSize(140),
|
||||||
height: 140,
|
height: scaleSize(140),
|
||||||
borderRadius: 70,
|
borderRadius: scaleSize(70),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "rgba(255,255,255,0.2)"
|
? "rgba(255,255,255,0.2)"
|
||||||
: "rgba(255,255,255,0.1)",
|
: "rgba(255,255,255,0.1)",
|
||||||
marginBottom: 14,
|
marginBottom: scaleSize(14),
|
||||||
borderWidth: focused ? 3 : 0,
|
borderWidth: focused ? scaleSize(3) : 0,
|
||||||
borderColor: "#fff",
|
borderColor: "#fff",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
@@ -105,14 +106,14 @@ export const TVUserIcon = React.forwardRef<View, TVUserIconProps>(
|
|||||||
{imageUrl ? (
|
{imageUrl ? (
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: imageUrl }}
|
source={{ uri: imageUrl }}
|
||||||
style={{ width: 140, height: 140 }}
|
style={{ width: scaleSize(140), height: scaleSize(140) }}
|
||||||
contentFit='cover'
|
contentFit='cover'
|
||||||
onError={() => setImageError(true)}
|
onError={() => setImageError(true)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='person'
|
name='person'
|
||||||
size={56}
|
size={scaleSize(56)}
|
||||||
color={
|
color={
|
||||||
focused ? "rgba(255,255,255,0.6)" : "rgba(255,255,255,0.4)"
|
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
|
<View
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
bottom: 10,
|
bottom: scaleSize(10),
|
||||||
right: 10,
|
right: scaleSize(10),
|
||||||
width: 32,
|
width: scaleSize(32),
|
||||||
height: 32,
|
height: scaleSize(32),
|
||||||
borderRadius: 16,
|
borderRadius: scaleSize(16),
|
||||||
backgroundColor: focused ? "#fff" : "rgba(255,255,255,0.9)",
|
backgroundColor: focused ? "#fff" : "rgba(255,255,255,0.9)",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
shadowColor: "#000",
|
shadowColor: "#000",
|
||||||
shadowOffset: { width: 0, height: 2 },
|
shadowOffset: { width: 0, height: scaleSize(2) },
|
||||||
shadowOpacity: 0.3,
|
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>
|
</View>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ScrollView, View } from "react-native";
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
import { useTVBackPress } from "@/hooks/useTVBackPress";
|
import { useTVBackPress } from "@/hooks/useTVBackPress";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import type {
|
import type {
|
||||||
SavedServer,
|
SavedServer,
|
||||||
SavedServerAccount,
|
SavedServerAccount,
|
||||||
@@ -47,7 +48,7 @@ export const TVUserSelectionScreen: React.FC<TVUserSelectionScreenProps> = ({
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingVertical: 60,
|
paddingVertical: scaleSize(60),
|
||||||
}}
|
}}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
@@ -55,18 +56,18 @@ export const TVUserSelectionScreen: React.FC<TVUserSelectionScreenProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingHorizontal: 60,
|
paddingHorizontal: scaleSize(60),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Server Info Header */}
|
{/* Server Info Header */}
|
||||||
<View style={{ marginBottom: 48, alignItems: "center" }}>
|
<View style={{ marginBottom: scaleSize(48), alignItems: "center" }}>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: typography.title,
|
fontSize: typography.title,
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{server.name || server.address}
|
{server.name || server.address}
|
||||||
@@ -87,7 +88,7 @@ export const TVUserSelectionScreen: React.FC<TVUserSelectionScreenProps> = ({
|
|||||||
fontSize: typography.body,
|
fontSize: typography.body,
|
||||||
color: "#6B7280",
|
color: "#6B7280",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginTop: 16,
|
marginTop: scaleSize(16),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{hasAccounts
|
{hasAccounts
|
||||||
@@ -101,8 +102,8 @@ export const TVUserSelectionScreen: React.FC<TVUserSelectionScreenProps> = ({
|
|||||||
horizontal
|
horizontal
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
contentContainerStyle={{
|
contentContainerStyle={{
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: scaleSize(20),
|
||||||
gap: 24,
|
gap: scaleSize(24),
|
||||||
}}
|
}}
|
||||||
style={{ overflow: "visible" }}
|
style={{ overflow: "visible" }}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVActorCardProps {
|
export interface TVActorCardProps {
|
||||||
@@ -40,23 +41,23 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
|
|||||||
animatedStyle,
|
animatedStyle,
|
||||||
{
|
{
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
width: 160,
|
width: scaleSize(160),
|
||||||
shadowColor: "#fff",
|
shadowColor: "#fff",
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: focused ? 0.5 : 0,
|
shadowOpacity: focused ? 0.5 : 0,
|
||||||
shadowRadius: focused ? 16 : 0,
|
shadowRadius: focused ? scaleSize(16) : 0,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 140,
|
width: scaleSize(140),
|
||||||
height: 140,
|
height: scaleSize(140),
|
||||||
borderRadius: 70,
|
borderRadius: scaleSize(70),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
backgroundColor: "rgba(255,255,255,0.1)",
|
backgroundColor: "rgba(255,255,255,0.1)",
|
||||||
marginBottom: 14,
|
marginBottom: scaleSize(14),
|
||||||
borderWidth: 2,
|
borderWidth: scaleSize(2),
|
||||||
borderColor: focused ? "#FFFFFF" : "transparent",
|
borderColor: focused ? "#FFFFFF" : "transparent",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -76,7 +77,7 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
|
|||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='person'
|
name='person'
|
||||||
size={56}
|
size={scaleSize(56)}
|
||||||
color='rgba(255,255,255,0.4)'
|
color='rgba(255,255,255,0.4)'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -89,9 +90,9 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
|
|||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
color: focused ? "#fff" : "rgba(255,255,255,0.9)",
|
color: focused ? "#fff" : "rgba(255,255,255,0.9)",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
}}
|
}}
|
||||||
numberOfLines={1}
|
numberOfLines={2}
|
||||||
>
|
>
|
||||||
{person.Name}
|
{person.Name}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -105,7 +106,7 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
|
|||||||
: "rgba(255,255,255,0.5)",
|
: "rgba(255,255,255,0.5)",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
}}
|
}}
|
||||||
numberOfLines={1}
|
numberOfLines={2}
|
||||||
>
|
>
|
||||||
{person.Role}
|
{person.Role}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Animated, Pressable, View, type ViewStyle } from "react-native";
|
import { Animated, Pressable, View, type ViewStyle } from "react-native";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVButtonProps {
|
export interface TVButtonProps {
|
||||||
@@ -98,13 +99,13 @@ export const TVButton: React.FC<TVButtonProps> = ({
|
|||||||
backgroundColor: buttonStyles.backgroundColor,
|
backgroundColor: buttonStyles.backgroundColor,
|
||||||
borderWidth: buttonStyles.borderWidth,
|
borderWidth: buttonStyles.borderWidth,
|
||||||
borderColor: buttonStyles.borderColor,
|
borderColor: buttonStyles.borderColor,
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
paddingVertical: 18,
|
paddingVertical: scaleSize(18),
|
||||||
paddingHorizontal: square ? 18 : 32,
|
paddingHorizontal: square ? scaleSize(18) : scaleSize(32),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
minWidth: square ? undefined : 180,
|
minWidth: square ? undefined : scaleSize(180),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable } from "react-native";
|
import { Animated, Pressable } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVCancelButtonProps {
|
export interface TVCancelButtonProps {
|
||||||
@@ -33,18 +34,18 @@ export const TVCancelButton: React.FC<TVCancelButtonProps> = ({
|
|||||||
animatedStyle,
|
animatedStyle,
|
||||||
{
|
{
|
||||||
backgroundColor: focused ? "#fff" : "rgba(255,255,255,0.15)",
|
backgroundColor: focused ? "#fff" : "rgba(255,255,255,0.15)",
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: scaleSize(20),
|
||||||
paddingVertical: 12,
|
paddingVertical: scaleSize(12),
|
||||||
borderRadius: 10,
|
borderRadius: scaleSize(10),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: 8,
|
gap: scaleSize(8),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='close'
|
name='close'
|
||||||
size={20}
|
size={scaleSize(20)}
|
||||||
color={focused ? "#000" : "rgba(255,255,255,0.8)"}
|
color={focused ? "#000" : "rgba(255,255,255,0.8)"}
|
||||||
/>
|
/>
|
||||||
<Text
|
<Text
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
export interface TVCastCrewTextProps {
|
export interface TVCastCrewTextProps {
|
||||||
director?: BaseItemPerson | null;
|
director?: BaseItemPerson | null;
|
||||||
@@ -22,18 +23,18 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ marginBottom: 32 }}>
|
<View style={{ marginBottom: scaleSize(32) }}>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: typography.heading,
|
fontSize: typography.heading,
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
marginBottom: 16,
|
marginBottom: scaleSize(16),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("item_card.cast_and_crew")}
|
{t("item_card.cast_and_crew")}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={{ flexDirection: "row", gap: 40 }}>
|
<View style={{ flexDirection: "row", gap: scaleSize(40) }}>
|
||||||
{director && (
|
{director && (
|
||||||
<View>
|
<View>
|
||||||
<Text
|
<Text
|
||||||
@@ -42,7 +43,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
|||||||
color: "#6B7280",
|
color: "#6B7280",
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("item_card.director")}
|
{t("item_card.director")}
|
||||||
@@ -60,7 +61,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
|||||||
color: "#6B7280",
|
color: "#6B7280",
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("item_card.cast")}
|
{t("item_card.cast")}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
StyleSheet,
|
StyleSheet,
|
||||||
type View,
|
type View,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVControlButtonProps {
|
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>
|
</RNAnimated.View>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
);
|
);
|
||||||
@@ -71,10 +72,10 @@ export const TVControlButton: FC<TVControlButtonProps> = ({
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
width: 64,
|
width: scaleSize(64),
|
||||||
height: 64,
|
height: scaleSize(64),
|
||||||
borderRadius: 32,
|
borderRadius: scaleSize(32),
|
||||||
borderWidth: 2,
|
borderWidth: scaleSize(2),
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVFilterButtonProps {
|
export interface TVFilterButtonProps {
|
||||||
@@ -42,13 +43,13 @@ export const TVFilterButton: React.FC<TVFilterButtonProps> = ({
|
|||||||
: hasActiveFilter
|
: hasActiveFilter
|
||||||
? "rgba(255, 255, 255, 0.25)"
|
? "rgba(255, 255, 255, 0.25)"
|
||||||
: "rgba(255,255,255,0.1)",
|
: "rgba(255,255,255,0.1)",
|
||||||
borderRadius: 10,
|
borderRadius: scaleSize(10),
|
||||||
paddingVertical: 10,
|
paddingVertical: scaleSize(10),
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: scaleSize(16),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: 8,
|
gap: scaleSize(8),
|
||||||
borderWidth: hasActiveFilter && !focused ? 1 : 0,
|
borderWidth: hasActiveFilter && !focused ? scaleSize(1) : 0,
|
||||||
borderColor: "rgba(255, 255, 255, 0.4)",
|
borderColor: "rgba(255, 255, 255, 0.4)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
} from "react-native";
|
} from "react-native";
|
||||||
import type { SharedValue } from "react-native-reanimated";
|
import type { SharedValue } from "react-native-reanimated";
|
||||||
import ReanimatedModule, { useAnimatedStyle } from "react-native-reanimated";
|
import ReanimatedModule, { useAnimatedStyle } from "react-native-reanimated";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
const ReanimatedView = ReanimatedModule.View;
|
const ReanimatedView = ReanimatedModule.View;
|
||||||
@@ -35,7 +36,7 @@ export interface TVFocusableProgressBarProps {
|
|||||||
style?: ViewStyle;
|
style?: ViewStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PROGRESS_BAR_HEIGHT = 14;
|
const PROGRESS_BAR_HEIGHT = scaleSize(14);
|
||||||
|
|
||||||
export const TVFocusableProgressBar: React.FC<TVFocusableProgressBarProps> =
|
export const TVFocusableProgressBar: React.FC<TVFocusableProgressBarProps> =
|
||||||
React.memo(
|
React.memo(
|
||||||
@@ -124,21 +125,21 @@ export const TVFocusableProgressBar: React.FC<TVFocusableProgressBarProps> =
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
pressableContainer: {
|
pressableContainer: {
|
||||||
// Add padding for focus scale animation to not clip
|
// Add padding for focus scale animation to not clip
|
||||||
paddingVertical: 8,
|
paddingVertical: scaleSize(8),
|
||||||
paddingHorizontal: 4,
|
paddingHorizontal: scaleSize(4),
|
||||||
},
|
},
|
||||||
animatedContainer: {
|
animatedContainer: {
|
||||||
height: PROGRESS_BAR_HEIGHT + 8,
|
height: PROGRESS_BAR_HEIGHT + scaleSize(8),
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
paddingHorizontal: 4,
|
paddingHorizontal: scaleSize(4),
|
||||||
},
|
},
|
||||||
animatedContainerFocused: {
|
animatedContainerFocused: {
|
||||||
// Subtle glow effect when focused
|
// Subtle glow effect when focused
|
||||||
shadowColor: "#fff",
|
shadowColor: "#fff",
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: 0.5,
|
shadowOpacity: 0.5,
|
||||||
shadowRadius: 12,
|
shadowRadius: scaleSize(12),
|
||||||
},
|
},
|
||||||
progressTrackWrapper: {
|
progressTrackWrapper: {
|
||||||
position: "relative",
|
position: "relative",
|
||||||
@@ -147,7 +148,7 @@ const styles = StyleSheet.create({
|
|||||||
progressTrack: {
|
progressTrack: {
|
||||||
height: PROGRESS_BAR_HEIGHT,
|
height: PROGRESS_BAR_HEIGHT,
|
||||||
backgroundColor: "rgba(255,255,255,0.2)",
|
backgroundColor: "rgba(255,255,255,0.2)",
|
||||||
borderRadius: 8,
|
borderRadius: scaleSize(8),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
progressTrackFocused: {
|
progressTrackFocused: {
|
||||||
@@ -160,7 +161,7 @@ const styles = StyleSheet.create({
|
|||||||
left: 0,
|
left: 0,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
backgroundColor: "rgba(255,255,255,0.3)",
|
backgroundColor: "rgba(255,255,255,0.3)",
|
||||||
borderRadius: 8,
|
borderRadius: scaleSize(8),
|
||||||
},
|
},
|
||||||
progressFill: {
|
progressFill: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@@ -168,7 +169,7 @@ const styles = StyleSheet.create({
|
|||||||
left: 0,
|
left: 0,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
backgroundColor: "#fff",
|
backgroundColor: "#fff",
|
||||||
borderRadius: 8,
|
borderRadius: scaleSize(8),
|
||||||
},
|
},
|
||||||
chapterMarkersContainer: {
|
chapterMarkersContainer: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@@ -179,11 +180,11 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
chapterMarker: {
|
chapterMarker: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
width: 2,
|
width: scaleSize(2),
|
||||||
height: PROGRESS_BAR_HEIGHT + 5,
|
height: PROGRESS_BAR_HEIGHT + scaleSize(5),
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
backgroundColor: "rgba(255, 255, 255, 0.6)",
|
backgroundColor: "rgba(255, 255, 255, 0.6)",
|
||||||
borderRadius: 1,
|
borderRadius: scaleSize(1),
|
||||||
transform: [{ translateX: -1 }],
|
transform: [{ translateX: -scaleSize(1) }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, StyleSheet, View } from "react-native";
|
import { Animated, Pressable, StyleSheet, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVLanguageCardProps {
|
export interface TVLanguageCardProps {
|
||||||
@@ -63,7 +64,7 @@ export const TVLanguageCard = React.forwardRef<View, TVLanguageCardProps>(
|
|||||||
<View style={styles.checkmark}>
|
<View style={styles.checkmark}>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='checkmark'
|
name='checkmark'
|
||||||
size={16}
|
size={scaleSize(16)}
|
||||||
color='rgba(255,255,255,0.8)'
|
color='rgba(255,255,255,0.8)'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -77,12 +78,12 @@ export const TVLanguageCard = React.forwardRef<View, TVLanguageCardProps>(
|
|||||||
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
||||||
StyleSheet.create({
|
StyleSheet.create({
|
||||||
languageCard: {
|
languageCard: {
|
||||||
width: 120,
|
width: scaleSize(120),
|
||||||
height: 60,
|
height: scaleSize(60),
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingHorizontal: 12,
|
paddingHorizontal: scaleSize(12),
|
||||||
},
|
},
|
||||||
languageCardText: {
|
languageCardText: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
@@ -94,7 +95,7 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
},
|
},
|
||||||
checkmark: {
|
checkmark: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 8,
|
top: scaleSize(8),
|
||||||
right: 8,
|
right: scaleSize(8),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { View } from "react-native";
|
|||||||
import { Badge } from "@/components/Badge";
|
import { Badge } from "@/components/Badge";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
export interface TVMetadataBadgesProps {
|
export interface TVMetadataBadgesProps {
|
||||||
year?: number | null;
|
year?: number | null;
|
||||||
@@ -22,8 +23,8 @@ export const TVMetadataBadges: React.FC<TVMetadataBadgesProps> = React.memo(
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
flexWrap: "wrap",
|
flexWrap: "wrap",
|
||||||
gap: 16,
|
gap: scaleSize(16),
|
||||||
marginBottom: 24,
|
marginBottom: scaleSize(24),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{year != null && (
|
{year != null && (
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import Animated, {
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl";
|
import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVNextEpisodeCountdownProps {
|
export interface TVNextEpisodeCountdownProps {
|
||||||
@@ -198,17 +199,17 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
StyleSheet.create({
|
StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
right: 80,
|
right: scaleSize(80),
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
},
|
},
|
||||||
focusedCard: {
|
focusedCard: {
|
||||||
shadowColor: "#fff",
|
shadowColor: "#fff",
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: 0.6,
|
shadowOpacity: 0.6,
|
||||||
shadowRadius: 16,
|
shadowRadius: scaleSize(16),
|
||||||
},
|
},
|
||||||
blur: {
|
blur: {
|
||||||
borderRadius: 16,
|
borderRadius: scaleSize(16),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
innerContainer: {
|
innerContainer: {
|
||||||
@@ -216,31 +217,31 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
alignItems: "stretch",
|
alignItems: "stretch",
|
||||||
},
|
},
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
width: 180,
|
width: scaleSize(180),
|
||||||
backgroundColor: "rgba(0,0,0,0.3)",
|
backgroundColor: "rgba(0,0,0,0.3)",
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
padding: 16,
|
padding: scaleSize(16),
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
width: 280,
|
width: scaleSize(280),
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
color: "rgba(255,255,255,0.5)",
|
color: "rgba(255,255,255,0.5)",
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
},
|
},
|
||||||
seriesName: {
|
seriesName: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
color: "rgba(255,255,255,0.7)",
|
color: "rgba(255,255,255,0.7)",
|
||||||
marginBottom: 2,
|
marginBottom: scaleSize(2),
|
||||||
},
|
},
|
||||||
episodeInfo: {
|
episodeInfo: {
|
||||||
fontSize: typography.body,
|
fontSize: typography.body,
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
marginBottom: 12,
|
marginBottom: scaleSize(12),
|
||||||
},
|
},
|
||||||
progressContainer: {
|
progressContainer: {
|
||||||
height: 4,
|
height: 4,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVOptionCardProps {
|
export interface TVOptionCardProps {
|
||||||
@@ -49,12 +50,14 @@ export const TVOptionCard = React.forwardRef<View, TVOptionCardProps>(
|
|||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "#fff"
|
? "#fff"
|
||||||
: selected
|
: selected
|
||||||
? "rgba(255,255,255,0.2)"
|
? "rgba(255,255,255,0.15)"
|
||||||
: "rgba(255,255,255,0.08)",
|
: "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",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingHorizontal: 12,
|
paddingHorizontal: scaleSize(12),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { TVCancelButton } from "./TVCancelButton";
|
import { TVCancelButton } from "./TVCancelButton";
|
||||||
import { TVOptionCard } from "./TVOptionCard";
|
import { TVOptionCard } from "./TVOptionCard";
|
||||||
|
|
||||||
@@ -170,21 +171,21 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
blurContainer: {
|
blurContainer: {
|
||||||
borderTopLeftRadius: 24,
|
borderTopLeftRadius: scaleSize(24),
|
||||||
borderTopRightRadius: 24,
|
borderTopRightRadius: scaleSize(24),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
paddingTop: 24,
|
paddingTop: scaleSize(24),
|
||||||
paddingBottom: 50,
|
paddingBottom: scaleSize(50),
|
||||||
overflow: "visible",
|
overflow: "visible",
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
fontWeight: "500",
|
fontWeight: "500",
|
||||||
color: "rgba(255,255,255,0.6)",
|
color: "rgba(255,255,255,0.6)",
|
||||||
marginBottom: 16,
|
marginBottom: scaleSize(16),
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
},
|
},
|
||||||
@@ -192,13 +193,13 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
overflow: "visible",
|
overflow: "visible",
|
||||||
},
|
},
|
||||||
scrollContent: {
|
scrollContent: {
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
paddingVertical: 20,
|
paddingVertical: scaleSize(20),
|
||||||
gap: 12,
|
gap: scaleSize(12),
|
||||||
},
|
},
|
||||||
cancelButtonContainer: {
|
cancelButtonContainer: {
|
||||||
marginTop: 16,
|
marginTop: scaleSize(16),
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
alignItems: "flex-start",
|
alignItems: "flex-start",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
GlassPosterView,
|
GlassPosterView,
|
||||||
isGlassEffectAvailable,
|
isGlassEffectAvailable,
|
||||||
} from "@/modules/glass-poster";
|
} from "@/modules/glass-poster";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
export interface TVSeriesSeasonCardProps {
|
export interface TVSeriesSeasonCardProps {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -66,10 +67,10 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
width: sizes.posters.poster,
|
width: sizes.posters.poster,
|
||||||
aspectRatio: 10 / 15,
|
aspectRatio: 10 / 15,
|
||||||
borderRadius: 24,
|
borderRadius: scaleSize(24),
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
backgroundColor: "rgba(255,255,255,0.1)",
|
backgroundColor: "rgba(255,255,255,0.1)",
|
||||||
borderWidth: 2,
|
borderWidth: scaleSize(2),
|
||||||
borderColor: focused ? "#FFFFFF" : "transparent",
|
borderColor: focused ? "#FFFFFF" : "transparent",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -87,7 +88,11 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
|
|||||||
alignItems: "center",
|
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>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
@@ -129,7 +134,7 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
|
|||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|
||||||
<View style={{ marginTop: 12 }}>
|
<View style={{ marginTop: scaleSize(12) }}>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: typography.body,
|
fontSize: typography.body,
|
||||||
@@ -145,7 +150,7 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
color: "#9CA3AF",
|
color: "#9CA3AF",
|
||||||
marginTop: 4,
|
marginTop: scaleSize(4),
|
||||||
}}
|
}}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import Animated, {
|
|||||||
withTiming,
|
withTiming,
|
||||||
} from "react-native-reanimated";
|
} from "react-native-reanimated";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVSkipSegmentCardProps {
|
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>
|
<Text style={styles.label}>{labelText}</Text>
|
||||||
</RNAnimated.View>
|
</RNAnimated.View>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
@@ -119,20 +120,20 @@ export const TVSkipSegmentCard: FC<TVSkipSegmentCardProps> = ({
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
right: 80,
|
right: scaleSize(80),
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingVertical: 10,
|
paddingVertical: scaleSize(10),
|
||||||
paddingHorizontal: 18,
|
paddingHorizontal: scaleSize(18),
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
borderWidth: 2,
|
borderWidth: scaleSize(2),
|
||||||
gap: 8,
|
gap: scaleSize(8),
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
fontSize: 20,
|
fontSize: scaleSize(20),
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
import type { SubtitleSearchResult } from "@/hooks/useRemoteSubtitles";
|
import type { SubtitleSearchResult } from "@/hooks/useRemoteSubtitles";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVSubtitleResultCardProps {
|
export interface TVSubtitleResultCardProps {
|
||||||
@@ -202,18 +203,18 @@ export const TVSubtitleResultCard = React.forwardRef<
|
|||||||
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
||||||
StyleSheet.create({
|
StyleSheet.create({
|
||||||
resultCard: {
|
resultCard: {
|
||||||
width: 220,
|
width: scaleSize(220),
|
||||||
minHeight: 120,
|
minHeight: scaleSize(120),
|
||||||
borderRadius: 14,
|
borderRadius: scaleSize(14),
|
||||||
padding: 14,
|
padding: scaleSize(14),
|
||||||
borderWidth: 1,
|
borderWidth: scaleSize(1),
|
||||||
},
|
},
|
||||||
providerBadge: {
|
providerBadge: {
|
||||||
alignSelf: "flex-start",
|
alignSelf: "flex-start",
|
||||||
paddingHorizontal: 8,
|
paddingHorizontal: scaleSize(8),
|
||||||
paddingVertical: 3,
|
paddingVertical: scaleSize(3),
|
||||||
borderRadius: 6,
|
borderRadius: scaleSize(6),
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
},
|
},
|
||||||
providerText: {
|
providerText: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
@@ -224,14 +225,14 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
resultName: {
|
resultName: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
fontWeight: "500",
|
fontWeight: "500",
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
lineHeight: 18,
|
lineHeight: scaleSize(18),
|
||||||
},
|
},
|
||||||
resultMeta: {
|
resultMeta: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: 12,
|
gap: scaleSize(12),
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
},
|
},
|
||||||
resultMetaText: {
|
resultMetaText: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
@@ -248,13 +249,13 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
},
|
},
|
||||||
flagsContainer: {
|
flagsContainer: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
gap: 6,
|
gap: scaleSize(6),
|
||||||
flexWrap: "wrap",
|
flexWrap: "wrap",
|
||||||
},
|
},
|
||||||
flag: {
|
flag: {
|
||||||
paddingHorizontal: 6,
|
paddingHorizontal: scaleSize(6),
|
||||||
paddingVertical: 2,
|
paddingVertical: scaleSize(2),
|
||||||
borderRadius: 4,
|
borderRadius: scaleSize(4),
|
||||||
},
|
},
|
||||||
flagText: {
|
flagText: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
@@ -264,7 +265,7 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
downloadingOverlay: {
|
downloadingOverlay: {
|
||||||
...StyleSheet.absoluteFillObject,
|
...StyleSheet.absoluteFillObject,
|
||||||
backgroundColor: "rgba(0,0,0,0.5)",
|
backgroundColor: "rgba(0,0,0,0.5)",
|
||||||
borderRadius: 14,
|
borderRadius: scaleSize(14),
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
export interface TVTechnicalDetailsProps {
|
export interface TVTechnicalDetailsProps {
|
||||||
mediaStreams: MediaStream[];
|
mediaStreams: MediaStream[];
|
||||||
@@ -22,18 +23,18 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ marginBottom: 32 }}>
|
<View style={{ marginBottom: scaleSize(32) }}>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
fontSize: typography.heading,
|
fontSize: typography.heading,
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
marginBottom: 20,
|
marginBottom: scaleSize(20),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("item_card.technical_details")}
|
{t("item_card.technical_details")}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={{ flexDirection: "row", gap: 40 }}>
|
<View style={{ flexDirection: "row", gap: scaleSize(40) }}>
|
||||||
{videoStream && (
|
{videoStream && (
|
||||||
<View>
|
<View>
|
||||||
<Text
|
<Text
|
||||||
@@ -42,7 +43,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
|||||||
color: "#6B7280",
|
color: "#6B7280",
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("common.video")}
|
{t("common.video")}
|
||||||
@@ -61,7 +62,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
|||||||
color: "#6B7280",
|
color: "#6B7280",
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
marginBottom: 4,
|
marginBottom: scaleSize(4),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("common.audio")}
|
{t("common.audio")}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
|
|||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { Animated, Easing, Pressable, View } from "react-native";
|
import { Animated, Easing, Pressable, View } from "react-native";
|
||||||
import { AnimatedEqualizer } from "@/components/music/AnimatedEqualizer";
|
import { AnimatedEqualizer } from "@/components/music/AnimatedEqualizer";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
|
|
||||||
interface TVThemeMusicIndicatorProps {
|
interface TVThemeMusicIndicatorProps {
|
||||||
isPlaying: boolean;
|
isPlaying: boolean;
|
||||||
@@ -51,16 +52,16 @@ export const TVThemeMusicIndicator: React.FC<TVThemeMusicIndicatorProps> = ({
|
|||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "rgba(255,255,255,0.25)"
|
? "rgba(255,255,255,0.25)"
|
||||||
: "rgba(255,255,255,0.1)",
|
: "rgba(255,255,255,0.1)",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
padding: 12,
|
padding: scaleSize(12),
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
width: 48,
|
width: scaleSize(48),
|
||||||
height: 48,
|
height: scaleSize(48),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isMuted ? (
|
{isMuted ? (
|
||||||
<Ionicons name='volume-mute' size={22} color='#FFFFFF' />
|
<Ionicons name='volume-mute' size={scaleSize(22)} color='#FFFFFF' />
|
||||||
) : (
|
) : (
|
||||||
<View style={{ marginRight: 0 }}>
|
<View style={{ marginRight: 0 }}>
|
||||||
<AnimatedEqualizer
|
<AnimatedEqualizer
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, StyleSheet, View } from "react-native";
|
import { Animated, Pressable, StyleSheet, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVTrackCardProps {
|
export interface TVTrackCardProps {
|
||||||
@@ -68,7 +69,7 @@ export const TVTrackCard = React.forwardRef<View, TVTrackCardProps>(
|
|||||||
<View style={styles.checkmark}>
|
<View style={styles.checkmark}>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='checkmark'
|
name='checkmark'
|
||||||
size={16}
|
size={scaleSize(16)}
|
||||||
color='rgba(255,255,255,0.8)'
|
color='rgba(255,255,255,0.8)'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -82,12 +83,12 @@ export const TVTrackCard = React.forwardRef<View, TVTrackCardProps>(
|
|||||||
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
||||||
StyleSheet.create({
|
StyleSheet.create({
|
||||||
trackCard: {
|
trackCard: {
|
||||||
width: 180,
|
width: scaleSize(180),
|
||||||
height: 80,
|
height: scaleSize(80),
|
||||||
borderRadius: 14,
|
borderRadius: scaleSize(14),
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
paddingHorizontal: 12,
|
paddingHorizontal: scaleSize(12),
|
||||||
},
|
},
|
||||||
trackCardText: {
|
trackCardText: {
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
@@ -99,7 +100,7 @@ const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
|||||||
},
|
},
|
||||||
checkmark: {
|
checkmark: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 8,
|
top: scaleSize(8),
|
||||||
right: 8,
|
right: scaleSize(8),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import type { AccountSecurityType } from "@/utils/secureCredentials";
|
import type { AccountSecurityType } from "@/utils/secureCredentials";
|
||||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
@@ -89,29 +90,33 @@ export const TVUserCard = React.forwardRef<View, TVUserCardProps>(
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: getBackgroundColor(),
|
backgroundColor: getBackgroundColor(),
|
||||||
borderRadius: 14,
|
borderRadius: scaleSize(14),
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: scaleSize(16),
|
||||||
paddingVertical: 14,
|
paddingVertical: scaleSize(14),
|
||||||
gap: 14,
|
gap: scaleSize(14),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{/* User Avatar */}
|
{/* User Avatar */}
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 44,
|
width: scaleSize(44),
|
||||||
height: 44,
|
height: scaleSize(44),
|
||||||
backgroundColor: isCurrent
|
backgroundColor: isCurrent
|
||||||
? "rgba(255,255,255,0.08)"
|
? "rgba(255,255,255,0.08)"
|
||||||
: focused
|
: focused
|
||||||
? "rgba(0,0,0,0.1)"
|
? "rgba(0,0,0,0.1)"
|
||||||
: "rgba(255,255,255,0.15)",
|
: "rgba(255,255,255,0.15)",
|
||||||
borderRadius: 22,
|
borderRadius: scaleSize(22),
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Ionicons name='person' size={24} color={getTextColor()} />
|
<Ionicons
|
||||||
|
name='person'
|
||||||
|
size={scaleSize(24)}
|
||||||
|
color={getTextColor()}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Text column */}
|
{/* Text column */}
|
||||||
@@ -153,7 +158,7 @@ export const TVUserCard = React.forwardRef<View, TVUserCardProps>(
|
|||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name={getSecurityIcon()}
|
name={getSecurityIcon()}
|
||||||
size={12}
|
size={scaleSize(12)}
|
||||||
color={getSecondaryColor()}
|
color={getSecondaryColor()}
|
||||||
/>
|
/>
|
||||||
<Text
|
<Text
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVLogoutButtonProps {
|
export interface TVLogoutButtonProps {
|
||||||
@@ -41,9 +42,9 @@ export const TVLogoutButton: React.FC<TVLogoutButtonProps> = ({
|
|||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: focused ? "#ef4444" : "rgba(239, 68, 68, 0.8)",
|
backgroundColor: focused ? "#ef4444" : "rgba(239, 68, 68, 0.8)",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
paddingVertical: 18,
|
paddingVertical: scaleSize(18),
|
||||||
paddingHorizontal: 48,
|
paddingHorizontal: scaleSize(48),
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVSettingsOptionButtonProps {
|
export interface TVSettingsOptionButtonProps {
|
||||||
@@ -40,10 +41,10 @@ export const TVSettingsOptionButton: React.FC<TVSettingsOptionButtonProps> = ({
|
|||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "rgba(255, 255, 255, 0.15)"
|
? "rgba(255, 255, 255, 0.15)"
|
||||||
: "rgba(255, 255, 255, 0.05)",
|
: "rgba(255, 255, 255, 0.05)",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
paddingVertical: 16,
|
paddingVertical: scaleSize(16),
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
@@ -59,12 +60,16 @@ export const TVSettingsOptionButton: React.FC<TVSettingsOptionButtonProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
color: "#9CA3AF",
|
color: "#9CA3AF",
|
||||||
marginRight: 12,
|
marginRight: scaleSize(12),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</Text>
|
</Text>
|
||||||
<Ionicons name='chevron-forward' size={20} color='#6B7280' />
|
<Ionicons
|
||||||
|
name='chevron-forward'
|
||||||
|
size={scaleSize(20)}
|
||||||
|
color='#6B7280'
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVSettingsRowProps {
|
export interface TVSettingsRowProps {
|
||||||
@@ -42,10 +43,10 @@ export const TVSettingsRow: React.FC<TVSettingsRowProps> = ({
|
|||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "rgba(255, 255, 255, 0.15)"
|
? "rgba(255, 255, 255, 0.15)"
|
||||||
: "rgba(255, 255, 255, 0.05)",
|
: "rgba(255, 255, 255, 0.05)",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
paddingVertical: 16,
|
paddingVertical: scaleSize(16),
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
@@ -60,13 +61,17 @@ export const TVSettingsRow: React.FC<TVSettingsRowProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
color: "#9CA3AF",
|
color: "#9CA3AF",
|
||||||
marginRight: showChevron ? 12 : 0,
|
marginRight: showChevron ? scaleSize(12) : 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</Text>
|
</Text>
|
||||||
{showChevron && (
|
{showChevron && (
|
||||||
<Ionicons name='chevron-forward' size={20} color='#6B7280' />
|
<Ionicons
|
||||||
|
name='chevron-forward'
|
||||||
|
size={scaleSize(20)}
|
||||||
|
color='#6B7280'
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVSettingsStepperProps {
|
export interface TVSettingsStepperProps {
|
||||||
@@ -38,10 +39,10 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
|||||||
labelAnim.focused || minusAnim.focused || plusAnim.focused
|
labelAnim.focused || minusAnim.focused || plusAnim.focused
|
||||||
? "rgba(255, 255, 255, 0.15)"
|
? "rgba(255, 255, 255, 0.15)"
|
||||||
: "rgba(255, 255, 255, 0.05)",
|
: "rgba(255, 255, 255, 0.05)",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
paddingVertical: 16,
|
paddingVertical: scaleSize(16),
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
@@ -72,9 +73,9 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
|||||||
style={[
|
style={[
|
||||||
minusAnim.animatedStyle,
|
minusAnim.animatedStyle,
|
||||||
{
|
{
|
||||||
width: 40,
|
width: scaleSize(40),
|
||||||
height: 40,
|
height: scaleSize(40),
|
||||||
borderRadius: 10,
|
borderRadius: scaleSize(10),
|
||||||
backgroundColor: minusAnim.focused ? "#FFFFFF" : "#4B5563",
|
backgroundColor: minusAnim.focused ? "#FFFFFF" : "#4B5563",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
@@ -83,7 +84,7 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
|||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='remove'
|
name='remove'
|
||||||
size={24}
|
size={scaleSize(24)}
|
||||||
color={minusAnim.focused ? "#000000" : "#FFFFFF"}
|
color={minusAnim.focused ? "#000000" : "#FFFFFF"}
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
@@ -92,9 +93,9 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
minWidth: 60,
|
minWidth: scaleSize(60),
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
marginHorizontal: 16,
|
marginHorizontal: scaleSize(16),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{displayValue}
|
{displayValue}
|
||||||
@@ -110,9 +111,9 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
|||||||
style={[
|
style={[
|
||||||
plusAnim.animatedStyle,
|
plusAnim.animatedStyle,
|
||||||
{
|
{
|
||||||
width: 40,
|
width: scaleSize(40),
|
||||||
height: 40,
|
height: scaleSize(40),
|
||||||
borderRadius: 10,
|
borderRadius: scaleSize(10),
|
||||||
backgroundColor: plusAnim.focused ? "#FFFFFF" : "#4B5563",
|
backgroundColor: plusAnim.focused ? "#FFFFFF" : "#4B5563",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
@@ -121,7 +122,7 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
|||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name='add'
|
name='add'
|
||||||
size={24}
|
size={scaleSize(24)}
|
||||||
color={plusAnim.focused ? "#000000" : "#FFFFFF"}
|
color={plusAnim.focused ? "#000000" : "#FFFFFF"}
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useRef } from "react";
|
|||||||
import { Animated, Pressable, TextInput } from "react-native";
|
import { Animated, Pressable, TextInput } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVSettingsTextInputProps {
|
export interface TVSettingsTextInputProps {
|
||||||
@@ -48,10 +49,10 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
|
|||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "rgba(255, 255, 255, 0.15)"
|
? "rgba(255, 255, 255, 0.15)"
|
||||||
: "rgba(255, 255, 255, 0.05)",
|
: "rgba(255, 255, 255, 0.05)",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
paddingVertical: 16,
|
paddingVertical: scaleSize(16),
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
@@ -59,7 +60,7 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
fontSize: typography.callout,
|
fontSize: typography.callout,
|
||||||
color: "#9CA3AF",
|
color: "#9CA3AF",
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
@@ -78,10 +79,10 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
|
|||||||
fontSize: typography.body,
|
fontSize: typography.body,
|
||||||
color: "#FFFFFF",
|
color: "#FFFFFF",
|
||||||
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
||||||
borderRadius: 8,
|
borderRadius: scaleSize(8),
|
||||||
paddingVertical: 12,
|
paddingVertical: scaleSize(12),
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: scaleSize(16),
|
||||||
borderWidth: focused ? 2 : 1,
|
borderWidth: focused ? scaleSize(2) : scaleSize(1),
|
||||||
borderColor: focused ? "#FFFFFF" : "#4B5563",
|
borderColor: focused ? "#FFFFFF" : "#4B5563",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import { Animated, Pressable, View } from "react-native";
|
import { Animated, Pressable, View } from "react-native";
|
||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||||
|
import { scaleSize } from "@/utils/scaleSize";
|
||||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||||
|
|
||||||
export interface TVSettingsToggleProps {
|
export interface TVSettingsToggleProps {
|
||||||
@@ -39,10 +40,10 @@ export const TVSettingsToggle: React.FC<TVSettingsToggleProps> = ({
|
|||||||
backgroundColor: focused
|
backgroundColor: focused
|
||||||
? "rgba(255, 255, 255, 0.15)"
|
? "rgba(255, 255, 255, 0.15)"
|
||||||
: "rgba(255, 255, 255, 0.05)",
|
: "rgba(255, 255, 255, 0.05)",
|
||||||
borderRadius: 12,
|
borderRadius: scaleSize(12),
|
||||||
paddingVertical: 16,
|
paddingVertical: scaleSize(16),
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: scaleSize(24),
|
||||||
marginBottom: 8,
|
marginBottom: scaleSize(8),
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
@@ -54,19 +55,19 @@ export const TVSettingsToggle: React.FC<TVSettingsToggleProps> = ({
|
|||||||
</Text>
|
</Text>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 56,
|
width: scaleSize(56),
|
||||||
height: 32,
|
height: scaleSize(32),
|
||||||
borderRadius: 16,
|
borderRadius: scaleSize(16),
|
||||||
backgroundColor: value ? "#FFFFFF" : "#4B5563",
|
backgroundColor: value ? "#FFFFFF" : "#4B5563",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
paddingHorizontal: 2,
|
paddingHorizontal: scaleSize(2),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 28,
|
width: scaleSize(28),
|
||||||
height: 28,
|
height: scaleSize(28),
|
||||||
borderRadius: 14,
|
borderRadius: scaleSize(14),
|
||||||
backgroundColor: value ? "#000000" : "#FFFFFF",
|
backgroundColor: value ? "#000000" : "#FFFFFF",
|
||||||
alignSelf: value ? "flex-end" : "flex-start",
|
alignSelf: value ? "flex-end" : "flex-start",
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export const TVAnimation = {
|
|||||||
* Applied to poster sizes and gaps.
|
* Applied to poster sizes and gaps.
|
||||||
*/
|
*/
|
||||||
const sizeScaleMultipliers: Record<TVTypographyScale, number> = {
|
const sizeScaleMultipliers: Record<TVTypographyScale, number> = {
|
||||||
[TVTypographyScale.Small]: 0.8,
|
[TVTypographyScale.Small]: 0.9,
|
||||||
[TVTypographyScale.Default]: 1.0,
|
[TVTypographyScale.Default]: 1.0,
|
||||||
[TVTypographyScale.Large]: 1.1,
|
[TVTypographyScale.Large]: 1.1,
|
||||||
[TVTypographyScale.ExtraLarge]: 1.2,
|
[TVTypographyScale.ExtraLarge]: 1.2,
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ export type TVTypographyKey = keyof typeof TVTypography;
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
const scaleMultipliers: Record<TVTypographyScale, number> = {
|
const scaleMultipliers: Record<TVTypographyScale, number> = {
|
||||||
[TVTypographyScale.Small]: 0.8,
|
[TVTypographyScale.Small]: 0.85,
|
||||||
[TVTypographyScale.Default]: 1.0,
|
[TVTypographyScale.Default]: 1.0,
|
||||||
[TVTypographyScale.Large]: 1.1,
|
[TVTypographyScale.Large]: 1.2,
|
||||||
[TVTypographyScale.ExtraLarge]: 1.2,
|
[TVTypographyScale.ExtraLarge]: 1.4,
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ internal object TvRecommendationsPublisher {
|
|||||||
|
|
||||||
imageUrl.takeIf { it.isNotBlank() }?.let {
|
imageUrl.takeIf { it.isNotBlank() }?.let {
|
||||||
val imageUri = Uri.parse(it)
|
val imageUri = Uri.parse(it)
|
||||||
|
builder.setPosterArtUri(imageUri)
|
||||||
builder.setThumbnailUri(imageUri)
|
builder.setThumbnailUri(imageUri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
40
plugins/withAndroidAlertColors.js
Normal file
40
plugins/withAndroidAlertColors.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
const {
|
||||||
|
withAndroidColors,
|
||||||
|
withAndroidColorsNight,
|
||||||
|
} = require("expo/config-plugins");
|
||||||
|
|
||||||
|
const withAndroidAlertColors = (config) => {
|
||||||
|
const setColor = (colorsList, name, value) => {
|
||||||
|
const existingColor = colorsList.find(
|
||||||
|
(item) => item.$ && item.$.name === name,
|
||||||
|
);
|
||||||
|
if (existingColor) {
|
||||||
|
existingColor._ = value;
|
||||||
|
} else {
|
||||||
|
colorsList.push({
|
||||||
|
$: { name },
|
||||||
|
_: value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
config = withAndroidColors(config, (config) => {
|
||||||
|
const colors = config.modResults;
|
||||||
|
const colorsList = colors.resources.color || [];
|
||||||
|
setColor(colorsList, "colorPrimary", "#000000");
|
||||||
|
colors.resources.color = colorsList;
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
|
config = withAndroidColorsNight(config, (config) => {
|
||||||
|
const colors = config.modResults;
|
||||||
|
const colorsList = colors.resources.color || [];
|
||||||
|
setColor(colorsList, "colorPrimary", "#FFFFFF");
|
||||||
|
colors.resources.color = colorsList;
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = withAndroidAlertColors;
|
||||||
Reference in New Issue
Block a user