diff --git a/src/components/player/AndroidVideoPlayer.tsx b/src/components/player/AndroidVideoPlayer.tsx index 19e5d7d1..66f6a9b5 100644 --- a/src/components/player/AndroidVideoPlayer.tsx +++ b/src/components/player/AndroidVideoPlayer.tsx @@ -124,8 +124,7 @@ const AndroidVideoPlayer: React.FC = () => { const [rnVideoAudioTracks, setRnVideoAudioTracks] = useState>([]); const [rnVideoTextTracks, setRnVideoTextTracks] = useState>([]); const [isPlayerReady, setIsPlayerReady] = useState(false); - const progressAnim = useRef(new Animated.Value(0)).current; - const progressBarRef = useRef(null); + // Removed progressAnim and progressBarRef - no longer needed with React Native Community Slider const [isDragging, setIsDragging] = useState(false); const isSeeking = useRef(false); const seekDebounceTimer = useRef(null); @@ -454,44 +453,29 @@ const AndroidVideoPlayer: React.FC = () => { } }, [seekTime, duration]); - const handleProgressBarTouch = (event: any) => { - if (duration > 0) { - const { locationX } = event.nativeEvent; - processProgressTouch(locationX); + // Slider callback functions for React Native Community Slider + const handleSliderValueChange = (value: number) => { + if (isDragging && duration > 0) { + const seekTime = Math.min(value, duration - END_EPSILON); + setCurrentTime(seekTime); + pendingSeekValue.current = seekTime; } }; - - const handleProgressBarDragStart = () => { + + const handleSlidingStart = () => { setIsDragging(true); }; - - const handleProgressBarDragMove = (event: any) => { - if (!isDragging || !duration || duration <= 0) return; - const { locationX } = event.nativeEvent; - processProgressTouch(locationX, true); - }; - - const handleProgressBarDragEnd = () => { + + const handleSlidingComplete = (value: number) => { setIsDragging(false); - if (pendingSeekValue.current !== null) { - seekToTime(pendingSeekValue.current); + if (duration > 0) { + const seekTime = Math.min(value, duration - END_EPSILON); + seekToTime(seekTime); pendingSeekValue.current = null; } }; - const processProgressTouch = (locationX: number, isDragging = false) => { - progressBarRef.current?.measure((x, y, width, height, pageX, pageY) => { - const percentage = Math.max(0, Math.min(locationX / width, 0.999)); - const seekTime = Math.min(percentage * duration, duration - END_EPSILON); - progressAnim.setValue(percentage); - if (isDragging) { - pendingSeekValue.current = seekTime; - setCurrentTime(seekTime); - } else { - seekToTime(seekTime); - } - }); - }; + // Removed processProgressTouch - no longer needed with React Native Community Slider const handleProgress = (data: any) => { if (isDragging || isSeeking.current) return; @@ -501,12 +485,7 @@ const AndroidVideoPlayer: React.FC = () => { // Update time more frequently for subtitle synchronization (0.1s threshold) if (Math.abs(currentTimeInSeconds - currentTime) > 0.1) { safeSetState(() => setCurrentTime(currentTimeInSeconds)); - const progressPercent = duration > 0 ? currentTimeInSeconds / duration : 0; - Animated.timing(progressAnim, { - toValue: progressPercent, - duration: 100, - useNativeDriver: false, - }).start(); + // Removed progressAnim animation - no longer needed with React Native Community Slider const bufferedTime = data.playableDuration || currentTimeInSeconds; safeSetState(() => setBuffered(bufferedTime)); } @@ -1199,12 +1178,9 @@ const AndroidVideoPlayer: React.FC = () => { setShowAudioModal={setShowAudioModal} setShowSubtitleModal={setShowSubtitleModal} setShowSourcesModal={setShowSourcesModal} - progressBarRef={progressBarRef} - progressAnim={progressAnim} - handleProgressBarTouch={handleProgressBarTouch} - handleProgressBarDragStart={handleProgressBarDragStart} - handleProgressBarDragMove={handleProgressBarDragMove} - handleProgressBarDragEnd={handleProgressBarDragEnd} + onSliderValueChange={handleSliderValueChange} + onSlidingStart={handleSlidingStart} + onSlidingComplete={handleSlidingComplete} buffered={buffered} formatTime={formatTime} /> diff --git a/src/components/player/VideoPlayer.tsx b/src/components/player/VideoPlayer.tsx index 0678dc52..3f1b6ce7 100644 --- a/src/components/player/VideoPlayer.tsx +++ b/src/components/player/VideoPlayer.tsx @@ -11,6 +11,7 @@ import { logger } from '../../utils/logger'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { MaterialIcons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; +import Slider from '@react-native-community/slider'; import AndroidVideoPlayer from './AndroidVideoPlayer'; import { useTraktAutosync } from '../../hooks/useTraktAutosync'; import { useTraktAutosyncSettings } from '../../hooks/useTraktAutosyncSettings'; @@ -127,8 +128,7 @@ const VideoPlayer: React.FC = () => { const [vlcAudioTracks, setVlcAudioTracks] = useState>([]); const [vlcTextTracks, setVlcTextTracks] = useState>([]); const [isPlayerReady, setIsPlayerReady] = useState(false); - const progressAnim = useRef(new Animated.Value(0)).current; - const progressBarRef = useRef(null); + // Removed progressAnim and progressBarRef - no longer needed with React Native Community Slider const [isDragging, setIsDragging] = useState(false); const isSeeking = useRef(false); const seekDebounceTimer = useRef(null); @@ -515,44 +515,29 @@ const VideoPlayer: React.FC = () => { } }; - const handleProgressBarTouch = (event: any) => { - if (duration > 0) { - const { locationX } = event.nativeEvent; - processProgressTouch(locationX); + // Slider callback functions for React Native Community Slider + const handleSliderValueChange = (value: number) => { + if (isDragging && duration > 0) { + const seekTime = Math.min(value, duration - END_EPSILON); + setCurrentTime(seekTime); + pendingSeekValue.current = seekTime; } }; - const handleProgressBarDragStart = () => { + const handleSlidingStart = () => { setIsDragging(true); }; - const handleProgressBarDragMove = (event: any) => { - if (!isDragging || !duration || duration <= 0) return; - const { locationX } = event.nativeEvent; - processProgressTouch(locationX, true); - }; - - const handleProgressBarDragEnd = () => { + const handleSlidingComplete = (value: number) => { setIsDragging(false); - if (pendingSeekValue.current !== null) { - seekToTime(pendingSeekValue.current); + if (duration > 0) { + const seekTime = Math.min(value, duration - END_EPSILON); + seekToTime(seekTime); pendingSeekValue.current = null; } }; - const processProgressTouch = (locationX: number, isDragging = false) => { - progressBarRef.current?.measure((x, y, width, height, pageX, pageY) => { - const percentage = Math.max(0, Math.min(locationX / width, 0.999)); - const seekTime = Math.min(percentage * duration, duration - END_EPSILON); - progressAnim.setValue(percentage); - if (isDragging) { - pendingSeekValue.current = seekTime; - setCurrentTime(seekTime); - } else { - seekToTime(seekTime); - } - }); - }; + // Removed processProgressTouch - no longer needed with React Native Community Slider const handleProgress = (event: any) => { if (isDragging || isSeeking.current) return; @@ -562,12 +547,7 @@ const VideoPlayer: React.FC = () => { // Only update if there's a significant change to avoid unnecessary updates if (Math.abs(currentTimeInSeconds - currentTime) > 0.5) { safeSetState(() => setCurrentTime(currentTimeInSeconds)); - const progressPercent = duration > 0 ? currentTimeInSeconds / duration : 0; - Animated.timing(progressAnim, { - toValue: progressPercent, - duration: 250, - useNativeDriver: false, - }).start(); + // Removed progressAnim animation - no longer needed with React Native Community Slider const bufferedTime = event.bufferTime / 1000 || currentTimeInSeconds; safeSetState(() => setBuffered(bufferedTime)); } @@ -1273,12 +1253,9 @@ const VideoPlayer: React.FC = () => { setShowAudioModal={setShowAudioModal} setShowSubtitleModal={setShowSubtitleModal} setShowSourcesModal={setShowSourcesModal} - progressBarRef={progressBarRef} - progressAnim={progressAnim} - handleProgressBarTouch={handleProgressBarTouch} - handleProgressBarDragStart={handleProgressBarDragStart} - handleProgressBarDragMove={handleProgressBarDragMove} - handleProgressBarDragEnd={handleProgressBarDragEnd} + onSliderValueChange={handleSliderValueChange} + onSlidingStart={handleSlidingStart} + onSlidingComplete={handleSlidingComplete} buffered={buffered} formatTime={formatTime} /> diff --git a/src/components/player/controls/PlayerControls.tsx b/src/components/player/controls/PlayerControls.tsx index 6b76bf5d..695e995d 100644 --- a/src/components/player/controls/PlayerControls.tsx +++ b/src/components/player/controls/PlayerControls.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import { View, Text, TouchableOpacity, Animated, StyleSheet } from 'react-native'; +import { View, Text, TouchableOpacity, Animated, StyleSheet, Platform } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; +import Slider from '@react-native-community/slider'; import { styles } from '../utils/playerStyles'; import { getTrackDisplayName } from '../utils/playerUtils'; @@ -31,12 +32,10 @@ interface PlayerControlsProps { setShowAudioModal: (show: boolean) => void; setShowSubtitleModal: (show: boolean) => void; setShowSourcesModal?: (show: boolean) => void; - progressBarRef: React.RefObject; - progressAnim: Animated.Value; - handleProgressBarTouch: (event: any) => void; - handleProgressBarDragStart: () => void; - handleProgressBarDragMove: (event: any) => void; - handleProgressBarDragEnd: () => void; + // Slider-specific props + onSliderValueChange: (value: number) => void; + onSlidingStart: () => void; + onSlidingComplete: (value: number) => void; buffered: number; formatTime: (seconds: number) => string; } @@ -67,12 +66,9 @@ export const PlayerControls: React.FC = ({ setShowAudioModal, setShowSubtitleModal, setShowSourcesModal, - progressBarRef, - progressAnim, - handleProgressBarTouch, - handleProgressBarDragStart, - handleProgressBarDragMove, - handleProgressBarDragEnd, + onSliderValueChange, + onSlidingStart, + onSlidingComplete, buffered, formatTime, }) => { @@ -81,55 +77,25 @@ export const PlayerControls: React.FC = ({ style={[StyleSheet.absoluteFill, { opacity: fadeAnim }]} pointerEvents={showControls ? 'auto' : 'none'} > - {/* Progress bar with enhanced touch handling */} + {/* Progress slider with native iOS slider */} - - - - {/* Buffered Progress */} - - {/* Animated Progress */} - - - - {/* Progress Thumb - Moved outside the progressBarContainer */} - - - + {formatTime(currentTime)} {formatTime(duration)} @@ -244,4 +210,4 @@ export const PlayerControls: React.FC = ({ ); }; -export default PlayerControls; \ No newline at end of file +export default PlayerControls; \ No newline at end of file