volume cleanup

This commit is contained in:
Jorrin
2024-02-14 20:00:36 +01:00
parent 82a3f431fa
commit c670047713
6 changed files with 70 additions and 28 deletions

View File

@@ -22,6 +22,7 @@ import type { HeaderData } from "~/components/player/Header";
import { ControlsOverlay } from "~/components/player/ControlsOverlay"; import { ControlsOverlay } from "~/components/player/ControlsOverlay";
import { Text } from "~/components/ui/Text"; import { Text } from "~/components/ui/Text";
import { useBrightness } from "~/hooks/player/useBrightness"; import { useBrightness } from "~/hooks/player/useBrightness";
import { useVolume } from "~/hooks/player/useVolume";
import { usePlayerStore } from "~/stores/player/store"; import { usePlayerStore } from "~/stores/player/store";
export default function VideoPlayerWrapper() { export default function VideoPlayerWrapper() {
@@ -50,13 +51,18 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
setShowBrightnessOverlay, setShowBrightnessOverlay,
handleBrightnessChange, handleBrightnessChange,
} = useBrightness(); } = useBrightness();
const {
currentVolume,
debouncedVolume,
showVolumeOverlay,
setShowVolumeOverlay,
handleVolumeChange,
} = useVolume();
const [videoSrc, setVideoSrc] = useState<AVPlaybackSource>(); const [videoSrc, setVideoSrc] = useState<AVPlaybackSource>();
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [headerData, setHeaderData] = useState<HeaderData>(); const [headerData, setHeaderData] = useState<HeaderData>();
const [resizeMode, setResizeMode] = useState(ResizeMode.CONTAIN); const [resizeMode, setResizeMode] = useState(ResizeMode.CONTAIN);
const [shouldPlay, setShouldPlay] = useState(true); const [shouldPlay, setShouldPlay] = useState(true);
const [showVolumeOverlay, setShowVolumeOverlay] = useState(false);
const [currentVolume, setCurrentVolume] = useState(0.5);
const router = useRouter(); const router = useRouter();
const scale = useSharedValue(1); const scale = useSharedValue(1);
@@ -94,20 +100,20 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
runOnJS(togglePlayback)(); runOnJS(togglePlayback)();
}); });
const handleVolumeChange = (newValue: number) => {
setCurrentVolume(newValue);
setShowVolumeOverlay(true);
setTimeout(() => setShowVolumeOverlay(false), 2000);
};
const screenHalfWidth = Dimensions.get("window").width / 2; const screenHalfWidth = Dimensions.get("window").width / 2;
const panGesture = Gesture.Pan() const panGesture = Gesture.Pan()
.onUpdate((event) => { .onUpdate((event) => {
const divisor = 5000; const divisor = 5000;
const dragIsNotInHeaderOrFooter = event.y < 100 || event.y > 400;
if (dragIsNotInHeaderOrFooter) return;
if (event.x > screenHalfWidth) { if (event.x > screenHalfWidth) {
const change = -event.translationY / divisor; const change = -event.translationY / divisor;
const newVolume = Math.max(0, Math.min(1, currentVolume + change)); const newVolume = Math.max(
0,
Math.min(1, currentVolume.value + change),
);
runOnJS(handleVolumeChange)(newVolume); runOnJS(handleVolumeChange)(newVolume);
} else { } else {
const change = -event.translationY / divisor; const change = -event.translationY / divisor;
@@ -120,6 +126,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
} }
}) })
.onEnd(() => { .onEnd(() => {
runOnJS(setShowVolumeOverlay)(false);
runOnJS(setShowBrightnessOverlay)(false); runOnJS(setShowBrightnessOverlay)(false);
}); });
@@ -211,7 +218,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
source={videoSrc} source={videoSrc}
shouldPlay={shouldPlay} shouldPlay={shouldPlay}
resizeMode={resizeMode} resizeMode={resizeMode}
volume={currentVolume} volume={currentVolume.value}
onLoadStart={onVideoLoadStart} onLoadStart={onVideoLoadStart}
onReadyForDisplay={onReadyForDisplay} onReadyForDisplay={onReadyForDisplay}
onPlaybackStatusUpdate={setStatus} onPlaybackStatusUpdate={setStatus}
@@ -224,9 +231,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
)} )}
{showVolumeOverlay && ( {showVolumeOverlay && (
<View className="absolute bottom-12 self-center rounded-xl bg-black p-3 opacity-50"> <View className="absolute bottom-12 self-center rounded-xl bg-black p-3 opacity-50">
<Text className="text-bold"> <Text className="font-bold">Volume: {debouncedVolume}</Text>
Volume: {Math.round(currentVolume * 100)}%
</Text>
</View> </View>
)} )}
{showBrightnessOverlay && ( {showBrightnessOverlay && (

View File

@@ -18,12 +18,12 @@ export const ControlsOverlay = ({ headerData }: ControlsOverlayProps) => {
setIsIdle(!idle); setIsIdle(!idle);
}; };
return ( return (
<TouchableWithoutFeedback onPress={handleTouch}>
<View className="absolute left-0 top-0 flex h-full w-full flex-1"> <View className="absolute left-0 top-0 flex h-full w-full flex-1">
<Header data={headerData} /> <Header data={headerData} />
<TouchableWithoutFeedback onPress={handleTouch}>
<MiddleControls /> <MiddleControls />
</TouchableWithoutFeedback>
<BottomControls /> <BottomControls />
</View> </View>
</TouchableWithoutFeedback>
); );
}; };

View File

@@ -1,4 +1,4 @@
import { View } from "react-native"; import { StyleSheet, View } from "react-native";
import { Controls } from "./Controls"; import { Controls } from "./Controls";
import { PlayButton } from "./PlayButton"; import { PlayButton } from "./PlayButton";
@@ -6,8 +6,8 @@ import { SeekButton } from "./SeekButton";
export const MiddleControls = () => { export const MiddleControls = () => {
return ( return (
<View className="flex flex-1 flex-row items-center justify-center gap-24"> <View style={styles.container}>
<Controls> <Controls className="mr-24">
<SeekButton type="backward" /> <SeekButton type="backward" />
</Controls> </Controls>
<Controls> <Controls>
@@ -19,3 +19,13 @@ export const MiddleControls = () => {
</View> </View>
); );
}; };
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: 82,
},
});

