fix(audio): replace autoStartPending bool with autoStartChapter number
The boolean flag was set by onended before goto() resolved, causing the still-mounted outgoing chapter's AudioPlayer $effect to fire and call startPlayback() for the wrong (old) chapter — restarting it from scratch. Replace with autoStartChapter (number | null): the AudioPlayer only acts when its own chapter prop === autoStartChapter, so the outgoing component never matches and the incoming one fires exactly once on mount.
This commit is contained in:
@@ -85,11 +85,16 @@ class AudioStore {
|
|||||||
nextChapter = $state<number | null>(null);
|
nextChapter = $state<number | null>(null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to true by the layout's onended handler (when autoNext fires a
|
* Set to the chapter number that should auto-start by the layout's onended
|
||||||
* navigation). The AudioPlayer on the new page checks this on mount
|
* handler (when autoNext fires a navigation). The AudioPlayer on the new
|
||||||
* and, if true, immediately starts the play flow then clears the flag.
|
* page checks this on mount: if it matches the component's own chapter prop
|
||||||
|
* it starts playback and clears the value.
|
||||||
|
*
|
||||||
|
* Using the target chapter number (instead of a plain boolean) prevents the
|
||||||
|
* still-mounted outgoing AudioPlayer from reacting to the flag before the
|
||||||
|
* navigation completes — it only matches the incoming chapter's component.
|
||||||
*/
|
*/
|
||||||
autoStartPending = $state(false);
|
autoStartChapter = $state<number | null>(null);
|
||||||
|
|
||||||
// ── Next-chapter pre-fetch state ─────────────────────────────────────────
|
// ── Next-chapter pre-fetch state ─────────────────────────────────────────
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -70,9 +70,11 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Auto-start: if the layout navigated here via auto-next, kick off playback.
|
// Auto-start: if the layout navigated here via auto-next, kick off playback.
|
||||||
|
// We match against the chapter prop so the outgoing chapter's AudioPlayer
|
||||||
|
// (still mounted during the brief navigation window) never reacts to this.
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (audioStore.autoStartPending) {
|
if (audioStore.autoStartChapter === chapter) {
|
||||||
audioStore.autoStartPending = false;
|
audioStore.autoStartChapter = null;
|
||||||
startPlayback();
|
startPlayback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -184,9 +184,11 @@
|
|||||||
// we need.
|
// we need.
|
||||||
const targetSlug = audioStore.slug;
|
const targetSlug = audioStore.slug;
|
||||||
const targetChapter = audioStore.nextChapter;
|
const targetChapter = audioStore.nextChapter;
|
||||||
audioStore.autoStartPending = true;
|
// Store the target chapter number so only the newly-mounted AudioPlayer
|
||||||
|
// for that chapter reacts — not the outgoing chapter's component.
|
||||||
|
audioStore.autoStartChapter = targetChapter;
|
||||||
goto(`/books/${targetSlug}/chapters/${targetChapter}`).catch(() => {
|
goto(`/books/${targetSlug}/chapters/${targetChapter}`).catch(() => {
|
||||||
audioStore.autoStartPending = false;
|
audioStore.autoStartChapter = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user