mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-04-29 20:06:29 +01:00
feat(tv): add scalable typography with user-configurable text size
This commit is contained in:
@@ -3,7 +3,7 @@ import { Image } from "expo-image";
|
||||
import React from "react";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVActorCardProps {
|
||||
@@ -19,6 +19,7 @@ export interface TVActorCardProps {
|
||||
|
||||
export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
|
||||
({ person, apiBasePath, onPress, hasTVPreferredFocus }, ref) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.08 });
|
||||
|
||||
@@ -84,7 +85,7 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
|
||||
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.body,
|
||||
fontSize: typography.body,
|
||||
fontWeight: "600",
|
||||
color: focused ? "#fff" : "rgba(255,255,255,0.9)",
|
||||
textAlign: "center",
|
||||
@@ -98,7 +99,7 @@ export const TVActorCard = React.forwardRef<View, TVActorCardProps>(
|
||||
{person.Role && (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: focused
|
||||
? "rgba(255,255,255,0.8)"
|
||||
: "rgba(255,255,255,0.5)",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
|
||||
import React from "react";
|
||||
import { Animated, Pressable } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVCancelButtonProps {
|
||||
@@ -16,6 +16,7 @@ export const TVCancelButton: React.FC<TVCancelButtonProps> = ({
|
||||
label = "Cancel",
|
||||
disabled = false,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.05, duration: 120 });
|
||||
|
||||
@@ -48,7 +49,7 @@ export const TVCancelButton: React.FC<TVCancelButtonProps> = ({
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: focused ? "#000" : "rgba(255,255,255,0.8)",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
|
||||
export interface TVCastCrewTextProps {
|
||||
director?: BaseItemPerson | null;
|
||||
@@ -14,6 +14,7 @@ export interface TVCastCrewTextProps {
|
||||
|
||||
export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
||||
({ director, cast, hideCast = false }) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!director && (!cast || cast.length === 0)) {
|
||||
@@ -24,7 +25,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
||||
<View style={{ marginBottom: 32 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.heading,
|
||||
fontSize: typography.heading,
|
||||
fontWeight: "600",
|
||||
color: "#FFFFFF",
|
||||
marginBottom: 16,
|
||||
@@ -37,7 +38,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#6B7280",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
@@ -46,7 +47,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
||||
>
|
||||
{t("item_card.director")}
|
||||
</Text>
|
||||
<Text style={{ fontSize: TVTypography.body, color: "#FFFFFF" }}>
|
||||
<Text style={{ fontSize: typography.body, color: "#FFFFFF" }}>
|
||||
{director.Name}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -55,7 +56,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#6B7280",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
@@ -64,7 +65,7 @@ export const TVCastCrewText: React.FC<TVCastCrewTextProps> = React.memo(
|
||||
>
|
||||
{t("item_card.cast")}
|
||||
</Text>
|
||||
<Text style={{ fontSize: TVTypography.body, color: "#FFFFFF" }}>
|
||||
<Text style={{ fontSize: typography.body, color: "#FFFFFF" }}>
|
||||
{cast.map((c) => c.Name).join(", ")}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ScrollView, TVFocusGuideView, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { TVActorCard } from "./TVActorCard";
|
||||
|
||||
export interface TVCastSectionProps {
|
||||
@@ -24,6 +24,7 @@ export const TVCastSection: React.FC<TVCastSectionProps> = React.memo(
|
||||
firstActorRefSetter,
|
||||
upwardFocusDestination,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (cast.length === 0) {
|
||||
@@ -34,7 +35,7 @@ export const TVCastSection: React.FC<TVCastSectionProps> = React.memo(
|
||||
<View style={{ marginBottom: 40 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.heading,
|
||||
fontSize: typography.heading,
|
||||
fontWeight: "600",
|
||||
color: "#FFFFFF",
|
||||
marginBottom: 24,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVFilterButtonProps {
|
||||
@@ -21,6 +21,7 @@ export const TVFilterButton: React.FC<TVFilterButtonProps> = ({
|
||||
disabled = false,
|
||||
hasActiveFilter = false,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.04, duration: 120 });
|
||||
|
||||
@@ -54,7 +55,7 @@ export const TVFilterButton: React.FC<TVFilterButtonProps> = ({
|
||||
{label ? (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: focused ? "#444" : "#bbb",
|
||||
}}
|
||||
>
|
||||
@@ -63,7 +64,7 @@ export const TVFilterButton: React.FC<TVFilterButtonProps> = ({
|
||||
) : null}
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: focused ? "#000" : "#FFFFFF",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
|
||||
@@ -2,28 +2,32 @@ import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
|
||||
export interface TVItemCardTextProps {
|
||||
item: BaseItemDto;
|
||||
}
|
||||
|
||||
export const TVItemCardText: React.FC<TVItemCardTextProps> = ({ item }) => (
|
||||
<View style={{ marginTop: 12 }}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{ fontSize: TVTypography.callout, color: "#FFFFFF" }}
|
||||
>
|
||||
{item.Name}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout - 2,
|
||||
color: "#9CA3AF",
|
||||
marginTop: 2,
|
||||
}}
|
||||
>
|
||||
{item.ProductionYear}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
export const TVItemCardText: React.FC<TVItemCardTextProps> = ({ item }) => {
|
||||
const typography = useScaledTVTypography();
|
||||
|
||||
return (
|
||||
<View style={{ marginTop: 12 }}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{ fontSize: typography.callout, color: "#FFFFFF" }}
|
||||
>
|
||||
{item.Name}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: typography.callout - 2,
|
||||
color: "#9CA3AF",
|
||||
marginTop: 2,
|
||||
}}
|
||||
>
|
||||
{item.ProductionYear}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
|
||||
import React from "react";
|
||||
import { Animated, Pressable, StyleSheet, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVLanguageCardProps {
|
||||
@@ -15,6 +15,8 @@ export interface TVLanguageCardProps {
|
||||
|
||||
export const TVLanguageCard = React.forwardRef<View, TVLanguageCardProps>(
|
||||
({ code, name, selected, hasTVPreferredFocus, onPress }, ref) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const styles = createStyles(typography);
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.05 });
|
||||
|
||||
@@ -72,26 +74,27 @@ export const TVLanguageCard = React.forwardRef<View, TVLanguageCardProps>(
|
||||
},
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
languageCard: {
|
||||
width: 120,
|
||||
height: 60,
|
||||
borderRadius: 12,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
languageCardText: {
|
||||
fontSize: TVTypography.callout,
|
||||
fontWeight: "500",
|
||||
},
|
||||
languageCardCode: {
|
||||
fontSize: TVTypography.callout,
|
||||
marginTop: 2,
|
||||
},
|
||||
checkmark: {
|
||||
position: "absolute",
|
||||
top: 8,
|
||||
right: 8,
|
||||
},
|
||||
});
|
||||
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
||||
StyleSheet.create({
|
||||
languageCard: {
|
||||
width: 120,
|
||||
height: 60,
|
||||
borderRadius: 12,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
languageCardText: {
|
||||
fontSize: typography.callout,
|
||||
fontWeight: "500",
|
||||
},
|
||||
languageCardCode: {
|
||||
fontSize: typography.callout,
|
||||
marginTop: 2,
|
||||
},
|
||||
checkmark: {
|
||||
position: "absolute",
|
||||
top: 8,
|
||||
right: 8,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { Badge } from "@/components/Badge";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
|
||||
export interface TVMetadataBadgesProps {
|
||||
year?: number | null;
|
||||
@@ -14,6 +14,8 @@ export interface TVMetadataBadgesProps {
|
||||
|
||||
export const TVMetadataBadges: React.FC<TVMetadataBadgesProps> = React.memo(
|
||||
({ year, duration, officialRating, communityRating }) => {
|
||||
const typography = useScaledTVTypography();
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
@@ -25,12 +27,12 @@ export const TVMetadataBadges: React.FC<TVMetadataBadgesProps> = React.memo(
|
||||
}}
|
||||
>
|
||||
{year != null && (
|
||||
<Text style={{ color: "white", fontSize: TVTypography.body }}>
|
||||
<Text style={{ color: "white", fontSize: typography.body }}>
|
||||
{year}
|
||||
</Text>
|
||||
)}
|
||||
{duration && (
|
||||
<Text style={{ color: "white", fontSize: TVTypography.body }}>
|
||||
<Text style={{ color: "white", fontSize: typography.body }}>
|
||||
{duration}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Api } from "@jellyfin/sdk";
|
||||
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
||||
import { BlurView } from "expo-blur";
|
||||
import { type FC, useEffect, useRef } from "react";
|
||||
import { type FC, useEffect, useMemo, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Image, StyleSheet, View } from "react-native";
|
||||
import Animated, {
|
||||
@@ -13,7 +13,7 @@ import Animated, {
|
||||
withTiming,
|
||||
} from "react-native-reanimated";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl";
|
||||
|
||||
export interface TVNextEpisodeCountdownProps {
|
||||
@@ -31,6 +31,7 @@ export const TVNextEpisodeCountdown: FC<TVNextEpisodeCountdownProps> = ({
|
||||
isPlaying,
|
||||
onFinish,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { t } = useTranslation();
|
||||
const progress = useSharedValue(0);
|
||||
const onFinishRef = useRef(onFinish);
|
||||
@@ -69,6 +70,8 @@ export const TVNextEpisodeCountdown: FC<TVNextEpisodeCountdownProps> = ({
|
||||
width: `${progress.value * 100}%`,
|
||||
}));
|
||||
|
||||
const styles = useMemo(() => createStyles(typography), [typography]);
|
||||
|
||||
if (!show) return null;
|
||||
|
||||
return (
|
||||
@@ -105,57 +108,58 @@ export const TVNextEpisodeCountdown: FC<TVNextEpisodeCountdownProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: "absolute",
|
||||
bottom: 180,
|
||||
right: 80,
|
||||
zIndex: 100,
|
||||
},
|
||||
blur: {
|
||||
borderRadius: 16,
|
||||
overflow: "hidden",
|
||||
},
|
||||
innerContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "stretch",
|
||||
},
|
||||
thumbnail: {
|
||||
width: 180,
|
||||
backgroundColor: "rgba(0,0,0,0.3)",
|
||||
},
|
||||
content: {
|
||||
padding: 16,
|
||||
justifyContent: "center",
|
||||
width: 280,
|
||||
},
|
||||
label: {
|
||||
fontSize: TVTypography.callout,
|
||||
color: "rgba(255,255,255,0.5)",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
marginBottom: 4,
|
||||
},
|
||||
seriesName: {
|
||||
fontSize: TVTypography.callout,
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
marginBottom: 2,
|
||||
},
|
||||
episodeInfo: {
|
||||
fontSize: TVTypography.body,
|
||||
color: "#fff",
|
||||
fontWeight: "600",
|
||||
marginBottom: 12,
|
||||
},
|
||||
progressContainer: {
|
||||
height: 4,
|
||||
backgroundColor: "rgba(255,255,255,0.2)",
|
||||
borderRadius: 2,
|
||||
overflow: "hidden",
|
||||
},
|
||||
progressBar: {
|
||||
height: "100%",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 2,
|
||||
},
|
||||
});
|
||||
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
||||
StyleSheet.create({
|
||||
container: {
|
||||
position: "absolute",
|
||||
bottom: 180,
|
||||
right: 80,
|
||||
zIndex: 100,
|
||||
},
|
||||
blur: {
|
||||
borderRadius: 16,
|
||||
overflow: "hidden",
|
||||
},
|
||||
innerContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "stretch",
|
||||
},
|
||||
thumbnail: {
|
||||
width: 180,
|
||||
backgroundColor: "rgba(0,0,0,0.3)",
|
||||
},
|
||||
content: {
|
||||
padding: 16,
|
||||
justifyContent: "center",
|
||||
width: 280,
|
||||
},
|
||||
label: {
|
||||
fontSize: typography.callout,
|
||||
color: "rgba(255,255,255,0.5)",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
marginBottom: 4,
|
||||
},
|
||||
seriesName: {
|
||||
fontSize: typography.callout,
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
marginBottom: 2,
|
||||
},
|
||||
episodeInfo: {
|
||||
fontSize: typography.body,
|
||||
color: "#fff",
|
||||
fontWeight: "600",
|
||||
marginBottom: 12,
|
||||
},
|
||||
progressContainer: {
|
||||
height: 4,
|
||||
backgroundColor: "rgba(255,255,255,0.2)",
|
||||
borderRadius: 2,
|
||||
overflow: "hidden",
|
||||
},
|
||||
progressBar: {
|
||||
height: "100%",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 2,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { BlurView } from "expo-blur";
|
||||
import React from "react";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVOptionButtonProps {
|
||||
@@ -14,6 +14,7 @@ export interface TVOptionButtonProps {
|
||||
|
||||
export const TVOptionButton = React.forwardRef<View, TVOptionButtonProps>(
|
||||
({ label, value, onPress, hasTVPreferredFocus }, ref) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.02, duration: 120 });
|
||||
|
||||
@@ -50,7 +51,7 @@ export const TVOptionButton = React.forwardRef<View, TVOptionButtonProps>(
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#444",
|
||||
}}
|
||||
>
|
||||
@@ -58,7 +59,7 @@ export const TVOptionButton = React.forwardRef<View, TVOptionButtonProps>(
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#000",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
@@ -88,7 +89,7 @@ export const TVOptionButton = React.forwardRef<View, TVOptionButtonProps>(
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#bbb",
|
||||
}}
|
||||
>
|
||||
@@ -96,7 +97,7 @@ export const TVOptionButton = React.forwardRef<View, TVOptionButtonProps>(
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#E5E7EB",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
|
||||
import React from "react";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVOptionCardProps {
|
||||
@@ -28,6 +28,7 @@ export const TVOptionCard = React.forwardRef<View, TVOptionCardProps>(
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.05 });
|
||||
|
||||
@@ -59,7 +60,7 @@ export const TVOptionCard = React.forwardRef<View, TVOptionCardProps>(
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: focused ? "#000" : "#fff",
|
||||
fontWeight: focused || selected ? "600" : "400",
|
||||
textAlign: "center",
|
||||
@@ -71,7 +72,7 @@ export const TVOptionCard = React.forwardRef<View, TVOptionCardProps>(
|
||||
{sublabel && (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: focused ? "rgba(0,0,0,0.6)" : "rgba(255,255,255,0.5)",
|
||||
textAlign: "center",
|
||||
marginTop: 2,
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
View,
|
||||
} from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { TVCancelButton } from "./TVCancelButton";
|
||||
import { TVOptionCard } from "./TVOptionCard";
|
||||
|
||||
@@ -41,6 +41,7 @@ export const TVOptionSelector = <T,>({
|
||||
cardWidth = 160,
|
||||
cardHeight = 75,
|
||||
}: TVOptionSelectorProps<T>) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
const firstCardRef = useRef<View>(null);
|
||||
|
||||
@@ -91,6 +92,8 @@ export const TVOptionSelector = <T,>({
|
||||
}
|
||||
}, [isReady]);
|
||||
|
||||
const styles = useMemo(() => createStyles(typography), [typography]);
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
return (
|
||||
@@ -151,50 +154,51 @@ export const TVOptionSelector = <T,>({
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
justifyContent: "flex-end",
|
||||
zIndex: 1000,
|
||||
},
|
||||
sheetContainer: {
|
||||
width: "100%",
|
||||
},
|
||||
blurContainer: {
|
||||
borderTopLeftRadius: 24,
|
||||
borderTopRightRadius: 24,
|
||||
overflow: "hidden",
|
||||
},
|
||||
content: {
|
||||
paddingTop: 24,
|
||||
paddingBottom: 50,
|
||||
overflow: "visible",
|
||||
},
|
||||
title: {
|
||||
fontSize: TVTypography.callout,
|
||||
fontWeight: "500",
|
||||
color: "rgba(255,255,255,0.6)",
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 48,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
},
|
||||
scrollView: {
|
||||
overflow: "visible",
|
||||
},
|
||||
scrollContent: {
|
||||
paddingHorizontal: 48,
|
||||
paddingVertical: 20,
|
||||
gap: 12,
|
||||
},
|
||||
cancelButtonContainer: {
|
||||
marginTop: 16,
|
||||
paddingHorizontal: 48,
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
});
|
||||
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
||||
StyleSheet.create({
|
||||
overlay: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
justifyContent: "flex-end",
|
||||
zIndex: 1000,
|
||||
},
|
||||
sheetContainer: {
|
||||
width: "100%",
|
||||
},
|
||||
blurContainer: {
|
||||
borderTopLeftRadius: 24,
|
||||
borderTopRightRadius: 24,
|
||||
overflow: "hidden",
|
||||
},
|
||||
content: {
|
||||
paddingTop: 24,
|
||||
paddingBottom: 50,
|
||||
overflow: "visible",
|
||||
},
|
||||
title: {
|
||||
fontSize: typography.callout,
|
||||
fontWeight: "500",
|
||||
color: "rgba(255,255,255,0.6)",
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 48,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
},
|
||||
scrollView: {
|
||||
overflow: "visible",
|
||||
},
|
||||
scrollContent: {
|
||||
paddingHorizontal: 48,
|
||||
paddingVertical: 20,
|
||||
gap: 12,
|
||||
},
|
||||
cancelButtonContainer: {
|
||||
marginTop: 16,
|
||||
paddingHorizontal: 48,
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ScrollView, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { TVSeriesSeasonCard } from "./TVSeriesSeasonCard";
|
||||
|
||||
export interface TVSeriesNavigationProps {
|
||||
@@ -16,6 +16,7 @@ export interface TVSeriesNavigationProps {
|
||||
|
||||
export const TVSeriesNavigation: React.FC<TVSeriesNavigationProps> = React.memo(
|
||||
({ item, seriesImageUrl, seasonImageUrl, onSeriesPress, onSeasonPress }) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Only show for episodes with a series
|
||||
@@ -27,7 +28,7 @@ export const TVSeriesNavigation: React.FC<TVSeriesNavigationProps> = React.memo(
|
||||
<View style={{ marginBottom: 32 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.heading,
|
||||
fontSize: typography.heading,
|
||||
fontWeight: "600",
|
||||
color: "#FFFFFF",
|
||||
marginBottom: 24,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Image } from "expo-image";
|
||||
import React from "react";
|
||||
import { Animated, Platform, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import {
|
||||
GlassPosterView,
|
||||
isGlassEffectAvailable,
|
||||
@@ -25,6 +25,7 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
|
||||
onPress,
|
||||
hasTVPreferredFocus,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.05 });
|
||||
|
||||
@@ -104,7 +105,7 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
|
||||
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.body,
|
||||
fontSize: typography.body,
|
||||
fontWeight: "600",
|
||||
color: focused ? "#fff" : "rgba(255,255,255,0.9)",
|
||||
textAlign: "center",
|
||||
@@ -118,7 +119,7 @@ export const TVSeriesSeasonCard: React.FC<TVSeriesSeasonCardProps> = ({
|
||||
{subtitle && (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: focused
|
||||
? "rgba(255,255,255,0.8)"
|
||||
: "rgba(255,255,255,0.5)",
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
View,
|
||||
} from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import type { SubtitleSearchResult } from "@/hooks/useRemoteSubtitles";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
@@ -23,6 +23,8 @@ export const TVSubtitleResultCard = React.forwardRef<
|
||||
View,
|
||||
TVSubtitleResultCardProps
|
||||
>(({ result, hasTVPreferredFocus, isDownloading, onPress }, ref) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const styles = createStyles(typography);
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.03 });
|
||||
|
||||
@@ -197,72 +199,73 @@ export const TVSubtitleResultCard = React.forwardRef<
|
||||
);
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
resultCard: {
|
||||
width: 220,
|
||||
minHeight: 120,
|
||||
borderRadius: 14,
|
||||
padding: 14,
|
||||
borderWidth: 1,
|
||||
},
|
||||
providerBadge: {
|
||||
alignSelf: "flex-start",
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
borderRadius: 6,
|
||||
marginBottom: 8,
|
||||
},
|
||||
providerText: {
|
||||
fontSize: TVTypography.callout,
|
||||
fontWeight: "600",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
resultName: {
|
||||
fontSize: TVTypography.callout,
|
||||
fontWeight: "500",
|
||||
marginBottom: 8,
|
||||
lineHeight: 18,
|
||||
},
|
||||
resultMeta: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 12,
|
||||
marginBottom: 8,
|
||||
},
|
||||
resultMetaText: {
|
||||
fontSize: TVTypography.callout,
|
||||
},
|
||||
ratingContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 3,
|
||||
},
|
||||
downloadCountContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 3,
|
||||
},
|
||||
flagsContainer: {
|
||||
flexDirection: "row",
|
||||
gap: 6,
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
flag: {
|
||||
paddingHorizontal: 6,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 4,
|
||||
},
|
||||
flagText: {
|
||||
fontSize: TVTypography.callout,
|
||||
fontWeight: "600",
|
||||
color: "#fff",
|
||||
},
|
||||
downloadingOverlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: "rgba(0,0,0,0.5)",
|
||||
borderRadius: 14,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
});
|
||||
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
||||
StyleSheet.create({
|
||||
resultCard: {
|
||||
width: 220,
|
||||
minHeight: 120,
|
||||
borderRadius: 14,
|
||||
padding: 14,
|
||||
borderWidth: 1,
|
||||
},
|
||||
providerBadge: {
|
||||
alignSelf: "flex-start",
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
borderRadius: 6,
|
||||
marginBottom: 8,
|
||||
},
|
||||
providerText: {
|
||||
fontSize: typography.callout,
|
||||
fontWeight: "600",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
resultName: {
|
||||
fontSize: typography.callout,
|
||||
fontWeight: "500",
|
||||
marginBottom: 8,
|
||||
lineHeight: 18,
|
||||
},
|
||||
resultMeta: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 12,
|
||||
marginBottom: 8,
|
||||
},
|
||||
resultMetaText: {
|
||||
fontSize: typography.callout,
|
||||
},
|
||||
ratingContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 3,
|
||||
},
|
||||
downloadCountContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 3,
|
||||
},
|
||||
flagsContainer: {
|
||||
flexDirection: "row",
|
||||
gap: 6,
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
flag: {
|
||||
paddingHorizontal: 6,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 4,
|
||||
},
|
||||
flagText: {
|
||||
fontSize: typography.callout,
|
||||
fontWeight: "600",
|
||||
color: "#fff",
|
||||
},
|
||||
downloadingOverlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: "rgba(0,0,0,0.5)",
|
||||
borderRadius: 14,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { Animated, Pressable } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVTabButtonProps {
|
||||
@@ -21,6 +21,7 @@ export const TVTabButton: React.FC<TVTabButtonProps> = ({
|
||||
switchOnFocus = false,
|
||||
disabled = false,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({
|
||||
scaleAmount: 1.05,
|
||||
@@ -56,7 +57,7 @@ export const TVTabButton: React.FC<TVTabButtonProps> = ({
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: focused ? "#000" : "#fff",
|
||||
fontWeight: focused || active ? "600" : "400",
|
||||
}}
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
|
||||
export interface TVTechnicalDetailsProps {
|
||||
mediaStreams: MediaStream[];
|
||||
@@ -11,6 +11,7 @@ export interface TVTechnicalDetailsProps {
|
||||
|
||||
export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
||||
({ mediaStreams }) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const videoStream = mediaStreams.find((s) => s.Type === "Video");
|
||||
@@ -24,7 +25,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
||||
<View style={{ marginBottom: 32 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.heading,
|
||||
fontSize: typography.heading,
|
||||
fontWeight: "600",
|
||||
color: "#FFFFFF",
|
||||
marginBottom: 20,
|
||||
@@ -37,7 +38,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#6B7280",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
@@ -46,7 +47,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
||||
>
|
||||
Video
|
||||
</Text>
|
||||
<Text style={{ fontSize: TVTypography.body, color: "#FFFFFF" }}>
|
||||
<Text style={{ fontSize: typography.body, color: "#FFFFFF" }}>
|
||||
{videoStream.DisplayTitle ||
|
||||
`${videoStream.Codec?.toUpperCase()} ${videoStream.Width}x${videoStream.Height}`}
|
||||
</Text>
|
||||
@@ -56,7 +57,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#6B7280",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
@@ -65,7 +66,7 @@ export const TVTechnicalDetails: React.FC<TVTechnicalDetailsProps> = React.memo(
|
||||
>
|
||||
Audio
|
||||
</Text>
|
||||
<Text style={{ fontSize: TVTypography.body, color: "#FFFFFF" }}>
|
||||
<Text style={{ fontSize: typography.body, color: "#FFFFFF" }}>
|
||||
{audioStream.DisplayTitle ||
|
||||
`${audioStream.Codec?.toUpperCase()} ${audioStream.Channels}ch`}
|
||||
</Text>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
|
||||
import React from "react";
|
||||
import { Animated, Pressable, StyleSheet, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "./hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVTrackCardProps {
|
||||
@@ -15,6 +15,8 @@ export interface TVTrackCardProps {
|
||||
|
||||
export const TVTrackCard = React.forwardRef<View, TVTrackCardProps>(
|
||||
({ label, sublabel, selected, hasTVPreferredFocus, onPress }, ref) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const styles = createStyles(typography);
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.05 });
|
||||
|
||||
@@ -77,26 +79,27 @@ export const TVTrackCard = React.forwardRef<View, TVTrackCardProps>(
|
||||
},
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
trackCard: {
|
||||
width: 180,
|
||||
height: 80,
|
||||
borderRadius: 14,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
trackCardText: {
|
||||
fontSize: TVTypography.callout,
|
||||
textAlign: "center",
|
||||
},
|
||||
trackCardSublabel: {
|
||||
fontSize: TVTypography.callout,
|
||||
marginTop: 2,
|
||||
},
|
||||
checkmark: {
|
||||
position: "absolute",
|
||||
top: 8,
|
||||
right: 8,
|
||||
},
|
||||
});
|
||||
const createStyles = (typography: ReturnType<typeof useScaledTVTypography>) =>
|
||||
StyleSheet.create({
|
||||
trackCard: {
|
||||
width: 180,
|
||||
height: 80,
|
||||
borderRadius: 14,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
trackCardText: {
|
||||
fontSize: typography.callout,
|
||||
textAlign: "center",
|
||||
},
|
||||
trackCardSublabel: {
|
||||
fontSize: typography.callout,
|
||||
marginTop: 2,
|
||||
},
|
||||
checkmark: {
|
||||
position: "absolute",
|
||||
top: 8,
|
||||
right: 8,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVLogoutButtonProps {
|
||||
@@ -15,6 +15,7 @@ export const TVLogoutButton: React.FC<TVLogoutButtonProps> = ({
|
||||
disabled,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.05 });
|
||||
|
||||
@@ -49,7 +50,7 @@ export const TVLogoutButton: React.FC<TVLogoutButtonProps> = ({
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.body,
|
||||
fontSize: typography.body,
|
||||
fontWeight: "bold",
|
||||
color: "#FFFFFF",
|
||||
}}
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
import React from "react";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
|
||||
export interface TVSectionHeaderProps {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const TVSectionHeader: React.FC<TVSectionHeaderProps> = ({ title }) => (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontWeight: "600",
|
||||
color: "#9CA3AF",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
marginTop: 32,
|
||||
marginBottom: 16,
|
||||
marginLeft: 8,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
);
|
||||
export const TVSectionHeader: React.FC<TVSectionHeaderProps> = ({ title }) => {
|
||||
const typography = useScaledTVTypography();
|
||||
|
||||
return (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: typography.callout,
|
||||
fontWeight: "600",
|
||||
color: "#9CA3AF",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
marginTop: 32,
|
||||
marginBottom: 16,
|
||||
marginLeft: 8,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
|
||||
import React from "react";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVSettingsOptionButtonProps {
|
||||
@@ -20,6 +20,7 @@ export const TVSettingsOptionButton: React.FC<TVSettingsOptionButtonProps> = ({
|
||||
isFirst,
|
||||
disabled,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.02 });
|
||||
|
||||
@@ -49,13 +50,13 @@ export const TVSettingsOptionButton: React.FC<TVSettingsOptionButtonProps> = ({
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Text style={{ fontSize: TVTypography.body, color: "#FFFFFF" }}>
|
||||
<Text style={{ fontSize: typography.body, color: "#FFFFFF" }}>
|
||||
{label}
|
||||
</Text>
|
||||
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#9CA3AF",
|
||||
marginRight: 12,
|
||||
}}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
|
||||
import React from "react";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVSettingsRowProps {
|
||||
@@ -22,6 +22,7 @@ export const TVSettingsRow: React.FC<TVSettingsRowProps> = ({
|
||||
showChevron = true,
|
||||
disabled,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.02 });
|
||||
|
||||
@@ -51,13 +52,13 @@ export const TVSettingsRow: React.FC<TVSettingsRowProps> = ({
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Text style={{ fontSize: TVTypography.body, color: "#FFFFFF" }}>
|
||||
<Text style={{ fontSize: typography.body, color: "#FFFFFF" }}>
|
||||
{label}
|
||||
</Text>
|
||||
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#9CA3AF",
|
||||
marginRight: showChevron ? 12 : 0,
|
||||
}}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Ionicons } from "@expo/vector-icons";
|
||||
import React from "react";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVSettingsStepperProps {
|
||||
@@ -24,6 +24,7 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
||||
isFirst,
|
||||
disabled,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const labelAnim = useTVFocusAnimation({ scaleAmount: 1.02 });
|
||||
const minusAnim = useTVFocusAnimation({ scaleAmount: 1.1 });
|
||||
const plusAnim = useTVFocusAnimation({ scaleAmount: 1.1 });
|
||||
@@ -54,7 +55,7 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
||||
focusable={!disabled}
|
||||
>
|
||||
<Animated.View style={labelAnim.animatedStyle}>
|
||||
<Text style={{ fontSize: TVTypography.body, color: "#FFFFFF" }}>
|
||||
<Text style={{ fontSize: typography.body, color: "#FFFFFF" }}>
|
||||
{label}
|
||||
</Text>
|
||||
</Animated.View>
|
||||
@@ -89,7 +90,7 @@ export const TVSettingsStepper: React.FC<TVSettingsStepperProps> = ({
|
||||
</Pressable>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#FFFFFF",
|
||||
minWidth: 60,
|
||||
textAlign: "center",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useRef } from "react";
|
||||
import { Animated, Pressable, TextInput } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVSettingsTextInputProps {
|
||||
@@ -23,6 +23,7 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
|
||||
secureTextEntry,
|
||||
disabled,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const inputRef = useRef<TextInput>(null);
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.02 });
|
||||
@@ -56,7 +57,7 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: TVTypography.callout,
|
||||
fontSize: typography.callout,
|
||||
color: "#9CA3AF",
|
||||
marginBottom: 8,
|
||||
}}
|
||||
@@ -74,7 +75,7 @@ export const TVSettingsTextInput: React.FC<TVSettingsTextInputProps> = ({
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
style={{
|
||||
fontSize: TVTypography.body,
|
||||
fontSize: typography.body,
|
||||
color: "#FFFFFF",
|
||||
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
||||
borderRadius: 8,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { Animated, Pressable, View } from "react-native";
|
||||
import { Text } from "@/components/common/Text";
|
||||
import { TVTypography } from "@/constants/TVTypography";
|
||||
import { useScaledTVTypography } from "@/constants/TVTypography";
|
||||
import { useTVFocusAnimation } from "../hooks/useTVFocusAnimation";
|
||||
|
||||
export interface TVSettingsToggleProps {
|
||||
@@ -19,6 +19,7 @@ export const TVSettingsToggle: React.FC<TVSettingsToggleProps> = ({
|
||||
isFirst,
|
||||
disabled,
|
||||
}) => {
|
||||
const typography = useScaledTVTypography();
|
||||
const { focused, handleFocus, handleBlur, animatedStyle } =
|
||||
useTVFocusAnimation({ scaleAmount: 1.02 });
|
||||
|
||||
@@ -48,7 +49,7 @@ export const TVSettingsToggle: React.FC<TVSettingsToggleProps> = ({
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Text style={{ fontSize: TVTypography.body, color: "#FFFFFF" }}>
|
||||
<Text style={{ fontSize: typography.body, color: "#FFFFFF" }}>
|
||||
{label}
|
||||
</Text>
|
||||
<View
|
||||
|
||||
Reference in New Issue
Block a user