diff --git a/components/AppleTVCarousel.tsx b/components/AppleTVCarousel.tsx index 2f5b2d50..c439069d 100644 --- a/components/AppleTVCarousel.tsx +++ b/components/AppleTVCarousel.tsx @@ -7,9 +7,10 @@ import { import { useQuery } from "@tanstack/react-query"; import { Image } from "expo-image"; import { LinearGradient } from "expo-linear-gradient"; +import { useRouter } from "expo-router"; import { useAtomValue } from "jotai"; import { useCallback, useEffect, useMemo, useState } from "react"; -import { Dimensions, Pressable, View } from "react-native"; +import { Dimensions, Pressable, TouchableOpacity, View } from "react-native"; import { Gesture, GestureDetector } from "react-native-gesture-handler"; import Animated, { Easing, @@ -25,6 +26,7 @@ import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { useSettings } from "@/utils/atoms/settings"; import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById"; import { ItemImage } from "./common/ItemImage"; +import { getItemNavigation } from "./common/TouchableItemRouter"; import type { SelectedOptions } from "./ItemContent"; import { PlayButton } from "./PlayButton"; import { PlayedStatus } from "./PlayedStatus"; @@ -150,6 +152,7 @@ export const AppleTVCarousel: React.FC = ({ const api = useAtomValue(apiAtom); const user = useAtomValue(userAtom); const { isConnected, serverConnected } = useNetworkStatus(); + const router = useRouter(); const [currentIndex, setCurrentIndex] = useState(initialIndex); const translateX = useSharedValue(-currentIndex * screenWidth); @@ -301,6 +304,14 @@ export const AppleTVCarousel: React.FC = ({ [hasItems, items, onItemChange, translateX], ); + const navigateToItem = useCallback( + (item: BaseItemDto) => { + const navigation = getItemNavigation(item, "(home)"); + router.push(navigation as any); + }, + [router], + ); + const panGesture = Gesture.Pan() .activeOffsetX([-PAN_ACTIVE_OFFSET, PAN_ACTIVE_OFFSET]) .onUpdate((event) => { @@ -591,7 +602,8 @@ export const AppleTVCarousel: React.FC = ({ {/* Logo Section */} {itemLogoUrl && ( - navigateToItem(item)} style={{ position: "absolute", bottom: LOGO_BOTTOM_POSITION, @@ -611,7 +623,7 @@ export const AppleTVCarousel: React.FC = ({ }} contentFit='contain' /> - + )} {/* Type and Genres Section */} @@ -625,41 +637,56 @@ export const AppleTVCarousel: React.FC = ({ alignItems: "center", }} > - - {(() => { - const typeLabel = - item.Type === "Series" - ? "TV Show" - : item.Type === "Movie" - ? "Movie" - : item.Type || ""; + navigateToItem(item)}> + + {(() => { + let typeLabel = ""; - const genres = - item.Genres && item.Genres.length > 0 - ? item.Genres.slice(0, MAX_GENRES_COUNT).join(" • ") - : ""; + if (item.Type === "Episode") { + // For episodes, show season and episode number + const season = item.ParentIndexNumber; + const episode = item.IndexNumber; + if (season && episode) { + typeLabel = `S${season} • E${episode}`; + } else { + typeLabel = "Episode"; + } + } else { + typeLabel = + item.Type === "Series" + ? "TV Show" + : item.Type === "Movie" + ? "Movie" + : item.Type || ""; + } - if (typeLabel && genres) { - return `${typeLabel} • ${genres}`; - } else if (typeLabel) { - return typeLabel; - } else if (genres) { - return genres; - } else { - return ""; - } - })()} - + const genres = + item.Genres && item.Genres.length > 0 + ? item.Genres.slice(0, MAX_GENRES_COUNT).join(" • ") + : ""; + + if (typeLabel && genres) { + return `${typeLabel} • ${genres}`; + } else if (typeLabel) { + return typeLabel; + } else if (genres) { + return genres; + } else { + return ""; + } + })()} + + {/* Controls Section */}