183 lines
5.4 KiB
TypeScript
183 lines
5.4 KiB
TypeScript
import { Platform, PermissionsAndroid, Alert, Linking } from 'react-native';
|
|
import Geolocation from 'react-native-geolocation-service';
|
|
import type { GeoPosition, GeoError } from 'react-native-geolocation-service';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Types
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export interface LatLng {
|
|
latitude: number;
|
|
longitude: number;
|
|
}
|
|
|
|
export interface LocationResult {
|
|
coords: LatLng;
|
|
address: string;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Constants
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const GOOGLE_MAPS_API_KEY = 'AIzaSyDKaKVyQCmSpHMXcMkNCccSXpILpuvwsVM';
|
|
|
|
/** Default region (Bengaluru) used as a fallback before the user's location loads. */
|
|
export const DEFAULT_LOCATION: LatLng = {
|
|
latitude: 12.9352,
|
|
longitude: 77.6245,
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Permission helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Request location permission from the user.
|
|
* Returns `true` if permission was granted, `false` otherwise.
|
|
*/
|
|
export const requestLocationPermission = async (): Promise<boolean> => {
|
|
if (Platform.OS === 'ios') {
|
|
try {
|
|
const result = await Geolocation.requestAuthorization('whenInUse');
|
|
return result === 'granted';
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Android
|
|
try {
|
|
const granted = await PermissionsAndroid.request(
|
|
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
|
|
{
|
|
title: 'Location Permission',
|
|
message: 'This app needs access to your location to set it on the map.',
|
|
buttonNeutral: 'Ask Me Later',
|
|
buttonNegative: 'Cancel',
|
|
buttonPositive: 'OK',
|
|
},
|
|
);
|
|
console.log('granted', granted);
|
|
return granted === PermissionsAndroid.RESULTS.GRANTED;
|
|
} catch {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Show an alert when the user denies location permission, with an option
|
|
* to open app settings.
|
|
*/
|
|
export const showPermissionDeniedAlert = (): void => {
|
|
Alert.alert(
|
|
'Location Permission Required',
|
|
'Please enable location permission in your device settings to use this feature.',
|
|
[
|
|
{ text: 'Cancel', style: 'cancel' },
|
|
{ text: 'Open Settings', onPress: () => Linking.openSettings() },
|
|
],
|
|
);
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Position helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Get the device's current GPS position.
|
|
* Wraps the callback-based Geolocation API in a Promise.
|
|
*/
|
|
export const getCurrentPosition = async (): Promise<LatLng> => {
|
|
try {
|
|
console.log('get current position');
|
|
console.log('Geolocation:', Geolocation);
|
|
console.log('getCurrentPosition:', Geolocation?.getCurrentPosition);
|
|
|
|
const location = await new Promise<LatLng>((resolve, reject) => {
|
|
Geolocation.getCurrentPosition(
|
|
(position: GeoPosition) => {
|
|
resolve({
|
|
latitude: position.coords.latitude,
|
|
longitude: position.coords.longitude,
|
|
});
|
|
},
|
|
(error: GeoError) => {
|
|
console.log('Geolocation Error:', error);
|
|
reject(error);
|
|
},
|
|
{
|
|
enableHighAccuracy: true,
|
|
timeout: 15000,
|
|
maximumAge: 10000,
|
|
forceRequestLocation: true,
|
|
showLocationDialog: true,
|
|
},
|
|
);
|
|
});
|
|
|
|
return location;
|
|
} catch (error) {
|
|
console.error('Failed to get current position:', error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Geocoding
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Reverse-geocode a lat/lng pair into a human-readable address string
|
|
* using the Google Maps Geocoding API.
|
|
*/
|
|
export const reverseGeocode = async (coords: LatLng): Promise<string> => {
|
|
try {
|
|
const url =
|
|
`https://maps.googleapis.com/maps/api/geocode/json` +
|
|
`?latlng=${coords.latitude},${coords.longitude}` +
|
|
`&key=${GOOGLE_MAPS_API_KEY}`;
|
|
|
|
const response = await fetch(url);
|
|
const data = await response.json();
|
|
|
|
if (data.status === 'OK' && data.results.length > 0) {
|
|
// Return the most specific formatted address.
|
|
return data.results[0].formatted_address;
|
|
}
|
|
|
|
return 'Address not found';
|
|
} catch (error) {
|
|
console.log('reverseGeocode error', error);
|
|
return 'Unable to fetch address';
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Combined helper
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* All-in-one helper: request permissions → get position → reverse geocode.
|
|
* Returns both the coordinates and the human-readable address.
|
|
*
|
|
* Throws if permission is denied or position cannot be obtained.
|
|
*/
|
|
export const getCurrentLocationWithAddress =
|
|
async (): Promise<LocationResult> => {
|
|
const hasPermission = await requestLocationPermission();
|
|
|
|
if (!hasPermission) {
|
|
showPermissionDeniedAlert();
|
|
throw new Error('Location permission denied');
|
|
}
|
|
|
|
const coords = await getCurrentPosition();
|
|
const address = await reverseGeocode(coords);
|
|
|
|
console.log('coords', coords);
|
|
console.log('address', address);
|
|
|
|
return { coords, address };
|
|
};
|