Update: 2026-07-23 22:14:10

This commit is contained in:
Hamza-Ayed
2026-07-23 22:14:10 +03:00
parent 695d6d7cb2
commit e7629a9eb9
8 changed files with 131 additions and 13 deletions
+6 -6
View File
@@ -16,15 +16,15 @@ function resolveServiceAccountPath(): string {
if (!empty($envPath) && file_exists($envPath)) { if (!empty($envPath) && file_exists($envPath)) {
return $envPath; return $envPath;
} }
if (file_exists('/keys/firebase_service_account.json')) { // if (file_exists('/keys/firebase_service_account.json')) {
return '/keys/firebase_service_account.json'; // return '/keys/firebase_service_account.json';
} // }
if (file_exists('/keys/service-account.json')) { if (file_exists('/keys/service-account.json')) {
return '/keys/service-account.json'; return '/keys/service-account.json';
} }
if (file_exists(__DIR__ . '/../../keys/firebase_service_account.json')) { // if (file_exists(__DIR__ . '/../../keys/firebase_service_account.json')) {
return __DIR__ . '/../../keys/firebase_service_account.json'; // return __DIR__ . '/../../keys/firebase_service_account.json';
} // }
return __DIR__ . '/service-account.json'; return __DIR__ . '/service-account.json';
} }
@@ -134,10 +134,6 @@ class FirebaseMessagesController extends GetxController {
switch (category) { switch (category) {
case 'ORDER': case 'ORDER':
case 'Order': // Handle both cases for backward compatibility case 'Order': // Handle both cases for backward compatibility
// if (Platform.isAndroid) {
// notificationController.showNotification(title, body, 'order', '');
// }
// 🔥 [Fix FCM-Guard] منع إعاقة الرحلة النشطة بطلبات جديدة عبر FCM // 🔥 [Fix FCM-Guard] منع إعاقة الرحلة النشطة بطلبات جديدة عبر FCM
String currentRideStatus = box.read(BoxName.rideStatus) ?? ''; String currentRideStatus = box.read(BoxName.rideStatus) ?? '';
if (currentRideStatus == 'Begin' || if (currentRideStatus == 'Begin' ||
@@ -150,6 +146,11 @@ class FirebaseMessagesController extends GetxController {
var myListString = message.data['DriverList']; var myListString = message.data['DriverList'];
if (myListString != null) { if (myListString != null) {
if (Platform.isAndroid) {
notificationController.showOrderNotification(
title, body, 'ding.wav', myListString);
}
var myList = jsonDecode(myListString) as List<dynamic>; var myList = jsonDecode(myListString) as List<dynamic>;
driverToken = myList[14].toString(); driverToken = myList[14].toString();
Get.put(HomeCaptainController(), permanent: true).changeRideId(); Get.put(HomeCaptainController(), permanent: true).changeRideId();
@@ -124,6 +124,11 @@ class FirebaseMessagesController extends GetxController {
// ... داخل معالج الإشعارات في تطبيق الراكب ... // ... داخل معالج الإشعارات في تطبيق الراكب ...
else if (category == 'Accepted Ride') { else if (category == 'Accepted Ride') {
if (Platform.isAndroid) {
String notifTitle = 'Ride Accepted ✅'.tr;
String notifBody = 'The captain is on their way to you now.'.tr;
notificationController.showNotification(notifTitle, notifBody, 'ding');
}
if (mapCtrl != null) { if (mapCtrl != null) {
Map<String, dynamic>? driverInfoMap; Map<String, dynamic>? driverInfoMap;
@@ -198,6 +203,11 @@ class FirebaseMessagesController extends GetxController {
update(); update();
} else if (category == 'Trip is Begin') { } else if (category == 'Trip is Begin') {
// <-- كان 'Trip is Begin' // <-- كان 'Trip is Begin'
if (Platform.isAndroid) {
String notifTitle = 'Trip Begun 🚀'.tr;
String notifBody = 'Have a safe and comfortable trip.'.tr;
notificationController.showNotification(notifTitle, notifBody, 'ding');
}
Log.print('[FCM] استقبل إشعار "TRIP_BEGUN".'); Log.print('[FCM] استقبل إشعار "TRIP_BEGUN".');
// استدعاء الحارس // استدعاء الحارس
mapCtrl!.processRideBegin(source: "FCM"); mapCtrl!.processRideBegin(source: "FCM");
@@ -208,9 +218,19 @@ class FirebaseMessagesController extends GetxController {
} }
update(); update();
} else if (category == "Arrive Ride") { } else if (category == "Arrive Ride") {
if (Platform.isAndroid) {
String notifTitle = 'Driver is outside 🚖'.tr;
String notifBody = 'The captain has arrived at your location.'.tr;
notificationController.showNotification(notifTitle, notifBody, 'ding');
}
// استدعاء الحارس // استدعاء الحارس
mapCtrl!.processDriverArrival("FCM"); mapCtrl!.processDriverArrival("FCM");
} else if (category == 'Driver Finish Trip') { } else if (category == 'Driver Finish Trip') {
if (Platform.isAndroid) {
String notifTitle = 'Trip Finished 🏁'.tr;
String notifBody = 'Please pay and rate the driver.'.tr;
notificationController.showNotification(notifTitle, notifBody, 'ding');
}
List<dynamic> driverList = []; List<dynamic> driverList = [];
// ✅ معالجة آمنة للبيانات // ✅ معالجة آمنة للبيانات
@@ -66,6 +66,27 @@ class NotificationController extends GetxController {
id: 0, title: title, body: message, notificationDetails: details); id: 0, title: title, body: message, notificationDetails: details);
Log.print('Notification shown: $title - $message'); Log.print('Notification shown: $title - $message');
} }
// 🆕 Static method for background isolates where GetX might not be initialized
static Future<void> showBackgroundNotification(String title, String message, String tone) async {
final FlutterLocalNotificationsPlugin plugin = FlutterLocalNotificationsPlugin();
const AndroidInitializationSettings android = AndroidInitializationSettings('@mipmap/launcher_icon');
const DarwinInitializationSettings ios = DarwinInitializationSettings();
await plugin.initialize(settings: const InitializationSettings(android: android, iOS: ios));
final AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
'high_importance_channel',
'High Importance Notifications',
importance: Importance.max,
priority: Priority.high,
showWhen: false,
sound: RawResourceAndroidNotificationSound(tone),
);
const DarwinNotificationDetails iosDetails = DarwinNotificationDetails(sound: 'default');
await plugin.show(id: 0, title: title, body: message, notificationDetails: NotificationDetails(android: androidDetails, iOS: iosDetails));
Log.print('Background notification shown: $title - $message');
}
// /Users/hamzaaleghwairyeen/development/App/ride 2/lib/controller/firebase/local_notification.dart // /Users/hamzaaleghwairyeen/development/App/ride 2/lib/controller/firebase/local_notification.dart
// Assume _flutterLocalNotificationsPlugin is initialized somewhere in your code // Assume _flutterLocalNotificationsPlugin is initialized somewhere in your code
+12 -1
View File
@@ -21,7 +21,18 @@ final Map<String, String> ar_eg = {
"Stops": "محطات", "Stops": "محطات",
"No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن", "No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن",
"Bus is delayed": "الباص متأخر", "Bus is delayed": "الباص متأخر",
"Missed the bus? Book a ride now": "فاتك الأتوبيس؟ احجز سيارة دلوقتي", "Missed the bus? Book a ride now": "فاتك الباص؟ اطلب سيارة الآن",
// ── FCM Notifications ──
"Ride Accepted ✅": "تم قبول رحلتك ✅",
"The captain is on their way to you now.": "الكابتن في طريقه إليك الآن.",
"Driver is outside 🚖": "السائق في الخارج 🚖",
"The captain has arrived at your location.": "الكابتن وصل إلى موقعك، الرجاء التوجه إليه.",
"Trip Begun 🚀": "بدأت الرحلة 🚀",
"Have a safe and comfortable trip.": "نتمنى لك رحلة آمنة ومريحة.",
"Trip Finished 🏁": "تم إنهاء الرحلة 🏁",
"Please pay and rate the driver.": "الرجاء الدفع وتقييم السائق.",
" ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using", " ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using",
" I am currently located at ": " أنا حالياً في ", " I am currently located at ": " أنا حالياً في ",
" I am using": " أنا استخدم", " I am using": " أنا استخدم",
@@ -22,6 +22,16 @@ final Map<String, String> ar_jo = {
"No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن", "No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن",
"Bus is delayed": "الباص متأخر", "Bus is delayed": "الباص متأخر",
"Missed the bus? Book a ride now": "فاتك الباص؟ اطلب سيارة الآن", "Missed the bus? Book a ride now": "فاتك الباص؟ اطلب سيارة الآن",
// ── FCM Notifications ──
"Ride Accepted ✅": "تم قبول رحلتك ✅",
"The captain is on their way to you now.": "الكابتن في طريقه إليك الآن.",
"Driver is outside 🚖": "السائق في الخارج 🚖",
"The captain has arrived at your location.": "الكابتن وصل إلى موقعك، الرجاء التوجه إليه.",
"Trip Begun 🚀": "بدأت الرحلة 🚀",
"Have a safe and comfortable trip.": "نتمنى لك رحلة آمنة ومريحة.",
"Trip Finished 🏁": "تم إنهاء الرحلة 🏁",
"Please pay and rate the driver.": "الرجاء الدفع وتقييم السائق.",
" ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using", " ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using",
" I am currently located at ": " أنا حالياً في ", " I am currently located at ": " أنا حالياً في ",
" I am using": " أنا استخدم", " I am using": " أنا استخدم",
+12 -1
View File
@@ -21,7 +21,18 @@ final Map<String, String> ar_sy = {
"Stops": "محطات", "Stops": "محطات",
"No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن", "No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن",
"Bus is delayed": "الباص متأخر", "Bus is delayed": "الباص متأخر",
"Missed the bus? Book a ride now": "فاتك الباص؟ اطلب سيارة هلق", "Missed the bus? Book a ride now": "فاتك الباص؟ اطلب سيارة الآن",
// ── FCM Notifications ──
"Ride Accepted ✅": "تم قبول رحلتك ✅",
"The captain is on their way to you now.": "الكابتن في طريقه إليك الآن.",
"Driver is outside 🚖": "السائق في الخارج 🚖",
"The captain has arrived at your location.": "الكابتن وصل إلى موقعك، الرجاء التوجه إليه.",
"Trip Begun 🚀": "بدأت الرحلة 🚀",
"Have a safe and comfortable trip.": "نتمنى لك رحلة آمنة ومريحة.",
"Trip Finished 🏁": "تم إنهاء الرحلة 🏁",
"Please pay and rate the driver.": "الرجاء الدفع وتقييم السائق.",
" ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using", " ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using",
" I am currently located at ": " أنا حالياً في ", " I am currently located at ": " أنا حالياً في ",
" I am using": " أنا استخدم", " I am using": " أنا استخدم",
+45 -1
View File
@@ -23,6 +23,7 @@ import 'controller/home/ios_live_activity_service.dart';
import 'services/android_live_update_service.dart'; import 'services/android_live_update_service.dart';
import 'controller/local/local_controller.dart'; import 'controller/local/local_controller.dart';
import 'controller/local/translations.dart'; import 'controller/local/translations.dart';
import 'controller/firebase/local_notification.dart';
import 'controller/themes/themes.dart'; import 'controller/themes/themes.dart';
import 'firebase_options.dart'; import 'firebase_options.dart';
import 'models/db_sql.dart'; import 'models/db_sql.dart';
@@ -72,6 +73,48 @@ Future<void> backgroundMessageHandler(RemoteMessage message) async {
} catch (e) { } catch (e) {
Log.print("Silent push location update failed: $e"); Log.print("Silent push location update failed: $e");
} }
// 🆕 عرض الإشعارات المترجمة في الخلفية
try {
final category = message.data['category'] ?? '';
if (category == 'Accepted Ride' ||
category == 'Arrive Ride' ||
category == 'Trip is Begin' ||
category == 'Driver Finish Trip') {
final storage = GetStorage();
final lang = storage.read(BoxName.lang) ?? 'ar';
String titleKey = '';
String bodyKey = '';
if (category == 'Accepted Ride') {
titleKey = 'Ride Accepted ✅';
bodyKey = 'The captain is on their way to you now.';
} else if (category == 'Arrive Ride') {
titleKey = 'Driver is outside 🚖';
bodyKey = 'The captain has arrived at your location.';
} else if (category == 'Trip is Begin') {
titleKey = 'Trip Begun 🚀';
bodyKey = 'Have a safe and comfortable trip.';
} else if (category == 'Driver Finish Trip') {
titleKey = 'Trip Finished 🏁';
bodyKey = 'Please pay and rate the driver.';
}
// ترجمة باستخدام ملفات الترجمة حتى في الخلفية
String title = titleKey;
String body = bodyKey;
if (lang.toString().startsWith('ar')) {
title = MyTranslation().keys['ar']?[titleKey] ?? titleKey;
body = MyTranslation().keys['ar']?[bodyKey] ?? bodyKey;
}
// عرض الإشعار المحلي عبر الكلاس المخصص
await NotificationController.showBackgroundNotification(title, body, 'ding');
}
} catch (e) {
Log.print("Background local notification failed: $e");
}
} }
} }
@@ -99,7 +142,8 @@ void main() {
// Initialize Geofencing Service only if permission is already granted to avoid auto-prompt // Initialize Geofencing Service only if permission is already granted to avoid auto-prompt
if (Platform.isAndroid || Platform.isIOS) { if (Platform.isAndroid || Platform.isIOS) {
LocationPermission permission = await Geolocator.checkPermission(); LocationPermission permission = await Geolocator.checkPermission();
if (permission != LocationPermission.denied && permission != LocationPermission.deniedForever) { if (permission != LocationPermission.denied &&
permission != LocationPermission.deniedForever) {
await SiroGeofencingService.initAndStart(); await SiroGeofencingService.initAndStart();
} }
} }