From ea6698b6e419cae12055b4018d84881348bf00be Mon Sep 17 00:00:00 2001 From: Jorrin Date: Wed, 14 Feb 2024 17:43:35 +0100 Subject: [PATCH] cleanup brightness hooks --- apps/expo/src/app/videoPlayer/index.tsx | 78 +++++---------------- apps/expo/src/hooks/player/useBrightness.ts | 46 ++++++++++++ apps/expo/src/hooks/useDebounce.ts | 17 +++++ 3 files changed, 81 insertions(+), 60 deletions(-) create mode 100644 apps/expo/src/hooks/player/useBrightness.ts create mode 100644 apps/expo/src/hooks/useDebounce.ts diff --git a/apps/expo/src/app/videoPlayer/index.tsx b/apps/expo/src/app/videoPlayer/index.tsx index 96167d9..6ab8900 100644 --- a/apps/expo/src/app/videoPlayer/index.tsx +++ b/apps/expo/src/app/videoPlayer/index.tsx @@ -5,13 +5,11 @@ import { Dimensions, Platform, StyleSheet, - Text, View, } from "react-native"; import { Gesture, GestureDetector } from "react-native-gesture-handler"; import { runOnJS, useSharedValue } from "react-native-reanimated"; import { ResizeMode, Video } from "expo-av"; -import * as Brightness from "expo-brightness"; import * as NavigationBar from "expo-navigation-bar"; import { useLocalSearchParams, useRouter } from "expo-router"; import * as StatusBar from "expo-status-bar"; @@ -22,6 +20,8 @@ import { findHighestQuality } from "@movie-web/provider-utils"; import type { ItemData } from "~/components/item/item"; import type { HeaderData } from "~/components/player/Header"; import { ControlsOverlay } from "~/components/player/ControlsOverlay"; +import { Text } from "~/components/ui/Text"; +import { useBrightness } from "~/hooks/player/useBrightness"; import { usePlayerStore } from "~/stores/player/store"; export default function VideoPlayerWrapper() { @@ -43,16 +43,23 @@ interface VideoPlayerProps { } const VideoPlayer: React.FC = ({ data }) => { + const { + brightness, + debouncedBrightness, + showBrightnessOverlay, + setShowBrightnessOverlay, + handleBrightnessChange, + } = useBrightness(); const [videoSrc, setVideoSrc] = useState(); const [isLoading, setIsLoading] = useState(true); const [headerData, setHeaderData] = useState(); const [resizeMode, setResizeMode] = useState(ResizeMode.CONTAIN); const [shouldPlay, setShouldPlay] = useState(true); const [showVolumeOverlay, setShowVolumeOverlay] = useState(false); - const [showBrightnessOverlay, setShowBrightnessOverlay] = useState(false); const [currentVolume, setCurrentVolume] = useState(0.5); const router = useRouter(); const scale = useSharedValue(1); + const setVideoRef = usePlayerStore((state) => state.setVideoRef); const setStatus = usePlayerStore((state) => state.setStatus); const isIdle = usePlayerStore((state) => state.interface.isIdle); @@ -87,35 +94,15 @@ const VideoPlayer: React.FC = ({ data }) => { runOnJS(togglePlayback)(); }); - const brightness = useSharedValue(0.5); - const handleVolumeChange = (newValue: number) => { setCurrentVolume(newValue); setShowVolumeOverlay(true); setTimeout(() => setShowVolumeOverlay(false), 2000); }; - const handleBrightnessChange = async (newValue: number) => { - try { - await Brightness.setBrightnessAsync(newValue); - setShowBrightnessOverlay(true); - setTimeout(() => setShowBrightnessOverlay(false), 2000); - } catch (error) { - console.error("Failed to set brightness:", error); - } - }; - const screenHalfWidth = Dimensions.get("window").width / 2; const panGesture = Gesture.Pan() - .onStart((event) => { - const isRightHalf = event.x > screenHalfWidth; - if (isRightHalf) { - runOnJS(setCurrentVolume)(0.5); - } else { - brightness.value = 0.5; - } - }) .onUpdate((event) => { const divisor = 5000; if (event.x > screenHalfWidth) { @@ -131,6 +118,9 @@ const VideoPlayer: React.FC = ({ data }) => { brightness.value = newBrightness; runOnJS(handleBrightnessChange)(newBrightness); } + }) + .onEnd(() => { + runOnJS(setShowBrightnessOverlay)(false); }); const composedGesture = Gesture.Exclusive( @@ -152,18 +142,6 @@ const VideoPlayer: React.FC = ({ data }) => { await NavigationBar.setVisibilityAsync("hidden"); } - const { status } = await Brightness.requestPermissionsAsync(); - if (status !== Brightness.PermissionStatus.GRANTED) { - console.warn("Brightness permissions not granted"); - } - - try { - const currentBrightness = await Brightness.getBrightnessAsync(); - brightness.value = currentBrightness; - } catch (error) { - console.error("Failed to get initial brightness:", error); - } - setIsLoading(true); const { item, stream, media } = data; @@ -215,13 +193,7 @@ const VideoPlayer: React.FC = ({ data }) => { void NavigationBar.setVisibilityAsync("visible"); } }; - }, [ - brightness, - data, - dismissFullscreenPlayer, - presentFullscreenPlayer, - router, - ]); + }, [data, dismissFullscreenPlayer, presentFullscreenPlayer, router]); const onVideoLoadStart = () => { setIsLoading(true); @@ -251,17 +223,15 @@ const VideoPlayer: React.FC = ({ data }) => { )} {showVolumeOverlay && ( - - + + Volume: {Math.round(currentVolume * 100)}% )} {showBrightnessOverlay && ( - - - Brightness: {Math.round(brightness.value * 100)}% - + + Brightness: {debouncedBrightness} )} @@ -307,16 +277,4 @@ const styles = StyleSheet.create({ left: 0, right: 0, }, - overlay: { - position: "absolute", - bottom: 50, - alignSelf: "center", - backgroundColor: "rgba(0,0,0,0.5)", - padding: 10, - borderRadius: 5, - }, - overlayText: { - color: "#fff", - fontSize: 16, - }, }); diff --git a/apps/expo/src/hooks/player/useBrightness.ts b/apps/expo/src/hooks/player/useBrightness.ts new file mode 100644 index 0000000..844c4b2 --- /dev/null +++ b/apps/expo/src/hooks/player/useBrightness.ts @@ -0,0 +1,46 @@ +import { useCallback, useEffect, useState } from "react"; +import { useSharedValue } from "react-native-reanimated"; +import * as Brightness from "expo-brightness"; + +import { useDebounce } from "../useDebounce"; + +export const useBrightness = () => { + const [showBrightnessOverlay, setShowBrightnessOverlay] = useState(false); + const debouncedShowBrightnessOverlay = useDebounce(showBrightnessOverlay, 20); + const brightness = useSharedValue(0.5); + const debouncedBrightness = useDebounce(brightness.value, 20); + + useEffect(() => { + async function init() { + try { + const { status } = await Brightness.requestPermissionsAsync(); + if (status === Brightness.PermissionStatus.GRANTED) { + const currentBrightness = await Brightness.getBrightnessAsync(); + brightness.value = currentBrightness; + } + } catch (error) { + console.error("Failed to get brightness permissions:", error); + } + } + + void init(); + }, []); + + const handleBrightnessChange = useCallback(async (newValue: number) => { + try { + setShowBrightnessOverlay(true); + brightness.value = newValue; + await Brightness.setBrightnessAsync(newValue); + } catch (error) { + console.error("Failed to set brightness:", error); + } + }, []); + + return { + showBrightnessOverlay: debouncedShowBrightnessOverlay, + brightness, + debouncedBrightness: `${Math.round(debouncedBrightness * 100)}%`, + setShowBrightnessOverlay, + handleBrightnessChange, + } as const; +}; diff --git a/apps/expo/src/hooks/useDebounce.ts b/apps/expo/src/hooks/useDebounce.ts new file mode 100644 index 0000000..5b11976 --- /dev/null +++ b/apps/expo/src/hooks/useDebounce.ts @@ -0,0 +1,17 @@ +import { useEffect, useState } from "react"; + +export const useDebounce = (value: T, delay?: number): T => { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => { + setDebouncedValue(value); + }, delay ?? 500); + + return () => { + clearTimeout(timer); + }; + }, [value, delay]); + + return debouncedValue; +};