diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 0b8b7998..1032b29b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -26,6 +26,9 @@ + + + - + + + + + + diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiver.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiver.kt index e9accb04..8fc1faae 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiver.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiver.kt @@ -1,32 +1,4 @@ -/* - * Copyright (c) 2018 Razeware LLC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, - * distribute, sublicense, create a derivative work, and/or sell copies of the - * Software in any work that is designed, intended, or marketed for pedagogical or - * instructional purposes related to programming, coding, application development, - * or information technology. Permission for such use, copying, modification, - * merger, publication, distribution, sublicensing, creation of derivative works, - * or sale is expressly withheld. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ + package com.cloud.diplomaticquarterapp.geofence diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceErrorMessages.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceErrorMessages.kt index e85c7ea3..4890f7cb 100755 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceErrorMessages.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceErrorMessages.kt @@ -1,32 +1,4 @@ -/* - * Copyright (c) 2018 Razeware LLC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, - * distribute, sublicense, create a derivative work, and/or sell copies of the - * Software in any work that is designed, intended, or marketed for pedagogical or - * instructional purposes related to programming, coding, application development, - * or information technology. Permission for such use, copying, modification, - * merger, publication, distribution, sublicensing, creation of derivative works, - * or sale is expressly withheld. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ + package com.cloud.diplomaticquarterapp.geofence diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt index 641e1522..08a0c93f 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt @@ -1,21 +1,27 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -package io.flutter.plugins.geofencing + +package com.cloud.diplomaticquarterapp.geofence import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.util.Log +import android.os.Handler +import android.os.Message import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence +import com.cloud.diplomaticquarterapp.utils.HMGUtils -class GeofencingRebootBroadcastReceiver : BroadcastReceiver() { +class GeofencingRebootBroadcastReceiver : BroadcastReceiver(){ override fun onReceive(context: Context, intent: Intent) { - if (intent.action.equals("android.intent.action.BOOT_COMPLETED")) { + + if (Intent.ACTION_BOOT_COMPLETED.equals(intent.action)) { + val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE) + pref.edit().putString("REBOOT_DETECTED","YES").apply() + HMG_Geofence.shared(context).unRegisterAll { status, exception -> - HMG_Geofence.shared(context).re + val geoZones = HMGUtils.getGeoZonesFromPreference(context) + HMG_Geofence.shared(context).register(geoZones) } } } + } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/HMG_Geofence.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/HMG_Geofence.kt index fbef8749..4d2c48b3 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/HMG_Geofence.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/HMG_Geofence.kt @@ -36,6 +36,7 @@ enum class GeofenceTransition(val value: Int) { const val PREFS_STORAGE = "FlutterSharedPreferences" const val PREF_KEY_SUCCESS = "HMG_GEOFENCE_SUCCESS" const val PREF_KEY_FAILED = "HMG_GEOFENCE_FAILED" +const val PREF_KEY_HMG_ZONES = "flutter.hmg-geo-fences" class HMG_Geofence { // https://developer.android.com/training/location/geofencing#java @@ -69,6 +70,8 @@ class HMG_Geofence { } fun register(geoZones: List){ + if (geoZones.isEmpty()) + return fun buildGeofencingRequest(geofences: List): GeofencingRequest { return GeofencingRequest.Builder() @@ -92,7 +95,7 @@ class HMG_Geofence { geofencingClient .addGeofences(buildGeofencingRequest(geofences), geofencePendingIntent) .addOnSuccessListener { - saveGeofenceResults(geofences.map { it.requestId }, listOf()) + saveActiveGeofence(geofences.map { it.requestId }, listOf()) } .addOnFailureListener { print(it.localizedMessage) @@ -103,6 +106,8 @@ class HMG_Geofence { fun unRegisterAll(completion: (status: Boolean, exception:Exception?) -> Unit){ getActiveGeofences({ success -> + val mList = success.toMutableList() + mList.add("12345") geofencingClient .removeGeofences(success) .addOnSuccessListener { @@ -111,17 +116,22 @@ class HMG_Geofence { .addOnFailureListener { completion(false, it) } + removeActiveGeofences() }, { failed -> // Nothing to do with failed geofences. }) } - fun saveGeofenceResults(success: List, failed: List){ + fun saveActiveGeofence(success: List, failed: List){ val jsonSuccess = gson.toJson(success) val jsonFailure = gson.toJson(failed) preferences.edit().putString(PREF_KEY_SUCCESS, jsonSuccess).apply() preferences.edit().putString(PREF_KEY_FAILED, jsonFailure).apply() + } + fun removeActiveGeofences(){ + preferences.edit().putString(PREF_KEY_SUCCESS,"[]").apply() + preferences.edit().putString(PREF_KEY_FAILED,"[]").apply() } fun getActiveGeofences(success: (success: List) -> Unit, failure: ((failed: List) -> Unit)?){ @@ -144,7 +154,7 @@ class HMG_Geofence { } fun getPatientID():Int?{ - val profileJson = preferences.getString("flutter.user-profile", "{}") + val profileJson = preferences.getString("flutter.imei-user-data", "{}") val type = object : TypeToken?>() {}.type return gson.fromJson?>(profileJson,type) ?.get("PatientID") diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt index 5b0201f2..bebd0101 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt @@ -13,8 +13,12 @@ import androidx.core.app.TaskStackBuilder import com.cloud.diplomaticquarterapp.BuildConfig import com.cloud.diplomaticquarterapp.MainActivity import com.cloud.diplomaticquarterapp.R +import com.cloud.diplomaticquarterapp.geofence.GeoZoneModel +import com.cloud.diplomaticquarterapp.geofence.PREFS_STORAGE +import com.cloud.diplomaticquarterapp.geofence.PREF_KEY_HMG_ZONES import com.github.kittinunf.fuel.core.extensions.jsonBody import com.github.kittinunf.fuel.httpPost +import com.google.android.gms.location.Geofence import com.google.gson.Gson import com.google.gson.reflect.TypeToken import io.flutter.plugin.common.MethodChannel @@ -64,6 +68,14 @@ class HMGUtils { } } + fun getGeoZonesFromPreference(context: Context):List{ + val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE) + val json = pref.getString(PREF_KEY_HMG_ZONES,"[]") + + val geoZones = GeoZoneModel().listFrom(json) + return geoZones + } + } } diff --git a/lib/core/service/geofencing/GeofencingServices.dart b/lib/core/service/geofencing/GeofencingServices.dart index e8308480..56b4f56e 100644 --- a/lib/core/service/geofencing/GeofencingServices.dart +++ b/lib/core/service/geofencing/GeofencingServices.dart @@ -38,6 +38,7 @@ class GeofencingServices extends BaseService { AppSharedPreferences pref = AppSharedPreferences(); await pref.setString(HMG_GEOFENCES, _zonesJsonString); + debugPrint("Finished Fetching GEO ZONES from HMG service..."); debugPrint("GEO ZONES saved to AppPreferences with key '$HMG_GEOFENCES'"); return geoZones; diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index a1750536..24d3b590 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -1,9 +1,12 @@ +import 'dart:convert'; import 'dart:io'; 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'; @@ -16,7 +19,11 @@ import 'package:diplomaticquarterapp/pages/medical/medical_profile_page.dart'; 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'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/bottom_navigation/bottom_nav_bar.dart'; import 'package:diplomaticquarterapp/widgets/buttons/floatingActionButton.dart'; @@ -44,24 +51,22 @@ class LandingPage extends StatefulWidget { } class _LandingPageState extends State with WidgetsBindingObserver { + var authProvider = new AuthProvider(); + int currentTab = 0; PageController pageController; - ProjectViewModel projectProvider; + ProjectViewModel projectViewModel; var notificationCount = ''; ///inject the user data - AuthenticatedUserObject authenticatedUserObject = - locator(); + AuthenticatedUserObject authenticatedUserObject = locator(); final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); final authService = new AuthProvider(); var event = RobotProvider(); void _requestIOSPermissions() { - flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation< - IOSFlutterLocalNotificationsPlugin>() - ?.requestPermissions( + flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions( alert: true, badge: true, sound: true, @@ -96,12 +101,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { if (LandingPage.isOpenCallPage) { if (!isPageNavigated) { isPageNavigated = true; - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => IncomingCall( - incomingCallData: LandingPage.incomingCallData))) - .then((value) { + Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) { isPageNavigated = false; }); } @@ -127,6 +127,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { @override void initState() { super.initState(); + WidgetsBinding.instance.addObserver(this); //setState(() { AppGlobal.context = context; @@ -135,20 +136,35 @@ 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)}); + }).checkAndConnectIfNoInternet(); + if (Platform.isIOS) { _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.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.location].isGranted) ; + 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) ; }); + // // //_firebase Background message handler // _firebaseMessaging.configure( @@ -269,18 +285,14 @@ class _LandingPageState extends State with WidgetsBindingObserver { showDialogs(String message) { ConfirmDialog dialog = new ConfirmDialog( - context: context, - confirmMessage: message, - okText: TranslationBase.of(context).confirm, - cancelText: TranslationBase.of(context).cancel_nocaps, - okFunction: () => {}, - cancelFunction: () => {}); + context: context, confirmMessage: message, okText: TranslationBase.of(context).confirm, cancelText: TranslationBase.of(context).cancel_nocaps, okFunction: () => {}, cancelFunction: () => {}); dialog.showAlertDialog(context); } - void requestPermissions() async { - await [ + Future> requestPermissions() async { + var permissionResults = [ Permission.location, + Permission.locationAlways, Permission.storage, Permission.camera, Permission.photos, @@ -292,63 +304,24 @@ class _LandingPageState extends State with WidgetsBindingObserver { var permissionsGranted = await deviceCalendarPlugin.hasPermissions(); if (permissionsGranted.isSuccess && !permissionsGranted.data) { permissionsGranted = await deviceCalendarPlugin.requestPermissions(); - if (!permissionsGranted.isSuccess || !permissionsGranted.data) { - return; - } + if (!permissionsGranted.isSuccess || !permissionsGranted.data) {} } - } - - 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); + return permissionResults; } @override Widget build(BuildContext context) { - ProjectViewModel projectViewModel = Provider.of(context); + projectViewModel = Provider.of(context); return Scaffold( appBar: AppBar( elevation: 0, textTheme: TextTheme( - headline6: - TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + headline6: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), ), title: Text( getText(currentTab).toUpperCase(), - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.white, - fontFamily: projectViewModel.isArabic ? 'Cairo' : 'WorkSans'), + style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontFamily: projectViewModel.isArabic ? 'Cairo' : 'WorkSans'), // bold: true, // color: Colors.white, ), @@ -379,7 +352,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { notificationCount, style: new TextStyle( color: Colors.white, - fontSize: projectViewModel.isArabic ? 8 : 9, + fontSize: projectViewModel.isArabic ? 8 : 9, ), textAlign: TextAlign.center, ), @@ -462,28 +435,25 @@ class _LandingPageState extends State with WidgetsBindingObserver { } void checkUserStatus(token) async { - authService + var result = await authService .selectDeviceImei(token) - .then((SelectDeviceIMEIRES value) => setUserValues(value)); + ; + setUserValues(result); + registerGeofences(); if (await sharedPref.getObject(USER_PROFILE) != null) { - var data = - AuthenticatedUser.fromJson(await sharedPref.getObject(USER_PROFILE)); + var data = AuthenticatedUser.fromJson(await sharedPref.getObject(USER_PROFILE)); if (data != null) { - authService - .registeredAuthenticatedUser(data, token, 0, 0) - .then((res) => {print(res)}); + authService.registeredAuthenticatedUser(data, token, 0, 0).then((res) => {print(res)}); authService.getDashboard().then((value) => { setState(() { - notificationCount = value['List_PatientDashboard'] - [0]['UnreadPatientNotificationCount'].toString(); + notificationCount = value['List_PatientDashboard'][0]['UnreadPatientNotificationCount'].toString(); }) }); } } } - static Future myBackgroundMessageHandler( - Map message) async { + static Future myBackgroundMessageHandler(Map message) async { Map myMap = new Map.from(message['data']); if (message.containsKey('data')) { print("myBackgroundMessageHandler Inside"); @@ -499,7 +469,12 @@ class _LandingPageState extends State with WidgetsBindingObserver { } void setUserValues(value) async { - sharedPref.setObject(IMEI_USER_DATA, value); + if (value != null) sharedPref.setObject(IMEI_USER_DATA, value); + } + + Future getUserInformation() async { + var userInfoJson = sharedPref.getObject(IMEI_USER_DATA); + return userInfoJson; } checkValue(projectProvider) { @@ -507,4 +482,26 @@ class _LandingPageState extends State with WidgetsBindingObserver { _changeCurrentTab(2); } } + + registerGeofences() async { + await locator().getAllGeoZones(GeoZonesRequestModel()); + + void doIt() { + getUserInformation().then((value) { + if (value != null) projectViewModel.platformBridge().registerHmgGeofences(); + }); + } + + if (await Permission.location.isGranted) { + doIt(); + } else { + [Permission.location].request().then((value) async { + if (await Permission.location.isGranted) { + doIt(); + } + }); + } + + requestPermissions().then((results) {}); + } }