diff --git a/android/app/build.gradle b/android/app/build.gradle index 8fc02fb..e29d183 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -44,8 +44,8 @@ android { applicationId = "com.intaleq_driver" minSdk = 29 targetSdk = 36 - versionCode = 17 // I've used the higher version number from your first file - versionName = '1.0.17' // I've used the higher version name + versionCode = 18 + versionName = '1.0.18' // I've used the higher version name multiDexEnabled = true ndk { diff --git a/lib/constant/notification.dart b/lib/constant/notification.dart index 0d25a7d..b9654bb 100755 --- a/lib/constant/notification.dart +++ b/lib/constant/notification.dart @@ -1,31 +1,31 @@ List syrianDriverMessages = [ - // --- رسائل وقت الذروة والطلبات المستعجلة --- - "البلد ولعانة هلأ! 🌃 هاد وقت الذروة، فرصة ذهبية لتدبّل أرباحك. انطلق معنا!", - "انتبه: الطلبات كتيرة بمنطقتك! ⚠️ خليك أول واحد بياخد مشوار واكسب أكتر. جاهز تطلع؟", - "لا تروح عليك ساعة الذروة! ⏳ زباين أكتر يعني مصاري أكتر. فوت عالبرنامج هلأ!", - "خلص الدوام عند كتير عالم، وصار وقت يرجعوا عالبيت! 🌇 خليك بطلن ووصلن بأمان.", + // --- أوقات الذروة والطلبات الكتيرة --- + "وقت الذروة: البلد مولّعة مشاوير! 🌃 افتح التطبيق بسرعة وبلّش أرباحك تدبّل.", + "طلبات كتير حواليك: ⚠️ خليك أول كابتن بيلتقط الطلب وخلّي يومك رابح.", + "الناس طالعة من الشغل: 🌇 الكل راجع عالبيت، خليك جاهز لرحلات كتيرة!", + "زحمة المساء: ⏳ الزباين عم تزيد بهالوقت، لا تضيّع الفرصة واشتغل معنا!", - // --- رسائل للتركيز عالربح والمصاري --- - "هدف اليوم صار قريب! 💪 كل مشوار بيقربك أكتر. بلّش مشوارك الجاي هلأ.", - "جزدانك ناطر مصاري زيادة! 💰 فوت عالبرنامج وحوّل وقتك لمصاري عنجد ومضمونة.", - "كبسة زر بتجيبلك ربح زيادة. جاهز للطلب الجاي؟ 🤔", - "لا تترك المصاري عالأرض! 💸 زباين انطلق عم يدوروا على كابتن شاطر متلك هلأ.", + // --- التركيز عالربح والمصاري --- + "ضاعف ربحك: 💰 كل مشوار بيقربك من هدفك اليومي. جاهز تنطلق؟", + "مصاري أكتر: جزدانك ناطر تعبك، كل دقيقة شغل هي ربح مضمون. 💪", + "خليك بالواجهة: الطلب الجاي ممكن يكون إلك، كبسة زر بتجيبلك رزقة اليوم.", + "رزقتك جاهزة: 💸 لا تخلّي الزباين يستنّوا، افتح التطبيق وخليك متأهّب.", - // --- رسائل تقدير وشكر --- - "أنت مو بس شوفير، أنت شريكنا بالنجاح. 🙏 زباينّا ناطرينك. يسلم إيديك!", - "نحنا عم نكبر فيك! 🌟 خليك فاتح واستقبل مشاوير جديدة من زباينّا الكويسين.", - "كباتنّا هنن الأحسن! 👍 ضل عم تقدّم هالخدمة الحلوة اللي بيعرفوها زباينا عن تطبيق انطلق.", - "كل توصيلة ناجحة هي قصة نجاح لإلك وإلنا. خلينا نعمل قصص نجاح أكتر اليوم! 🗺️", + // --- التقدير والشكر --- + "شكراً إلك: 🙏 إنت مو بس سائق، إنت أساس نجاح تطبيق انطلق.", + "نفتخر فيك: 🌟 الكباتن متلك هنن يلي رافعين اسمنا بالعالي.", + "أداء ممتاز: 👍 استمر بنفس الروح الحلوة، زباينك مبسوطين منك.", + "نجاح مشترك: 🗺️ كل توصيلة بتعملها بتكبر فيها شركتنا وانت كمان.", - // --- رسائل تحفيز وتشجيع --- - "يوم جديد، فرصة جديدة للنجاح! ☀️ فوت عالبرنامج وخلينا ننطلق سوا لأهدافك.", - "طريق النجاح ببلّش بمشوار. 🏁 خود مشوارك الجاي واعمل إنجازات أكتر.", - "فيك تعمل دخل كتير منيح اليوم. نحنا واثقين فيك! انطلق هلأ. 💼", - "الطلب الجاي يمكن يكون الأحسن! لا تضيّع فرصتك. فوت عالبرنامج وخليك جاهز. 🔔", + // --- التحفيز والتشجيع --- + "صباح النشاط: ☀️ بلّش نهارك بطاقة إيجابية وانطلق لتكسب أكتر.", + "كل مشوار فرصة: 🏁 لا توقف، الطريق لإلك والنجاح ناطرك.", + "يوم مربح: 💼 السوق ناشط اليوم، لا تفوّت الفرصة!", + "جاهز للطلب الجاي: 🔔 الزبون الجاي ممكن يكون أوفر ممتاز، خليك مستعد.", - // --- رسائل نصايح ومعلومات --- - "نصيحة اليوم: روح عالأسواق والمطاعم هلأ بتزيد فرصة يجيك مشاوير. 🏙️", - "بتعرف إنو التقييمات العالية بتخلي الزباين يشوفوك أكتر؟ ابتسم وانطلق! 😊", - "يمكن تشتّي بعد شوي! 🌧️ الطلب بيزيد بهيك جو، فرصة ممتازة تزود مصاريك.", - "في حفلة كبيرة بقلب البلد اليوم. 🎆 جهّز حالك للمشاوير الكتيرة بهديك المنطقة." + // --- نصايح ومعلومات --- + "نصيحة اليوم: روح صوب الأسواق والمطاعم، الطلب هناك عالي هالفترة. 🏙️", + "حافظ على تقييمك: 😊 الزبون بينجذب للكابتن يلي عنده تقييم عالي وابتسامة.", + "جو ممطر: 🌧️ المطر يعني طلبات أكتر، خليك شغّال بهالوقت!", + "حدث اليوم: 🎆 في فعالية بالبلد، المشاوير كتيرة بهالمنطقة، استغلها!" ]; diff --git a/lib/controller/auth/captin/invit_controller.dart b/lib/controller/auth/captin/invit_controller.dart index 66f7826..892449e 100755 --- a/lib/controller/auth/captin/invit_controller.dart +++ b/lib/controller/auth/captin/invit_controller.dart @@ -356,8 +356,8 @@ Download the Intaleq app now and enjoy your ride! '${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n' '_*${d['message']['inviteCode'].toString()}*_\n\n' '${"Install our app:".tr}\n' - '*Android:* https://play.google.com/store/apps/details?id=com.sefer_driver\n\n\n' - '*iOS:* https://apps.apple.com/ae/app/sefer-driver/id6502189302'; + '*Android:* https://play.google.com/store/apps/details?id=com.intaleq_driver\n\n\n' + '*iOS:* https://apps.apple.com/st/app/intaleq-driver/id6482995159'; launchCommunication('whatsapp', formattedPhoneNumber, message); invitePhoneController.clear(); @@ -395,8 +395,8 @@ Download the Intaleq app now and enjoy your ride! '${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n' '_*${d['message']['inviteCode'].toString()}*_\n\n' '${"Install our app:".tr}\n' - '*Android:* https://play.google.com/store/apps/details?id=com.mobileapp.store.ride\n\n\n' - '*iOS:* https://apps.apple.com/us/app/sefer/id6458734951'; + '*Android:* https://play.google.com/store/apps/details?id=com.Intaleq.intaleq\n\n\n' + '*iOS:* https://apps.apple.com/st/app/intaleq-rider/id6748075179'; launchCommunication('whatsapp', formattedPhoneNumber, message); invitePhoneController.clear(); diff --git a/lib/controller/auth/captin/login_captin_controller.dart b/lib/controller/auth/captin/login_captin_controller.dart index 898e757..2a6b8b3 100755 --- a/lib/controller/auth/captin/login_captin_controller.dart +++ b/lib/controller/auth/captin/login_captin_controller.dart @@ -26,6 +26,7 @@ import '../../../views/auth/captin/otp_page.dart'; import '../../../views/auth/captin/otp_token_page.dart'; import '../../../views/auth/syria/pending_driver_page.dart'; import '../../firebase/firbase_messge.dart'; +import '../../firebase/notification_service.dart'; import '../../functions/encrypt_decrypt.dart'; import '../../functions/package_info.dart'; import '../../functions/secure_storage.dart'; @@ -258,7 +259,7 @@ class LoginDriverController extends GetxController { update(); await SecurityHelper.performSecurityChecks(); // Log.print('(BoxName.emailDriver): ${box.read(BoxName.emailDriver)}'); - + // await getJWT(); var res = await CRUD().get(link: AppLink.loginFromGoogleCaptin, payload: { 'email': email ?? 'yet', 'id': driverID, @@ -328,8 +329,11 @@ class LoginDriverController extends GetxController { // if (box.read(BoxName.emailDriver).toString() != // '963992952235@intaleqapp.com') { if (token != 'failure') { - if ((jsonDecode(token)['data'][0]['token'].toString()) != - box.read(BoxName.tokenDriver).toString()) { + var serverData = jsonDecode(token); + if ((serverData['data'][0]['token'].toString()) != + box.read(BoxName.tokenDriver).toString() || + serverData['data'][0]['fingerPrint'].toString() != + fingerPrint.toString()) { await Get.defaultDialog( barrierDismissible: false, title: 'Device Change Detected'.tr, @@ -534,12 +538,20 @@ class LoginDriverController extends GetxController { if (token != 'failure') { if ((jsonDecode(token)['data'][0]['token']) != (box.read(BoxName.tokenDriver))) { - Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP( - 'token change'.tr, - 'change device'.tr, - (jsonDecode(token)['data'][0]['token']).toString(), - [], - 'ding.wav'); + // Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP( + // 'token change'.tr, + // 'change device'.tr, + // (jsonDecode(token)['data'][0]['token']).toString(), + // [], + // 'ding.wav'); + NotificationService.sendNotification( + target: (jsonDecode(token)['data'][0]['token']).toString(), + title: 'token change', + body: 'token change'.tr, + isTopic: false, // Important: this is a token + tone: 'cancel', + driverList: [], + ); Get.defaultDialog( title: 'you will use this device?'.tr, middleText: '', diff --git a/lib/controller/auth/captin/opt_token_controller.dart b/lib/controller/auth/captin/opt_token_controller.dart index 5c1bea4..35346c2 100644 --- a/lib/controller/auth/captin/opt_token_controller.dart +++ b/lib/controller/auth/captin/opt_token_controller.dart @@ -8,6 +8,7 @@ import '../../../constant/box_name.dart'; import '../../../constant/links.dart'; import '../../../main.dart'; import '../../firebase/firbase_messge.dart'; +import '../../firebase/notification_service.dart'; import '../../functions/crud.dart'; class OtpVerificationController extends GetxController { @@ -101,12 +102,20 @@ class OtpVerificationController extends GetxController { ? Get.find() : Get.put(FirebaseMessagesController()); - await fcm.sendNotificationToDriverMAP( - 'token change', - 'change device'.tr, - ptoken.toString(), - [], - 'cancel.wav', + // await fcm.sendNotificationToDriverMAP( + // 'token change', + // 'change device'.tr, + // ptoken.toString(), + // [], + // 'cancel.wav', + // ); + await NotificationService.sendNotification( + target: ptoken.toString(), + title: 'token change', + body: 'token change'.tr, + isTopic: false, // Important: this is a token + tone: 'cancel', + driverList: [], ); Get.offAll(() => HomeCaptain()); diff --git a/lib/controller/firebase/firbase_messge.dart b/lib/controller/firebase/firbase_messge.dart index dfdd07a..7d63b19 100755 --- a/lib/controller/firebase/firbase_messge.dart +++ b/lib/controller/firebase/firbase_messge.dart @@ -26,6 +26,7 @@ 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; @@ -154,12 +155,20 @@ class FirebaseMessagesController extends GetxController { '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'); + // 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()); @@ -387,360 +396,360 @@ class FirebaseMessagesController extends GetxController { // })); // } - 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'); - } - } + // 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 []); + // 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(); + // // استبعد توكنك واحذف الفارغ + // 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(); + // 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} - }, - }, - }, - }), - ); + // 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)); // تخفيف ضغط - } - } - } + // 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 _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); + // 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}'); + // // 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, - }, - }, - }, - }, - }), - ); + // // 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}'); + // 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); - } - } - } + // 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); + // 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}'); + // // 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, - }, - }, - }, - }, - }), - ); + // // 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}'); + // 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); - } - } - } + // 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; - } + // 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}'); + // // 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}'); + // // 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, - }, - }, - }, - }, - }), - ); + // // 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); - } - } - } + // 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 - } + // 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 { diff --git a/lib/controller/firebase/notification_service.dart b/lib/controller/firebase/notification_service.dart index ecb3000..11b7e6b 100644 --- a/lib/controller/firebase/notification_service.dart +++ b/lib/controller/firebase/notification_service.dart @@ -6,66 +6,50 @@ class NotificationService { static const String _serverUrl = 'https://syria.intaleq.xyz/intaleq/fcm/send_fcm.php'; - /// Sends a notification via your backend server. - /// - /// [target]: The device token or the topic name. - /// [title]: The notification title. - /// [body]: The notification body. - /// [isTopic]: Set to true if the target is a topic, false if it's a device token. static Future sendNotification({ required String target, required String title, required String body, + String? tone, + List? driverList, // <-- [تعديل 1] : إضافة المتغير الجديد bool isTopic = false, }) async { try { + final Map payload = { + 'target': target, + 'title': title, + 'body': body, + 'isTopic': isTopic, + }; + + // نضيف النغمة فقط إذا لم تكن فارغة + if (tone != null) { + payload['tone'] = tone; + } + + // <-- [تعديل 2] : نضيف قائمة البيانات بعد تشفيرها إلى JSON + if (driverList != null) { + payload['driverList'] = jsonEncode(driverList); + } + final response = await http.post( Uri.parse(_serverUrl), headers: { 'Content-Type': 'application/json; charset=UTF-8', }, - body: jsonEncode({ - 'target': target, - 'title': title, - 'body': body, - 'isTopic': isTopic, - }), + body: jsonEncode(payload), ); if (response.statusCode == 200) { - print('Notification sent successfully.'); + print('✅ Notification sent successfully.'); print('Server Response: ${response.body}'); } else { print( - 'Failed to send notification. Status code: ${response.statusCode}'); + '❌ Failed to send notification. Status code: ${response.statusCode}'); print('Server Error: ${response.body}'); } } catch (e) { - print('An error occurred while sending notification: $e'); + print('❌ An error occurred while sending notification: $e'); } } } - -// --- Example of how to use it --- - -// To send to a specific driver (using their token) -void sendToSpecificDriver() { - String driverToken = - 'bk3RNwTe3H0:CI2k_HHwgIpoDKCI5oT...'; // The driver's FCM token - NotificationService.sendNotification( - target: driverToken, - title: 'New Trip Request!', - body: 'A passenger is waiting for you.', - isTopic: false, // Important: this is a token - ); -} - -// To send to all drivers (using a topic) -void sendToAllDrivers() { - NotificationService.sendNotification( - target: 'drivers', // The name of the topic - title: 'Important Announcement', - body: 'Please update your app to the latest version.', - isTopic: true, // Important: this is a topic - ); -} diff --git a/lib/controller/functions/gemeni.dart b/lib/controller/functions/gemeni.dart index c155fec..02a88c7 100755 --- a/lib/controller/functions/gemeni.dart +++ b/lib/controller/functions/gemeni.dart @@ -29,6 +29,7 @@ import '../../constant/api_key.dart'; import '../../constant/char_map.dart'; import '../../constant/colors.dart'; import '../../print.dart'; +import '../firebase/notification_service.dart'; import 'encrypt_decrypt.dart'; import 'tts.dart'; import 'upload_image.dart'; @@ -105,12 +106,20 @@ class AI extends GetxController { NotificationController().showNotification( "Code approved".tr, "Code approved".tr, 'tone2', ''); // Notification text with dynamic token - Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP( - 'You have received a gift token!'.tr, - 'for '.tr + box.read(BoxName.phoneDriver).toString(), - jsonDecode(res)['message'][0]['token'].toString(), - [], - 'tone2', // Type of notification + // Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP( + // 'You have received a gift token!'.tr, + // 'for '.tr + box.read(BoxName.phoneDriver).toString(), + // jsonDecode(res)['message'][0]['token'].toString(), + // [], + // 'tone2', // Type of notification + // ); + NotificationService.sendNotification( + target: jsonDecode(res)['message'][0]['token'].toString(), + title: 'You have received a gift token!'.tr, + body: 'for '.tr + box.read(BoxName.phoneDriver).toString(), + isTopic: false, // Important: this is a token + tone: 'tone2', + driverList: [], ); } else { // mySnackeBarError( diff --git a/lib/controller/home/captin/behavior_controller.dart b/lib/controller/home/captin/behavior_controller.dart index 64d5f17..e5cf6a7 100644 --- a/lib/controller/home/captin/behavior_controller.dart +++ b/lib/controller/home/captin/behavior_controller.dart @@ -91,14 +91,16 @@ class DriverBehaviorController extends GetxController { final summary = await analyzeData(); if (summary.isEmpty) return; - final body = { + final Map body = { 'driver_id': driverId, 'trip_id': tripId, - ...summary, + ...summary, // فيه doubles }; - CRUD().post(link: AppLink.saveBehavior, payload: (body)); + // اجبر كل القيم على String + final payload = body.map((k, v) => MapEntry(k, v?.toString() ?? '')); + await CRUD().post(link: AppLink.saveBehavior, payload: payload); await clearData(); } diff --git a/lib/controller/home/captin/map_driver_controller.dart b/lib/controller/home/captin/map_driver_controller.dart index e3147a5..92dd0f0 100755 --- a/lib/controller/home/captin/map_driver_controller.dart +++ b/lib/controller/home/captin/map_driver_controller.dart @@ -24,6 +24,7 @@ import '../../../print.dart'; import '../../../views/Rate/rate_passenger.dart'; import '../../../views/home/Captin/home_captain/home_captin.dart'; import '../../firebase/firbase_messge.dart'; +import '../../firebase/notification_service.dart'; import '../../functions/crud.dart'; import '../../functions/encrypt_decrypt.dart'; import '../../functions/location_controller.dart'; @@ -195,13 +196,23 @@ class MapDriverController extends GetxController { cancelTripFromDriverAfterApplied() async { if (formKeyCancel.currentState!.validate()) { box.write(BoxName.statusDriverLocation, 'off'); - Get.find().sendNotificationToDriverMAP( - "Cancel Trip from driver", - "Trip Cancelled from driver. We are looking for a new driver. Please wait." - .tr, - tokenPassenger, - [], - 'cancel.wav', + // Get.find().sendNotificationToDriverMAP( + // "Cancel Trip from driver", + // "Trip Cancelled from driver. We are looking for a new driver. Please wait." + // .tr, + // tokenPassenger, + // [], + // 'cancel.wav', + // ); + NotificationService.sendNotification( + target: tokenPassenger.toString(), + title: "Cancel Trip from driver".tr, + body: + "Trip Cancelled from driver. We are looking for a new driver. Please wait." + .tr, + isTopic: false, // Important: this is a token + tone: 'cancel', + driverList: [], ); await CRUD().post( link: "${AppLink.seferCairoServer}/ride/rides/update.php", @@ -334,12 +345,20 @@ class MapDriverController extends GetxController { // Get.find().changeToAppliedRide('Applied'); - Get.find().sendNotificationToDriverMAP( - 'Driver Is Going To Passenger', - box.read(BoxName.nameDriver).toString(), //todo name driver - tokenPassenger, - [], - 'start.wav'); + // Get.find().sendNotificationToDriverMAP( + // 'Driver Is Going To Passenger', + // box.read(BoxName.nameDriver).toString(), //todo name driver + // tokenPassenger, + // [], + // 'start.wav'); + NotificationService.sendNotification( + target: tokenPassenger.toString(), + title: 'Driver Is Going To Passenger'.tr, + body: box.read(BoxName.nameDriver).toString(), + isTopic: false, // Important: this is a token + tone: 'start', + driverList: [], + ); } bool isSocialPressed = false; @@ -427,15 +446,15 @@ class MapDriverController extends GetxController { 'order_id': (rideId).toString(), 'status': 'Begin' }); - final fcm = Get.isRegistered() - ? Get.find() - : Get.put(FirebaseMessagesController()); - fcm.sendNotificationToDriverMAP( - 'Trip is Begin', - box.read(BoxName.nameDriver).toString(), - tokenPassenger, - [], - 'start.wav'); + + NotificationService.sendNotification( + target: tokenPassenger.toString(), + title: 'Trip is Begin', + body: box.read(BoxName.nameDriver).toString(), + isTopic: false, // Important: this is a token + tone: 'start', + driverList: [], + ); rideIsBeginPassengerTimer(); update(); @@ -752,17 +771,30 @@ class MapDriverController extends GetxController { Get.put(DriverBehaviorController()) .sendSummaryToServer(driverId, rideId); - Get.find().sendNotificationToDriverMAP( - "Driver Finish Trip", - '${'you will pay to Driver'.tr} $paymentAmount \$', - tokenPassenger, - [ - box.read(BoxName.driverID), - rideId, - box.read(BoxName.tokenDriver), - paymentAmount.toString() - ], - 'ding.wav'); + // Get.find().sendNotificationToDriverMAP( + // "Driver Finish Trip", + // '${'you will pay to Driver'.tr} $paymentAmount \$', + // tokenPassenger, + // [ + // box.read(BoxName.driverID), + // rideId, + // box.read(BoxName.tokenDriver), + // paymentAmount.toString() + // ], + // 'ding.wav'); + NotificationService.sendNotification( + target: tokenPassenger.toString(), + title: "Driver Finish Trip", + body: '${'you will pay to Driver'.tr} $paymentAmount \$'.tr, + isTopic: false, // Important: this is a token + tone: 'ding', + driverList: [ + box.read(BoxName.driverID), + rideId, + box.read(BoxName.tokenDriver), + paymentAmount.toString() + ], + ); Get.to(() => RatePassenger(), arguments: { 'passengerId': passengerId, @@ -1617,17 +1649,30 @@ class MapDriverController extends GetxController { if (distance < 300) { // 300 متر قبل الوجهة - Get.find().sendNotificationToDriverMAP( - "You are near the destination", - "You are near the destination".tr, - tokenPassenger, - [ + // Get.find().sendNotificationToDriverMAP( + // "You are near the destination", + // "You are near the destination".tr, + // tokenPassenger, + // [ + // box.read(BoxName.driverID), + // rideId, + // box.read(BoxName.tokenDriver), + // paymentAmount.toString() + // ], + // 'ding.wav', + // ); + NotificationService.sendNotification( + target: tokenPassenger.toString(), + title: "You are near the destination", + body: "You are near the destination".tr, + isTopic: false, // Important: this is a token + tone: 'ding', + driverList: [ box.read(BoxName.driverID), rideId, box.read(BoxName.tokenDriver), paymentAmount.toString() ], - 'ding.wav', ); // يمكن إضافة أي إجراء آخر هنا عند الاقتراب من الوجهة } diff --git a/lib/controller/home/payment/captain_wallet_controller.dart b/lib/controller/home/payment/captain_wallet_controller.dart index 1262d6b..e465bae 100755 --- a/lib/controller/home/payment/captain_wallet_controller.dart +++ b/lib/controller/home/payment/captain_wallet_controller.dart @@ -14,6 +14,7 @@ import 'package:sefer_driver/controller/functions/crud.dart'; import 'package:sefer_driver/main.dart'; import '../../../views/widgets/mydialoug.dart'; +import '../../firebase/notification_service.dart'; class CaptainWalletController extends GetxController { bool isLoading = false; @@ -291,13 +292,23 @@ class CaptainWalletController extends GetxController { 'paymentMethod': paymentMethod2.toString(), }); if (res1 != 'failure') { - Get.find().sendNotificationToDriverMAP( - 'Transfer', - '${'You have transfer to your wallet from'.tr}' - '${box.read(BoxName.nameDriver)}', - amountToNewDriverMap[0]['token'].toString(), - [], - 'order1.wav'); + // Get.find().sendNotificationToDriverMAP( + // 'Transfer', + // '${'You have transfer to your wallet from'.tr}' + // '${box.read(BoxName.nameDriver)}', + // amountToNewDriverMap[0]['token'].toString(), + // [], + // 'order1.wav'); + NotificationService.sendNotification( + target: amountToNewDriverMap[0]['token'].toString(), + title: 'Transfer'.tr, + body: '${'You have transfer to your wallet from'.tr}' + '${box.read(BoxName.nameDriver)}', + + isTopic: false, // Important: this is a token + tone: 'ding', + driverList: [], + ); await addSeferWallet('payout fee', '5'); Get.defaultDialog( diff --git a/lib/controller/local/translations.dart b/lib/controller/local/translations.dart index 9538097..6197e81 100755 --- a/lib/controller/local/translations.dart +++ b/lib/controller/local/translations.dart @@ -140,6 +140,9 @@ class MyTranslation extends Translations { "What is the feature of our wallet?": "ما هي مميزات محفظتنا؟", "What is Types of Trips in Intaleq?": "ما هي أنواع الرحلات في Intaleq؟", + "No rides available for your vehicle type.": "لا توجد رحلات متاحة .", + "Failed to fetch rides. Please try again.": + "فشل في جلب الرحلات. يرجى المحاولة مرة أخرى.", '''Types of Trips in Intaleq: Comfort: For cars newer than 2017 with air conditioning. diff --git a/lib/controller/notification/passenger_notification_controller.dart b/lib/controller/notification/passenger_notification_controller.dart index 5a2ae3a..48f86d0 100755 --- a/lib/controller/notification/passenger_notification_controller.dart +++ b/lib/controller/notification/passenger_notification_controller.dart @@ -8,6 +8,7 @@ import '../../constant/links.dart'; import '../../constant/style.dart'; import '../../main.dart'; import '../../views/widgets/elevated_btn.dart'; +import '../firebase/notification_service.dart'; import '../functions/crud.dart'; class PassengerNotificationController extends GetxController { @@ -53,8 +54,16 @@ class PassengerNotificationController extends GetxController { 'title': title, 'body': body, }); - FirebaseMessagesController() - .sendNotificationToPassengerToken(title, body, 'token', [], 'ding.wav'); + // FirebaseMessagesController() + // .sendNotificationToPassengerToken(title, body, 'token', [], 'ding.wav'); + NotificationService.sendNotification( + target: 'token'.toString(), + title: title, + body: body, + isTopic: false, // Important: this is a token + tone: 'ding', + driverList: [], + ); } @override diff --git a/lib/controller/rate/rate_app_controller.dart b/lib/controller/rate/rate_app_controller.dart index e2658b3..05b3da2 100755 --- a/lib/controller/rate/rate_app_controller.dart +++ b/lib/controller/rate/rate_app_controller.dart @@ -1,10 +1,8 @@ import 'dart:convert'; import 'package:sefer_driver/constant/box_name.dart'; -import 'package:sefer_driver/constant/colors.dart'; import 'package:sefer_driver/constant/links.dart'; import 'package:sefer_driver/controller/functions/crud.dart'; -import 'package:sefer_driver/controller/functions/encrypt_decrypt.dart'; import 'package:sefer_driver/main.dart'; import 'package:sefer_driver/views/widgets/error_snakbar.dart'; import 'package:sefer_driver/views/widgets/mydialoug.dart'; @@ -24,9 +22,10 @@ class RatingController extends GetxController { void _redirectToAppStore() async { // URLs for App Store and Google Play Store - const appStoreUrl = 'https://apps.apple.com/app/6502189302'; + const appStoreUrl = + 'https://apps.apple.com/st/app/intaleq-driver/id6482995159'; const playStoreUrl = - 'https://play.google.com/store/apps/details?id=com.sefer_driver'; + 'https://play.google.com/store/apps/details?id=com.intaleq_driver'; final url = GetPlatform.isIOS ? appStoreUrl : playStoreUrl; if (await launchUrl(Uri.parse(url))) { @@ -59,13 +58,14 @@ class RatingController extends GetxController { if (res != 'failure') { try { // Attempt to parse the response as JSON - final parsedResponse = jsonDecode(res); + final parsedResponse = (res); if (parsedResponse['status'] == 'success') { // Display a success message CRUD().post(link: AppLink.sendEmailRateingApp, payload: { "name": payload["name"], "email": payload["email"], + "phone": payload["phone"], "rating": rating.toString(), "comment": payload["comment"], }); diff --git a/lib/controller/rate/rate_conroller.dart b/lib/controller/rate/rate_conroller.dart index c29d8f2..b5dcc72 100755 --- a/lib/controller/rate/rate_conroller.dart +++ b/lib/controller/rate/rate_conroller.dart @@ -11,6 +11,8 @@ import 'package:sefer_driver/main.dart'; import 'package:sefer_driver/views/home/Captin/home_captain/home_captin.dart'; import 'package:sefer_driver/views/widgets/elevated_btn.dart'; +import '../firebase/notification_service.dart'; + // import '../home/captin/home_captain_controller.dart'; class RateController extends GetxController { @@ -67,12 +69,20 @@ class RateController extends GetxController { 'driverID': box.read(BoxName.driverID).toString(), }); - Get.find().sendNotificationToDriverMAP( - 'Wallet Added'.tr, - 'Wallet Added${(remainingFee).toStringAsFixed(0)}'.tr, - Get.find().tokenPassenger, - [], - 'tone2.wav'); + // Get.find().sendNotificationToDriverMAP( + // 'Wallet Added'.tr, + // 'Wallet Added${(remainingFee).toStringAsFixed(0)}'.tr, + // Get.find().tokenPassenger, + // [], + // 'tone2.wav'); + NotificationService.sendNotification( + target: Get.find().tokenPassenger.toString(), + title: 'Wallet Added'.tr, + body: 'Wallet Added${(remainingFee).toStringAsFixed(0)}'.tr, + isTopic: false, // Important: this is a token + tone: 'tone2', + driverList: [], + ); walletChecked = 'true'; // } diff --git a/lib/views/home/Captin/home_captain/widget/left_menu_map_captain.dart b/lib/views/home/Captin/home_captain/widget/left_menu_map_captain.dart index 9f43432..de826a0 100755 --- a/lib/views/home/Captin/home_captain/widget/left_menu_map_captain.dart +++ b/lib/views/home/Captin/home_captain/widget/left_menu_map_captain.dart @@ -14,6 +14,7 @@ import 'package:sefer_driver/views/widgets/mydialoug.dart'; import '../../../../../constant/colors.dart'; import '../../../../../constant/links.dart'; import '../../../../../controller/firebase/firbase_messge.dart'; +import '../../../../../controller/firebase/notification_service.dart'; import '../../../../../controller/functions/crud.dart'; import '../../../../../controller/home/captin/order_request_controller.dart'; import '../../../../../controller/home/navigation/navigation_view.dart'; @@ -318,8 +319,16 @@ void _sendAcceptanceNotification(String? customerToken, rideId) { // Safely check for customer token final String? token = customerToken; if (token != null && token.isNotEmpty) { - _firebaseMessagesController.sendNotificationToDriverMAP('Accepted Ride', - 'your ride is applied'.tr, token, bodyToPassenger, 'start.wav'); + // _firebaseMessagesController.sendNotificationToDriverMAP('Accepted Ride', + // 'your ride is applied'.tr, token, bodyToPassenger, 'start.wav'); + NotificationService.sendNotification( + target: token.toString(), + title: 'Accepted Ride', + body: 'your ride is Accepted'.tr, + isTopic: false, // Important: this is a token + tone: 'start', + driverList: [], + ); } else {} } catch (e) {} } diff --git a/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart b/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart index 7fe1faf..512e6b9 100755 --- a/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart +++ b/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart @@ -9,7 +9,9 @@ import 'package:sefer_driver/views/widgets/elevated_btn.dart'; import '../../../../constant/box_name.dart'; import '../../../../constant/style.dart'; +import '../../../../controller/firebase/notification_service.dart'; import '../../../../main.dart'; +import '../../../../print.dart'; // Changed: إعادة تصميم كاملة لتصبح شريط معلومات علوي مدمج class PassengerInfoWindow extends StatelessWidget { @@ -154,12 +156,23 @@ class PassengerInfoWindow extends StatelessWidget { if (await controller .calculateDistanceBetweenDriverAndPassengerLocation() < 140) { - fcm.sendNotificationToDriverMAP( - 'Hi ,I Arrive your site', - 'I Arrive at your site'.tr, - controller.tokenPassenger, - [], - 'ding.wav', + // fcm.sendNotificationToDriverMAP( + // 'Hi ,I Arrive your site', + // 'I Arrive at your site'.tr, + // controller.tokenPassenger, + // [], + // 'ding.wav', + // ); + Log.print( + 'controller.tokenPassenger: ${controller.tokenPassenger}'); + + NotificationService.sendNotification( + target: controller.tokenPassenger.toString(), + title: 'Hi ,I Arrive your site'.tr, + body: 'I Arrive at your site'.tr, + isTopic: false, // Important: this is a token + tone: 'ding', + driverList: [], ); controller.startTimerToShowDriverWaitPassengerDuration(); controller.isArrivedSend = false; @@ -239,13 +252,22 @@ class PassengerInfoWindow extends StatelessWidget { kolor: AppColor.deepPurpleAccent, onPressed: () { MyDialog().getDialog('Are you sure to cancel?'.tr, '', () async { - fcm.sendNotificationToDriverMAP( - 'Driver Cancelled Your Trip', - 'You will need to pay the cost to the driver, or it will be deducted from your next trip' - .tr, - controller.tokenPassenger, - [], - 'cancel.wav'); + // fcm.sendNotificationToDriverMAP( + // 'Driver Cancelled Your Trip', + // 'You will need to pay the cost to the driver, or it will be deducted from your next trip' + // .tr, + // controller.tokenPassenger, + // [], + // 'cancel.wav'); + NotificationService.sendNotification( + target: controller.tokenPassenger.toString(), + title: 'Driver Cancelled Your Trip', + body: + 'You will need to pay the cost to the driver, or it will be deducted from your next trip', + isTopic: false, // Important: this is a token + tone: 'cancel', + driverList: [], + ); box.write(BoxName.rideStatus, 'Cancel'); await controller.addWaitingTimeCostFromPassengerToDriverWallet(); controller.isdriverWaitTimeEnd = false; diff --git a/lib/views/home/Captin/mapDriverWidgets/sos_connect.dart b/lib/views/home/Captin/mapDriverWidgets/sos_connect.dart index aa3188d..6cfe0b2 100755 --- a/lib/views/home/Captin/mapDriverWidgets/sos_connect.dart +++ b/lib/views/home/Captin/mapDriverWidgets/sos_connect.dart @@ -201,6 +201,7 @@ import '../../../../constant/box_name.dart'; import '../../../../constant/colors.dart'; import '../../../../constant/style.dart'; import '../../../../controller/firebase/firbase_messge.dart'; +import '../../../../controller/firebase/notification_service.dart'; import '../../../../controller/functions/launch.dart'; import '../../../../controller/home/captin/map_driver_controller.dart'; import '../../../../main.dart'; @@ -339,23 +340,39 @@ class SosConnect extends StatelessWidget { _buildMessageTile( text: "Where are you, sir?".tr, onTap: () { - fcm.sendNotificationToDriverMAP( - 'message From Driver', - "Where are you, sir?".tr, - controller.tokenPassenger, - [], - 'ding.wav'); + // fcm.sendNotificationToDriverMAP( + // 'message From Driver', + // "Where are you, sir?".tr, + // controller.tokenPassenger, + // [], + // 'ding'); + NotificationService.sendNotification( + target: controller.tokenPassenger.toString(), + title: 'message From Driver'.tr, + body: "Where are you, sir?".tr, + isTopic: false, // Important: this is a token + tone: 'ding', + driverList: [], + ); Get.back(); }), _buildMessageTile( text: "I've been trying to reach you but your phone is off.".tr, onTap: () { - fcm.sendNotificationToDriverMAP( - 'message From Driver', - "I've been trying to reach you but your phone is off.".tr, - controller.tokenPassenger, - [], - 'ding.wav'); + // fcm.sendNotificationToDriverMAP( + // 'message From Driver', + // "I've been trying to reach you but your phone is off.".tr, + // controller.tokenPassenger, + // [], + // 'ding'); + NotificationService.sendNotification( + target: controller.tokenPassenger.toString(), + title: 'message From Driver'.tr, + body: "I've been trying to reach you but your phone is off.".tr, + isTopic: false, // Important: this is a token + tone: 'ding', + driverList: [], + ); Get.back(); }), const SizedBox(height: 16), @@ -374,12 +391,20 @@ class SosConnect extends StatelessWidget { ), IconButton( onPressed: () { - fcm.sendNotificationToDriverMAP( - 'message From Driver', - controller.messageToPassenger.text, - controller.tokenPassenger, - [], - 'ding.wav'); + // fcm.sendNotificationToDriverMAP( + // 'message From Driver', + // controller.messageToPassenger.text, + // controller.tokenPassenger, + // [], + // 'ding'); + NotificationService.sendNotification( + target: controller.tokenPassenger.toString(), + title: 'message From Driver'.tr, + body: 'change device'.tr, + isTopic: false, // Important: this is a token + tone: 'cancel', + driverList: [], + ); controller.messageToPassenger.clear(); Get.back(); }, diff --git a/lib/views/home/Captin/orderCaptin/order_over_lay.dart b/lib/views/home/Captin/orderCaptin/order_over_lay.dart index b783e71..fe609bc 100755 --- a/lib/views/home/Captin/orderCaptin/order_over_lay.dart +++ b/lib/views/home/Captin/orderCaptin/order_over_lay.dart @@ -8,6 +8,7 @@ import '../../../../constant/box_name.dart'; import '../../../../constant/links.dart'; import '../../../../controller/firebase/firbase_messge.dart'; import '../../../../controller/firebase/local_notification.dart'; +import '../../../../controller/firebase/notification_service.dart'; import '../../../../controller/functions/crud.dart'; import '../../../../main.dart'; import '../../../../models/model/order_data.dart'; @@ -228,12 +229,20 @@ class _OrderOverlayState extends State ? Get.find() : Get.put(FirebaseMessagesController()); - fmc.sendNotificationToDriverMAP( - "Accepted Ride", - 'your ride is Accepted'.tr, - _getData(9).toString(), - bodyToPassenger, - 'start.wav', + // fmc.sendNotificationToDriverMAP( + // "Accepted Ride", + // 'your ride is Accepted'.tr, + // _getData(9).toString(), + // bodyToPassenger, + // 'start.wav', + // ); + NotificationService.sendNotification( + target: _getData(9).toString(), + title: "Accepted Ride", + body: 'your ride is Accepted'.tr, + isTopic: false, // Important: this is a token + tone: 'start', + driverList: [], ); final payload = { // بيانات أساسية diff --git a/lib/views/home/Captin/orderCaptin/order_request_page.dart b/lib/views/home/Captin/orderCaptin/order_request_page.dart index 5a944d3..b803f9d 100755 --- a/lib/views/home/Captin/orderCaptin/order_request_page.dart +++ b/lib/views/home/Captin/orderCaptin/order_request_page.dart @@ -13,10 +13,12 @@ import 'dart:math' as math; import '../../../../constant/colors.dart'; import '../../../../constant/links.dart'; import '../../../../constant/style.dart'; +import '../../../../controller/firebase/notification_service.dart'; import '../../../../controller/functions/crud.dart'; import '../../../../controller/functions/encrypt_decrypt.dart'; import '../../../../controller/functions/launch.dart'; import '../../../../controller/home/captin/order_request_controller.dart'; +import '../../../../print.dart'; import '../../../widgets/elevated_btn.dart'; class OrderRequestPage extends StatefulWidget { @@ -279,12 +281,20 @@ class _OrderRequestPageState extends State { ? Get.find() : Get.put(FirebaseMessagesController()); - fmc.sendNotificationToDriverMAP( - "Accepted Ride", - 'your ride is Accepted'.tr, - controller.myList[9].toString(), - bodyToPassenger, - 'start.wav', + // fmc.sendNotificationToDriverMAP( + // "Accepted Ride", + // 'your ride is Accepted'.tr, + // controller.myList[9].toString(), + // bodyToPassenger, + // 'start', + // ); + NotificationService.sendNotification( + target: controller.myList[9].toString(), + title: "Accepted Ride", + body: 'your ride is Accepted'.tr, + isTopic: false, // Important: this is a token + tone: 'start', + driverList: [], ); Get.back(); box.write(BoxName.rideArguments, { @@ -338,6 +348,8 @@ class _OrderRequestPageState extends State { }); Get.to(() => PassengerLocationMapPage(), arguments: box.read(BoxName.rideArguments)); + Log.print( + 'box.read(BoxName.rideArguments): ${box.read(BoxName.rideArguments)}'); } }, ), @@ -372,13 +384,22 @@ class _OrderRequestPageState extends State { box.read(BoxName.tokenDriver).toString(), ]; - FirebaseMessagesController() - .sendNotificationToPassengerToken( - 'Order Under Review'.tr, - '${box.read(BoxName.nameDriver)} ${'is reviewing your order. They may need more information or a higher price.'.tr}', - controller.myList[9].toString(), - bodyToPassenger, - 'notification.wav'); + // FirebaseMessagesController() + // .sendNotificationToPassengerToken( + // 'Order Under Review'.tr, + // '${box.read(BoxName.nameDriver)} ${'is reviewing your order. They may need more information or a higher price.'.tr}', + // controller.myList[9].toString(), + // bodyToPassenger, + // 'notification'); + NotificationService.sendNotification( + target: controller.myList[9].toString(), + title: 'Order Under Review'.tr, + body: + '${box.read(BoxName.nameDriver)} ${'is reviewing your order. They may need more information or a higher price.'.tr}', + isTopic: false, // Important: this is a token + tone: 'start', + driverList: [], + ); controller.refuseOrder( EncryptionHelper.instance.encryptData( diff --git a/lib/views/home/Captin/orderCaptin/order_speed_request.dart b/lib/views/home/Captin/orderCaptin/order_speed_request.dart index aa5771f..47f6f08 100755 --- a/lib/views/home/Captin/orderCaptin/order_speed_request.dart +++ b/lib/views/home/Captin/orderCaptin/order_speed_request.dart @@ -11,6 +11,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import '../../../../constant/colors.dart'; // Your AppColor import '../../../../constant/links.dart'; // Your AppLink import '../../../../constant/style.dart'; // Your AppStyle +import '../../../../controller/firebase/notification_service.dart'; import '../../../../controller/functions/crud.dart'; import '../../../../controller/functions/launch.dart'; import '../../../../controller/home/captin/order_request_controller.dart'; @@ -385,16 +386,28 @@ class OrderSpeedRequest extends StatelessWidget { box.read(BoxName.tokenDriver).toString(), rideId.toString(), ]; - Get.put(FirebaseMessagesController()) - .sendNotificationToDriverMAP( - 'Accepted Ride', - 'your ride is applied'.tr, - controller.arguments?['DriverList'] - ?[9] - ?.toString() ?? - _getData(9), // Safer access - bodyToPassenger, - 'start.wav'); + // Get.put(FirebaseMessagesController()) + // .sendNotificationToDriverMAP( + // 'Accepted Ride', + // 'your ride is applied'.tr, + // controller.arguments?['DriverList'] + // ?[9] + // ?.toString() ?? + // _getData(9), // Safer access + // bodyToPassenger, + // 'start.wav'); + NotificationService.sendNotification( + target: controller.arguments?['DriverList'] + ?[9] + ?.toString() ?? + _getData(9), + title: 'Accepted Ride', + body: 'your ride is applied'.tr, + isTopic: + false, // Important: this is a token + tone: 'start', + driverList: [], + ); // Using rideId (_getData(16)) for order_id consistently CRUD().postFromDialogue( diff --git a/lib/views/notification/available_rides_page.dart b/lib/views/notification/available_rides_page.dart index c3eb7da..24e7aa6 100755 --- a/lib/views/notification/available_rides_page.dart +++ b/lib/views/notification/available_rides_page.dart @@ -8,6 +8,7 @@ import '../../constant/colors.dart'; import '../../constant/links.dart'; import '../../constant/style.dart'; import '../../controller/firebase/firbase_messge.dart'; +import '../../controller/firebase/notification_service.dart'; import '../../controller/functions/crud.dart'; import '../../controller/home/captin/home_captain_controller.dart'; import '../../controller/notification/ride_available_controller.dart'; @@ -338,12 +339,20 @@ class RideAvailableCard extends StatelessWidget { payload: {'id': rideInfo['id'], 'status': 'Applied'}); } - FirebaseMessagesController().sendNotificationToPassengerToken( - "Accepted Ride".tr, - 'your ride is Accepted'.tr, - rideInfo['passengerToken'].toString(), - bodyToPassenger, - 'start.wav'); + // FirebaseMessagesController().sendNotificationToPassengerToken( + // "Accepted Ride".tr, + // 'your ride is Accepted'.tr, + // rideInfo['passengerToken'].toString(), + // bodyToPassenger, + // 'start.wav'); + NotificationService.sendNotification( + target: rideInfo['passengerToken'].toString(), + title: 'Accepted Ride', + body: 'your ride is Accepted'.tr, + isTopic: false, // Important: this is a token + tone: 'start', + driverList: [], + ); Get.back(); Get.to(() => PassengerLocationMapPage(), arguments: { 'passengerLocation': rideInfo['start_location'].toString(),