feat: fix player
This commit is contained in:
@@ -19,11 +19,10 @@ export default ({
|
||||
}) => {
|
||||
const offset = useSharedValue(0)
|
||||
const boxWidth = useSharedValue(INITIAL_BOX_SIZE)
|
||||
const [layout, setLayout] = useState(null)
|
||||
const [sliderWidth, setSliderWidth] = useState(0)
|
||||
const seekingRef = useRef(false)
|
||||
|
||||
const SLIDER_WIDTH = layout?.width
|
||||
const MAX_VALUE = SLIDER_WIDTH - INITIAL_BOX_SIZE
|
||||
const MAX_VALUE = Math.max(0, sliderWidth - INITIAL_BOX_SIZE)
|
||||
|
||||
const handleSeekStart = () => {
|
||||
if (seekEnabled && typeof onSeekStart === 'function' && !seekingRef.current) {
|
||||
@@ -49,6 +48,11 @@ export default ({
|
||||
})
|
||||
.onChange((event) => {
|
||||
runOnJS(handleSeekStart)()
|
||||
if (!(MAX_VALUE > 0)) {
|
||||
offset.value = 0
|
||||
boxWidth.value = INITIAL_BOX_SIZE
|
||||
return
|
||||
}
|
||||
offset.value =
|
||||
Math.abs(offset.value) <= MAX_VALUE
|
||||
? offset.value + event.changeX <= 0
|
||||
@@ -62,7 +66,7 @@ export default ({
|
||||
boxWidth.value = newWidth
|
||||
})
|
||||
.onEnd(() => {
|
||||
if (seekEnabled && typeof onSeek === 'function' && MAX_VALUE) {
|
||||
if (seekEnabled && typeof onSeek === 'function' && MAX_VALUE > 0) {
|
||||
const ratio = MAX_VALUE > 0 ? Math.min(1, Math.max(0, offset.value / MAX_VALUE)) : 0
|
||||
// Reanimated -> JS thread bridge
|
||||
runOnJS(onSeek)(ratio)
|
||||
@@ -77,15 +81,20 @@ export default ({
|
||||
useEffect(() => {
|
||||
if (seekingRef.current) return
|
||||
|
||||
if (typeof progress === 'number' && layout?.width) {
|
||||
const max = layout.width - INITIAL_BOX_SIZE
|
||||
if (typeof progress === 'number' && sliderWidth > 0) {
|
||||
const max = sliderWidth - INITIAL_BOX_SIZE
|
||||
if (!(max > 0)) {
|
||||
offset.value = 0
|
||||
boxWidth.value = INITIAL_BOX_SIZE
|
||||
return
|
||||
}
|
||||
const clamped = Math.max(0, Math.min(1, progress))
|
||||
const newOffset = clamped * max
|
||||
offset.value = newOffset
|
||||
boxWidth.value = INITIAL_BOX_SIZE + newOffset
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [progress, layout?.width])
|
||||
}, [progress, sliderWidth])
|
||||
|
||||
const boxStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
@@ -100,8 +109,13 @@ export default ({
|
||||
})
|
||||
|
||||
return (
|
||||
<View onLayout={(e) => setLayout(e.nativeEvent.layout)}>
|
||||
<View style={{ ...styles.sliderTrack, width: SLIDER_WIDTH }}>
|
||||
<View
|
||||
onLayout={(e) => {
|
||||
const nextWidth = Math.max(0, Math.round(e.nativeEvent.layout?.width || 0))
|
||||
setSliderWidth((prev) => (prev === nextWidth ? prev : nextWidth))
|
||||
}}
|
||||
>
|
||||
<View style={{ ...styles.sliderTrack, width: sliderWidth || undefined }}>
|
||||
<Animated.View style={[styles.box, boxStyle]}>
|
||||
<LinearGradient
|
||||
colors={['#F94697', '#7023F7']}
|
||||
|
||||
@@ -25,6 +25,7 @@ const ProgressSlider = ({
|
||||
disabled = false,
|
||||
}) => {
|
||||
const wasPlayingRef = useRef(false)
|
||||
const pendingSeekPromiseRef = useRef(null)
|
||||
const [isSeeking, setIsSeeking] = useState(false)
|
||||
const [previewRatio, setPreviewRatio] = useState(null)
|
||||
|
||||
@@ -54,22 +55,36 @@ const ProgressSlider = ({
|
||||
const bounded = clamp01(ratio)
|
||||
setPreviewRatio(bounded)
|
||||
const targetMs = safeDuration * bounded
|
||||
onSeek(targetMs)
|
||||
const maybePromise = onSeek(targetMs)
|
||||
pendingSeekPromiseRef.current =
|
||||
maybePromise && typeof maybePromise.then === 'function'
|
||||
? maybePromise
|
||||
: Promise.resolve()
|
||||
},
|
||||
[disabled, onSeek, safeDuration]
|
||||
)
|
||||
|
||||
const handleSeekEnd = useCallback(() => {
|
||||
if (disabled || !safeDuration) return
|
||||
setIsSeeking(false)
|
||||
setPreviewRatio(null)
|
||||
if (typeof onSeekEnd === 'function') {
|
||||
onSeekEnd()
|
||||
const finalize = async () => {
|
||||
try {
|
||||
if (typeof onSeekEnd === 'function') {
|
||||
await onSeekEnd()
|
||||
}
|
||||
if (pendingSeekPromiseRef.current) {
|
||||
await pendingSeekPromiseRef.current
|
||||
}
|
||||
} finally {
|
||||
setIsSeeking(false)
|
||||
setPreviewRatio(null)
|
||||
pendingSeekPromiseRef.current = null
|
||||
if (wasPlayingRef.current && typeof onPlay === 'function') {
|
||||
onPlay()
|
||||
}
|
||||
wasPlayingRef.current = false
|
||||
}
|
||||
}
|
||||
if (wasPlayingRef.current && typeof onPlay === 'function') {
|
||||
onPlay()
|
||||
}
|
||||
wasPlayingRef.current = false
|
||||
finalize()
|
||||
}, [disabled, onPlay, onSeekEnd, safeDuration])
|
||||
|
||||
return (
|
||||
@@ -78,7 +93,7 @@ const ProgressSlider = ({
|
||||
isSeeking && previewRatio != null ? safeDuration * previewRatio : safePosition
|
||||
)}
|
||||
maxValue={formatTime(safeDuration)}
|
||||
progress={progress}
|
||||
progress={isSeeking && previewRatio != null ? previewRatio : progress}
|
||||
seekEnabled={!disabled && safeDuration > 0}
|
||||
onSeekStart={handleSeekStart}
|
||||
onSeek={handleSeek}
|
||||
|
||||
Reference in New Issue
Block a user