import 'package:shared_preferences/shared_preferences.dart'; import 'package:qyuota/config/api_config.dart'; import 'dart:math' show asin, cos, pow, sin, sqrt; class LocationConfig { // Singleton pattern static final LocationConfig _instance = LocationConfig._internal(); factory LocationConfig() => _instance; LocationConfig._internal(); // Mendapatkan latitude kantor dari SharedPreferences atau default Future getOfficeLatitude() async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getDouble(ApiConfig.officeLatitudeKey) ?? ApiConfig.defaultOfficeLatitude; } // Mendapatkan longitude kantor dari SharedPreferences atau default Future getOfficeLongitude() async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getDouble(ApiConfig.officeLongitudeKey) ?? ApiConfig.defaultOfficeLongitude; } // Mendapatkan radius presensi dari SharedPreferences atau default Future getRadiusInMeters() async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getDouble(ApiConfig.radiusInMetersKey) ?? ApiConfig.defaultRadiusInMeters; } // Menyimpan konfigurasi lokasi kantor baru Future saveOfficeLocation(double latitude, double longitude) async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setDouble(ApiConfig.officeLatitudeKey, latitude); return await prefs.setDouble(ApiConfig.officeLongitudeKey, longitude); } // Menyimpan radius presensi baru Future saveRadius(double radius) async { SharedPreferences prefs = await SharedPreferences.getInstance(); return await prefs.setDouble(ApiConfig.radiusInMetersKey, radius); } // Menghitung jarak antara dua koordinat (Haversine formula) double calculateDistance(double lat1, double lon1, double lat2, double lon2) { const double earthRadius = 6371000; // Radius bumi dalam meter const double tolerance = 50.0; // Toleransi 50 meter untuk akurasi GPS // Konversi derajat ke radian final double dLat = _toRadians(lat2 - lat1); final double dLon = _toRadians(lon2 - lon1); // Rumus haversine final double a = pow(sin(dLat / 2), 2) + cos(_toRadians(lat1)) * cos(_toRadians(lat2)) * pow(sin(dLon / 2), 2); final double c = 2 * asin(sqrt(a)); // Jarak dalam meter dengan toleransi double distance = (earthRadius * c) - tolerance; print('\n=== DETAIL PERHITUNGAN JARAK ==='); print('Koordinat 1: ($lat1, $lon1)'); print('Koordinat 2: ($lat2, $lon2)'); print('dLat (radian): ${dLat.toStringAsFixed(6)}'); print('dLon (radian): ${dLon.toStringAsFixed(6)}'); print('a: ${a.toStringAsFixed(6)}'); print('c: ${c.toStringAsFixed(6)}'); print('Jarak akhir: ${distance.toStringAsFixed(2)} meter'); print('Toleransi: ${tolerance.toStringAsFixed(2)} meter'); return distance > 0 ? distance : 0; // Pastikan jarak tidak negatif } // Konversi derajat ke radian double _toRadians(double degree) { return degree * (3.141592653589793 / 180); } // Memeriksa apakah lokasi berada dalam radius yang ditentukan Future isLocationInRadius(double latitude, double longitude) async { double officeLatitude = await getOfficeLatitude(); double officeLongitude = await getOfficeLongitude(); double radiusInMeters = await getRadiusInMeters(); double distance = calculateDistance( latitude, longitude, officeLatitude, officeLongitude ); return distance <= radiusInMeters; } }