import { Ionicons } from "@expo/vector-icons"; import { Image } from "expo-image"; import React from "react"; import { useTranslation } from "react-i18next"; import { Animated, FlatList, Pressable, View } from "react-native"; import { Text } from "@/components/common/Text"; import { useTVFocusAnimation } from "@/components/tv/hooks/useTVFocusAnimation"; import { useScaledTVTypography } from "@/constants/TVTypography"; import { useJellyseerr } from "@/hooks/useJellyseerr"; import { MediaStatus } from "@/utils/jellyseerr/server/constants/media"; import type { MovieResult, PersonResult, TvResult, } from "@/utils/jellyseerr/server/models/Search"; const SCALE_PADDING = 20; interface TVJellyseerrPosterProps { item: MovieResult | TvResult; onPress: () => void; isFirstItem?: boolean; } const TVJellyseerrPoster: React.FC = ({ item, onPress, isFirstItem = false, }) => { const typography = useScaledTVTypography(); const { jellyseerrApi, getTitle, getYear } = useJellyseerr(); const { focused, handleFocus, handleBlur, animatedStyle } = useTVFocusAnimation({ scaleAmount: 1.05 }); const posterUrl = item.posterPath ? jellyseerrApi?.imageProxy(item.posterPath, "w342") : null; const title = getTitle(item); const year = getYear(item); const isInLibrary = item.mediaInfo?.status === MediaStatus.AVAILABLE || item.mediaInfo?.status === MediaStatus.PARTIALLY_AVAILABLE; return ( {posterUrl ? ( ) : ( )} {isInLibrary && ( )} {title} {year && ( {year} )} ); }; interface TVJellyseerrPersonPosterProps { item: PersonResult; onPress: () => void; } const TVJellyseerrPersonPoster: React.FC = ({ item, onPress, }) => { const typography = useScaledTVTypography(); const { jellyseerrApi } = useJellyseerr(); const { focused, handleFocus, handleBlur, animatedStyle } = useTVFocusAnimation(); const posterUrl = item.profilePath ? jellyseerrApi?.imageProxy(item.profilePath, "w185") : null; return ( {posterUrl ? ( ) : ( )} {item.name} ); }; interface TVJellyseerrMovieSectionProps { title: string; items: MovieResult[]; isFirstSection?: boolean; onItemPress: (item: MovieResult) => void; } const TVJellyseerrMovieSection: React.FC = ({ title, items, isFirstSection = false, onItemPress, }) => { const typography = useScaledTVTypography(); if (!items || items.length === 0) return null; return ( {title} item.id.toString()} showsHorizontalScrollIndicator={false} contentContainerStyle={{ paddingHorizontal: SCALE_PADDING, paddingVertical: SCALE_PADDING, gap: 20, }} style={{ overflow: "visible" }} renderItem={({ item, index }) => ( onItemPress(item)} isFirstItem={isFirstSection && index === 0} /> )} /> ); }; interface TVJellyseerrTvSectionProps { title: string; items: TvResult[]; isFirstSection?: boolean; onItemPress: (item: TvResult) => void; } const TVJellyseerrTvSection: React.FC = ({ title, items, isFirstSection = false, onItemPress, }) => { const typography = useScaledTVTypography(); if (!items || items.length === 0) return null; return ( {title} item.id.toString()} showsHorizontalScrollIndicator={false} contentContainerStyle={{ paddingHorizontal: SCALE_PADDING, paddingVertical: SCALE_PADDING, gap: 20, }} style={{ overflow: "visible" }} renderItem={({ item, index }) => ( onItemPress(item)} isFirstItem={isFirstSection && index === 0} /> )} /> ); }; interface TVJellyseerrPersonSectionProps { title: string; items: PersonResult[]; isFirstSection?: boolean; onItemPress: (item: PersonResult) => void; } const TVJellyseerrPersonSection: React.FC = ({ title, items, isFirstSection: _isFirstSection = false, onItemPress, }) => { const typography = useScaledTVTypography(); if (!items || items.length === 0) return null; return ( {title} item.id.toString()} showsHorizontalScrollIndicator={false} contentContainerStyle={{ paddingHorizontal: SCALE_PADDING, paddingVertical: SCALE_PADDING, gap: 20, }} style={{ overflow: "visible" }} renderItem={({ item }) => ( onItemPress(item)} /> )} /> ); }; export interface TVJellyseerrSearchResultsProps { movieResults: MovieResult[]; tvResults: TvResult[]; personResults: PersonResult[]; loading: boolean; noResults: boolean; searchQuery: string; onMoviePress: (item: MovieResult) => void; onTvPress: (item: TvResult) => void; onPersonPress: (item: PersonResult) => void; } export const TVJellyseerrSearchResults: React.FC< TVJellyseerrSearchResultsProps > = ({ movieResults, tvResults, personResults, loading, noResults, searchQuery, onMoviePress, onTvPress, onPersonPress, }) => { const { t } = useTranslation(); const hasMovies = movieResults && movieResults.length > 0; const hasTv = tvResults && tvResults.length > 0; const hasPersons = personResults && personResults.length > 0; if (loading) { return null; } if (noResults && searchQuery.length > 0) { return ( {t("search.no_results_found_for")} "{searchQuery}" ); } return ( ); };