import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get/get.dart'; import 'package:muaawana/config/provider.dart'; import 'package:muaawana/views/client_view/main_screen.dart'; import 'package:muaawana/views/technicien_view/home_tech_screen.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../models/local_notification_model.dart'; import '../models/notification_response.dart' as localNotifResponse; import '../models/utils/api_response.dart'; import '../providers/navbar_provider/bottom_navigation_provider.dart'; import '../providers/navbar_provider/client_bottom_nav_provider.dart'; import '../providers/notif/notification_singleton.dart'; import '../providers/request_status_provider.dart'; import '../utils/connection.dart'; import '../utils/utils_singleton.dart'; import 'package:http/http.dart' as http; const url = 'server.muaawana.com'; class PushNotificationService { // It is assumed that all messages contain a data field with the key 'type' String token = "InvalidToken"; int statusCode = -1; bool errorToken = false; final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); AndroidNotificationChannel? channel; ///******************************************************* getToken *******************************************************************/ Future getToken() async { final prefs = await SharedPreferences.getInstance(); if (prefs.getString('token') == null || prefs.getString('token') == '') { prefs.setString('token', 'InvalidToken'); } if (prefs.getString('token') != null) { token = prefs.getString('token')!; } return token.toString(); } // ///*********************** request Notification Permission ********************/ Future requestNotificationPermission() async { if (Platform.isIOS) { try { NotificationSettings settings = await FirebaseMessaging.instance .requestPermission(alert: true, badge: true, sound: true); if (settings.authorizationStatus == AuthorizationStatus.authorized) { log('User granted permission'); return true; } else if (settings.authorizationStatus == AuthorizationStatus.provisional) { log('User granted provisional permission'); return true; } else { log('User declined or has not accepted permission'); return false; } } catch (e) { log("an error has occurred in request Notification Permission"); log(e.toString()); return false; } } else { return true; } } ///*************** setup firebaseMessaging ( init) **********************/ Future setupInteractedMessage(BuildContext context) async { log("++++++++++++ Notification service : Set Interacted messages (init)"); if (await Connection.checkConnection()) { try { log("++++++++++++ Notification service :request notification permission"); if (await requestNotificationPermission()) { log("++++++++++++ Notification service :request notification permission true"); log("++++++++++++ Notification service : enableIOSNotifications - start "); await enableIOSNotifications(); log("++++++++++++ Notification service : enableIOSNotifications - after"); log("++++++++++++ Notification service : await FCM Token - start"); await getFCMToken(); log("++++++++++++ Notification service : await FCM Token - after"); log("++++++++++++ Notification service : initNotificationPlugin - start"); await initNotificationPlugin(context); log("++++++++++++ Notification service : initNotificationPlugin - after"); log("++++++++++++ Notification service : registering notification listener - start"); await registerNotificationListeners(context); log("++++++++++++ Notification service : Firebase messaging - on message openedApp - Listener Set up"); FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { log("++++++++++++ Notification service : on message open App listener - inside"); log("$message"); log("message received notification : ${message.toString()}"); AndroidNotification? android = message.notification?.android; log("++++++++++++ Notification service : logging android $android"); if (android != null) { log("++++++++++++ Notification service : show notification : $android"); // showNotification(message, android, true); } if (message != null) { if (util.user != null) { if (util.user!.role!.role == "ROLE_TECHNICIAN") { if (message.data['action'] == "NEW_MESSAGE") { context.read().setCurrentIndex(1); Get.to(() => const HomeTechView()); } else { context.read().setCurrentIndex(0); Get.to(() => const HomeTechView()); } } else { if (message.data['action'] == "NEW_MESSAGE") { context .read() .setCurrentIndex(3); Get.to(() => const HomeClientView()); } else { print(message.data['actionId'] is String); print(message.data['actionId'] is int); print(message.data['actionId']); final id = int.tryParse(message.data['actionId']); print(id is int); context .read() .setCurrentIndex(1); context .read() .addActiveNotificationRequest(id!); context.read().refreshListOrder(id); context .read() .setCurrentIndex(1); Get.to(() => const HomeClientView()); } } } } }); log("++++++++++++ Notification service : registering notification listener - end"); util.setInitialized(true); } } catch (e) { log("an error has occurred in setupInteractedMessage"); log(e.toString()); util.setInitialized(false); } } else { util.setInitialized(false); } } // static Future onDidReceiveBackgroundNotificationResponse( // NotificationResponse message) async { // print("got background notification"); // final notification = notificationSingleton.getNotif(message.id.toString()); // if (notification != null) { // if (notification.action != null) { // log(">>>>>>>>>>>>>>>>> here 5"); // handleNotificationClick( // notification.action ?? "IDLE", int.parse(message.actionId ?? "0")); // } // } // } ///*********************** get FCM Token **************************/ getFCMToken() async { final prefs = await SharedPreferences.getInstance(); await FirebaseMessaging.instance.getToken().then((token) { prefs.setString("FCM token", token ?? ""); }).timeout(const Duration(seconds: 5), onTimeout: () { log("timeout !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); prefs.setString("FCM token", ""); }).catchError((error) { log("catchError !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); log(error); prefs.setString("FCM token", ""); }).whenComplete(() {}); // if(fcmToken!=null){ // prefs.setString("FCM token", fcmToken); // } } ///**************** init local notification plugin + onSelect ********************/ initNotificationPlugin(BuildContext context) async { log("++++++++++++ Notification service : init notification plugin function - start"); channel = androidNotificationChannel(); var androidSettings = const AndroidInitializationSettings('@mipmap/ic_launcher'); var iOSSettings = const DarwinInitializationSettings( requestSoundPermission: false, requestBadgePermission: false, requestAlertPermission: false, ); var initSettings = InitializationSettings(android: androidSettings, iOS: iOSSettings); flutterLocalNotificationsPlugin.initialize(initSettings, onDidReceiveNotificationResponse: (message) async { log("++++++++++++ Notification service : onselect notification - start"); log(message.toString()); if (message != null) { log("message not null in on select notification"); } }, // onDidReceiveBackgroundNotificationResponse: // onDidReceiveBackgroundNotificationResponse ); log("++++++++++++ Notification service : create notification channel - start"); await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel!); } LocalNotificationModel? parseNotification( Map notification, bool isBackground) { log("++++++++++++ Notification service : parse notification"); LocalNotificationModel result = LocalNotificationModel.fromJson(notification); if (isBackground) { notificationSingleton.addNotif(result); } return result; } /* NEW_ITEM_REQUEST, NEW_MESSAGE, NEW_PRODUCT_REQUEST, NEW_SERVICE_RATE, NEW_SERVICE_REQUEST, NEW_URGENT_REQUEST, REQUEST_ACCEPTED, REQUEST_NOT_DONE, REQUEST_REJECTED, REQUEST_STATE_CHANGED, TECHNICIAN_ACCEPTED_REQUEST, TECHNICIAN_COMPLETED_REQUEST, TECHNICIAN_COMPLETED_URGENT_REQUEST, TECHNICIAN_DISABLED, URGENT_REQUEST_ASSIGNED, URGENT_REQUEST_NOT_DONE, URGENT_REQUEST_STATE_CHANGED, URGENT_REQUEST_TECHNICIAN, * */ Map notificationData(RemoteNotification? notification) { if (notification == null || notification.title == null) { return { "title": "New notification", "body": "You have a new notification", }; } switch (notification.title) { case "ADMIN_ASSIGNED_REQUEST": return { "title": "Request Assigned", "body": "You have a new assigned request", }; case "NEW_ITEM_REQUEST": return { "title": "New Item Request", "body": "New item requested", }; case "NEW_MESSAGE": return { "title": "New Message", "body": "You have a new message", }; case "NEW_PRODUCT_REQUEST": return { "title": "New Product Request", "body": "New product requested", }; case "NEW_SERVICE_REQUEST": return { "title": "New Service Request", "body": "You have a new service request", }; case "NEW_URGENT_REQUEST": return { "title": "New Urgent Request", "body": "You have a new urgent request", }; case "REQUEST_ACCEPTED": return { "title": "Request Accepted", "body": "Your request has been accepted", }; case "REQUEST_NOT_DONE": return { "title": "Request Not Done", "body": "Your request has not been completed for this reason : ${notification.body}", }; case "REQUEST_REJECTED": return { "title": "Request Rejected", "body": "Your request has been rejected by a technician", }; case "REQUEST_STATE_CHANGED": return { "title": "Request State Changed", "body": "The state of your request has changed", }; case "TECHNICIAN_ACCEPTED_REQUEST": return { "title": "Technician Accepted Request", "body": "A technician has accepted your request", }; case "TECHNICIAN_COMPLETED_REQUEST": return { "title": "Technician Completed Request", "body": "A technician has completed your request", }; case "TECHNICIAN_COMPLETED_URGENT_REQUEST": return { "title": "Technician Completed Urgent Request", "body": "A technician has completed your urgent request", }; case "URGENT_REQUEST_ASSIGNED": return { "title": "Urgent Request Assigned", "body": "An urgent request has been assigned", }; case "URGENT_REQUEST_NOT_DONE": return { "title": "Urgent Request Not Done", "body": "An urgent request has not been completed", }; case "URGENT_REQUEST_STATE_CHANGED": return { "title": "Urgent Request State Changed", "body": "The state of an urgent request has changed", }; case "URGENT_REQUEST_TECHNICIAN": return { "title": "Urgent Request Technician", "body": "A technician is assigned to an urgent request", }; default: return { "title": "New notification", "body": "You have a new notification", }; } } ///****************************************************************** show Notification ****************************************************************/ showNotification(RemoteMessage notification, AndroidNotification android, bool isBackground) { log("++++++++++++ Notification service : show notification - Function"); log("notification before parse : ${notification.toString()}"); final Map notificationMapped = notification.toMap(); log("$notificationMapped"); final notif = parseNotification(notification.data, isBackground); print("notification parsed : ${notif?.toJson()}"); print("id : ${notif!.id}"); if (notif != null) { channel ??= androidNotificationChannel(); flutterLocalNotificationsPlugin .show( notification.data.hashCode, notificationData(notification.notification)["title"], "${notificationData(notification.notification)["body"]!}. Request id : ${notif.id}", NotificationDetails( android: AndroidNotificationDetails( channel!.id, channel!.name, // icon: , playSound: true, ), ), payload: jsonEncode(notification.data)) .then((value) => log("notif shown !!!!!!!!!!!!")); } } ///*************************************************** Foreground message listener ***************************************************************/ registerNotificationListeners(BuildContext context) async { log("++++++++++++ Notification service : register notification listener"); // onMessage is called when the app is in foreground and a notification is received FirebaseMessaging.onMessage.listen((RemoteMessage? message) { print("this is notification data from ==========> "); print(message?.toMap().toString()); if (message != null) { AndroidNotification? android = message.notification ?.android; // If `onMessage` is triggered with a notification, construct our own // local notification to show to users using the created channel. if (android != null) { log("on message listen : notification received"); showNotification(message, android, true); } // if (message != null) { // if (util.user != null) { // if (util.user!.role!.role == "ROLE_TECHNICIAN") { // if (message.data['action'] == "NEW_MESSAGE") { // context.read().setCurrentIndex(1); // Get.to(() => const HomeTechView()); // } else { // context.read().setCurrentIndex(0); // Get.to(() => const HomeTechView()); // } // } else { // if (message.data['action'] == "NEW_MESSAGE") { // context // .read() // .setCurrentIndex(3); // // Get.to(() => const HomeClientView()); // } else { // print(message.data['actionId'] is String); // print(message.data['actionId'] is int); // print(message.data['actionId']); // final id = int.tryParse(message.data['actionId']); // print(id is int); // context // .read() // .setCurrentIndex(1); // context // .read() // .addActiveNotificationRequest(id!); // context.read().refreshListOrder(id); // Get.to(() => const HomeClientView()); // } // } // } // } } }); // FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage? message) { // if (message != null) { // AndroidNotification? android = message.notification // ?.android; // If `onMessage` is triggered with a notification, construct our own // // local notification to show to users using the created channel. // if (android != null) { // log("on message listen : notification received"); // showNotification(message, android, true); // } // if (message != null) { // if (util.user != null) { // if (util.user!.role!.role == "ROLE_TECHNICIAN") { // if (message.data['action'] == "NEW_MESSAGE") { // context.read().setCurrentIndex(1); // Get.to(() => const HomeTechView()); // } else { // context.read().setCurrentIndex(0); // Get.to(() => const HomeTechView()); // } // } else { // if (message.data['action'] == "NEW_MESSAGE") { // context // .read() // .setCurrentIndex(3); // // Get.to(() => const HomeClientView()); // } else { // print(message.data['actionId'] is String); // print(message.data['actionId'] is int); // print(message.data['actionId']); // final id = int.tryParse(message.data['actionId']); // print(id is int); // context // .read() // .setCurrentIndex(1); // context // .read() // .addActiveNotificationRequest(id!); // context.read().refreshListOrder(id); // Get.to(() => const HomeClientView()); // } // } // } // } // } // }); } ///******************************************************* IOS / Android settings ************************************************/ enableIOSNotifications() async { await FirebaseMessaging.instance .setForegroundNotificationPresentationOptions( alert: true, // Required to display a heads up notification badge: true, sound: true, ); } androidNotificationChannel() => const AndroidNotificationChannel( 'high_importance_channel', // id 'High Importance Notifications', // title importance: Importance.max, ); ///******************************************* get all notifications ***************************************************************/ Future> getAllNotifications(int size, int number) async { errorToken = false; statusCode = -1; await getToken(); final queryParameters = {'page': '$number', 'size': '$size'}; return await http.get( Uri.https( url, 'api/v1/notification/all_my_notification', queryParameters), headers: { 'Authorization': 'Bearer $token', 'Content-type': 'application/json', 'Accept': 'application/json' }).then((data) async { statusCode = data.statusCode; if (data.statusCode == 200 || data.statusCode == 201) { log("getAllNotifications ===> ${data.body}"); final jsonData = json.decode(data.body); localNotifResponse.NotificationResponse result = localNotifResponse.NotificationResponse.fromJson(jsonData); return APIResponse(statusCode: statusCode, data: result); } return APIResponse( statusCode: statusCode, errorMessage: 'Please check your info'); }).catchError((e) => APIResponse( statusCode: statusCode, errorMessage: e.toString())); } }