View File

@@ -1,5 +1,5 @@
import { useCallback } from "react"; import { useCallback } from "react";
import { View } from "react-native"; import { TouchableOpacity } from "react-native";
import { usePlayerStore } from "~/stores/player/store"; import { usePlayerStore } from "~/stores/player/store";
import VideoSlider from "./VideoSlider"; import VideoSlider from "./VideoSlider";
@@ -7,6 +7,7 @@ import VideoSlider from "./VideoSlider";
export const ProgressBar = () => { export const ProgressBar = () => {
const status = usePlayerStore((state) => state.status); const status = usePlayerStore((state) => state.status);
const videoRef = usePlayerStore((state) => state.videoRef); const videoRef = usePlayerStore((state) => state.videoRef);
const setIsIdle = usePlayerStore((state) => state.setIsIdle);
const updateProgress = useCallback( const updateProgress = useCallback(
(newProgress: number) => { (newProgress: number) => {
@@ -19,9 +20,12 @@ export const ProgressBar = () => {
if (status?.isLoaded) { if (status?.isLoaded) {
return ( return (
<View className="flex h-10 flex-1 items-center justify-center p-8"> <TouchableOpacity
className="flex h-10 flex-1 items-center justify-center p-8"
onPress={() => setIsIdle(false)}
>
<VideoSlider onSlidingComplete={updateProgress} /> <VideoSlider onSlidingComplete={updateProgress} />
</View> </TouchableOpacity>
); );
} }
}; };

View File

@@ -31,6 +31,8 @@ interface VideoSliderProps {
} }
const VideoSlider = ({ onSlidingComplete }: VideoSliderProps) => { const VideoSlider = ({ onSlidingComplete }: VideoSliderProps) => {
const tapRef = useRef<TapGestureHandler>(null);
const panRef = useRef<PanGestureHandler>(null);
const status = usePlayerStore((state) => state.status); const status = usePlayerStore((state) => state.status);
const width = Dimensions.get("screen").width - 200; const width = Dimensions.get("screen").width - 200;
@@ -52,9 +54,6 @@ const VideoSlider = ({ onSlidingComplete }: VideoSliderProps) => {
const valueX = valueToX(value); const valueX = valueToX(value);
const translateX = useSharedValue(valueToX(value)); const translateX = useSharedValue(valueToX(value));
const tapRef = useRef<TapGestureHandler>(null);
const panRef = useRef<PanGestureHandler>(null);
useEffect(() => { useEffect(() => {
translateX.value = clamp(valueX, 0, width - knobSize_); translateX.value = clamp(valueX, 0, width - knobSize_);
}, [valueX]); }, [valueX]);

View File

@@ -0,0 +1,24 @@
import { useCallback, useState } from "react";
import { useSharedValue } from "react-native-reanimated";
import { useDebounce } from "../useDebounce";
export const useVolume = () => {
const [showVolumeOverlay, setShowVolumeOverlay] = useState(false);
const debouncedShowVolumeOverlay = useDebounce(showVolumeOverlay, 20);
const volume = useSharedValue(1);
const debouncedVolume = useDebounce(volume.value, 20);
const handleVolumeChange = useCallback((newValue: number) => {
volume.value = newValue;
setShowVolumeOverlay(true);
}, []);
return {
showVolumeOverlay: debouncedShowVolumeOverlay,
currentVolume: volume,
debouncedVolume: `${Math.round(debouncedVolume * 100)}%`,
setShowVolumeOverlay,
handleVolumeChange,
} as const;
};