From bd10bb4f1d036980d3309781249f53bd04e50422 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 8 Jan 2023 16:43:09 +0300 Subject: [PATCH 1/2] Push notifications handler implemented --- lib/api/chat/chat_api_client.dart | 2 + lib/app_state/app_state.dart | 6 ++ lib/classes/push-notification-handler.dart | 59 +++++++++++++++++++ lib/ui/login/login_screen.dart | 9 ++- .../widgets/marathon_details_card.dart | 2 +- lib/widgets/mark_attendance_widget.dart | 9 +++ 6 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 lib/classes/push-notification-handler.dart diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart index 87e684e..c4bba3a 100644 --- a/lib/api/chat/chat_api_client.dart +++ b/lib/api/chat/chat_api_client.dart @@ -30,6 +30,8 @@ class ChatApiClient { { "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", + "isMobile": true, + "deviceToken": AppState().getDeviceToken, }, ); if (!kReleaseMode) { diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index e43c774..b3a4a32 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -17,6 +17,12 @@ class AppState { factory AppState() => _instance; + String? deviceToken = ""; + + set setDeviceToken(v) => deviceToken = v; + + String? get getDeviceToken => deviceToken; + bool isAuthenticated = false; set setIsAuthenticated(v) => isAuthenticated = v; diff --git a/lib/classes/push-notification-handler.dart b/lib/classes/push-notification-handler.dart new file mode 100644 index 0000000..b95ceb2 --- /dev/null +++ b/lib/classes/push-notification-handler.dart @@ -0,0 +1,59 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; + +// |--> Push Notification Background +Future backgroundMessageHandler(message) async { + print("Firebase backgroundMessageHandler!!!"); +} + +class PushNotificationHandler { + final BuildContext context; + static PushNotificationHandler? _instance; + + PushNotificationHandler(this.context) { + PushNotificationHandler._instance = this; + } + + static PushNotificationHandler getInstance() => _instance!; + + void init() async { + FirebaseMessaging.onMessage.listen((RemoteMessage message) async { + if (Platform.isIOS) { + await Future.delayed(Duration(milliseconds: 3000)).then((value) { + newMessage(message); + }); + } else { + newMessage(message); + } + }); + + FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async { + if (Platform.isIOS) { + await Future.delayed(Duration(milliseconds: 3000)).then((value) { + newMessage(message); + }); + } else { + newMessage(message); + } + }); + + FirebaseMessaging.instance.onTokenRefresh.listen((fcm_token) { + print("Push Notification onTokenRefresh: " + fcm_token); + AppState().setDeviceToken = fcm_token; + }); + + FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); + } + + void newMessage(RemoteMessage remoteMessage) async { + print("Remote Message: " + remoteMessage.data.toString()); + if (remoteMessage.data.isEmpty) { + return; + } + } +} diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 7ba82e4..26e9f3e 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:mohem_flutter_app/classes/push-notification-handler.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; @@ -91,8 +92,15 @@ class _LoginScreenState extends State { try { Utils.showLoading(context); await Firebase.initializeApp(); + await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( + alert: true, + badge: true, + sound: true, + ); + PushNotificationHandler(context).init(); _firebaseMessaging = FirebaseMessaging.instance; firebaseToken = await _firebaseMessaging.getToken(); + AppState().setDeviceToken = firebaseToken; loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); if (loginInfo == null) { await checkPrefs(); @@ -171,7 +179,6 @@ class _LoginScreenState extends State { } if (isAppOpenBySystem!) checkFirebaseToken(); } - // username.text = "15444"; return Scaffold( diff --git a/lib/ui/marathon/widgets/marathon_details_card.dart b/lib/ui/marathon/widgets/marathon_details_card.dart index dda7ef8..267d2d3 100644 --- a/lib/ui/marathon/widgets/marathon_details_card.dart +++ b/lib/ui/marathon/widgets/marathon_details_card.dart @@ -57,7 +57,7 @@ class MarathonDetailsCard extends StatelessWidget { children: marathonDetailModel.sponsors!.first.sponsorPrizes! .map( (SponsorPrizes prizes) => - "${AppState().isArabic(context) ? prizes.marathonPrizeAr : prizes.marathonPrizeAr}".toText16(color: MyColors.greenColor, isBold: true).paddingOnly(right: 5), + "${AppState().isArabic(context) ? prizes.marathonPrizeAr : prizes.marathonPrizeEn}".toText16(color: MyColors.greenColor, isBold: true).paddingOnly(right: 5), ) .toList(), ), diff --git a/lib/widgets/mark_attendance_widget.dart b/lib/widgets/mark_attendance_widget.dart index dfe3b79..59681b7 100644 --- a/lib/widgets/mark_attendance_widget.dart +++ b/lib/widgets/mark_attendance_widget.dart @@ -218,6 +218,15 @@ class _MarkAttendanceWidgetState extends State { Utils.showLoading(context); bool isConnected = await WiFiForIoTPlugin.connect(AppState().getMohemmWifiSSID ?? "", password: AppState().getMohemmWifiPassword ?? "", joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false); + // + // print("CURRENT SSID: ${await WiFiForIoTPlugin.getSSID()}"); + + if (await WiFiForIoTPlugin.getSSID() == AppState().getMohemmWifiSSID) { + isConnected = true; + } else { + isConnected = false; + } + if (isConnected) { if (Platform.isIOS) { await closeWifiRequest(); From a9bf383164c68fa7fecddcdf7993ab68108a267a Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 18 Jan 2023 12:53:43 +0300 Subject: [PATCH 2/2] Updates & fixes --- android/app/build.gradle | 22 ++++++++++++++----- android/app/src/main/AndroidManifest.xml | 1 + ios/Runner/Info.plist | 16 ++++++++------ .../items_for_sale_api_client.dart | 2 +- lib/api/offers_and_discounts_api_client.dart | 2 +- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 4 ++-- lib/ui/login/login_screen.dart | 9 ++++++++ lib/widgets/mark_attendance_widget.dart | 12 +++++----- pubspec.yaml | 4 ++-- 10 files changed, 49 insertions(+), 25 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 9cd8b0e..198bc87 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -21,6 +21,12 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'com.google.gms.google-services' @@ -44,18 +50,24 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.cloudSolutions.mohemmtest" + applicationId "hmg.cloudSolutions.mohem" minSdkVersion 21 - targetSdkVersion 32 + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } buildTypes { release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig signingConfigs.release } } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 30555e1..bd112a0 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + CFBundleInfoDictionaryVersion 6.0 CFBundleName - mohem_flutter_app + MOHEMM CFBundlePackageType APPL CFBundleShortVersionString @@ -42,10 +42,10 @@ This App requires access to your location to mark your attendance. NSLocationWhenInUseUsageDescription This App requires access to your location to mark your attendance. - NSPhotoLibraryUsageDescription - This app requires photo library access to select image as document & upload it. NSMicrophoneUsageDescription This app requires microphone access to for call. + NSPhotoLibraryUsageDescription + This app requires photo library access to select image as document & upload it. UIBackgroundModes remote-notification @@ -69,13 +69,15 @@ UIViewControllerBasedStatusBarAppearance - com.apple.developer.nfc.readersession.formats - - TAG - com.apple.developer.nfc.readersession.felica.systemcodes 0000 + ITSAppUsesNonExemptEncryption + + com.apple.developer.nfc.readersession.formats + + TAG + diff --git a/lib/api/items_for_sale/items_for_sale_api_client.dart b/lib/api/items_for_sale/items_for_sale_api_client.dart index eae6ffb..a04651e 100644 --- a/lib/api/items_for_sale/items_for_sale_api_client.dart +++ b/lib/api/items_for_sale/items_for_sale_api_client.dart @@ -32,7 +32,7 @@ class ItemsForSaleApiClient { getSaleCategoriesListObj.titleAr = "الجميع"; getSaleCategoriesListObj.isActive = true; getSaleCategoriesListObj.content = - ''; + ' '; getSaleCategoriesList.add(getSaleCategoriesListObj); diff --git a/lib/api/offers_and_discounts_api_client.dart b/lib/api/offers_and_discounts_api_client.dart index 6189612..1d3153c 100644 --- a/lib/api/offers_and_discounts_api_client.dart +++ b/lib/api/offers_and_discounts_api_client.dart @@ -30,7 +30,7 @@ class OffersAndDiscountsApiClient { getSaleCategoriesListObj.categoryNameAr = "الجميع"; getSaleCategoriesListObj.isActive = true; getSaleCategoriesListObj.content = - ''; + ' '; getSaleCategoriesList.add(getSaleCategoriesListObj); diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index b3a4a32..6f4e698 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -76,7 +76,7 @@ class AppState { bool get getIsDemoMarathon => _isDemoMarathon; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 3.8, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 3.9, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 6679cbb..56b0008 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,8 +3,8 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server - // static String baseUrl = "https://hmgwebservices.com"; // Live server + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server + static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 26e9f3e..0d14e99 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -26,6 +26,7 @@ import 'package:mohem_flutter_app/models/member_login_list_model.dart'; import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:safe_device/safe_device.dart'; class LoginScreen extends StatefulWidget { @@ -92,6 +93,14 @@ class _LoginScreenState extends State { try { Utils.showLoading(context); await Firebase.initializeApp(); + if(Platform.isIOS) { + await FirebaseMessaging.instance.requestPermission(); + } else { + await Permission.notification.request().then((value) { + }).catchError((err) { + print(err); + }); + } await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: true, badge: true, diff --git a/lib/widgets/mark_attendance_widget.dart b/lib/widgets/mark_attendance_widget.dart index 59681b7..6b89c42 100644 --- a/lib/widgets/mark_attendance_widget.dart +++ b/lib/widgets/mark_attendance_widget.dart @@ -218,13 +218,13 @@ class _MarkAttendanceWidgetState extends State { Utils.showLoading(context); bool isConnected = await WiFiForIoTPlugin.connect(AppState().getMohemmWifiSSID ?? "", password: AppState().getMohemmWifiPassword ?? "", joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false); - // - // print("CURRENT SSID: ${await WiFiForIoTPlugin.getSSID()}"); - if (await WiFiForIoTPlugin.getSSID() == AppState().getMohemmWifiSSID) { - isConnected = true; - } else { - isConnected = false; + if (Platform.isIOS) { + if (await WiFiForIoTPlugin.getSSID() == AppState().getMohemmWifiSSID) { + isConnected = true; + } else { + isConnected = false; + } } if (isConnected) { diff --git a/pubspec.yaml b/pubspec.yaml index 3167dcd..db3f4ed 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.6.0+300060 +version: 3.2.0+300020 environment: sdk: ">=2.16.0 <3.0.0" @@ -40,7 +40,7 @@ dependencies: provider: ^6.0.1 easy_localization: ^3.0.0 http: ^0.13.4 - permission_handler: ^9.2.0 + permission_handler: ^10.2.0 flutter_svg: any sizer: ^2.0.15 local_auth: ^1.1.9