@symbiote-native/keep-awake 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/build/angular/index.d.ts +2 -0
- package/build/angular/index.js +4 -0
- package/build/angular/services/keep-awake.service/index.d.ts +5 -0
- package/build/angular/services/keep-awake.service/index.js +83 -0
- package/build/core/index.d.ts +3 -0
- package/build/core/index.js +1 -0
- package/build/core/keep-awake.d.ts +17 -0
- package/build/core/keep-awake.js +41 -0
- package/build/core/native-module.d.ts +9 -0
- package/build/core/native-module.js +3 -0
- package/build/core/types.d.ts +8 -0
- package/build/core/types.js +1 -0
- package/build/react/hooks/use-keep-awake/index.d.ts +2 -0
- package/build/react/hooks/use-keep-awake/index.js +35 -0
- package/build/react/index.d.ts +2 -0
- package/build/react/index.js +5 -0
- package/build/vue/composables/use-keep-awake/index.d.ts +2 -0
- package/build/vue/composables/use-keep-awake/index.js +28 -0
- package/build/vue/index.d.ts +2 -0
- package/build/vue/index.js +5 -0
- package/build-ngc/angular/index.d.ts +2 -0
- package/build-ngc/angular/index.js +5 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/angular/services/keep-awake.service/index.d.ts +8 -0
- package/build-ngc/angular/services/keep-awake.service/index.js +41 -0
- package/build-ngc/angular/services/keep-awake.service/index.js.map +1 -0
- package/build-ngc/core/index.d.ts +3 -0
- package/build-ngc/core/index.js +2 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/keep-awake.d.ts +17 -0
- package/build-ngc/core/keep-awake.js +42 -0
- package/build-ngc/core/keep-awake.js.map +1 -0
- package/build-ngc/core/native-module.d.ts +9 -0
- package/build-ngc/core/native-module.js +4 -0
- package/build-ngc/core/native-module.js.map +1 -0
- package/build-ngc/core/types.d.ts +8 -0
- package/build-ngc/core/types.js +2 -0
- package/build-ngc/core/types.js.map +1 -0
- package/native-link.json +12 -0
- package/package.json +107 -0
- package/src/angular/index.ts +14 -0
- package/src/angular/services/keep-awake.service/index.ts +46 -0
- package/src/angular/services/keep-awake.service/keep-awake.service.test.ts +98 -0
- package/src/core/index.ts +9 -0
- package/src/core/keep-awake.test.ts +119 -0
- package/src/core/keep-awake.ts +50 -0
- package/src/core/native-module.ts +20 -0
- package/src/core/types.ts +14 -0
- package/src/react/hooks/use-keep-awake/index.ts +43 -0
- package/src/react/hooks/use-keep-awake/use-keep-awake.test.tsx +70 -0
- package/src/react/index.ts +16 -0
- package/src/vue/composables/use-keep-awake/index.ts +36 -0
- package/src/vue/composables/use-keep-awake/use-keep-awake.test.ts +76 -0
- package/src/vue/index.ts +16 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 A. Prokopenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# @symbiote-native/keep-awake
|
|
2
|
+
|
|
3
|
+
Port of [`expo-keep-awake`](https://docs.expo.dev/versions/latest/sdk/keep-awake/) for
|
|
4
|
+
[SymbioteNative](../../README.md) — keeps the screen on for the lifetime of a mounted
|
|
5
|
+
component/composable/service, reachable from every adapter (React, Vue, Angular), not just
|
|
6
|
+
React.
|
|
7
|
+
|
|
8
|
+
Built the same way as [`@symbiote-native/battery`](../battery) and
|
|
9
|
+
[`@symbiote-native/device`](../device), an `expo-modules-core`-based wrapper (see the
|
|
10
|
+
`symbiote-expo-native-module` project skill for the full mechanism: why `expo-modules-core` is
|
|
11
|
+
depended on directly and never the `expo` meta-package, why the upstream JS is hand-ported into
|
|
12
|
+
`core/` rather than imported, and how autolinking picks up the native module).
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @symbiote-native/keep-awake
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Depends on `expo-keep-awake` and `expo-modules-core` directly (regular dependencies, pinned to
|
|
21
|
+
exact versions — never a caret range, since this package's `core/` is hand-ported against one
|
|
22
|
+
specific native API shape and a newer resolve could silently drift the two apart). Never install
|
|
23
|
+
`expo-keep-awake` yourself, and never add the `expo` package to this project — it bundles its own
|
|
24
|
+
Metro/Babel pipeline that conflicts with this project's own.
|
|
25
|
+
|
|
26
|
+
### Required one-time step: native autolinking wiring
|
|
27
|
+
|
|
28
|
+
Unlike a plain RN native module, `expo-keep-awake`'s native code is discovered by
|
|
29
|
+
`expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism — this needs wiring
|
|
30
|
+
into the native host app **once**, covering this package and every other `expo-modules-core`
|
|
31
|
+
package (`@symbiote-native/battery`, `@symbiote-native/device`, `@symbiote-native/sensors`, …)
|
|
32
|
+
with zero further changes:
|
|
33
|
+
|
|
34
|
+
| Platform | Touches |
|
|
35
|
+
|---|---|
|
|
36
|
+
| iOS | `ios/Podfile` — add `use_expo_modules!` |
|
|
37
|
+
| iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
|
|
38
|
+
| Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
|
|
39
|
+
| Android | `MainApplication.kt` — Expo's bootstrap hook, plus a hand-written native-module name map (there's no `expo` meta-package here to auto-generate one) |
|
|
40
|
+
|
|
41
|
+
The recurring per-package half of the Android wiring (`app/build.gradle`'s
|
|
42
|
+
`implementation project(':expo-keep-awake')` line and `MainApplication.kt`'s module-name map
|
|
43
|
+
entry) is automated by this package's own `postinstall` script via
|
|
44
|
+
`@symbiote-native/expo-modules-link` — see that package's README for how the `native-link.json`
|
|
45
|
+
manifest above drives it. Full mechanics — the Podfile pieces that normally ship inside the
|
|
46
|
+
`expo` package, the `expo` peer-dependency exclusion list — live in the
|
|
47
|
+
`symbiote-expo-native-module` skill.
|
|
48
|
+
|
|
49
|
+
No platform permission string is needed — keeping the screen awake has no runtime permission
|
|
50
|
+
prompt on either platform.
|
|
51
|
+
|
|
52
|
+
## Shape
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
src/core/ keep-awake.ts — isAvailableAsync/activateKeepAwakeAsync/
|
|
56
|
+
deactivateKeepAwake/addListener, ExpoKeepAwakeTag. native-module.ts
|
|
57
|
+
resolves the native module through expo-modules-core's
|
|
58
|
+
requireNativeModule. types.ts — KeepAwakeEvent/KeepAwakeListener/
|
|
59
|
+
KeepAwakeOptions, hand-ported from KeepAwake.types.ts.
|
|
60
|
+
src/react/hooks/ @symbiote-native/keep-awake/react — useKeepAwake
|
|
61
|
+
src/vue/composables/ @symbiote-native/keep-awake/vue — useKeepAwake
|
|
62
|
+
src/angular/services/ @symbiote-native/keep-awake/angular — KeepAwakeService (`.connect()`,
|
|
63
|
+
no return value — a pure side effect for the component's lifetime)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Each adapter's hook/composable/service activates a keep-awake lock on mount and deactivates it on
|
|
67
|
+
unmount, over the same `core` functions — the tag-generation and activate/deactivate lifecycle is
|
|
68
|
+
written once and shared by all three. React uses `useId()` for its default per-instance tag,
|
|
69
|
+
matching upstream; Vue and Angular have no `useId` equivalent, so both fall back to a small
|
|
70
|
+
monotonically-incrementing module-local counter (`keep-awake-tag-1`, `keep-awake-tag-2`, …) when
|
|
71
|
+
no explicit tag is given.
|
|
72
|
+
|
|
73
|
+
## Use it
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
// React — examples/expo-react/screens/KeepAwakeScreen.tsx
|
|
77
|
+
import { useKeepAwake } from '@symbiote-native/keep-awake/react';
|
|
78
|
+
|
|
79
|
+
function KeepAwakeScreen() {
|
|
80
|
+
useKeepAwake(); // screen stays on for as long as this component is mounted
|
|
81
|
+
|
|
82
|
+
return <Text>Screen will not sleep</Text>;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<!-- Vue — examples/expo-vue-sfc/screens/KeepAwakeScreen.vue -->
|
|
88
|
+
<script setup lang="ts">
|
|
89
|
+
import { useKeepAwake } from '@symbiote-native/keep-awake/vue';
|
|
90
|
+
|
|
91
|
+
useKeepAwake();
|
|
92
|
+
</script>
|
|
93
|
+
<template>
|
|
94
|
+
<Text>Screen will not sleep</Text>
|
|
95
|
+
</template>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
// Angular — examples/expo-angular/src/screens/KeepAwakeScreen.ts
|
|
100
|
+
import { Component, inject } from '@angular/core';
|
|
101
|
+
import { KeepAwakeService } from '@symbiote-native/keep-awake/angular';
|
|
102
|
+
|
|
103
|
+
@Component({ /* ... */ })
|
|
104
|
+
export class KeepAwakeScreen {
|
|
105
|
+
constructor() {
|
|
106
|
+
inject(KeepAwakeService).connect();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## API
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
isAvailableAsync(): Promise<boolean> // keep-awake API availability on this device
|
|
115
|
+
activateKeepAwakeAsync(tag?: string): Promise<void> // acquires a lock under `tag` (default tag when omitted)
|
|
116
|
+
deactivateKeepAwake(tag?: string): Promise<void> // releases the lock under `tag` (default tag when omitted)
|
|
117
|
+
addListener(tagOrListener, listener?): EventSubscription // subscribes to keep-awake state changes
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Plus `ExpoKeepAwakeTag` (the shared default tag string), `KeepAwakeEvent`, `KeepAwakeListener`,
|
|
121
|
+
`KeepAwakeOptions` — ported from upstream's `KeepAwake.types.ts`. `KeepAwakeEvent#state` is kept
|
|
122
|
+
as a minimal `unknown` placeholder: upstream's own shape there is web-specific and has no native
|
|
123
|
+
analogue, and native listeners for it rarely fire.
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { activateKeepAwakeAsync, deactivateKeepAwake } from '@symbiote-native/keep-awake';
|
|
127
|
+
|
|
128
|
+
// framework-scoped entry points re-export the same free functions, plus a lifecycle
|
|
129
|
+
// hook/composable/service:
|
|
130
|
+
import { useKeepAwake } from '@symbiote-native/keep-awake/react';
|
|
131
|
+
import { useKeepAwake } from '@symbiote-native/keep-awake/vue';
|
|
132
|
+
import { KeepAwakeService } from '@symbiote-native/keep-awake/angular';
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Each hook/composable/service activates a lock on mount (optionally registering `options.listener`
|
|
136
|
+
once activation resolves) and deactivates it on unmount — mirroring upstream's own
|
|
137
|
+
`useKeepAwake(tag?, options?)`.
|
|
138
|
+
|
|
139
|
+
## Test it
|
|
140
|
+
|
|
141
|
+
No Fabric/Descriptor angle at all — keep-awake is a pure async-function + `EventEmitter` listener
|
|
142
|
+
surface, never a view. Tests inject a fake native-module object in place of the real
|
|
143
|
+
`requireNativeModule` resolution (`src/core/keep-awake.test.ts`,
|
|
144
|
+
`src/{react,vue,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
|
|
145
|
+
`@symbiote-native/battery` and `@symbiote-native/device` use — no `installFabric()`-driven Fabric
|
|
146
|
+
assertions on the core level, only the adapter lifecycle tests mount through the fake Fabric slot
|
|
147
|
+
to prove activate-on-mount/deactivate-on-unmount. Native rendering itself is verified on-device —
|
|
148
|
+
see the parent [README](../../README.md).
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { KeepAwakeService } from './services/keep-awake.service';
|
|
2
|
+
export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, type KeepAwakeEvent, type KeepAwakeListener, type KeepAwakeOptions, type EventSubscription, } from '../core';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// KeepAwakeService is the Angular-only lifecycle half; the free functions and event
|
|
2
|
+
// subscription plumbing all live in core, shared with React/Vue.
|
|
3
|
+
export { KeepAwakeService } from './services/keep-awake.service';
|
|
4
|
+
export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from '../core';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
import { effect, inject, Injectable, Injector } from '@angular/core';
|
|
36
|
+
import { activateKeepAwakeAsync, addListener, deactivateKeepAwake, } from '../../../core';
|
|
37
|
+
// Angular twin of React's `useKeepAwake` hook and Vue's `useKeepAwake` composable. See
|
|
38
|
+
// LowPowerModeService (packages/battery) for the `connect()`/`effect()` pattern rationale — same
|
|
39
|
+
// wiring, but keep-awake has no value to surface as a Signal since it's a pure side effect for
|
|
40
|
+
// the component's lifetime. Angular has no useId equivalent either, so the default tag comes
|
|
41
|
+
// from the same monotonically-incrementing module-local counter the Vue composable uses.
|
|
42
|
+
//
|
|
43
|
+
// constructor() { inject(KeepAwakeService).connect(); }
|
|
44
|
+
let tagCounter = 0;
|
|
45
|
+
let KeepAwakeService = (() => {
|
|
46
|
+
let _classDecorators = [Injectable({ providedIn: 'root' })];
|
|
47
|
+
let _classDescriptor;
|
|
48
|
+
let _classExtraInitializers = [];
|
|
49
|
+
let _classThis;
|
|
50
|
+
var KeepAwakeService = class {
|
|
51
|
+
static { _classThis = this; }
|
|
52
|
+
static {
|
|
53
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
54
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
55
|
+
KeepAwakeService = _classThis = _classDescriptor.value;
|
|
56
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
57
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
58
|
+
}
|
|
59
|
+
injector = inject(Injector);
|
|
60
|
+
connect(tag, options) {
|
|
61
|
+
const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
|
|
62
|
+
effect(onCleanup => {
|
|
63
|
+
activateKeepAwakeAsync(tagOrDefault)
|
|
64
|
+
.then(() => {
|
|
65
|
+
if (options?.listener) {
|
|
66
|
+
addListener(tagOrDefault, options.listener);
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
.catch(() => { });
|
|
70
|
+
onCleanup(() => {
|
|
71
|
+
if (options?.suppressDeactivateWarnings) {
|
|
72
|
+
deactivateKeepAwake(tagOrDefault).catch(() => { });
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
deactivateKeepAwake(tagOrDefault);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}, { injector: this.injector });
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
return KeepAwakeService = _classThis;
|
|
82
|
+
})();
|
|
83
|
+
export { KeepAwakeService };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from './keep-awake';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type EventSubscription } from 'expo-modules-core';
|
|
2
|
+
import type { KeepAwakeListener } from './types';
|
|
3
|
+
export declare const ExpoKeepAwakeTag = "ExpoKeepAwakeDefaultTag";
|
|
4
|
+
/** Resolves with whether the keep-awake API is available on this device. */
|
|
5
|
+
export declare function isAvailableAsync(): Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
|
|
8
|
+
* screen stays on for as long as any tag holds an active lock.
|
|
9
|
+
*/
|
|
10
|
+
export declare function activateKeepAwakeAsync(tag?: string): Promise<void>;
|
|
11
|
+
/** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
|
|
12
|
+
export declare function deactivateKeepAwake(tag?: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Subscribes to keep-awake state changes for a tag. Overloaded to accept a bare listener for the
|
|
15
|
+
* default tag, matching upstream's own `addListener` signature.
|
|
16
|
+
*/
|
|
17
|
+
export declare function addListener(tagOrListener: string | KeepAwakeListener, listener?: KeepAwakeListener): EventSubscription;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Hand-ported from .vendors/expo/packages/expo-keep-awake/src/index.ts (sdk-57, confirmed
|
|
2
|
+
// against origin/sdk-57 — the .vendors/expo working tree sits on `main` and differs
|
|
3
|
+
// cosmetically). Unlike battery (which falls back to a sentinel when a method is missing),
|
|
4
|
+
// upstream keep-awake throws from `addListener` when the native module lacks
|
|
5
|
+
// `addListenerForTag`, matching local-auth/haptics's UnavailabilityError convention.
|
|
6
|
+
import { UnavailabilityError } from 'expo-modules-core';
|
|
7
|
+
import { expoKeepAwake } from './native-module';
|
|
8
|
+
export const ExpoKeepAwakeTag = 'ExpoKeepAwakeDefaultTag';
|
|
9
|
+
/** Resolves with whether the keep-awake API is available on this device. */
|
|
10
|
+
export async function isAvailableAsync() {
|
|
11
|
+
if (expoKeepAwake.isAvailableAsync) {
|
|
12
|
+
return await expoKeepAwake.isAvailableAsync();
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
|
|
18
|
+
* screen stays on for as long as any tag holds an active lock.
|
|
19
|
+
*/
|
|
20
|
+
export async function activateKeepAwakeAsync(tag = ExpoKeepAwakeTag) {
|
|
21
|
+
await expoKeepAwake.activate?.(tag);
|
|
22
|
+
}
|
|
23
|
+
/** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
|
|
24
|
+
export async function deactivateKeepAwake(tag = ExpoKeepAwakeTag) {
|
|
25
|
+
await expoKeepAwake.deactivate?.(tag);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Subscribes to keep-awake state changes for a tag. Overloaded to accept a bare listener for the
|
|
29
|
+
* default tag, matching upstream's own `addListener` signature.
|
|
30
|
+
*/
|
|
31
|
+
export function addListener(tagOrListener, listener) {
|
|
32
|
+
if (!expoKeepAwake.addListenerForTag) {
|
|
33
|
+
throw new UnavailabilityError('ExpoKeepAwake', 'addListenerForTag');
|
|
34
|
+
}
|
|
35
|
+
const tag = typeof tagOrListener === 'string' ? tagOrListener : ExpoKeepAwakeTag;
|
|
36
|
+
const resolvedListener = typeof tagOrListener === 'function' ? tagOrListener : listener;
|
|
37
|
+
if (!resolvedListener) {
|
|
38
|
+
throw new TypeError('addListener requires a listener function');
|
|
39
|
+
}
|
|
40
|
+
return expoKeepAwake.addListenerForTag(tag, resolvedListener);
|
|
41
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { EventSubscription } from 'expo-modules-core';
|
|
2
|
+
import type { KeepAwakeListener } from './types';
|
|
3
|
+
export type INativeKeepAwakeModule = {
|
|
4
|
+
isAvailableAsync?(): Promise<boolean>;
|
|
5
|
+
activate?(tag: string): Promise<void>;
|
|
6
|
+
deactivate?(tag: string): Promise<void>;
|
|
7
|
+
addListenerForTag?(tag: string, listener: KeepAwakeListener): EventSubscription;
|
|
8
|
+
};
|
|
9
|
+
export declare const expoKeepAwake: INativeKeepAwakeModule;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// React lifecycle wiring over the framework-agnostic core (core/keep-awake.ts) — activates on
|
|
2
|
+
// mount, deactivates on unmount, mirroring upstream's own useKeepAwake. Uses React's useId for
|
|
3
|
+
// the default per-instance tag exactly like upstream, so two components calling useKeepAwake()
|
|
4
|
+
// concurrently without an explicit tag don't clobber each other's activation/deactivation.
|
|
5
|
+
//
|
|
6
|
+
// Upstream also checks the native module's own `addListenerForTag` presence directly before
|
|
7
|
+
// calling `addListener`; that private module isn't reachable from here (only core's public API
|
|
8
|
+
// is), so registering the listener just goes through the same promise chain — an
|
|
9
|
+
// UnavailabilityError from `addListener` is swallowed by the trailing `.catch(() => {})` exactly
|
|
10
|
+
// like a rejected `activateKeepAwakeAsync`, same net effect as upstream's own guard.
|
|
11
|
+
import { useEffect, useId } from 'react';
|
|
12
|
+
import { activateKeepAwakeAsync, addListener, deactivateKeepAwake, } from '../../../core';
|
|
13
|
+
export function useKeepAwake(tag, options) {
|
|
14
|
+
const defaultTag = useId();
|
|
15
|
+
const tagOrDefault = tag ?? defaultTag;
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
let isMounted = true;
|
|
18
|
+
activateKeepAwakeAsync(tagOrDefault)
|
|
19
|
+
.then(() => {
|
|
20
|
+
if (isMounted && options?.listener) {
|
|
21
|
+
addListener(tagOrDefault, options.listener);
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
.catch(() => { });
|
|
25
|
+
return () => {
|
|
26
|
+
isMounted = false;
|
|
27
|
+
if (options?.suppressDeactivateWarnings) {
|
|
28
|
+
deactivateKeepAwake(tagOrDefault).catch(() => { });
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
deactivateKeepAwake(tagOrDefault);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}, [tagOrDefault]);
|
|
35
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @symbiote-native/keep-awake/react: the React entry over the framework-agnostic core. The
|
|
2
|
+
// lifecycle bucket is `hooks/` (never `composables/`, that's Vue's term) — see
|
|
3
|
+
// adapters/react/src/hooks for the same convention.
|
|
4
|
+
export { useKeepAwake } from './hooks/use-keep-awake';
|
|
5
|
+
export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from '../core';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic core (core/keep-awake.ts) — activates on
|
|
2
|
+
// mount, deactivates on unmount, mirroring React's useKeepAwake hook. Vue has no useId
|
|
3
|
+
// equivalent, so the default tag comes from a small monotonically-incrementing module-local
|
|
4
|
+
// counter instead — simplest robust way to give each composable instance its own tag when the
|
|
5
|
+
// caller doesn't supply one.
|
|
6
|
+
import { onMounted, onUnmounted } from '@vue/runtime-core';
|
|
7
|
+
import { activateKeepAwakeAsync, addListener, deactivateKeepAwake, } from '../../../core';
|
|
8
|
+
let tagCounter = 0;
|
|
9
|
+
export function useKeepAwake(tag, options) {
|
|
10
|
+
const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
|
|
11
|
+
onMounted(() => {
|
|
12
|
+
activateKeepAwakeAsync(tagOrDefault)
|
|
13
|
+
.then(() => {
|
|
14
|
+
if (options?.listener) {
|
|
15
|
+
addListener(tagOrDefault, options.listener);
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
.catch(() => { });
|
|
19
|
+
});
|
|
20
|
+
onUnmounted(() => {
|
|
21
|
+
if (options?.suppressDeactivateWarnings) {
|
|
22
|
+
deactivateKeepAwake(tagOrDefault).catch(() => { });
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
deactivateKeepAwake(tagOrDefault);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @symbiote-native/keep-awake/vue: the Vue entry over the framework-agnostic core. The
|
|
2
|
+
// lifecycle bucket is `composables/` (never `hooks/`, that's React's term) — see
|
|
3
|
+
// adapters/vue/src/composables for the same convention.
|
|
4
|
+
export { useKeepAwake } from './composables/use-keep-awake';
|
|
5
|
+
export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from '../core';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { KeepAwakeService } from './services/keep-awake.service';
|
|
2
|
+
export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, type KeepAwakeEvent, type KeepAwakeListener, type KeepAwakeOptions, type EventSubscription, } from '../core';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// KeepAwakeService is the Angular-only lifecycle half; the free functions and event
|
|
2
|
+
// subscription plumbing all live in core, shared with React/Vue.
|
|
3
|
+
export { KeepAwakeService } from './services/keep-awake.service';
|
|
4
|
+
export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from '../core';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,iEAAiE;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,WAAW,GAKZ,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type KeepAwakeOptions } from '../../../core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class KeepAwakeService {
|
|
4
|
+
private readonly injector;
|
|
5
|
+
connect(tag?: string, options?: KeepAwakeOptions): void;
|
|
6
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<KeepAwakeService, never>;
|
|
7
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<KeepAwakeService>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { effect, inject, Injectable, Injector } from '@angular/core';
|
|
2
|
+
import { activateKeepAwakeAsync, addListener, deactivateKeepAwake, } from '../../../core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
// Angular twin of React's `useKeepAwake` hook and Vue's `useKeepAwake` composable. See
|
|
5
|
+
// LowPowerModeService (packages/battery) for the `connect()`/`effect()` pattern rationale — same
|
|
6
|
+
// wiring, but keep-awake has no value to surface as a Signal since it's a pure side effect for
|
|
7
|
+
// the component's lifetime. Angular has no useId equivalent either, so the default tag comes
|
|
8
|
+
// from the same monotonically-incrementing module-local counter the Vue composable uses.
|
|
9
|
+
//
|
|
10
|
+
// constructor() { inject(KeepAwakeService).connect(); }
|
|
11
|
+
let tagCounter = 0;
|
|
12
|
+
export class KeepAwakeService {
|
|
13
|
+
injector = inject(Injector);
|
|
14
|
+
connect(tag, options) {
|
|
15
|
+
const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
|
|
16
|
+
effect(onCleanup => {
|
|
17
|
+
activateKeepAwakeAsync(tagOrDefault)
|
|
18
|
+
.then(() => {
|
|
19
|
+
if (options?.listener) {
|
|
20
|
+
addListener(tagOrDefault, options.listener);
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
.catch(() => { });
|
|
24
|
+
onCleanup(() => {
|
|
25
|
+
if (options?.suppressDeactivateWarnings) {
|
|
26
|
+
deactivateKeepAwake(tagOrDefault).catch(() => { });
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
deactivateKeepAwake(tagOrDefault);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}, { injector: this.injector });
|
|
33
|
+
}
|
|
34
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: KeepAwakeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
35
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: KeepAwakeService, providedIn: 'root' });
|
|
36
|
+
}
|
|
37
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: KeepAwakeService, decorators: [{
|
|
38
|
+
type: Injectable,
|
|
39
|
+
args: [{ providedIn: 'root' }]
|
|
40
|
+
}] });
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/keep-awake.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EACL,sBAAsB,EACtB,WAAW,EACX,mBAAmB,GAEpB,MAAM,eAAe,CAAC;;AAEvB,uFAAuF;AACvF,iGAAiG;AACjG,+FAA+F;AAC/F,6FAA6F;AAC7F,yFAAyF;AACzF,EAAE;AACF,0DAA0D;AAC1D,IAAI,UAAU,GAAG,CAAC,CAAC;AAGnB,MAAM,OAAO,gBAAgB;IACV,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO,CAAC,GAAY,EAAE,OAA0B;QAC9C,MAAM,YAAY,GAAG,GAAG,IAAI,kBAAkB,EAAE,UAAU,EAAE,CAAC;QAE7D,MAAM,CACJ,SAAS,CAAC,EAAE;YACV,sBAAsB,CAAC,YAAY,CAAC;iBACjC,IAAI,CAAC,GAAG,EAAE;gBACT,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;oBACtB,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAEnB,SAAS,CAAC,GAAG,EAAE;gBACb,IAAI,OAAO,EAAE,0BAA0B,EAAE,CAAC;oBACxC,mBAAmB,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACpD,CAAC;qBAAM,CAAC;oBACN,mBAAmB,CAAC,YAAY,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B,CAAC;IACJ,CAAC;uGA1BU,gBAAgB;2GAAhB,gBAAgB,cADH,MAAM;;2FACnB,gBAAgB;kBAD5B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,WAAW,GACZ,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type EventSubscription } from 'expo-modules-core';
|
|
2
|
+
import type { KeepAwakeListener } from './types';
|
|
3
|
+
export declare const ExpoKeepAwakeTag = "ExpoKeepAwakeDefaultTag";
|
|
4
|
+
/** Resolves with whether the keep-awake API is available on this device. */
|
|
5
|
+
export declare function isAvailableAsync(): Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
|
|
8
|
+
* screen stays on for as long as any tag holds an active lock.
|
|
9
|
+
*/
|
|
10
|
+
export declare function activateKeepAwakeAsync(tag?: string): Promise<void>;
|
|
11
|
+
/** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
|
|
12
|
+
export declare function deactivateKeepAwake(tag?: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Subscribes to keep-awake state changes for a tag. Overloaded to accept a bare listener for the
|
|
15
|
+
* default tag, matching upstream's own `addListener` signature.
|
|
16
|
+
*/
|
|
17
|
+
export declare function addListener(tagOrListener: string | KeepAwakeListener, listener?: KeepAwakeListener): EventSubscription;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Hand-ported from .vendors/expo/packages/expo-keep-awake/src/index.ts (sdk-57, confirmed
|
|
2
|
+
// against origin/sdk-57 — the .vendors/expo working tree sits on `main` and differs
|
|
3
|
+
// cosmetically). Unlike battery (which falls back to a sentinel when a method is missing),
|
|
4
|
+
// upstream keep-awake throws from `addListener` when the native module lacks
|
|
5
|
+
// `addListenerForTag`, matching local-auth/haptics's UnavailabilityError convention.
|
|
6
|
+
import { UnavailabilityError } from 'expo-modules-core';
|
|
7
|
+
import { expoKeepAwake } from './native-module';
|
|
8
|
+
export const ExpoKeepAwakeTag = 'ExpoKeepAwakeDefaultTag';
|
|
9
|
+
/** Resolves with whether the keep-awake API is available on this device. */
|
|
10
|
+
export async function isAvailableAsync() {
|
|
11
|
+
if (expoKeepAwake.isAvailableAsync) {
|
|
12
|
+
return await expoKeepAwake.isAvailableAsync();
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
|
|
18
|
+
* screen stays on for as long as any tag holds an active lock.
|
|
19
|
+
*/
|
|
20
|
+
export async function activateKeepAwakeAsync(tag = ExpoKeepAwakeTag) {
|
|
21
|
+
await expoKeepAwake.activate?.(tag);
|
|
22
|
+
}
|
|
23
|
+
/** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
|
|
24
|
+
export async function deactivateKeepAwake(tag = ExpoKeepAwakeTag) {
|
|
25
|
+
await expoKeepAwake.deactivate?.(tag);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Subscribes to keep-awake state changes for a tag. Overloaded to accept a bare listener for the
|
|
29
|
+
* default tag, matching upstream's own `addListener` signature.
|
|
30
|
+
*/
|
|
31
|
+
export function addListener(tagOrListener, listener) {
|
|
32
|
+
if (!expoKeepAwake.addListenerForTag) {
|
|
33
|
+
throw new UnavailabilityError('ExpoKeepAwake', 'addListenerForTag');
|
|
34
|
+
}
|
|
35
|
+
const tag = typeof tagOrListener === 'string' ? tagOrListener : ExpoKeepAwakeTag;
|
|
36
|
+
const resolvedListener = typeof tagOrListener === 'function' ? tagOrListener : listener;
|
|
37
|
+
if (!resolvedListener) {
|
|
38
|
+
throw new TypeError('addListener requires a listener function');
|
|
39
|
+
}
|
|
40
|
+
return expoKeepAwake.addListenerForTag(tag, resolvedListener);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=keep-awake.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keep-awake.js","sourceRoot":"","sources":["../../src/core/keep-awake.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,oFAAoF;AACpF,2FAA2F;AAC3F,6EAA6E;AAC7E,qFAAqF;AACrF,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAE1D,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,aAAa,CAAC,gBAAgB,EAAE,CAAC;QACnC,OAAO,MAAM,aAAa,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,MAAc,gBAAgB;IACzE,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAc,gBAAgB;IACtE,MAAM,aAAa,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,aAAyC,EACzC,QAA4B;IAE5B,IAAI,CAAC,aAAa,CAAC,iBAAiB,EAAE,CAAC;QACrC,MAAM,IAAI,mBAAmB,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACjF,MAAM,gBAAgB,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxF,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,aAAa,CAAC,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { EventSubscription } from 'expo-modules-core';
|
|
2
|
+
import type { KeepAwakeListener } from './types';
|
|
3
|
+
export type INativeKeepAwakeModule = {
|
|
4
|
+
isAvailableAsync?(): Promise<boolean>;
|
|
5
|
+
activate?(tag: string): Promise<void>;
|
|
6
|
+
deactivate?(tag: string): Promise<void>;
|
|
7
|
+
addListenerForTag?(tag: string, listener: KeepAwakeListener): EventSubscription;
|
|
8
|
+
};
|
|
9
|
+
export declare const expoKeepAwake: INativeKeepAwakeModule;
|