25-10-5/1

This commit is contained in:
Hamza-Ayed
2025-10-08 13:14:07 +03:00
parent 1cc66029a3
commit 482c1296bc
22 changed files with 770 additions and 559 deletions

View File

@@ -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<void> 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<void> 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<String> all =
List<String>.from(box.read(BoxName.tokens) ?? const []);
// void sendNotificationAll(String title, body, tone) async {
// // توكني الحالي (لا أرسل لنفسي)
// final String myToken = box.read(BoxName.tokenFCM) ?? '';
// // اقرأ قائمة كل التوكنات
// final List<String> all =
// List<String>.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<String> 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<String> 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: <String, String>{
'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: <String, String>{
// '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<String> 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<String> 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: <String, String>{
'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: <String, String>{
// '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<void> sendNotificationToDriverMAP(
String title, String body, String token, List<String> data, String tone,
{int retryCount = 2}) async {
try {
if (serviceAccountKeyJson.isEmpty) {
print("🔴 Error: Service Account Key is empty");
return;
}
// Future<void> sendNotificationToDriverMAP(
// String title, String body, String token, List<String> 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: <String, String>{
'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: <String, String>{
// '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<void> 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<void> 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 {