import 'package:geolocator/geolocator.dart'; import '../models/report.dart'; /// Service for handling location operations and permissions class LocationService { /// Check if location services are enabled static Future isLocationServiceEnabled() async { try { return await Geolocator.isLocationServiceEnabled(); } catch (e) { print('Error checking location service: $e'); // Handle specific Android exceptions that can cause crashes if (e.toString().contains('DeadSystemException') || e.toString().contains('DeadSystemRuntimeException') || e.toString().contains('SecurityException')) { print('System-level location service error detected, returning false'); return false; } return false; } } /// Check location permissions static Future checkPermission() async { try { return await Geolocator.checkPermission(); } catch (e) { print('Error checking location permission: $e'); // Handle specific Android exceptions that can cause crashes if (e.toString().contains('DeadSystemException') || e.toString().contains('DeadSystemRuntimeException') || e.toString().contains('SecurityException')) { print('System-level permission error detected, returning denied'); return LocationPermission.denied; } return LocationPermission.denied; } } /// Request location permissions static Future requestPermission() async { try { return await Geolocator.requestPermission(); } catch (e) { print('Error requesting location permission: $e'); // Handle specific Android exceptions that can cause crashes if (e.toString().contains('DeadSystemException') || e.toString().contains('DeadSystemRuntimeException') || e.toString().contains('SecurityException')) { print( 'System-level permission request error detected, returning denied', ); return LocationPermission.denied; } return LocationPermission.denied; } } /// Get current position with high accuracy static Future getCurrentPosition() async { try { // Check if location services are enabled final serviceEnabled = await isLocationServiceEnabled(); if (!serviceEnabled) { print('Location services are disabled'); return null; } // Check permissions var permission = await checkPermission(); if (permission == LocationPermission.denied) { permission = await requestPermission(); if (permission == LocationPermission.denied) { print('Location permission denied'); return null; } } if (permission == LocationPermission.deniedForever) { print('Location permission permanently denied'); return null; } // Get current position with multiple fallback strategies return await _getPositionWithFallback(); } catch (e) { print('Error getting current position: $e'); return null; } } /// Get position with fallback strategies to avoid crashes static Future _getPositionWithFallback() async { try { // Try high accuracy first with a reasonable timeout return await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.high, timeLimit: const Duration(seconds: 15), ); } catch (e) { print('High accuracy failed, trying medium accuracy: $e'); try { // Fallback to medium accuracy return await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.medium, timeLimit: const Duration(seconds: 10), ); } catch (e2) { print('Medium accuracy failed, trying low accuracy: $e2'); try { // Final fallback to low accuracy return await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.low, timeLimit: const Duration(seconds: 5), ); } catch (e3) { print('All accuracy levels failed: $e3'); return null; } } } } /// Get current position with best available accuracy static Future getBestAvailablePosition() async { try { // Check if location services are enabled final serviceEnabled = await isLocationServiceEnabled(); if (!serviceEnabled) { print('Location services are disabled'); return null; } // Check permissions var permission = await checkPermission(); if (permission == LocationPermission.denied) { permission = await requestPermission(); if (permission == LocationPermission.denied) { print('Location permission denied'); return null; } } if (permission == LocationPermission.deniedForever) { print('Location permission permanently denied'); return null; } // Try high accuracy first, fallback to medium if it takes too long try { return await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.high, timeLimit: const Duration(seconds: 15), ); } catch (e) { print('High accuracy failed, trying medium accuracy: $e'); return await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.medium, timeLimit: const Duration(seconds: 10), ); } } catch (e) { print('Error getting best available position: $e'); return null; } } /// Convert Position to LocationData static LocationData positionToLocationData(Position position) { return LocationData( lat: position.latitude, lng: position.longitude, accuracy: position.accuracy, ); } /// Get location accuracy description static String getAccuracyDescription(double? accuracy) { if (accuracy == null) return 'Unknown'; if (accuracy <= 3) { return 'Very High'; } else if (accuracy <= 10) { return 'High'; } else if (accuracy <= 50) { return 'Medium'; } else if (accuracy <= 100) { return 'Low'; } else { return 'Very Low'; } } /// Check if location accuracy is good enough for reporting static bool isAccuracyGoodForReporting(double? accuracy) { if (accuracy == null) return false; return accuracy <= 50; // Within 50 meters is acceptable } /// Get user-friendly location permission status message static String getPermissionStatusMessage(LocationPermission permission) { switch (permission) { case LocationPermission.denied: return 'Location permission denied. Please enable location access to attach GPS coordinates to your reports.'; case LocationPermission.deniedForever: return 'Location permission permanently denied. Please enable location access in your device settings to use this feature.'; case LocationPermission.whileInUse: case LocationPermission.always: return 'Location permission granted.'; case LocationPermission.unableToDetermine: return 'Unable to determine location permission status.'; } } /// Open device location settings static Future openLocationSettings() async { try { return await Geolocator.openLocationSettings(); } catch (e) { print('Error opening location settings: $e'); return false; } } /// Calculate distance between two points in meters static double calculateDistance(LocationData point1, LocationData point2) { return Geolocator.distanceBetween( point1.lat, point1.lng, point2.lat, point2.lng, ); } /// Get address from coordinates (placeholder - would need geocoding service) static Future getAddressFromCoordinates( double lat, double lng, ) async { // This is a placeholder implementation // In a real app, you would use a geocoding service like Google Maps API // or OpenStreetMap Nominatim API return null; } /// Validate location data static bool isValidLocation(LocationData location) { final acc = location.accuracy; return location.lat >= -90 && location.lat <= 90 && location.lng >= -180 && location.lng <= 180 && acc != null && acc >= 0; } }