Spaces:
Running
Running
File size: 2,681 Bytes
6c3af4e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | import { useEffect } from "react";
import { addLogEntry } from "@/modules/logEntries";
const describeError = (error: unknown) =>
error instanceof Error ? error.message : "unknown error";
/**
* Holds the platform screen wake lock while `isActive` is true, so a phone left
* untouched during a long answer does not lock while the text streams in.
*
* The platform releases the lock on its own whenever the document stops being
* visible (tab switch, screen lock) and a released sentinel cannot be reused,
* so a fresh one is requested on every return to visibility. A lock the browser
* drops for another reason (power saving, low battery) is only replaced on the
* next return to visibility, because re-requesting straight from the `release`
* event fights the browser's own decision. The same goes for a visibility round
* trip that happens entirely while a request is pending: the request in flight
* wins, and if it fails there is no event left to retry on until the next one.
* See https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API
*/
export function useScreenWakeLock(isActive: boolean) {
useEffect(() => {
if (!isActive || !("wakeLock" in navigator)) return;
let sentinel: WakeLockSentinel | null = null;
let isEffectActive = true;
let isRequestInFlight = false;
const acquireWakeLock = async () => {
if (
sentinel ||
isRequestInFlight ||
document.visibilityState !== "visible"
) {
return;
}
isRequestInFlight = true;
try {
const requestedSentinel = await navigator.wakeLock.request("screen");
if (!isEffectActive) {
await requestedSentinel.release();
return;
}
if (requestedSentinel.released) return;
sentinel = requestedSentinel;
requestedSentinel.addEventListener("release", () => {
if (sentinel === requestedSentinel) sentinel = null;
});
addLogEntry("Screen wake lock acquired");
} catch (error) {
addLogEntry(`Screen wake lock unavailable: ${describeError(error)}`);
} finally {
isRequestInFlight = false;
}
};
acquireWakeLock();
document.addEventListener("visibilitychange", acquireWakeLock);
return () => {
isEffectActive = false;
document.removeEventListener("visibilitychange", acquireWakeLock);
sentinel
?.release()
.then(() => addLogEntry("Screen wake lock released"))
.catch((error: unknown) => {
addLogEntry(
`Failed to release screen wake lock: ${describeError(error)}`,
);
});
};
}, [isActive]);
}
|