From 58f5fbab5e00147a52b59bbf7f9070216ea91cde Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 15 Feb 2024 16:38:42 +0300 Subject: [PATCH] push notifications added. --- android/app/proguard-rules.pro | 2 +- .../firebase_notification_manger.dart | 85 ++++++++++++++----- .../notification/notification_manger.dart | 75 +++++++++------- lib/main.dart | 1 + lib/models/system_notification_model.dart | 19 +++++ .../recent_activites_fragment.dart | 4 +- .../pages/land_page/dashboard_page.dart | 20 ++++- lib/new_views/pages/splash_page.dart | 32 +++++-- .../notifications/notifications_list.dart | 4 +- .../work_order/work_orders_list_page.dart | 1 - 10 files changed, 180 insertions(+), 63 deletions(-) diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index f8768e4b..6f22e90b 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -9,7 +9,7 @@ # Gson specific classes -dontwarn sun.misc.** #-keep class com.google.gson.stream.** { *; } - +-keep class com.dexterous.** { *; } # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory, # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) -keep class * extends com.google.gson.TypeAdapter diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index c82dc586..58bd71d3 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -1,6 +1,22 @@ +import 'dart:convert'; + import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; +import 'package:test_sa/controllers/notification/notification_manger.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/device/asset_transfer.dart'; +import 'package:test_sa/models/new_models/gas_refill_model.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/models/system_notification_model.dart'; +import 'package:test_sa/views/pages/device_transfer/device_transfer_details.dart'; +import 'package:test_sa/views/pages/user/gas_refill/gas_refill_details.dart'; +import 'package:test_sa/views/pages/user/ppm/ppm_details_page.dart'; +import 'package:test_sa/views/pages/user/requests/service_request_details.dart'; + +@pragma('vm:entry-point') +Future firebaseMessagingBackgroundHandler(RemoteMessage message) async {} class FirebaseNotificationManger { static FirebaseMessaging messaging = FirebaseMessaging.instance; @@ -20,12 +36,45 @@ class FirebaseNotificationManger { if (settings.authorizationStatus == AuthorizationStatus.authorized) { token = await messaging.getToken(); } + print("pushToken:$token"); return token; } + static void handleMessage(context, Map messageData) { + if (messageData["requestType"] != null && messageData["requestNumber"] != null) { + Widget serviceClass; + + if (messageData["requestType"] == "Service request to engineer") { + serviceClass = ServiceRequestDetailsPage(serviceRequest: ServiceRequest(id: messageData["requestNumber"].toString())); + } else if (messageData["requestType"] == "Gas Refill") { + serviceClass = GasRefillDetailsPage( + priority: messageData["priority"], + date: messageData["createdOn"], + model: GasRefillModel(id: int.parse(messageData["requestNumber"].toString())), + ); + } else if (messageData["requestType"] == "Asset Transfer") { + serviceClass = DeviceTransferDetails(model: AssetTransfer(id: int.parse(messageData["requestNumber"].toString()))); + } else if (messageData["requestType"] == "PPM") { + serviceClass = PpmDetailsPage( + request: RequestsDetails( + id: int.parse(messageData["requestNumber"].toString()), + priority: messageData["priority"], + )); + } + // else if (data["requestType"] == "WorkOrder") { + // + // } + + if (serviceClass != null) { + Navigator.of(context).push(MaterialPageRoute(builder: (_) => serviceClass)); + } + } + } + static initialized(BuildContext context) async { - await Firebase.initializeApp(); + //await Firebase.initializeApp(); NotificationSettings settings; + try { settings = await messaging.requestPermission( alert: true, @@ -44,25 +93,23 @@ class FirebaseNotificationManger { return; } - // Also handle any interaction when the app is in the background via a - // Stream listener - FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); + await FirebaseMessaging.instance.setAutoInitEnabled(true); + await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(alert: true, badge: true, sound: true); - // todo @sikander, check notifications payload, because notification model is different to need to check from backend + FirebaseMessaging.instance.getInitialMessage().then((initialMessage) { + if (initialMessage != null) { + handleMessage(context, initialMessage.data); + } + }); - // FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { - // SystemNotificationModel notification = SystemNotificationModel.fromJson(message.data); - // if (notification.path == null || notification.path.isEmpty) return; - // Navigator.pushNamed(context, notification.path, arguments: notification.requestId); - // }); - // - // FirebaseMessaging.onMessage.listen((RemoteMessage message) { - // SystemNotificationModel notification = SystemNotificationModel.fromJson(message.data); - // NotificationManger.showNotification( - // title: message.notification.title, subtext: message.notification.body, hashcode: int.tryParse(notification.requestId ?? "") ?? 1, payload: json.encode(message.data)); - // return; - // }); + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + NotificationManger.showNotification( + title: message.notification.title, subtext: message.notification.body, hashcode: int.tryParse("1234" ?? "") ?? 1, payload: json.encode(message.data), context: context); + return; + }); + FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { + handleMessage(context, message.data); + }); + FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); } } - -Future firebaseMessagingBackgroundHandler(RemoteMessage message) async {} diff --git a/lib/controllers/notification/notification_manger.dart b/lib/controllers/notification/notification_manger.dart index 1f68a24b..7bb6de1f 100644 --- a/lib/controllers/notification/notification_manger.dart +++ b/lib/controllers/notification/notification_manger.dart @@ -1,65 +1,80 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:permission_handler/permission_handler.dart'; class NotificationManger { // private constructor to avoid create object NotificationManger._(); - static FlutterLocalNotificationsPlugin localNotificationsPlugin = FlutterLocalNotificationsPlugin(); + static FlutterLocalNotificationsPlugin localNotificationsPlugin; //= FlutterLocalNotificationsPlugin(); /// initialisation setting for all platform /// onNotificationPressed action when notification pressed to open tap /// onIOSNotificationPressed action when notification pressed /// to open tap in iOS versions older than 10 + Future requestPermissions() async { + + } static initialisation(Function(NotificationResponse) onNotificationPressed, DidReceiveLocalNotificationCallback onIOSNotificationPressed) async { - FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); // initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project - const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings( - 'app_icon', - ); + const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@drawable/ic_stat_name'); final DarwinInitializationSettings initializationSettingsDarwin = DarwinInitializationSettings(onDidReceiveLocalNotification: onIOSNotificationPressed); final InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsDarwin, macOS: initializationSettingsDarwin); + localNotificationsPlugin = _flutterLocalNotificationsPlugin; + + if (Platform.isIOS) { + await localNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); + } else if (Platform.isAndroid) { + AndroidFlutterLocalNotificationsPlugin androidImplementation = localNotificationsPlugin.resolvePlatformSpecificImplementation(); + bool granted = await androidImplementation?.requestPermission(); + granted = granted ?? false; + if (granted == false) { + if (kDebugMode) { + print("-------------------- Permission Granted ------------------------"); + print(granted); + } + await Permission.notification.request(); + } + } - await flutterLocalNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationPressed); + await localNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationPressed); + //localNotificationsPlugin = flutterLocalNotificationsPlugin; } - // push new notification - static Future showNotification({@required BuildContext context, @required String title, @required String subtext, @required int hashcode, String payload}) async { - final AndroidNotificationDetails androidChannel = AndroidNotificationDetails( - 'com.newtrack.testsa', - 'Test SA', - channelDescription: 'Push notification service for Test SA', + + + // push new notificationBuildContext + static Future showNotification({@required context, @required String title, @required String subtext, @required int hashcode, String payload}) async { + const AndroidNotificationDetails androidChannel = AndroidNotificationDetails( + 'com.hmg.atoms', + 'ATOMS', + channelDescription: 'Push notification service for ATOMS', importance: Importance.max, priority: Priority.max, + icon: "@drawable/ic_stat_name", playSound: true, channelShowBadge: true, - enableLights: true, + // enableLights: false, visibility: NotificationVisibility.public, - ledColor: Theme.of(context).colorScheme.secondary, - ledOnMs: 1, - ledOffMs: 0, + //ledColor: Theme.of(context).colorScheme.secondary, + // ledOnMs: 1, + // ledOffMs: 0, enableVibration: true, - groupKey: 'com.newtrack.testsa', + groupKey: 'com.hmg.atoms', ); const DarwinNotificationDetails iosNotificationDetails = DarwinNotificationDetails( - categoryIdentifier: "testSA", + categoryIdentifier: "atoms", ); - final platformChannel = NotificationDetails( - android: androidChannel, - iOS: iosNotificationDetails, - macOS: iosNotificationDetails, - ); + const platformChannel = NotificationDetails(android: androidChannel, iOS: iosNotificationDetails, macOS: iosNotificationDetails); - await localNotificationsPlugin.show( - hashcode, - title, - subtext, - platformChannel, - payload: payload, - ); + await localNotificationsPlugin.show(hashcode, title, subtext, platformChannel, payload: payload); } } diff --git a/lib/main.dart b/lib/main.dart index 5d12fa77..08f501b7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -122,6 +122,7 @@ void main() async { DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); + runApp(ChangeNotifierProvider(create: (_) => SettingProvider(), child: const MyApp())); } diff --git a/lib/models/system_notification_model.dart b/lib/models/system_notification_model.dart index 1a3838b6..2d9eb4cf 100644 --- a/lib/models/system_notification_model.dart +++ b/lib/models/system_notification_model.dart @@ -30,6 +30,25 @@ class SystemNotificationModel { modifiedOn = json['modifiedOn']; } + Map toNotificationJson() { + final Map data = new Map(); + data['userId'] = this.userId; + data['userName'] = this.userName; + data['title'] = this.title; + data['text'] = this.text; + data['requestNumber'] = this.referenceId; + data['sourceId'] = this.sourceId; + data['requestType'] = this.sourceName; + data['readed'] = this.readed; + data['readingDate'] = this.readingDate; + data['id'] = this.id; + data['createdOn'] = this.createdOn; + data['modifiedOn'] = this.modifiedOn; + data['priority'] = "Low Priority"; + + return data; + } + Map toJson() { final Map data = new Map(); data['userId'] = this.userId; diff --git a/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart b/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart index dca8b180..2820749c 100644 --- a/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart +++ b/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -53,8 +54,7 @@ class RecentActivitiesFragment extends StatelessWidget { isLoading: _notificationsProvider.isLoading, notification: _notificationsProvider.notifications[itemIndex], onPressed: (notification) { - // todo @sikander, check notifications payload, because notification model is different to need to check from backend - //Navigator.of(context).pushNamed(FutureRequestServiceDetails.id, arguments: notification.requestId); + FirebaseNotificationManger.handleMessage(context, notification.toNotificationJson()); }, ); }, diff --git a/lib/new_views/pages/land_page/dashboard_page.dart b/lib/new_views/pages/land_page/dashboard_page.dart index 7f632293..9b3863a3 100644 --- a/lib/new_views/pages/land_page/dashboard_page.dart +++ b/lib/new_views/pages/land_page/dashboard_page.dart @@ -1,17 +1,25 @@ +import 'dart:convert'; + +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; +import 'package:test_sa/controllers/notification/notification_manger.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/notifications_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart'; import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart'; import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart'; import 'package:test_sa/views/pages/user/notifications/notifications_page.dart'; +import 'package:test_sa/views/pages/user/requests/service_request_details.dart'; class DashboardPage extends StatefulWidget { final VoidCallback onDrawerPress; @@ -28,7 +36,7 @@ class _DashboardPageState extends State { @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_){ + WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of(context, listen: false).getRequests(); Provider.of(context, listen: false).getSystemNotifications(); }); @@ -39,8 +47,18 @@ class _DashboardPageState extends State { super.dispose(); } + bool isFCM = true; + @override Widget build(BuildContext context) { + if (isFCM) { + FirebaseNotificationManger.initialized(context); + NotificationManger.initialisation((notificationDetails) { + FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload)); + }, (id, title, body, payload) async {}); + + isFCM = false; + } final user = Provider.of(context, listen: false).user; return Scaffold( appBar: AppBar( diff --git a/lib/new_views/pages/splash_page.dart b/lib/new_views/pages/splash_page.dart index c721f66c..41824a81 100644 --- a/lib/new_views/pages/splash_page.dart +++ b/lib/new_views/pages/splash_page.dart @@ -5,9 +5,12 @@ import 'package:provider/provider.dart'; import 'package:test_sa/controllers/notification/notification_manger.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart'; import 'package:test_sa/new_views/pages/login_page.dart'; +import 'package:test_sa/views/pages/user/requests/service_request_details.dart'; import '../../models/size_config.dart'; @@ -24,15 +27,26 @@ class _SplashPageState extends State { SettingProvider _settingProvider; UserProvider _userProvider; + bool isnotificationCame=false; + @override void initState() { Firebase.initializeApp(); - NotificationManger.initialisation((notificationDetails) { - // todo @sikander, check notifications payload, because notification model is different to need to check from backend - // SystemNotificationModel notification = SystemNotificationModel.fromJson(json.decode(notificationDetails.payload)); - // if (notification.path == null || notification.path.isEmpty) return; - // Navigator.pushNamed(context, notification.path, arguments: notification.requestId); - }, (id, title, body, payload) async {}); + // NotificationManger.initialisation((notificationDetails) { + // // todo @sikander, check notifications payload, because notification model is different to need to check from backend + // // SystemNotificationModel notification = SystemNotificationModel.fromJson(json.decode(notificationDetails.payload)); + // // if (notification.path == null || notification.path.isEmpty) return; + // // Navigator.pushNamed(context, notification.path, arguments: notification.requestId); + // + // isnotificationCame = true; + // "initialisation:${notificationDetails?.toString()}".showToast; + // + // // Navigator.of(context).push(MaterialPageRoute( + // // builder: (_) => ServiceRequestDetailsPage( + // // serviceRequest: ServiceRequest(id: "72348"), + // // ))); + // + // }, (id, title, body, payload) async {}); super.initState(); } @@ -53,7 +67,11 @@ class _SplashPageState extends State { if (_settingProvider.isLoaded && (_settingProvider.user?.isLiveToken ?? false)) { _userProvider.user = _settingProvider.user; Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); - + // if(isnotificationCame) + // Navigator.of(context).push(MaterialPageRoute( + // builder: (_) => ServiceRequestDetailsPage( + // serviceRequest: ServiceRequest(id: "72348"), + // ))); /// The below line for the new design // Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); } diff --git a/lib/views/pages/user/notifications/notifications_list.dart b/lib/views/pages/user/notifications/notifications_list.dart index 16922f23..fcd9516b 100644 --- a/lib/views/pages/user/notifications/notifications_list.dart +++ b/lib/views/pages/user/notifications/notifications_list.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/system_notification_model.dart'; @@ -33,8 +34,7 @@ class NotificationsList extends StatelessWidget { return NotificationItem( notification: notifications[itemIndex], onPressed: (notification) { - // todo @sikander, check notifications payload, because notification model is different to need to check from backend - //Navigator.of(context).pushNamed(FutureRequestServiceDetails.id, arguments: notification.requestId); + FirebaseNotificationManger.handleMessage(context, notification.toNotificationJson()); }, ); }, diff --git a/lib/views/pages/user/requests/work_order/work_orders_list_page.dart b/lib/views/pages/user/requests/work_order/work_orders_list_page.dart index 8a819b72..768aba12 100644 --- a/lib/views/pages/user/requests/work_order/work_orders_list_page.dart +++ b/lib/views/pages/user/requests/work_order/work_orders_list_page.dart @@ -33,7 +33,6 @@ class WorkOrderListPage extends StatelessWidget { ServiceRequestsProvider serviceRequestsProvider; UserProvider _userProvider = Provider.of(context); serviceRequestsProvider ??= Provider.of(context); - print("serviceRequest.statusValue:${serviceRequest?.statusValue}"); return Scaffold( appBar: DefaultAppBar(title: context.translation.workOrders), //backgroundColor: const Color(0xfff8f9fb),