feat: fix player

This commit is contained in:
Victor
2026-02-27 15:50:57 +01:00
parent ae93cd4521
commit 006b65eed4
5 changed files with 385 additions and 166 deletions
+23 -9
View File
@@ -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 -10
View File
@@ -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}