import { AudioTrackSelector } from "@/components/AudioTrackSelector"; import { Bitrate, BitrateSelector } from "@/components/BitrateSelector"; import { DownloadItem } from "@/components/DownloadItem"; import { OverviewText } from "@/components/OverviewText"; import { ParallaxScrollView } from "@/components/ParallaxPage"; import { PlayButton } from "@/components/PlayButton"; import { PlayedStatus } from "@/components/PlayedStatus"; import { SimilarItems } from "@/components/SimilarItems"; import { SubtitleTrackSelector } from "@/components/SubtitleTrackSelector"; import { ItemImage } from "@/components/common/ItemImage"; import { CastAndCrew } from "@/components/series/CastAndCrew"; import { CurrentSeries } from "@/components/series/CurrentSeries"; import { SeasonEpisodesCarousel } from "@/components/series/SeasonEpisodesCarousel"; import { useImageColors } from "@/hooks/useImageColors"; import { apiAtom } from "@/providers/JellyfinProvider"; import { usePlaySettings } from "@/providers/PlaySettingsProvider"; import { useSettings } from "@/utils/atoms/settings"; import { getDefaultPlaySettings } from "@/utils/jellyfin/getDefaultPlaySettings"; import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById"; import { BaseItemDto, MediaSourceInfo, } from "@jellyfin/sdk/lib/generated-client/models"; import { Image } from "expo-image"; import { useFocusEffect, useNavigation } from "expo-router"; import * as ScreenOrientation from "expo-screen-orientation"; import { useAtom } from "jotai"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Chromecast } from "./Chromecast"; import { ItemHeader } from "./ItemHeader"; import { MediaSourceSelector } from "./MediaSourceSelector"; import { MoreMoviesWithActor } from "./MoreMoviesWithActor"; export const ItemContent: React.FC<{ item: BaseItemDto }> = React.memo( ({ item }) => { const [api] = useAtom(apiAtom); const { setPlaySettings, playUrl, playSettings } = usePlaySettings(); const [settings] = useSettings(); const navigation = useNavigation(); const [loadingLogo, setLoadingLogo] = useState(true); const [orientation, setOrientation] = useState( ScreenOrientation.Orientation.PORTRAIT_UP ); useFocusEffect( useCallback(() => { if (!settings) return; const { bitrate, mediaSource, audioIndex, subtitleIndex } = getDefaultPlaySettings(item, settings); setPlaySettings({ item, bitrate, mediaSource, audioIndex, subtitleIndex, }); }, [item, settings]) ); const selectedMediaSource = useMemo(() => { return playSettings?.mediaSource || undefined; }, [playSettings?.mediaSource]); const setSelectedMediaSource = (mediaSource: MediaSourceInfo) => { setPlaySettings((prev) => ({ ...prev, mediaSource, })); }; const selectedAudioStream = useMemo(() => { return playSettings?.audioIndex; }, [playSettings?.audioIndex]); const setSelectedAudioStream = (audioIndex: number) => { setPlaySettings((prev) => ({ ...prev, audioIndex, })); }; const selectedSubtitleStream = useMemo(() => { return playSettings?.subtitleIndex; }, [playSettings?.subtitleIndex]); const setSelectedSubtitleStream = (subtitleIndex: number) => { setPlaySettings((prev) => ({ ...prev, subtitleIndex, })); }; const maxBitrate = useMemo(() => { return playSettings?.bitrate; }, [playSettings?.bitrate]); const setMaxBitrate = (bitrate: Bitrate | undefined) => { console.log("setMaxBitrate", bitrate); setPlaySettings((prev) => ({ ...prev, bitrate, })); }; useEffect(() => { const subscription = ScreenOrientation.addOrientationChangeListener( (event) => { setOrientation(event.orientationInfo.orientation); } ); ScreenOrientation.getOrientationAsync().then((initialOrientation) => { setOrientation(initialOrientation); }); return () => { ScreenOrientation.removeOrientationChangeListener(subscription); }; }, []); const [headerHeight, setHeaderHeight] = useState(350); useImageColors({ item }); useEffect(() => { navigation.setOptions({ headerRight: () => item && ( {item.Type !== "Program" && ( )} ), }); }, [item]); useEffect(() => { // If landscape if (orientation !== ScreenOrientation.Orientation.PORTRAIT_UP) { setHeaderHeight(230); return; } if (item.Type === "Movie") setHeaderHeight(500); else setHeaderHeight(350); }, [item.Type, orientation]); const logoUrl = useMemo(() => getLogoImageUrlById({ api, item }), [item]); const loading = useMemo(() => { return Boolean(logoUrl && loadingLogo); }, [loadingLogo, logoUrl]); const insets = useSafeAreaInsets(); return ( } logo={ <> {logoUrl ? ( setLoadingLogo(false)} onError={() => setLoadingLogo(false)} /> ) : null} } > {item.Type !== "Program" && ( setMaxBitrate(val)} selected={maxBitrate} /> {selectedMediaSource && ( <> )} )} {item.Type === "Episode" && ( )} {item.Type !== "Program" && ( <> {item.People && item.People.length > 0 && ( {item.People.slice(0, 3).map((person) => ( ))} )} {item.Type === "Episode" && ( )} )} ); } );