Update: 2026-07-23 22:14:10
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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": " أنا استخدم",
|
||||||
|
|||||||
@@ -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": " أنا استخدم",
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user