chore(sample): review seeker in sample (#3787)
This commit is contained in:
155
examples/basic/src/components/Seeker.tsx
Normal file
155
examples/basic/src/components/Seeker.tsx
Normal file
@@ -0,0 +1,155 @@
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {PanResponder, View} from 'react-native';
|
||||
import styles from '../styles';
|
||||
|
||||
interface SeekerProps {
|
||||
currentTime: number;
|
||||
duration: number;
|
||||
isLoading: boolean;
|
||||
isUISeeking: boolean;
|
||||
videoSeek: (arg0: number) => void;
|
||||
}
|
||||
|
||||
const Seeker = ({
|
||||
currentTime,
|
||||
duration,
|
||||
isLoading,
|
||||
isUISeeking,
|
||||
videoSeek,
|
||||
}: SeekerProps) => {
|
||||
const [seeking, setSeeking] = useState(false);
|
||||
const [seekerPosition, setSeekerPosition] = useState(0);
|
||||
const [seekerWidth, setSeekerWidth] = useState(0);
|
||||
|
||||
/**
|
||||
* Set the position of the seekbar's components
|
||||
* (both fill and handle) according to the
|
||||
* position supplied.
|
||||
*
|
||||
* @param {float} position position in px of seeker handle}
|
||||
*/
|
||||
const updateSeekerPosition = useCallback(
|
||||
(position = 0) => {
|
||||
if (position <= 0) {
|
||||
position = 0;
|
||||
} else if (position >= seekerWidth) {
|
||||
position = seekerWidth;
|
||||
}
|
||||
setSeekerPosition(position);
|
||||
},
|
||||
[seekerWidth],
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the time that the video should be at
|
||||
* based on where the seeker handle is.
|
||||
*
|
||||
* @return {float} time in ms based on seekerPosition.
|
||||
*/
|
||||
const calculateTimeFromSeekerPosition = () => {
|
||||
const percent = seekerPosition / seekerWidth;
|
||||
return duration * percent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get our seekbar responder going
|
||||
*/
|
||||
|
||||
const seekPanResponder = PanResponder.create({
|
||||
// Ask to be the responder.
|
||||
onStartShouldSetPanResponder: (_evt, _gestureState) => true,
|
||||
onMoveShouldSetPanResponder: (_evt, _gestureState) => true,
|
||||
|
||||
/**
|
||||
* When we start the pan tell the machine that we're
|
||||
* seeking. This stops it from updating the seekbar
|
||||
* position in the onProgress listener.
|
||||
*/
|
||||
onPanResponderGrant: (evt, _gestureState) => {
|
||||
const position = evt.nativeEvent.locationX;
|
||||
updateSeekerPosition(position);
|
||||
setSeeking(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* When panning, update the seekbar position, duh.
|
||||
*/
|
||||
onPanResponderMove: (evt, _gestureState) => {
|
||||
const position = evt.nativeEvent.locationX;
|
||||
updateSeekerPosition(position);
|
||||
},
|
||||
|
||||
/**
|
||||
* On release we update the time and seek to it in the video.
|
||||
* If you seek to the end of the video we fire the
|
||||
* onEnd callback
|
||||
*/
|
||||
onPanResponderRelease: (_evt, _gestureState) => {
|
||||
const time = calculateTimeFromSeekerPosition();
|
||||
if (time >= duration && !isLoading) {
|
||||
// FIXME ...
|
||||
// state.paused = true;
|
||||
// this.onEnd();
|
||||
} else {
|
||||
videoSeek(time);
|
||||
setSeeking(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && !seeking && !isUISeeking) {
|
||||
console.log('update position from currentTime');
|
||||
const percent = currentTime / duration;
|
||||
const position = seekerWidth * percent;
|
||||
updateSeekerPosition(position);
|
||||
}
|
||||
}, [
|
||||
currentTime,
|
||||
duration,
|
||||
isLoading,
|
||||
seekerWidth,
|
||||
seeking,
|
||||
isUISeeking,
|
||||
updateSeekerPosition,
|
||||
]);
|
||||
|
||||
if (!seekPanResponder) {
|
||||
return null;
|
||||
}
|
||||
const seekerStyle = [
|
||||
styles.seekbarFill,
|
||||
{
|
||||
width: seekerPosition > 0 ? seekerPosition : 0,
|
||||
backgroundColor: '#FFF',
|
||||
},
|
||||
];
|
||||
|
||||
const seekerPositionStyle = [
|
||||
styles.seekbarHandle,
|
||||
{
|
||||
left: seekerPosition > 0 ? seekerPosition : 0,
|
||||
},
|
||||
];
|
||||
|
||||
const seekerPointerStyle = [styles.seekbarCircle, {backgroundColor: '#FFF'}];
|
||||
|
||||
return (
|
||||
<View
|
||||
style={styles.seekbarContainer}
|
||||
{...seekPanResponder.panHandlers}
|
||||
{...styles.generalControls}>
|
||||
<View
|
||||
style={styles.seekbarTrack}
|
||||
onLayout={event => setSeekerWidth(event.nativeEvent.layout.width)}
|
||||
pointerEvents={'none'}>
|
||||
<View style={seekerStyle} pointerEvents={'none'} />
|
||||
</View>
|
||||
<View style={seekerPositionStyle} pointerEvents={'none'}>
|
||||
<View style={seekerPointerStyle} pointerEvents={'none'} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Seeker;
|
Reference in New Issue
Block a user