UNPKG

expo-location

Version:

Allows reading geolocation information from the device. Your app can poll for the current location or subscribe to location update events.

109 lines (92 loc) 2.91 kB
import { type EventSubscription } from 'expo-modules-core'; import ExpoLocation from './ExpoLocation'; import { LocationCallback, LocationErrorCallback, LocationHeadingCallback } from './Location.types'; import { LocationEventEmitter } from './LocationEventEmitter'; type EventObject = { watchId: number; [key: string]: any; }; let nextWatchId = 0; class Subscriber< CallbackType extends LocationCallback | LocationHeadingCallback | LocationErrorCallback, > { private eventName: string; private eventDataField: string; private callbacks: { [id: string]: CallbackType } = {}; private eventSubscription: EventSubscription | null = null; constructor(eventName: string, eventDataField: string) { this.eventName = eventName; this.eventDataField = eventDataField; } maybeInitializeSubscription() { if (this.eventSubscription) { return; } this.eventSubscription = LocationEventEmitter.addListener( this.eventName, (event: EventObject) => this.trigger(event) ); } /** * Registers given callback under new id which is then returned. */ registerCallback(callback: CallbackType): number { this.maybeInitializeSubscription(); const id = ++nextWatchId; this.callbacks[id] = callback; return id; } /** * Registers given callback under and existing id. This can be used to * create a subscriber for the error event on the same id as the location * event is subscribed to. */ registerCallbackForId(watchId: number, callback: CallbackType): number { this.maybeInitializeSubscription(); const id = watchId; this.callbacks[id] = callback; return id; } /** * Unregisters a callback with given id and revokes the subscription if possible. */ unregisterCallback(id: number): void { // Do nothing if we have already unregistered the callback. if (!this.callbacks[id]) { return; } delete this.callbacks[id]; ExpoLocation.removeWatchAsync(id); if (Object.keys(this.callbacks).length === 0 && this.eventSubscription) { LocationEventEmitter.removeSubscription(this.eventSubscription); this.eventSubscription = null; } } trigger(event: EventObject): void { const watchId = event.watchId; const callback = this.callbacks[watchId]; if (callback) { callback(event[this.eventDataField]); } else { ExpoLocation.removeWatchAsync(watchId); } } } export const LocationSubscriber = new Subscriber<LocationCallback>( 'Expo.locationChanged', 'location' ); export const HeadingSubscriber = new Subscriber<LocationHeadingCallback>( 'Expo.headingChanged', 'heading' ); export const LocationErrorSubscriber = new Subscriber<LocationErrorCallback>( 'Expo.locationError', 'reason' ); /** * @private Necessary for some unit tests. */ export function _getCurrentWatchId(): number { return nextWatchId; }