diff --git a/src/components/metadata/SeriesContent.tsx b/src/components/metadata/SeriesContent.tsx index 3ad9b8e..a35c403 100644 --- a/src/components/metadata/SeriesContent.tsx +++ b/src/components/metadata/SeriesContent.tsx @@ -219,7 +219,7 @@ export const SeriesContent: React.FC = ({ style={[ styles.episodeCard, isTablet && styles.episodeCardTablet, - { backgroundColor: currentTheme.colors.elevation2 } + { backgroundColor: currentTheme.colors.darkBackground } ]} onPress={() => onSelectEpisode(episode)} activeOpacity={0.7} @@ -385,10 +385,10 @@ const styles = StyleSheet.create({ elevation: 8, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, - shadowOpacity: 0.25, - shadowRadius: 8, + shadowOpacity: 0.35, + shadowRadius: 12, borderWidth: 1, - borderColor: 'rgba(255,255,255,0.1)', + borderColor: 'rgba(255,255,255,0.05)', height: 120, }, episodeCardTablet: { @@ -410,12 +410,12 @@ const styles = StyleSheet.create({ position: 'absolute', bottom: 8, right: 4, - backgroundColor: 'rgba(0,0,0,0.85)', + backgroundColor: 'rgba(0,0,0,0.9)', paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4, borderWidth: 1, - borderColor: 'rgba(255,255,255,0.2)', + borderColor: 'rgba(255,255,255,0.15)', zIndex: 1, }, episodeNumberText: { @@ -446,7 +446,7 @@ const styles = StyleSheet.create({ ratingContainer: { flexDirection: 'row', alignItems: 'center', - backgroundColor: 'rgba(0,0,0,0.7)', + backgroundColor: 'rgba(0,0,0,0.85)', paddingHorizontal: 4, paddingVertical: 2, borderRadius: 4, @@ -557,7 +557,7 @@ const styles = StyleSheet.create({ runtimeContainer: { flexDirection: 'row', alignItems: 'center', - backgroundColor: 'rgba(0,0,0,0.7)', + backgroundColor: 'rgba(0,0,0,0.85)', paddingHorizontal: 4, paddingVertical: 2, borderRadius: 4, diff --git a/src/components/player/VideoPlayer.tsx b/src/components/player/VideoPlayer.tsx index 418f0d1..c44be09 100644 --- a/src/components/player/VideoPlayer.tsx +++ b/src/components/player/VideoPlayer.tsx @@ -466,10 +466,31 @@ const VideoPlayer: React.FC = () => { }; const handleClose = () => { - ScreenOrientation.unlockAsync().then(() => { + // Start exit animation + Animated.parallel([ + Animated.timing(fadeAnim, { + toValue: 0, + duration: 150, + useNativeDriver: true, + }), + Animated.timing(openingFadeAnim, { + toValue: 0, + duration: 150, + useNativeDriver: true, + }), + ]).start(); + + // Small delay to allow animation to start, then unlock orientation and navigate + setTimeout(() => { + ScreenOrientation.unlockAsync().then(() => { disableImmersiveMode(); navigation.goBack(); - }); + }).catch(() => { + // Fallback: navigate even if orientation unlock fails + disableImmersiveMode(); + navigation.goBack(); + }); + }, 100); }; useEffect(() => { diff --git a/src/screens/StreamsScreen.tsx b/src/screens/StreamsScreen.tsx index 81e61aa..4c470df 100644 --- a/src/screens/StreamsScreen.tsx +++ b/src/screens/StreamsScreen.tsx @@ -16,7 +16,7 @@ import { Linking, } from 'react-native'; import * as ScreenOrientation from 'expo-screen-orientation'; -import { useRoute, useNavigation } from '@react-navigation/native'; +import { useRoute, useNavigation, useFocusEffect } from '@react-navigation/native'; import { RouteProp } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; import { MaterialIcons } from '@expo/vector-icons'; @@ -246,6 +246,9 @@ export const StreamsScreen = () => { const isMounted = useRef(true); const loadStartTimeRef = useRef(0); const hasDoneInitialLoadRef = useRef(false); + + // Add state for handling orientation transition + const [isTransitioning, setIsTransitioning] = useState(false); // Add timing logs const [loadStartTime, setLoadStartTime] = useState(0); @@ -888,6 +891,44 @@ export const StreamsScreen = () => { }; }, []); + // Add orientation handling when screen comes into focus + useFocusEffect( + useCallback(() => { + // Set transitioning state to mask any visual glitches + setIsTransitioning(true); + + // Immediately lock to portrait when returning to this screen + const lockToPortrait = async () => { + try { + await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP); + // Small delay then unlock to allow natural portrait orientation + setTimeout(async () => { + try { + await ScreenOrientation.unlockAsync(); + // Clear transition state after orientation is handled + setTimeout(() => { + setIsTransitioning(false); + }, 100); + } catch (error) { + logger.error('[StreamsScreen] Error unlocking orientation:', error); + setIsTransitioning(false); + } + }, 200); + } catch (error) { + logger.error('[StreamsScreen] Error locking to portrait:', error); + setIsTransitioning(false); + } + }; + + lockToPortrait(); + + return () => { + // Cleanup when screen loses focus + setIsTransitioning(false); + }; + }, []) + ); + return ( { barStyle="light-content" /> + {/* Transition overlay to mask orientation changes */} + {isTransitioning && ( + + + + )} + StyleSheet.create({ fontSize: 13, fontWeight: '600', }, + transitionOverlay: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: colors.darkBackground, + justifyContent: 'center', + alignItems: 'center', + zIndex: 9999, + }, }); export default memo(StreamsScreen); \ No newline at end of file