63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
export type WakeStatus = "off" | "waiting" | "requesting" | "active" | "unavailable" | "unsupported";
|
|
type Sentinel = Pick<WakeLockSentinel, "released" | "release" | "addEventListener">;
|
|
|
|
// Browser access is injected so asynchronous acquisition and release can be tested.
|
|
export function createScreenWakeLock(options: {
|
|
request?: () => Promise<Sentinel>;
|
|
visible: () => boolean;
|
|
status: (value: WakeStatus) => void;
|
|
}) {
|
|
let desired = false;
|
|
let disposed = false;
|
|
let pending = false;
|
|
let generation = 0;
|
|
let lock: Sentinel | null = null;
|
|
const report = (value: WakeStatus) => { if (!disposed) options.status(value); };
|
|
const wanted = () => desired && !disposed && options.visible();
|
|
function release() {
|
|
generation++;
|
|
const old = lock;
|
|
lock = null;
|
|
if (old) void old.release().catch(() => {});
|
|
}
|
|
async function sync() {
|
|
if (!wanted()) {
|
|
release();
|
|
report(desired ? "waiting" : "off");
|
|
return;
|
|
}
|
|
if (!options.request) { report("unsupported"); return; }
|
|
if (lock && !lock.released) { report("active"); return; }
|
|
if (pending) return;
|
|
pending = true;
|
|
const version = generation;
|
|
report("requesting");
|
|
try {
|
|
const acquired = await options.request();
|
|
if (version !== generation || !wanted()) {
|
|
await acquired.release();
|
|
return;
|
|
}
|
|
lock = acquired;
|
|
acquired.addEventListener("release", () => {
|
|
if (lock !== acquired) return;
|
|
lock = null;
|
|
// Do not repeatedly fight a system/battery decision to revoke the lock.
|
|
report(wanted() ? "unavailable" : desired ? "waiting" : "off");
|
|
}, { once: true });
|
|
report(acquired.released ? "unavailable" : "active");
|
|
} catch {
|
|
if (version === generation && wanted()) report("unavailable");
|
|
} finally {
|
|
pending = false;
|
|
// An off/on or hidden/visible transition may have invalidated a pending request.
|
|
if (version !== generation && wanted()) void sync();
|
|
}
|
|
}
|
|
return {
|
|
update(enabled: boolean) { desired = enabled; void sync(); },
|
|
refresh() { void sync(); },
|
|
dispose() { disposed = true; desired = false; release(); },
|
|
};
|
|
}
|