fixes to videoplayer

This commit is contained in:
tapframe 2025-07-17 14:18:40 +05:30
parent 42daa4decc
commit 19b6e6b3d5
3 changed files with 198 additions and 113 deletions

View file

@ -90,6 +90,14 @@ const VideoPlayer: React.FC = () => {
const screenData = Dimensions.get('screen');
const [screenDimensions, setScreenDimensions] = useState(screenData);
// iPad-specific fullscreen handling
const isIPad = Platform.OS === 'ios' && (screenData.width > 1000 || screenData.height > 1000);
const shouldUseFullscreen = isIPad;
// Use window dimensions for iPad instead of screen dimensions
const windowData = Dimensions.get('window');
const effectiveDimensions = shouldUseFullscreen ? windowData : screenData;
const [paused, setPaused] = useState(false);
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
@ -116,8 +124,8 @@ const VideoPlayer: React.FC = () => {
const openingScaleAnim = useRef(new Animated.Value(0.8)).current;
const backgroundFadeAnim = useRef(new Animated.Value(1)).current;
const [isBuffering, setIsBuffering] = useState(false);
const [vlcAudioTracks, setVlcAudioTracks] = useState<Array<{id: number, name: string, language?: string}>>([]);
const [vlcTextTracks, setVlcTextTracks] = useState<Array<{id: number, name: string, language?: string}>>([]);
const [vlcAudioTracks, setVlcAudioTracks] = useState<Array<{ id: number, name: string, language?: string }>>([]);
const [vlcTextTracks, setVlcTextTracks] = useState<Array<{ id: number, name: string, language?: string }>>([]);
const [isPlayerReady, setIsPlayerReady] = useState(false);
const progressAnim = useRef(new Animated.Value(0)).current;
const progressBarRef = useRef<View>(null);
@ -140,6 +148,7 @@ const VideoPlayer: React.FC = () => {
const [customSubtitles, setCustomSubtitles] = useState<SubtitleCue[]>([]);
const [currentSubtitle, setCurrentSubtitle] = useState<string>('');
const [subtitleSize, setSubtitleSize] = useState<number>(DEFAULT_SUBTITLE_SIZE);
const [subtitleBackground, setSubtitleBackground] = useState<boolean>(true);
const [useCustomSubtitles, setUseCustomSubtitles] = useState<boolean>(false);
const [isLoadingSubtitles, setIsLoadingSubtitles] = useState<boolean>(false);
const [availableSubtitles, setAvailableSubtitles] = useState<WyzieSubtitle[]>([]);
@ -224,25 +233,47 @@ const VideoPlayer: React.FC = () => {
};
useEffect(() => {
if (videoAspectRatio && screenDimensions.width > 0 && screenDimensions.height > 0) {
if (videoAspectRatio && effectiveDimensions.width > 0 && effectiveDimensions.height > 0) {
const styles = calculateVideoStyles(
videoAspectRatio * 1000,
1000,
screenDimensions.width,
screenDimensions.height
effectiveDimensions.width,
effectiveDimensions.height
);
setCustomVideoStyles(styles);
if (DEBUG_MODE) {
logger.log(`[VideoPlayer] Screen dimensions changed, recalculated styles:`, styles);
}
}
}, [screenDimensions, videoAspectRatio]);
}, [effectiveDimensions, videoAspectRatio]);
// Force landscape orientation immediately when component mounts
useEffect(() => {
const lockOrientation = async () => {
try {
await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE);
logger.log('[VideoPlayer] Locked to landscape orientation');
} catch (error) {
logger.warn('[VideoPlayer] Failed to lock orientation:', error);
}
};
// Lock orientation immediately
lockOrientation();
return () => {
// Unlock orientation when component unmounts
ScreenOrientation.unlockAsync().catch(() => {
// Ignore unlock errors
});
};
}, []);
useEffect(() => {
const subscription = Dimensions.addEventListener('change', ({ screen }) => {
setScreenDimensions(screen);
});
const initializePlayer = () => {
const initializePlayer = async () => {
StatusBar.setHidden(true, 'none');
enableImmersiveMode();
startOpeningAnimation();
@ -250,10 +281,6 @@ const VideoPlayer: React.FC = () => {
initializePlayer();
return () => {
subscription?.remove();
const unlockOrientation = async () => {
await ScreenOrientation.unlockAsync();
};
unlockOrientation();
disableImmersiveMode();
};
}, []);
@ -461,7 +488,7 @@ const VideoPlayer: React.FC = () => {
isSeeking.current = false;
if (DEBUG_MODE) {
logger.log(`[VideoPlayer] Android seek completed to ${timeInSeconds.toFixed(2)}s`);
}
}
}
}, 500);
} else {
@ -685,22 +712,53 @@ const VideoPlayer: React.FC = () => {
}),
]).start();
// Longer delay to ensure Trakt sync completes
setTimeout(() => {
ScreenOrientation.unlockAsync().then(() => {
disableImmersiveMode();
navigation.goBack();
}).catch(() => {
// Fallback: navigate even if orientation unlock fails
disableImmersiveMode();
navigation.goBack();
});
}, 500); // Increased from 100ms to 500ms
// Cleanup and navigate back
const cleanup = async () => {
try {
// Unlock orientation first
await ScreenOrientation.unlockAsync();
logger.log('[VideoPlayer] Orientation unlocked');
} catch (orientationError) {
logger.warn('[VideoPlayer] Failed to unlock orientation:', orientationError);
}
// Disable immersive mode
disableImmersiveMode();
// Navigate back with proper handling for fullscreen modal
try {
if (navigation.canGoBack()) {
navigation.goBack();
} else {
// Fallback: navigate to main tabs if can't go back
navigation.navigate('MainTabs');
}
logger.log('[VideoPlayer] Navigation completed');
} catch (navError) {
logger.error('[VideoPlayer] Navigation error:', navError);
// Last resort: try to navigate to home
navigation.navigate('MainTabs');
}
};
// Delay to ensure Trakt sync completes and animations finish
setTimeout(cleanup, 500);
} catch (error) {
logger.error('[VideoPlayer] Error syncing to Trakt before closing:', error);
// Navigate anyway even if sync fails
disableImmersiveMode();
navigation.goBack();
try {
await ScreenOrientation.unlockAsync();
} catch (orientationError) {
// Ignore orientation unlock errors
}
if (navigation.canGoBack()) {
navigation.goBack();
} else {
navigation.navigate('MainTabs');
}
}
};
@ -864,7 +922,7 @@ const VideoPlayer: React.FC = () => {
const togglePlayback = () => {
if (vlcRef.current) {
setPaused(!paused);
setPaused(!paused);
}
};
@ -912,6 +970,10 @@ const VideoPlayer: React.FC = () => {
saveSubtitleSize(newSize);
};
const toggleSubtitleBackground = () => {
setSubtitleBackground(prev => !prev);
};
useEffect(() => {
if (pendingSeek && isPlayerReady && isVideoLoaded && duration > 0) {
logger.log(`[VideoPlayer] Player ready after source change, seeking to position: ${pendingSeek.position}s out of ${duration}s total`);
@ -1019,13 +1081,21 @@ const VideoPlayer: React.FC = () => {
};
return (
<View style={[styles.container, {
width: screenDimensions.width,
height: screenDimensions.height,
position: 'absolute',
top: 0,
left: 0,
}]}>
<View style={[
styles.container,
shouldUseFullscreen ? {
// iPad fullscreen: use flex layout instead of absolute positioning
flex: 1,
width: '100%',
height: '100%',
} : {
// iPhone: use absolute positioning with screen dimensions
width: screenDimensions.width,
height: screenDimensions.height,
position: 'absolute',
top: 0,
left: 0,
}]}>
<Animated.View
style={[
styles.openingOverlay,
@ -1210,6 +1280,7 @@ const VideoPlayer: React.FC = () => {
useCustomSubtitles={useCustomSubtitles}
currentSubtitle={currentSubtitle}
subtitleSize={subtitleSize}
subtitleBackground={subtitleBackground}
zoomScale={zoomScale}
/>
@ -1246,11 +1317,13 @@ const VideoPlayer: React.FC = () => {
selectedTextTrack={selectedTextTrack}
useCustomSubtitles={useCustomSubtitles}
subtitleSize={subtitleSize}
subtitleBackground={subtitleBackground}
fetchAvailableSubtitles={fetchAvailableSubtitles}
loadWyzieSubtitle={loadWyzieSubtitle}
selectTextTrack={selectTextTrack}
increaseSubtitleSize={increaseSubtitleSize}
decreaseSubtitleSize={decreaseSubtitleSize}
toggleSubtitleBackground={toggleSubtitleBackground}
/>
<SourcesModal

View file

@ -3,6 +3,7 @@ import { StyleSheet } from 'react-native';
export const styles = StyleSheet.create({
container: {
backgroundColor: '#000',
flex: 1,
position: 'absolute',
top: 0,
left: 0,

View file

@ -770,9 +770,20 @@ const AppNavigator = ({ initialRouteName }: { initialRouteName?: keyof RootStack
options={{
animation: 'slide_from_right',
animationDuration: Platform.OS === 'android' ? 200 : 300,
// Force fullscreen presentation on iPad
presentation: Platform.OS === 'ios' ? 'fullScreenModal' : 'card',
// Disable gestures during video playback
gestureEnabled: false,
// Ensure proper orientation handling
orientation: 'landscape',
contentStyle: {
backgroundColor: '#000000', // Pure black for video player
},
// iPad-specific fullscreen options
...(Platform.OS === 'ios' && {
statusBarHidden: true,
statusBarAnimation: 'none',
}),
}}
/>
<Stack.Screen