diff --git a/app/(auth)/player/direct-player.tsx b/app/(auth)/player/direct-player.tsx index e3558408..17a06798 100644 --- a/app/(auth)/player/direct-player.tsx +++ b/app/(auth)/player/direct-player.tsx @@ -27,7 +27,6 @@ import { useInvalidatePlaybackProgressCache } from "@/hooks/useRevalidatePlaybac import { useWebSocket } from "@/hooks/useWebsockets"; import { VlcPlayerView } from "@/modules"; import type { - PipStartedPayload, PlaybackStatePayload, ProgressUpdatePayload, VlcPlayerViewRef, @@ -60,7 +59,6 @@ export default function page() { const [isMuted, setIsMuted] = useState(false); const [isBuffering, setIsBuffering] = useState(true); const [isVideoLoaded, setIsVideoLoaded] = useState(false); - const [isPipStarted, setIsPipStarted] = useState(false); const progress = useSharedValue(0); const isSeeking = useSharedValue(false); @@ -390,11 +388,6 @@ export default function page() { ], ); - const onPipStarted = useCallback((e: PipStartedPayload) => { - const { pipStarted } = e.nativeEvent; - setIsPipStarted(pipStarted); - }, []); - /** Gets the initial playback position in seconds. */ const startPosition = useMemo(() => { return ticksToSeconds(getInitialPlaybackTicks()); @@ -690,7 +683,6 @@ export default function page() { onVideoProgress={onProgress} progressUpdateInterval={1000} onVideoStateChange={onPlaybackStateChanged} - onPipStarted={onPipStarted} onVideoLoadEnd={() => { setIsVideoLoaded(true); }} @@ -704,7 +696,7 @@ export default function page() { }} /> - {!isPipStarted && isMounted === true && item && ( + {isMounted === true && item && ( = ({ style={{ flexDirection: "column", alignSelf: "flex-end", - opacity: showControls ? 1 : 0, }} pointerEvents={showControls ? "box-none" : "none"} > @@ -164,9 +163,6 @@ export const BottomControls: FC = ({ diff --git a/components/video-player/controls/CenterControls.tsx b/components/video-player/controls/CenterControls.tsx index 0f3b154a..fca8d701 100644 --- a/components/video-player/controls/CenterControls.tsx +++ b/components/video-player/controls/CenterControls.tsx @@ -55,7 +55,6 @@ export const CenterControls: FC = ({ transform: [{ rotate: "270deg" }], left: 0, bottom: 30, - opacity: showControls ? 1 : 0, }} > @@ -68,7 +67,6 @@ export const CenterControls: FC = ({ position: "relative", justifyContent: "center", alignItems: "center", - opacity: showControls ? 1 : 0, }} > = ({ name={isPlaying ? "pause" : "play"} size={ICON_SIZES.CENTER} color='white' - style={{ - opacity: showControls ? 1 : 0, - }} /> ) : ( @@ -118,7 +113,6 @@ export const CenterControls: FC = ({ position: "relative", justifyContent: "center", alignItems: "center", - opacity: showControls ? 1 : 0, }} > = ({ const min = useSharedValue(0); const max = useSharedValue(item.RunTimeTicks || 0); + // Animation values for controls + const controlsOpacity = useSharedValue(showControls ? 1 : 0); + const headerTranslateY = useSharedValue(showControls ? 0 : -50); + const bottomTranslateY = useSharedValue(showControls ? 0 : 50); + useEffect(() => { prefetchAllTrickplayImages(); }, [prefetchAllTrickplayImages]); + // Animate controls visibility + useEffect(() => { + const animationConfig = { + duration: 300, + easing: Easing.out(Easing.quad), + }; + + controlsOpacity.value = withTiming(showControls ? 1 : 0, animationConfig); + headerTranslateY.value = withTiming( + showControls ? 0 : -10, + animationConfig, + ); + bottomTranslateY.value = withTiming(showControls ? 0 : 10, animationConfig); + }, [showControls, controlsOpacity, headerTranslateY, bottomTranslateY]); + + // Create animated styles + const headerAnimatedStyle = useAnimatedStyle(() => ({ + opacity: controlsOpacity.value, + transform: [{ translateY: headerTranslateY.value }], + position: "absolute" as const, + top: 0, + left: 0, + right: 0, + zIndex: 10, + })); + + const centerAnimatedStyle = useAnimatedStyle(() => ({ + opacity: controlsOpacity.value, + position: "absolute" as const, + top: 0, + left: 0, + right: 0, + bottom: 0, + zIndex: 5, + })); + + const bottomAnimatedStyle = useAnimatedStyle(() => ({ + opacity: controlsOpacity.value, + transform: [{ translateY: bottomTranslateY.value }], + position: "absolute" as const, + bottom: 0, + left: 0, + right: 0, + zIndex: 10, + })); + // Initialize progress values useEffect(() => { if (item) { @@ -435,68 +489,83 @@ export const Controls: FC = ({ showControls={showControls} onToggleControls={toggleControls} /> - - - + + + + + + + + + )} {settings.maxAutoPlayEpisodeCount.value !== -1 && ( diff --git a/components/video-player/controls/HeaderControls.tsx b/components/video-player/controls/HeaderControls.tsx index e88033d0..d14a8a3f 100644 --- a/components/video-player/controls/HeaderControls.tsx +++ b/components/video-player/controls/HeaderControls.tsx @@ -106,7 +106,6 @@ export const HeaderControls: FC = ({ width: settings?.safeAreaInControlsEnabled ? screenWidth - insets.left - insets.right : screenWidth, - opacity: showControls ? 1 : 0, }, ]} pointerEvents={showControls ? "auto" : "none"} @@ -138,7 +137,6 @@ export const HeaderControls: FC = ({ name='picture-in-picture' size={ICON_SIZES.HEADER} color='white' - style={{ opacity: showControls ? 1 : 0 }} /> )}