UNPKG

one

Version:

One is a React framework for web, iOS, and Android apps.

215 lines (198 loc) • 5.59 kB
import { useEffect, useState } from 'react' import { NitroModules } from 'react-native-nitro-modules' import { rethrowNativeError } from '../nativeError' import type { OneBattery } from '../specs/OneBattery.nitro' import type { BatteryLevelEvent, BatteryPowerModeEvent, BatteryPowerState, BatteryState, BatteryStateEvent, BatterySubscription, } from './types' import { assertLevelListener, assertLowPowerModeListener, assertStateListener, } from './validate' export type { BatteryLevelEvent, BatteryPowerModeEvent, BatteryPowerState, BatteryState, BatteryStateEvent, BatterySubscription, } from './types' // battery level, state and low power mode matching expo-battery, backed by // the OneBattery nitro hybrid object (created on first use and cached). // the first listener starts the native monitor, so the first event can // never race the subscription. let hybrid: OneBattery | undefined function native(): OneBattery { hybrid ??= NitroModules.createHybridObject<OneBattery>('OneBattery') return hybrid } function getLevel(): Promise<number> { return native().getLevel().catch(rethrowNativeError) } function getState(): Promise<BatteryState> { return native().getState().catch(rethrowNativeError) } function getPowerState(): Promise<BatteryPowerState> { return native().getPowerState().catch(rethrowNativeError) } function isLowPowerModeEnabled(): Promise<boolean> { return native().isLowPowerModeEnabled().catch(rethrowNativeError) } function isAvailable(): boolean { return native().isAvailable() } function addLevelListener( listener: (event: BatteryLevelEvent) => void ): BatterySubscription { assertLevelListener(listener) const remove = native().addLevelListener(listener) return { remove: () => remove() } } function addStateListener( listener: (event: BatteryStateEvent) => void ): BatterySubscription { assertStateListener(listener) const remove = native().addStateListener(listener) return { remove: () => remove() } } function addLowPowerModeListener( listener: (event: BatteryPowerModeEvent) => void ): BatterySubscription { assertLowPowerModeListener(listener) const remove = native().addLowPowerModeListener(listener) return { remove: () => remove() } } function useBatteryLevel(): number { const [level, setLevel] = useState(-1) useEffect(() => { let active = true let fromEvent = false getLevel() .then((next) => { if (active && !fromEvent) setLevel(next) }) .catch(() => {}) const subscription = addLevelListener((event) => { if (active) { fromEvent = true setLevel(event.batteryLevel) } }) return () => { active = false subscription.remove() } }, []) return level } function useBatteryState(): BatteryState { const [state, setState] = useState<BatteryState>('unknown') useEffect(() => { let active = true let fromEvent = false getState() .then((next) => { if (active && !fromEvent) setState(next) }) .catch(() => {}) const subscription = addStateListener((event) => { if (active) { fromEvent = true setState(event.batteryState) } }) return () => { active = false subscription.remove() } }, []) return state } function useLowPowerMode(): boolean { const [enabled, setEnabled] = useState(false) useEffect(() => { let active = true let fromEvent = false isLowPowerModeEnabled() .then((next) => { if (active && !fromEvent) setEnabled(next) }) .catch(() => {}) const subscription = addLowPowerModeListener((event) => { if (active) { fromEvent = true setEnabled(event.lowPowerMode) } }) return () => { active = false subscription.remove() } }, []) return enabled } function usePowerState(): BatteryPowerState { const [power, setPower] = useState<BatteryPowerState>({ batteryLevel: -1, batteryState: 'unknown', lowPowerMode: false, }) useEffect(() => { let active = true let levelFromEvent = false let stateFromEvent = false let modeFromEvent = false getPowerState() .then((next) => { if (!active) return setPower((current) => ({ batteryLevel: levelFromEvent ? current.batteryLevel : next.batteryLevel, batteryState: stateFromEvent ? current.batteryState : next.batteryState, lowPowerMode: modeFromEvent ? current.lowPowerMode : next.lowPowerMode, })) }) .catch(() => {}) const onLevel = addLevelListener((event) => { if (active) { levelFromEvent = true setPower((current) => ({ ...current, batteryLevel: event.batteryLevel })) } }) const onState = addStateListener((event) => { if (active) { stateFromEvent = true setPower((current) => ({ ...current, batteryState: event.batteryState })) } }) const onMode = addLowPowerModeListener((event) => { if (active) { modeFromEvent = true setPower((current) => ({ ...current, lowPowerMode: event.lowPowerMode })) } }) return () => { active = false onLevel.remove() onState.remove() onMode.remove() } }, []) return power } export const Battery = Object.freeze({ getLevel, getState, getPowerState, isLowPowerModeEnabled, isAvailable, addLevelListener, addStateListener, addLowPowerModeListener, }) export { useBatteryLevel, useBatteryState, useLowPowerMode, usePowerState }