diff --git a/src/components/player/modals/AudioTrackModal.tsx b/src/components/player/modals/AudioTrackModal.tsx index d35e4b694..c8ec13f1b 100644 --- a/src/components/player/modals/AudioTrackModal.tsx +++ b/src/components/player/modals/AudioTrackModal.tsx @@ -1,6 +1,28 @@ import React from 'react'; -import { View, Text, TouchableOpacity, ScrollView } from 'react-native'; -import { Ionicons } from '@expo/vector-icons'; +import { View, Text, TouchableOpacity, ScrollView, Dimensions } from 'react-native'; +import { Ionicons, MaterialIcons } from '@expo/vector-icons'; +import { BlurView } from 'expo-blur'; +import Animated, { + FadeIn, + FadeOut, + SlideInDown, + SlideOutDown, + FadeInDown, + FadeInUp, + Layout, + withSpring, + withTiming, + useAnimatedStyle, + useSharedValue, + interpolate, + Easing, + withDelay, + withSequence, + runOnJS, + BounceIn, + ZoomIn +} from 'react-native-reanimated'; +import { LinearGradient } from 'expo-linear-gradient'; import { styles } from '../utils/playerStyles'; import { getTrackDisplayName } from '../utils/playerUtils'; @@ -12,6 +34,53 @@ interface AudioTrackModalProps { selectAudioTrack: (trackId: number) => void; } +const { width, height } = Dimensions.get('window'); + +const AudioBadge = ({ + text, + color, + bgColor, + icon, + delay = 0 +}: { + text: string; + color: string; + bgColor: string; + icon?: string; + delay?: number; +}) => ( + + {icon && ( + + )} + + {text} + + +); + export const AudioTrackModal: React.FC = ({ showAudioModal, setShowAudioModal, @@ -19,56 +88,405 @@ export const AudioTrackModal: React.FC = ({ selectedAudioTrack, selectAudioTrack, }) => { + const modalScale = useSharedValue(0.9); + const modalOpacity = useSharedValue(0); + + React.useEffect(() => { + if (showAudioModal) { + modalScale.value = withSpring(1, { + damping: 20, + stiffness: 300, + mass: 0.8, + }); + modalOpacity.value = withTiming(1, { + duration: 200, + easing: Easing.out(Easing.quad), + }); + } + }, [showAudioModal]); + + const modalStyle = useAnimatedStyle(() => ({ + transform: [{ scale: modalScale.value }], + opacity: modalOpacity.value, + })); + + const handleClose = () => { + modalScale.value = withTiming(0.9, { duration: 150 }); + modalOpacity.value = withTiming(0, { duration: 150 }); + setTimeout(() => setShowAudioModal(false), 150); + }; + if (!showAudioModal) return null; return ( - - - - Audio - setShowAudioModal(false)} + + {/* Backdrop */} + + + {/* Modal Content */} + + {/* Glassmorphism Background */} + + {/* Header */} + - - - - - - - {vlcAudioTracks.length > 0 ? vlcAudioTracks.map(track => ( - { - selectAudioTrack(track.id); - setShowAudioModal(false); + + + Audio Tracks + + + Choose from {vlcAudioTracks.length} available track{vlcAudioTracks.length !== 1 ? 's' : ''} + + + + + - - - {getTrackDisplayName(track)} - - {(track.name && track.language) && ( - {track.name} - )} - - {selectedAudioTrack === track.id && ( - - - - )} + - )) : ( - - - No audio tracks available + + + + {/* Content */} + + {/* Audio Tracks Section */} + + + + + + Available Audio Tracks + + + Select your preferred audio language + + - )} - - - - + + {/* Audio Tracks List */} + {vlcAudioTracks.length > 0 ? vlcAudioTracks.map((track, index) => { + const isSelected = selectedAudioTrack === track.id; + + return ( + + { + selectAudioTrack(track.id); + handleClose(); + }} + activeOpacity={0.85} + > + + + + + {getTrackDisplayName(track)} + + + {isSelected && ( + + + + ACTIVE + + + )} + + + {(track.name && track.language) && ( + + {track.name} + + )} + + + + {track.language && ( + + )} + + + + + {isSelected ? ( + + + + ) : ( + + )} + + + + + ); + }) : ( + + + + No audio tracks available + + + This content doesn't have multiple audio tracks.{'\n'}The default audio will be used. + + + )} + + + + + ); };