From f331d2becb7fa4b949302bcef85181bd4417a537 Mon Sep 17 00:00:00 2001 From: tapframe Date: Tue, 8 Jul 2025 14:09:53 +0530 Subject: [PATCH] Refactor SubtitleModals for improved UI and functionality, including enhanced subtitle menu, updated animations, and removal of unused components. --- .../player/modals/SubtitleModals.tsx | 1267 +++++------------ 1 file changed, 359 insertions(+), 908 deletions(-) diff --git a/src/components/player/modals/SubtitleModals.tsx b/src/components/player/modals/SubtitleModals.tsx index 14e8bad..ff3f0e8 100644 --- a/src/components/player/modals/SubtitleModals.tsx +++ b/src/components/player/modals/SubtitleModals.tsx @@ -1,16 +1,16 @@ import React from 'react'; -import { View, Text, TouchableOpacity, ScrollView, ActivityIndicator, Image, Dimensions } from 'react-native'; +import { View, Text, TouchableOpacity, ScrollView, ActivityIndicator, Dimensions } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; -import { BlurView } from 'expo-blur'; import Animated, { FadeIn, FadeOut, + SlideInRight, + SlideOutRight, useAnimatedStyle, useSharedValue, withTiming, runOnJS, } 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'; @@ -36,51 +36,7 @@ interface SubtitleModalsProps { } const { width, height } = Dimensions.get('window'); - -const MODAL_WIDTH = Math.min(width - 32, 520); -const MODAL_MAX_HEIGHT = height * 0.85; - -const SubtitleBadge = ({ - text, - color, - bgColor, - icon -}: { - text: string; - color: string; - bgColor: string; - icon?: string; -}) => ( - - {icon && ( - - )} - - {text} - - -); +const MENU_WIDTH = Math.min(width * 0.85, 400); export const SubtitleModals: React.FC = ({ showSubtitleModal, @@ -101,919 +57,414 @@ export const SubtitleModals: React.FC = ({ increaseSubtitleSize, decreaseSubtitleSize, }) => { - const modalOpacity = useSharedValue(0); - const languageModalOpacity = useSharedValue(0); - React.useEffect(() => { - if (showSubtitleModal) { - modalOpacity.value = withTiming(1, { duration: 200 }); - } else { - modalOpacity.value = withTiming(0, { duration: 150 }); - } - - return () => { - modalOpacity.value = 0; - }; - }, [showSubtitleModal]); - - React.useEffect(() => { - if (showSubtitleLanguageModal) { - languageModalOpacity.value = withTiming(1, { duration: 200 }); - } else { - languageModalOpacity.value = withTiming(0, { duration: 150 }); - } - - return () => { - languageModalOpacity.value = 0; - }; - }, [showSubtitleLanguageModal]); - - React.useEffect(() => { - if (showSubtitleLanguageModal && !isLoadingSubtitleList && availableSubtitles.length === 0) { + if (showSubtitleModal && !isLoadingSubtitleList && availableSubtitles.length === 0) { fetchAvailableSubtitles(); } - }, [showSubtitleLanguageModal]); - - const modalStyle = useAnimatedStyle(() => ({ - opacity: modalOpacity.value, - })); - - const languageModalStyle = useAnimatedStyle(() => ({ - opacity: languageModalOpacity.value, - })); + }, [showSubtitleModal]); const handleClose = () => { - modalOpacity.value = withTiming(0, { duration: 150 }, () => { - runOnJS(setShowSubtitleModal)(false); - }); + setShowSubtitleModal(false); }; const handleLanguageClose = () => { - languageModalOpacity.value = withTiming(0, { duration: 150 }, () => { - runOnJS(setShowSubtitleLanguageModal)(false); - }); + setShowSubtitleLanguageModal(false); }; - // Render subtitle settings modal - const renderSubtitleModal = () => { + // Main subtitle menu + const renderSubtitleMenu = () => { if (!showSubtitleModal) return null; return ( - - + {/* Backdrop */} + - - - - - - - Subtitle Settings - - - Customize your subtitle experience - - - - - - - - - - - - - Size Adjustment - - - - - - - - - - {subtitleSize} - - - Font Size - - - - - - - - - - - - Subtitle Source - - - fetchAvailableSubtitles()} - > - - - - Search Online Subtitles - - - - - - - - - - setShowSubtitleLanguageModal(true)} - > - - - - Change Language - - - - {selectedTextTrack !== -1 && ( - t.id === selectedTextTrack)?.language?.toUpperCase() || 'UNKNOWN'} - color="#6B7280" - bgColor="rgba(107, 114, 128, 0.15)" - /> - )} - - - - - - - - - + - - ); - }; - // Render subtitle language selection modal - const renderSubtitleLanguageModal = () => { - if (!showSubtitleLanguageModal) return null; - - return ( - - - - - - + + Subtitles + + + + + + + + {/* Font Size Section */} + + + Font Size + + + - + backgroundColor: 'rgba(255, 255, 255, 0.05)', + borderRadius: 12, + padding: 16, + }}> + + + + - Subtitle Language - - - Choose from {vlcTextTracks.length} available tracks + {subtitleSize} + + + + - - - - - + - - - {vlcTextTracks.map((track) => ( - - { - selectTextTrack(track.id); - handleLanguageClose(); - }} - activeOpacity={0.85} - > - - - - - {getTrackDisplayName(track)} - - - {selectedTextTrack === track.id && ( - - - - ACTIVE - - - )} - - - - - {track.language && ( - - )} - - - - - - - - - - ))} - - {/* Online subtitles section */} - {isLoadingSubtitleList && ( - - - - )} - - {availableSubtitles.length > 0 && ( - <> - - - Online Subtitles - - - - {availableSubtitles.map((sub) => { - const isCustomSelected = useCustomSubtitles && customSubtitles.length > 0; - const isThisSubSelected = isCustomSelected; // Since we only load one custom sub at a time - - return ( - - { - loadWyzieSubtitle(sub); - handleLanguageClose(); - }} - activeOpacity={0.85} - disabled={isLoadingSubtitles} - > - - - - - {sub.display} - - - {isThisSubSelected && ( - - - - LOADED - - - )} - - - - {isThisSubSelected && ( - - )} - - - - - {isLoadingSubtitles ? ( - - ) : ( - - )} - - - - - ); - })} - - )} - - {/* No Subtitles Option */} - - { - selectTextTrack(-1); - handleLanguageClose(); - }} - activeOpacity={0.85} - > - - - + {/* Built-in Subtitles */} + {vlcTextTracks.length > 0 && ( + + + Built-in Subtitles + + + + {vlcTextTracks.map((track) => { + const isSelected = selectedTextTrack === track.id; + return ( + { + selectTextTrack(track.id); + }} + activeOpacity={0.7} + > + - No Subtitles + {getTrackDisplayName(track)} - - {selectedTextTrack === -1 && !useCustomSubtitles && ( - - - - ACTIVE - - + {isSelected && ( + )} - - - - - - - - - - - + + ); + })} - - + )} + + {/* Online Subtitles */} + + + + Online Subtitles + + fetchAvailableSubtitles()} + disabled={isLoadingSubtitleList} + > + {isLoadingSubtitleList ? ( + + ) : ( + + )} + + {isLoadingSubtitleList ? 'Searching' : 'Refresh'} + + + + + {availableSubtitles.length > 0 ? ( + + {availableSubtitles.map((sub) => { + const isSelected = useCustomSubtitles && customSubtitles.length > 0; + return ( + { + loadWyzieSubtitle(sub); + }} + activeOpacity={0.7} + disabled={isLoadingSubtitles} + > + + + + {sub.display} + + + {formatLanguage(sub.language)} + + + {isLoadingSubtitles ? ( + + ) : isSelected ? ( + + ) : ( + + )} + + + ); + })} + + ) : !isLoadingSubtitleList ? ( + fetchAvailableSubtitles()} + activeOpacity={0.7} + > + + + Tap to search online + + + ) : ( + + + + Searching... + + + )} + + + {/* Turn Off Subtitles */} + + + Options + + + { + selectTextTrack(-1); + }} + activeOpacity={0.7} + > + + + + + Turn Off Subtitles + + + {selectedTextTrack === -1 && !useCustomSubtitles && ( + + )} + + + + - + ); }; return ( <> - {renderSubtitleModal()} - {renderSubtitleLanguageModal()} + {renderSubtitleMenu()} ); };