diff --git a/src/screens/MetadataScreen.tsx b/src/screens/MetadataScreen.tsx index a8848068..0a92ff06 100644 --- a/src/screens/MetadataScreen.tsx +++ b/src/screens/MetadataScreen.tsx @@ -15,11 +15,12 @@ import { NativeSyntheticEvent, NativeScrollEvent, } from 'react-native'; -import { SafeAreaView } from 'react-native-safe-area-context'; +import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; import { useRoute, useNavigation, useFocusEffect } from '@react-navigation/native'; import { MaterialIcons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; import { Image } from 'expo-image'; +import { BlurView } from 'expo-blur'; import { colors } from '../styles/colors'; import { useMetadata } from '../hooks/useMetadata'; import { CastSection as OriginalCastSection } from '../components/metadata/CastSection'; @@ -228,6 +229,9 @@ const MetadataScreen = () => { const [lastScrollTop, setLastScrollTop] = useState(0); const [isFullDescriptionOpen, setIsFullDescriptionOpen] = useState(false); + // Get safe area insets + const { top: safeAreaTop } = useSafeAreaInsets(); + // Animation values const screenScale = useSharedValue(0.92); const screenOpacity = useSharedValue(0); @@ -264,6 +268,13 @@ const MetadataScreen = () => { // Create a dampened scroll value for smoother parallax const dampedScrollY = useSharedValue(0); + // Add shared value for floating header opacity + const headerOpacity = useSharedValue(0); + + // Add values for animated header elements + const headerElementsY = useSharedValue(-10); + const headerElementsOpacity = useSharedValue(0); + // Debug log for route params // logger.log('[MetadataScreen] Component mounted with route params:', { id, type, episodeId }); @@ -869,6 +880,18 @@ const MetadataScreen = () => { duration: 300, easing: Easing.bezier(0.16, 1, 0.3, 1), // Custom spring-like curve }); + + // Update header opacity based on scroll position + const headerThreshold = height * 0.5 - safeAreaTop - 70; // Hero height - inset - buffer + if (rawScrollY > headerThreshold) { + headerOpacity.value = withTiming(1, { duration: 200 }); + headerElementsY.value = withTiming(0, { duration: 300 }); + headerElementsOpacity.value = withTiming(1, { duration: 450 }); + } else { + headerOpacity.value = withTiming(0, { duration: 150 }); + headerElementsY.value = withTiming(-10, { duration: 200 }); + headerElementsOpacity.value = withTiming(0, { duration: 200 }); + } }, }); @@ -900,6 +923,20 @@ const MetadataScreen = () => { }; }); + // Add animated style for floating header + const headerAnimatedStyle = useAnimatedStyle(() => ({ + opacity: headerOpacity.value, + transform: [ + { translateY: interpolate(headerOpacity.value, [0, 1], [-20, 0], Extrapolate.CLAMP) } + ] + })); + + // Add animated style for header elements + const headerElementsStyle = useAnimatedStyle(() => ({ + opacity: headerElementsOpacity.value, + transform: [{ translateY: headerElementsY.value }] + })); + if (loading) { return ( { animated={true} /> + {/* Floating Header */} + + + + + + + + + {metadata.logo ? ( + + ) : ( + {metadata.name} + )} + + + + + + + + {Platform.OS === 'ios' && } + +