From 8d5d55a150b9d347a9d6c3a4d4ad3a9c19eea898 Mon Sep 17 00:00:00 2001 From: Zohaib Kambrani Date: Thu, 10 Dec 2020 17:47:55 +0300 Subject: [PATCH] Geofencing in progress --- android/app/src/main/AndroidManifest.xml | 8 ++ ios/Runner/Info.plist | 12 ++ lib/config/config.dart | 5 + lib/config/shared_pref_kay.dart | 1 + .../requests/GeoZonesRequestModel.dart | 9 ++ .../requests/LogGeoZoneRequestModel.dart | 10 ++ .../responses/GeoZonesResponseModel.dart | 62 +++++++++ .../responses/LogGeoZoneResponseModel.dart | 26 ++++ .../geofencing/GeofencingServices.dart | 40 ++++++ .../PackagesOffersServices.dart | 2 - .../json/GeoZonesResponseModel_helper.dart | 50 ++++++++ ... OfferCategoriesResponseModel_helper.dart} | 4 +- ...=> OfferProductsResponseModel_helper.dart} | 0 .../json/base/json_convert_content.dart | 28 +++- ...geo_zone_response_model_entity_helper.dart | 54 ++++++++ lib/locator.dart | 9 ++ lib/main.dart | 8 ++ lib/pages/landing/home_page.dart | 6 + lib/uitl/HMG_Geofence.dart | 120 ++++++++++++++++++ lib/uitl/LocalNotification.dart | 44 ++++--- pubspec.yaml | 1 + 21 files changed, 471 insertions(+), 28 deletions(-) create mode 100644 lib/core/model/geofencing/requests/GeoZonesRequestModel.dart create mode 100644 lib/core/model/geofencing/requests/LogGeoZoneRequestModel.dart create mode 100644 lib/core/model/geofencing/responses/GeoZonesResponseModel.dart create mode 100644 lib/core/model/geofencing/responses/LogGeoZoneResponseModel.dart create mode 100644 lib/core/service/geofencing/GeofencingServices.dart create mode 100644 lib/generated/json/GeoZonesResponseModel_helper.dart rename lib/generated/json/{offer_categories_response_model_entity_helper_.dart => OfferCategoriesResponseModel_helper.dart} (96%) rename lib/generated/json/{OfferProductsResponseModel_helper_.dart => OfferProductsResponseModel_helper.dart} (100%) create mode 100644 lib/generated/json/log_geo_zone_response_model_entity_helper.dart create mode 100644 lib/uitl/HMG_Geofence.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9bff802f..b2132a0d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ FlutterApplication and put your custom class here. --> + @@ -73,6 +74,13 @@ + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 8c6c1ed1..e27d2e38 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -24,6 +24,8 @@ NSCameraUsageDescription Need camera access for uploading images + NSLocationAlwaysAndWhenInUseUsageDescription + This app will use your location to show cool stuffs near you. NSLocationUsageDescription Need location access for updating nearby friends NSLocationWhenInUseUsageDescription @@ -32,6 +34,10 @@ Need microphone access for uploading videos NSPhotoLibraryUsageDescription Need photo library access for uploading images + UIBackgroundModes + + location + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -53,5 +59,11 @@ io.flutter.embedded_views_preview + UIRequiredDeviceCapabilities + + location-services + gps + armv7 + diff --git a/lib/config/config.dart b/lib/config/config.dart index 1108a6e2..c82c8593 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:diplomaticquarterapp/core/service/geofencing/GeofencingServices.dart'; import 'package:diplomaticquarterapp/models/Request.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/widgets/mobile-no/mobile_no.dart'; @@ -17,6 +18,10 @@ const PING_SERVICE = 'Services/Weather.svc/REST/CheckConnectivity'; // const BASE_URL = 'https://hmgwebservices.com/'; const GET_PROJECT = 'Services/Lists.svc/REST/GetProject'; +///Geofencing +const GET_GEO_ZONES = 'Services/Patients.svc/REST/GeoF_GetAllPoints'; +const LOG_GEO_ZONES = 'Services/Patients.svc/REST/GeoF_InsertPatientFileInfo'; + ///Doctor const GET_MY_DOCTOR = 'Services/Doctors.svc/REST/GetPatientDoctorAppointmentResult'; const GET_DOCTOR_PROFILE = 'Services/Doctors.svc/REST/GetDocProfiles'; diff --git a/lib/config/shared_pref_kay.dart b/lib/config/shared_pref_kay.dart index b79edb08..30d866de 100644 --- a/lib/config/shared_pref_kay.dart +++ b/lib/config/shared_pref_kay.dart @@ -20,3 +20,4 @@ const IS_VIBRATION = 'is_vibration'; const THEME_VALUE = 'is_vibration'; const MAIN_USER = 'main-user'; const PHARMACY_LAST_VISITED_PRODUCTS = 'last-visited'; +const HMG_GEOFENCES = 'hmg-geo-fences'; diff --git a/lib/core/model/geofencing/requests/GeoZonesRequestModel.dart b/lib/core/model/geofencing/requests/GeoZonesRequestModel.dart new file mode 100644 index 00000000..b807691e --- /dev/null +++ b/lib/core/model/geofencing/requests/GeoZonesRequestModel.dart @@ -0,0 +1,9 @@ +class GeoZonesRequestModel { + final String PatientID; + + GeoZonesRequestModel({this.PatientID}); + + Map toFlatMap() { + return {"PatientID": PatientID.toString()}; + } +} diff --git a/lib/core/model/geofencing/requests/LogGeoZoneRequestModel.dart b/lib/core/model/geofencing/requests/LogGeoZoneRequestModel.dart new file mode 100644 index 00000000..181dea37 --- /dev/null +++ b/lib/core/model/geofencing/requests/LogGeoZoneRequestModel.dart @@ -0,0 +1,10 @@ +class LogGeoZoneRequestModel { + final int PointsID; + final int GeoType; + + LogGeoZoneRequestModel({this.PointsID, this.GeoType}); + + Map toFlatMap() { + return {"PointsID": PointsID.toString(), "GeoType": GeoType.toString()}; + } +} diff --git a/lib/core/model/geofencing/responses/GeoZonesResponseModel.dart b/lib/core/model/geofencing/responses/GeoZonesResponseModel.dart new file mode 100644 index 00000000..58771fab --- /dev/null +++ b/lib/core/model/geofencing/responses/GeoZonesResponseModel.dart @@ -0,0 +1,62 @@ +import 'package:diplomaticquarterapp/generated/json/base/json_convert_content.dart'; +import 'package:diplomaticquarterapp/generated/json/base/json_field.dart'; + +class GeoZonesResponseModel with JsonConvert { + @JSONField(name: "GEOF_ID") + int geofId; + @JSONField(name: "Description") + String description; + @JSONField(name: "DescriptionN") + String descriptionN; + @JSONField(name: "Latitude") + String latitude; + @JSONField(name: "Longitude") + String longitude; + @JSONField(name: "Radius") + int radius; + @JSONField(name: "Type") + int type; + @JSONField(name: "ProjectID") + int projectID; + @JSONField(name: "ImageURL") + String imageURL; + @JSONField(name: "IsCity") + bool isCity; + + // Outside Server Response + bool isRegistered = false; + bool onEntry = true; + bool onExit = true; + + String geofenceId() { + return "$geofId\_${description.replaceAll(" ", "")}"; + } + + static get(String coordinates, int radius, String name) { + coordinates = coordinates.replaceAll(" ", ""); + var geo = GeoZonesResponseModel(); + geo.latitude = coordinates.split(",").first; + geo.longitude = coordinates.split(",").last; + geo.radius = radius; + geo.description = name; + return geo; + } + + static GeoZonesResponseModel zkH() { + var geo = GeoZonesResponseModel(); + geo.latitude = "24.691136"; + geo.longitude = "46.650116"; + geo.radius = 150; + geo.description = "zkH"; + return geo; + } + + static GeoZonesResponseModel csO() { + var geo = GeoZonesResponseModel(); + geo.latitude = "24.7087913"; + geo.longitude = "46.6656461"; + geo.radius = 150; + geo.description = "csO"; + return geo; + } +} diff --git a/lib/core/model/geofencing/responses/LogGeoZoneResponseModel.dart b/lib/core/model/geofencing/responses/LogGeoZoneResponseModel.dart new file mode 100644 index 00000000..2242755f --- /dev/null +++ b/lib/core/model/geofencing/responses/LogGeoZoneResponseModel.dart @@ -0,0 +1,26 @@ +import 'package:diplomaticquarterapp/generated/json/base/json_convert_content.dart'; +import 'package:diplomaticquarterapp/generated/json/base/json_field.dart'; + +class LogGeoZoneResponseModel with JsonConvert { + @JSONField(name: "LanguageID") + int languageID; + @JSONField(name: "ErrorCode") + dynamic errorCode; + @JSONField(name: "ErrorEndUserMessage") + String errorEndUserMessage; + @JSONField(name: "ErrorEndUserMessageN") + dynamic errorEndUserMessageN; + @JSONField(name: "ErrorMessage") + dynamic errorMessage; + @JSONField(name: "ErrorType") + int errorType; + @JSONField(name: "IsAuthenticated") + bool isAuthenticated; + @JSONField(name: "SuccessMsg") + dynamic successMsg; + @JSONField(name: "SuccessMsgN") + dynamic successMsgN; + int statusCode; + @JSONField(name: "MessageStatus") + int messageStatus; +} diff --git a/lib/core/service/geofencing/GeofencingServices.dart b/lib/core/service/geofencing/GeofencingServices.dart new file mode 100644 index 00000000..a40fa8ea --- /dev/null +++ b/lib/core/service/geofencing/GeofencingServices.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:diplomaticquarterapp/config/config.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/model/geofencing/responses/LogGeoZoneResponseModel.dart'; +import 'package:diplomaticquarterapp/core/service/base_service.dart'; + +import '../../../locator.dart'; + +class GeofencingServices extends BaseService { + List geoZones = List(); + + Future> getAllGeoZones(GeoZonesRequestModel request) async { + hasError = false; + await baseAppClient.post(GET_GEO_ZONES, onSuccess: (dynamic response, int statusCode) { + response['GeoF_PointsList'].forEach((json) { + geoZones.add(GeoZonesResponseModel().fromJson(json)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + return Future.error(error); + }, body: request.toFlatMap()); + return geoZones; + } + + LogGeoZoneResponseModel logResponse; + Future logMyGeoZone(LogGeoZoneRequestModel request) async { + hasError = false; + await baseAppClient.post(LOG_GEO_ZONES, onSuccess: (dynamic response, int statusCode) { + logResponse = LogGeoZoneResponseModel().fromJson(response); + }, onFailure: (String error, int statusCode) { + hasError = true; + return Future.error(error); + }, body: request.toFlatMap()); + return logResponse; + } +} diff --git a/lib/core/service/packages_offers/PackagesOffersServices.dart b/lib/core/service/packages_offers/PackagesOffersServices.dart index d75744b6..e58c3fa3 100644 --- a/lib/core/service/packages_offers/PackagesOffersServices.dart +++ b/lib/core/service/packages_offers/PackagesOffersServices.dart @@ -18,7 +18,6 @@ class OffersAndPackagesServices extends BaseService { hasError = false; var url = EXA_CART_API_BASE_URL + PACKAGES_CATEGORIES; await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { - log(stringResponse); if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['categories'].forEach((json) { @@ -37,7 +36,6 @@ class OffersAndPackagesServices extends BaseService { hasError = false; var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { - log(stringResponse); if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['products'].forEach((json) { diff --git a/lib/generated/json/GeoZonesResponseModel_helper.dart b/lib/generated/json/GeoZonesResponseModel_helper.dart new file mode 100644 index 00000000..7cf3cc5f --- /dev/null +++ b/lib/generated/json/GeoZonesResponseModel_helper.dart @@ -0,0 +1,50 @@ +import 'package:diplomaticquarterapp/core/model/geofencing/responses/GeoZonesResponseModel.dart'; + +geoZonesResponseModelEntityFromJson(GeoZonesResponseModel data, Map json) { + if (json['GEOF_ID'] != null) { + data.geofId = json['GEOF_ID']?.toInt(); + } + if (json['Description'] != null) { + data.description = json['Description']?.toString(); + } + if (json['DescriptionN'] != null) { + data.descriptionN = json['DescriptionN']?.toString(); + } + if (json['Latitude'] != null) { + data.latitude = json['Latitude']?.toString(); + } + if (json['Longitude'] != null) { + data.longitude = json['Longitude']?.toString(); + } + if (json['Radius'] != null) { + data.radius = json['Radius']?.toInt(); + } + if (json['Type'] != null) { + data.type = json['Type']?.toInt(); + } + if (json['ProjectID'] != null) { + data.projectID = json['ProjectID']?.toInt(); + } + if (json['ImageURL'] != null) { + data.imageURL = json['ImageURL']?.toString(); + } + if (json['IsCity'] != null) { + data.isCity = json['IsCity']; + } + return data; +} + +Map geoZonesResponseModelEntityToJson(GeoZonesResponseModel entity) { + final Map data = new Map(); + data['GEOF_ID'] = entity.geofId; + data['Description'] = entity.description; + data['DescriptionN'] = entity.descriptionN; + data['Latitude'] = entity.latitude; + data['Longitude'] = entity.longitude; + data['Radius'] = entity.radius; + data['Type'] = entity.type; + data['ProjectID'] = entity.projectID; + data['ImageURL'] = entity.imageURL; + data['IsCity'] = entity.isCity; + return data; +} diff --git a/lib/generated/json/offer_categories_response_model_entity_helper_.dart b/lib/generated/json/OfferCategoriesResponseModel_helper.dart similarity index 96% rename from lib/generated/json/offer_categories_response_model_entity_helper_.dart rename to lib/generated/json/OfferCategoriesResponseModel_helper.dart index 08d1c7f9..e5ebc914 100644 --- a/lib/generated/json/offer_categories_response_model_entity_helper_.dart +++ b/lib/generated/json/OfferCategoriesResponseModel_helper.dart @@ -1,6 +1,6 @@ import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferCategoriesResponseModel.dart'; -offerCategoriesResponseModelEntityFromJson(OfferCategoriesResponseModel data, Map json) { +offerCategoriesResponseModelFromJson(OfferCategoriesResponseModel data, Map json) { if (json['id'] != null) { data.id = json['id']?.toString(); } @@ -91,7 +91,7 @@ offerCategoriesResponseModelEntityFromJson(OfferCategoriesResponseModel data, Ma return data; } -Map offerCategoriesResponseModelEntityToJson(OfferCategoriesResponseModel entity) { +Map offerCategoriesResponseModelToJson(OfferCategoriesResponseModel entity) { final Map data = new Map(); data['id'] = entity.id; data['name'] = entity.name; diff --git a/lib/generated/json/OfferProductsResponseModel_helper_.dart b/lib/generated/json/OfferProductsResponseModel_helper.dart similarity index 100% rename from lib/generated/json/OfferProductsResponseModel_helper_.dart rename to lib/generated/json/OfferProductsResponseModel_helper.dart diff --git a/lib/generated/json/base/json_convert_content.dart b/lib/generated/json/base/json_convert_content.dart index fbec021d..9fab946e 100644 --- a/lib/generated/json/base/json_convert_content.dart +++ b/lib/generated/json/base/json_convert_content.dart @@ -4,9 +4,13 @@ // This file is automatically generated. DO NOT EDIT, all your changes would be lost. import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferCategoriesResponseModel.dart'; +import 'package:diplomaticquarterapp/generated/json/OfferCategoriesResponseModel_helper.dart'; +import 'package:diplomaticquarterapp/core/model/geofencing/responses/LogGeoZoneResponseModel.dart'; +import 'package:diplomaticquarterapp/generated/json/log_geo_zone_response_model_entity_helper.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferProductsResponseModel.dart'; -import 'package:diplomaticquarterapp/generated/json/offer_categories_response_model_entity_helper_.dart'; -import 'package:diplomaticquarterapp/generated/json/OfferProductsResponseModel_helper_.dart'; +import 'package:diplomaticquarterapp/generated/json/OfferProductsResponseModel_helper.dart'; +import 'package:diplomaticquarterapp/core/model/geofencing/responses/GeoZonesResponseModel.dart'; +import 'package:diplomaticquarterapp/generated/json/GeoZonesResponseModel_helper.dart'; class JsonConvert { T fromJson(Map json) { @@ -20,11 +24,13 @@ class JsonConvert { static _getFromJson(Type type, data, json) { switch (type) { case OfferCategoriesResponseModel: - return offerCategoriesResponseModelEntityFromJson(data as OfferCategoriesResponseModel, json) as T; + return offerCategoriesResponseModelFromJson(data as OfferCategoriesResponseModel, json) as T; case OfferCategoriesResponseModelLocalizedName: return offerCategoriesResponseModelLocalizedNameFromJson(data as OfferCategoriesResponseModelLocalizedName, json) as T; case OfferCategoriesResponseModelImage: return offerCategoriesResponseModelImageFromJson(data as OfferCategoriesResponseModelImage, json) as T; + case LogGeoZoneResponseModel: + return logGeoZoneResponseModelEntityFromJson(data as LogGeoZoneResponseModel, json) as T; case OfferProductsResponseModel: return offerProductsResponseModelFromJson(data as OfferProductsResponseModel, json) as T; case OfferProductsResponseModelLocalizedName: @@ -33,6 +39,8 @@ class JsonConvert { return offerProductsResponseModelImageFromJson(data as OfferProductsResponseModelImage, json) as T; case OfferProductsResponseModelSpecification: return offerProductsResponseModelSpecificationFromJson(data as OfferProductsResponseModelSpecification, json) as T; + case GeoZonesResponseModel: + return geoZonesResponseModelEntityFromJson(data as GeoZonesResponseModel, json) as T; } return data as T; } @@ -40,11 +48,13 @@ class JsonConvert { static _getToJson(Type type, data) { switch (type) { case OfferCategoriesResponseModel: - return offerCategoriesResponseModelEntityToJson(data as OfferCategoriesResponseModel); + return offerCategoriesResponseModelToJson(data as OfferCategoriesResponseModel); case OfferCategoriesResponseModelLocalizedName: return offerCategoriesResponseModelLocalizedNameToJson(data as OfferCategoriesResponseModelLocalizedName); case OfferCategoriesResponseModelImage: return offerCategoriesResponseModelImageToJson(data as OfferCategoriesResponseModelImage); + case LogGeoZoneResponseModel: + return logGeoZoneResponseModelEntityToJson(data as LogGeoZoneResponseModel); case OfferProductsResponseModel: return offerProductsResponseModelToJson(data as OfferProductsResponseModel); case OfferProductsResponseModelLocalizedName: @@ -53,6 +63,8 @@ class JsonConvert { return offerProductsResponseModelImageToJson(data as OfferProductsResponseModelImage); case OfferProductsResponseModelSpecification: return offerProductsResponseModelSpecificationToJson(data as OfferProductsResponseModelSpecification); + case GeoZonesResponseModel: + return geoZonesResponseModelEntityToJson(data as GeoZonesResponseModel); } return data as T; } @@ -66,6 +78,8 @@ class JsonConvert { return OfferCategoriesResponseModelLocalizedName().fromJson(json); } else if (type == (OfferCategoriesResponseModelImage).toString()) { return OfferCategoriesResponseModelImage().fromJson(json); + } else if (type == (LogGeoZoneResponseModel).toString()) { + return LogGeoZoneResponseModel().fromJson(json); } else if (type == (OfferProductsResponseModel).toString()) { return OfferProductsResponseModel().fromJson(json); } else if (type == (OfferProductsResponseModelLocalizedName).toString()) { @@ -74,6 +88,8 @@ class JsonConvert { return OfferProductsResponseModelImage().fromJson(json); } else if (type == (OfferProductsResponseModelSpecification).toString()) { return OfferProductsResponseModelSpecification().fromJson(json); + } else if (type == (GeoZonesResponseModel).toString()) { + return GeoZonesResponseModel().fromJson(json); } return null; } @@ -86,6 +102,8 @@ class JsonConvert { return data.map((e) => OfferCategoriesResponseModelLocalizedName().fromJson(e)).toList() as M; } else if (List() is M) { return data.map((e) => OfferCategoriesResponseModelImage().fromJson(e)).toList() as M; + } else if (List() is M) { + return data.map((e) => LogGeoZoneResponseModel().fromJson(e)).toList() as M; } else if (List() is M) { return data.map((e) => OfferProductsResponseModel().fromJson(e)).toList() as M; } else if (List() is M) { @@ -94,6 +112,8 @@ class JsonConvert { return data.map((e) => OfferProductsResponseModelImage().fromJson(e)).toList() as M; } else if (List() is M) { return data.map((e) => OfferProductsResponseModelSpecification().fromJson(e)).toList() as M; + } else if (List() is M) { + return data.map((e) => GeoZonesResponseModel().fromJson(e)).toList() as M; } return null; } diff --git a/lib/generated/json/log_geo_zone_response_model_entity_helper.dart b/lib/generated/json/log_geo_zone_response_model_entity_helper.dart new file mode 100644 index 00000000..28b8c996 --- /dev/null +++ b/lib/generated/json/log_geo_zone_response_model_entity_helper.dart @@ -0,0 +1,54 @@ +import 'package:diplomaticquarterapp/core/model/geofencing/responses/LogGeoZoneResponseModel.dart'; + +logGeoZoneResponseModelEntityFromJson(LogGeoZoneResponseModel data, Map json) { + if (json['LanguageID'] != null) { + data.languageID = json['LanguageID']?.toInt(); + } + if (json['ErrorCode'] != null) { + data.errorCode = json['ErrorCode']; + } + if (json['ErrorEndUserMessage'] != null) { + data.errorEndUserMessage = json['ErrorEndUserMessage']?.toString(); + } + if (json['ErrorEndUserMessageN'] != null) { + data.errorEndUserMessageN = json['ErrorEndUserMessageN']; + } + if (json['ErrorMessage'] != null) { + data.errorMessage = json['ErrorMessage']; + } + if (json['ErrorType'] != null) { + data.errorType = json['ErrorType']?.toInt(); + } + if (json['IsAuthenticated'] != null) { + data.isAuthenticated = json['IsAuthenticated']; + } + if (json['SuccessMsg'] != null) { + data.successMsg = json['SuccessMsg']; + } + if (json['SuccessMsgN'] != null) { + data.successMsgN = json['SuccessMsgN']; + } + if (json['statusCode'] != null) { + data.statusCode = json['statusCode']?.toInt(); + } + if (json['MessageStatus'] != null) { + data.messageStatus = json['MessageStatus']?.toInt(); + } + return data; +} + +Map logGeoZoneResponseModelEntityToJson(LogGeoZoneResponseModel entity) { + final Map data = new Map(); + data['LanguageID'] = entity.languageID; + data['ErrorCode'] = entity.errorCode; + data['ErrorEndUserMessage'] = entity.errorEndUserMessage; + data['ErrorEndUserMessageN'] = entity.errorEndUserMessageN; + data['ErrorMessage'] = entity.errorMessage; + data['ErrorType'] = entity.errorType; + data['IsAuthenticated'] = entity.isAuthenticated; + data['SuccessMsg'] = entity.successMsg; + data['SuccessMsgN'] = entity.successMsgN; + data['statusCode'] = entity.statusCode; + data['MessageStatus'] = entity.messageStatus; + return data; +} diff --git a/lib/locator.dart b/lib/locator.dart index 8916d08e..f00cc1f6 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -5,6 +5,7 @@ import 'package:diplomaticquarterapp/core/viewModels/child_vaccines/user_informa import 'package:diplomaticquarterapp/core/viewModels/AlHabibMedicalService/home_health_care_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/dashboard_view_model.dart'; import 'package:diplomaticquarterapp/uitl/navigation_service.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get_it/get_it.dart'; import 'core/service/AlHabibMedicalService/cmc_service.dart'; @@ -25,6 +26,7 @@ import 'core/service/dashboard_service.dart'; import 'core/service/er/am_service.dart'; import 'core/service/er/er_service.dart'; import 'core/service/feedback/feedback_service.dart'; +import 'core/service/geofencing/GeofencingServices.dart'; import 'core/service/hospital_service.dart'; import 'core/service/medical/ActiveMedicationsService.dart'; import 'core/service/medical/AllergiesService.dart'; @@ -95,6 +97,9 @@ GetIt locator = GetIt.instance; ///di void setupLocator() { + /// Others + locator.registerLazySingleton(() => FlutterLocalNotificationsPlugin()); + /// Services locator.registerLazySingleton(() => AuthenticatedUserObject()); locator.registerLazySingleton(() => HospitalService()); @@ -195,4 +200,8 @@ void setupLocator() { locator.registerLazySingleton(() => OffersAndPackagesServices()); // offerPackagesServices Service locator.registerFactory(() => OfferCategoriesViewModel()); // Categories View Model locator.registerFactory(() => OfferProductsViewModel()); // Products View Model + + // Geofencing + // --------------------- + locator.registerLazySingleton(() => GeofencingServices()); // Geofencing Services } diff --git a/lib/main.dart b/lib/main.dart index 83492d81..54cc5040 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:diplomaticquarterapp/routes.dart'; 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/PlatformBridge.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:flutter/material.dart'; @@ -12,6 +13,8 @@ import 'package:hexcolor/hexcolor.dart'; import 'package:provider/provider.dart'; import 'config/size_config.dart'; +import 'core/model/geofencing/requests/GeoZonesRequestModel.dart'; +import 'core/service/geofencing/GeofencingServices.dart'; import 'core/viewModels/project_view_model.dart'; import 'locator.dart'; @@ -25,6 +28,11 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { PlatformBridge.init(context); + var geofence = HMG_Geofence(context); + locator().getAllGeoZones(GeoZonesRequestModel(PatientID: "1231755")).then((value) { + geofence.initiate(value); + }).catchError((e) {}); + return LayoutBuilder( builder: (context, constraints) { return OrientationBuilder( diff --git a/lib/pages/landing/home_page.dart b/lib/pages/landing/home_page.dart index 745733b2..79d462b5 100644 --- a/lib/pages/landing/home_page.dart +++ b/lib/pages/landing/home_page.dart @@ -1,6 +1,10 @@ import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/core/model/geofencing/requests/GeoZonesRequestModel.dart'; +import 'package:diplomaticquarterapp/core/model/geofencing/requests/LogGeoZoneRequestModel.dart'; +import 'package:diplomaticquarterapp/core/service/geofencing/GeofencingServices.dart'; import 'package:diplomaticquarterapp/core/viewModels/dashboard_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; +import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/ComprehensiveMedicalCheckup/cmc_index_page.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/HomeHealthCare/home_health_care_index_page.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/all_habib_medical_service_page.dart'; @@ -11,6 +15,7 @@ import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/pages/livecare/livecare_home.dart'; import 'package:diplomaticquarterapp/pages/paymentService/payment_service.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/pharmacy_module_page.dart'; +import 'package:diplomaticquarterapp/uitl/HMG_Geofence.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; @@ -37,6 +42,7 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); + return BaseView( onModelReady: (model) => model.getPatientRadOrders(), builder: (_, model, wi) => AppScaffold( diff --git a/lib/uitl/HMG_Geofence.dart b/lib/uitl/HMG_Geofence.dart new file mode 100644 index 00000000..b17d9269 --- /dev/null +++ b/lib/uitl/HMG_Geofence.dart @@ -0,0 +1,120 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:ui'; + +import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/core/model/geofencing/responses/GeoZonesResponseModel.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 { + 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(); + ReceivePort port = ReceivePort(); + + HMG_Geofence(this.context) { + triggers.add(GeofenceEvent.enter); + triggers.add(GeofenceEvent.exit); + // triggers.add(GeofenceEvent.dwell); + } + + void initiate(List zones) async { + _zones = zones; + + if (kDebugMode) { + // debug check + addTestingGeofences(); + } + _saveZones(); + await GeofencingManager.initialize(); + await Future.delayed(Duration(seconds: 2)); + _registerIsolatePort(); + _registerGeofences().then((value) { + debugPrint(value.toString()); + }); + } + + 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) async { + id.forEach((element) { + final SendPort send = IsolateNameServer.lookupPortByName(_isolatePortName); + send?.send(event.toString()); + }); + } + + void _registerIsolatePort() { + IsolateNameServer.registerPortWithName(port.sendPort, _isolatePortName); + AppSharedPreferences pref = AppSharedPreferences(); + var jsonString = pref.getString(HMG_GEOFENCES); + List jsonList = json.decode(jsonString); + jsonList.forEach((element) { + + }) + + port.listen((dynamic data) { + LocalNotification.showNow( + title: "HMG-Geofence", + subtitle: element, + onClickNotification: (payload) { + debugPrint(payload); + }, + payload: "Zohaib Kambrani"); + }); + } +} diff --git a/lib/uitl/LocalNotification.dart b/lib/uitl/LocalNotification.dart index 5b826f00..43cb598a 100644 --- a/lib/uitl/LocalNotification.dart +++ b/lib/uitl/LocalNotification.dart @@ -1,17 +1,31 @@ +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(); +final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); class LocalNotification { - static Future scheduleNotification( - {@required DateTime scheduledNotificationDateTime, - @required String title, - @required String description}) async { + static Future showNow({@required String title, @required String subtitle, String payload, Function(String payload) onClickNotification}) { + var plugin = FlutterLocalNotificationsPlugin(); + var initializationSettingsAndroid = new AndroidInitializationSettings('app_icon'); + var initializationSettingsIOS = IOSInitializationSettings(onDidReceiveLocalNotification: null); + var initializationSettings = InitializationSettings(initializationSettingsAndroid, initializationSettingsIOS); + plugin.initialize(initializationSettings, onSelectNotification: onClickNotification); + + var rng = new Random(); + Future.delayed(Duration(seconds: 1)).then((result) async { + var androidPlatformChannelSpecifics = AndroidNotificationDetails('com.hmg', 'HMG', 'HMG', importance: Importance.Max, priority: Priority.High, ticker: 'ticker'); + var iOSPlatformChannelSpecifics = IOSNotificationDetails(); + var platformChannelSpecifics = NotificationDetails(androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); + await flutterLocalNotificationsPlugin.show(rng.nextInt(100000), title, subtitle, platformChannelSpecifics, payload: payload); + }); + } + + static Future scheduleNotification({@required DateTime scheduledNotificationDateTime, @required String title, @required String description}) async { ///vibrationPattern var vibrationPattern = Int64List(4); vibrationPattern[0] = 0; @@ -19,10 +33,7 @@ class LocalNotification { vibrationPattern[2] = 5000; vibrationPattern[3] = 2000; - var androidPlatformChannelSpecifics = AndroidNotificationDetails( - 'active-prescriptions', - 'ActivePrescriptions', - 'ActivePrescriptionsDescription', + var androidPlatformChannelSpecifics = AndroidNotificationDetails('active-prescriptions', 'ActivePrescriptions', 'ActivePrescriptionsDescription', // icon: 'secondary_icon', sound: RawResourceAndroidNotificationSound('slow_spring_board'), @@ -34,8 +45,7 @@ class LocalNotification { ledColor: const Color.fromARGB(255, 255, 0, 0), ledOnMs: 1000, ledOffMs: 500); - var iOSPlatformChannelSpecifics = - IOSNotificationDetails(sound: 'slow_spring_board.aiff'); + var iOSPlatformChannelSpecifics = IOSNotificationDetails(sound: 'slow_spring_board.aiff'); ///change it to be as ionic // var platformChannelSpecifics = NotificationDetails( @@ -47,10 +57,7 @@ class LocalNotification { ///Repeat notification every day at approximately 10:00:00 am static Future showDailyAtTime() async { var time = Time(10, 0, 0); - var androidPlatformChannelSpecifics = AndroidNotificationDetails( - 'repeatDailyAtTime channel id', - 'repeatDailyAtTime channel name', - 'repeatDailyAtTime description'); + var androidPlatformChannelSpecifics = AndroidNotificationDetails('repeatDailyAtTime channel id', 'repeatDailyAtTime channel name', 'repeatDailyAtTime description'); var iOSPlatformChannelSpecifics = IOSNotificationDetails(); // var platformChannelSpecifics = NotificationDetails( // androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); @@ -65,10 +72,7 @@ class LocalNotification { ///Repeat notification weekly on Monday at approximately 10:00:00 am static Future showWeeklyAtDayAndTime() async { var time = Time(10, 0, 0); - var androidPlatformChannelSpecifics = AndroidNotificationDetails( - 'show weekly channel id', - 'show weekly channel name', - 'show weekly description'); + var androidPlatformChannelSpecifics = AndroidNotificationDetails('show weekly channel id', 'show weekly channel name', 'show weekly description'); var iOSPlatformChannelSpecifics = IOSNotificationDetails(); // var platformChannelSpecifics = NotificationDetails( // androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); diff --git a/pubspec.yaml b/pubspec.yaml index 4a9206e0..a4129776 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -162,6 +162,7 @@ dependencies: # Dep by Zohaib shimmer: ^1.1.2 + geofencing: ^0.1.0 dev_dependencies: flutter_test: