From 9aa0dc0a3d02a071c5edcf81e05474b9b5874485 Mon Sep 17 00:00:00 2001 From: Fredrik Burmester Date: Tue, 24 Sep 2024 18:16:26 +0200 Subject: [PATCH] wip: full screen player --- app/(auth)/play.tsx | 48 +++++++++++ app/_layout.tsx | 6 +- components/FullScreenVideoPlayer.tsx | 116 +++++++++++++++++---------- components/PlayButton.tsx | 6 ++ 4 files changed, 133 insertions(+), 43 deletions(-) create mode 100644 app/(auth)/play.tsx diff --git a/app/(auth)/play.tsx b/app/(auth)/play.tsx new file mode 100644 index 00000000..0d3b3891 --- /dev/null +++ b/app/(auth)/play.tsx @@ -0,0 +1,48 @@ +import { FullScreenVideoPlayer } from "@/components/FullScreenVideoPlayer"; +import { useSettings } from "@/utils/atoms/settings"; +import * as NavigationBar from "expo-navigation-bar"; +import { StatusBar } from "expo-status-bar"; +import { useEffect, useState } from "react"; +import { Platform, View, ViewProps } from "react-native"; +import * as ScreenOrientation from "expo-screen-orientation"; + +interface Props extends ViewProps {} + +export default function page() { + const [settings] = useSettings(); + + useEffect(() => { + if (settings?.autoRotate) { + // Don't need to do anything + } else if (settings?.defaultVideoOrientation) { + ScreenOrientation.lockAsync(settings.defaultVideoOrientation); + } + + if (Platform.OS === "android") { + NavigationBar.setVisibilityAsync("hidden"); + NavigationBar.setBehaviorAsync("overlay-swipe"); + } + + return () => { + if (settings?.autoRotate) { + ScreenOrientation.unlockAsync(); + } else { + ScreenOrientation.lockAsync( + ScreenOrientation.OrientationLock.PORTRAIT_UP + ); + } + + if (Platform.OS === "android") { + NavigationBar.setVisibilityAsync("visible"); + NavigationBar.setBehaviorAsync("inset-swipe"); + } + }; + }, [settings]); + + return ( + + + ); +} diff --git a/app/_layout.tsx b/app/_layout.tsx index cac8f2ea..e610f447 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -120,13 +120,17 @@ function Layout() { title: "", }} /> + - + {/* */} diff --git a/components/FullScreenVideoPlayer.tsx b/components/FullScreenVideoPlayer.tsx index d9faf3f4..c80fdb76 100644 --- a/components/FullScreenVideoPlayer.tsx +++ b/components/FullScreenVideoPlayer.tsx @@ -45,6 +45,9 @@ import { ticksToSeconds, } from "@/utils/time"; +const windowDimensions = Dimensions.get("window"); +const screenDimensions = Dimensions.get("screen"); + export const FullScreenVideoPlayer: React.FC = () => { const { currentlyPlaying, @@ -85,7 +88,20 @@ export const FullScreenVideoPlayer: React.FC = () => { const min = useSharedValue(0); const max = useSharedValue(currentlyPlaying?.item.RunTimeTicks || 0); - const { width: screenWidth, height: screenHeight } = Dimensions.get("window"); + const [dimensions, setDimensions] = useState({ + window: windowDimensions, + screen: screenDimensions, + }); + + useEffect(() => { + const subscription = Dimensions.addEventListener( + "change", + ({ window, screen }) => { + setDimensions({ window, screen }); + } + ); + return () => subscription?.remove(); + }); const from = useMemo(() => segments[2], [segments]); @@ -123,7 +139,13 @@ export const FullScreenVideoPlayer: React.FC = () => { onPress: () => null, style: "cancel", }, - { text: "Yes", onPress: () => stopPlayback() }, + { + text: "Yes", + onPress: () => { + stopPlayback(); + router.back(); + }, + }, ]); return true; } @@ -136,7 +158,7 @@ export const FullScreenVideoPlayer: React.FC = () => { ); return () => backHandler.remove(); - }, [currentlyPlaying, stopPlayback]); + }, [currentlyPlaying, stopPlayback, router]); const [orientation, setOrientation] = useState( ScreenOrientation.OrientationLock.UNKNOWN @@ -154,6 +176,10 @@ export const FullScreenVideoPlayer: React.FC = () => { } ); + ScreenOrientation.getOrientationAsync().then((orientation) => { + setOrientation(orientationToOrientationLock(orientation)); + }); + return () => { subscription.remove(); }; @@ -199,25 +225,13 @@ export const FullScreenVideoPlayer: React.FC = () => { }, [currentlyPlaying, api, poster]); useEffect(() => { - if (!currentlyPlaying) { - ScreenOrientation.unlockAsync(); - progress.value = 0; - max.value = 0; - setShowControls(true); - setIsStatusBarHidden(false); - isSeeking.value = false; - } else { - setIsStatusBarHidden(true); - ScreenOrientation.lockAsync( - settings?.defaultVideoOrientation || - ScreenOrientation.OrientationLock.DEFAULT - ); + if (currentlyPlaying) { progress.value = currentlyPlaying.item?.UserData?.PlaybackPositionTicks || 0; max.value = currentlyPlaying.item.RunTimeTicks || 0; setShowControls(true); } - }, [currentlyPlaying, settings]); + }, [currentlyPlaying]); const toggleControls = () => setShowControls(!showControls); @@ -243,10 +257,10 @@ export const FullScreenVideoPlayer: React.FC = () => { [setIsPlaying] ); - const handlePlayPause = () => { + const handlePlayPause = useCallback(() => { if (isPlaying) pauseVideo(); else playVideo(); - }; + }, [isPlaying, pauseVideo, playVideo]); const handleSliderComplete = (value: number) => { progress.value = value; @@ -287,25 +301,25 @@ export const FullScreenVideoPlayer: React.FC = () => { } }, [settings]); - const handleGoToPreviousItem = () => { + const handleGoToPreviousItem = useCallback(() => { if (!previousItem || !from) return; const url = itemRouter(previousItem, from); stopPlayback(); // @ts-ignore router.push(url); - }; + }, [previousItem, from, stopPlayback, router]); - const handleGoToNextItem = () => { + const handleGoToNextItem = useCallback(() => { if (!nextItem || !from) return; const url = itemRouter(nextItem, from); stopPlayback(); // @ts-ignore router.push(url); - }; + }, [nextItem, from, stopPlayback, router]); - const toggleIgnoreSafeArea = () => { - setIgnoreSafeArea(!ignoreSafeArea); - }; + const toggleIgnoreSafeArea = useCallback(() => { + setIgnoreSafeArea((prev) => !prev); + }, []); const { data: introTimestamps } = useQuery({ queryKey: ["introTimestamps", currentlyPlaying?.item.Id], @@ -338,27 +352,26 @@ export const FullScreenVideoPlayer: React.FC = () => { enabled: !!currentlyPlaying?.item.Id, }); - const skipIntro = async () => { + const skipIntro = useCallback(async () => { if (!introTimestamps || !videoRef.current) return; try { videoRef.current.seek(introTimestamps.IntroEnd); } catch (error) { writeToLog("ERROR", "Error skipping intro", error); } - }; + }, [introTimestamps]); if (!currentlyPlaying) return null; return ( -