diff --git a/components/video-player/controls/AudioSlider.tsx b/components/video-player/controls/AudioSlider.tsx index 0fe613d3..6d579e0a 100644 --- a/components/video-player/controls/AudioSlider.tsx +++ b/components/video-player/controls/AudioSlider.tsx @@ -1,15 +1,21 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useRef } from "react"; import { View, StyleSheet } from "react-native"; import { useSharedValue } from "react-native-reanimated"; import { Slider } from "react-native-awesome-slider"; import { VolumeManager } from "react-native-volume-manager"; import { Ionicons } from "@expo/vector-icons"; -const AudioSlider = () => { +interface AudioSliderProps { + setVisibility: (show: boolean) => void; +} + +const AudioSlider: React.FC = ({ setVisibility }) => { const volume = useSharedValue(50); // Explicitly type as number const min = useSharedValue(0); // Explicitly type as number const max = useSharedValue(100); // Explicitly type as number + const timeoutRef = useRef(null); // Use a ref to store the timeout ID + useEffect(() => { const fetchInitialVolume = async () => { try { @@ -33,7 +39,7 @@ const AudioSlider = () => { const handleValueChange = async (value: number) => { volume.value = value; - console.log("volume", value); + console.log("volume through slider", value); await VolumeManager.setVolume(value / 100); // Re-call showNativeVolumeUI to ensure the setting is applied on iOS @@ -42,14 +48,28 @@ const AudioSlider = () => { useEffect(() => { const volumeListener = VolumeManager.addVolumeListener((result) => { - console.log("Volume changed:", result.volume); + console.log("Volume through device", result.volume); volume.value = result.volume * 100; + setVisibility(true); + + // Clear any existing timeout + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + // Set a new timeout to hide the visibility after 2 seconds + timeoutRef.current = setTimeout(() => { + setVisibility(false); + }, 1000); }); return () => { volumeListener.remove(); + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } }; - }, []); + }, [volume]); return ( diff --git a/components/video-player/controls/Controls.tsx b/components/video-player/controls/Controls.tsx index b875a859..95f22dfb 100644 --- a/components/video-player/controls/Controls.tsx +++ b/components/video-player/controls/Controls.tsx @@ -253,7 +253,14 @@ export const Controls: React.FC = ({ useEffect(() => { prefetchAllTrickplayImages(); }, []); - const toggleControls = () => setShowControls(!showControls); + const toggleControls = () => { + if (showControls) { + setShowAudioSlider(false); + setShowControls(false); + } else { + setShowControls(true); + } + }; const handleSliderStart = useCallback(() => { if (showControls === false) return; @@ -438,6 +445,9 @@ export const Controls: React.FC = ({ router.replace(`player/transcoding-player?${queryParams}`); }; + // Used when user changes audio through audio button on device. + const [showAudioSlider, setShowAudioSlider] = useState(false); + return ( = ({ alignItems: "center", transform: [{ translateY: -22.5 }], // Adjust for the button's height (half of 45) paddingHorizontal: "28%", // Add some padding to the left and right - opacity: showControls ? 1 : 0, }} pointerEvents={showControls ? "box-none" : "none"} > @@ -557,6 +566,7 @@ export const Controls: React.FC = ({ transform: [{ rotate: "270deg" }], // Rotate the slider to make it vertical left: 0, bottom: 30, + opacity: showControls ? 1 : 0, }} > @@ -567,6 +577,7 @@ export const Controls: React.FC = ({ position: "relative", justifyContent: "center", alignItems: "center", + opacity: showControls ? 1 : 0, }} > = ({ name={isPlaying ? "pause" : "play"} size={50} color="white" + style={{ + opacity: showControls ? 1 : 0, + }} /> ) : ( @@ -613,6 +627,7 @@ export const Controls: React.FC = ({ position: "relative", justifyContent: "center", alignItems: "center", + opacity: showControls ? 1 : 0, }} > @@ -637,9 +652,10 @@ export const Controls: React.FC = ({ transform: [{ rotate: "270deg" }], // Rotate the slider to make it vertical bottom: 30, right: 0, + opacity: showAudioSlider || showControls ? 1 : 0, }} > - + diff --git a/components/video-player/controls/contexts/ControlContext.tsx b/components/video-player/controls/contexts/ControlContext.tsx index 4d2a8df4..7847f0a9 100644 --- a/components/video-player/controls/contexts/ControlContext.tsx +++ b/components/video-player/controls/contexts/ControlContext.tsx @@ -1,6 +1,9 @@ -import { TrackInfo } from '@/modules/vlc-player'; -import { BaseItemDto, MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client'; -import React, { createContext, useContext, useState, ReactNode } from 'react'; +import { TrackInfo } from "@/modules/vlc-player"; +import { + BaseItemDto, + MediaSourceInfo, +} from "@jellyfin/sdk/lib/generated-client"; +import React, { createContext, useContext, useState, ReactNode } from "react"; interface ControlContextProps { item: BaseItemDto; @@ -8,7 +11,9 @@ interface ControlContextProps { isVideoLoaded: boolean | undefined; } -const ControlContext = createContext(undefined); +const ControlContext = createContext( + undefined +); interface ControlProviderProps { children: ReactNode; @@ -17,7 +22,12 @@ interface ControlProviderProps { isVideoLoaded: boolean | undefined; } -export const ControlProvider: React.FC = ({ children, item, mediaSource, isVideoLoaded }) => { +export const ControlProvider: React.FC = ({ + children, + item, + mediaSource, + isVideoLoaded, +}) => { return ( {children} @@ -28,7 +38,7 @@ export const ControlProvider: React.FC = ({ children, item export const useControlContext = () => { const context = useContext(ControlContext); if (context === undefined) { - throw new Error('useControlContext must be used within a ControlProvider'); + throw new Error("useControlContext must be used within a ControlProvider"); } return context; -}; \ No newline at end of file +};