feat(audio-player): Resume Rewind select in the settings popover
Release / build-and-push (push) Successful in 4m43s

The player window could only change Skip and Speed; resume rewind
lived exclusively on the profile page. The user-facing settings now
match Speed's precedent — changeable from the player, saved to the
account, applied immediately.

The select mirrors the default-speed row (CSP-safe @change bound to
one Alpine method; templ emits the option list from the shared
ResumeRewindOptions allow-list and the :selected expression against
the live resumeRewind field). Applying updates the running player's
value first — the next open/unpause uses it with no reload — then
PUTs audio_resume_rewind_seconds to the profile endpoint as the
string wire shape the server binds. normalizeResumeRewind gates the
select's value through 0/5/10 before both steps.
This commit is contained in:
John O'Keefe committed 2026-11-01 21:29:19 -05:00
1 parent ef827a3a05
commit fbdd4ab9f9
4 files changed
+142 -40

No files matched your search

+21
View File
@@ -789,6 +789,27 @@ Alpine.data("audioReader", () => ({
applyDefaultSpeedFromSelect(e: Event) {
this.setDefaultSpeed(Number((e.target as HTMLSelectElement).value));
},
// Player-side control of the account setting: applies LIVE (the
// next open/unpause uses it — no reload) and rides the profile
// endpoint like the profile-page select. String wire shape — the
// server binds audio_resume_rewind_seconds keep_screen_awake-style.
applyResumeRewindFromSelect(e: Event) {
const seconds = normalizeResumeRewind((e.target as HTMLSelectElement).value);
this.resumeRewind = seconds;
fetch("/api/auth/profile", {
method: "PUT",
headers: { ...getAuthHeaders(), "content-type": "application/json" },
body: JSON.stringify({ audio_resume_rewind_seconds: String(seconds) }),
})
.then((r) => {
if (!r.ok) throw new Error(String(r.status));
showToast(
seconds === 0 ? "Resume rewind off" : `Resume rewind: ${seconds}s before saved position`,
"success",
);
})
.catch(() => showToast("Resume rewind not saved", "error"));
},
isDefaultSpeed(rate: number): boolean {
return this.defaultSpeed === rate;
},