diff --git a/src/components/player/AndroidVideoPlayer.tsx b/src/components/player/AndroidVideoPlayer.tsx index 74f1c3bd..84876c52 100644 --- a/src/components/player/AndroidVideoPlayer.tsx +++ b/src/components/player/AndroidVideoPlayer.tsx @@ -106,6 +106,7 @@ const AndroidVideoPlayer: React.FC = () => { const [isInitialSeekComplete, setIsInitialSeekComplete] = useState(false); const [showResumeOverlay, setShowResumeOverlay] = useState(false); const [resumePosition, setResumePosition] = useState(null); + const [savedDuration, setSavedDuration] = useState(null); const [rememberChoice, setRememberChoice] = useState(false); const [resumePreference, setResumePreference] = useState(null); const fadeAnim = useRef(new Animated.Value(1)).current; @@ -279,7 +280,8 @@ const AndroidVideoPlayer: React.FC = () => { if (progressPercent < 85) { setResumePosition(savedProgress.currentTime); - logger.log(`[AndroidVideoPlayer] Set resume position to: ${savedProgress.currentTime}`); + setSavedDuration(savedProgress.duration); + logger.log(`[AndroidVideoPlayer] Set resume position to: ${savedProgress.currentTime} of ${savedProgress.duration}`); const pref = await AsyncStorage.getItem(RESUME_PREF_KEY); logger.log(`[AndroidVideoPlayer] Resume preference: ${pref}`); @@ -357,22 +359,25 @@ const AndroidVideoPlayer: React.FC = () => { const seekToTime = (timeInSeconds: number) => { if (videoRef.current && duration > 0 && !isSeeking.current) { if (DEBUG_MODE) { - logger.log(`[AndroidVideoPlayer] Seeking to ${timeInSeconds.toFixed(2)}s`); + logger.log(`[AndroidVideoPlayer] Seeking to ${timeInSeconds.toFixed(2)}s out of ${duration.toFixed(2)}s`); } isSeeking.current = true; setSeekTime(timeInSeconds); - // Clear seek state after seek + // Clear seek state after seek with longer timeout setTimeout(() => { if (isMounted.current) { setSeekTime(null); isSeeking.current = false; + if (DEBUG_MODE) { + logger.log(`[AndroidVideoPlayer] Seek completed to ${timeInSeconds.toFixed(2)}s`); + } } - }, 100); + }, 500); } else { if (DEBUG_MODE) { - logger.error('[AndroidVideoPlayer] Seek failed: Player not ready, duration is zero, or already seeking.'); + logger.error(`[AndroidVideoPlayer] Seek failed: videoRef=${!!videoRef.current}, duration=${duration}, seeking=${isSeeking.current}`); } } }; @@ -615,7 +620,9 @@ const AndroidVideoPlayer: React.FC = () => { }; const handleResume = async () => { - if (resumePosition !== null && videoRef.current) { + if (resumePosition !== null) { + logger.log(`[AndroidVideoPlayer] Resume requested to position: ${resumePosition}s, duration: ${duration}, isPlayerReady: ${isPlayerReady}`); + if (rememberChoice) { try { await AsyncStorage.setItem(RESUME_PREF_KEY, RESUME_PREF.ALWAYS_RESUME); @@ -623,13 +630,18 @@ const AndroidVideoPlayer: React.FC = () => { logger.error('[AndroidVideoPlayer] Error saving resume preference:', error); } } - setInitialPosition(resumePosition); + setShowResumeOverlay(false); - setTimeout(() => { - if (videoRef.current) { - seekToTime(resumePosition); - } - }, 500); + + // If video is already loaded and ready, seek immediately + if (isPlayerReady && duration > 0 && videoRef.current) { + logger.log(`[AndroidVideoPlayer] Video ready, seeking immediately to: ${resumePosition}s`); + seekToTime(resumePosition); + } else { + // Otherwise, set initial position for when video loads + logger.log(`[AndroidVideoPlayer] Video not ready, setting initial position: ${resumePosition}s`); + setInitialPosition(resumePosition); + } } }; @@ -1091,7 +1103,7 @@ const AndroidVideoPlayer: React.FC = () => { { const [isInitialSeekComplete, setIsInitialSeekComplete] = useState(false); const [showResumeOverlay, setShowResumeOverlay] = useState(false); const [resumePosition, setResumePosition] = useState(null); + const [savedDuration, setSavedDuration] = useState(null); const [rememberChoice, setRememberChoice] = useState(false); const [resumePreference, setResumePreference] = useState(null); const fadeAnim = useRef(new Animated.Value(1)).current; @@ -274,18 +275,13 @@ const VideoPlayer: React.FC = () => { if (progressPercent < 85) { setResumePosition(savedProgress.currentTime); - logger.log(`[VideoPlayer] Set resume position to: ${savedProgress.currentTime}`); + setSavedDuration(savedProgress.duration); + logger.log(`[VideoPlayer] Set resume position to: ${savedProgress.currentTime} of ${savedProgress.duration}`); const pref = await AsyncStorage.getItem(RESUME_PREF_KEY); logger.log(`[VideoPlayer] Resume preference: ${pref}`); - // TEMPORARY: Clear the preference to test overlay - if (pref) { - await AsyncStorage.removeItem(RESUME_PREF_KEY); - logger.log(`[VideoPlayer] CLEARED resume preference for testing`); - setShowResumeOverlay(true); - logger.log(`[VideoPlayer] Showing resume overlay after clearing preference`); - } else if (pref === RESUME_PREF.ALWAYS_RESUME) { + if (pref === RESUME_PREF.ALWAYS_RESUME) { setInitialPosition(savedProgress.currentTime); logger.log(`[VideoPlayer] Auto-resuming due to preference`); } else if (pref === RESUME_PREF.ALWAYS_START_OVER) { @@ -375,7 +371,7 @@ const VideoPlayer: React.FC = () => { const seekToTime = (timeInSeconds: number) => { if (vlcRef.current && duration > 0 && !isSeeking.current) { if (DEBUG_MODE) { - logger.log(`[VideoPlayer] Seeking to ${timeInSeconds.toFixed(2)}s`); + logger.log(`[VideoPlayer] Seeking to ${timeInSeconds.toFixed(2)}s out of ${duration.toFixed(2)}s`); } isSeeking.current = true; @@ -390,8 +386,11 @@ const VideoPlayer: React.FC = () => { setTimeout(() => { if (isMounted.current) { isSeeking.current = false; + if (DEBUG_MODE) { + logger.log(`[VideoPlayer] Android seek completed to ${timeInSeconds.toFixed(2)}s`); + } } - }, 300); + }, 500); } else { // iOS fallback - use seek prop const position = timeInSeconds / duration; @@ -401,12 +400,15 @@ const VideoPlayer: React.FC = () => { if (isMounted.current) { setSeekPosition(null); isSeeking.current = false; + if (DEBUG_MODE) { + logger.log(`[VideoPlayer] iOS seek completed to ${timeInSeconds.toFixed(2)}s`); + } } }, 500); } } else { if (DEBUG_MODE) { - logger.error('[VideoPlayer] Seek failed: Player not ready, duration is zero, or already seeking.'); + logger.error(`[VideoPlayer] Seek failed: vlcRef=${!!vlcRef.current}, duration=${duration}, seeking=${isSeeking.current}`); } } }; @@ -633,7 +635,9 @@ const VideoPlayer: React.FC = () => { }; const handleResume = async () => { - if (resumePosition !== null && vlcRef.current) { + if (resumePosition !== null) { + logger.log(`[VideoPlayer] Resume requested to position: ${resumePosition}s, duration: ${duration}, isPlayerReady: ${isPlayerReady}`); + if (rememberChoice) { try { await AsyncStorage.setItem(RESUME_PREF_KEY, RESUME_PREF.ALWAYS_RESUME); @@ -641,13 +645,18 @@ const VideoPlayer: React.FC = () => { logger.error('[VideoPlayer] Error saving resume preference:', error); } } - setInitialPosition(resumePosition); + setShowResumeOverlay(false); - setTimeout(() => { - if (vlcRef.current) { - seekToTime(resumePosition); - } - }, 500); + + // If video is already loaded and ready, seek immediately + if (isPlayerReady && duration > 0 && vlcRef.current) { + logger.log(`[VideoPlayer] Video ready, seeking immediately to: ${resumePosition}s`); + seekToTime(resumePosition); + } else { + // Otherwise, set initial position for when video loads + logger.log(`[VideoPlayer] Video not ready, setting initial position: ${resumePosition}s`); + setInitialPosition(resumePosition); + } } }; @@ -1110,7 +1119,7 @@ const VideoPlayer: React.FC = () => {