fix(player): scrubber seekuje takze gdy dlugosc zna tylko scena, nie player

SPROSTOWANIE: paska postepu NIE trzeba bylo budowac, on juz istnial (track + fill +
thumb + gest + czasy, 48px hit-box). Moja wczesniejsza diagnoza "player nie ma czym
przewijac" byla bledna: szukalem po nazwach Slider/progressBar/seekBar, a implementacja
nazywa sie scrub*. Zamiast dublowac funkcje, zostal realny blad, ktory przy okazji
wyszedl.

Blad: UI paska liczy sie z `dur = knownDuration || durationSec || 0`, czyli z fallbackiem
na dlugosc z metadanych sceny, ale seek w `onEnd` byl strzezony warunkiem na samym
`knownDuration` (to, co zglosil player). Dla zrodla, ktore nie poda dlugosci playerowi,
a ma ja w metadanych, uchwyt i czas jechaly za palcem, a po puszczeniu nie dzialo sie
nic. Teraz seek uzywa tej samej wartosci co rysowanie, przez `durRef` (gest powstaje raz
w useMemo, wiec domykalby stara wartosc).

Zweryfikowane na emulatorze na realnym odtwarzaniu: przeciagniecie paska przenioslo
pozycje z 1:36 na 18:03, wypelnienie i uchwyt zgodne.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
goon-foss 2026-08-18 14:55:32 +02:00
parent 068a65dd8c
commit 20c04698b1
2 changed files with 21 additions and 3 deletions

View file

@ -16,6 +16,13 @@ export type ChangelogEntry = {
};
export const CHANGELOG: ChangelogEntry[] = [
{
id: '2026-08-18i',
date: 'August 2026',
items: [
'Dragging the progress bar now works on videos whose length the player has not reported yet. The handle and the time moved with your finger, but letting go did nothing; it seeks properly now.',
],
},
{
id: '2026-08-18h',
date: 'August 2026',

View file

@ -741,6 +741,11 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) {
);
const dur = knownDuration || durationSec || 0;
// Gest scrubbera powstaje raz (useMemo), więc czyta długość przez ref, nie z domknięcia.
const durRef = React.useRef(dur);
React.useEffect(() => {
durRef.current = dur;
}, [dur]);
const panSeek = React.useMemo(
() =>
@ -818,10 +823,16 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) {
})
.onEnd((e) => {
const w = scrubBarWidthRef.current;
if (w > 0 && knownDuration > 0) {
// `durRef`, NIE `knownDuration`: pasek RYSUJE się z `dur`, czyli z fallbackiem
// na długość z metadanych sceny, gdy player jeszcze nie zgłosił swojej. Warunek
// na samym `knownDuration` powodował, że przy takim źródle uchwyt i czas jechały
// za palcem, a po puszczeniu nie działo się nic. Ref, bo gest jest zbudowany raz
// i domykałby starą wartość.
const total = durRef.current;
if (w > 0 && total > 0) {
const ratio = Math.max(0, Math.min(1, e.x / w));
try {
player.currentTime = ratio * knownDuration;
player.currentTime = ratio * total;
} catch {
// ignore
}
@ -830,7 +841,7 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) {
scheduleHide();
})
.runOnJS(true),
[player, knownDuration, cancelHide, scheduleHide],
[player, cancelHide, scheduleHide],
);
// ----- fullscreen toggle ----------------------------------------------------