import 'dart:convert'; import 'dart:io'; import 'package:sefer_driver/controller/home/captin/home_captain_controller.dart'; import 'package:sefer_driver/views/home/Captin/orderCaptin/order_speed_request.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:sefer_driver/views/widgets/elevated_btn.dart'; import '../../constant/box_name.dart'; import '../../constant/colors.dart'; import '../../constant/style.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_request_page.dart'; import '../../views/home/Captin/orderCaptin/vip_order_page.dart'; import '../auth/google_sign.dart'; import '../functions/face_detect.dart'; import '../home/captin/map_driver_controller.dart'; import 'local_notification.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!)); }); // 🔹 الاشتراك في topic await fcmToken.subscribeToTopic("drivers"); // أو "users" حسب نوع المستخدم print("Subscribed to 'drivers' topic ✅"); 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) { 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) { fireBaseTitles(message); } }); } Future fireBaseTitles(RemoteMessage message) async { // [!! تعديل جوهري !!] // اقرأ "النوع" من حمولة البيانات، وليس من العنوان String category = message.data['category'] ?? ''; // اقرأ العنوان والنص (للعرض) String title = message.notification?.title ?? ''; String body = message.notification?.body ?? ''; // استخدم switch لسهولة القراءة والصيانة switch (category) { case 'ORDER': case 'Order': // Handle both cases for backward compatibility if (Platform.isAndroid) { notificationController.showNotification(title, body, 'order', ''); } var myListString = message.data['DriverList']; if (myListString != null) { var myList = jsonDecode(myListString) as List; driverToken = myList[14].toString(); Get.put(HomeCaptainController()).changeRideId(); update(); Get.toNamed('/OrderRequestPage', arguments: { 'myListString': myListString, 'DriverList': myList, 'body': body }); } break; case 'OrderVIP': var myListString = message.data['DriverList']; if (myListString != null) { var myList = jsonDecode(myListString) as List; if (Platform.isAndroid) { notificationController.showNotification(title, body, 'order', ''); } Get.to(VipOrderPage(), arguments: { 'myListString': myListString, 'DriverList': myList, 'body': body }); } break; case 'Cancel Trip': case 'TRIP_CANCELLED': if (Platform.isAndroid) { notificationController.showNotification( title, 'Passenger Cancel Trip'.tr, 'cancel', ''); } Log.print("🔔 FCM: Ride Cancelled by Passenger received."); // 1. استخراج السبب (أرسلناه من PHP باسم 'reason') String reason = message.data['reason'] ?? 'No reason provided'; // 2. توجيه الأمر للكنترولر if (Get.isRegistered()) { // استدعاء الحارس (سيتجاهل الأمر إذا كان السوكيت قد سبقه) Get.find() .processRideCancelledByPassenger(reason, source: "FCM"); } break; case 'VIP Order Accepted': // This seems to be a notification for the passenger, but if the driver needs to see it: if (Platform.isAndroid) { notificationController.showNotification(title, body, 'order', ''); } // Maybe show a simple snackbar confirmation mySnackbarSuccess('You accepted the VIP order.'.tr); break; case 'message From passenger': case 'MSG_FROM_PASSENGER': if (Platform.isAndroid) { notificationController.showNotification(title, body, 'ding', ''); } MyDialog().getDialog(title, body, () { Get.back(); }); break; case 'token change': case 'TOKEN_CHANGE': GoogleSignInHelper.signOut(); break; case 'face detect': case 'FACE_DETECT': if (Platform.isAndroid) { notificationController.showNotification(title, body, 'tone2', ''); } String result0 = await faceDetector(); 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(); break; case 'Hi ,I will go now': case 'PASSENGER_COMING': if (Platform.isAndroid) { notificationController.showNotification(title, body, 'tone2', ''); } update(); break; case 'Criminal Document Required': case 'DOC_REQUIRED': if (Platform.isAndroid) { notificationController.showNotification(title, body, 'tone2', ''); } MyDialog().getDialog(title, 'You should have upload it .'.tr, () { Get.to(() => const CriminalDocumemtPage()); }); break; case 'Order Applied': case 'ORDER_TAKEN': mySnackbarSuccess("The order has been accepted by another driver.".tr); break; default: Log.print('Received unhandled notification category: $category'); // Optionally show a generic notification if (Platform.isAndroid) { notificationController.showNotification(title, body, 'default', ''); } break; } } 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()); })); } } 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), ), ], ), ), ); } }