@symbiote-native/battery 0.0.1 → 0.2.0
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 +172 -27
- package/build/angular/index.d.ts +4 -0
- package/build/angular/index.js +8 -0
- package/build/angular/services/battery-level.service/index.d.ts +5 -0
- package/build/angular/services/battery-level.service/index.js +74 -0
- package/build/angular/services/battery-state.service/index.d.ts +6 -0
- package/build/angular/services/battery-state.service/index.js +69 -0
- package/build/angular/services/low-power-mode.service/index.d.ts +5 -0
- package/build/angular/services/low-power-mode.service/index.js +69 -0
- package/build/core/battery.d.ts +44 -0
- package/build/core/battery.js +79 -0
- package/build/core/index.d.ts +3 -0
- package/build/core/index.js +2 -0
- package/build/core/native-module.d.ts +13 -0
- package/build/core/native-module.js +3 -0
- package/build/core/types.d.ts +40 -0
- package/build/core/types.js +23 -0
- package/build/react/hooks/use-battery-level/index.d.ts +1 -0
- package/build/react/hooks/use-battery-level/index.js +16 -0
- package/build/react/hooks/use-battery-state/index.d.ts +2 -0
- package/build/react/hooks/use-battery-state/index.js +14 -0
- package/build/react/hooks/use-low-power-mode/index.d.ts +1 -0
- package/build/react/hooks/use-low-power-mode/index.js +15 -0
- package/build/react/index.d.ts +4 -0
- package/build/react/index.js +9 -0
- package/build/svelte/index.d.ts +4 -0
- package/build/svelte/index.js +9 -0
- package/build/svelte/runes/use-battery-level.svelte.d.ts +3 -0
- package/build/svelte/runes/use-battery-level.svelte.js +37 -0
- package/build/svelte/runes/use-battery-state.svelte.d.ts +4 -0
- package/build/svelte/runes/use-battery-state.svelte.js +22 -0
- package/build/svelte/runes/use-low-power-mode.svelte.d.ts +3 -0
- package/build/svelte/runes/use-low-power-mode.svelte.js +22 -0
- package/build/vue/composables/use-battery-level/index.d.ts +2 -0
- package/build/vue/composables/use-battery-level/index.js +23 -0
- package/build/vue/composables/use-battery-state/index.d.ts +3 -0
- package/build/vue/composables/use-battery-state/index.js +21 -0
- package/build/vue/composables/use-low-power-mode/index.d.ts +2 -0
- package/build/vue/composables/use-low-power-mode/index.js +22 -0
- package/build/vue/index.d.ts +4 -0
- package/build/vue/index.js +9 -0
- package/build-ngc/angular/index.d.ts +4 -0
- package/build-ngc/angular/index.js +9 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/angular/services/battery-level.service/index.d.ts +8 -0
- package/build-ngc/angular/services/battery-level.service/index.js +33 -0
- package/build-ngc/angular/services/battery-level.service/index.js.map +1 -0
- package/build-ngc/angular/services/battery-state.service/index.d.ts +9 -0
- package/build-ngc/angular/services/battery-state.service/index.js +28 -0
- package/build-ngc/angular/services/battery-state.service/index.js.map +1 -0
- package/build-ngc/angular/services/low-power-mode.service/index.d.ts +8 -0
- package/build-ngc/angular/services/low-power-mode.service/index.js +28 -0
- package/build-ngc/angular/services/low-power-mode.service/index.js.map +1 -0
- package/build-ngc/core/battery.d.ts +44 -0
- package/build-ngc/core/battery.js +80 -0
- package/build-ngc/core/battery.js.map +1 -0
- package/build-ngc/core/index.d.ts +3 -0
- package/build-ngc/core/index.js +3 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/native-module.d.ts +13 -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 +40 -0
- package/build-ngc/core/types.js +24 -0
- package/build-ngc/core/types.js.map +1 -0
- package/native-link.json +12 -0
- package/package.json +106 -1
- package/src/angular/index.ts +8 -0
- package/src/angular/services/battery-level.service/index.ts +32 -0
- package/src/angular/services/battery-state.service/index.ts +27 -0
- package/src/angular/services/low-power-mode.service/index.ts +27 -0
- package/src/core/battery.ts +105 -0
- package/src/core/index.ts +19 -0
- package/src/core/native-module.ts +31 -0
- package/src/core/types.ts +47 -0
- package/src/react/hooks/use-battery-level/index.ts +19 -0
- package/src/react/hooks/use-battery-state/index.ts +17 -0
- package/src/react/hooks/use-low-power-mode/index.ts +18 -0
- package/src/react/index.ts +10 -0
- package/src/svelte/index.ts +10 -0
- package/src/svelte/runes/use-battery-level.svelte.ts +41 -0
- package/src/svelte/runes/use-battery-state.svelte.ts +30 -0
- package/src/svelte/runes/use-low-power-mode.svelte.ts +29 -0
- package/src/svelte/svelte-ambient.d.ts +6 -0
- package/src/vue/composables/use-battery-level/index.ts +32 -0
- package/src/vue/composables/use-battery-state/index.ts +31 -0
- package/src/vue/composables/use-low-power-mode/index.ts +31 -0
- package/src/vue/index.ts +10 -0
package/README.md
CHANGED
|
@@ -1,19 +1,144 @@
|
|
|
1
1
|
# @symbiote-native/battery
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
This package currently ships nothing but `package.json` and this README. No `src/`, no
|
|
5
|
-
dependencies, no build. See the `symbiote-new-package-skeleton` project skill for what a
|
|
6
|
-
tier-1 skeleton package is and isn't.
|
|
7
|
-
|
|
8
|
-
Planned: a port of [`expo-battery`](https://docs.expo.dev/versions/latest/sdk/battery/) for
|
|
3
|
+
Port of [`expo-battery`](https://docs.expo.dev/versions/latest/sdk/battery/) for
|
|
9
4
|
[SymbioteNative](../../README.md) — battery level and state, low-power-mode detection, reachable
|
|
10
5
|
from every adapter (React, Vue, Angular), not just React.
|
|
11
6
|
|
|
12
|
-
|
|
7
|
+
Built the same way as [`@symbiote-native/local-auth`](../local-auth) and
|
|
8
|
+
[`@symbiote-native/sensors`](../sensors), an `expo-modules-core`-based wrapper (see the
|
|
9
|
+
`symbiote-expo-native-module` project skill for the full mechanism: why `expo-modules-core` is
|
|
10
|
+
depended on directly and never the `expo` meta-package, why the upstream JS is hand-ported into
|
|
11
|
+
`core/` rather than imported, and how autolinking picks up the native module).
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @symbiote-native/battery
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Depends on `expo-battery` and `expo-modules-core` directly (regular dependencies, pinned to exact
|
|
20
|
+
versions — never a caret range, since this package's `core/` is hand-ported against one specific
|
|
21
|
+
native API shape and a newer resolve could silently drift the two apart). Never install
|
|
22
|
+
`expo-battery` yourself, and never add the `expo` package to this project — it bundles its own
|
|
23
|
+
Metro/Babel pipeline that conflicts with this project's own.
|
|
24
|
+
|
|
25
|
+
### Required one-time step: native autolinking wiring
|
|
26
|
+
|
|
27
|
+
Unlike a plain RN native module, `expo-battery`'s native code is discovered by
|
|
28
|
+
`expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism — this needs wiring
|
|
29
|
+
into the native host app **once**, covering this package and every other `expo-modules-core`
|
|
30
|
+
package (`@symbiote-native/sensors`, `@symbiote-native/local-auth`) with zero further changes:
|
|
31
|
+
|
|
32
|
+
| Platform | Touches |
|
|
33
|
+
|---|---|
|
|
34
|
+
| iOS | `ios/Podfile` — add `use_expo_modules!` |
|
|
35
|
+
| iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
|
|
36
|
+
| Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
|
|
37
|
+
| 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) |
|
|
38
|
+
|
|
39
|
+
Full mechanics — the Podfile pieces that normally ship inside the `expo` package, the `expo`
|
|
40
|
+
peer-dependency exclusion list — live in the `symbiote-expo-native-module` skill. Reference
|
|
41
|
+
implementation: `examples/expo-react/ios/Podfile` and
|
|
42
|
+
`examples/expo-react/android/app/src/main/java/com/canaryexpo/MainApplication.kt`.
|
|
43
|
+
|
|
44
|
+
No platform permission string is needed for battery's basic surface —
|
|
45
|
+
`isBatteryOptimizationEnabledAsync` reads an Android-only system state with no runtime permission
|
|
46
|
+
prompt either.
|
|
47
|
+
|
|
48
|
+
## Shape
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
src/core/ Battery.ts — one-shot get*Async functions + addListener subscriptions.
|
|
52
|
+
native-module.ts resolves the native module through expo-modules-core's
|
|
53
|
+
requireNativeModule. types.ts — BatteryState enum, PowerState,
|
|
54
|
+
*Event shapes, hand-ported from Battery.types.ts.
|
|
55
|
+
src/react/hooks/ @symbiote-native/battery/react — useBatteryLevel, useBatteryState,
|
|
56
|
+
useLowPowerMode
|
|
57
|
+
src/vue/composables/ @symbiote-native/battery/vue — same three names, Vue lifecycle
|
|
58
|
+
src/angular/services/ @symbiote-native/battery/angular — BatteryLevelService, BatteryStateService,
|
|
59
|
+
LowPowerModeService (`.connect()` returns a Signal)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Each adapter's hook/composable/service is a thin lifecycle wrapper (seed from the one-shot
|
|
63
|
+
`get*Async` call, subscribe to the matching listener, unsubscribe on unmount/cleanup) over the
|
|
64
|
+
same `core` functions — the subscription and fallback logic is written once and shared by all
|
|
65
|
+
three.
|
|
66
|
+
|
|
67
|
+
## Use it
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
// React — examples/expo-react/screens/BatteryScreen.tsx
|
|
71
|
+
import { useBatteryLevel, useBatteryState, useLowPowerMode } from '@symbiote-native/battery/react';
|
|
72
|
+
import { BatteryState } from '@symbiote-native/battery';
|
|
73
|
+
|
|
74
|
+
function BatteryScreen() {
|
|
75
|
+
const batteryLevel = useBatteryLevel(); // number, -1 until the first reading arrives
|
|
76
|
+
const batteryState = useBatteryState(); // BatteryState, UNKNOWN until the first reading
|
|
77
|
+
const lowPowerMode = useLowPowerMode(); // boolean, false until the first reading
|
|
78
|
+
|
|
79
|
+
const batteryLevelLabel = batteryLevel < 0 ? 'unknown' : `${Math.round(batteryLevel * 100)}%`;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<>
|
|
83
|
+
<Text>{batteryLevelLabel}</Text>
|
|
84
|
+
<Text>{batteryState === BatteryState.CHARGING ? 'Charging' : 'Not charging'}</Text>
|
|
85
|
+
<Text>{lowPowerMode ? 'On' : 'Off'}</Text>
|
|
86
|
+
</>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<!-- Vue — examples/expo-vue-sfc/screens/BatteryScreen.vue -->
|
|
93
|
+
<script setup lang="ts">
|
|
94
|
+
import { computed } from 'vue';
|
|
95
|
+
import { useBatteryLevel, useBatteryState, useLowPowerMode } from '@symbiote-native/battery/vue';
|
|
96
|
+
|
|
97
|
+
const batteryLevel = useBatteryLevel(); // Ref<number>
|
|
98
|
+
const batteryState = useBatteryState(); // Ref<BatteryState>
|
|
99
|
+
const lowPowerMode = useLowPowerMode(); // Ref<boolean>
|
|
100
|
+
|
|
101
|
+
const batteryLevelText = computed(() =>
|
|
102
|
+
batteryLevel.value < 0 ? 'unknown' : `${Math.round(batteryLevel.value * 100)}%`,
|
|
103
|
+
);
|
|
104
|
+
</script>
|
|
105
|
+
<template>
|
|
106
|
+
<Text>{{ batteryLevelText }}</Text>
|
|
107
|
+
<Text>{{ lowPowerMode ? 'ON' : 'OFF' }}</Text>
|
|
108
|
+
</template>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
// Angular — examples/expo-angular/src/screens/BatteryScreen.ts
|
|
113
|
+
import { Component, inject } from '@angular/core';
|
|
114
|
+
import { BatteryLevelService, BatteryStateService, LowPowerModeService } from '@symbiote-native/battery/angular';
|
|
115
|
+
|
|
116
|
+
@Component({ /* ... */ })
|
|
117
|
+
export class BatteryScreen {
|
|
118
|
+
readonly batteryLevel = inject(BatteryLevelService).connect(); // Signal<number>
|
|
119
|
+
readonly batteryState = inject(BatteryStateService).connect(); // Signal<BatteryState>
|
|
120
|
+
readonly lowPowerMode = inject(LowPowerModeService).connect(); // Signal<boolean>
|
|
121
|
+
|
|
122
|
+
batteryLevelLabel(): string {
|
|
123
|
+
const level = this.batteryLevel();
|
|
124
|
+
return level < 0 ? 'unknown' : `${Math.round(level * 100)}%`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
13
128
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
129
|
+
Each of the three demo screens above also renders a one-shot capabilities card
|
|
130
|
+
(`isAvailableAsync()`, and Android-only `isBatteryOptimizationEnabledAsync()`) resolved directly
|
|
131
|
+
from `@symbiote-native/battery`'s core entry point — see the linked files for the full version.
|
|
132
|
+
The iOS Simulator reports the battery API as unavailable (`isAvailableAsync()` resolves `false`)
|
|
133
|
+
since simulators have no real battery hardware; a physical device is needed to see live readings.
|
|
134
|
+
|
|
135
|
+
## API
|
|
136
|
+
|
|
137
|
+
A mix of stateless async functions and three listener-based subscriptions
|
|
138
|
+
(`addBatteryLevelListener`/`addBatteryStateListener`/`addLowPowerModeListener`), each with its
|
|
139
|
+
own adapter-level lifecycle hook — one hook/composable/service per listener, matching upstream's
|
|
140
|
+
own `useBatteryLevel`/`useBatteryState`/`useLowPowerMode` being three separate hooks, not one
|
|
141
|
+
combined hook.
|
|
17
142
|
|
|
18
143
|
```ts
|
|
19
144
|
isAvailableAsync(): Promise<boolean> // battery API availability on this device
|
|
@@ -22,23 +147,43 @@ getBatteryStateAsync(): Promise<BatteryState> // UNKNOWN/UNPLUGG
|
|
|
22
147
|
isLowPowerModeEnabledAsync(): Promise<boolean> // Low Power Mode (iOS) / Power Saver (Android)
|
|
23
148
|
isBatteryOptimizationEnabledAsync(): Promise<boolean> // Android only
|
|
24
149
|
getPowerStateAsync(): Promise<PowerState> // combined level + state + lowPowerMode
|
|
25
|
-
addBatteryLevelListener(listener):
|
|
26
|
-
addBatteryStateListener(listener):
|
|
27
|
-
addLowPowerModeListener(listener):
|
|
150
|
+
addBatteryLevelListener(listener): EventSubscription // fires on battery level change
|
|
151
|
+
addBatteryStateListener(listener): EventSubscription // fires on battery state change
|
|
152
|
+
addLowPowerModeListener(listener): EventSubscription // fires when low-power mode toggles
|
|
28
153
|
```
|
|
29
154
|
|
|
30
155
|
Plus `BatteryState` (enum), `PowerState`, `BatteryLevelEvent`, `BatteryStateEvent`,
|
|
31
|
-
`PowerModeEvent` — ported from upstream's `Battery.types.ts`.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
156
|
+
`PowerModeEvent` — ported from upstream's `Battery.types.ts`.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { getBatteryLevelAsync, addBatteryLevelListener } from '@symbiote-native/battery';
|
|
160
|
+
|
|
161
|
+
// framework-scoped entry points re-export the same free functions, plus a lifecycle
|
|
162
|
+
// hook/composable/service per listener:
|
|
163
|
+
import { useBatteryLevel, useBatteryState, useLowPowerMode } from '@symbiote-native/battery/react';
|
|
164
|
+
import { useBatteryLevel, useBatteryState, useLowPowerMode } from '@symbiote-native/battery/vue';
|
|
165
|
+
import {
|
|
166
|
+
BatteryLevelService,
|
|
167
|
+
BatteryStateService,
|
|
168
|
+
LowPowerModeService,
|
|
169
|
+
} from '@symbiote-native/battery/angular';
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Each hook/composable/service seeds its initial value from the matching one-shot
|
|
173
|
+
`get*Async`/`is*Async` call, then subscribes to the matching listener for updates, and
|
|
174
|
+
unsubscribes on unmount — mirroring upstream's own `useBatteryLevel`/`useBatteryState`/
|
|
175
|
+
`useLowPowerMode`.
|
|
176
|
+
|
|
177
|
+
## Test it
|
|
178
|
+
|
|
179
|
+
No Fabric/Descriptor angle at all — battery is a pure async-function + `EventEmitter` listener
|
|
180
|
+
surface, never a view. Tests inject a fake native-module object in place of the real
|
|
181
|
+
`requireNativeModule` resolution (`src/core/battery.test.ts`,
|
|
182
|
+
`src/{react,vue,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
|
|
183
|
+
`@symbiote-native/sensors` and `@symbiote-native/local-auth` use — no `installFabric()`, no
|
|
184
|
+
ViewConfig. Native rendering itself is verified on-device — see the parent
|
|
185
|
+
[README](../../README.md).
|
|
186
|
+
|
|
187
|
+
The Android/iOS native wiring is done across all four `examples/expo-*` canary apps
|
|
188
|
+
(`examples/expo-react`, `examples/expo-vue-sfc`, `examples/expo-vue-tsx`, `examples/expo-angular`);
|
|
189
|
+
this package isn't yet in the public, non-Expo `examples/react` canary.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// BatteryLevelService/BatteryStateService/LowPowerModeService are the Angular-only lifecycle
|
|
2
|
+
// half; the free functions and event subscription plumbing all live in core, shared with
|
|
3
|
+
// React/Vue. Three separate services (not one combined service), matching upstream's own
|
|
4
|
+
// useBatteryLevel/useBatteryState/useLowPowerMode being three separate hooks.
|
|
5
|
+
export { BatteryLevelService } from './services/battery-level.service/index.js';
|
|
6
|
+
export { BatteryStateService } from './services/battery-state.service/index.js';
|
|
7
|
+
export { LowPowerModeService } from './services/low-power-mode.service/index.js';
|
|
8
|
+
export * from '../core/index.js';
|
|
@@ -0,0 +1,74 @@
|
|
|
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, signal } from '@angular/core';
|
|
36
|
+
import { addBatteryLevelListener, getBatteryLevelAsync } from '../../../core/index.js';
|
|
37
|
+
// Angular twin of React's `useBatteryLevel` hook and Vue's `useBatteryLevel` composable.
|
|
38
|
+
// Angular has no per-instance hook — state and lifecycle live in DI instead, so `connect()`
|
|
39
|
+
// stands in for the hook's role: call it ONCE (typically from a component's field initializer,
|
|
40
|
+
// inside an injection context).
|
|
41
|
+
//
|
|
42
|
+
// readonly batteryLevel = inject(BatteryLevelService).connect();
|
|
43
|
+
// // template: {{ batteryLevel() }}
|
|
44
|
+
//
|
|
45
|
+
// Mirrors AccelerometerService.connect() — a single effect() that seeds the initial value with
|
|
46
|
+
// getBatteryLevelAsync(), subscribes once, and cleans up once.
|
|
47
|
+
let BatteryLevelService = (() => {
|
|
48
|
+
let _classDecorators = [Injectable({ providedIn: 'root' })];
|
|
49
|
+
let _classDescriptor;
|
|
50
|
+
let _classExtraInitializers = [];
|
|
51
|
+
let _classThis;
|
|
52
|
+
var BatteryLevelService = class {
|
|
53
|
+
static { _classThis = this; }
|
|
54
|
+
static {
|
|
55
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
56
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
57
|
+
BatteryLevelService = _classThis = _classDescriptor.value;
|
|
58
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
59
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
60
|
+
}
|
|
61
|
+
injector = inject(Injector);
|
|
62
|
+
connect() {
|
|
63
|
+
const batteryLevel = signal(-1);
|
|
64
|
+
effect(onCleanup => {
|
|
65
|
+
getBatteryLevelAsync().then(level => batteryLevel.set(level));
|
|
66
|
+
const subscription = addBatteryLevelListener(event => batteryLevel.set(event.batteryLevel));
|
|
67
|
+
onCleanup(() => subscription.remove());
|
|
68
|
+
}, { injector: this.injector });
|
|
69
|
+
return batteryLevel.asReadonly();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return BatteryLevelService = _classThis;
|
|
73
|
+
})();
|
|
74
|
+
export { BatteryLevelService };
|
|
@@ -0,0 +1,69 @@
|
|
|
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, signal } from '@angular/core';
|
|
36
|
+
import { addBatteryStateListener, BatteryState, getBatteryStateAsync } from '../../../core/index.js';
|
|
37
|
+
// Angular twin of React's `useBatteryState` hook and Vue's `useBatteryState` composable. See
|
|
38
|
+
// BatteryLevelService for the `connect()` pattern rationale.
|
|
39
|
+
//
|
|
40
|
+
// readonly batteryState = inject(BatteryStateService).connect();
|
|
41
|
+
// // template: {{ batteryState() }}
|
|
42
|
+
let BatteryStateService = (() => {
|
|
43
|
+
let _classDecorators = [Injectable({ providedIn: 'root' })];
|
|
44
|
+
let _classDescriptor;
|
|
45
|
+
let _classExtraInitializers = [];
|
|
46
|
+
let _classThis;
|
|
47
|
+
var BatteryStateService = class {
|
|
48
|
+
static { _classThis = this; }
|
|
49
|
+
static {
|
|
50
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
51
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
52
|
+
BatteryStateService = _classThis = _classDescriptor.value;
|
|
53
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
54
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
55
|
+
}
|
|
56
|
+
injector = inject(Injector);
|
|
57
|
+
connect() {
|
|
58
|
+
const batteryState = signal(BatteryState.UNKNOWN);
|
|
59
|
+
effect(onCleanup => {
|
|
60
|
+
getBatteryStateAsync().then(state => batteryState.set(state));
|
|
61
|
+
const subscription = addBatteryStateListener(event => batteryState.set(event.batteryState));
|
|
62
|
+
onCleanup(() => subscription.remove());
|
|
63
|
+
}, { injector: this.injector });
|
|
64
|
+
return batteryState.asReadonly();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return BatteryStateService = _classThis;
|
|
68
|
+
})();
|
|
69
|
+
export { BatteryStateService };
|
|
@@ -0,0 +1,69 @@
|
|
|
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, signal } from '@angular/core';
|
|
36
|
+
import { addLowPowerModeListener, isLowPowerModeEnabledAsync } from '../../../core/index.js';
|
|
37
|
+
// Angular twin of React's `useLowPowerMode` hook and Vue's `useLowPowerMode` composable. See
|
|
38
|
+
// BatteryLevelService for the `connect()` pattern rationale.
|
|
39
|
+
//
|
|
40
|
+
// readonly lowPowerMode = inject(LowPowerModeService).connect();
|
|
41
|
+
// // template: {{ lowPowerMode() }}
|
|
42
|
+
let LowPowerModeService = (() => {
|
|
43
|
+
let _classDecorators = [Injectable({ providedIn: 'root' })];
|
|
44
|
+
let _classDescriptor;
|
|
45
|
+
let _classExtraInitializers = [];
|
|
46
|
+
let _classThis;
|
|
47
|
+
var LowPowerModeService = class {
|
|
48
|
+
static { _classThis = this; }
|
|
49
|
+
static {
|
|
50
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
51
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
52
|
+
LowPowerModeService = _classThis = _classDescriptor.value;
|
|
53
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
54
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
55
|
+
}
|
|
56
|
+
injector = inject(Injector);
|
|
57
|
+
connect() {
|
|
58
|
+
const lowPowerMode = signal(false);
|
|
59
|
+
effect(onCleanup => {
|
|
60
|
+
isLowPowerModeEnabledAsync().then(enabled => lowPowerMode.set(enabled));
|
|
61
|
+
const subscription = addLowPowerModeListener(event => lowPowerMode.set(event.lowPowerMode));
|
|
62
|
+
onCleanup(() => subscription.remove());
|
|
63
|
+
}, { injector: this.injector });
|
|
64
|
+
return lowPowerMode.asReadonly();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return LowPowerModeService = _classThis;
|
|
68
|
+
})();
|
|
69
|
+
export { LowPowerModeService };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { EventSubscription } from 'expo-modules-core';
|
|
2
|
+
import { BatteryState, type BatteryLevelEvent, type BatteryStateEvent, type PowerModeEvent, type PowerState } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves with whether the battery API is available on the current device. `true` on Android
|
|
5
|
+
* and physical iOS devices, `false` on iOS simulators.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isAvailableAsync(): Promise<boolean>;
|
|
8
|
+
/**
|
|
9
|
+
* Gets the battery level of the device as a number between `0` and `1`, inclusive. If the
|
|
10
|
+
* device does not support retrieving the battery level, this method returns `-1`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getBatteryLevelAsync(): Promise<number>;
|
|
13
|
+
/** Tells the battery's current state. */
|
|
14
|
+
export declare function getBatteryStateAsync(): Promise<BatteryState>;
|
|
15
|
+
/**
|
|
16
|
+
* Gets the current status of Power Saver mode on Android and Low Power mode on iOS. If a
|
|
17
|
+
* platform doesn't support low-power-mode reporting, this always resolves `false`, even if the
|
|
18
|
+
* device is actually in low-power mode.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isLowPowerModeEnabledAsync(): Promise<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* Checks whether battery optimization is enabled for this app. If enabled, background tasks
|
|
23
|
+
* might be affected when the app goes into doze mode state.
|
|
24
|
+
* @platform android
|
|
25
|
+
*/
|
|
26
|
+
export declare function isBatteryOptimizationEnabledAsync(): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Gets the power state of the device: battery level, whether it is plugged in, and whether the
|
|
29
|
+
* system is currently in Power Saver Mode (Android) / Low Power Mode (iOS).
|
|
30
|
+
*/
|
|
31
|
+
export declare function getPowerStateAsync(): Promise<PowerState>;
|
|
32
|
+
/**
|
|
33
|
+
* Subscribe to battery level change updates. On Android this only fires on significant changes
|
|
34
|
+
* (crossing the low/okay battery thresholds); on iOS it fires per one-percent drop, at most once
|
|
35
|
+
* a minute.
|
|
36
|
+
*/
|
|
37
|
+
export declare function addBatteryLevelListener(listener: (event: BatteryLevelEvent) => void): EventSubscription;
|
|
38
|
+
/** Subscribe to battery state (charging/full/unplugged/unknown) change updates. */
|
|
39
|
+
export declare function addBatteryStateListener(listener: (event: BatteryStateEvent) => void): EventSubscription;
|
|
40
|
+
/**
|
|
41
|
+
* Subscribe to Power Saver Mode (Android) / Low Power Mode (iOS) updates. Fires whenever the
|
|
42
|
+
* power mode is toggled.
|
|
43
|
+
*/
|
|
44
|
+
export declare function addLowPowerModeListener(listener: (event: PowerModeEvent) => void): EventSubscription;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { expoBattery } from './native-module.js';
|
|
2
|
+
import { BatteryState, } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves with whether the battery API is available on the current device. `true` on Android
|
|
5
|
+
* and physical iOS devices, `false` on iOS simulators.
|
|
6
|
+
*/
|
|
7
|
+
export async function isAvailableAsync() {
|
|
8
|
+
return Promise.resolve((expoBattery && expoBattery.isSupported) || false);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Gets the battery level of the device as a number between `0` and `1`, inclusive. If the
|
|
12
|
+
* device does not support retrieving the battery level, this method returns `-1`.
|
|
13
|
+
*/
|
|
14
|
+
export async function getBatteryLevelAsync() {
|
|
15
|
+
if (!expoBattery.getBatteryLevelAsync) {
|
|
16
|
+
return -1;
|
|
17
|
+
}
|
|
18
|
+
return expoBattery.getBatteryLevelAsync();
|
|
19
|
+
}
|
|
20
|
+
/** Tells the battery's current state. */
|
|
21
|
+
export async function getBatteryStateAsync() {
|
|
22
|
+
if (!expoBattery.getBatteryStateAsync) {
|
|
23
|
+
return BatteryState.UNKNOWN;
|
|
24
|
+
}
|
|
25
|
+
return expoBattery.getBatteryStateAsync();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Gets the current status of Power Saver mode on Android and Low Power mode on iOS. If a
|
|
29
|
+
* platform doesn't support low-power-mode reporting, this always resolves `false`, even if the
|
|
30
|
+
* device is actually in low-power mode.
|
|
31
|
+
*/
|
|
32
|
+
export async function isLowPowerModeEnabledAsync() {
|
|
33
|
+
if (!expoBattery.isLowPowerModeEnabledAsync) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return expoBattery.isLowPowerModeEnabledAsync();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Checks whether battery optimization is enabled for this app. If enabled, background tasks
|
|
40
|
+
* might be affected when the app goes into doze mode state.
|
|
41
|
+
* @platform android
|
|
42
|
+
*/
|
|
43
|
+
export async function isBatteryOptimizationEnabledAsync() {
|
|
44
|
+
if (!expoBattery.isBatteryOptimizationEnabledAsync) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return expoBattery.isBatteryOptimizationEnabledAsync();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Gets the power state of the device: battery level, whether it is plugged in, and whether the
|
|
51
|
+
* system is currently in Power Saver Mode (Android) / Low Power Mode (iOS).
|
|
52
|
+
*/
|
|
53
|
+
export async function getPowerStateAsync() {
|
|
54
|
+
const [batteryLevel, batteryState, lowPowerMode] = await Promise.all([
|
|
55
|
+
getBatteryLevelAsync(),
|
|
56
|
+
getBatteryStateAsync(),
|
|
57
|
+
isLowPowerModeEnabledAsync(),
|
|
58
|
+
]);
|
|
59
|
+
return { batteryLevel, batteryState, lowPowerMode };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Subscribe to battery level change updates. On Android this only fires on significant changes
|
|
63
|
+
* (crossing the low/okay battery thresholds); on iOS it fires per one-percent drop, at most once
|
|
64
|
+
* a minute.
|
|
65
|
+
*/
|
|
66
|
+
export function addBatteryLevelListener(listener) {
|
|
67
|
+
return expoBattery.addListener('Expo.batteryLevelDidChange', listener);
|
|
68
|
+
}
|
|
69
|
+
/** Subscribe to battery state (charging/full/unplugged/unknown) change updates. */
|
|
70
|
+
export function addBatteryStateListener(listener) {
|
|
71
|
+
return expoBattery.addListener('Expo.batteryStateDidChange', listener);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Subscribe to Power Saver Mode (Android) / Low Power Mode (iOS) updates. Fires whenever the
|
|
75
|
+
* power mode is toggled.
|
|
76
|
+
*/
|
|
77
|
+
export function addLowPowerModeListener(listener) {
|
|
78
|
+
return expoBattery.addListener('Expo.powerModeDidChange', listener);
|
|
79
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { isAvailableAsync, getBatteryLevelAsync, getBatteryStateAsync, isLowPowerModeEnabledAsync, isBatteryOptimizationEnabledAsync, getPowerStateAsync, addBatteryLevelListener, addBatteryStateListener, addLowPowerModeListener, } from './battery';
|
|
2
|
+
export { BatteryState, type PowerState, type BatteryLevelEvent, type BatteryStateEvent, type PowerModeEvent, } from './types';
|
|
3
|
+
export type { EventSubscription } from 'expo-modules-core';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { isAvailableAsync, getBatteryLevelAsync, getBatteryStateAsync, isLowPowerModeEnabledAsync, isBatteryOptimizationEnabledAsync, getPowerStateAsync, addBatteryLevelListener, addBatteryStateListener, addLowPowerModeListener, } from './battery.js';
|
|
2
|
+
export { BatteryState, } from './types.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EventSubscription } from 'expo-modules-core';
|
|
2
|
+
import type { BatteryLevelEvent, BatteryState, BatteryStateEvent, PowerModeEvent } from './types';
|
|
3
|
+
export type INativeBatteryModule = {
|
|
4
|
+
isSupported?: boolean;
|
|
5
|
+
getBatteryLevelAsync?(): Promise<number>;
|
|
6
|
+
getBatteryStateAsync?(): Promise<BatteryState>;
|
|
7
|
+
isLowPowerModeEnabledAsync?(): Promise<boolean>;
|
|
8
|
+
isBatteryOptimizationEnabledAsync?(): Promise<boolean>;
|
|
9
|
+
addListener(eventName: 'Expo.batteryLevelDidChange', listener: (event: BatteryLevelEvent) => void): EventSubscription;
|
|
10
|
+
addListener(eventName: 'Expo.batteryStateDidChange', listener: (event: BatteryStateEvent) => void): EventSubscription;
|
|
11
|
+
addListener(eventName: 'Expo.powerModeDidChange', listener: (event: PowerModeEvent) => void): EventSubscription;
|
|
12
|
+
};
|
|
13
|
+
export declare const expoBattery: INativeBatteryModule;
|