BigBrainParking/app/src/features/location/useLocation.ts
Hank 1dede50995 Initial commit: parksmarter-client + BigBrainParking app
Reverse-engineered ParkSmarter API client (TypeScript, live-verified) plus a
de-Googled Expo/React Native app for GrapheneOS: MapLibre meter map with GPS,
VisionCamera QR kiosk scanning with save/share, local session-expiry reminders,
UnifiedPush wiring, and Gitea CI to publish signed APKs for Obtainium.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 08:33:47 -07:00

63 lines
2 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react';
import * as Location from 'expo-location';
import AsyncStorage from '@react-native-async-storage/async-storage';
export interface Coords {
latitude: number;
longitude: number;
}
const LAST_LOC_KEY = 'ps_last_location';
/** Persist the most recent fix so the "near my last location" button works cold. */
async function saveLastLocation(c: Coords) {
await AsyncStorage.setItem(LAST_LOC_KEY, JSON.stringify(c));
}
export async function getLastKnownSavedLocation(): Promise<Coords | null> {
const raw = await AsyncStorage.getItem(LAST_LOC_KEY);
return raw ? (JSON.parse(raw) as Coords) : null;
}
/**
* Foreground location. On GrapheneOS this uses the OS location provider directly
* (no Google Play Services). We prefer a fast last-known fix, then refine.
*/
export function useLocation() {
const [coords, setCoords] = useState<Coords | null>(null);
const [granted, setGranted] = useState<boolean | null>(null);
const [error, setError] = useState<string | null>(null);
const refresh = useCallback(async () => {
try {
const { status } = await Location.requestForegroundPermissionsAsync();
const ok = status === 'granted';
setGranted(ok);
if (!ok) {
setError('Location permission denied.');
return null;
}
const last = await Location.getLastKnownPositionAsync();
if (last) {
const c = { latitude: last.coords.latitude, longitude: last.coords.longitude };
setCoords(c);
void saveLastLocation(c);
}
const cur = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.Balanced,
});
const c = { latitude: cur.coords.latitude, longitude: cur.coords.longitude };
setCoords(c);
void saveLastLocation(c);
return c;
} catch (e: any) {
setError(e?.message ?? 'Failed to get location.');
return null;
}
}, []);
useEffect(() => {
void refresh();
}, [refresh]);
return { coords, granted, error, refresh };
}