TIF_E41222181/lib/services/geolocation_service.dart

262 lines
7.9 KiB
Dart

import 'dart:developer';
import 'package:app_settings/app_settings.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geocoding/geocoding.dart';
import 'package:get/get.dart';
import 'dart:async';
import 'package:geolocator/geolocator.dart';
import 'package:absensi_qr/models/geolocation/position_item.dart';
class GeolocationService extends GetxService {
// do something here
static const String _kLocationServicesDisabledMessage =
'Location services are disabled.';
static const String _kPermissionDeniedMessage = 'Permission denied.';
static const String _kPermissionDeniedForeverMessage =
'Permission denied forever.';
static const String _kPermissionGrantedMessage = 'Permission granted.';
final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance;
final List<PositionItem> _positionItems = <PositionItem>[];
// service subscription for listener
StreamSubscription<ServiceStatus>? _serviceStatusStreamSubscription;
// flag fetch location
bool _hasFetchedLocation = false;
String serviceStatusValue = 'disabled';
String? lattitude = '';
String? longitude = '';
// placemark value =====================
var outputPlacemark = ''.obs;
var placemarkResult = Rxn<Placemark?>();
// =====================================
// cek penggunaan mockup location untuk terhindar dari kecurangan lokasi palsu user.
Future<bool> isMockLocation() async {
try {
final position = await _geolocatorPlatform.getCurrentPosition();
return position.isMocked;
} catch (e) {
log('Error checking mock location: $e');
return false; // Jika terjadi error, anggap bukan mock location
}
}
Future<bool> getCurrentPosition(int limitSecond) async {
final hasPermission = await _handlePermission();
if (!hasPermission) {
return false;
}
Fluttertoast.showToast(msg: 'mencoba mendapatkan lokasi...');
try {
final position = await _geolocatorPlatform.getCurrentPosition(
locationSettings:
LocationSettings(timeLimit: Duration(seconds: limitSecond)));
_updatePositionList(
PositionItemType.position,
position.toString(),
);
lattitude = position.latitude.toString();
longitude = position.longitude.toString();
log('lat: $lattitude, long: $longitude');
// Fluttertoast.showToast(
// msg: "Lokasi: ${position.latitude}, ${position.longitude}",
// toastLength: Toast.LENGTH_LONG,
// );
// Fluttertoast.showToast(msg: "lokasi telah di update");
if ((lattitude != '') &&
(longitude != '')) {
await placemarkLocation(
lattitude!, longitude!);
} else {
Fluttertoast.showToast(msg: 'gagal mendapatkan alamat!');
}
return true;
} on TimeoutException {
log("Timeout: lokasi tidak bisa didapatkan dalam $limitSecond detik");
Fluttertoast.showToast(
msg: "Gagal dapat lokasi (timeout $limitSecond detik)");
return false;
} catch (e) {
log("Error getCurrentPosition: $e");
Fluttertoast.showToast(msg: "Gagal dapat lokasi: $e");
return false;
}
}
Future<bool> checkLocationPermission() async {
LocationPermission permission = await _geolocatorPlatform.checkPermission();
if (permission == LocationPermission.denied) {
permission = await _geolocatorPlatform.requestPermission();
if (permission == LocationPermission.denied) {
_updatePositionList(PositionItemType.log, _kPermissionDeniedMessage);
Fluttertoast.showToast(
msg: _kPermissionDeniedMessage, toastLength: Toast.LENGTH_LONG);
return false;
}
}
if (permission == LocationPermission.deniedForever) {
_updatePositionList(
PositionItemType.log, _kPermissionDeniedForeverMessage);
Fluttertoast.showToast(
msg: _kPermissionDeniedForeverMessage,
toastLength: Toast.LENGTH_LONG);
return false;
}
return true;
}
Future<bool> _handlePermission() async {
bool serviceEnabled;
// Test if location services are enabled.
serviceEnabled = await _geolocatorPlatform.isLocationServiceEnabled();
if (!serviceEnabled) {
// Location services are not enabled don't continue
// accessing the position and request users of the
// App to enable the location services.
Fluttertoast.showToast(
msg: "GPS belum aktif, aktifkan dulu!",
toastLength: Toast.LENGTH_LONG,
);
_updatePositionList(
PositionItemType.log,
_kLocationServicesDisabledMessage,
);
await AppSettings.openAppSettings(type: AppSettingsType.location);
return false;
}
bool hasPermission = await checkLocationPermission();
if (!hasPermission) return false;
_updatePositionList(PositionItemType.log, _kPermissionGrantedMessage);
return true;
}
void _updatePositionList(PositionItemType type, String displayValue) {
_positionItems.add(PositionItem(type, displayValue));
}
Future<void> waitForGpsEnabled(
{int maxRetries = 5, Duration delay = const Duration(seconds: 2)}) async {
// Pastikan listener aktif
listenGpsStatus();
int retries = 0;
while (serviceStatusValue != 'enabled' && retries < maxRetries) {
log("GPS masih disabled, retry ke-$retries...");
await Future.delayed(delay);
if (retries == 1) {
Fluttertoast.showToast(msg: 'Mohon Nyalakan GPS!');
}
if (retries == 4) {
Fluttertoast.showToast(msg: 'Mengalihkan ke pengaturan lokasi...');
}
retries++;
}
if (serviceStatusValue != 'enabled') {
throw Exception("GPS masih disabled setelah $maxRetries percobaan");
}
if (_hasFetchedLocation != true) {
await getCurrentPosition(15);
}
}
void stopListening() {
_serviceStatusStreamSubscription?.cancel();
_serviceStatusStreamSubscription = null;
log("GPS listener dihentikan");
}
void listenGpsStatus() async {
bool isEnabled = await _geolocatorPlatform.isLocationServiceEnabled();
serviceStatusValue = isEnabled ? 'enabled' : 'disabled';
if (isEnabled) {
_hasFetchedLocation = true;
await getCurrentPosition(15);
}
if (_serviceStatusStreamSubscription == null) {
final serviceStatusStream = _geolocatorPlatform.getServiceStatusStream();
_serviceStatusStreamSubscription =
serviceStatusStream.handleError((error) {
_serviceStatusStreamSubscription?.cancel();
_serviceStatusStreamSubscription = null;
}).listen(
(serviceStatus) {
if (serviceStatus == ServiceStatus.enabled && !_hasFetchedLocation) {
serviceStatusValue = 'enabled';
// stopListening();
_hasFetchedLocation = true;
getCurrentPosition(15);
} else {
serviceStatusValue = 'disabled';
_hasFetchedLocation = false;
/// jika GPS dimatikan saat aplikasi berjalan, maka data lokasi akan direset
_hasFetchedLocation = false;
lattitude = '';
longitude = '';
outputPlacemark.value = '';
placemarkResult.value = null;
}
_updatePositionList(
PositionItemType.log,
'Location service has been $serviceStatusValue',
);
},
);
}
}
Future<void> placemarkLocation(String lat, String lon) async {
var convertedLat = double.parse(lat);
var convertedLon = double.parse(lon);
await placemarkFromCoordinates(convertedLat, convertedLon)
.then((placemarks) {
if (placemarks.isNotEmpty) {
outputPlacemark.value = placemarks[0].toString();
placemarkResult.value = placemarks[0];
}
});
}
// initialize
Future<GeolocationService> init() async {
// inisialisasi token etc...
return this;
}
@override
void onClose() {
stopListening();
super.onClose();
}
}