import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import '../Provider/utils_singleton.dart'; import '../config/api_response.dart'; import '../config/constants/app_constant.dart'; import '../config/constants/consts.dart'; import '../models/notification/local_notification_model.dart'; import '../utils/connection.dart'; import '../utils/notification_singleton.dart'; import '../models/notification/notification_response.dart' as local; class PushNotificationService { String token = "InvalidToken"; int statusCode = -1; bool errorToken = false; final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); AndroidNotificationChannel? channel; ///************************************************************* getToken *******************************************************************/ Future getToken() async { final prefs = await SharedPreferences.getInstance(); token = prefs.getString('token') ?? 'InvalidToken'; return token; } ///************************************************************* logError *******************************************************************/ Future logError({ String? comment, required String errorCode, required String errorMessage, required String path, }) async { await getToken(); final Map query = { "clientid": "283386", "comment": comment ?? "No comment provided", "errorcode": errorCode, "errormessage": errorMessage, "path": path, "source": "MOBILE_APP", "useremail": utils.user?.email ?? "email@email.com", "username": utils.user?.name ?? "anonymous user", "userphonenumber": utils.user?.phoneNumber ?? "00000000", }; try { final data = await http.post( Uri.https(AppString.reportLink, 'api/v1/servererror/new_error', query), headers: { 'Content-type': 'application/json', 'Accept': 'application/json' }, ); statusCode = data.statusCode; if (statusCode == 200 || statusCode == 201) { return APIResponse(statusCode: statusCode); } return APIResponse(statusCode: statusCode, errorMessage: 'Please check your info'); } catch (_) { return APIResponse(statusCode: statusCode, errorMessage: 'no internet connection'); } } static Future onDidReceiveBackgroundNotificationResponse( NotificationResponse message) async { log("Tapped on notification - background message - message: \$message"); final notification = notificationSingleton.getNotif(message.id.toString()); if (notification?.action != null) { log(">>>>>>>>>>>>>>>>> here 5"); } } ///************************************************************* requestNotificationPermission *******************************************************************/ Future requestNotificationPermission() async { if (Platform.isIOS) { try { NotificationSettings settings = await FirebaseMessaging.instance .requestPermission(alert: true, badge: true, sound: true); if (settings.authorizationStatus == AuthorizationStatus.authorized || settings.authorizationStatus == AuthorizationStatus.provisional) { log('User granted permission'); return true; } else { log('User declined or has not accepted permission'); return false; } } catch (e) { log("Error requesting notification permission: \$e"); return false; } } else { return true; } } ///************************************************************* setupInteractedMessage *******************************************************************/ Future setupInteractedMessage() async { log("++++++++++++ Notification service : Set Interacted messages (init)"); if (await Connection.checkConnection()) { try { if (await requestNotificationPermission()) { await enableIOSNotifications(); await getFCMToken(); await initNotificationPlugin(); registerNotificationListeners(); } } catch (e) { log("Error in setupInteractedMessage: \$e"); await Future.delayed(Duration(seconds: 5)); await setupInteractedMessage(); } } else { utils.setInitialized(false); } } ///************************************************************* get FCM Token *******************************************************************/ Future getFCMToken() async { final prefs = await SharedPreferences.getInstance(); try { await Future.delayed(const Duration(seconds: 2)); // Adding a small delay String? token = await FirebaseMessaging.instance.getToken().timeout(const Duration(seconds: 10)); prefs.setString("FCM token", token ?? "InvalidToken"); } catch (e) { prefs.setString("FCM token", "InvalidToken"); log("Error in getting Firebase token: $e"); await Future.delayed(const Duration(seconds: 5)); await getFCMToken(); } } ///************************************************************* initNotificationPlugin *******************************************************************/ Future initNotificationPlugin() async { log("++++++++++++ Notification service : init notification plugin function"); channel = androidNotificationChannel(); await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel!); const AndroidInitializationSettings androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); const DarwinInitializationSettings iOSSettings = DarwinInitializationSettings( requestSoundPermission: true, requestBadgePermission: true, requestAlertPermission: true, ); const InitializationSettings initSettings = InitializationSettings(android: androidSettings, iOS: iOSSettings); await flutterLocalNotificationsPlugin.initialize(initSettings, onDidReceiveNotificationResponse: (message) async { final notification = notificationSingleton.getNotif(message.id.toString()); if (notification?.action != null) { log(">>>>>>>>>>>>>>>>> here 3"); } log("Tapped on notification - message: \$message"); }, onDidReceiveBackgroundNotificationResponse: onDidReceiveBackgroundNotificationResponse); } ///************************************************************* showNotification *******************************************************************/ void showNotification(RemoteMessage notification, AndroidNotification android, bool isBackground) { log("++++++++++++ Notification service : show notification - Function"); final notif = LocalNotificationModel.fromJson(notification.data); notificationSingleton.addNotif(notif); channel ??= androidNotificationChannel(); flutterLocalNotificationsPlugin.show( notification.hashCode, notificationData(notification.data['action'])['title'], notificationData(notification.data['action'])['body'], NotificationDetails( android: AndroidNotificationDetails( channel!.id, channel!.name, icon: android.smallIcon, playSound: true, ), ), payload: "\${notification.data['actionId']}_\${notif.id}", ).then((_) => log("Notification shown")); } ///************************************************************* notificationData *******************************************************************/ static Map notificationData(String? notificationAction) { switch (notificationAction) { case "RIDE_START": return { "title": "Account Activated", "body": "Your account has been activated successfully. Welcome!", }; case "STOP": return { "title": "Account Suspended", "body": "Your account has been suspended. Please contact support for more information.", }; default: return { "title": "New notification", "body": "You have a new notification", }; } } ///************************************************************* registerNotificationListeners *******************************************************************/ void registerNotificationListeners() { log("++++++++++++ Notification service : register notification listener"); FirebaseMessaging.onMessage.listen((RemoteMessage? message) { if (message?.notification?.android != null) { log("onMessage: notification received"); showNotification(message!, message.notification!.android!, false); } }); } ///************************************************************* IOS settings *******************************************************************/ Future enableIOSNotifications() async { await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true, ); } ///************************************************************* Android Notification Channel *******************************************************************/ AndroidNotificationChannel androidNotificationChannel() => const AndroidNotificationChannel( 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, ); ///************************************************************* getAllNotifications *******************************************************************/ Future> getAllNotifications( int size, int number) async { await getToken(); final queryParameters = {'size': '\$size', 'page': '\$number'}; try { final response = await http.get( Uri.https(url, 'api/v1/notification/all_my_notification', queryParameters), headers: { 'Authorization': 'Bearer \$token', 'Content-type': 'application/json', 'Accept': 'application/json' }, ); statusCode = response.statusCode; if (statusCode == 200 || statusCode == 201) { final jsonData = json.decode(utf8.decode(response.bodyBytes)); final result = local.NotificationResponse.fromJson(jsonData); return APIResponse(statusCode: statusCode, data: result); } await logError( errorCode: statusCode.toString(), errorMessage: response.body.toString(), path: 'api/v1/notification/all_my_notification'); return APIResponse( statusCode: statusCode, errorMessage: 'Please check your info'); } catch (e) { await logError( errorCode: statusCode.toString(), errorMessage: "Caught error : \$e", path: 'api/v1/notification/all_my_notification'); return APIResponse( statusCode: statusCode, errorMessage: e.toString()); } } }