779 lines
27 KiB
Dart
Executable File
779 lines
27 KiB
Dart
Executable File
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'package:sefer_driver/constant/api_key.dart';
|
|
import 'package:sefer_driver/controller/home/captin/home_captain_controller.dart';
|
|
import 'package:sefer_driver/views/widgets/error_snakbar.dart';
|
|
import 'package:sefer_driver/views/widgets/mydialoug.dart';
|
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:sefer_driver/views/widgets/elevated_btn.dart';
|
|
|
|
import '../../constant/box_name.dart';
|
|
import '../../constant/colors.dart';
|
|
import '../../constant/style.dart';
|
|
import '../../env/env.dart';
|
|
import '../../main.dart';
|
|
import '../../print.dart';
|
|
import '../../views/auth/captin/criminal_documents_page.dart';
|
|
import '../../views/home/Captin/home_captain/home_captin.dart';
|
|
import '../../views/home/Captin/orderCaptin/order_speed_request.dart';
|
|
import '../../views/home/Captin/orderCaptin/order_request_page.dart';
|
|
import '../../views/home/Captin/orderCaptin/vip_order_page.dart';
|
|
import '../auth/google_sign.dart';
|
|
import '../functions/encrypt_decrypt.dart';
|
|
import '../functions/face_detect.dart';
|
|
import 'access_token.dart';
|
|
import 'local_notification.dart';
|
|
|
|
class FirebaseMessagesController extends GetxController {
|
|
final fcmToken = FirebaseMessaging.instance;
|
|
|
|
List<String> tokens = [];
|
|
List dataTokens = [];
|
|
late String driverID;
|
|
late String driverToken;
|
|
NotificationSettings? notificationSettings;
|
|
NotificationController notificationController =
|
|
Get.put(NotificationController());
|
|
Future<void> getNotificationSettings() async {
|
|
// Get the current notification settings
|
|
NotificationSettings? notificationSettings =
|
|
await FirebaseMessaging.instance.getNotificationSettings();
|
|
'Notification authorization status: ${notificationSettings.authorizationStatus}';
|
|
|
|
// Call the update function if needed
|
|
update();
|
|
}
|
|
|
|
Future<void> requestFirebaseMessagingPermission() async {
|
|
FirebaseMessaging messaging = FirebaseMessaging.instance;
|
|
|
|
// Check if the platform is Android
|
|
if (Platform.isAndroid) {
|
|
// Request permission for Android
|
|
await messaging.requestPermission();
|
|
} else if (Platform.isIOS) {
|
|
// Request permission for iOS
|
|
NotificationSettings settings = await messaging.requestPermission(
|
|
alert: true,
|
|
announcement: true,
|
|
badge: true,
|
|
carPlay: true,
|
|
criticalAlert: true,
|
|
provisional: false,
|
|
sound: true,
|
|
);
|
|
messaging.setForegroundNotificationPresentationOptions(
|
|
alert: true, badge: true, sound: true);
|
|
}
|
|
}
|
|
|
|
Future getToken() async {
|
|
fcmToken.getToken().then((token) {
|
|
Log.print('token: ${token}');
|
|
box.write(BoxName.tokenDriver, (token!));
|
|
});
|
|
|
|
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
|
// If the app is in the background or terminated, show a system tray message
|
|
RemoteNotification? notification = message.notification;
|
|
AndroidNotification? android = notification?.android;
|
|
// if (notification != null && android != null) {
|
|
|
|
if (message.data.isNotEmpty && message.notification != null) {
|
|
fireBaseTitles(message);
|
|
}
|
|
if (message.data.isNotEmpty && message.notification != null) {
|
|
fireBaseTitles(message);
|
|
}
|
|
});
|
|
FirebaseMessaging.onBackgroundMessage((RemoteMessage message) async {});
|
|
|
|
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
|
if (message.data.isNotEmpty && message.notification != null) {
|
|
fireBaseTitles(message);
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<void> fireBaseTitles(RemoteMessage message) async {
|
|
if (message.notification!.title! == 'Order') {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
message.notification!.title.toString(),
|
|
message.notification!.body.toString(),
|
|
'tone1',
|
|
'');
|
|
}
|
|
// await FirebaseMessagesController().showOverlayNotification(message);
|
|
var myListString = message.data['DriverList'];
|
|
// var points = message.data['PolylineJson'];
|
|
|
|
var myList = jsonDecode(myListString) as List<dynamic>;
|
|
// var myPoints = jsonDecode(points) as List<dynamic>;
|
|
driverToken = myList[14].toString();
|
|
// This is for location using and uploading status
|
|
Get.put(HomeCaptainController()).changeRideId();
|
|
update();
|
|
Get.to(() => OrderRequestPage(), arguments: {
|
|
// Get.to(() => OrderRequestPage(), arguments: {
|
|
'myListString': myListString,
|
|
'DriverList': myList,
|
|
// 'PolylineJson': myPoints,
|
|
'body': message.notification!.body
|
|
});
|
|
} else if (message.notification!.title == 'OrderVIP') {
|
|
var myListString = message.data['DriverList'];
|
|
|
|
var myList = jsonDecode(myListString) as List<dynamic>;
|
|
|
|
// driverToken = myList[10].toString();
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'OrderVIP'.tr, 'OrderVIP'.tr, 'order', '');
|
|
}
|
|
Get.to(VipOrderPage(), arguments: {
|
|
'myListString': myListString,
|
|
'DriverList': myList,
|
|
// 'PolylineJson': myPoints,
|
|
'body': message.notification!.body
|
|
});
|
|
} else if (message.notification!.title == 'Cancel Trip'.tr) {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'Cancel Trip'.tr, 'Passenger Cancel Trip'.tr, 'cancel', '');
|
|
}
|
|
cancelTripDialog();
|
|
} else if (message.notification!.title == 'VIP Order') {
|
|
var myListString = message.data['DriverList'];
|
|
var driverList = jsonDecode(myListString) as List<dynamic>;
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'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');
|
|
});
|
|
|
|
// Get.to(const VipOrderPage());
|
|
} else if (message.notification!.title == 'message From passenger') {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'message From passenger'.tr, ''.tr, 'ding', '');
|
|
}
|
|
MyDialog().getDialog(
|
|
'message From passenger'.tr, message.notification!.body!, () {
|
|
Get.back();
|
|
});
|
|
} else if (message.notification!.title == 'Cancel') {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'Cancel'.tr, ''.tr, 'cancel', '');
|
|
}
|
|
MyDialog().getDialog(
|
|
'Passenger Cancel Trip'.tr,
|
|
'Trip Cancelled. The cost of the trip will be added to your wallet.'
|
|
.tr, () {
|
|
box.write(BoxName.rideStatus, 'Cancel');
|
|
Log.print('rideStatus from 184 : ${box.read(BoxName.rideStatus)}');
|
|
Get.offAll(HomeCaptain());
|
|
});
|
|
// cancelTripDialog1();
|
|
} else if (message.notification!.title! == 'token change') {
|
|
// notificationController
|
|
// .showNotification('token change'.tr, 'token change', 'cancel');
|
|
// GoogleSignInHelper.signOut();
|
|
GoogleSignInHelper.signOut();
|
|
} else if (message.notification!.title! == 'face detect') {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'face detect'.tr, ''.tr, 'tone2', '');
|
|
}
|
|
String result0 = await faceDetector();
|
|
// Handle the result here, e.g., show a dialog or update the UI
|
|
var result = jsonDecode(result0);
|
|
MyDialogContent().getDialog(
|
|
'Face Detection Result'.tr,
|
|
Text(
|
|
result['similar'].toString() == 'true'
|
|
? 'similar'.tr
|
|
: 'not similar'.tr,
|
|
style: AppStyle.title,
|
|
),
|
|
() {
|
|
Get.back();
|
|
},
|
|
);
|
|
|
|
update();
|
|
} else if (message.notification!.title! == 'Hi ,I will go now') {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'tone2', '');
|
|
}
|
|
update();
|
|
} else if (message.notification!.title! == 'Call Income'.tr) {
|
|
try {
|
|
var myListString = message.data['passengerList'];
|
|
var driverList = jsonDecode(myListString) as List<dynamic>;
|
|
// if (Platform.isAndroid) {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification('Call Income'.tr,
|
|
message.notification!.body!, 'iphone_ringtone', '');
|
|
}
|
|
// }
|
|
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
|
// Get.to(() => PassengerCallPage(
|
|
// channelName: driverList[1].toString(),
|
|
// token: driverList[0].toString(),
|
|
// remoteID: driverList[2].toString(),
|
|
// ));
|
|
} catch (e) {}
|
|
} else if (message.notification!.title! ==
|
|
'Call Income from Passenger'.tr) {
|
|
try {
|
|
var myListString = message.data['passengerList'];
|
|
var driverList = jsonDecode(myListString) as List<dynamic>;
|
|
// if (Platform.isAndroid) {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification('Call Income'.tr,
|
|
message.notification!.body!, 'iphone_ringtone', '');
|
|
}
|
|
// }
|
|
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
|
// Get.to(() => CallPage(
|
|
// // channelName: driverList[1].toString(),
|
|
// // token: driverList[0].toString(),
|
|
// // remoteID: driverList[2].toString(),
|
|
// ));
|
|
} catch (e) {}
|
|
} else if (message.notification!.title! ==
|
|
"Criminal Document Required".tr) {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification("Criminal Document Required".tr,
|
|
message.notification!.body!, 'tone2', '');
|
|
}
|
|
MyDialog().getDialog(
|
|
"Criminal Document Required".tr, 'You should have upload it .'.tr,
|
|
() {
|
|
Get.to(() => const CriminalDocumemtPage());
|
|
});
|
|
Get.to(() => const CriminalDocumemtPage());
|
|
} else if (message.notification!.title! == 'Call End'.tr) {
|
|
try {
|
|
var myListString = message.data['passengerList'];
|
|
var driverList = jsonDecode(myListString) as List<dynamic>;
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'Call End'.tr, message.notification!.body!, 'tone2', '');
|
|
}
|
|
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
|
// Get.off(const CallPage());
|
|
} catch (e) {}
|
|
} else if (message.notification!.title! == 'Order Applied'.tr) {
|
|
mySnackbarSuccess("The order has been accepted by another driver.".tr);
|
|
} else if (message.notification!.title! == 'Order') {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
message.notification!.title.toString(),
|
|
message.notification!.body.toString(),
|
|
'order',
|
|
'');
|
|
}
|
|
var myListString = message.data['DriverList'];
|
|
// var points = message.data['PolylineJson'];
|
|
|
|
var myList = jsonDecode(myListString) as List<dynamic>;
|
|
// var myPoints = jsonDecode(points) as List<dynamic>;
|
|
driverToken = myList[14].toString();
|
|
Get.put(HomeCaptainController()).changeRideId();
|
|
update();
|
|
Get.to(() => OrderSpeedRequest(), arguments: {
|
|
'myListString': myListString,
|
|
'DriverList': myList,
|
|
// 'PolylineJson': myPoints,
|
|
'body': message.notification!.body
|
|
});
|
|
} else if (message.notification!.title! == 'Order Applied'.tr) {
|
|
if (Platform.isAndroid) {
|
|
notificationController.showNotification(
|
|
'The order Accepted by another Driver'.tr,
|
|
'We regret to inform you that another driver has accepted this order.'
|
|
.tr,
|
|
'order',
|
|
'');
|
|
}
|
|
}
|
|
}
|
|
|
|
SnackbarController driverAppliedTripSnakBar() {
|
|
return Get.snackbar(
|
|
'Driver Applied the Ride for You'.tr,
|
|
'',
|
|
colorText: AppColor.greenColor,
|
|
duration: const Duration(seconds: 3),
|
|
snackPosition: SnackPosition.TOP,
|
|
titleText: Text(
|
|
'Applied'.tr,
|
|
style: const TextStyle(color: AppColor.redColor),
|
|
),
|
|
messageText: Text(
|
|
'Driver Applied the Ride for You'.tr,
|
|
style: AppStyle.title,
|
|
),
|
|
icon: const Icon(Icons.approval),
|
|
shouldIconPulse: true,
|
|
margin: const EdgeInsets.all(16),
|
|
padding: const EdgeInsets.all(16),
|
|
);
|
|
}
|
|
|
|
Future<dynamic> cancelTripDialog() {
|
|
return Get.defaultDialog(
|
|
barrierDismissible: false,
|
|
title: 'Passenger Cancel Trip'.tr,
|
|
middleText: '',
|
|
confirm: MyElevatedButton(
|
|
title: 'Ok'.tr,
|
|
onPressed: () {
|
|
box.write(BoxName.rideStatus, 'Cancel');
|
|
box.write(BoxName.statusDriverLocation, 'off');
|
|
Log.print(
|
|
'rideStatus from 347 : ${box.read(BoxName.rideStatus)}');
|
|
Get.offAll(HomeCaptain());
|
|
}));
|
|
}
|
|
|
|
Future<dynamic> cancelTripDialog1() {
|
|
return Get.defaultDialog(
|
|
barrierDismissible: false,
|
|
title: 'Passenger Cancel Trip'.tr,
|
|
middleText:
|
|
'Trip Cancelled. The cost of the trip will be added to your wallet.'
|
|
.tr,
|
|
confirm: MyElevatedButton(
|
|
title: 'Ok'.tr,
|
|
onPressed: () {
|
|
box.write(BoxName.rideStatus, 'Cancel');
|
|
Log.print(
|
|
'rideStatus from 364 : ${box.read(BoxName.rideStatus)}');
|
|
Get.offAll(HomeCaptain());
|
|
}));
|
|
}
|
|
|
|
// Future<dynamic> driverArrivePassengerDialoge() {
|
|
// return Get.defaultDialog(
|
|
// barrierDismissible: false,
|
|
// title: 'Hi ,I Arrive your site'.tr,
|
|
// middleText: 'Please go to Car Driver'.tr,
|
|
// confirm: MyElevatedButton(
|
|
// title: 'Ok I will go now.'.tr,
|
|
// onPressed: () {
|
|
// FirebaseMessagesController().sendNotificationToPassengerToken(
|
|
// 'Hi ,I will go now'.tr,
|
|
// 'I will go now'.tr,
|
|
// Get.find<MapDriverController>().driverToken, []);
|
|
// Get.find<MapPassengerController>()
|
|
// .startTimerDriverWaitPassenger5Minute();
|
|
|
|
// Get.back();
|
|
// }));
|
|
// }
|
|
|
|
Future<dynamic> passengerDialog(String message) {
|
|
return Get.defaultDialog(
|
|
barrierDismissible: false,
|
|
title: 'message From passenger'.tr,
|
|
titleStyle: AppStyle.title,
|
|
middleTextStyle: AppStyle.title,
|
|
middleText: message.tr,
|
|
confirm: MyElevatedButton(
|
|
title: 'Ok'.tr,
|
|
onPressed: () {
|
|
// FirebaseMessagesController().sendNotificationToPassengerToken(
|
|
// 'Hi ,I will go now'.tr,
|
|
// 'I will go now'.tr,
|
|
// Get.find<MapPassengerController>().driverToken, []);
|
|
// Get.find<MapPassengerController>()
|
|
// .startTimerDriverWaitPassenger5Minute();
|
|
|
|
Get.back();
|
|
}));
|
|
}
|
|
|
|
late String serviceAccountKeyJson;
|
|
@override
|
|
Future<void> onInit() async {
|
|
super.onInit();
|
|
try {
|
|
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 {
|
|
// Get the token you want to subtract.
|
|
String token = box.read(BoxName.tokenFCM);
|
|
tokens = box.read(BoxName.tokens);
|
|
// Subtract the token from the list of tokens.
|
|
tokens.remove(token);
|
|
|
|
// Save the list of tokens back to the box.
|
|
// box.write(BoxName.tokens, tokens);
|
|
tokens = box.read(BoxName.tokens);
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
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}');
|
|
|
|
// 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': {
|
|
// '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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
.whenComplete(() {})
|
|
.catchError((e) {});
|
|
}
|
|
}
|
|
|
|
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}');
|
|
|
|
// 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}');
|
|
|
|
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);
|
|
|
|
// 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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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}');
|
|
|
|
// 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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
class OverlayContent extends StatelessWidget {
|
|
final String title;
|
|
final String body;
|
|
|
|
OverlayContent(this.title, this.body);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Material(
|
|
child: Container(
|
|
padding: const EdgeInsets.all(16.0),
|
|
color: Colors.white,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
title,
|
|
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
|
),
|
|
const SizedBox(height: 8.0),
|
|
Text(
|
|
body,
|
|
style: const TextStyle(fontSize: 16),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|