1import { CodedError, Platform, Subscription } from 'expo-modules-core';
2
3import { KeepAwakeEventState, KeepAwakeListener } from './KeepAwake.types';
4
5const wakeLockMap: Record<string, WakeLockSentinel> = {};
6
7type WakeLockSentinel = {
8  onrelease: null | ((event: any) => void);
9  released: boolean;
10  type: 'screen';
11  release?: Function;
12
13  addEventListener?: (event: string, listener: (event: any) => void) => void;
14  removeEventListener?: (event: string, listener: (event: any) => void) => void;
15};
16
17declare const navigator: {
18  wakeLock: {
19    request(type: 'screen'): Promise<WakeLockSentinel>;
20  };
21};
22
23/** Wraps the webWakeLock API https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API */
24export default {
25  async isAvailableAsync() {
26    if (Platform.isDOMAvailable) {
27      return 'wakeLock' in navigator;
28    }
29    return false;
30  },
31  async activate(tag: string) {
32    if (!Platform.isDOMAvailable) {
33      return;
34    }
35    const wakeLock = await navigator.wakeLock.request('screen');
36    wakeLockMap[tag] = wakeLock;
37  },
38  async deactivate(tag: string) {
39    if (!Platform.isDOMAvailable) {
40      return;
41    }
42    if (wakeLockMap[tag]) {
43      wakeLockMap[tag].release?.();
44      delete wakeLockMap[tag];
45    } else {
46      throw new CodedError(
47        'ERR_KEEP_AWAKE_TAG_INVALID',
48        `The wake lock with tag ${tag} has not activated yet`
49      );
50    }
51  },
52  addListenerForTag(tag: string, listener: KeepAwakeListener): Subscription {
53    const eventListener = () => {
54      listener({ state: KeepAwakeEventState.RELEASE });
55    };
56    const sentinel = wakeLockMap[tag];
57    if (sentinel) {
58      if ('addEventListener' in sentinel) {
59        sentinel.addEventListener?.('release', eventListener);
60      } else {
61        sentinel.onrelease = eventListener;
62      }
63    }
64    return {
65      remove: () => {
66        const sentinel = wakeLockMap[tag];
67        if (sentinel) {
68          if (sentinel.removeEventListener) {
69            sentinel.removeEventListener('release', eventListener);
70          } else {
71            sentinel.onrelease = null;
72          }
73        }
74      },
75    };
76  },
77};
78