@symbiote-native/battery 3.0.2 → 3.0.3
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/README.md +53 -38
- package/build/angular/index.d.ts +1 -0
- package/build/angular/index.js +1 -0
- package/build/angular/services/power-state.service/index.d.ts +6 -0
- package/build/angular/services/power-state.service/index.js +60 -0
- package/build/core/index.d.ts +1 -0
- package/build/core/index.js +1 -0
- package/build/core/power-state.d.ts +3 -0
- package/build/core/power-state.js +37 -0
- package/build/react/hooks/use-power-state/index.d.ts +2 -0
- package/build/react/hooks/use-power-state/index.js +8 -0
- package/build/react/index.d.ts +1 -0
- package/build/react/index.js +1 -0
- package/build/solid/index.d.ts +1 -0
- package/build/solid/index.js +1 -0
- package/build/solid/primitives/create-power-state.d.ts +3 -0
- package/build/solid/primitives/create-power-state.js +8 -0
- package/build/svelte/index.d.ts +1 -0
- package/build/svelte/index.js +1 -0
- package/build/svelte/runes/use-power-state.svelte.d.ts +4 -0
- package/build/svelte/runes/use-power-state.svelte.js +13 -0
- package/build/vue/composables/use-power-state/index.d.ts +3 -0
- package/build/vue/composables/use-power-state/index.js +16 -0
- package/build/vue/index.d.ts +1 -0
- package/build/vue/index.js +1 -0
- package/build-ngc/angular/index.d.ts +1 -0
- package/build-ngc/angular/index.js +1 -0
- package/build-ngc/angular/index.js.map +1 -1
- package/build-ngc/angular/services/power-state.service/index.d.ts +9 -0
- package/build-ngc/angular/services/power-state.service/index.js +18 -0
- package/build-ngc/angular/services/power-state.service/index.js.map +1 -0
- package/build-ngc/core/index.d.ts +1 -0
- package/build-ngc/core/index.js +1 -0
- package/build-ngc/core/index.js.map +1 -1
- package/build-ngc/core/power-state.d.ts +3 -0
- package/build-ngc/core/power-state.js +38 -0
- package/build-ngc/core/power-state.js.map +1 -0
- package/package.json +15 -15
- package/src/angular/index.ts +1 -0
- package/src/angular/services/power-state.service/index.ts +21 -0
- package/src/core/index.ts +1 -0
- package/src/core/power-state.ts +63 -0
- package/src/react/hooks/use-power-state/index.ts +15 -0
- package/src/react/index.ts +1 -0
- package/src/solid/index.ts +1 -0
- package/src/solid/primitives/create-power-state.ts +15 -0
- package/src/svelte/index.ts +1 -0
- package/src/svelte/runes/use-power-state.svelte.ts +22 -0
- package/src/vue/composables/use-power-state/index.ts +29 -0
- package/src/vue/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @symbiote-native/battery
|
|
2
2
|
|
|
3
3
|
Port of [`expo-battery`](https://docs.expo.dev/versions/latest/sdk/battery/) for
|
|
4
|
-
[SymbioteNative](../../README.md)
|
|
4
|
+
[SymbioteNative](../../README.md) - battery level and state, low-power-mode detection, reachable
|
|
5
5
|
from every adapter (React, Vue, Svelte, Solid, Angular), not just React.
|
|
6
6
|
|
|
7
7
|
Built the same way as [`@symbiote-native/local-auth`](../local-auth) and
|
|
@@ -24,74 +24,74 @@ npx @symbiote-native/cli new my-app --battery
|
|
|
24
24
|
npx @symbiote-native/cli add --battery
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Either way: installs `@symbiote-native/battery` and wires the native autolinking automatically
|
|
27
|
+
Either way: installs `@symbiote-native/battery` and wires the native autolinking automatically - see
|
|
28
28
|
[`@symbiote-native/cli`](../cli).
|
|
29
29
|
|
|
30
30
|
<details>
|
|
31
|
-
<summary>Manual install (no CLI
|
|
31
|
+
<summary>Manual install (no CLI - installing and wiring native autolinking by hand)</summary>
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
npm install @symbiote-native/battery
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
Depends on `expo-battery` and `expo-modules-core` directly (regular dependencies, pinned to exact
|
|
38
|
-
versions
|
|
38
|
+
versions - never a caret range, since this package's `core/` is hand-ported against one specific
|
|
39
39
|
native API shape and a newer resolve could silently drift the two apart). Never install
|
|
40
|
-
`expo-battery` yourself, and never add the `expo` package to this project
|
|
40
|
+
`expo-battery` yourself, and never add the `expo` package to this project - it bundles its own
|
|
41
41
|
Metro/Babel pipeline that conflicts with this project's own.
|
|
42
42
|
|
|
43
43
|
### Required one-time step: native autolinking wiring
|
|
44
44
|
|
|
45
45
|
Unlike a plain RN native module, `expo-battery`'s native code is discovered by
|
|
46
|
-
`expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism
|
|
46
|
+
`expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism - this needs wiring
|
|
47
47
|
into the native host app **once**, covering this package and every other `expo-modules-core`
|
|
48
48
|
package (`@symbiote-native/sensors`, `@symbiote-native/local-auth`) with zero further changes:
|
|
49
49
|
|
|
50
50
|
| Platform | Touches |
|
|
51
51
|
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
-
| iOS | `ios/Podfile`
|
|
53
|
-
| iOS | `AppDelegate.swift`
|
|
54
|
-
| Android | `settings.gradle` / `app/build.gradle`
|
|
55
|
-
| Android | `MainApplication.kt`
|
|
52
|
+
| iOS | `ios/Podfile` - add `use_expo_modules!` |
|
|
53
|
+
| iOS | `AppDelegate.swift` - Expo's runtime-bootstrap hook |
|
|
54
|
+
| Android | `settings.gradle` / `app/build.gradle` - resolve and include the Expo Gradle projects |
|
|
55
|
+
| 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) |
|
|
56
56
|
|
|
57
|
-
Full mechanics
|
|
58
|
-
peer-dependency exclusion list
|
|
57
|
+
Full mechanics - the Podfile pieces that normally ship inside the `expo` package, the `expo`
|
|
58
|
+
peer-dependency exclusion list - live in the `symbiote-expo-native-module` skill. Reference
|
|
59
59
|
implementation: `examples/expo-react/ios/Podfile` and
|
|
60
60
|
`examples/expo-react/android/app/src/main/java/com/canaryexpo/MainApplication.kt`.
|
|
61
61
|
|
|
62
62
|
</details>
|
|
63
63
|
|
|
64
|
-
No platform permission string is needed for battery's basic surface
|
|
64
|
+
No platform permission string is needed for battery's basic surface:
|
|
65
65
|
`isBatteryOptimizationEnabledAsync` reads an Android-only system state with no runtime permission
|
|
66
66
|
prompt either.
|
|
67
67
|
|
|
68
68
|
## Shape
|
|
69
69
|
|
|
70
70
|
```
|
|
71
|
-
src/core/ Battery.ts
|
|
71
|
+
src/core/ Battery.ts - one-shot get*Async functions + addListener subscriptions.
|
|
72
72
|
native-module.ts resolves the native module through expo-modules-core's
|
|
73
|
-
requireNativeModule. types.ts
|
|
73
|
+
requireNativeModule. types.ts - BatteryState enum, PowerState,
|
|
74
74
|
*Event shapes, hand-ported from Battery.types.ts.
|
|
75
|
-
src/react/hooks/ @symbiote-native/battery/react
|
|
76
|
-
useLowPowerMode
|
|
77
|
-
src/vue/composables/ @symbiote-native/battery/vue
|
|
78
|
-
src/svelte/runes/ @symbiote-native/battery/svelte
|
|
79
|
-
src/solid/primitives/ @symbiote-native/battery/solid
|
|
80
|
-
createLowPowerMode (each returns an Accessor)
|
|
81
|
-
src/angular/services/ @symbiote-native/battery/angular
|
|
82
|
-
LowPowerModeService (`.connect()` returns a Signal)
|
|
75
|
+
src/react/hooks/ @symbiote-native/battery/react - useBatteryLevel, useBatteryState,
|
|
76
|
+
useLowPowerMode, usePowerState
|
|
77
|
+
src/vue/composables/ @symbiote-native/battery/vue - same four names, Vue lifecycle
|
|
78
|
+
src/svelte/runes/ @symbiote-native/battery/svelte - same four names, read as `.current`
|
|
79
|
+
src/solid/primitives/ @symbiote-native/battery/solid - createBatteryLevel, createBatteryState,
|
|
80
|
+
createLowPowerMode, createPowerState (each returns an Accessor)
|
|
81
|
+
src/angular/services/ @symbiote-native/battery/angular - BatteryLevelService, BatteryStateService,
|
|
82
|
+
LowPowerModeService, PowerStateService (`.connect()` returns a Signal)
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
Each adapter's hook/composable/rune/primitive/service is a thin lifecycle wrapper (seed from the
|
|
86
86
|
one-shot `get*Async` call, subscribe to the matching listener, unsubscribe on unmount/cleanup)
|
|
87
|
-
over the same `core` functions
|
|
87
|
+
over the same `core` functions - the subscription and fallback logic is written once and shared
|
|
88
88
|
by every adapter. Solid's naming differs on purpose: `create*`, not `use*`, which Solid reserves
|
|
89
89
|
for consuming something that already exists.
|
|
90
90
|
|
|
91
91
|
## Use it
|
|
92
92
|
|
|
93
93
|
```tsx
|
|
94
|
-
// React
|
|
94
|
+
// React - examples/expo-react/screens/BatteryScreen.tsx
|
|
95
95
|
import {
|
|
96
96
|
useBatteryLevel,
|
|
97
97
|
useBatteryState,
|
|
@@ -120,7 +120,7 @@ function BatteryScreen() {
|
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
```vue
|
|
123
|
-
<!-- Vue
|
|
123
|
+
<!-- Vue - examples/expo-vue-sfc/screens/BatteryScreen.vue -->
|
|
124
124
|
<script setup lang="ts">
|
|
125
125
|
import { computed } from 'vue';
|
|
126
126
|
import {
|
|
@@ -146,7 +146,7 @@ const batteryLevelText = computed(() =>
|
|
|
146
146
|
```
|
|
147
147
|
|
|
148
148
|
```svelte
|
|
149
|
-
<!-- Svelte
|
|
149
|
+
<!-- Svelte - examples/expo-svelte/screens/BatteryScreen.svelte. Each rune returns a boxed
|
|
150
150
|
getter object, read as `.current`, since a bare `$state` doesn't survive being handed out
|
|
151
151
|
of a plain function. -->
|
|
152
152
|
<script lang="ts">
|
|
@@ -176,7 +176,7 @@ const batteryLevelText = computed(() =>
|
|
|
176
176
|
```
|
|
177
177
|
|
|
178
178
|
```tsx
|
|
179
|
-
// Solid
|
|
179
|
+
// Solid - an accessor per value; call it to read, so a component body that runs once still
|
|
180
180
|
// re-renders the leaf that reads it.
|
|
181
181
|
import {
|
|
182
182
|
createBatteryLevel,
|
|
@@ -207,7 +207,7 @@ function BatteryScreen() {
|
|
|
207
207
|
```
|
|
208
208
|
|
|
209
209
|
```ts
|
|
210
|
-
// Angular
|
|
210
|
+
// Angular - examples/expo-angular/src/screens/BatteryScreen.ts
|
|
211
211
|
import { Component, inject } from '@angular/core';
|
|
212
212
|
import {
|
|
213
213
|
BatteryLevelService,
|
|
@@ -230,7 +230,7 @@ export class BatteryScreen {
|
|
|
230
230
|
|
|
231
231
|
Each of the demo screens above also renders a one-shot capabilities card
|
|
232
232
|
(`isAvailableAsync()`, and Android-only `isBatteryOptimizationEnabledAsync()`) resolved directly
|
|
233
|
-
from `@symbiote-native/battery`'s core entry point
|
|
233
|
+
from `@symbiote-native/battery`'s core entry point - see the linked files for the full version.
|
|
234
234
|
The iOS Simulator reports the battery API as unavailable (`isAvailableAsync()` resolves `false`)
|
|
235
235
|
since simulators have no real battery hardware; a physical device is needed to see live readings.
|
|
236
236
|
|
|
@@ -238,9 +238,9 @@ since simulators have no real battery hardware; a physical device is needed to s
|
|
|
238
238
|
|
|
239
239
|
A mix of stateless async functions and three listener-based subscriptions
|
|
240
240
|
(`addBatteryLevelListener`/`addBatteryStateListener`/`addLowPowerModeListener`), each with its
|
|
241
|
-
own adapter-level lifecycle hook
|
|
242
|
-
|
|
243
|
-
|
|
241
|
+
own adapter-level lifecycle hook, matching upstream's `useBatteryLevel`/`useBatteryState`/
|
|
242
|
+
`useLowPowerMode`. `usePowerState` merges all three into one `PowerState` value; the seed and
|
|
243
|
+
merge logic is `watchPowerState` in core, so every adapter only holds the state.
|
|
244
244
|
|
|
245
245
|
```ts
|
|
246
246
|
isAvailableAsync(): Promise<boolean> // battery API availability on this device
|
|
@@ -255,7 +255,7 @@ addLowPowerModeListener(listener): EventSubscription // fires when low
|
|
|
255
255
|
```
|
|
256
256
|
|
|
257
257
|
Plus `BatteryState` (enum), `PowerState`, `BatteryLevelEvent`, `BatteryStateEvent`,
|
|
258
|
-
`PowerModeEvent`
|
|
258
|
+
`PowerModeEvent` - ported from upstream's `Battery.types.ts`.
|
|
259
259
|
|
|
260
260
|
```ts
|
|
261
261
|
import {
|
|
@@ -269,42 +269,57 @@ import {
|
|
|
269
269
|
useBatteryLevel,
|
|
270
270
|
useBatteryState,
|
|
271
271
|
useLowPowerMode,
|
|
272
|
+
usePowerState,
|
|
272
273
|
} from '@symbiote-native/battery/react';
|
|
273
274
|
import {
|
|
274
275
|
useBatteryLevel,
|
|
275
276
|
useBatteryState,
|
|
276
277
|
useLowPowerMode,
|
|
278
|
+
usePowerState,
|
|
277
279
|
} from '@symbiote-native/battery/vue';
|
|
278
280
|
import {
|
|
279
281
|
useBatteryLevel,
|
|
280
282
|
useBatteryState,
|
|
281
283
|
useLowPowerMode,
|
|
284
|
+
usePowerState,
|
|
282
285
|
} from '@symbiote-native/battery/svelte';
|
|
283
286
|
import {
|
|
284
287
|
createBatteryLevel,
|
|
285
288
|
createBatteryState,
|
|
286
289
|
createLowPowerMode,
|
|
290
|
+
createPowerState,
|
|
287
291
|
} from '@symbiote-native/battery/solid';
|
|
288
292
|
import {
|
|
289
293
|
BatteryLevelService,
|
|
290
294
|
BatteryStateService,
|
|
291
295
|
LowPowerModeService,
|
|
296
|
+
PowerStateService,
|
|
292
297
|
} from '@symbiote-native/battery/angular';
|
|
293
298
|
```
|
|
294
299
|
|
|
295
300
|
Each hook/composable/service seeds its initial value from the matching one-shot
|
|
296
301
|
`get*Async`/`is*Async` call, then subscribes to the matching listener for updates, and
|
|
297
|
-
unsubscribes on unmount
|
|
302
|
+
unsubscribes on unmount - mirroring upstream's own `useBatteryLevel`/`useBatteryState`/
|
|
298
303
|
`useLowPowerMode`.
|
|
299
304
|
|
|
305
|
+
## Common questions
|
|
306
|
+
|
|
307
|
+
- **Level reads `-1`.** Unknown level (simulator, unsupported device): check for `-1` before
|
|
308
|
+
formatting and do not treat it as low battery.
|
|
309
|
+
- **Live updates?** Read the initial level, then subscribe to the listener and clean up on unmount.
|
|
310
|
+
- **Low Power Mode?** Use the low power mode query and listener to reduce background work.
|
|
311
|
+
|
|
312
|
+
Sources: [Expo docs: Battery](https://docs.expo.dev/versions/latest/sdk/battery/),
|
|
313
|
+
[Battery -100% bug report](https://github.com/karlgroves/bugrout/issues/202).
|
|
314
|
+
|
|
300
315
|
## Test it
|
|
301
316
|
|
|
302
|
-
No Fabric/Descriptor angle at all
|
|
317
|
+
No Fabric/Descriptor angle at all - battery is a pure async-function + `EventEmitter` listener
|
|
303
318
|
surface, never a view. Tests inject a fake native-module object in place of the real
|
|
304
319
|
`requireNativeModule` resolution (`src/core/battery.test.ts`,
|
|
305
320
|
`src/{react,vue,svelte,solid,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
|
|
306
|
-
`@symbiote-native/sensors` and `@symbiote-native/local-auth` use
|
|
307
|
-
ViewConfig. Native rendering itself is verified on-device
|
|
321
|
+
`@symbiote-native/sensors` and `@symbiote-native/local-auth` use - no `installFabric()`, no
|
|
322
|
+
ViewConfig. Native rendering itself is verified on-device - see the parent
|
|
308
323
|
[README](../../README.md).
|
|
309
324
|
|
|
310
325
|
The Android/iOS native wiring is done across all six `examples/expo-*` canary apps
|
package/build/angular/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { BatteryLevelService } from './services/battery-level.service';
|
|
2
2
|
export { BatteryStateService } from './services/battery-state.service';
|
|
3
3
|
export { LowPowerModeService } from './services/low-power-mode.service';
|
|
4
|
+
export { PowerStateService } from './services/power-state.service';
|
|
4
5
|
export * from '../core';
|
package/build/angular/index.js
CHANGED
|
@@ -5,4 +5,5 @@
|
|
|
5
5
|
export { BatteryLevelService } from './services/battery-level.service/index.js';
|
|
6
6
|
export { BatteryStateService } from './services/battery-state.service/index.js';
|
|
7
7
|
export { LowPowerModeService } from './services/low-power-mode.service/index.js';
|
|
8
|
+
export { PowerStateService } from './services/power-state.service/index.js';
|
|
8
9
|
export * from '../core/index.js';
|
|
@@ -0,0 +1,60 @@
|
|
|
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 { inject, Injectable, Injector } from '@angular/core';
|
|
36
|
+
import { connectWatchedSignal } from '@symbiote-native/angular';
|
|
37
|
+
import { initialPowerState, watchPowerState, } from '../../../core/index.js';
|
|
38
|
+
// Angular twin of `usePowerState`, same `connect()` pattern as `BatteryLevelService`
|
|
39
|
+
let PowerStateService = (() => {
|
|
40
|
+
let _classDecorators = [Injectable({ providedIn: 'root' })];
|
|
41
|
+
let _classDescriptor;
|
|
42
|
+
let _classExtraInitializers = [];
|
|
43
|
+
let _classThis;
|
|
44
|
+
var PowerStateService = class {
|
|
45
|
+
static { _classThis = this; }
|
|
46
|
+
static {
|
|
47
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
48
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
49
|
+
PowerStateService = _classThis = _classDescriptor.value;
|
|
50
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
51
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
52
|
+
}
|
|
53
|
+
injector = inject(Injector);
|
|
54
|
+
connect() {
|
|
55
|
+
return connectWatchedSignal(this.injector, initialPowerState, watchPowerState);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
return PowerStateService = _classThis;
|
|
59
|
+
})();
|
|
60
|
+
export { PowerStateService };
|
package/build/core/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { isAvailableAsync, getBatteryLevelAsync, getBatteryStateAsync, isLowPowerModeEnabledAsync, isBatteryOptimizationEnabledAsync, getPowerStateAsync, addBatteryLevelListener, addBatteryStateListener, addLowPowerModeListener, } from './battery';
|
|
2
2
|
export { BatteryState, type PowerState, type BatteryLevelEvent, type BatteryStateEvent, type PowerModeEvent, } from './types';
|
|
3
|
+
export { initialPowerState, watchPowerState } from './power-state';
|
|
3
4
|
export type { EventSubscription } from 'expo-modules-core';
|
package/build/core/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { isAvailableAsync, getBatteryLevelAsync, getBatteryStateAsync, isLowPowerModeEnabledAsync, isBatteryOptimizationEnabledAsync, getPowerStateAsync, addBatteryLevelListener, addBatteryStateListener, addLowPowerModeListener, } from './battery.js';
|
|
2
2
|
export { BatteryState, } from './types.js';
|
|
3
|
+
export { initialPowerState, watchPowerState } from './power-state.js';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Shared half of upstream's `usePowerState`: level, state and low-power mode as one merged value
|
|
2
|
+
import { addBatteryLevelListener, addBatteryStateListener, addLowPowerModeListener, getBatteryLevelAsync, getBatteryStateAsync, isLowPowerModeEnabledAsync, } from './battery.js';
|
|
3
|
+
import { BatteryState } from './types.js';
|
|
4
|
+
export const initialPowerState = {
|
|
5
|
+
lowPowerMode: false,
|
|
6
|
+
batteryLevel: -1,
|
|
7
|
+
batteryState: BatteryState.UNKNOWN,
|
|
8
|
+
};
|
|
9
|
+
// Seeds each field with a one-shot fetch, then follows native events; returns the teardown
|
|
10
|
+
export function watchPowerState(onChange) {
|
|
11
|
+
let state = initialPowerState;
|
|
12
|
+
let isStopped = false;
|
|
13
|
+
const heardFields = new Set();
|
|
14
|
+
// A native event that lands before its seed resolves wins because the seed is the older value
|
|
15
|
+
function write(key, value, isSeed) {
|
|
16
|
+
if (isStopped || (isSeed && heardFields.has(key))) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!isSeed) {
|
|
20
|
+
heardFields.add(key);
|
|
21
|
+
}
|
|
22
|
+
state = { ...state, [key]: value };
|
|
23
|
+
onChange(state);
|
|
24
|
+
}
|
|
25
|
+
const subscriptions = [
|
|
26
|
+
addLowPowerModeListener(event => write('lowPowerMode', event.lowPowerMode, false)),
|
|
27
|
+
addBatteryLevelListener(event => write('batteryLevel', event.batteryLevel, false)),
|
|
28
|
+
addBatteryStateListener(event => write('batteryState', event.batteryState, false)),
|
|
29
|
+
];
|
|
30
|
+
isLowPowerModeEnabledAsync().then(value => write('lowPowerMode', value, true));
|
|
31
|
+
getBatteryLevelAsync().then(value => write('batteryLevel', value, true));
|
|
32
|
+
getBatteryStateAsync().then(value => write('batteryState', value, true));
|
|
33
|
+
return () => {
|
|
34
|
+
isStopped = true;
|
|
35
|
+
subscriptions.forEach(subscription => subscription.remove());
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// React lifecycle wiring over `watchPowerState` from core, twin of upstream's `usePowerState`
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { initialPowerState, watchPowerState, } from '../../../core/index.js';
|
|
4
|
+
export function usePowerState() {
|
|
5
|
+
const [powerState, setPowerState] = useState(initialPowerState);
|
|
6
|
+
useEffect(() => watchPowerState(setPowerState), []);
|
|
7
|
+
return powerState;
|
|
8
|
+
}
|
package/build/react/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { useBatteryLevel } from './hooks/use-battery-level';
|
|
2
2
|
export { useBatteryState } from './hooks/use-battery-state';
|
|
3
3
|
export { useLowPowerMode } from './hooks/use-low-power-mode';
|
|
4
|
+
export { usePowerState } from './hooks/use-power-state';
|
|
4
5
|
export * from '../core';
|
package/build/react/index.js
CHANGED
|
@@ -6,4 +6,5 @@
|
|
|
6
6
|
export { useBatteryLevel } from './hooks/use-battery-level/index.js';
|
|
7
7
|
export { useBatteryState } from './hooks/use-battery-state/index.js';
|
|
8
8
|
export { useLowPowerMode } from './hooks/use-low-power-mode/index.js';
|
|
9
|
+
export { usePowerState } from './hooks/use-power-state/index.js';
|
|
9
10
|
export * from '../core/index.js';
|
package/build/solid/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createBatteryLevel } from './primitives/create-battery-level';
|
|
2
2
|
export { createBatteryState } from './primitives/create-battery-state';
|
|
3
3
|
export { createLowPowerMode } from './primitives/create-low-power-mode';
|
|
4
|
+
export { createPowerState } from './primitives/create-power-state';
|
|
4
5
|
export * from '../core';
|
package/build/solid/index.js
CHANGED
|
@@ -7,4 +7,5 @@
|
|
|
7
7
|
export { createBatteryLevel } from './primitives/create-battery-level.js';
|
|
8
8
|
export { createBatteryState } from './primitives/create-battery-state.js';
|
|
9
9
|
export { createLowPowerMode } from './primitives/create-low-power-mode.js';
|
|
10
|
+
export { createPowerState } from './primitives/create-power-state.js';
|
|
10
11
|
export * from '../core/index.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Solid lifecycle wiring over `watchPowerState` from core, twin of upstream's `usePowerState`
|
|
2
|
+
import { createSignal, onCleanup } from 'solid-js';
|
|
3
|
+
import { initialPowerState, watchPowerState, } from '../../core/index.js';
|
|
4
|
+
export function createPowerState() {
|
|
5
|
+
const [powerState, setPowerState] = createSignal(initialPowerState);
|
|
6
|
+
onCleanup(watchPowerState(setPowerState));
|
|
7
|
+
return powerState;
|
|
8
|
+
}
|
package/build/svelte/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { useBatteryLevel } from './runes/use-battery-level.svelte';
|
|
2
2
|
export { useBatteryState } from './runes/use-battery-state.svelte';
|
|
3
3
|
export { useLowPowerMode } from './runes/use-low-power-mode.svelte';
|
|
4
|
+
export { usePowerState } from './runes/use-power-state.svelte';
|
|
4
5
|
export * from '../core';
|
package/build/svelte/index.js
CHANGED
|
@@ -6,4 +6,5 @@
|
|
|
6
6
|
export { useBatteryLevel } from './runes/use-battery-level.svelte';
|
|
7
7
|
export { useBatteryState } from './runes/use-battery-state.svelte';
|
|
8
8
|
export { useLowPowerMode } from './runes/use-low-power-mode.svelte';
|
|
9
|
+
export { usePowerState } from './runes/use-power-state.svelte';
|
|
9
10
|
export * from '../core/index.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Svelte lifecycle wiring over `watchPowerState` from core, twin of upstream's `usePowerState`
|
|
2
|
+
import { initialPowerState, watchPowerState, } from '../../core/index.js';
|
|
3
|
+
export function usePowerState() {
|
|
4
|
+
let powerState = $state.raw(initialPowerState);
|
|
5
|
+
$effect(() => watchPowerState(next => {
|
|
6
|
+
powerState = next;
|
|
7
|
+
}));
|
|
8
|
+
return {
|
|
9
|
+
get current() {
|
|
10
|
+
return powerState;
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Vue lifecycle wiring over `watchPowerState` from core, twin of upstream's `usePowerState`
|
|
2
|
+
import { onMounted, onUnmounted, shallowRef, } from '@vue/runtime-core';
|
|
3
|
+
import { initialPowerState, watchPowerState, } from '../../../core/index.js';
|
|
4
|
+
export function usePowerState() {
|
|
5
|
+
const powerState = shallowRef(initialPowerState);
|
|
6
|
+
let stop;
|
|
7
|
+
onMounted(() => {
|
|
8
|
+
stop = watchPowerState(next => {
|
|
9
|
+
powerState.value = next;
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
onUnmounted(() => {
|
|
13
|
+
stop?.();
|
|
14
|
+
});
|
|
15
|
+
return powerState;
|
|
16
|
+
}
|
package/build/vue/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { useBatteryLevel } from './composables/use-battery-level';
|
|
2
2
|
export { useBatteryState } from './composables/use-battery-state';
|
|
3
3
|
export { useLowPowerMode } from './composables/use-low-power-mode';
|
|
4
|
+
export { usePowerState } from './composables/use-power-state';
|
|
4
5
|
export * from '../core';
|
package/build/vue/index.js
CHANGED
|
@@ -6,4 +6,5 @@
|
|
|
6
6
|
export { useBatteryLevel } from './composables/use-battery-level/index.js';
|
|
7
7
|
export { useBatteryState } from './composables/use-battery-state/index.js';
|
|
8
8
|
export { useLowPowerMode } from './composables/use-low-power-mode/index.js';
|
|
9
|
+
export { usePowerState } from './composables/use-power-state/index.js';
|
|
9
10
|
export * from '../core/index.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { BatteryLevelService } from './services/battery-level.service';
|
|
2
2
|
export { BatteryStateService } from './services/battery-state.service';
|
|
3
3
|
export { LowPowerModeService } from './services/low-power-mode.service';
|
|
4
|
+
export { PowerStateService } from './services/power-state.service';
|
|
4
5
|
export * from '../core';
|
|
@@ -5,5 +5,6 @@
|
|
|
5
5
|
export { BatteryLevelService } from './services/battery-level.service';
|
|
6
6
|
export { BatteryStateService } from './services/battery-state.service';
|
|
7
7
|
export { LowPowerModeService } from './services/low-power-mode.service';
|
|
8
|
+
export { PowerStateService } from './services/power-state.service';
|
|
8
9
|
export * from '../core';
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,yFAAyF;AACzF,yFAAyF;AACzF,8EAA8E;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,yFAAyF;AACzF,yFAAyF;AACzF,8EAA8E;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Signal } from '@angular/core';
|
|
2
|
+
import { type PowerState } from '../../../core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class PowerStateService {
|
|
5
|
+
private readonly injector;
|
|
6
|
+
connect(): Signal<PowerState>;
|
|
7
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<PowerStateService, never>;
|
|
8
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<PowerStateService>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { inject, Injectable, Injector } from '@angular/core';
|
|
2
|
+
import { connectWatchedSignal } from '@symbiote-native/angular';
|
|
3
|
+
import { initialPowerState, watchPowerState, } from '../../../core';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
// Angular twin of `usePowerState`, same `connect()` pattern as `BatteryLevelService`
|
|
6
|
+
export class PowerStateService {
|
|
7
|
+
injector = inject(Injector);
|
|
8
|
+
connect() {
|
|
9
|
+
return connectWatchedSignal(this.injector, initialPowerState, watchPowerState);
|
|
10
|
+
}
|
|
11
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PowerStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
12
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PowerStateService, providedIn: 'root' });
|
|
13
|
+
}
|
|
14
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PowerStateService, decorators: [{
|
|
15
|
+
type: Injectable,
|
|
16
|
+
args: [{ providedIn: 'root' }]
|
|
17
|
+
}] });
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/power-state.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAe,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EACL,iBAAiB,EACjB,eAAe,GAEhB,MAAM,eAAe,CAAC;;AAEvB,qFAAqF;AAErF,MAAM,OAAO,iBAAiB;IACX,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO;QACL,OAAO,oBAAoB,CACzB,IAAI,CAAC,QAAQ,EACb,iBAAiB,EACjB,eAAe,CAChB,CAAC;IACJ,CAAC;uGATU,iBAAiB;2GAAjB,iBAAiB,cADJ,MAAM;;2FACnB,iBAAiB;kBAD7B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { isAvailableAsync, getBatteryLevelAsync, getBatteryStateAsync, isLowPowerModeEnabledAsync, isBatteryOptimizationEnabledAsync, getPowerStateAsync, addBatteryLevelListener, addBatteryStateListener, addLowPowerModeListener, } from './battery';
|
|
2
2
|
export { BatteryState, type PowerState, type BatteryLevelEvent, type BatteryStateEvent, type PowerModeEvent, } from './types';
|
|
3
|
+
export { initialPowerState, watchPowerState } from './power-state';
|
|
3
4
|
export type { EventSubscription } from 'expo-modules-core';
|
package/build-ngc/core/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { isAvailableAsync, getBatteryLevelAsync, getBatteryStateAsync, isLowPowerModeEnabledAsync, isBatteryOptimizationEnabledAsync, getPowerStateAsync, addBatteryLevelListener, addBatteryStateListener, addLowPowerModeListener, } from './battery';
|
|
2
2
|
export { BatteryState, } from './types';
|
|
3
|
+
export { initialPowerState, watchPowerState } from './power-state';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,EAC1B,iCAAiC,EACjC,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,GAKb,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,EAC1B,iCAAiC,EACjC,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,GAKb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Shared half of upstream's `usePowerState`: level, state and low-power mode as one merged value
|
|
2
|
+
import { addBatteryLevelListener, addBatteryStateListener, addLowPowerModeListener, getBatteryLevelAsync, getBatteryStateAsync, isLowPowerModeEnabledAsync, } from './battery';
|
|
3
|
+
import { BatteryState } from './types';
|
|
4
|
+
export const initialPowerState = {
|
|
5
|
+
lowPowerMode: false,
|
|
6
|
+
batteryLevel: -1,
|
|
7
|
+
batteryState: BatteryState.UNKNOWN,
|
|
8
|
+
};
|
|
9
|
+
// Seeds each field with a one-shot fetch, then follows native events; returns the teardown
|
|
10
|
+
export function watchPowerState(onChange) {
|
|
11
|
+
let state = initialPowerState;
|
|
12
|
+
let isStopped = false;
|
|
13
|
+
const heardFields = new Set();
|
|
14
|
+
// A native event that lands before its seed resolves wins because the seed is the older value
|
|
15
|
+
function write(key, value, isSeed) {
|
|
16
|
+
if (isStopped || (isSeed && heardFields.has(key))) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!isSeed) {
|
|
20
|
+
heardFields.add(key);
|
|
21
|
+
}
|
|
22
|
+
state = { ...state, [key]: value };
|
|
23
|
+
onChange(state);
|
|
24
|
+
}
|
|
25
|
+
const subscriptions = [
|
|
26
|
+
addLowPowerModeListener(event => write('lowPowerMode', event.lowPowerMode, false)),
|
|
27
|
+
addBatteryLevelListener(event => write('batteryLevel', event.batteryLevel, false)),
|
|
28
|
+
addBatteryStateListener(event => write('batteryState', event.batteryState, false)),
|
|
29
|
+
];
|
|
30
|
+
isLowPowerModeEnabledAsync().then(value => write('lowPowerMode', value, true));
|
|
31
|
+
getBatteryLevelAsync().then(value => write('batteryLevel', value, true));
|
|
32
|
+
getBatteryStateAsync().then(value => write('batteryState', value, true));
|
|
33
|
+
return () => {
|
|
34
|
+
isStopped = true;
|
|
35
|
+
subscriptions.forEach(subscription => subscription.remove());
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=power-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"power-state.js","sourceRoot":"","sources":["../../src/core/power-state.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,YAAY,EAAmB,MAAM,SAAS,CAAC;AAExD,MAAM,CAAC,MAAM,iBAAiB,GAAe;IAC3C,YAAY,EAAE,KAAK;IACnB,YAAY,EAAE,CAAC,CAAC;IAChB,YAAY,EAAE,YAAY,CAAC,OAAO;CACnC,CAAC;AAEF,2FAA2F;AAC3F,MAAM,UAAU,eAAe,CAC7B,QAAqC;IAErC,IAAI,KAAK,GAAG,iBAAiB,CAAC;IAC9B,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEhD,8FAA8F;IAC9F,SAAS,KAAK,CACZ,GAAM,EACN,KAAoB,EACpB,MAAe;QAEf,IAAI,SAAS,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAClD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,KAAK,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;QACnC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,aAAa,GAAG;QACpB,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAC9B,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CACjD;QACD,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAC9B,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CACjD;QACD,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAC9B,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CACjD;KACF,CAAC;IACF,0BAA0B,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CACxC,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,CACnC,CAAC;IACF,oBAAoB,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IACzE,oBAAoB,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAEzE,OAAO,GAAG,EAAE;QACV,SAAS,GAAG,IAAI,CAAC;QACjB,aAAa,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/battery",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "expo-battery wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Battery level and state (charging/full/unplugged/unknown), low-power-mode detection, plus event listeners for level and state changes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"expo-battery": "57.0.1",
|
|
73
|
-
"expo-modules-core": "57.0.
|
|
73
|
+
"expo-modules-core": "57.0.20"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@angular/core": ">=20",
|
|
@@ -80,12 +80,12 @@
|
|
|
80
80
|
"solid-js": ">=1.9.0",
|
|
81
81
|
"svelte": ">=5.56.0",
|
|
82
82
|
"vue": ">=3.5.0",
|
|
83
|
-
"@symbiote-native/angular": "^3.
|
|
84
|
-
"@symbiote-native/engine": "^1.
|
|
85
|
-
"@symbiote-native/react": "^3.0
|
|
86
|
-
"@symbiote-native/solid": "^3.0
|
|
87
|
-
"@symbiote-native/svelte": "^3.0
|
|
88
|
-
"@symbiote-native/vue": "^3.0
|
|
83
|
+
"@symbiote-native/angular": "^3.2.0",
|
|
84
|
+
"@symbiote-native/engine": "^1.5.0",
|
|
85
|
+
"@symbiote-native/react": "^3.2.0",
|
|
86
|
+
"@symbiote-native/solid": "^3.1.0",
|
|
87
|
+
"@symbiote-native/svelte": "^3.1.0",
|
|
88
|
+
"@symbiote-native/vue": "^3.2.0"
|
|
89
89
|
},
|
|
90
90
|
"peerDependenciesMeta": {
|
|
91
91
|
"@symbiote-native/angular": {
|
|
@@ -133,13 +133,13 @@
|
|
|
133
133
|
"solid-js": "^1.9.14",
|
|
134
134
|
"svelte": "^5.56.0",
|
|
135
135
|
"typescript": "~6.0.0",
|
|
136
|
-
"@symbiote-native/angular": "3.
|
|
137
|
-
"@symbiote-native/engine": "1.
|
|
138
|
-
"@symbiote-native/react": "3.0
|
|
139
|
-
"@symbiote-native/solid": "3.0
|
|
140
|
-
"@symbiote-native/svelte": "3.0
|
|
141
|
-
"@symbiote-native/test-utils": "0.4.
|
|
142
|
-
"@symbiote-native/vue": "3.0
|
|
136
|
+
"@symbiote-native/angular": "3.2.0",
|
|
137
|
+
"@symbiote-native/engine": "1.5.0",
|
|
138
|
+
"@symbiote-native/react": "3.2.0",
|
|
139
|
+
"@symbiote-native/solid": "3.1.0",
|
|
140
|
+
"@symbiote-native/svelte": "3.1.0",
|
|
141
|
+
"@symbiote-native/test-utils": "0.4.6",
|
|
142
|
+
"@symbiote-native/vue": "3.2.0"
|
|
143
143
|
},
|
|
144
144
|
"scripts": {
|
|
145
145
|
"typecheck": "tsc --build",
|
package/src/angular/index.ts
CHANGED
|
@@ -5,4 +5,5 @@
|
|
|
5
5
|
export { BatteryLevelService } from './services/battery-level.service';
|
|
6
6
|
export { BatteryStateService } from './services/battery-state.service';
|
|
7
7
|
export { LowPowerModeService } from './services/low-power-mode.service';
|
|
8
|
+
export { PowerStateService } from './services/power-state.service';
|
|
8
9
|
export * from '../core';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { inject, Injectable, Injector, type Signal } from '@angular/core';
|
|
2
|
+
import { connectWatchedSignal } from '@symbiote-native/angular';
|
|
3
|
+
import {
|
|
4
|
+
initialPowerState,
|
|
5
|
+
watchPowerState,
|
|
6
|
+
type PowerState,
|
|
7
|
+
} from '../../../core';
|
|
8
|
+
|
|
9
|
+
// Angular twin of `usePowerState`, same `connect()` pattern as `BatteryLevelService`
|
|
10
|
+
@Injectable({ providedIn: 'root' })
|
|
11
|
+
export class PowerStateService {
|
|
12
|
+
private readonly injector = inject(Injector);
|
|
13
|
+
|
|
14
|
+
connect(): Signal<PowerState> {
|
|
15
|
+
return connectWatchedSignal(
|
|
16
|
+
this.injector,
|
|
17
|
+
initialPowerState,
|
|
18
|
+
watchPowerState,
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/core/index.ts
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Shared half of upstream's `usePowerState`: level, state and low-power mode as one merged value
|
|
2
|
+
import {
|
|
3
|
+
addBatteryLevelListener,
|
|
4
|
+
addBatteryStateListener,
|
|
5
|
+
addLowPowerModeListener,
|
|
6
|
+
getBatteryLevelAsync,
|
|
7
|
+
getBatteryStateAsync,
|
|
8
|
+
isLowPowerModeEnabledAsync,
|
|
9
|
+
} from './battery';
|
|
10
|
+
import { BatteryState, type PowerState } from './types';
|
|
11
|
+
|
|
12
|
+
export const initialPowerState: PowerState = {
|
|
13
|
+
lowPowerMode: false,
|
|
14
|
+
batteryLevel: -1,
|
|
15
|
+
batteryState: BatteryState.UNKNOWN,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Seeds each field with a one-shot fetch, then follows native events; returns the teardown
|
|
19
|
+
export function watchPowerState(
|
|
20
|
+
onChange: (state: PowerState) => void,
|
|
21
|
+
): () => void {
|
|
22
|
+
let state = initialPowerState;
|
|
23
|
+
let isStopped = false;
|
|
24
|
+
const heardFields = new Set<keyof PowerState>();
|
|
25
|
+
|
|
26
|
+
// A native event that lands before its seed resolves wins because the seed is the older value
|
|
27
|
+
function write<K extends keyof PowerState>(
|
|
28
|
+
key: K,
|
|
29
|
+
value: PowerState[K],
|
|
30
|
+
isSeed: boolean,
|
|
31
|
+
): void {
|
|
32
|
+
if (isStopped || (isSeed && heardFields.has(key))) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!isSeed) {
|
|
36
|
+
heardFields.add(key);
|
|
37
|
+
}
|
|
38
|
+
state = { ...state, [key]: value };
|
|
39
|
+
onChange(state);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const subscriptions = [
|
|
43
|
+
addLowPowerModeListener(event =>
|
|
44
|
+
write('lowPowerMode', event.lowPowerMode, false),
|
|
45
|
+
),
|
|
46
|
+
addBatteryLevelListener(event =>
|
|
47
|
+
write('batteryLevel', event.batteryLevel, false),
|
|
48
|
+
),
|
|
49
|
+
addBatteryStateListener(event =>
|
|
50
|
+
write('batteryState', event.batteryState, false),
|
|
51
|
+
),
|
|
52
|
+
];
|
|
53
|
+
isLowPowerModeEnabledAsync().then(value =>
|
|
54
|
+
write('lowPowerMode', value, true),
|
|
55
|
+
);
|
|
56
|
+
getBatteryLevelAsync().then(value => write('batteryLevel', value, true));
|
|
57
|
+
getBatteryStateAsync().then(value => write('batteryState', value, true));
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
isStopped = true;
|
|
61
|
+
subscriptions.forEach(subscription => subscription.remove());
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// React lifecycle wiring over `watchPowerState` from core, twin of upstream's `usePowerState`
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
initialPowerState,
|
|
5
|
+
watchPowerState,
|
|
6
|
+
type PowerState,
|
|
7
|
+
} from '../../../core';
|
|
8
|
+
|
|
9
|
+
export function usePowerState(): PowerState {
|
|
10
|
+
const [powerState, setPowerState] = useState(initialPowerState);
|
|
11
|
+
|
|
12
|
+
useEffect(() => watchPowerState(setPowerState), []);
|
|
13
|
+
|
|
14
|
+
return powerState;
|
|
15
|
+
}
|
package/src/react/index.ts
CHANGED
|
@@ -7,4 +7,5 @@
|
|
|
7
7
|
export { useBatteryLevel } from './hooks/use-battery-level';
|
|
8
8
|
export { useBatteryState } from './hooks/use-battery-state';
|
|
9
9
|
export { useLowPowerMode } from './hooks/use-low-power-mode';
|
|
10
|
+
export { usePowerState } from './hooks/use-power-state';
|
|
10
11
|
export * from '../core';
|
package/src/solid/index.ts
CHANGED
|
@@ -8,4 +8,5 @@
|
|
|
8
8
|
export { createBatteryLevel } from './primitives/create-battery-level';
|
|
9
9
|
export { createBatteryState } from './primitives/create-battery-state';
|
|
10
10
|
export { createLowPowerMode } from './primitives/create-low-power-mode';
|
|
11
|
+
export { createPowerState } from './primitives/create-power-state';
|
|
11
12
|
export * from '../core';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Solid lifecycle wiring over `watchPowerState` from core, twin of upstream's `usePowerState`
|
|
2
|
+
import { createSignal, onCleanup, type Accessor } from 'solid-js';
|
|
3
|
+
import {
|
|
4
|
+
initialPowerState,
|
|
5
|
+
watchPowerState,
|
|
6
|
+
type PowerState,
|
|
7
|
+
} from '../../core';
|
|
8
|
+
|
|
9
|
+
export function createPowerState(): Accessor<PowerState> {
|
|
10
|
+
const [powerState, setPowerState] = createSignal(initialPowerState);
|
|
11
|
+
|
|
12
|
+
onCleanup(watchPowerState(setPowerState));
|
|
13
|
+
|
|
14
|
+
return powerState;
|
|
15
|
+
}
|
package/src/svelte/index.ts
CHANGED
|
@@ -7,4 +7,5 @@
|
|
|
7
7
|
export { useBatteryLevel } from './runes/use-battery-level.svelte';
|
|
8
8
|
export { useBatteryState } from './runes/use-battery-state.svelte';
|
|
9
9
|
export { useLowPowerMode } from './runes/use-low-power-mode.svelte';
|
|
10
|
+
export { usePowerState } from './runes/use-power-state.svelte';
|
|
10
11
|
export * from '../core';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Svelte lifecycle wiring over `watchPowerState` from core, twin of upstream's `usePowerState`
|
|
2
|
+
import {
|
|
3
|
+
initialPowerState,
|
|
4
|
+
watchPowerState,
|
|
5
|
+
type PowerState,
|
|
6
|
+
} from '../../core';
|
|
7
|
+
|
|
8
|
+
export function usePowerState(): { readonly current: PowerState } {
|
|
9
|
+
let powerState = $state.raw(initialPowerState);
|
|
10
|
+
|
|
11
|
+
$effect(() =>
|
|
12
|
+
watchPowerState(next => {
|
|
13
|
+
powerState = next;
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
get current(): PowerState {
|
|
19
|
+
return powerState;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Vue lifecycle wiring over `watchPowerState` from core, twin of upstream's `usePowerState`
|
|
2
|
+
import {
|
|
3
|
+
onMounted,
|
|
4
|
+
onUnmounted,
|
|
5
|
+
shallowRef,
|
|
6
|
+
type Ref,
|
|
7
|
+
} from '@vue/runtime-core';
|
|
8
|
+
import {
|
|
9
|
+
initialPowerState,
|
|
10
|
+
watchPowerState,
|
|
11
|
+
type PowerState,
|
|
12
|
+
} from '../../../core';
|
|
13
|
+
|
|
14
|
+
export function usePowerState(): Ref<PowerState> {
|
|
15
|
+
const powerState = shallowRef(initialPowerState);
|
|
16
|
+
let stop: (() => void) | undefined;
|
|
17
|
+
|
|
18
|
+
onMounted(() => {
|
|
19
|
+
stop = watchPowerState(next => {
|
|
20
|
+
powerState.value = next;
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
onUnmounted(() => {
|
|
25
|
+
stop?.();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return powerState;
|
|
29
|
+
}
|
package/src/vue/index.ts
CHANGED
|
@@ -7,4 +7,5 @@
|
|
|
7
7
|
export { useBatteryLevel } from './composables/use-battery-level';
|
|
8
8
|
export { useBatteryState } from './composables/use-battery-state';
|
|
9
9
|
export { useLowPowerMode } from './composables/use-low-power-mode';
|
|
10
|
+
export { usePowerState } from './composables/use-power-state';
|
|
10
11
|
export * from '../core';
|