one
Version:
One is a React framework for web, iOS, and Android apps.
77 lines (71 loc) • 2.54 kB
text/typescript
import { useEffect, useId } from 'react'
import { KeepAwake as unavailable } from './unavailable'
import {
assertKeepAwakeEnabled,
assertKeepAwakeTag,
normalizeKeepAwakeTag,
} from './validate'
const active = new Set<string>()
let lock: WakeLockSentinel | undefined
let operation: Promise<void> = Promise.resolve()
function live(): boolean {
return !!lock && !lock.released
}
function apply(owner: 'setEnabled' | 'activate' | 'deactivate'): Promise<void> {
const next = operation
.catch(() => {})
.then(async () => {
if (active.size === 0) {
await lock?.release()
lock = undefined
return
}
if (live()) return
if (!navigator.wakeLock)
throw new Error(`KeepAwake.${owner}: Screen Wake Lock is unavailable`)
lock = await navigator.wakeLock.request('screen')
})
operation = next
return next
}
export const KeepAwake = Object.freeze({
isEnabled: async (): Promise<boolean> =>
typeof window !== 'undefined' && active.size > 0 && live(),
setEnabled: (enabled: boolean): Promise<void> => {
assertKeepAwakeEnabled(enabled)
if (typeof window === 'undefined') return unavailable.setEnabled(enabled)
if (enabled) active.add(normalizeKeepAwakeTag(undefined))
else active.delete(normalizeKeepAwakeTag(undefined))
return apply('setEnabled')
},
activate: (tag?: string): Promise<void> => {
assertKeepAwakeTag(tag, 'activate')
if (typeof window === 'undefined') return unavailable.activate(tag)
active.add(normalizeKeepAwakeTag(tag))
return apply('activate')
},
deactivate: (tag?: string): Promise<void> => {
assertKeepAwakeTag(tag, 'deactivate')
if (typeof window === 'undefined') return unavailable.deactivate(tag)
active.delete(normalizeKeepAwakeTag(tag))
return apply('deactivate')
},
})
export function useKeepAwake(tag?: string): void {
const fallback = useId()
assertKeepAwakeTag(tag, 'useKeepAwake')
// a hook without a tag owns an id unique to its component instance, never
// the shared default tag, matching expo-keep-awake.
const effective = tag ?? fallback
useEffect(() => {
if (typeof window === 'undefined') return
// a hook has no caller to reject to, so failures are reported, as
// usePreventScreenCapture does.
KeepAwake.activate(effective).catch((error: unknown) => {
console.error(`Failed to keep the screen awake: ${String(error)}`)
})
return () => {
KeepAwake.deactivate(effective).catch(() => {})
}
}, [effective])
}