import { Ionicons } from "@expo/vector-icons"; import { BottomSheetBackdrop, type BottomSheetBackdropProps, BottomSheetModal, BottomSheetScrollView, } from "@gorhom/bottom-sheet"; import { useLocalSearchParams, useRouter } from "expo-router"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Platform, StyleSheet, TouchableOpacity, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { BITRATES } from "@/components/BitrateSelector"; import { Text } from "@/components/common/Text"; import { useControlContext } from "../contexts/ControlContext"; import { useVideoContext } from "../contexts/VideoContext"; const DropdownView = () => { const videoContext = useVideoContext(); const { subtitleTracks, audioTracks } = videoContext; const ControlContext = useControlContext(); const [item, mediaSource] = [ ControlContext?.item, ControlContext?.mediaSource, ]; const router = useRouter(); const insets = useSafeAreaInsets(); const [open, setOpen] = useState(false); const bottomSheetModalRef = useRef(null); const snapPoints = useMemo(() => ["75%"], []); const { subtitleIndex, audioIndex, bitrateValue, playbackPosition, offline } = useLocalSearchParams<{ itemId: string; audioIndex: string; subtitleIndex: string; mediaSourceId: string; bitrateValue: string; playbackPosition: string; offline: string; }>(); const isOffline = offline === "true"; const changeBitrate = useCallback( (bitrate: string) => { const queryParams = new URLSearchParams({ itemId: item.Id ?? "", audioIndex: audioIndex?.toString() ?? "", subtitleIndex: subtitleIndex.toString() ?? "", mediaSourceId: mediaSource?.Id ?? "", bitrateValue: bitrate.toString(), playbackPosition: playbackPosition, }).toString(); router.replace(`player/direct-player?${queryParams}` as any); }, [item, mediaSource, subtitleIndex, audioIndex, playbackPosition], ); const handleSheetChanges = useCallback((index: number) => { if (index === -1) { setOpen(false); } }, []); const renderBackdrop = useCallback( (props: BottomSheetBackdropProps) => ( ), [], ); const handleOpen = () => { setOpen(true); bottomSheetModalRef.current?.present(); }; const handleClose = () => { setOpen(false); bottomSheetModalRef.current?.dismiss(); }; useEffect(() => { if (open) bottomSheetModalRef.current?.present(); else bottomSheetModalRef.current?.dismiss(); }, [open]); // Hide on TV platforms if (Platform.isTV) return null; return ( <> Playback Options {/* Quality Section */} {!isOffline && ( Quality {BITRATES?.map((bitrate, idx: number) => ( { changeBitrate(bitrate.value?.toString() ?? ""); setTimeout(() => handleClose(), 250); }} className='bg-neutral-800 px-4 py-3 flex flex-row items-center justify-between' > {bitrate.key} {bitrateValue === (bitrate.value?.toString() ?? "") ? ( ) : ( )} {idx < BITRATES.length - 1 && ( )} ))} )} {/* Subtitle Section */} Subtitles {subtitleTracks?.map((sub, idx: number) => ( { sub.setTrack(); setTimeout(() => handleClose(), 250); }} className='bg-neutral-800 px-4 py-3 flex flex-row items-center justify-between' > {sub.name} {subtitleIndex === sub.index.toString() ? ( ) : ( )} {idx < (subtitleTracks?.length ?? 0) - 1 && ( )} ))} {/* Audio Section */} {(audioTracks?.length ?? 0) > 0 && ( Audio {audioTracks?.map((track, idx: number) => ( { track.setTrack(); setTimeout(() => handleClose(), 250); }} className='bg-neutral-800 px-4 py-3 flex flex-row items-center justify-between' > {track.name} {audioIndex === track.index.toString() ? ( ) : ( )} {idx < (audioTracks?.length ?? 0) - 1 && ( )} ))} )} ); }; export default DropdownView;