From 79b3de3e8db62051a70209d0aacb81cdc5d35302 Mon Sep 17 00:00:00 2001 From: Admin Date: Mon, 6 Apr 2026 00:15:12 +0500 Subject: [PATCH] fix(player): fill ListeningMode empty space + global audio context + chapter picker from mini-bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - justify-between on scrollable body so cover art sits top, controls sit bottom — no more half-empty screen on tall phones - Move ListeningMode outside {#if audioStore.active} so pausing never tears down the overlay and loses resume context - Mini-bar time/track click now opens ListeningMode with chapter picker pre-shown (same view as the Chapters button inside ListeningMode) - Remove the old chapterDrawerOpen mini-bar drawer (replaced by above) - Add openChapters prop to ListeningMode for pre-opening chapter modal --- ui/src/lib/components/ListeningMode.svelte | 316 +++++++++++---------- ui/src/routes/+layout.svelte | 83 +----- 2 files changed, 175 insertions(+), 224 deletions(-) diff --git a/ui/src/lib/components/ListeningMode.svelte b/ui/src/lib/components/ListeningMode.svelte index da30799..e9cb86c 100644 --- a/ui/src/lib/components/ListeningMode.svelte +++ b/ui/src/lib/components/ListeningMode.svelte @@ -7,9 +7,11 @@ interface Props { /** Called when the user closes the overlay. */ onclose: () => void; + /** When true, open the chapter picker immediately on mount. */ + openChapters?: boolean; } - let { onclose }: Props = $props(); + let { onclose, openChapters = false }: Props = $props(); // Voices come from the store (populated by AudioPlayer on mount/play) const voices = $derived(audioStore.voices); @@ -18,7 +20,8 @@ const cfaiVoices = $derived(voices.filter((v) => v.engine === 'cfai')); let showVoiceModal = $state(false); - let showChapterModal = $state(false); + // svelte-ignore state_referenced_locally + let showChapterModal = $state(openChapters && audioStore.chapters.length > 0); let voiceSearch = $state(''); let samplePlayingVoice = $state(null); let sampleAudio: HTMLAudioElement | null = null; @@ -419,19 +422,19 @@ {/if} - -
+ +
-
+
{#if audioStore.cover} {:else} -
+
@@ -444,165 +447,170 @@

{audioStore.bookTitle}

- -
- -
- {formatTime(audioStore.currentTime)} - {formatTime(audioStore.duration)} + +
+ + +
+ +
+ {formatTime(audioStore.currentTime)} + {formatTime(audioStore.duration)} +
-
- -
- - {#if audioStore.chapter > 1 && audioStore.slug} - - - - - - {:else} -
- {/if} - - - - - - - - - - - {#if audioStore.nextChapter !== null && audioStore.slug} - + + + + + + + + + + {#if audioStore.nextChapter !== null && audioStore.slug} + + + + + + {:else} +
+ {/if} +
+ + +
+ +
+ {#each SPEED_OPTIONS as s} + + {/each} +
+ + +
+ Auto + {#if audioStore.autoNext && audioStore.nextStatus === 'prefetching'} + + {:else if audioStore.autoNext && audioStore.nextStatus === 'prefetched'} + + {/if} + - -
- -
- {#each SPEED_OPTIONS as s} - - {/each} + +
- - - - -
diff --git a/ui/src/routes/+layout.svelte b/ui/src/routes/+layout.svelte index ee78740..304c00c 100644 --- a/ui/src/routes/+layout.svelte +++ b/ui/src/routes/+layout.svelte @@ -33,28 +33,13 @@ ]; // Chapter list drawer state for the mini-player - let chapterDrawerOpen = $state(false); - let activeChapterEl = $state(null); let listeningModeOpen = $state(false); + let listeningModeChapters = $state(false); // Build time formatted in the user's local timezone (populated on mount so // SSR and CSR don't produce a mismatch — SSR renders nothing, hydration fills it in). let buildTimeLocal = $state(''); - function setIfActive(node: HTMLElement, isActive: boolean) { - if (isActive) activeChapterEl = node; - return { - update(nowActive: boolean) { if (nowActive) activeChapterEl = node; }, - destroy() { if (activeChapterEl === node) activeChapterEl = null; } - }; - } - - $effect(() => { - if (chapterDrawerOpen && activeChapterEl) { - activeChapterEl.scrollIntoView({ block: 'center' }); - } - }); - $effect(() => { if (env.PUBLIC_BUILD_TIME && env.PUBLIC_BUILD_TIME !== 'unknown') { buildTimeLocal = new Date(env.PUBLIC_BUILD_TIME).toLocaleString(); @@ -792,52 +777,6 @@ {#if audioStore.active}
- - {#if chapterDrawerOpen && audioStore.chapters.length > 0} -
-
- -
- {m.player_chapters()} - -
- - -
-
- {/if} - {#if audioStore.status === 'generating' || audioStore.status === 'loading'}
@@ -864,10 +803,10 @@
- +
- - - {#if listeningModeOpen} - (listeningModeOpen = false)} /> - {/if} +{/if} + + +{#if listeningModeOpen} + { listeningModeOpen = false; listeningModeChapters = false; }} + openChapters={listeningModeChapters} + /> {/if}