import 'dart:async'; import 'package:flutter/material.dart'; import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; class MapsController extends GetxController { final count = 0.obs; GoogleMapController? mapController; // Gunakan nullable untuk menghindari LateInitializationError RxSet markers = {}.obs; var addressMessage = "".obs; Set polygons = {}; // Menyimpan poligon area kampus String selectedBuilding = ''; double selectedLatitude = 0.0; double selectedLongitude = 0.0; TextEditingController latitudeController = TextEditingController(); TextEditingController longitudeController = TextEditingController(); TextEditingController keteranganController = TextEditingController(); StreamSubscription? _positionStreamSubscription; var myPosition = Position( altitudeAccuracy: 0, headingAccuracy: 0, longitude: 0, latitude: 0, timestamp: DateTime.now(), accuracy: 0, altitude: 0.0, heading: 0, speed: 0, speedAccuracy: 0, ).obs; @override void onInit() { super.onInit(); _positionStreamSubscription?.cancel(); addPolygon(); determinePosition(); } @override void onReady() { super.onReady(); } @override void onClose() { super.onClose(); } void increment() => count.value++; Future determinePosition() async { bool serviceEnabled; LocationPermission permission; // Test if location services are enabled. serviceEnabled = await Geolocator.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. return Future.error('Location services are disabled.'); } permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { // Permissions are denied, next time you could try // requesting permissions again (this is also where // Android's shouldShowRequestPermissionRationale // returned true. According to Android guidelines // your App should show an explanatory UI now. return Future.error('Location permissions are denied'); } } if (permission == LocationPermission.deniedForever) { // Permissions are denied forever, handle appropriately. return Future.error( 'Location permissions are permanently denied, we cannot request permissions.'); } // When we reach here, permissions are granted and we can // continue accessing the position of the device. return await Geolocator.getCurrentPosition(); } Future isLocationServiceEnabled() async { return await Geolocator.isLocationServiceEnabled(); } Future startLocationStreaming() async { try { _positionStreamSubscription = Geolocator.getPositionStream( locationSettings: const LocationSettings( accuracy: LocationAccuracy.best, distanceFilter: 10, // set the distance filter as needed ), ).listen((Position position) { updateLocation(position); }); } catch (e) { print("Error streaming location: $e"); } } void updateLocation(Position position) { // Handling lokasi yang valid if (position.latitude != 0.0 && position.longitude != 0.0) { mapController?.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( target: LatLng(position.latitude, position.longitude), zoom: 17.0, ), ), ); markers.clear(); markers.add( Marker( markerId: MarkerId(position.toString()), position: LatLng(position.latitude, position.longitude), infoWindow: InfoWindow(title: 'Lokasi Saat Ini'), icon: BitmapDescriptor.defaultMarker, ), ); latitudeController.text = position.latitude.toString(); longitudeController.text = position.longitude.toString(); getAddressFromLatLng(position.latitude, position.longitude); } else { // Handle jika lokasi tidak valid Get.snackbar( 'Error', 'Gagal mendapatkan lokasi yang valid', backgroundColor: Colors.red, colorText: Colors.white, ); } } bool isInsideCampus(LatLng point) { for (Polygon polygon in polygons) { if (_pointInPolygon(point, polygon.points)) { return true; } } return false; } void placeMarker(double latitude, double longitude) { mapController?.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( target: LatLng(latitude, longitude), zoom: 17.0, ), ), ); markers.clear(); markers.add( Marker( markerId: MarkerId('selected_location'), position: LatLng(latitude, longitude), infoWindow: InfoWindow(title: 'Lokasi Gedung Dipilih'), icon: BitmapDescriptor.defaultMarker, ), ); latitudeController.text = latitude.toString(); longitudeController.text = longitude.toString(); getAddressFromLatLng(latitude, longitude); } Future getAddressFromLatLng(double lat, double long) async { List placemarks = await placemarkFromCoordinates(lat, long); print(placemarks); if (placemarks != null && placemarks.isNotEmpty) { Placemark place = placemarks[0]; addressMessage.value = "${place.street}, ${place.subLocality}, ${place.locality}, ${place.postalCode}, ${place.country} "; } else { addressMessage.value = "alamat tidak ditemukan"; } } bool _pointInPolygon(LatLng point, List polygon) { bool isInside = false; int i, j = polygon.length - 1; for (i = 0; i < polygon.length; i++) { if ((polygon[i].latitude < point.latitude && polygon[j].latitude >= point.latitude || polygon[j].latitude < point.latitude && polygon[i].latitude >= point.latitude)) { if (polygon[i].longitude + (point.latitude - polygon[i].latitude) / (polygon[j].latitude - polygon[i].latitude) * (polygon[j].longitude - polygon[i].longitude) < point.longitude) { isInside = !isInside; } } j = i; } return isInside; } bool _rayCastIntersect(LatLng point, LatLng vertA, LatLng vertB) { double aY = vertA.latitude; double bY = vertB.latitude; double pY = point.latitude; double pX = point.longitude; double aX = vertA.longitude; double bX = vertB.longitude; if ((pY > aY && pY > bY) || (pY < aY && pY < bY) || (pX > aX && pX > bX)) { return false; } if (pX < aX && pX < bX) { return true; } double m = (aY - bY) / (aX - bX); double x = (pY - bY + m * bX + m * m * pX) / (m * m + 1); return x > pX; } void addPolygon() { List polygonCoordinates = [ LatLng(-8.160196, 113.720363), LatLng(-8.159211356625963, 113.72074965270397), LatLng(-8.158427, 113.721077), LatLng(-8.15816791731383, 113.72121032209817), LatLng(-8.155363353768134, 113.72276208474295), LatLng(-8.155346495030903, 113.7233347509108), LatLng(-8.155487, 113.723629), LatLng(-8.15538037443089, 113.7237392656189), LatLng(-8.155291758556917, 113.72457443735635), LatLng(-8.155322915349174, 113.7247593045013), LatLng(-8.155214056883109, 113.72478545603816), LatLng(-8.15534481979311, 113.72562699911745), LatLng(-8.155099888211316, 113.72570210097138), LatLng(-8.155341500937823, 113.72654297349261), LatLng(-8.155083957696679, 113.72670859990627), LatLng(-8.155221108341713, 113.72716676381422), LatLng(-8.154990150457476, 113.72721755397869), LatLng(-8.155045140441796, 113.72743023773916), LatLng(-8.15611605559663, 113.72717058078224), LatLng(-8.16046268775949, 113.72547806238292), LatLng(-8.160842629741886, 113.72507175302918), LatLng(-8.160449405693358, 113.72421176932542), LatLng(-8.160700593250922, 113.72409844837689), LatLng(-8.160793321613193, 113.72360964572987), LatLng(-8.161291333350428, 113.72322506548953), LatLng(-8.160996623292966, 113.72260346355264), LatLng(-8.160196964920255, 113.72035606335321), ]; polygons.add( Polygon( polygonId: PolygonId('kampus_boundary'), points: polygonCoordinates, fillColor: Colors.blue.withOpacity(0.5), strokeWidth: 2, strokeColor: Colors.blue, ), ); mapController?.animateCamera( CameraUpdate.newLatLngBounds( LatLngBounds( southwest: polygonCoordinates.reduce( (value, element) => LatLng( value.latitude < element.latitude ? value.latitude : element.latitude, value.longitude < element.longitude ? value.longitude : element.longitude, ), ), northeast: polygonCoordinates.reduce( (value, element) => LatLng( value.latitude > element.latitude ? value.latitude : element.latitude, value.longitude > element.longitude ? value.longitude : element.longitude, ), ), ), 50.0, ), ); } Future getCurrentLocation() async { try { Position position = await Geolocator.getCurrentPosition( forceAndroidLocationManager: true, desiredAccuracy: LocationAccuracy.best) .timeout(Duration(seconds: 15)); updateLocation(position); // Mengecek apakah lokasi yang didapatkan valid (latitude dan longitude bukan 0.0) if (position.latitude != 0.0 && position.longitude != 0.0) { mapController?.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( target: LatLng(position.latitude, position.longitude), zoom: 17.0, ), ), ); markers.clear(); markers.add( Marker( markerId: MarkerId(position.toString()), position: LatLng(position.latitude, position.longitude), infoWindow: InfoWindow(title: 'Lokasi Saat Ini'), icon: BitmapDescriptor.defaultMarker, ), ); latitudeController.text = position.latitude.toString(); longitudeController.text = position.longitude.toString(); getAddressFromLatLng(position.latitude, position.longitude); } else { // Handle jika lokasi tidak valid Get.snackbar( 'Error', 'Gagal mendapatkan lokasi yang valid', backgroundColor: Colors.red, colorText: Colors.white, ); } } catch (e) { // Handle kesalahan saat mendapatkan lokasi Get.snackbar( 'Error', 'Gagal mendapatkan lokasi saat ini: $e', backgroundColor: Colors.red, colorText: Colors.white, ); } } void goToKampus() { mapController?.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( target: LatLng(-8.15794, 113.72380), zoom: 17.0, ), ), ); } }