diff --git a/src/components/player/AndroidVideoPlayer.tsx b/src/components/player/AndroidVideoPlayer.tsx
index a2c925a..68fd412 100644
--- a/src/components/player/AndroidVideoPlayer.tsx
+++ b/src/components/player/AndroidVideoPlayer.tsx
@@ -29,12 +29,12 @@ import {
} from './utils/playerTypes';
import { safeDebugLog, parseSRT, DEBUG_MODE, formatTime } from './utils/playerUtils';
import { styles } from './utils/playerStyles';
-import SubtitleModals from './modals/SubtitleModals';
-import AudioTrackModal from './modals/AudioTrackModal';
+import { SubtitleModals } from './modals/SubtitleModals';
+import { AudioTrackModal } from './modals/AudioTrackModal';
import ResumeOverlay from './modals/ResumeOverlay';
import PlayerControls from './controls/PlayerControls';
import CustomSubtitles from './subtitles/CustomSubtitles';
-import SourcesModal from './modals/SourcesModal';
+import { SourcesModal } from './modals/SourcesModal';
// Map VLC resize modes to react-native-video resize modes
const getVideoResizeMode = (resizeMode: ResizeModeType) => {
diff --git a/src/components/player/modals/AudioTrackModal.tsx b/src/components/player/modals/AudioTrackModal.tsx
index 77e3bbb..cfc50d6 100644
--- a/src/components/player/modals/AudioTrackModal.tsx
+++ b/src/components/player/modals/AudioTrackModal.tsx
@@ -1,16 +1,12 @@
import React from 'react';
import { View, Text, TouchableOpacity, ScrollView, Dimensions } from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
-import { BlurView } from 'expo-blur';
import Animated, {
FadeIn,
FadeOut,
- useAnimatedStyle,
- useSharedValue,
- withTiming,
+ SlideInRight,
+ SlideOutRight,
} from 'react-native-reanimated';
-import { LinearGradient } from 'expo-linear-gradient';
-import { styles } from '../utils/playerStyles';
import { getTrackDisplayName } from '../utils/playerUtils';
interface AudioTrackModalProps {
@@ -21,52 +17,8 @@ interface AudioTrackModalProps {
selectAudioTrack: (trackId: number) => void;
}
-const { width, height } = Dimensions.get('window');
-
-const MODAL_WIDTH = Math.min(width - 32, 520);
-const MODAL_MAX_HEIGHT = height * 0.85;
-
-const AudioBadge = ({
- text,
- color,
- bgColor,
- icon
-}: {
- text: string;
- color: string;
- bgColor: string;
- icon?: string;
-}) => (
-
- {icon && (
-
- )}
-
- {text}
-
-
-);
+const { width } = Dimensions.get('window');
+const MENU_WIDTH = Math.min(width * 0.85, 400);
export const AudioTrackModal: React.FC = ({
showAudioModal,
@@ -75,325 +27,173 @@ export const AudioTrackModal: React.FC = ({
selectedAudioTrack,
selectAudioTrack,
}) => {
- const modalOpacity = useSharedValue(0);
-
- React.useEffect(() => {
- if (showAudioModal) {
- modalOpacity.value = withTiming(1, { duration: 200 });
- }
- }, [showAudioModal]);
-
- const modalStyle = useAnimatedStyle(() => ({
- opacity: modalOpacity.value,
- }));
-
const handleClose = () => {
- modalOpacity.value = withTiming(0, { duration: 150 });
- setTimeout(() => setShowAudioModal(false), 150);
+ setShowAudioModal(false);
};
if (!showAudioModal) return null;
return (
-
-
+ {/* Backdrop */}
+
-
-
-
-
-
-
- Audio Tracks
-
-
- Choose from {vlcAudioTracks.length} available track{vlcAudioTracks.length !== 1 ? 's' : ''}
-
-
-
-
-
-
-
+
+
-
+ {/* Header */}
+
+
+ Audio Tracks
+
+
-
- {vlcAudioTracks.length > 0 ? vlcAudioTracks.map((track) => (
-
+
+
+
+
+
+ {/* Audio Tracks */}
+
+
+ Available Tracks ({vlcAudioTracks.length})
+
+
+
+ {vlcAudioTracks.map((track) => {
+ const isSelected = selectedAudioTrack === track.id;
+ return (
{
selectAudioTrack(track.id);
- handleClose();
}}
- activeOpacity={0.85}
+ activeOpacity={0.7}
>
-
-
-
+
+
+ {getTrackDisplayName(track)}
+
+ {track.language && (
- {getTrackDisplayName(track)}
+ {track.language.toUpperCase()}
-
- {selectedAudioTrack === track.id && (
-
-
-
- ACTIVE
-
-
- )}
-
-
-
-
- {track.language && (
-
- )}
-
-
-
-
-
+ )}
+ {isSelected && (
+
+ )}
-
- )) : (
-
-
-
- No audio tracks found
-
-
- No audio tracks are available for this content.{'\n'}Try a different source or check your connection.
-
-
- )}
+ );
+ })}
-
-
-
-
- );
-};
-export default AudioTrackModal;
\ No newline at end of file
+ {vlcAudioTracks.length === 0 && (
+
+
+
+ No audio tracks available
+
+
+ )}
+
+
+
+ >
+ );
+};
\ No newline at end of file
diff --git a/src/components/player/modals/SourcesModal.tsx b/src/components/player/modals/SourcesModal.tsx
index 9533f6f..f8aa33a 100644
--- a/src/components/player/modals/SourcesModal.tsx
+++ b/src/components/player/modals/SourcesModal.tsx
@@ -1,19 +1,13 @@
import React from 'react';
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,
- useAnimatedStyle,
- useSharedValue,
- withTiming,
- runOnJS,
+ SlideInRight,
+ SlideOutRight,
} from 'react-native-reanimated';
-import { LinearGradient } from 'expo-linear-gradient';
-import { styles } from '../utils/playerStyles';
import { Stream } from '../../../types/streams';
-import QualityBadge from '../../metadata/QualityBadge';
interface SourcesModalProps {
showSourcesModal: boolean;
@@ -24,12 +18,10 @@ interface SourcesModalProps {
isChangingSource: boolean;
}
-const { width, height } = Dimensions.get('window');
+const { width } = Dimensions.get('window');
+const MENU_WIDTH = Math.min(width * 0.85, 400);
-const MODAL_WIDTH = Math.min(width - 32, 520);
-const MODAL_MAX_HEIGHT = height * 0.85;
-
-const QualityIndicator = ({ quality }: { quality: string | null }) => {
+const QualityBadge = ({ quality }: { quality: string | null }) => {
if (!quality) return null;
const qualityNum = parseInt(quality);
@@ -54,22 +46,15 @@ const QualityIndicator = ({ quality }: { quality: string | null }) => {
borderColor: `${color}60`,
borderWidth: 1,
paddingHorizontal: 8,
- paddingVertical: 3,
+ paddingVertical: 4,
borderRadius: 8,
flexDirection: 'row',
alignItems: 'center',
}}
>
-
@@ -79,49 +64,7 @@ const QualityIndicator = ({ quality }: { quality: string | null }) => {
);
};
-const StreamMetaBadge = ({
- text,
- color,
- bgColor,
- icon
-}: {
- text: string;
- color: string;
- bgColor: string;
- icon?: string;
-}) => (
-
- {icon && (
-
- )}
-
- {text}
-
-
-);
-
-const SourcesModal: React.FC = ({
+export const SourcesModal: React.FC = ({
showSourcesModal,
setShowSourcesModal,
availableStreams,
@@ -129,28 +72,8 @@ const SourcesModal: React.FC = ({
onSelectStream,
isChangingSource,
}) => {
- const modalOpacity = useSharedValue(0);
-
- React.useEffect(() => {
- if (showSourcesModal) {
- modalOpacity.value = withTiming(1, { duration: 200 });
- } else {
- modalOpacity.value = withTiming(0, { duration: 150 });
- }
-
- return () => {
- modalOpacity.value = 0;
- };
- }, [showSourcesModal]);
-
- const modalStyle = useAnimatedStyle(() => ({
- opacity: modalOpacity.value,
- }));
-
const handleClose = () => {
- modalOpacity.value = withTiming(0, { duration: 150 }, () => {
- runOnJS(setShowSourcesModal)(false);
- });
+ setShowSourcesModal(false);
};
if (!showSourcesModal) return null;
@@ -174,305 +97,237 @@ const SourcesModal: React.FC = ({
};
return (
-
-
+ {/* Backdrop */}
+
-
-
-
-
+
+
+ {/* Side Menu */}
+
+ {/* Header */}
+
+
+ Change Source
+
+
+
+
+
+
+
+ {isChangingSource && (
+
-
+ }}>
+
- Video Sources
-
-
- Choose from {Object.values(availableStreams).reduce((acc, curr) => acc + curr.streams.length, 0)} available sources
+ Switching source...
-
-
-
-
-
+ )}
-
- {sortedProviders.map(([providerId, { streams, addonName }]) => (
-
- 0 ? (
+ sortedProviders.map(([providerId, providerData]) => (
+
+
-
- {addonName}
-
-
-
- {streams.length}
-
-
-
-
- {streams.map((stream, index) => {
- const isSelected = isStreamSelected(stream);
- const quality = getQualityFromTitle(stream.title);
-
- return (
-
+ {providerData.addonName} ({providerData.streams.length})
+
+
+
+ {providerData.streams.map((stream, index) => {
+ const isSelected = isStreamSelected(stream);
+ const quality = getQualityFromTitle(stream.title) || stream.quality;
+
+ return (
handleStreamSelect(stream)}
- activeOpacity={0.85}
+ activeOpacity={0.7}
disabled={isChangingSource}
>
-
-
+
+
- {stream.title || 'Untitled Stream'}
+ {stream.title || stream.name || `Stream ${index + 1}`}
-
- {isSelected && (
-
-
-
- PLAYING
-
-
- )}
+ {quality && }
-
- {quality && }
-
-
+ {(stream.size || stream.lang) && (
+
+ {stream.size && (
+
+
+
+ {(stream.size / (1024 * 1024 * 1024)).toFixed(1)} GB
+
+
+ )}
+ {stream.lang && (
+
+
+
+ {stream.lang.toUpperCase()}
+
+
+ )}
+
+ )}
- {isChangingSource ? (
-
+ {isSelected ? (
+
) : (
-
+
)}
-
- );
- })}
+ );
+ })}
+
- ))}
-
-
+ ))
+ ) : (
+
+
+
+ No sources available
+
+
+ Try searching for different content
+
+
+ )}
+
-
+ >
);
-};
-
-export default SourcesModal;
\ No newline at end of file
+};
\ No newline at end of file