diff --git a/lib/core/model/geofencing/requests/LogGeoZoneRequestModel.dart b/lib/core/model/geofencing/requests/LogGeoZoneRequestModel.dart index 181dea37..e21a7d69 100644 --- a/lib/core/model/geofencing/requests/LogGeoZoneRequestModel.dart +++ b/lib/core/model/geofencing/requests/LogGeoZoneRequestModel.dart @@ -1,8 +1,10 @@ +import 'package:flutter/cupertino.dart'; + class LogGeoZoneRequestModel { final int PointsID; final int GeoType; - LogGeoZoneRequestModel({this.PointsID, this.GeoType}); + LogGeoZoneRequestModel({@required this.PointsID, @required this.GeoType}); Map toFlatMap() { return {"PointsID": PointsID.toString(), "GeoType": GeoType.toString()}; diff --git a/lib/core/service/geofencing/GeofencingServices.dart b/lib/core/service/geofencing/GeofencingServices.dart index a40fa8ea..96e37239 100644 --- a/lib/core/service/geofencing/GeofencingServices.dart +++ b/lib/core/service/geofencing/GeofencingServices.dart @@ -27,7 +27,7 @@ class GeofencingServices extends BaseService { } LogGeoZoneResponseModel logResponse; - Future logMyGeoZone(LogGeoZoneRequestModel request) async { + Future logGeoZone(LogGeoZoneRequestModel request) async { hasError = false; await baseAppClient.post(LOG_GEO_ZONES, onSuccess: (dynamic response, int statusCode) { logResponse = LogGeoZoneResponseModel().fromJson(response); diff --git a/lib/main.dart b/lib/main.dart index 54cc5040..19304516 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,7 @@ import 'package:diplomaticquarterapp/services/robo_search/event_provider.dart'; import 'package:diplomaticquarterapp/services/robo_search/search_provider.dart'; import 'package:diplomaticquarterapp/theme/theme_value.dart'; import 'package:diplomaticquarterapp/uitl/HMG_Geofence.dart'; +import 'package:diplomaticquarterapp/uitl/LocalNotification.dart'; import 'package:diplomaticquarterapp/uitl/PlatformBridge.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:flutter/material.dart'; @@ -27,11 +28,9 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { PlatformBridge.init(context); - - var geofence = HMG_Geofence(context); - locator().getAllGeoZones(GeoZonesRequestModel(PatientID: "1231755")).then((value) { - geofence.initiate(value); - }).catchError((e) {}); + LocalNotification.init(onNotificationClick: (payload){ + LocalNotification.getInstance().showNow(title: "Payload", subtitle: payload, payload: payload); + }); return LayoutBuilder( builder: (context, constraints) { diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index 93542618..60d6c187 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -3,7 +3,9 @@ import 'dart:typed_data'; import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/core/model/geofencing/requests/GeoZonesRequestModel.dart'; import 'package:diplomaticquarterapp/core/service/AuthenticatedUserObject.dart'; +import 'package:diplomaticquarterapp/core/service/geofencing/GeofencingServices.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; import 'package:diplomaticquarterapp/models/Authentication/select_device_imei_res.dart'; @@ -17,6 +19,7 @@ import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart' import 'package:diplomaticquarterapp/services/robo_search/event_provider.dart'; import 'package:diplomaticquarterapp/uitl/CalendarUtils.dart'; import 'package:diplomaticquarterapp/uitl/HMGNetworkConnectivity.dart'; +import 'package:diplomaticquarterapp/uitl/HMG_Geofence.dart'; import 'package:diplomaticquarterapp/uitl/LocalNotification.dart'; import 'package:diplomaticquarterapp/uitl/PlatformBridge.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; @@ -130,6 +133,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { pageController = PageController(keepPage: true); _firebaseMessaging.setAutoInitEnabled(true); + // HMG (Guest/Internet) Wifi Access [Zohaib Kambrani] HMGNetworkConnectivity(context, () { GifLoaderDialogUtils.showMyDialog(context); PlatformBridge().connectHMGGuestWifi().then((value) => {GifLoaderDialogUtils.hideDialog(context)}); @@ -139,15 +143,29 @@ class _LandingPageState extends State with WidgetsBindingObserver { _firebaseMessaging.requestNotificationPermissions(); } - _firebaseMessaging.getToken().then((String token) { - sharedPref.setString(PUSH_TOKEN, token); - if (token != null && DEVICE_TOKEN == "") { - DEVICE_TOKEN = token; - checkUserStatus(token); - } - requestPermissions(); - }).catchError((err) { - print(err); + + // Flip Permission Checks [Zohaib Kambrani] + requestPermissions().then((results){ + if(results[Permission.locationAlways].isGranted + || results[Permission.location].isGranted ) + HMG_Geofencing(context) + .loadZones() + .then((instance) => instance.init()); + + if(results[Permission.notification].isGranted) + _firebaseMessaging.getToken().then((String token) { + sharedPref.setString(PUSH_TOKEN, token); + if (token != null && DEVICE_TOKEN == "") { + DEVICE_TOKEN = token; + checkUserStatus(token); + } + }); + + if(results[Permission.storage].isGranted); + if(results[Permission.camera].isGranted); + if(results[Permission.photos].isGranted); + if(results[Permission.accessMediaLocation].isGranted); + if(results[Permission.calendar].isGranted); }); // @@ -274,9 +292,10 @@ class _LandingPageState extends State with WidgetsBindingObserver { dialog.showAlertDialog(context); } - void requestPermissions() async { - await [ + Future> requestPermissions() async { + var permissionResults = [ Permission.location, + Permission.locationAlways, Permission.storage, Permission.camera, Permission.photos, @@ -284,44 +303,16 @@ class _LandingPageState extends State with WidgetsBindingObserver { Permission.accessMediaLocation, Permission.calendar, ].request(); - + var permissionsGranted = await deviceCalendarPlugin.hasPermissions(); if (permissionsGranted.isSuccess && !permissionsGranted.data) { permissionsGranted = await deviceCalendarPlugin.requestPermissions(); if (!permissionsGranted.isSuccess || !permissionsGranted.data) { - return; } } + return permissionResults; } - Future _scheduleNotification() async { - var scheduledNotificationDateTime = DateTime.now().add(Duration(seconds: 5)); - var vibrationPattern = Int64List(4); - vibrationPattern[0] = 0; - vibrationPattern[1] = 1000; - vibrationPattern[2] = 5000; - vibrationPattern[3] = 2000; - - var androidPlatformChannelSpecifics = AndroidNotificationDetails('your other channel id', 'your other channel name', 'your other channel description', - // icon: 'secondary_icon', - sound: RawResourceAndroidNotificationSound('slow_spring_board'), - largeIcon: DrawableResourceAndroidBitmap('sample_large_icon'), - vibrationPattern: vibrationPattern, - enableLights: true, - color: const Color.fromARGB(255, 255, 0, 0), - ledColor: const Color.fromARGB(255, 255, 0, 0), - ledOnMs: 1000, - ledOffMs: 500); - var iOSPlatformChannelSpecifics = IOSNotificationDetails(sound: 'slow_spring_board.aiff'); - // var platformChannelSpecifics = NotificationDetails( - // androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); - // await flutterLocalNotificationsPlugin.schedule( - // 0, - // 'scheduled title', - // 'scheduled body', - // scheduledNotificationDateTime, - // platformChannelSpecifics); - } @override Widget build(BuildContext context) { diff --git a/lib/uitl/HMG_Geofence.dart b/lib/uitl/HMG_Geofence.dart index 53c25090..95ca7c37 100644 --- a/lib/uitl/HMG_Geofence.dart +++ b/lib/uitl/HMG_Geofence.dart @@ -1,17 +1,24 @@ 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_Geofence { +class HMG_Geofencing { + var _testTrigger = false; static var _isolatePortName = "hmg_geofencing_send_port"; List _zones; @@ -21,19 +28,21 @@ class HMG_Geofence { final BuildContext context; final List triggers = List(); - ReceivePort port = ReceivePort(); - HMG_Geofence(this.context) { + HMG_Geofencing(this.context) { triggers.add(GeofenceEvent.enter); triggers.add(GeofenceEvent.exit); // triggers.add(GeofenceEvent.dwell); } - void initiate(List zones) async { - _zones = zones; + Future loadZones() async{ + _zones = await locator().getAllGeoZones(GeoZonesRequestModel()); + return this; + } + void init() async { + // debug check (Testing Geo Zones) if (kDebugMode) { - // debug check addTestingGeofences(); } _saveZones(); @@ -42,7 +51,13 @@ class HMG_Geofence { _registerIsolatePort(); _registerGeofences().then((value) { debugPrint(value.toString()); + if(_testTrigger) { + var events = [GeofenceEvent.enter,GeofenceEvent.exit]; + events.shuffle(); + transitionTrigger(value, null, events.first); + } }); + } void _saveZones() { @@ -91,59 +106,84 @@ class HMG_Geofence { _zones.add(GeoZonesResponseModel.get("24.7087913,46.6656461", 150, "csO")); } - static void transitionTrigger(List id, Location location, GeofenceEvent event) async { - id.forEach((element) { - LocalNotification.showNow( - title: "GeofenceEvent: ${event.toString()}", - subtitle: element, - onClickNotification: (payload) { - debugPrint(payload); - }, - payload: element); + 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)); + + }); + + }); }); - // id.forEach((element) { - // final SendPort send = IsolateNameServer.lookupPortByName(_isolatePortName); - // send?.send({"event": event, "geofence_id": element}); - // }); } - void _registerIsolatePort() { - IsolateNameServer.registerPortWithName(port.sendPort, _isolatePortName); - AppSharedPreferences pref = AppSharedPreferences(); - var jsonString = pref.getString(HMG_GEOFENCES); - List jsonList = json.decode(jsonString); - List geoList = jsonList.map((e) => GeoZonesResponseModel().fromJson(e)); - - port.listen((dynamic data) { - GeofenceEvent event = data["event"]; - String geofence_id = data["geofence_id"]; - - GeoZonesResponseModel geofence = _findByGeofenceIdFrom(geoList, geofence_id); - - LocalNotification.showNow( - title: "GeofenceEvent: ${_nameOf(event)}", - subtitle: geofence.description, - onClickNotification: (payload) { - debugPrint(payload); - }, - payload: json.encode(geofence.toJson())); + _logGeoZoneToServer({int zoneId, int transition}){ + locator() + .logGeoZone(LogGeoZoneRequestModel(GeoType: transition, PointsID: zoneId ?? 1)) + .then((response){ + + }).catchError((error){ + }); + } - GeoZonesResponseModel _findByGeofenceIdFrom(List list, String geofence_id) { - var have = list.where((element) => element.geofenceId() == geofence_id).toList().first; + GeoZonesResponseModel _findByGeofenceFrom(List list, { String by}) { + var have = list.where((element) => element.geofenceId() == by).toList().first; return have; } String _nameOf(GeofenceEvent event) { - if (event == GeofenceEvent.exit) { - return "Exit"; - } else if (event == GeofenceEvent.enter) { - return "Enter"; - } else if (event == GeofenceEvent.dwell) { - return "Well"; - } else { - event.toString(); + 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; } } } diff --git a/lib/uitl/LocalNotification.dart b/lib/uitl/LocalNotification.dart index 43cb598a..0b148f49 100644 --- a/lib/uitl/LocalNotification.dart +++ b/lib/uitl/LocalNotification.dart @@ -2,30 +2,61 @@ import 'dart:math'; import 'dart:typed_data'; import 'dart:ui'; -import 'package:diplomaticquarterapp/locator.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); class LocalNotification { - static Future showNow({@required String title, @required String subtitle, String payload, Function(String payload) onClickNotification}) { - var plugin = FlutterLocalNotificationsPlugin(); + Function(String payload) _onNotificationClick; + static LocalNotification _instance; + static LocalNotification getInstance(){ + return _instance; + } + static init({Function(String payload) onNotificationClick}){ + if(_instance == null){ + _instance = LocalNotification(); + _instance._onNotificationClick = onNotificationClick; + _instance._initialize(); + }else{ + assert(false,(){ + "LocalNotification Already Initialized"; + }); + } + } + + _initialize(){ var initializationSettingsAndroid = new AndroidInitializationSettings('app_icon'); var initializationSettingsIOS = IOSInitializationSettings(onDidReceiveLocalNotification: null); var initializationSettings = InitializationSettings(initializationSettingsAndroid, initializationSettingsIOS); - plugin.initialize(initializationSettings, onSelectNotification: onClickNotification); + flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: _onNotificationClick); + } + + var _random = new Random(); + _randomNumber({int from = 100000}){ + return _random.nextInt(from); + } + + _vibrationPattern(){ + var vibrationPattern = Int64List(4); + vibrationPattern[0] = 0; + vibrationPattern[1] = 1000; + vibrationPattern[2] = 5000; + vibrationPattern[3] = 2000; + + return vibrationPattern; + } - var rng = new Random(); + Future showNow({@required String title, @required String subtitle, String payload}) { Future.delayed(Duration(seconds: 1)).then((result) async { - var androidPlatformChannelSpecifics = AndroidNotificationDetails('com.hmg', 'HMG', 'HMG', importance: Importance.Max, priority: Priority.High, ticker: 'ticker'); + var androidPlatformChannelSpecifics = AndroidNotificationDetails('com.hmg.local_notification', 'HMG', 'HMG', importance: Importance.Max, priority: Priority.High, ticker: 'ticker', vibrationPattern: _vibrationPattern()); var iOSPlatformChannelSpecifics = IOSNotificationDetails(); var platformChannelSpecifics = NotificationDetails(androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); - await flutterLocalNotificationsPlugin.show(rng.nextInt(100000), title, subtitle, platformChannelSpecifics, payload: payload); + await flutterLocalNotificationsPlugin.show(_randomNumber(), title, subtitle, platformChannelSpecifics, payload: payload); }); } - static Future scheduleNotification({@required DateTime scheduledNotificationDateTime, @required String title, @required String description}) async { + Future scheduleNotification({@required DateTime scheduledNotificationDateTime, @required String title, @required String description}) async { ///vibrationPattern var vibrationPattern = Int64List(4); vibrationPattern[0] = 0; @@ -55,7 +86,7 @@ class LocalNotification { } ///Repeat notification every day at approximately 10:00:00 am - static Future showDailyAtTime() async { + Future showDailyAtTime() async { var time = Time(10, 0, 0); var androidPlatformChannelSpecifics = AndroidNotificationDetails('repeatDailyAtTime channel id', 'repeatDailyAtTime channel name', 'repeatDailyAtTime description'); var iOSPlatformChannelSpecifics = IOSNotificationDetails(); @@ -70,7 +101,7 @@ class LocalNotification { } ///Repeat notification weekly on Monday at approximately 10:00:00 am - static Future showWeeklyAtDayAndTime() async { + Future showWeeklyAtDayAndTime() async { var time = Time(10, 0, 0); var androidPlatformChannelSpecifics = AndroidNotificationDetails('show weekly channel id', 'show weekly channel name', 'show weekly description'); var iOSPlatformChannelSpecifics = IOSNotificationDetails(); @@ -85,15 +116,15 @@ class LocalNotification { // platformChannelSpecifics); } - static String _toTwoDigitString(int value) { + String _toTwoDigitString(int value) { return value.toString().padLeft(2, '0'); } - static Future cancelNotification() async { + Future cancelNotification() async { await flutterLocalNotificationsPlugin.cancel(0); } - static Future cancelAllNotifications() async { + Future cancelAllNotifications() async { await flutterLocalNotificationsPlugin.cancelAll(); } }