import 'dart:convert'; import 'dart:io'; import 'package:sefer_driver/constant/api_key.dart'; import 'package:sefer_driver/controller/home/captin/home_captain_controller.dart'; import 'package:sefer_driver/views/widgets/error_snakbar.dart'; import 'package:sefer_driver/views/widgets/mydialoug.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'package:sefer_driver/views/widgets/elevated_btn.dart'; import '../../constant/box_name.dart'; import '../../constant/colors.dart'; import '../../constant/style.dart'; import '../../env/env.dart'; import '../../main.dart'; import '../../print.dart'; import '../../views/auth/captin/criminal_documents_page.dart'; import '../../views/home/Captin/home_captain/home_captin.dart'; import '../../views/home/Captin/orderCaptin/order_speed_request.dart'; import '../../views/home/Captin/orderCaptin/order_request_page.dart'; import '../../views/home/Captin/orderCaptin/vip_order_page.dart'; import '../auth/google_sign.dart'; import '../functions/encrypt_decrypt.dart'; import '../functions/face_detect.dart'; import 'access_token.dart'; import 'local_notification.dart'; import 'notification_service.dart'; class FirebaseMessagesController extends GetxController { final fcmToken = FirebaseMessaging.instance; List tokens = []; List dataTokens = []; late String driverID; late String driverToken; NotificationSettings? notificationSettings; NotificationController notificationController = Get.put(NotificationController()); Future getNotificationSettings() async { // Get the current notification settings NotificationSettings? notificationSettings = await FirebaseMessaging.instance.getNotificationSettings(); 'Notification authorization status: ${notificationSettings.authorizationStatus}'; // Call the update function if needed update(); } Future requestFirebaseMessagingPermission() async { FirebaseMessaging messaging = FirebaseMessaging.instance; // Check if the platform is Android if (Platform.isAndroid) { // Request permission for Android await messaging.requestPermission(); } else if (Platform.isIOS) { // Request permission for iOS NotificationSettings settings = await messaging.requestPermission( alert: true, announcement: true, badge: true, carPlay: true, criticalAlert: true, provisional: false, sound: true, ); messaging.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true); } } Future getToken() async { fcmToken.getToken().then((token) { Log.print('token fcm driver: ${token}'); box.write(BoxName.tokenDriver, (token!)); }); FirebaseMessaging.onMessage.listen((RemoteMessage message) { // If the app is in the background or terminated, show a system tray message RemoteNotification? notification = message.notification; AndroidNotification? android = notification?.android; // if (notification != null && android != null) { if (message.data.isNotEmpty && message.notification != null) { fireBaseTitles(message); } // if (message.data.isNotEmpty && message.notification != null) { // fireBaseTitles(message); // } }); FirebaseMessaging.onBackgroundMessage((RemoteMessage message) async {}); FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { if (message.data.isNotEmpty && message.notification != null) { fireBaseTitles(message); } }); } Future fireBaseTitles(RemoteMessage message) async { if (message.notification!.title! == 'Order') { if (Platform.isAndroid) { notificationController.showNotification( message.notification!.title.toString(), message.notification!.body.toString(), 'tone1', ''); } // await FirebaseMessagesController().showOverlayNotification(message); var myListString = message.data['DriverList']; // var points = message.data['PolylineJson']; var myList = jsonDecode(myListString) as List; // var myPoints = jsonDecode(points) as List; driverToken = myList[14].toString(); // This is for location using and uploading status Get.put(HomeCaptainController()).changeRideId(); update(); Get.to(() => OrderRequestPage(), arguments: { // Get.to(() => OrderRequestPage(), arguments: { 'myListString': myListString, 'DriverList': myList, // 'PolylineJson': myPoints, 'body': message.notification!.body }); } else if (message.notification!.title == 'OrderVIP') { var myListString = message.data['DriverList']; var myList = jsonDecode(myListString) as List; // driverToken = myList[10].toString(); if (Platform.isAndroid) { notificationController.showNotification( 'OrderVIP'.tr, 'OrderVIP'.tr, 'order', ''); } Get.to(VipOrderPage(), arguments: { 'myListString': myListString, 'DriverList': myList, // 'PolylineJson': myPoints, 'body': message.notification!.body }); } else if (message.notification!.title == 'Cancel Trip'.tr) { if (Platform.isAndroid) { notificationController.showNotification( 'Cancel Trip'.tr, 'Passenger Cancel Trip'.tr, 'cancel', ''); } cancelTripDialog(); } else if (message.notification!.title == 'VIP Order') { var myListString = message.data['DriverList']; var driverList = jsonDecode(myListString) as List; if (Platform.isAndroid) { notificationController.showNotification( 'VIP Order'.tr, '', 'order', ''); } MyDialog().getDialog('VIP Order'.tr, 'midTitle', () { // sendNotificationToPassengerToken( // 'VIP Order Accepted'.tr, // 'The driver accepted your trip'.tr, // driverList[0], // [driverList[1]], // 'order'); NotificationService.sendNotification( target: driverList[0].toString(), title: 'VIP Order Accepted'.tr, body: 'The driver accepted your trip'.tr, isTopic: false, // Important: this is a token tone: 'order', driverList: [], ); }); // Get.to(const VipOrderPage()); } else if (message.notification!.title == 'message From passenger') { if (Platform.isAndroid) { notificationController.showNotification( 'message From passenger'.tr, ''.tr, 'ding', ''); } MyDialog().getDialog( 'message From passenger'.tr, message.notification!.body!, () { Get.back(); }); } else if (message.notification!.title == 'Cancel') { if (Platform.isAndroid) { notificationController.showNotification( 'Cancel'.tr, ''.tr, 'cancel', ''); } MyDialog().getDialog( 'Passenger Cancel Trip'.tr, 'Trip Cancelled. The cost of the trip will be added to your wallet.' .tr, () { box.write(BoxName.rideStatus, 'Cancel'); Log.print('rideStatus from 184 : ${box.read(BoxName.rideStatus)}'); Get.offAll(HomeCaptain()); }); // cancelTripDialog1(); } else if (message.notification!.title! == 'token change') { // notificationController // .showNotification('token change'.tr, 'token change', 'cancel'); // GoogleSignInHelper.signOut(); GoogleSignInHelper.signOut(); } else if (message.notification!.title! == 'face detect') { if (Platform.isAndroid) { notificationController.showNotification( 'face detect'.tr, ''.tr, 'tone2', ''); } String result0 = await faceDetector(); // Handle the result here, e.g., show a dialog or update the UI var result = jsonDecode(result0); MyDialogContent().getDialog( 'Face Detection Result'.tr, Text( result['similar'].toString() == 'true' ? 'similar'.tr : 'not similar'.tr, style: AppStyle.title, ), () { Get.back(); }, ); update(); } else if (message.notification!.title! == 'Hi ,I will go now') { if (Platform.isAndroid) { notificationController.showNotification( 'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'tone2', ''); } update(); } else if (message.notification!.title! == 'Call Income'.tr) { try { var myListString = message.data['passengerList']; var driverList = jsonDecode(myListString) as List; // if (Platform.isAndroid) { if (Platform.isAndroid) { notificationController.showNotification('Call Income'.tr, message.notification!.body!, 'iphone_ringtone', ''); } // } // Assuming GetMaterialApp is initialized and context is valid for navigation // Get.to(() => PassengerCallPage( // channelName: driverList[1].toString(), // token: driverList[0].toString(), // remoteID: driverList[2].toString(), // )); } catch (e) {} } else if (message.notification!.title! == 'Call Income from Passenger'.tr) { try { var myListString = message.data['passengerList']; var driverList = jsonDecode(myListString) as List; // if (Platform.isAndroid) { if (Platform.isAndroid) { notificationController.showNotification('Call Income'.tr, message.notification!.body!, 'iphone_ringtone', ''); } // } // Assuming GetMaterialApp is initialized and context is valid for navigation // Get.to(() => CallPage( // // channelName: driverList[1].toString(), // // token: driverList[0].toString(), // // remoteID: driverList[2].toString(), // )); } catch (e) {} } else if (message.notification!.title! == "Criminal Document Required".tr) { if (Platform.isAndroid) { notificationController.showNotification("Criminal Document Required".tr, message.notification!.body!, 'tone2', ''); } MyDialog().getDialog( "Criminal Document Required".tr, 'You should have upload it .'.tr, () { Get.to(() => const CriminalDocumemtPage()); }); Get.to(() => const CriminalDocumemtPage()); } else if (message.notification!.title! == 'Call End'.tr) { try { var myListString = message.data['passengerList']; var driverList = jsonDecode(myListString) as List; if (Platform.isAndroid) { notificationController.showNotification( 'Call End'.tr, message.notification!.body!, 'tone2', ''); } // Assuming GetMaterialApp is initialized and context is valid for navigation // Get.off(const CallPage()); } catch (e) {} } else if (message.notification!.title! == 'Order Applied'.tr) { mySnackbarSuccess("The order has been accepted by another driver.".tr); } else if (message.notification!.title! == 'Order') { if (Platform.isAndroid) { notificationController.showNotification( message.notification!.title.toString(), message.notification!.body.toString(), 'order', ''); } var myListString = message.data['DriverList']; // var points = message.data['PolylineJson']; var myList = jsonDecode(myListString) as List; // var myPoints = jsonDecode(points) as List; driverToken = myList[14].toString(); Get.put(HomeCaptainController()).changeRideId(); update(); Get.to(() => OrderSpeedRequest(), arguments: { 'myListString': myListString, 'DriverList': myList, // 'PolylineJson': myPoints, 'body': message.notification!.body }); } else if (message.notification!.title! == 'Order Applied'.tr) { if (Platform.isAndroid) { notificationController.showNotification( 'The order Accepted by another Driver'.tr, 'We regret to inform you that another driver has accepted this order.' .tr, 'order', ''); } } } SnackbarController driverAppliedTripSnakBar() { return Get.snackbar( 'Driver Applied the Ride for You'.tr, '', colorText: AppColor.greenColor, duration: const Duration(seconds: 3), snackPosition: SnackPosition.TOP, titleText: Text( 'Applied'.tr, style: const TextStyle(color: AppColor.redColor), ), messageText: Text( 'Driver Applied the Ride for You'.tr, style: AppStyle.title, ), icon: const Icon(Icons.approval), shouldIconPulse: true, margin: const EdgeInsets.all(16), padding: const EdgeInsets.all(16), ); } Future cancelTripDialog() { return Get.defaultDialog( barrierDismissible: false, title: 'Passenger Cancel Trip'.tr, middleText: '', confirm: MyElevatedButton( title: 'Ok'.tr, onPressed: () { box.write(BoxName.rideStatus, 'Cancel'); box.write(BoxName.statusDriverLocation, 'off'); Log.print( 'rideStatus from 347 : ${box.read(BoxName.rideStatus)}'); Get.offAll(HomeCaptain()); })); } Future cancelTripDialog1() { return Get.defaultDialog( barrierDismissible: false, title: 'Passenger Cancel Trip'.tr, middleText: 'Trip Cancelled. The cost of the trip will be added to your wallet.' .tr, confirm: MyElevatedButton( title: 'Ok'.tr, onPressed: () { box.write(BoxName.rideStatus, 'Cancel'); Log.print( 'rideStatus from 364 : ${box.read(BoxName.rideStatus)}'); Get.offAll(HomeCaptain()); })); } // Future driverArrivePassengerDialoge() { // return Get.defaultDialog( // barrierDismissible: false, // title: 'Hi ,I Arrive your site'.tr, // middleText: 'Please go to Car Driver'.tr, // confirm: MyElevatedButton( // title: 'Ok I will go now.'.tr, // onPressed: () { // FirebaseMessagesController().sendNotificationToPassengerToken( // 'Hi ,I will go now'.tr, // 'I will go now'.tr, // Get.find().driverToken, []); // Get.find() // .startTimerDriverWaitPassenger5Minute(); // Get.back(); // })); // } // late String serviceAccountKeyJson; // @override // Future onInit() async { // super.onInit(); // try { // // getToken(); // var encryptedKey = Env.privateKeyFCM; // // Log.print('encryptedKey: ${encryptedKey}'); // serviceAccountKeyJson = // EncryptionHelper.instance.decryptData(encryptedKey); // // Log.print('serviceAccountKeyJson: ${serviceAccountKeyJson}'); // } catch (e) { // print('🔴 Error decrypting FCM key: $e'); // } // } // void sendNotificationAll(String title, body, tone) async { // // توكني الحالي (لا أرسل لنفسي) // final String myToken = box.read(BoxName.tokenFCM) ?? ''; // // اقرأ قائمة كل التوكنات // final List all = // List.from(box.read(BoxName.tokens) ?? const []); // // استبعد توكنك واحذف الفارغ // final targets = all.where((t) => t.isNotEmpty && t != myToken).toList(); // if (serviceAccountKeyJson.isEmpty) { // print("🔴 Error: Service Account Key is empty"); // return; // } // final accessTokenManager = AccessTokenManager(serviceAccountKeyJson); // final accessToken = await accessTokenManager.getAccessToken(); // for (final t in targets) { // // ⚠️ المهم: استخدم t (توكن الهدف)، وليس المتغير myToken // final response = await http.post( // Uri.parse( // 'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'), // headers: { // 'Content-Type': 'application/json', // 'Authorization': 'Bearer $accessToken', // }, // body: jsonEncode({ // 'message': { // 'token': t, // 'notification': {'title': title, 'body': body}, // 'android': { // 'priority': 'HIGH', // القيم الصحيحة: HIGH/NORMAL // 'notification': {'sound': tone}, // // (اختياري) TTL لتجنّب رسائل قديمة // 'ttl': '30s', // }, // 'apns': { // 'headers': { // 'apns-priority': '10', // // لو iOS: حدد نوع الدفع // 'apns-push-type': 'alert', // }, // 'payload': { // 'aps': {'sound': tone} // }, // }, // }, // }), // ); // if (response.statusCode != 200) { // // حاول تقرأ الخطأ وتشيل التوكنات التالفة // _handleV1Error(response, badToken: t); // await Future.delayed(const Duration(milliseconds: 50)); // تخفيف ضغط // } // } // } // void _handleV1Error(http.Response res, {required String badToken}) { // try { // final body = jsonDecode(res.body); // final err = body['error']?['status']?.toString() ?? ''; // // أمثلة شائعة: // if (err.contains('UNREGISTERED') || err.contains('NOT_FOUND')) { // removeInvalidToken(badToken); // } else if (err.contains('INVALID_ARGUMENT')) { // // payload غير صحيح // print( // '⚠️ INVALID_ARGUMENT for $badToken: ${body['error']?['message']}'); // } else if (err.contains('RESOURCE_EXHAUSTED') || // err.contains('QUOTA_EXCEEDED')) { // // تجاوزت الحصة—خفّف السرعة/قسّم الإرسال (FCM v1 له حصة/دقيقة) // // https docs: 600k req/min per project (token bucket) // print('⏳ Throttled by FCM: slow down sending rate.'); // } else { // print('FCM v1 error: ${res.statusCode} ${res.body}'); // } // } catch (_) { // print('FCM v1 error: ${res.statusCode} ${res.body}'); // } // } // void sendNotificationToPassengerToken( // String title, body, token, List map, String tone, // {int retryCount = 2}) async { // try { // if (serviceAccountKeyJson.isEmpty) { // print("🔴 Error: Service Account Key is empty"); // return; // } // // Initialize AccessTokenManager // final accessTokenManager = AccessTokenManager(serviceAccountKeyJson); // // Obtain an OAuth 2.0 access token // final accessToken = await accessTokenManager.getAccessToken(); // // Log.print('accessToken: ${accessToken}'); // // Send the notification // final response = await http.post( // Uri.parse( // 'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'), // headers: { // 'Content-Type': 'application/json', // 'Authorization': 'Bearer $accessToken', // }, // body: jsonEncode({ // 'message': { // 'token': token, // 'notification': { // 'title': title, // 'body': body, // }, // 'data': { // 'passengerList': jsonEncode(map), // }, // 'android': { // 'priority': 'HIGH ', // Set priority to high // 'notification': { // 'sound': tone, // }, // }, // 'apns': { // 'headers': { // 'apns-priority': '10', // Set APNs priority to 10 // }, // 'payload': { // 'aps': { // 'sound': tone, // }, // }, // }, // }, // }), // ); // if (response.statusCode == 200) { // print( // 'Notification sent successfully. Status code: ${response.statusCode}'); // print('Response body: ${response.body}'); // } else { // print( // 'Failed to send notification. Status code: ${response.statusCode}'); // print('Response body: ${response.body}'); // if (retryCount > 0) { // print('Retrying... Attempts remaining: $retryCount'); // await Future.delayed( // const Duration(seconds: 2)); // Optional delay before retrying // return sendNotificationToPassengerToken(title, body, token, map, tone, // retryCount: retryCount - 1); // } // } // } catch (e) { // print('Error sending notification: $e'); // if (retryCount > 0) { // print('Retrying... Attempts remaining: $retryCount'); // await Future.delayed( // const Duration(seconds: 2)); // Optional delay before retrying // return sendNotificationToPassengerToken(title, body, token, map, tone, // retryCount: retryCount - 1); // } // } // } // void sendNotificationToPassengerTokenCALL( // String title, body, token, List map, String tone, // {int retryCount = 2}) async { // try { // if (serviceAccountKeyJson.isEmpty) { // print("🔴 Error: Service Account Key is empty"); // return; // } // // Initialize AccessTokenManager // final accessTokenManager = AccessTokenManager(serviceAccountKeyJson); // // Obtain an OAuth 2.0 access token // final accessToken = await accessTokenManager.getAccessToken(); // // Log.print('accessToken: ${accessToken}'); // // Send the notification // final response = await http.post( // Uri.parse( // 'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'), // headers: { // 'Content-Type': 'application/json', // 'Authorization': 'Bearer $accessToken', // }, // body: jsonEncode({ // 'message': { // 'token': token, // 'notification': { // 'title': title, // 'body': body, // }, // 'data': { // 'passengerList': jsonEncode(map), // }, // 'android': { // 'priority': 'HIGH ', // Set priority to high // 'notification': { // 'sound': tone, // }, // }, // 'apns': { // 'headers': { // 'apns-priority': '10', // Set APNs priority to 10 // }, // 'payload': { // 'aps': { // 'sound': tone, // }, // }, // }, // }, // }), // ); // if (response.statusCode == 200) { // print( // 'Notification sent successfully. Status code: ${response.statusCode}'); // print('Response body: ${response.body}'); // } else { // print( // 'Failed to send notification. Status code: ${response.statusCode}'); // print('Response body: ${response.body}'); // if (retryCount > 0) { // print('Retrying... Attempts remaining: $retryCount'); // await Future.delayed( // const Duration(seconds: 2)); // Optional delay before retrying // return sendNotificationToPassengerTokenCALL( // title, body, token, map, tone, // retryCount: retryCount - 1); // } // } // } catch (e) { // print('Error sending notification: $e'); // if (retryCount > 0) { // print('Retrying... Attempts remaining: $retryCount'); // await Future.delayed( // const Duration(seconds: 2)); // Optional delay before retrying // return sendNotificationToPassengerTokenCALL( // title, body, token, map, tone, // retryCount: retryCount - 1); // } // } // } // Future sendNotificationToDriverMAP( // String title, String body, String token, List data, String tone, // {int retryCount = 2}) async { // try { // if (serviceAccountKeyJson.isEmpty) { // print("🔴 Error: Service Account Key is empty"); // return; // } // // Initialize AccessTokenManager // final accessTokenManager = AccessTokenManager(serviceAccountKeyJson); // Log.print( // 'accessTokenManager: ${accessTokenManager.serviceAccountJsonKey}'); // // Obtain an OAuth 2.0 access token // final accessToken = await accessTokenManager.getAccessToken(); // // Log.print('accessToken: ${accessToken}'); // // Send the notification // final response = await http.post( // Uri.parse( // 'https://fcm.googleapis.com/v1/projects/intaleq-d48a7/messages:send'), // headers: { // 'Content-Type': 'application/json', // 'Authorization': 'Bearer $accessToken', // }, // body: jsonEncode({ // 'message': { // 'token': token, // 'notification': { // 'title': title, // 'body': body, // }, // 'data': { // 'DriverList': jsonEncode(data), // }, // 'android': { // 'priority': 'HIGH ', // Set priority to high // 'notification': { // 'sound': tone, // }, // }, // 'apns': { // 'headers': { // 'apns-priority': '10', // Set APNs priority to 10 // }, // 'payload': { // 'aps': { // 'sound': tone, // }, // }, // }, // }, // }), // ); // if (response.statusCode == 200) { // print( // 'Notification sent successfully. Status code: ${response.statusCode}'); // // print('Response token: ${token}'); // } else { // print( // 'Failed to send notification. Status code: ${response.statusCode}'); // print('Response body: ${response.body}'); // if (retryCount > 0) { // print('Retrying... Attempts remaining: $retryCount'); // await Future.delayed( // Duration(seconds: 2)); // Optional delay before retrying // return sendNotificationToDriverMAP(title, body, token, data, tone, // retryCount: retryCount - 1); // } // } // } catch (e) { // print('Error sending notification: $e'); // if (retryCount > 0) { // print('Retrying... Attempts remaining: $retryCount'); // await Future.delayed( // Duration(seconds: 2)); // Optional delay before retrying // return sendNotificationToDriverMAP(title, body, token, data, tone, // retryCount: retryCount - 1); // } // } // } // Future removeInvalidToken(String token) async { // // Remove token from your database/storage // // This prevents future attempts to send to invalid tokens // print('Removing invalid token from database: $token'); // // Your database cleanup logic here // } } class OverlayContent extends StatelessWidget { final String title; final String body; OverlayContent(this.title, this.body); @override Widget build(BuildContext context) { return Material( child: Container( padding: const EdgeInsets.all(16.0), color: Colors.white, child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( title, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), const SizedBox(height: 8.0), Text( body, style: const TextStyle(fontSize: 16), ), ], ), ), ); } }