From ea488741a8671dec3e8f6c63a9ecbac447b850dd Mon Sep 17 00:00:00 2001 From: tapframe Date: Tue, 10 Jun 2025 03:22:14 +0530 Subject: [PATCH] Enhance SubtitleModals with improved animations and visual elements This update introduces a new SubtitleBadge component for better visual feedback on subtitle options, along with enhanced animations for modal transitions. The modal now features a glassmorphism background and improved layout, providing a more engaging user experience. Additionally, subtitle size controls and external subtitle search functionalities have been refined for better usability. --- .../player/modals/SubtitleModals.tsx | 1234 ++++++++++++++--- 1 file changed, 1044 insertions(+), 190 deletions(-) diff --git a/src/components/player/modals/SubtitleModals.tsx b/src/components/player/modals/SubtitleModals.tsx index 582cf714..e5259633 100644 --- a/src/components/player/modals/SubtitleModals.tsx +++ b/src/components/player/modals/SubtitleModals.tsx @@ -1,6 +1,28 @@ import React from 'react'; -import { View, Text, TouchableOpacity, ScrollView, ActivityIndicator, Image } from 'react-native'; -import { Ionicons } from '@expo/vector-icons'; +import { View, Text, TouchableOpacity, ScrollView, ActivityIndicator, Image, 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 { WyzieSubtitle, SubtitleCue } from '../utils/playerTypes'; import { getTrackDisplayName, formatLanguage } from '../utils/playerUtils'; @@ -25,6 +47,53 @@ interface SubtitleModalsProps { decreaseSubtitleSize: () => void; } +const { width, height } = Dimensions.get('window'); + +const SubtitleBadge = ({ + text, + color, + bgColor, + icon, + delay = 0 +}: { + text: string; + color: string; + bgColor: string; + icon?: string; + delay?: number; +}) => ( + + {icon && ( + + )} + + {text} + + +); + export const SubtitleModals: React.FC = ({ showSubtitleModal, setShowSubtitleModal, @@ -44,169 +113,742 @@ export const SubtitleModals: React.FC = ({ increaseSubtitleSize, decreaseSubtitleSize, }) => { + const modalScale = useSharedValue(0.9); + const modalOpacity = useSharedValue(0); + const languageModalScale = useSharedValue(0.9); + const languageModalOpacity = useSharedValue(0); + + React.useEffect(() => { + if (showSubtitleModal) { + modalScale.value = withSpring(1, { + damping: 20, + stiffness: 300, + mass: 0.8, + }); + modalOpacity.value = withTiming(1, { + duration: 200, + easing: Easing.out(Easing.quad), + }); + } + }, [showSubtitleModal]); + + React.useEffect(() => { + if (showSubtitleLanguageModal) { + languageModalScale.value = withSpring(1, { + damping: 20, + stiffness: 300, + mass: 0.8, + }); + languageModalOpacity.value = withTiming(1, { + duration: 200, + easing: Easing.out(Easing.quad), + }); + } + }, [showSubtitleLanguageModal]); + + const modalStyle = useAnimatedStyle(() => ({ + transform: [{ scale: modalScale.value }], + opacity: modalOpacity.value, + })); + + const languageModalStyle = useAnimatedStyle(() => ({ + transform: [{ scale: languageModalScale.value }], + opacity: languageModalOpacity.value, + })); + + const handleClose = () => { + modalScale.value = withTiming(0.9, { duration: 150 }); + modalOpacity.value = withTiming(0, { duration: 150 }); + setTimeout(() => setShowSubtitleModal(false), 150); + }; + + const handleLanguageClose = () => { + languageModalScale.value = withTiming(0.9, { duration: 150 }); + languageModalOpacity.value = withTiming(0, { duration: 150 }); + setTimeout(() => setShowSubtitleLanguageModal(false), 150); + }; + // Render subtitle settings modal const renderSubtitleModal = () => { if (!showSubtitleModal) return null; return ( - - - - Subtitle Settings - setShowSubtitleModal(false)} + + {/* Backdrop */} + + + {/* Modal Content */} + + {/* Glassmorphism Background */} + + {/* Header */} + - - - - - - + + + Subtitle Settings + + + Configure subtitles and language options + + - {/* External Subtitles Section - Priority */} - - External Subtitles - High quality subtitles with size control + + + + + + + + {/* Content */} + + - {/* Custom subtitles option - show if loaded */} - {customSubtitles.length > 0 ? ( - { - selectTextTrack(-999); - setShowSubtitleModal(false); - }} - > - - - - - Custom Subtitles - - {customSubtitles.length} cues • Size adjustable + {/* External Subtitles Section */} + + + + + + External Subtitles + + + High quality with size control - {useCustomSubtitles && ( - - - - )} - - ) : null} - - {/* Search for external subtitles */} - { - setShowSubtitleModal(false); - fetchAvailableSubtitles(); - }} - disabled={isLoadingSubtitleList} - > - - {isLoadingSubtitleList ? ( - - ) : ( - - )} - - {isLoadingSubtitleList ? 'Searching...' : 'Search Online Subtitles'} - - - - {/* Subtitle Size Controls - Only for custom subtitles */} - {useCustomSubtitles && ( - - Size Control - - 0 && ( + - - - - {subtitleSize}px - Font Size - - - - - - - )} - - {/* Built-in Subtitles Section */} - - Built-in Subtitles - System default sizing • No customization - - {/* Off option */} - { - selectTextTrack(-1); - setShowSubtitleModal(false); - }} - > - - - - - Disabled - No subtitles - - {(selectedTextTrack === -1 && !useCustomSubtitles) && ( - - - + { + selectTextTrack(-999); + setShowSubtitleModal(false); + }} + activeOpacity={0.85} + > + + + + + Custom Subtitles + + + {useCustomSubtitles && ( + + + + ACTIVE + + + )} + + + + + + + + + + {useCustomSubtitles ? ( + + + + ) : ( + + )} + + + + )} - + + {/* Search for external subtitles */} + + { + handleClose(); + fetchAvailableSubtitles(); + }} + disabled={isLoadingSubtitleList} + activeOpacity={0.85} + > + + {isLoadingSubtitleList ? ( + + ) : ( + + )} + + {isLoadingSubtitleList ? 'Searching...' : 'Search Online Subtitles'} + + + + + + + {/* Subtitle Size Controls */} + {useCustomSubtitles && ( + + + + + + Size Control + + + Adjust font size for better readability + + + + + + + + + + + + + {subtitleSize}px + + + Font Size + + + + + + + + + + )} {/* Available built-in subtitle tracks */} - {vlcTextTracks.length > 0 ? vlcTextTracks.map(track => ( - 0 ? vlcTextTracks.map((track, index) => ( + { - selectTextTrack(track.id); - setShowSubtitleModal(false); + entering={FadeInDown.duration(300).delay(400 + (index * 50))} + layout={Layout.springify()} + style={{ marginBottom: 16 }} + > + { + selectTextTrack(track.id); + handleClose(); + }} + activeOpacity={0.85} + > + + + + + {getTrackDisplayName(track)} + + + {(selectedTextTrack === track.id && !useCustomSubtitles) && ( + + + + ACTIVE + + + )} + + + + + + + + + + {(selectedTextTrack === track.id && !useCustomSubtitles) ? ( + + + + ) : ( + + )} + + + + + )) : ( + - - - - - - {getTrackDisplayName(track)} - - - Built-in track • System font size - - - {(selectedTextTrack === track.id && !useCustomSubtitles) && ( - - - - )} - - )) : ( - - - No built-in subtitles available - + + + No built-in subtitles available + + + Try searching for external subtitles + + )} - - - - + + + + ); }; @@ -215,58 +857,270 @@ export const SubtitleModals: React.FC = ({ if (!showSubtitleLanguageModal) return null; return ( - - - - Select Language - setShowSubtitleLanguageModal(false)} + + {/* Backdrop */} + + + {/* Modal Content */} + + {/* Glassmorphism Background */} + + {/* Header */} + - - - - - - - {availableSubtitles.length > 0 ? availableSubtitles.map(subtitle => ( - loadWyzieSubtitle(subtitle)} - disabled={isLoadingSubtitles} + + + Select Language + + + Choose from {availableSubtitles.length} available languages + + + + + - - - - - {formatLanguage(subtitle.language)} - - - {subtitle.display} - - - - {isLoadingSubtitles && ( - - )} + + + + + {/* Content */} + + {availableSubtitles.length > 0 ? availableSubtitles.map((subtitle, index) => ( + + loadWyzieSubtitle(subtitle)} + disabled={isLoadingSubtitles} + activeOpacity={0.85} + > + + + + + + {formatLanguage(subtitle.language)} + + + {subtitle.display} + + + + + + {isLoadingSubtitles ? ( + + ) : ( + + )} + + + + )) : ( - - - - No subtitles found for this content + + + + No subtitles found - + + No subtitles are available for this content.{'\n'}Try searching again or check back later. + + )} - - - - + + + + ); };