From 0d2b33a9956eca2092cb9e29843a88a6ca099d31 Mon Sep 17 00:00:00 2001 From: tapframe Date: Sun, 8 Jun 2025 16:12:33 +0530 Subject: [PATCH] Refactor VideoPlayer component to improve loading animations and state management This update disables the debug mode for production and introduces a new state to track video loading status. The opening animation sequence has been modified to wait for the video to load before displaying the player, enhancing the user experience during playback. Additionally, unnecessary code related to seeking has been removed for clarity and performance improvements. --- src/screens/VideoPlayer.tsx | 116 ++++++++++++++---------------------- 1 file changed, 45 insertions(+), 71 deletions(-) diff --git a/src/screens/VideoPlayer.tsx b/src/screens/VideoPlayer.tsx index 90f81da..1f65cee 100644 --- a/src/screens/VideoPlayer.tsx +++ b/src/screens/VideoPlayer.tsx @@ -22,7 +22,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; // Debug flag - set back to false to disable verbose logging // WARNING: Setting this to true currently causes infinite render loops // Use selective logging instead if debugging is needed -const DEBUG_MODE = true; +const DEBUG_MODE = false; // Safer debug function that won't cause render loops // Call this with any debugging info you need instead of using inline DEBUG_MODE checks @@ -276,6 +276,9 @@ const VideoPlayer: React.FC = () => { const pendingSeekValue = useRef(null); const lastSeekTime = useRef(0); + // Add state for tracking if the video is loaded + const [isVideoLoaded, setIsVideoLoaded] = useState(false); + // Lock screen to landscape when component mounts useEffect(() => { // Since orientation is now locked before navigation, we can start immediately @@ -299,40 +302,44 @@ const VideoPlayer: React.FC = () => { }; }, []); - // Opening animation sequence + // Opening animation sequence - modified to wait for video load const startOpeningAnimation = () => { - // Much shorter delay since rotation is already handled - setTimeout(() => { - // Start the main animation sequence - Animated.parallel([ - // Fade in the video player - Animated.timing(openingFadeAnim, { - toValue: 1, - duration: 600, // Reduced back to original duration - useNativeDriver: true, - }), - // Scale up from 80% to 100% - Animated.timing(openingScaleAnim, { - toValue: 1, - duration: 700, // Reduced back to original duration - useNativeDriver: true, - }), - // Fade out the black background overlay - Animated.timing(backgroundFadeAnim, { - toValue: 0, - duration: 800, // Reduced back to original duration - useNativeDriver: true, - }), - ]).start(() => { - // Animation is complete - setIsOpeningAnimationComplete(true); - - // Hide the background overlay completely after animation - setTimeout(() => { - backgroundFadeAnim.setValue(0); - }, 100); - }); - }, 150); // Much shorter delay since no rotation is needed + // Keep everything black until video loads + // Only show loading indicator, no video player fade-in yet + // Note: All animations will be triggered by onLoad when video is ready + }; + + // Complete the opening animation when video loads + const completeOpeningAnimation = () => { + // Start all animations together when video is ready + Animated.parallel([ + // Fade in the video player + Animated.timing(openingFadeAnim, { + toValue: 1, + duration: 600, + useNativeDriver: true, + }), + // Scale up from 80% to 100% + Animated.timing(openingScaleAnim, { + toValue: 1, + duration: 700, + useNativeDriver: true, + }), + // Fade out the black background overlay + Animated.timing(backgroundFadeAnim, { + toValue: 0, + duration: 800, + useNativeDriver: true, + }), + ]).start(() => { + // Animation is complete + setIsOpeningAnimationComplete(true); + + // Hide the background overlay completely after animation + setTimeout(() => { + backgroundFadeAnim.setValue(0); + }, 100); + }); }; // Load saved watch progress on mount @@ -465,19 +472,6 @@ const VideoPlayer: React.FC = () => { } }; - // Replace the reset seek value effect - // useEffect(() => { - // if (seekValue !== undefined) { - // const timer = setTimeout(() => { - // if (isMounted.current) { - // setSeekValue(undefined); - // } - // }, 1000); // Longer timeout to ensure VLC processes the seek properly - - // return () => clearTimeout(timer); - // } - // }, [seekValue]); - // Simplify the seekToTime function to use VLC's direct methods const seekToTime = (timeInSeconds: number) => { if (!isPlayerReady || duration <= 0 || !vlcRef.current) return; @@ -501,11 +495,6 @@ const VideoPlayer: React.FC = () => { } else { logger.error('[VideoPlayer] No seek method available on VLC player'); } - - // Update UI immediately for responsiveness - const progressPercent = timeInSeconds / duration; - progressAnim.setValue(progressPercent); - } catch (error) { logger.error('[VideoPlayer] Error during seek operation:', error); } @@ -586,13 +575,16 @@ const VideoPlayer: React.FC = () => { } }, 1000); } + + // Mark video as loaded and complete opening animation + setIsVideoLoaded(true); + completeOpeningAnimation(); }; const skip = (seconds: number) => { if (vlcRef.current) { const newTime = Math.max(0, Math.min(currentTime + seconds, duration)); seekToTime(newTime); - // Let seekToTime handle all state updates } }; @@ -679,24 +671,6 @@ const VideoPlayer: React.FC = () => { } }, [showSubtitleModal, textTracks]); - // Attempt to seek once vlcRef is available - useEffect(() => { - if (initialPosition !== null && !isInitialSeekComplete && vlcRef.current) { - if (DEBUG_MODE) { - logger.log(`[VideoPlayer] vlcRef is now available, attempting to seek to: ${initialPosition}`); - } - try { - seekToTime(initialPosition); - setIsInitialSeekComplete(true); - if (DEBUG_MODE) { - logger.log(`[VideoPlayer] Successfully seeked to position: ${initialPosition}`); - } - } catch (error) { - logger.error('[VideoPlayer] Error seeking to position on ref available:', error); - } - } - }, [vlcRef.current, initialPosition, isInitialSeekComplete]); - // Load resume preference on mount useEffect(() => { const loadResumePreference = async () => {