import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client"; import type { FC } from "react"; import { View } from "react-native"; import { Slider } from "react-native-awesome-slider"; import { type SharedValue } from "react-native-reanimated"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Text } from "@/components/common/Text"; import { useSettings } from "@/utils/atoms/settings"; import NextEpisodeCountDownButton from "./NextEpisodeCountDownButton"; import SkipButton from "./SkipButton"; import { TimeDisplay } from "./TimeDisplay"; import { TrickplayBubble } from "./TrickplayBubble"; interface BottomControlsProps { item: BaseItemDto; showControls: boolean; isSliding: boolean; showRemoteBubble: boolean; currentTime: number; remainingTime: number; showSkipButton: boolean; showSkipCreditButton: boolean; hasContentAfterCredits: boolean; skipIntro: () => void; skipCredit: () => void; nextItem?: BaseItemDto | null; handleNextEpisodeAutoPlay: () => void; handleNextEpisodeManual: () => void; handleControlsInteraction: () => void; // Slider props min: SharedValue; max: SharedValue; effectiveProgress: SharedValue; cacheProgress: SharedValue; handleSliderStart: () => void; handleSliderComplete: (value: number) => void; handleSliderChange: (value: number) => void; handleTouchStart: () => void; handleTouchEnd: () => void; // Trickplay props trickPlayUrl: { x: number; y: number; url: string; } | null; trickplayInfo: { aspectRatio?: number; data: { TileWidth?: number; TileHeight?: number; }; } | null; time: { hours: number; minutes: number; seconds: number; }; } export const BottomControls: FC = ({ item, showControls, isSliding, showRemoteBubble, currentTime, remainingTime, showSkipButton, showSkipCreditButton, hasContentAfterCredits, skipIntro, skipCredit, nextItem, handleNextEpisodeAutoPlay, handleNextEpisodeManual, handleControlsInteraction, min, max, effectiveProgress, cacheProgress, handleSliderStart, handleSliderComplete, handleSliderChange, handleTouchStart, handleTouchEnd, trickPlayUrl, trickplayInfo, time, }) => { const { settings } = useSettings(); const insets = useSafeAreaInsets(); return ( {item?.Type === "Episode" && ( {`${item.SeriesName} - ${item.SeasonName} Episode ${item.IndexNumber}`} )} {item?.Name} {item?.Type === "Movie" && ( {item?.ProductionYear} )} {item?.Type === "Audio" && ( {item?.Album} )} {/* Smart Skip Credits behavior: - Show "Skip Credits" if there's content after credits OR no next episode - Show "Next Episode" if credits extend to video end AND next episode exists */} {settings.autoPlayNextEpisode !== false && (settings.maxAutoPlayEpisodeCount.value === -1 || settings.autoPlayEpisodeCount < settings.maxAutoPlayEpisodeCount.value) && ( )} null} cache={cacheProgress} onSlidingStart={handleSliderStart} onSlidingComplete={handleSliderComplete} onValueChange={handleSliderChange} containerStyle={{ borderRadius: 100, }} renderBubble={() => (isSliding || showRemoteBubble) && ( ) } sliderHeight={10} thumbWidth={0} progress={effectiveProgress} minimumValue={min} maximumValue={max} /> ); };