diff --git a/src/components/player/AndroidVideoPlayer.tsx b/src/components/player/AndroidVideoPlayer.tsx index 11c8fc0..4dc1857 100644 --- a/src/components/player/AndroidVideoPlayer.tsx +++ b/src/components/player/AndroidVideoPlayer.tsx @@ -781,15 +781,12 @@ const AndroidVideoPlayer: React.FC = () => { } disableImmersiveMode(); - // For series, reset to streams screen for current episode to ensure no hidden players remain on the stack + // For series, hard reset to a single Streams route to avoid stacking multiple modals/pages if (type === 'series' && id && episodeId) { (navigation as any).reset({ index: 0, routes: [ - { - name: 'Streams', - params: { id, type: 'series', episodeId } - } + { name: 'Streams', params: { id, type: 'series', episodeId } } ] }); } else { @@ -804,15 +801,12 @@ const AndroidVideoPlayer: React.FC = () => { } disableImmersiveMode(); - // For series, reset to streams screen for current episode to ensure no hidden players remain on the stack + // For series, hard reset to a single Streams route to avoid stacking multiple modals/pages if (type === 'series' && id && episodeId) { (navigation as any).reset({ index: 0, routes: [ - { - name: 'Streams', - params: { id, type: 'series', episodeId } - } + { name: 'Streams', params: { id, type: 'series', episodeId } } ] }); } else { @@ -1418,7 +1412,7 @@ const AndroidVideoPlayer: React.FC = () => { // Handle next episode button visibility based on current time and next episode availability useEffect(() => { - if ((type as any) !== 'series' || !nextEpisode || duration <= 0 || isLoadingNextEpisode) { + if ((type as any) !== 'series' || !nextEpisode || duration <= 0) { if (showNextEpisodeButton) { // Hide button with animation Animated.parallel([ @@ -1439,9 +1433,9 @@ const AndroidVideoPlayer: React.FC = () => { return; } - // Show button when 2.5 minutes (150 seconds) remain + // Show button when 1 minute (60 seconds) remains const timeRemaining = duration - currentTime; - const shouldShowButton = timeRemaining <= 150 && timeRemaining > 10; // Hide in last 10 seconds + const shouldShowButton = timeRemaining <= 60 && timeRemaining > 10; // Hide in last 10 seconds if (shouldShowButton && !showNextEpisodeButton) { setShowNextEpisodeButton(true); @@ -1474,7 +1468,7 @@ const AndroidVideoPlayer: React.FC = () => { setShowNextEpisodeButton(false); }); } - }, [type, nextEpisode, duration, currentTime, showNextEpisodeButton, isLoadingNextEpisode]); + }, [type, nextEpisode, duration, currentTime, showNextEpisodeButton]); useEffect(() => { isMounted.current = true; @@ -1980,11 +1974,11 @@ const AndroidVideoPlayer: React.FC = () => { {/* Next Episode Button */} {showNextEpisodeButton && nextEpisode && ( - { { elevation: 8, }} onPress={handlePlayNextEpisode} - disabled={isLoadingNextEpisode} activeOpacity={0.8} > {isLoadingNextEpisode ? ( ) : ( - + )} - - {isLoadingNextEpisode ? 'Loading...' : 'Up Next'} + + {isLoadingNextEpisode ? 'Loading next episode…' : 'Up next'} - + S{nextEpisode.season_number}E{nextEpisode.episode_number} {nextEpisode.name ? `: ${nextEpisode.name}` : ''} diff --git a/src/components/player/VideoPlayer.tsx b/src/components/player/VideoPlayer.tsx index 967ca47..9e34b76 100644 --- a/src/components/player/VideoPlayer.tsx +++ b/src/components/player/VideoPlayer.tsx @@ -825,15 +825,12 @@ const VideoPlayer: React.FC = () => { // Navigate back with proper handling for fullscreen modal try { - // For series, reset to streams screen for current episode to ensure no hidden players remain on the stack + // For series, hard reset to a single Streams route to avoid stacking multiple modals/pages if (type === 'series' && id && episodeId) { (navigation as any).reset({ index: 0, routes: [ - { - name: 'Streams', - params: { id, type: 'series', episodeId } - } + { name: 'Streams', params: { id, type: 'series', episodeId } } ] }); } else if (navigation.canGoBack()) { @@ -1319,7 +1316,7 @@ const VideoPlayer: React.FC = () => { // Handle next episode button visibility based on current time and next episode availability useEffect(() => { - if (type !== 'series' || !nextEpisode || duration <= 0 || isLoadingNextEpisode) { + if (type !== 'series' || !nextEpisode || duration <= 0) { if (showNextEpisodeButton) { // Hide button with animation Animated.parallel([ @@ -1340,9 +1337,9 @@ const VideoPlayer: React.FC = () => { return; } - // Show button when 2.5 minutes (150 seconds) remain + // Show button when 1 minute (60 seconds) remains const timeRemaining = duration - currentTime; - const shouldShowButton = timeRemaining <= 150 && timeRemaining > 10; // Hide in last 10 seconds + const shouldShowButton = timeRemaining <= 60 && timeRemaining > 10; // Hide in last 10 seconds if (shouldShowButton && !showNextEpisodeButton) { setShowNextEpisodeButton(true); @@ -1375,7 +1372,7 @@ const VideoPlayer: React.FC = () => { setShowNextEpisodeButton(false); }); } - }, [type, nextEpisode, duration, currentTime, showNextEpisodeButton, isLoadingNextEpisode]); + }, [type, nextEpisode, duration, currentTime, showNextEpisodeButton]); useEffect(() => { isMounted.current = true; @@ -1888,7 +1885,7 @@ const VideoPlayer: React.FC = () => { style={{ position: 'absolute', bottom: 80 + insets.bottom, - right: 24 + insets.right, + right: 8 + insets.right, opacity: nextEpisodeButtonOpacity, transform: [{ scale: nextEpisodeButtonScale }], }} @@ -1896,9 +1893,9 @@ const VideoPlayer: React.FC = () => { { elevation: 8, }} onPress={handlePlayNextEpisode} - disabled={isLoadingNextEpisode} activeOpacity={0.8} > {isLoadingNextEpisode ? ( ) : ( - + )} - - {isLoadingNextEpisode ? 'Loading...' : 'Up Next'} + + {isLoadingNextEpisode ? 'Loading next episode…' : 'Up next'} - + S{nextEpisode.season_number}E{nextEpisode.episode_number} {nextEpisode.name ? `: ${nextEpisode.name}` : ''} diff --git a/src/screens/StreamsScreen.tsx b/src/screens/StreamsScreen.tsx index 5478d89..d799abc 100644 --- a/src/screens/StreamsScreen.tsx +++ b/src/screens/StreamsScreen.tsx @@ -16,6 +16,7 @@ import { Linking, Clipboard, } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; import * as ScreenOrientation from 'expo-screen-orientation'; import { useRoute, useNavigation, useFocusEffect } from '@react-navigation/native'; @@ -349,6 +350,7 @@ const ProviderFilter = memo(({ }); export const StreamsScreen = () => { + const insets = useSafeAreaInsets(); const route = useRoute>(); const navigation = useNavigation(); const { id, type, episodeId, episodeThumbnail } = route.params; @@ -1381,7 +1383,10 @@ export const StreamsScreen = () => { style={[styles.backButtonContainer]} >