Add control visibility timeout and animation to video player components

This update introduces a timeout mechanism for hiding video player controls in both AndroidVideoPlayer and VideoPlayer components. The controls will fade out after 3 seconds of inactivity, enhancing user experience by keeping the interface clean. Additionally, the toggleControls function is updated to clear the timeout when controls are shown, ensuring that the controls remain visible as long as the user interacts with the player.
This commit is contained in:
tapframe 2025-06-21 02:14:13 +05:30
parent 7086184eae
commit cfb8ee56cf
2 changed files with 63 additions and 29 deletions

View file

@ -152,6 +152,15 @@ const AndroidVideoPlayer: React.FC = () => {
const [currentStreamProvider, setCurrentStreamProvider] = useState<string | undefined>(streamProvider); const [currentStreamProvider, setCurrentStreamProvider] = useState<string | undefined>(streamProvider);
const [currentStreamName, setCurrentStreamName] = useState<string | undefined>(streamName); const [currentStreamName, setCurrentStreamName] = useState<string | undefined>(streamName);
const isMounted = useRef(true); const isMounted = useRef(true);
const controlsTimeout = useRef<NodeJS.Timeout | null>(null);
const hideControls = () => {
Animated.timing(fadeAnim, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start(() => setShowControls(false));
};
const calculateVideoStyles = (videoWidth: number, videoHeight: number, screenWidth: number, screenHeight: number) => { const calculateVideoStyles = (videoWidth: number, videoHeight: number, screenWidth: number, screenHeight: number) => {
return { return {
@ -489,6 +498,7 @@ const AndroidVideoPlayer: React.FC = () => {
}, 1000); }, 1000);
} }
completeOpeningAnimation(); completeOpeningAnimation();
controlsTimeout.current = setTimeout(hideControls, 3000);
} }
}; };
@ -624,35 +634,41 @@ const AndroidVideoPlayer: React.FC = () => {
}; };
const handleStartFromBeginning = async () => { const handleStartFromBeginning = async () => {
if (rememberChoice) { if (DEBUG_MODE) logger.log("[AndroidVideoPlayer] Starting from beginning.");
try {
await AsyncStorage.setItem(RESUME_PREF_KEY, RESUME_PREF.ALWAYS_START_OVER);
} catch (error) {
logger.error('[AndroidVideoPlayer] Error saving resume preference:', error);
}
}
setShowResumeOverlay(false); setShowResumeOverlay(false);
setInitialPosition(0);
if (videoRef.current) { if (videoRef.current) {
seekToTime(0); seekToTime(0);
setCurrentTime(0); }
await resetResumePreference();
setPaused(false);
// Start playback
if (isMounted.current) {
setIsInitialSeekComplete(true);
} }
}; };
const toggleControls = () => { const toggleControls = () => {
setShowControls(previousState => !previousState); if (controlsTimeout.current) {
clearTimeout(controlsTimeout.current);
controlsTimeout.current = null;
}
setShowControls(prevShowControls => {
const newShowControls = !prevShowControls;
Animated.timing(fadeAnim, {
toValue: newShowControls ? 1 : 0,
duration: 300,
useNativeDriver: true,
}).start();
if (newShowControls) {
controlsTimeout.current = setTimeout(hideControls, 3000);
}
return newShowControls;
});
}; };
useEffect(() => {
Animated.timing(fadeAnim, {
toValue: showControls ? 1 : 0,
duration: 300,
useNativeDriver: true,
}).start();
}, [showControls]);
const handleError = (error: any) => { const handleError = (error: any) => {
logger.error('[AndroidVideoPlayer] Playback Error:', error); logger.error('AndroidVideoPlayer error: ', error);
}; };
const onBuffer = (data: any) => { const onBuffer = (data: any) => {

View file

@ -147,6 +147,15 @@ const VideoPlayer: React.FC = () => {
const [currentStreamProvider, setCurrentStreamProvider] = useState<string | undefined>(streamProvider); const [currentStreamProvider, setCurrentStreamProvider] = useState<string | undefined>(streamProvider);
const [currentStreamName, setCurrentStreamName] = useState<string | undefined>(streamName); const [currentStreamName, setCurrentStreamName] = useState<string | undefined>(streamName);
const isMounted = useRef(true); const isMounted = useRef(true);
const controlsTimeout = useRef<NodeJS.Timeout | null>(null);
const hideControls = () => {
Animated.timing(fadeAnim, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start(() => setShowControls(false));
};
const calculateVideoStyles = (videoWidth: number, videoHeight: number, screenWidth: number, screenHeight: number) => { const calculateVideoStyles = (videoWidth: number, videoHeight: number, screenWidth: number, screenHeight: number) => {
return { return {
@ -499,6 +508,7 @@ const VideoPlayer: React.FC = () => {
}, 1000); }, 1000);
} }
completeOpeningAnimation(); completeOpeningAnimation();
controlsTimeout.current = setTimeout(hideControls, 3000);
} }
}; };
@ -658,17 +668,25 @@ const VideoPlayer: React.FC = () => {
}; };
const toggleControls = () => { const toggleControls = () => {
setShowControls(previousState => !previousState); if (controlsTimeout.current) {
clearTimeout(controlsTimeout.current);
controlsTimeout.current = null;
}
setShowControls(prevShowControls => {
const newShowControls = !prevShowControls;
Animated.timing(fadeAnim, {
toValue: newShowControls ? 1 : 0,
duration: 300,
useNativeDriver: true,
}).start();
if (newShowControls) {
controlsTimeout.current = setTimeout(hideControls, 3000);
}
return newShowControls;
});
}; };
useEffect(() => {
Animated.timing(fadeAnim, {
toValue: showControls ? 1 : 0,
duration: 300,
useNativeDriver: true,
}).start();
}, [showControls]);
const handleError = (error: any) => { const handleError = (error: any) => {
logger.error('[VideoPlayer] Playback Error:', error); logger.error('[VideoPlayer] Playback Error:', error);
}; };