feat(web): hold a Screen Wake Lock while reading or listening
Release / build-and-push (push) Successful in 3m12s
Release / build-and-push (push) Successful in 3m12s
New wake-lock.ts engine (sanctioned island, dependency-injected for tests): feature-detected navigator.wakeLock, silent no-op when unsupported or denied, and the spec-mandated force-release-on-hide → re-acquire-on-visible loop handled via the sentinel release event. The player acquires on play and releases on pause (sleep-timer fades ride the same path); the reader holds the lock for the session. Both gate on the keep_screen_awake preference — data-keep-awake on the player root, keepScreenAwake in readerInitExpr. Hidden-tab playback intentionally does not keep the screen awake: the spec forbids screen wake locks for hidden documents.
This commit is contained in:
1 parent
c645b8e207
commit
afbf1029a9
8 files changed
+375
-56
No files matched your search
@@ -15,6 +15,7 @@
|
||||
import { Alpine } from "./alpine";
|
||||
import { renderNoteHtml } from "./markdown";
|
||||
import { showToast } from "./toast";
|
||||
import { WakeLockManager } from "./wake-lock";
|
||||
import {
|
||||
MOUSE_GUIDE,
|
||||
resolveShortcut,
|
||||
@@ -288,6 +289,13 @@ Alpine.data("audioReader", () => ({
|
||||
// 30s of a countdown. Reset by stop/finish.
|
||||
sleepDim: 0,
|
||||
|
||||
// Screen wake lock (keep_screen_awake profile preference): held while
|
||||
// playing so the display doesn't blank/lock mid-listen. The browser
|
||||
// force-releases when the page hides; the manager re-acquires on
|
||||
// visibility regain while audio is still going.
|
||||
wakeLock: new WakeLockManager(),
|
||||
keepAwakeEnabled: false,
|
||||
|
||||
// Settings popover (plan §4): header gear → panel. Autoplay-on-open
|
||||
// is the first option; the panel is structured for more.
|
||||
settingsOpen: false,
|
||||
@@ -336,6 +344,7 @@ Alpine.data("audioReader", () => ({
|
||||
const title = body.getAttribute("data-title") || "";
|
||||
const cover = body.getAttribute("data-cover") || "";
|
||||
const fileUrl = body.getAttribute("data-file-url") || "";
|
||||
this.keepAwakeEnabled = body.getAttribute("data-keep-awake") === "true";
|
||||
this.mediaItemId = mediaId;
|
||||
this.title = title;
|
||||
this.fileUrl = fileUrl;
|
||||
@@ -413,6 +422,7 @@ Alpine.data("audioReader", () => ({
|
||||
// is awake and asked for audio); stopSleep restores the volume.
|
||||
if (this.sleep.mode === "fading") this.stopSleep();
|
||||
this.updateMediaSessionState();
|
||||
if (this.keepAwakeEnabled) void this.wakeLock.acquire();
|
||||
});
|
||||
audio.addEventListener("pause", () => {
|
||||
const now = performance.now();
|
||||
@@ -423,6 +433,7 @@ Alpine.data("audioReader", () => ({
|
||||
this.playing = false;
|
||||
this.pushProgress(true);
|
||||
this.updateMediaSessionState();
|
||||
if (this.keepAwakeEnabled) this.wakeLock.release();
|
||||
});
|
||||
window.addEventListener("pagehide", () => this.pushProgress(true));
|
||||
window.addEventListener("resize", () => this.recomputeTicks());
|
||||
|
||||
Reference in new issue
Block a user