feat(audio-player): end-time label toggles total / book-left / chapter-left (plan §10 web)
Clicking the end time cycles the three display modes, persisted per device in localStorage (audio_time_display). Pure helpers (mode list, normalize, cycle, endTimeLabel with 0-clamp and no-chapters fallback to book remaining) + vitest; aria-label announces the current mode and the next. Remaining values track the scrub cursor mid-drag. 140 unit tests; 15 Playwright checks on KJV + Gardens.
This commit is contained in:
1 parent
96fd2aad42
commit
a9430f3c06
4 files changed
+121
-4
No files matched your search
+48
-2
@@ -2,11 +2,15 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
SPEEDS,
|
||||
normalizeSpeed,
|
||||
stepSpeed,
|
||||
SKIP_SECONDS,
|
||||
TIME_DISPLAY_MODES,
|
||||
cycleSkip,
|
||||
cycleTimeDisplay,
|
||||
endTimeLabel,
|
||||
normalizeAutoplay,
|
||||
normalizeSpeed,
|
||||
normalizeTimeDisplay,
|
||||
stepSpeed,
|
||||
} from "./audio";
|
||||
|
||||
describe("SPEEDS", () => {
|
||||
@@ -93,3 +97,45 @@ describe("normalizeAutoplay", () => {
|
||||
expect(normalizeAutoplay("2")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("time display mode (§10 end-label toggle)", () => {
|
||||
it("cycles total → book remaining → chapter remaining → total", () => {
|
||||
expect(TIME_DISPLAY_MODES).toEqual(["total", "book-left", "chapter-left"]);
|
||||
expect(cycleTimeDisplay("total")).toBe("book-left");
|
||||
expect(cycleTimeDisplay("book-left")).toBe("chapter-left");
|
||||
expect(cycleTimeDisplay("chapter-left")).toBe("total");
|
||||
});
|
||||
|
||||
it("normalizes persisted values, defaulting to total", () => {
|
||||
expect(normalizeTimeDisplay("total")).toBe("total");
|
||||
expect(normalizeTimeDisplay("book-left")).toBe("book-left");
|
||||
expect(normalizeTimeDisplay("chapter-left")).toBe("chapter-left");
|
||||
expect(normalizeTimeDisplay(null)).toBe("total");
|
||||
expect(normalizeTimeDisplay("")).toBe("total");
|
||||
expect(normalizeTimeDisplay("remaining")).toBe("total");
|
||||
});
|
||||
|
||||
it("renders total as the book duration", () => {
|
||||
// 93807s = 26:03:27 (Gardens-shaped)
|
||||
expect(endTimeLabel("total", 0, 93_807, null)).toBe("26:03:27");
|
||||
});
|
||||
|
||||
it("renders book remaining, clamped at zero", () => {
|
||||
expect(endTimeLabel("book-left", 93_807 - 3_662, 93_807, null)).toBe("−1:01:02");
|
||||
expect(endTimeLabel("book-left", 93_807, 93_807, null)).toBe("−0:00");
|
||||
expect(endTimeLabel("book-left", 99_999, 93_807, null)).toBe("−0:00");
|
||||
});
|
||||
|
||||
it("renders chapter remaining with minutes:seconds formatting", () => {
|
||||
// 842s left in the chapter → −14:02
|
||||
expect(endTimeLabel("chapter-left", 5_000, 93_807, 5_842)).toBe("−14:02");
|
||||
});
|
||||
|
||||
it("falls back to book remaining when the book has no chapters", () => {
|
||||
expect(endTimeLabel("chapter-left", 93_807 - 3_662, 93_807, null)).toBe("−1:01:02");
|
||||
});
|
||||
|
||||
it("treats a chapter end in the past as zero remaining", () => {
|
||||
expect(endTimeLabel("chapter-left", 6_000, 93_807, 5_842)).toBe("−0:00");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user