import 'package:geolocator/geolocator.dart';
class LocationCoordinate {
const LocationCoordinate({required this.latitude, required this.longitude});
final double latitude;
final double longitude;
}
enum LocationAccess { granted, denied, unavailable }
class LocationResult {
const LocationResult({required this.access, this.coordinate});
final LocationAccess access;
final LocationCoordinate? coordinate;
}
abstract interface class LocationProvider {
Future<bool> isLocationServiceEnabled();
Future<LocationPermission> checkPermission();
Future<LocationPermission> requestPermission();
Future<Position> getCurrentPosition();
}
class GeolocatorLocationProvider implements LocationProvider {
const GeolocatorLocationProvider();
@override
Future<bool> isLocationServiceEnabled() =>
Geolocator.isLocationServiceEnabled();
@override
Future<LocationPermission> checkPermission() => Geolocator.checkPermission();
@override
Future<LocationPermission> requestPermission() =>
Geolocator.requestPermission();
@override
Future<Position> getCurrentPosition() => Geolocator.getCurrentPosition();
}
class LocationService {
LocationService({LocationProvider? provider})
: _provider = provider ?? const GeolocatorLocationProvider();
final LocationProvider _provider;
Future<LocationResult> requestCurrentLocation() async {
try {
if (!await _provider.isLocationServiceEnabled()) {
return const LocationResult(access: LocationAccess.unavailable);
}
var permission = await _provider.checkPermission();
if (permission == LocationPermission.denied) {
permission = await _provider.requestPermission();
}
if (permission == LocationPermission.denied ||
permission == LocationPermission.deniedForever) {
return const LocationResult(access: LocationAccess.denied);
}
final position = await _provider.getCurrentPosition();
if (!_isValidCoordinate(position.latitude, position.longitude)) {
return const LocationResult(access: LocationAccess.unavailable);
}
return LocationResult(
access: LocationAccess.granted,
coordinate: LocationCoordinate(
latitude: position.latitude,
longitude: position.longitude,
),
);
} catch (_) {
return const LocationResult(access: LocationAccess.unavailable);
}
}
static bool _isValidCoordinate(double latitude, double longitude) =>
latitude.isFinite &&
longitude.isFinite &&
latitude >= -90 &&
latitude <= 90 &&
longitude >= -180 &&
longitude <= 180;
}
