@symbiote-native/battery 0.0.1 → 0.1.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/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 +92 -1
- package/src/angular/index.ts +24 -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 +26 -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 +26 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Hand-ported from .vendors/expo/packages/expo-battery/src/Battery.types.ts (sdk-57) — plain
|
|
2
|
+
// data shapes, no `expo` meta-package import to swap out (unlike local-auth's types.ts).
|
|
3
|
+
export var BatteryState;
|
|
4
|
+
(function (BatteryState) {
|
|
5
|
+
/** If the battery state is unknown or inaccessible. */
|
|
6
|
+
BatteryState[BatteryState["UNKNOWN"] = 0] = "UNKNOWN";
|
|
7
|
+
/**
|
|
8
|
+
* If the battery is discharging (typically not connected to power). On Android, this
|
|
9
|
+
* corresponds to `BATTERY_STATUS_DISCHARGING`.
|
|
10
|
+
*/
|
|
11
|
+
BatteryState[BatteryState["UNPLUGGED"] = 1] = "UNPLUGGED";
|
|
12
|
+
/** If battery is charging. */
|
|
13
|
+
BatteryState[BatteryState["CHARGING"] = 2] = "CHARGING";
|
|
14
|
+
/** If the battery level is full. */
|
|
15
|
+
BatteryState[BatteryState["FULL"] = 3] = "FULL";
|
|
16
|
+
/**
|
|
17
|
+
* The battery is not charging while power is connected (AC/USB/wireless), for example when
|
|
18
|
+
* battery protection limits charge to 80%, or optimized charging pauses. This differs from
|
|
19
|
+
* `UNPLUGGED` (discharging on battery).
|
|
20
|
+
* @platform android
|
|
21
|
+
*/
|
|
22
|
+
BatteryState[BatteryState["NOT_CHARGING"] = 4] = "NOT_CHARGING";
|
|
23
|
+
})(BatteryState || (BatteryState = {}));
|
|
24
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,yFAAyF;AAWzF,MAAM,CAAN,IAAY,YAmBX;AAnBD,WAAY,YAAY;IACtB,uDAAuD;IACvD,qDAAW,CAAA;IACX;;;OAGG;IACH,yDAAS,CAAA;IACT,8BAA8B;IAC9B,uDAAQ,CAAA;IACR,oCAAoC;IACpC,+CAAI,CAAA;IACJ;;;;;OAKG;IACH,+DAAY,CAAA;AACd,CAAC,EAnBW,YAAY,KAAZ,YAAY,QAmBvB"}
|
package/native-link.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/battery",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "expo-battery wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, 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": {
|
|
@@ -13,7 +13,98 @@
|
|
|
13
13
|
"url": "https://github.com/OneEyed1366/symbiote-native/issues"
|
|
14
14
|
},
|
|
15
15
|
"author": "Andrey Prokopenko <psevdoproger@gmail.com>",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./build/core/index.js",
|
|
18
|
+
"module": "./build/core/index.js",
|
|
19
|
+
"types": "./build/core/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./build/core/index.d.ts",
|
|
23
|
+
"default": "./build/core/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./vue": {
|
|
26
|
+
"types": "./build/vue/index.d.ts",
|
|
27
|
+
"default": "./build/vue/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./react": {
|
|
30
|
+
"types": "./build/react/index.d.ts",
|
|
31
|
+
"default": "./build/react/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./angular": {
|
|
34
|
+
"types": "./build-ngc/angular/index.d.ts",
|
|
35
|
+
"react-native": "./build-ngc/angular/index.js",
|
|
36
|
+
"default": "./src/angular/index.ts"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"src",
|
|
41
|
+
"build",
|
|
42
|
+
"build-ngc",
|
|
43
|
+
"native-link.json",
|
|
44
|
+
"!src/**/*.test.*",
|
|
45
|
+
"!src/**/*.spec.*",
|
|
46
|
+
"!src/**/*.detox.*"
|
|
47
|
+
],
|
|
16
48
|
"publishConfig": {
|
|
17
49
|
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"expo-battery": "57.0.1",
|
|
53
|
+
"expo-modules-core": "57.0.5"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@symbiote-native/engine": ">=0.1.7",
|
|
57
|
+
"@angular/core": ">=20",
|
|
58
|
+
"@vue/runtime-core": "^3.5.13",
|
|
59
|
+
"react": ">=19.0.0",
|
|
60
|
+
"react-native": ">=0.86",
|
|
61
|
+
"vue": ">=3.5.0",
|
|
62
|
+
"@symbiote-native/angular": "0.6.2",
|
|
63
|
+
"@symbiote-native/react": "0.2.8",
|
|
64
|
+
"@symbiote-native/vue": "0.3.8"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"@symbiote-native/angular": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"@symbiote-native/react": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"@symbiote-native/vue": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"@angular/core": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"@vue/runtime-core": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"react": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"vue": {
|
|
86
|
+
"optional": true
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@angular/compiler": "^22",
|
|
91
|
+
"@angular/compiler-cli": "^22",
|
|
92
|
+
"@angular/core": "^22",
|
|
93
|
+
"@types/node": "^26.0.0",
|
|
94
|
+
"@types/react": "^19.2.0",
|
|
95
|
+
"@vue/runtime-core": "^3.5.13",
|
|
96
|
+
"react": "19.2.3",
|
|
97
|
+
"typescript": "~6.0.0",
|
|
98
|
+
"@symbiote-native/angular": "0.6.2",
|
|
99
|
+
"@symbiote-native/engine": "0.1.7",
|
|
100
|
+
"@symbiote-native/react": "0.2.8",
|
|
101
|
+
"@symbiote-native/test-utils": "0.1.6",
|
|
102
|
+
"@symbiote-native/vue": "0.3.8"
|
|
103
|
+
},
|
|
104
|
+
"scripts": {
|
|
105
|
+
"typecheck": "tsc --build",
|
|
106
|
+
"clean": "rm -rf build-ngc",
|
|
107
|
+
"ng:build": "pnpm run clean && ngc -p tsconfig.angular.json",
|
|
108
|
+
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
18
109
|
}
|
|
19
110
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
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';
|
|
6
|
+
export { BatteryStateService } from './services/battery-state.service';
|
|
7
|
+
export { LowPowerModeService } from './services/low-power-mode.service';
|
|
8
|
+
export {
|
|
9
|
+
isAvailableAsync,
|
|
10
|
+
getBatteryLevelAsync,
|
|
11
|
+
getBatteryStateAsync,
|
|
12
|
+
isLowPowerModeEnabledAsync,
|
|
13
|
+
isBatteryOptimizationEnabledAsync,
|
|
14
|
+
getPowerStateAsync,
|
|
15
|
+
addBatteryLevelListener,
|
|
16
|
+
addBatteryStateListener,
|
|
17
|
+
addLowPowerModeListener,
|
|
18
|
+
BatteryState,
|
|
19
|
+
type PowerState,
|
|
20
|
+
type BatteryLevelEvent,
|
|
21
|
+
type BatteryStateEvent,
|
|
22
|
+
type PowerModeEvent,
|
|
23
|
+
type EventSubscription,
|
|
24
|
+
} from '../core';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { effect, inject, Injectable, Injector, signal, type Signal } from '@angular/core';
|
|
2
|
+
import { addBatteryLevelListener, getBatteryLevelAsync } from '../../../core';
|
|
3
|
+
|
|
4
|
+
// Angular twin of React's `useBatteryLevel` hook and Vue's `useBatteryLevel` composable.
|
|
5
|
+
// Angular has no per-instance hook — state and lifecycle live in DI instead, so `connect()`
|
|
6
|
+
// stands in for the hook's role: call it ONCE (typically from a component's field initializer,
|
|
7
|
+
// inside an injection context).
|
|
8
|
+
//
|
|
9
|
+
// readonly batteryLevel = inject(BatteryLevelService).connect();
|
|
10
|
+
// // template: {{ batteryLevel() }}
|
|
11
|
+
//
|
|
12
|
+
// Mirrors AccelerometerService.connect() — a single effect() that seeds the initial value with
|
|
13
|
+
// getBatteryLevelAsync(), subscribes once, and cleans up once.
|
|
14
|
+
@Injectable({ providedIn: 'root' })
|
|
15
|
+
export class BatteryLevelService {
|
|
16
|
+
private readonly injector = inject(Injector);
|
|
17
|
+
|
|
18
|
+
connect(): Signal<number> {
|
|
19
|
+
const batteryLevel = signal(-1);
|
|
20
|
+
|
|
21
|
+
effect(
|
|
22
|
+
onCleanup => {
|
|
23
|
+
getBatteryLevelAsync().then(level => batteryLevel.set(level));
|
|
24
|
+
const subscription = addBatteryLevelListener(event => batteryLevel.set(event.batteryLevel));
|
|
25
|
+
onCleanup(() => subscription.remove());
|
|
26
|
+
},
|
|
27
|
+
{ injector: this.injector },
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
return batteryLevel.asReadonly();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { effect, inject, Injectable, Injector, signal, type Signal } from '@angular/core';
|
|
2
|
+
import { addBatteryStateListener, BatteryState, getBatteryStateAsync } from '../../../core';
|
|
3
|
+
|
|
4
|
+
// Angular twin of React's `useBatteryState` hook and Vue's `useBatteryState` composable. See
|
|
5
|
+
// BatteryLevelService for the `connect()` pattern rationale.
|
|
6
|
+
//
|
|
7
|
+
// readonly batteryState = inject(BatteryStateService).connect();
|
|
8
|
+
// // template: {{ batteryState() }}
|
|
9
|
+
@Injectable({ providedIn: 'root' })
|
|
10
|
+
export class BatteryStateService {
|
|
11
|
+
private readonly injector = inject(Injector);
|
|
12
|
+
|
|
13
|
+
connect(): Signal<BatteryState> {
|
|
14
|
+
const batteryState = signal<BatteryState>(BatteryState.UNKNOWN);
|
|
15
|
+
|
|
16
|
+
effect(
|
|
17
|
+
onCleanup => {
|
|
18
|
+
getBatteryStateAsync().then(state => batteryState.set(state));
|
|
19
|
+
const subscription = addBatteryStateListener(event => batteryState.set(event.batteryState));
|
|
20
|
+
onCleanup(() => subscription.remove());
|
|
21
|
+
},
|
|
22
|
+
{ injector: this.injector },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return batteryState.asReadonly();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { effect, inject, Injectable, Injector, signal, type Signal } from '@angular/core';
|
|
2
|
+
import { addLowPowerModeListener, isLowPowerModeEnabledAsync } from '../../../core';
|
|
3
|
+
|
|
4
|
+
// Angular twin of React's `useLowPowerMode` hook and Vue's `useLowPowerMode` composable. See
|
|
5
|
+
// BatteryLevelService for the `connect()` pattern rationale.
|
|
6
|
+
//
|
|
7
|
+
// readonly lowPowerMode = inject(LowPowerModeService).connect();
|
|
8
|
+
// // template: {{ lowPowerMode() }}
|
|
9
|
+
@Injectable({ providedIn: 'root' })
|
|
10
|
+
export class LowPowerModeService {
|
|
11
|
+
private readonly injector = inject(Injector);
|
|
12
|
+
|
|
13
|
+
connect(): Signal<boolean> {
|
|
14
|
+
const lowPowerMode = signal(false);
|
|
15
|
+
|
|
16
|
+
effect(
|
|
17
|
+
onCleanup => {
|
|
18
|
+
isLowPowerModeEnabledAsync().then(enabled => lowPowerMode.set(enabled));
|
|
19
|
+
const subscription = addLowPowerModeListener(event => lowPowerMode.set(event.lowPowerMode));
|
|
20
|
+
onCleanup(() => subscription.remove());
|
|
21
|
+
},
|
|
22
|
+
{ injector: this.injector },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return lowPowerMode.asReadonly();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Hand-ported from .vendors/expo/packages/expo-battery/src/Battery.ts (sdk-57). Unlike
|
|
2
|
+
// local-auth/pedometer, upstream Battery never throws UnavailabilityError — every function
|
|
3
|
+
// falls back to a documented sentinel (-1 / BatteryState.UNKNOWN / false) when the native
|
|
4
|
+
// method is absent, so that fallback shape is preserved here verbatim rather than guessed.
|
|
5
|
+
import type { EventSubscription } from 'expo-modules-core';
|
|
6
|
+
import { expoBattery } from './native-module';
|
|
7
|
+
import {
|
|
8
|
+
BatteryState,
|
|
9
|
+
type BatteryLevelEvent,
|
|
10
|
+
type BatteryStateEvent,
|
|
11
|
+
type PowerModeEvent,
|
|
12
|
+
type PowerState,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolves with whether the battery API is available on the current device. `true` on Android
|
|
17
|
+
* and physical iOS devices, `false` on iOS simulators.
|
|
18
|
+
*/
|
|
19
|
+
export async function isAvailableAsync(): Promise<boolean> {
|
|
20
|
+
return Promise.resolve((expoBattery && expoBattery.isSupported) || false);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Gets the battery level of the device as a number between `0` and `1`, inclusive. If the
|
|
25
|
+
* device does not support retrieving the battery level, this method returns `-1`.
|
|
26
|
+
*/
|
|
27
|
+
export async function getBatteryLevelAsync(): Promise<number> {
|
|
28
|
+
if (!expoBattery.getBatteryLevelAsync) {
|
|
29
|
+
return -1;
|
|
30
|
+
}
|
|
31
|
+
return expoBattery.getBatteryLevelAsync();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Tells the battery's current state. */
|
|
35
|
+
export async function getBatteryStateAsync(): Promise<BatteryState> {
|
|
36
|
+
if (!expoBattery.getBatteryStateAsync) {
|
|
37
|
+
return BatteryState.UNKNOWN;
|
|
38
|
+
}
|
|
39
|
+
return expoBattery.getBatteryStateAsync();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Gets the current status of Power Saver mode on Android and Low Power mode on iOS. If a
|
|
44
|
+
* platform doesn't support low-power-mode reporting, this always resolves `false`, even if the
|
|
45
|
+
* device is actually in low-power mode.
|
|
46
|
+
*/
|
|
47
|
+
export async function isLowPowerModeEnabledAsync(): Promise<boolean> {
|
|
48
|
+
if (!expoBattery.isLowPowerModeEnabledAsync) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return expoBattery.isLowPowerModeEnabledAsync();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Checks whether battery optimization is enabled for this app. If enabled, background tasks
|
|
56
|
+
* might be affected when the app goes into doze mode state.
|
|
57
|
+
* @platform android
|
|
58
|
+
*/
|
|
59
|
+
export async function isBatteryOptimizationEnabledAsync(): Promise<boolean> {
|
|
60
|
+
if (!expoBattery.isBatteryOptimizationEnabledAsync) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return expoBattery.isBatteryOptimizationEnabledAsync();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gets the power state of the device: battery level, whether it is plugged in, and whether the
|
|
68
|
+
* system is currently in Power Saver Mode (Android) / Low Power Mode (iOS).
|
|
69
|
+
*/
|
|
70
|
+
export async function getPowerStateAsync(): Promise<PowerState> {
|
|
71
|
+
const [batteryLevel, batteryState, lowPowerMode] = await Promise.all([
|
|
72
|
+
getBatteryLevelAsync(),
|
|
73
|
+
getBatteryStateAsync(),
|
|
74
|
+
isLowPowerModeEnabledAsync(),
|
|
75
|
+
]);
|
|
76
|
+
return { batteryLevel, batteryState, lowPowerMode };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe to battery level change updates. On Android this only fires on significant changes
|
|
81
|
+
* (crossing the low/okay battery thresholds); on iOS it fires per one-percent drop, at most once
|
|
82
|
+
* a minute.
|
|
83
|
+
*/
|
|
84
|
+
export function addBatteryLevelListener(
|
|
85
|
+
listener: (event: BatteryLevelEvent) => void,
|
|
86
|
+
): EventSubscription {
|
|
87
|
+
return expoBattery.addListener('Expo.batteryLevelDidChange', listener);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Subscribe to battery state (charging/full/unplugged/unknown) change updates. */
|
|
91
|
+
export function addBatteryStateListener(
|
|
92
|
+
listener: (event: BatteryStateEvent) => void,
|
|
93
|
+
): EventSubscription {
|
|
94
|
+
return expoBattery.addListener('Expo.batteryStateDidChange', listener);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Subscribe to Power Saver Mode (Android) / Low Power Mode (iOS) updates. Fires whenever the
|
|
99
|
+
* power mode is toggled.
|
|
100
|
+
*/
|
|
101
|
+
export function addLowPowerModeListener(
|
|
102
|
+
listener: (event: PowerModeEvent) => void,
|
|
103
|
+
): EventSubscription {
|
|
104
|
+
return expoBattery.addListener('Expo.powerModeDidChange', listener);
|
|
105
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export {
|
|
2
|
+
isAvailableAsync,
|
|
3
|
+
getBatteryLevelAsync,
|
|
4
|
+
getBatteryStateAsync,
|
|
5
|
+
isLowPowerModeEnabledAsync,
|
|
6
|
+
isBatteryOptimizationEnabledAsync,
|
|
7
|
+
getPowerStateAsync,
|
|
8
|
+
addBatteryLevelListener,
|
|
9
|
+
addBatteryStateListener,
|
|
10
|
+
addLowPowerModeListener,
|
|
11
|
+
} from './battery';
|
|
12
|
+
export {
|
|
13
|
+
BatteryState,
|
|
14
|
+
type PowerState,
|
|
15
|
+
type BatteryLevelEvent,
|
|
16
|
+
type BatteryStateEvent,
|
|
17
|
+
type PowerModeEvent,
|
|
18
|
+
} from './types';
|
|
19
|
+
export type { EventSubscription } from 'expo-modules-core';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { requireNativeModule } from 'expo-modules-core';
|
|
2
|
+
import type { EventSubscription } from 'expo-modules-core';
|
|
3
|
+
import type { BatteryLevelEvent, BatteryState, BatteryStateEvent, PowerModeEvent } from './types';
|
|
4
|
+
|
|
5
|
+
const EXPO_BATTERY_MODULE_NAME = 'ExpoBattery';
|
|
6
|
+
|
|
7
|
+
// Upstream's own event names, verified against .vendors/expo/packages/expo-battery/src/Battery.ts
|
|
8
|
+
// (sdk-57) — a single native module fans out three distinct event shapes through one
|
|
9
|
+
// `addListener`, so the overloads below key the payload type off the literal event name, the
|
|
10
|
+
// same trick TypeScript uses for DOM's `addEventListener`.
|
|
11
|
+
export type INativeBatteryModule = {
|
|
12
|
+
isSupported?: boolean;
|
|
13
|
+
getBatteryLevelAsync?(): Promise<number>;
|
|
14
|
+
getBatteryStateAsync?(): Promise<BatteryState>;
|
|
15
|
+
isLowPowerModeEnabledAsync?(): Promise<boolean>;
|
|
16
|
+
isBatteryOptimizationEnabledAsync?(): Promise<boolean>;
|
|
17
|
+
addListener(
|
|
18
|
+
eventName: 'Expo.batteryLevelDidChange',
|
|
19
|
+
listener: (event: BatteryLevelEvent) => void,
|
|
20
|
+
): EventSubscription;
|
|
21
|
+
addListener(
|
|
22
|
+
eventName: 'Expo.batteryStateDidChange',
|
|
23
|
+
listener: (event: BatteryStateEvent) => void,
|
|
24
|
+
): EventSubscription;
|
|
25
|
+
addListener(
|
|
26
|
+
eventName: 'Expo.powerModeDidChange',
|
|
27
|
+
listener: (event: PowerModeEvent) => void,
|
|
28
|
+
): EventSubscription;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const expoBattery = requireNativeModule<INativeBatteryModule>(EXPO_BATTERY_MODULE_NAME);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Hand-ported from .vendors/expo/packages/expo-battery/src/Battery.types.ts (sdk-57) — plain
|
|
2
|
+
// data shapes, no `expo` meta-package import to swap out (unlike local-auth's types.ts).
|
|
3
|
+
|
|
4
|
+
export type PowerState = {
|
|
5
|
+
/** A number between `0` and `1`, inclusive, or `-1` if the battery level is unknown. */
|
|
6
|
+
batteryLevel: number;
|
|
7
|
+
/** An enum value representing the battery state. */
|
|
8
|
+
batteryState: BatteryState;
|
|
9
|
+
/** `true` if lowPowerMode is on, `false` if lowPowerMode is off. */
|
|
10
|
+
lowPowerMode: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export enum BatteryState {
|
|
14
|
+
/** If the battery state is unknown or inaccessible. */
|
|
15
|
+
UNKNOWN = 0,
|
|
16
|
+
/**
|
|
17
|
+
* If the battery is discharging (typically not connected to power). On Android, this
|
|
18
|
+
* corresponds to `BATTERY_STATUS_DISCHARGING`.
|
|
19
|
+
*/
|
|
20
|
+
UNPLUGGED,
|
|
21
|
+
/** If battery is charging. */
|
|
22
|
+
CHARGING,
|
|
23
|
+
/** If the battery level is full. */
|
|
24
|
+
FULL,
|
|
25
|
+
/**
|
|
26
|
+
* The battery is not charging while power is connected (AC/USB/wireless), for example when
|
|
27
|
+
* battery protection limits charge to 80%, or optimized charging pauses. This differs from
|
|
28
|
+
* `UNPLUGGED` (discharging on battery).
|
|
29
|
+
* @platform android
|
|
30
|
+
*/
|
|
31
|
+
NOT_CHARGING,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type BatteryLevelEvent = {
|
|
35
|
+
/** A number between `0` and `1`, inclusive, or `-1` if the battery level is unknown. */
|
|
36
|
+
batteryLevel: number;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type BatteryStateEvent = {
|
|
40
|
+
/** An enum value representing the battery state. */
|
|
41
|
+
batteryState: BatteryState;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type PowerModeEvent = {
|
|
45
|
+
/** `true` if lowPowerMode is on, `false` if lowPowerMode is off. */
|
|
46
|
+
lowPowerMode: boolean;
|
|
47
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// React lifecycle wiring over the framework-agnostic core (core/battery.ts) — mirrors the
|
|
2
|
+
// lifecycle-bucket naming convention of adapters/react/src/hooks and the shape of
|
|
3
|
+
// packages/sensors/src/react/hooks/use-accelerometer. Seeds the initial value with a one-shot
|
|
4
|
+
// getBatteryLevelAsync() call before the first native event fires, matching upstream's own
|
|
5
|
+
// useBatteryLevel (.vendors/expo/packages/expo-battery/src/Battery.ts).
|
|
6
|
+
import { useEffect, useState } from 'react';
|
|
7
|
+
import { addBatteryLevelListener, getBatteryLevelAsync } from '../../../core';
|
|
8
|
+
|
|
9
|
+
export function useBatteryLevel(): number {
|
|
10
|
+
const [batteryLevel, setBatteryLevel] = useState(-1);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
getBatteryLevelAsync().then(setBatteryLevel);
|
|
14
|
+
const subscription = addBatteryLevelListener(event => setBatteryLevel(event.batteryLevel));
|
|
15
|
+
return () => subscription.remove();
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
return batteryLevel;
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// React lifecycle wiring over the framework-agnostic core (core/battery.ts) — mirrors
|
|
2
|
+
// use-battery-level's shape. Seeds the initial value with a one-shot getBatteryStateAsync()
|
|
3
|
+
// call before the first native event fires, matching upstream's own useBatteryState.
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
import { addBatteryStateListener, BatteryState, getBatteryStateAsync } from '../../../core';
|
|
6
|
+
|
|
7
|
+
export function useBatteryState(): BatteryState {
|
|
8
|
+
const [batteryState, setBatteryState] = useState<BatteryState>(BatteryState.UNKNOWN);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
getBatteryStateAsync().then(setBatteryState);
|
|
12
|
+
const subscription = addBatteryStateListener(event => setBatteryState(event.batteryState));
|
|
13
|
+
return () => subscription.remove();
|
|
14
|
+
}, []);
|
|
15
|
+
|
|
16
|
+
return batteryState;
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// React lifecycle wiring over the framework-agnostic core (core/battery.ts) — mirrors
|
|
2
|
+
// use-battery-level's shape. Seeds the initial value with a one-shot
|
|
3
|
+
// isLowPowerModeEnabledAsync() call before the first native event fires, matching upstream's
|
|
4
|
+
// own useLowPowerMode.
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
import { addLowPowerModeListener, isLowPowerModeEnabledAsync } from '../../../core';
|
|
7
|
+
|
|
8
|
+
export function useLowPowerMode(): boolean {
|
|
9
|
+
const [lowPowerMode, setLowPowerMode] = useState(false);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
isLowPowerModeEnabledAsync().then(setLowPowerMode);
|
|
13
|
+
const subscription = addLowPowerModeListener(event => setLowPowerMode(event.lowPowerMode));
|
|
14
|
+
return () => subscription.remove();
|
|
15
|
+
}, []);
|
|
16
|
+
|
|
17
|
+
return lowPowerMode;
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// @symbiote-native/battery/react: the React entry over the framework-agnostic core. Battery's
|
|
2
|
+
// three subscription-backed values (level/state/low-power-mode) each get their own lifecycle
|
|
3
|
+
// hook, matching upstream's own useBatteryLevel/useBatteryState/useLowPowerMode being three
|
|
4
|
+
// separate hooks, not one combined hook — mirrors the lifecycle-bucket naming convention of
|
|
5
|
+
// adapters/react/src/hooks (never `composables`, that's Vue's term).
|
|
6
|
+
|
|
7
|
+
export { useBatteryLevel } from './hooks/use-battery-level';
|
|
8
|
+
export { useBatteryState } from './hooks/use-battery-state';
|
|
9
|
+
export { useLowPowerMode } from './hooks/use-low-power-mode';
|
|
10
|
+
export {
|
|
11
|
+
isAvailableAsync,
|
|
12
|
+
getBatteryLevelAsync,
|
|
13
|
+
getBatteryStateAsync,
|
|
14
|
+
isLowPowerModeEnabledAsync,
|
|
15
|
+
isBatteryOptimizationEnabledAsync,
|
|
16
|
+
getPowerStateAsync,
|
|
17
|
+
addBatteryLevelListener,
|
|
18
|
+
addBatteryStateListener,
|
|
19
|
+
addLowPowerModeListener,
|
|
20
|
+
BatteryState,
|
|
21
|
+
type PowerState,
|
|
22
|
+
type BatteryLevelEvent,
|
|
23
|
+
type BatteryStateEvent,
|
|
24
|
+
type PowerModeEvent,
|
|
25
|
+
type EventSubscription,
|
|
26
|
+
} from '../core';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic core (core/battery.ts) — mirrors the
|
|
2
|
+
// lifecycle-bucket naming convention of adapters/vue/src/composables and the
|
|
3
|
+
// onMounted/onUnmounted shape of packages/sensors/src/vue/composables/use-accelerometer. Seeds
|
|
4
|
+
// the initial value with a one-shot getBatteryLevelAsync() call before the first native event
|
|
5
|
+
// fires, matching upstream's own useBatteryLevel.
|
|
6
|
+
|
|
7
|
+
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
8
|
+
import {
|
|
9
|
+
addBatteryLevelListener,
|
|
10
|
+
getBatteryLevelAsync,
|
|
11
|
+
type EventSubscription,
|
|
12
|
+
} from '../../../core';
|
|
13
|
+
|
|
14
|
+
export function useBatteryLevel(): Ref<number> {
|
|
15
|
+
const batteryLevel = ref(-1);
|
|
16
|
+
let subscription: EventSubscription | undefined;
|
|
17
|
+
|
|
18
|
+
onMounted(() => {
|
|
19
|
+
getBatteryLevelAsync().then(level => {
|
|
20
|
+
batteryLevel.value = level;
|
|
21
|
+
});
|
|
22
|
+
subscription = addBatteryLevelListener(event => {
|
|
23
|
+
batteryLevel.value = event.batteryLevel;
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
onUnmounted(() => {
|
|
28
|
+
subscription?.remove();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return batteryLevel;
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic core (core/battery.ts) — mirrors
|
|
2
|
+
// use-battery-level's shape. Seeds the initial value with a one-shot getBatteryStateAsync()
|
|
3
|
+
// call before the first native event fires, matching upstream's own useBatteryState.
|
|
4
|
+
|
|
5
|
+
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
6
|
+
import {
|
|
7
|
+
addBatteryStateListener,
|
|
8
|
+
BatteryState,
|
|
9
|
+
getBatteryStateAsync,
|
|
10
|
+
type EventSubscription,
|
|
11
|
+
} from '../../../core';
|
|
12
|
+
|
|
13
|
+
export function useBatteryState(): Ref<BatteryState> {
|
|
14
|
+
const batteryState = ref<BatteryState>(BatteryState.UNKNOWN);
|
|
15
|
+
let subscription: EventSubscription | undefined;
|
|
16
|
+
|
|
17
|
+
onMounted(() => {
|
|
18
|
+
getBatteryStateAsync().then(state => {
|
|
19
|
+
batteryState.value = state;
|
|
20
|
+
});
|
|
21
|
+
subscription = addBatteryStateListener(event => {
|
|
22
|
+
batteryState.value = event.batteryState;
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
onUnmounted(() => {
|
|
27
|
+
subscription?.remove();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return batteryState;
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Vue lifecycle wiring over the framework-agnostic core (core/battery.ts) — mirrors
|
|
2
|
+
// use-battery-level's shape. Seeds the initial value with a one-shot
|
|
3
|
+
// isLowPowerModeEnabledAsync() call before the first native event fires, matching upstream's
|
|
4
|
+
// own useLowPowerMode.
|
|
5
|
+
|
|
6
|
+
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
7
|
+
import {
|
|
8
|
+
addLowPowerModeListener,
|
|
9
|
+
isLowPowerModeEnabledAsync,
|
|
10
|
+
type EventSubscription,
|
|
11
|
+
} from '../../../core';
|
|
12
|
+
|
|
13
|
+
export function useLowPowerMode(): Ref<boolean> {
|
|
14
|
+
const lowPowerMode = ref(false);
|
|
15
|
+
let subscription: EventSubscription | undefined;
|
|
16
|
+
|
|
17
|
+
onMounted(() => {
|
|
18
|
+
isLowPowerModeEnabledAsync().then(enabled => {
|
|
19
|
+
lowPowerMode.value = enabled;
|
|
20
|
+
});
|
|
21
|
+
subscription = addLowPowerModeListener(event => {
|
|
22
|
+
lowPowerMode.value = event.lowPowerMode;
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
onUnmounted(() => {
|
|
27
|
+
subscription?.remove();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return lowPowerMode;
|
|
31
|
+
}
|