slider change

This commit is contained in:
tapframe 2025-07-29 14:39:49 +05:30
parent 6405fd2c71
commit 17339d82a6
3 changed files with 65 additions and 146 deletions

View file

@ -124,8 +124,7 @@ const AndroidVideoPlayer: React.FC = () => {
const [rnVideoAudioTracks, setRnVideoAudioTracks] = useState<Array<{id: number, name: string, language?: string}>>([]);
const [rnVideoTextTracks, setRnVideoTextTracks] = useState<Array<{id: number, name: string, language?: string}>>([]);
const [isPlayerReady, setIsPlayerReady] = useState(false);
const progressAnim = useRef(new Animated.Value(0)).current;
const progressBarRef = useRef<View>(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<NodeJS.Timeout | null>(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}
/>

View file

@ -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<Array<{ id: number, name: string, language?: string }>>([]);
const [vlcTextTracks, setVlcTextTracks] = useState<Array<{ id: number, name: string, language?: string }>>([]);
const [isPlayerReady, setIsPlayerReady] = useState(false);
const progressAnim = useRef(new Animated.Value(0)).current;
const progressBarRef = useRef<View>(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<NodeJS.Timeout | null>(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}
/>

View file

@ -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<View>;
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<PlayerControlsProps> = ({
setShowAudioModal,
setShowSubtitleModal,
setShowSourcesModal,
progressBarRef,
progressAnim,
handleProgressBarTouch,
handleProgressBarDragStart,
handleProgressBarDragMove,
handleProgressBarDragEnd,
onSliderValueChange,
onSlidingStart,
onSlidingComplete,
buffered,
formatTime,
}) => {
@ -81,55 +77,25 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
style={[StyleSheet.absoluteFill, { opacity: fadeAnim }]}
pointerEvents={showControls ? 'auto' : 'none'}
>
{/* Progress bar with enhanced touch handling */}
{/* Progress slider with native iOS slider */}
<View style={styles.sliderContainer}>
<View
style={styles.progressTouchArea}
onTouchStart={handleProgressBarDragStart}
onTouchMove={handleProgressBarDragMove}
onTouchEnd={handleProgressBarDragEnd}
>
<TouchableOpacity
activeOpacity={0.8}
onPress={handleProgressBarTouch}
style={{width: '100%'}}
>
<View
ref={progressBarRef}
style={styles.progressBarContainer}
>
{/* Buffered Progress */}
<View style={[styles.bufferProgress, {
width: `${(buffered / (duration || 1)) * 100}%`
}]} />
{/* Animated Progress */}
<Animated.View
style={[
styles.progressBarFill,
{
width: progressAnim.interpolate({
inputRange: [0, 1],
outputRange: ['0%', '100%']
})
}
]}
/>
</View>
{/* Progress Thumb - Moved outside the progressBarContainer */}
<Animated.View
style={[
styles.progressThumb,
{
left: progressAnim.interpolate({
inputRange: [0, 1],
outputRange: ['0%', '100%']
})
}
]}
/>
</TouchableOpacity>
</View>
<Slider
style={{
width: '100%',
height: 40,
marginHorizontal: 0,
}}
minimumValue={0}
maximumValue={duration || 1}
value={currentTime}
onValueChange={onSliderValueChange}
onSlidingStart={onSlidingStart}
onSlidingComplete={onSlidingComplete}
minimumTrackTintColor="#FFFFFF"
maximumTrackTintColor="rgba(255, 255, 255, 0.3)"
thumbTintColor={Platform.OS === 'android' ? '#FFFFFF' : undefined}
tapToSeek={Platform.OS === 'ios'}
/>
<View style={styles.timeDisplay}>
<Text style={styles.duration}>{formatTime(currentTime)}</Text>
<Text style={styles.duration}>{formatTime(duration)}</Text>
@ -244,4 +210,4 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
);
};
export default PlayerControls;
export default PlayerControls;