import 'dart:convert'; import 'dart:core'; import 'dart:io'; import 'dart:isolate'; import 'dart:math'; import 'dart:ui'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/core/model/geofencing/requests/GeoZonesRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/geofencing/requests/LogGeoZoneRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/geofencing/responses/GeoZonesResponseModel.dart'; import 'package:diplomaticquarterapp/core/service/geofencing/GeofencingServices.dart'; import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/uitl/LocalNotification.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:geofencing/geofencing.dart'; class HMG_Geofencing { var _testTrigger = false; static var _isolatePortName = "hmg_geofencing_send_port"; List _zones; List registeredGeofences = []; final AndroidGeofencingSettings androidSettings = AndroidGeofencingSettings(initialTrigger: [GeofenceEvent.enter, GeofenceEvent.exit, GeofenceEvent.dwell], loiteringDelay: 1000 * 60); final BuildContext context; final List triggers = List(); HMG_Geofencing(this.context) { triggers.add(GeofenceEvent.enter); triggers.add(GeofenceEvent.exit); // triggers.add(GeofenceEvent.dwell); } Future loadZones() async{ _zones = await locator().getAllGeoZones(GeoZonesRequestModel()); return this; } void init() async { // debug check (Testing Geo Zones) if (kDebugMode) { addTestingGeofences(); } _saveZones(); await GeofencingManager.initialize(); await Future.delayed(Duration(seconds: 2)); _registerIsolatePort(); _registerGeofences().then((value) { debugPrint(value.toString()); if(_testTrigger) { var events = [GeofenceEvent.enter,GeofenceEvent.exit]; events.shuffle(); transitionTrigger(value, null, events.first); } }); } void _saveZones() { var list = List(); _zones.forEach((element) { list.add(element.toJson()); }); var jsonString = jsonEncode(list); AppSharedPreferences pref = AppSharedPreferences(); pref.setString(HMG_GEOFENCES, jsonString); } Future> _registerGeofences() async { registeredGeofences = await GeofencingManager.getRegisteredGeofenceIds(); var maxLimit = Platform.isIOS ? 20 : 100; if (registeredGeofences.length < maxLimit) { var notRegistered = _zones.where((element) => !(registeredGeofences.contains(element.geofenceId()))).toList(); for (int i = 0; i < notRegistered.length; i++) { var zone = notRegistered.elementAt(i); var lat = double.tryParse(zone.latitude); var lon = double.tryParse(zone.longitude); var rad = double.tryParse(zone.radius.toString()); if (lat != null || lon != null || rad != null) { await GeofencingManager.registerGeofence(GeofenceRegion(zone.geofenceId(), lat, lon, rad, triggers), transitionTrigger); registeredGeofences.add(zone.geofenceId()); if (registeredGeofences.length >= maxLimit) { break; } await Future.delayed(Duration(milliseconds: 100)); debugPrint("Geofence: ${zone.description} registered"); } else { debugPrint("Geofence: ${zone.description} registered"); } } } return registeredGeofences; } void addTestingGeofences() { _zones.add(GeoZonesResponseModel.get("24.777577,46.652675", 150, "msH")); _zones.add(GeoZonesResponseModel.get("24.691136,46.650116", 150, "zkH")); _zones.add(GeoZonesResponseModel.get("24.7087913,46.6656461", 150, "csO")); } static void transitionTrigger(List id, Location location, GeofenceEvent event) { var dataToSend = id.map((element) => {"event": event, "geofence_id": element}).toList() ?? []; final SendPort send = IsolateNameServer.lookupPortByName(_isolatePortName); send?.send(dataToSend); } ReceivePort _port = ReceivePort(); void _registerIsolatePort() async{ IsolateNameServer.registerPortWithName(_port.sendPort, _isolatePortName); _port.listen((dynamic data) { Future result = AppSharedPreferences().getStringWithDefaultValue(HMG_GEOFENCES,"[]"); result.then((jsonString){ List jsonList = json.decode(jsonString) ?? []; List geoList = jsonList.map((e) => GeoZonesResponseModel().fromJson(e)).toList() ?? []; (data as List).forEach((element) async { GeofenceEvent geofenceEvent = element["event"]; String geofence_id = element["geofence_id"]; GeoZonesResponseModel geoZone = _findByGeofenceFrom(geoList, by: geofence_id); if(geoZone != null) { LocalNotification.getInstance().showNow( title: "GeofenceEvent: ${_nameOf(geofenceEvent)}", subtitle: geoZone.description, payload: json.encode(geoZone.toJson())); _logGeoZoneToServer(zoneId: geoZone.geofId, transition: _idOf(geofenceEvent)); } await Future.delayed(Duration(milliseconds: 700)); }); }); }); } _logGeoZoneToServer({int zoneId, int transition}){ locator() .logGeoZone(LogGeoZoneRequestModel(GeoType: transition, PointsID: zoneId ?? 1)) .then((response){ }).catchError((error){ }); } GeoZonesResponseModel _findByGeofenceFrom(List list, { String by}) { var have = list.where((element) => element.geofenceId() == by).toList().first; return have; } String _nameOf(GeofenceEvent event) { switch (event) { case GeofenceEvent.enter: return "Enter"; case GeofenceEvent.exit: return "Exit"; case GeofenceEvent.dwell: return "dWell"; default: return event.toString(); } } int _idOf(GeofenceEvent event){ switch (event) { case GeofenceEvent.enter: return 1; case GeofenceEvent.exit: return 2; case GeofenceEvent.dwell: return 3; default: return -1; } } }