diff --git a/android/app/build.gradle b/android/app/build.gradle index 4b8ceb6..44cc32f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -54,8 +54,8 @@ android { // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdk = 23 targetSdk = flutter.targetSdkVersion - versionCode = 113 - versionName = '1.5.13' + versionCode = 117 + versionName = '1.5.17' multiDexEnabled =true } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f879353..9fa8907 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -28,6 +28,8 @@ + + + + + + + + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 8d7a39e..7c88e58 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -35,7 +35,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 72 + 77 CFBundleSignature ???? CFBundleURLTypes @@ -50,7 +50,7 @@ CFBundleVersion - 4.0.72 + 4.0.77 FirebaseAppDelegateProxyEnabled NO GMSApiKey diff --git a/lib/constant/links.dart b/lib/constant/links.dart index 7cf7500..458d10e 100644 --- a/lib/constant/links.dart +++ b/lib/constant/links.dart @@ -48,7 +48,8 @@ class AppLink { static String getWalletByDriver = "$walletDriver/getWalletByDriver.php"; static String driverStatistic = "$walletDriver/driverStatistic.php"; - static String getDriverDetails = "$walletDriver/getDriverDetails.php"; + static String getDriverDetails = + "$seferCairoServer/ride/driverWallet/getDriverDetails.php"; static String getDriverWeekPaymentMove = "$walletDriver/getDriverWeekPaymentMove.php"; static String getDriversWallet = "$walletDriver/get.php"; @@ -73,6 +74,7 @@ class AppLink { //-----------------ridessss------------------ static String addRides = "$ride/rides/add.php"; static String getRides = "$ride/rides/get.php"; + static String getMishwari = "$ride/ride/mishwari/get.php"; static String getTripCountByCaptain = "$ride/rides/getTripCountByCaptain.php"; static String getRideOrderID = "$ride/rides/getRideOrderID.php"; static String getRideStatus = "$ride/rides/getRideStatus.php"; @@ -235,6 +237,10 @@ class AppLink { static String getTotalDriverDurationToday = "$location/getTotalDriverDurationToday.php"; + //==================cars new drivers============= + static String addNewCarsDrivers = '$server/ride/carDrivers/add.php'; + static String getNewCarsDrivers = '$server/ride/carDrivers/get.php'; + //==================Blog============= static String profile = '$server/ride/profile'; static String getprofile = "$profile/get.php"; diff --git a/lib/constant/notification.dart b/lib/constant/notification.dart new file mode 100644 index 0000000..7684973 --- /dev/null +++ b/lib/constant/notification.dart @@ -0,0 +1,22 @@ +List driverMessages = [ + "💸 فرص الربح: افتح تطبيق سفر الآن وزد دخلك اليوم! المزيد من الطلبات بانتظارك! 🚗", + "🚀 طلبات جديدة: لا تضيع الفرصة! المزيد من الركاب ينتظرونك الآن على تطبيق سفر. 🏃‍♂️", + "📈 زيادة الدخل: حقق أعلى أرباح اليوم مع سفر! افتح التطبيق وابدأ عملك الآن. 💵", + "🕒 أوقات الذروة: استعد لكسب المزيد خلال فترات الطلب المرتفعة. افتح التطبيق الآن! 📲", + "🚗 طلبات جديدة: كن مستعداً، افتح تطبيق سفر الآن واستقبل المزيد من الطلبات. 🔔", + "🎉 فرص النجاح: ابدأ رحلتك إلى النجاح! افتح تطبيق سفر لزيادة دخلك اليوم. 💼", + "🌍 طلبات مرتفعة: المزيد من الركاب بانتظارك، لا تفوّت الفرص، افتح التطبيق الآن! 🚖", + "💪 زيادة الدخل: انطلق نحو تحقيق أهدافك المالية، افتح تطبيق سفر واكسب المزيد. 🏆", + "💰 أرباح إضافية: افتح التطبيق واستعد لتحقيق أرباح إضافية مع سفر! المزيد من الطلبات في انتظارك. 🛣️", + "🔥 فرص جديدة: تطبيق سفر مزدحم الآن! افتح التطبيق وزد أرباحك بفرص جديدة. 🚗", + "🚨 طلبات متزايدة: افتح تطبيق سفر الآن! الطلب مرتفع وفرص الربح كبيرة! 💸", + "💼 زيادة الدخل: هل أنت جاهز لتحقيق المزيد من الدخل؟ افتح التطبيق وانطلق الآن! 🚖", + "🚗 أوقات الذروة: احجز مقعدك في فترات الطلب العالي، افتح تطبيق سفر الآن واكسب المزيد. 📈", + "📲 بدء اليوم: ابدأ يومك مع سفر، وافتح التطبيق الآن لتزيد من فرص الربح. 💵", + "💸 فرص مستمرة: لا تفوت فرص الربح، افتح تطبيق سفر الآن وكن على استعداد للمزيد! 🔔", + "📆 زيادة الطلب: انطلق اليوم واستفد من الطلبات المتزايدة على تطبيق سفر! افتح التطبيق الآن. 🚗", + "💥 دخل إضافي: افتح تطبيق سفر الآن واستقبل طلبات جديدة تحقق لك المزيد من الدخل. 💰", + "🏆 فرص مرتفعة: استفد من طلبات اليوم المرتفعة، افتح التطبيق الآن مع سفر. 📲", + "🚗 تفضيل العملاء: كن السائق الذي يختاره الجميع! افتح تطبيق سفر اليوم واربح المزيد. 🔥", + "💸 دخل إضافي: فرص الدخل الإضافي في انتظارك! افتح تطبيق سفر واستمتع بالطلبات المتزايدة. 💼", +]; diff --git a/lib/controller/auth/captin/login_captin_controller.dart b/lib/controller/auth/captin/login_captin_controller.dart index 7637d07..785728c 100644 --- a/lib/controller/auth/captin/login_captin_controller.dart +++ b/lib/controller/auth/captin/login_captin_controller.dart @@ -187,12 +187,12 @@ class LoginDriverController extends GetxController { if (token != 'failure') { if (jsonDecode(token)['data'][0]['token'] != box.read(BoxName.tokenDriver)) { - Get.put(FirebaseMessagesController()) - .sendNotificationToAnyWithoutData( - 'token change'.tr, - 'change device'.tr, - jsonDecode(token)['data'][0]['token'].toString(), - 'promo.wav'); + Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP( + 'token change'.tr, + 'change device'.tr, + jsonDecode(token)['data'][0]['token'].toString(), + [], + 'promo.wav'); Get.defaultDialog( title: 'you will use this device?'.tr, middleText: '', @@ -316,12 +316,12 @@ class LoginDriverController extends GetxController { if (token != 'failure') { if (jsonDecode(token)['data'][0]['token'] != box.read(BoxName.tokenDriver)) { - Get.put(FirebaseMessagesController()) - .sendNotificationToAnyWithoutData( - 'token change'.tr, - 'change device'.tr, - jsonDecode(token)['data'][0]['token'].toString(), - 'promo.wav'); + Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP( + 'token change'.tr, + 'change device'.tr, + jsonDecode(token)['data'][0]['token'].toString(), + [], + 'promo.wav'); Get.defaultDialog( title: 'you will use this device?'.tr, middleText: '', diff --git a/lib/controller/auth/google_sign.dart b/lib/controller/auth/google_sign.dart index 05015f8..bf8f3ff 100644 --- a/lib/controller/auth/google_sign.dart +++ b/lib/controller/auth/google_sign.dart @@ -90,15 +90,28 @@ class GoogleSignInHelper { final GoogleSignInAccount? googleUser = await _googleSignIn.signIn(); if (googleUser != null) { + // Handle sign-up and store user information await _handleSignUp(googleUser); - // Add detailed debug print statements + // Retrieve driverID and emailDriver with added validation final driverID = box.read(BoxName.driverID)?.toString() ?? 'Unknown ID'; final emailDriver = box.read(BoxName.emailDriver)?.toString() ?? 'Unknown Email'; + // Debug print statements + print('Driver ID: $driverID'); + print('Driver Email: $emailDriver'); + + // Check if driverID is a valid numeric string + // if (driverID != 'Unknown ID' && int.tryParse(driverID) != null) { await Get.find() .loginUsingCredentials(driverID, emailDriver); + // } + // else { + // print('Invalid driverID format: $driverID'); + // Get.snackbar('Login Error', 'Invalid driver ID format.', + // backgroundColor: AppColor.redColor); + // } } return googleUser; @@ -110,6 +123,13 @@ class GoogleSignInHelper { } } + static Future _handleSignUp(GoogleSignInAccount user) async { + // Store driver information + box.write(BoxName.driverID, + user.id ?? 'Unknown ID'); // Ensure there's a fallback value + box.write(BoxName.emailDriver, user.email ?? 'Unknown Email'); + } + // Method to handle Google Sign-Out static Future signOut() async { try { @@ -145,16 +165,4 @@ class GoogleSignInHelper { static GoogleSignInAccount? getCurrentUser() { return _googleSignIn.currentUser; } - - // Method to handle sign-up process - static Future _handleSignUp(GoogleSignInAccount user) async { - // Store driver information - box.write(BoxName.driverID, user.id); - box.write(BoxName.emailDriver, user.email); - // box.write(BoxName.nameDriver, user.displayName); - // box.write(BoxName.driverPhotoUrl, user.photoUrl); - - // Perform any additional sign-up tasks or API calls here - // For example, you can send the user data to your server for registration - } } diff --git a/lib/controller/firebase/firbase_messge.dart b/lib/controller/firebase/firbase_messge.dart index 152129e..e862b2e 100644 --- a/lib/controller/firebase/firbase_messge.dart +++ b/lib/controller/firebase/firbase_messge.dart @@ -33,7 +33,8 @@ class FirebaseMessagesController extends GetxController { late String driverID; late String driverToken; NotificationSettings? notificationSettings; - + NotificationController notificationController = + Get.put(NotificationController()); Future getNotificationSettings() async { // Get the current notification settings NotificationSettings? notificationSettings = @@ -78,34 +79,15 @@ class FirebaseMessagesController extends GetxController { 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 { - // if (message.notification!.title! == 'Order'.tr) { - // if (Platform.isAndroid) { - // NotificationController1() - // .showNotification('Order'.tr, '', 'order', 'order_page_payload'); - // } - // // await FirebaseMessagesController().showOverlayNotification(message); - // var myListString = message.data['DriverList']; - // // var points = message.data['PolylineJson']; - - // var myList = jsonDecode(myListString) as List; - // // var myPoints = jsonDecode(points) as List; - // driverToken = myList[14].toString(); - // // This is for location using and uploading status - // Get.put(HomeCaptainController()).changeRideId(); - // update(); - // Get.to(() => OrderRequestPage(), arguments: { - // 'myListString': myListString, - // 'DriverList': myList, - // // 'PolylineJson': myPoints, - // 'body': message.notification!.body - // }); - // } - }); + FirebaseMessaging.onBackgroundMessage((RemoteMessage message) async {}); FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { if (message.data.isNotEmpty && message.notification != null) { @@ -117,7 +99,7 @@ class FirebaseMessagesController extends GetxController { Future fireBaseTitles(RemoteMessage message) async { if (message.notification!.title! == 'OrderSpeed'.tr) { if (Platform.isAndroid) { - NotificationController().showNotification( + notificationController.showNotification( message.notification!.title.toString(), message.notification!.body.toString(), 'order', @@ -139,9 +121,25 @@ class FirebaseMessagesController extends GetxController { // 'PolylineJson': myPoints, 'body': message.notification!.body }); - } else if (message.notification!.title == 'Cancel Trip') { + } else if (message.notification!.title == 'OrderVIP') { + var myListString = message.data['DriverList']; + + var myList = jsonDecode(myListString) as List; + + // driverToken = myList[10].toString(); if (Platform.isAndroid) { - NotificationController1().showNotification( + 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(); @@ -149,8 +147,8 @@ class FirebaseMessagesController extends GetxController { var myListString = message.data['DriverList']; var driverList = jsonDecode(myListString) as List; if (Platform.isAndroid) { - NotificationController1() - .showNotification('VIP Order'.tr, '', 'order', ''); + notificationController.showNotification( + 'VIP Order'.tr, '', 'order', ''); } MyDialog().getDialog('VIP Order'.tr, 'midTitle', () { sendNotificationToPassengerToken( @@ -162,26 +160,19 @@ class FirebaseMessagesController extends GetxController { }); // Get.to(const VipOrderPage()); - } else if (message.notification!.title! == 'message From passenger'.tr) { - // passengerDialog(message.notification!.body!); + } else if (message.notification!.title == 'message From passenger') { if (Platform.isAndroid) { - NotificationController() - .showNotification('message From passenger'.tr, ''.tr, 'ding', ''); + notificationController.showNotification( + 'message From passenger'.tr, ''.tr, 'ding', ''); } MyDialog().getDialog( 'message From passenger'.tr, message.notification!.body!, () { - // FirebaseMessagesController().sendNotificationToPassengerToken( - // 'Hi ,I will go now'.tr, - // 'I will go now'.tr, - // Get.find().driverToken, []); - // Get.find() - // .startTimerDriverWaitPassenger5Minute(); Get.back(); }); } else if (message.notification!.title == 'Cancel') { if (Platform.isAndroid) { - NotificationController() - .showNotification('Cancel'.tr, ''.tr, 'cancel', ''); + notificationController.showNotification( + 'Cancel'.tr, ''.tr, 'cancel', ''); } MyDialog().getDialog( 'Passenger Cancel Trip'.tr, @@ -192,14 +183,14 @@ class FirebaseMessagesController extends GetxController { }); // cancelTripDialog1(); } else if (message.notification!.title! == 'token change') { - // NotificationController1() + // 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', ''); + notificationController.showNotification( + 'face detect'.tr, ''.tr, 'tone2', ''); } String result0 = await faceDetector(); // Handle the result here, e.g., show a dialog or update the UI @@ -220,7 +211,7 @@ class FirebaseMessagesController extends GetxController { // Get.snackbar('Hi ,I will go now', '', // backgroundColor: AppColor.greenColor); if (Platform.isAndroid) { - NotificationController1().showNotification( + notificationController.showNotification( 'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'tone2', ''); } update(); @@ -230,7 +221,7 @@ class FirebaseMessagesController extends GetxController { var driverList = jsonDecode(myListString) as List; // if (Platform.isAndroid) { if (Platform.isAndroid) { - NotificationController1().showNotification('Call Income'.tr, + notificationController.showNotification('Call Income'.tr, message.notification!.body!, 'iphone_ringtone', ''); } // } @@ -248,7 +239,7 @@ class FirebaseMessagesController extends GetxController { var driverList = jsonDecode(myListString) as List; // if (Platform.isAndroid) { if (Platform.isAndroid) { - NotificationController1().showNotification('Call Income'.tr, + notificationController.showNotification('Call Income'.tr, message.notification!.body!, 'iphone_ringtone', ''); } // } @@ -262,11 +253,8 @@ class FirebaseMessagesController extends GetxController { } else if (message.notification!.title! == "Criminal Document Required".tr) { if (Platform.isAndroid) { - NotificationController1().showNotification( - "Criminal Document Required".tr, - message.notification!.body!, - 'tone2', - ''); + notificationController.showNotification("Criminal Document Required".tr, + message.notification!.body!, 'tone2', ''); } MyDialog().getDialog( "Criminal Document Required".tr, 'You should have upload it .'.tr, @@ -279,7 +267,7 @@ class FirebaseMessagesController extends GetxController { var myListString = message.data['passengerList']; var driverList = jsonDecode(myListString) as List; if (Platform.isAndroid) { - NotificationController1().showNotification( + notificationController.showNotification( 'Call End'.tr, message.notification!.body!, 'tone2', ''); } // Assuming GetMaterialApp is initialized and context is valid for navigation @@ -296,7 +284,7 @@ class FirebaseMessagesController extends GetxController { ); } else if (message.notification!.title! == 'Order') { if (Platform.isAndroid) { - NotificationController().showNotification( + notificationController.showNotification( message.notification!.title.toString(), message.notification!.body.toString(), 'order', @@ -318,7 +306,7 @@ class FirebaseMessagesController extends GetxController { }); } else if (message.notification!.title! == 'Order Applied'.tr) { if (Platform.isAndroid) { - NotificationController1().showNotification( + notificationController.showNotification( 'The order Accepted by another Driver'.tr, 'We regret to inform you that another driver has accepted this order.' .tr, @@ -761,98 +749,6 @@ class FirebaseMessagesController extends GetxController { } } - void sendNotificationToAnyWithoutData( - String title, String body, String token, String tone, - {int retryCount = 2}) async { - try { - String serviceAccountKeyJson = '''{ - "type": "service_account", - "project_id": "ride-b1bd8", - "private_key_id": "75e817c0b902db2ef35edf2c2bd159dec1f13249", - "private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD0zH9TQGDQHUv3\\na3/JAD1UKPwAp3wNKT0a6fxiIzjI3JxQWI30QvZCcfl6CdMhIcydX1ncSaYTcEeC\\n/AdPVCPkqyJx1YIGGg6P/mRzCWeaN8fsp6z250m5vcObDCZc3dbJEkepbep+6FPY\\n21m3KO+AHh1glgsTGZOTm5xiU8NGXpdk2QEh8wpiIIlR/HuKwVw9g8urNe3Sno+U\\nDm3z37iFqvZdmpqO8aWTJu6beb3hsREK9XK2I9JqC2JUwiGQRo3idOvPP6hkqrWx\\nKSX96vglQFYfakvJdDp2ZATOlpBYPMtS/IWhJ985u58TSS+Kl8qpnpaZBSxgJirf\\nhWzhnKLfAgMBAAECggEAJP785SePGhS7ZN6ltspm+l+hSjYFrPWFCxq+rlQ1YkHZ\\nC9l+RqKSFhOkiPmQI2s4wbXl3kFxLHHlFNoi/q2wKQBmGb8TQfnRJpjjNHGA61Ev\\n0Ue7/6qPvVb9B2MsLw/FxKiTFPuMG3bgKR9pbSFuJLYoaW7zqITOhVnYphGTqwAY\\nBVVcvISSLvELDmH9VZcv/9DVqVlqbbESHWh1Z4W6XGPoEqeDH/upNTyQQ/46Msgm\\nTGE6VqLHpWuSf6SqHp+r0Y0lI3vIPM1vz5FAJDJbOE/enHa0fSup0OHSMxl0HVMn\\nnO1yrGF3vsIPOej5HKr5d71bEIckzk73/yjNC1/mDQKBgQD7RtUvc9omsSsFMJ6e\\nBASAn6Dktx/QY/XNJjFzHQj69cywLDe5t5AL2gUi3phQ2oqB5XJdwnd5bTIEPEPZ\\nDOuOai2802p6FJk6kjmZAMVGx5JtXBH+vs6jrmQQSMiKbjwN1TT6xIWakvLOonUi\\nX6ZvjYYjU/E0YJU3jSiXWEr76wKBgQD5Zn4SouJ6BCDZMbausJVMBkk3qxsYooip\\np89WakC6e7AZinpkRcqjGGV9GOvc8crJs6fyXAA9ORepGP47Mc0ZrDssOkstznsM\\npr8R0S6MKwEZaT9ixOHdOcLZ47ps+JzA2Wr4KN2OvFHksUkB/46ATD1j9WZVgB8M\\namsYp/Y73QKBgHOo+PvsoZ9psVmkNX6abtAdqdtdB0HOoRea2uwXk0ig12TIFaZg\\nfedWpUKVnxqoXVTJHklV99RmlL0qWDiSH+LfsMnXro0e6iDxqZ1po2Se/CFmXcoa\\nXdctsFVmixhdATuExewfhTfPKABA+xWlXWC/jdy5CK+JPWXijaqMM4edAoGAE5Bj\\nsWiPpYyvWvpYX0nA3G7dzX0hqgQN/mkIjbnWDArp3IcNZNJIvBSM2Yxb7EAXbU0n\\njo6DAkp5Pa2VO+WDNlFZbvW/sf8xjeOCt44WPa6d7nVgIIpbQXRngZoopKW3/jTP\\n/FmQT8McFXmGxZ5belsAsdetSGW9icbLUerTGQ0CgYEAmf/G8Ag3XxmqTXvvHuv2\\n14OP7WnrVqkEMnydrftEwn4peXd/Lz+/GYX5Zc4ZoNgbN8IvZ5z0+OmRsallsbiW\\nBw0/tc68CjzxXOvReWxDluUopqWVGj5tlGqE5xUDku9SWJSxbkiQ3rqutzBdPXpr\\noqHwPyDrmK/Zgqn+uiIm4Ck=\\n-----END PRIVATE KEY-----\\n", - "client_email": "firebase-adminsdk-o2wqi@ride-b1bd8.iam.gserviceaccount.com", - "client_id": "111210077025005706623", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-o2wqi%40ride-b1bd8.iam.gserviceaccount.com", - "universe_domain": "googleapis.com" -} -'''; // As defined above - - // Initialize AccessTokenManager - final accessTokenManager = AccessTokenManager(serviceAccountKeyJson); - - // Obtain an OAuth 2.0 access token - final accessToken = await accessTokenManager.getAccessToken(); - - // 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': { - // 'DriverList': jsonEncode([]), - // }, - '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 sendNotificationToAnyWithoutData(title, body, token, 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 sendNotificationToAnyWithoutData(title, body, token, tone, - retryCount: retryCount - 1); - } - } - } - void sendNotificationToDriverMAP( String title, String body, String token, List data, String tone, {int retryCount = 2}) async { @@ -946,79 +842,6 @@ class FirebaseMessagesController extends GetxController { } } } - - void sendNotificationToDriverMapPolyline(String title, String body, - String token, List data, String polylineJson, String tone) async { - try { - String serviceAccountKeyJson = '''{ - "type": "service_account", - "project_id": "ride-b1bd8", - "private_key_id": "75e817c0b902db2ef35edf2c2bd159dec1f13249", - "private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD0zH9TQGDQHUv3\\na3/JAD1UKPwAp3wNKT0a6fxiIzjI3JxQWI30QvZCcfl6CdMhIcydX1ncSaYTcEeC\\n/AdPVCPkqyJx1YIGGg6P/mRzCWeaN8fsp6z250m5vcObDCZc3dbJEkepbep+6FPY\\n21m3KO+AHh1glgsTGZOTm5xiU8NGXpdk2QEh8wpiIIlR/HuKwVw9g8urNe3Sno+U\\nDm3z37iFqvZdmpqO8aWTJu6beb3hsREK9XK2I9JqC2JUwiGQRo3idOvPP6hkqrWx\\nKSX96vglQFYfakvJdDp2ZATOlpBYPMtS/IWhJ985u58TSS+Kl8qpnpaZBSxgJirf\\nhWzhnKLfAgMBAAECggEAJP785SePGhS7ZN6ltspm+l+hSjYFrPWFCxq+rlQ1YkHZ\\nC9l+RqKSFhOkiPmQI2s4wbXl3kFxLHHlFNoi/q2wKQBmGb8TQfnRJpjjNHGA61Ev\\n0Ue7/6qPvVb9B2MsLw/FxKiTFPuMG3bgKR9pbSFuJLYoaW7zqITOhVnYphGTqwAY\\nBVVcvISSLvELDmH9VZcv/9DVqVlqbbESHWh1Z4W6XGPoEqeDH/upNTyQQ/46Msgm\\nTGE6VqLHpWuSf6SqHp+r0Y0lI3vIPM1vz5FAJDJbOE/enHa0fSup0OHSMxl0HVMn\\nnO1yrGF3vsIPOej5HKr5d71bEIckzk73/yjNC1/mDQKBgQD7RtUvc9omsSsFMJ6e\\nBASAn6Dktx/QY/XNJjFzHQj69cywLDe5t5AL2gUi3phQ2oqB5XJdwnd5bTIEPEPZ\\nDOuOai2802p6FJk6kjmZAMVGx5JtXBH+vs6jrmQQSMiKbjwN1TT6xIWakvLOonUi\\nX6ZvjYYjU/E0YJU3jSiXWEr76wKBgQD5Zn4SouJ6BCDZMbausJVMBkk3qxsYooip\\np89WakC6e7AZinpkRcqjGGV9GOvc8crJs6fyXAA9ORepGP47Mc0ZrDssOkstznsM\\npr8R0S6MKwEZaT9ixOHdOcLZ47ps+JzA2Wr4KN2OvFHksUkB/46ATD1j9WZVgB8M\\namsYp/Y73QKBgHOo+PvsoZ9psVmkNX6abtAdqdtdB0HOoRea2uwXk0ig12TIFaZg\\nfedWpUKVnxqoXVTJHklV99RmlL0qWDiSH+LfsMnXro0e6iDxqZ1po2Se/CFmXcoa\\nXdctsFVmixhdATuExewfhTfPKABA+xWlXWC/jdy5CK+JPWXijaqMM4edAoGAE5Bj\\nsWiPpYyvWvpYX0nA3G7dzX0hqgQN/mkIjbnWDArp3IcNZNJIvBSM2Yxb7EAXbU0n\\njo6DAkp5Pa2VO+WDNlFZbvW/sf8xjeOCt44WPa6d7nVgIIpbQXRngZoopKW3/jTP\\n/FmQT8McFXmGxZ5belsAsdetSGW9icbLUerTGQ0CgYEAmf/G8Ag3XxmqTXvvHuv2\\n14OP7WnrVqkEMnydrftEwn4peXd/Lz+/GYX5Zc4ZoNgbN8IvZ5z0+OmRsallsbiW\\nBw0/tc68CjzxXOvReWxDluUopqWVGj5tlGqE5xUDku9SWJSxbkiQ3rqutzBdPXpr\\noqHwPyDrmK/Zgqn+uiIm4Ck=\\n-----END PRIVATE KEY-----\\n", - "client_email": "firebase-adminsdk-o2wqi@ride-b1bd8.iam.gserviceaccount.com", - "client_id": "111210077025005706623", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-o2wqi%40ride-b1bd8.iam.gserviceaccount.com", - "universe_domain": "googleapis.com" -} -'''; // As defined above - - // Initialize AccessTokenManager - final accessTokenManager = AccessTokenManager(serviceAccountKeyJson); - - // Obtain an OAuth 2.0 access token - final accessToken = await accessTokenManager.getAccessToken(); - - // 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': { - '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) { - // Notification sent successfully - } else { - // Handle error response - 'Failed to send notification. Status code: ${response.statusCode}'; - } - } catch (e) { - // Handle other exceptions - } - } } class OverlayContent extends StatelessWidget { diff --git a/lib/controller/firebase/local_notification.dart b/lib/controller/firebase/local_notification.dart index cf94801..1f16930 100644 --- a/lib/controller/firebase/local_notification.dart +++ b/lib/controller/firebase/local_notification.dart @@ -1,4 +1,6 @@ +import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'dart:typed_data'; import 'package:SEFER/constant/colors.dart'; @@ -6,7 +8,11 @@ import 'package:SEFER/views/home/Captin/orderCaptin/order_request_page.dart'; import 'package:SEFER/views/home/Captin/orderCaptin/order_speed_request.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get/get.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:timezone/data/latest.dart' as tz; +import 'package:timezone/timezone.dart' as tz; +import '../../constant/box_name.dart'; import '../../main.dart'; import '../../print.dart'; import '../../views/notification/notification_captain.dart'; @@ -19,10 +25,17 @@ class NotificationController extends GetxController { Future initNotifications() async { const AndroidInitializationSettings android = AndroidInitializationSettings('@mipmap/launcher_icon'); - - const InitializationSettings initializationSettings = - InitializationSettings(android: android); - + DarwinInitializationSettings ios = DarwinInitializationSettings( + requestAlertPermission: true, + requestBadgePermission: true, + requestSoundPermission: true, + onDidReceiveLocalNotification: + (int id, String? title, String? body, String? payload) async {}, + ); + InitializationSettings initializationSettings = + InitializationSettings(android: android, iOS: ios); + tz.initializeTimeZones(); + print('Notifications initialized'); await _flutterLocalNotificationsPlugin.initialize( initializationSettings, onDidReceiveNotificationResponse: onDidReceiveNotificationResponse, @@ -85,13 +98,266 @@ class NotificationController extends GetxController { ], category: AndroidNotificationCategory.progress, ); - - NotificationDetails details = NotificationDetails(android: android); + DarwinNotificationDetails ios = const DarwinNotificationDetails( + sound: 'default', + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + NotificationDetails details = + NotificationDetails(android: android, iOS: ios); await _flutterLocalNotificationsPlugin.show(0, title, message, details, payload: jsonEncode({'title': title, 'data': payLoad})); } + void scheduleNotificationAtSpecificTime( + String title, String message, String tone, int hour, int minute) async { + // Initialize and set Cairo time zone + tz.initializeTimeZones(); + var cairoLocation; + if (box.read(BoxName.countryCode).toString() == 'Egypt') { + cairoLocation = tz.getLocation('Africa/Cairo'); + } else {} // todo get for location country + + final AndroidNotificationDetails android = AndroidNotificationDetails( + 'high_importance_channel', + 'High Importance Notifications', + importance: Importance.max, + priority: Priority.high, + showWhen: false, + sound: RawResourceAndroidNotificationSound(tone), + ); + + const DarwinNotificationDetails ios = DarwinNotificationDetails( + sound: 'default', + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + + final NotificationDetails details = + NotificationDetails(android: android, iOS: ios); + + final now = + tz.TZDateTime.now(cairoLocation); // Use Cairo timezone for current time + tz.TZDateTime scheduledTime = tz.TZDateTime( + cairoLocation, now.year, now.month, now.day, hour, minute); + + // If the scheduled time has already passed for today, schedule it for the next day + if (scheduledTime.isBefore(now)) { + scheduledTime = scheduledTime.add(const Duration(days: 1)); + } + + if (Platform.isAndroid) { + if (await Permission.scheduleExactAlarm.isDenied) { + if (await Permission.scheduleExactAlarm.request().isGranted) { + print('SCHEDULE_EXACT_ALARM permission granted'); + } else { + print('SCHEDULE_EXACT_ALARM permission denied'); + return; + } + } + } + + print('Current time: $now'); + print('Scheduling notification for: $scheduledTime'); + await _flutterLocalNotificationsPlugin.zonedSchedule( + 0, + title, + message, + scheduledTime, + details, + androidAllowWhileIdle: true, + uiLocalNotificationDateInterpretation: + UILocalNotificationDateInterpretation.absoluteTime, + matchDateTimeComponents: + DateTimeComponents.time, // Triggers daily at the same time + ); + print('Notification scheduled successfully'); + } + + void scheduleNotificationAfter1Minute( + String title, String message, String tone) async { + final AndroidNotificationDetails android = AndroidNotificationDetails( + 'high_importance_channel', + 'High Importance Notifications', + importance: Importance.max, + priority: Priority.high, + showWhen: false, + sound: RawResourceAndroidNotificationSound(tone), + ); + + const DarwinNotificationDetails ios = DarwinNotificationDetails( + sound: 'default', + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + + final NotificationDetails details = + NotificationDetails(android: android, iOS: ios); + +// Schedule the notification to be shown after 1 minute + Timer.periodic(const Duration(seconds: 15), (timer) async { + final now = tz.TZDateTime.now(tz.local); + final scheduledTime = now.add(const Duration(seconds: 10)); + Log.print('scheduledTime: ${scheduledTime}'); + if (Platform.isAndroid) { + if (await Permission.scheduleExactAlarm.isDenied) { + if (await Permission.scheduleExactAlarm.request().isGranted) { + print('SCHEDULE_EXACT_ALARM permission granted'); + } else { + print('SCHEDULE_EXACT_ALARM permission denied'); + return; + } + } + } + + print('Scheduling notification for: $scheduledTime'); + await _flutterLocalNotificationsPlugin.zonedSchedule( + 0, + title, + message, + scheduledTime, + details, + androidAllowWhileIdle: true, + uiLocalNotificationDateInterpretation: + UILocalNotificationDateInterpretation.absoluteTime, + matchDateTimeComponents: DateTimeComponents.time, + ); + print('Notification scheduled successfully'); + }); + } + + void scheduleDailyNotifications( + String title, String message, String tone) async { + final AndroidNotificationDetails android = AndroidNotificationDetails( + 'high_importance_channel', + 'High Importance Notifications', + importance: Importance.max, + priority: Priority.high, + sound: RawResourceAndroidNotificationSound(tone), + ); + + const DarwinNotificationDetails ios = DarwinNotificationDetails( + sound: 'default', + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + + final NotificationDetails details = + NotificationDetails(android: android, iOS: ios); + + // Check for the exact alarm permission on Android 12 and above + if (Platform.isAndroid) { + if (await Permission.scheduleExactAlarm.isDenied) { + if (await Permission.scheduleExactAlarm.request().isGranted) { + print('SCHEDULE_EXACT_ALARM permission granted'); + } else { + print('SCHEDULE_EXACT_ALARM permission denied'); + return; + } + } + } + + // Schedule notifications for 10:00 AM and 3:00 PM daily + await _scheduleNotificationForTime(7, 0, title, message, details); + await _scheduleNotificationForTime(13, 0, title, message, details); + await _scheduleNotificationForTime(18, 0, title, message, details); + // await _scheduleNotificationForTime(0, 22, title, message, details); + + print('Daily notifications scheduled successfully'); + } + +// Helper function to get the next instance of a specific hour and minute + Future _scheduleNotificationForTime(int hour, int minute, String title, + String message, NotificationDetails details) async { + // Initialize and set Cairo timezone + tz.initializeTimeZones(); + final cairoLocation = tz.getLocation('Africa/Cairo'); // Set Cairo timezone + + final now = tz.TZDateTime.now( + cairoLocation); // Use Cairo timezone for the current time + tz.TZDateTime scheduledDate = tz.TZDateTime( + cairoLocation, now.year, now.month, now.day, hour, minute); + + // If scheduled time is already past today, schedule it for the next day + if (scheduledDate.isBefore(now)) { + scheduledDate = scheduledDate.add(const Duration(days: 1)); + } + + print('Current time (Cairo): $now'); + print('Scheduling notification for: $scheduledDate'); + + await _flutterLocalNotificationsPlugin.zonedSchedule( + 0, // Use unique IDs if you want to manage each notification separately + title, + message, + scheduledDate, + details, + androidAllowWhileIdle: true, + uiLocalNotificationDateInterpretation: + UILocalNotificationDateInterpretation.absoluteTime, + matchDateTimeComponents: DateTimeComponents.time, + ); + print('Notification scheduled successfully for Cairo timezone'); + } + + void scheduleNotificationEvery10Hours( + String title, String message, String tone) async { + final AndroidNotificationDetails android = AndroidNotificationDetails( + 'high_importance_channel', + 'High Importance Notifications', + importance: Importance.max, + priority: Priority.high, + showWhen: false, + sound: RawResourceAndroidNotificationSound(tone), + ); + + const DarwinNotificationDetails ios = DarwinNotificationDetails( + sound: 'default', + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + + final NotificationDetails details = + NotificationDetails(android: android, iOS: ios); + + if (Platform.isAndroid) { + if (await Permission.scheduleExactAlarm.isDenied) { + if (await Permission.scheduleExactAlarm.request().isGranted) { + print('SCHEDULE_EXACT_ALARM permission granted'); + } else { + print('SCHEDULE_EXACT_ALARM permission denied'); + return; + } + } + } + + Timer.periodic(const Duration(hours: 10), (timer) async { + final now = tz.TZDateTime.now(tz.local); + final scheduledTime = now.add(const Duration(minutes: 10)); + + print('Scheduling notification for: $scheduledTime'); + await _flutterLocalNotificationsPlugin.zonedSchedule( + 0, + title.tr, + message.tr, + scheduledTime, + details, + androidAllowWhileIdle: true, + uiLocalNotificationDateInterpretation: + UILocalNotificationDateInterpretation.absoluteTime, + matchDateTimeComponents: DateTimeComponents.time, + ); + }); + + print('Notifications scheduled every 5 seconds'); + } + // Callback when the notification is tapped void onDidReceiveNotificationResponse(NotificationResponse response) { handleNotificationResponse(response); diff --git a/lib/controller/functions/gemeni.dart b/lib/controller/functions/gemeni.dart index 8b6bf38..8b520b2 100644 --- a/lib/controller/functions/gemeni.dart +++ b/lib/controller/functions/gemeni.dart @@ -626,6 +626,51 @@ class AI extends GetxController { } } + Future allMethodForAINewCar( + String prompt, String linkPHP, String imagePath, String carID) async { + isLoading = true; + update(); + + try { + await ImageController().choosImageNewCAr(linkPHP, imagePath); + + // if (imagePath == 'driver_license') { + // await ImageController().choosFaceFromDriverLicense(linkPHP, 'face'); + // } + + await Future.delayed(const Duration(seconds: 2)); + + var extractedString = + await CRUD().arabicTextExtractByVisionAndAI(imagePath: imagePath); + var json = jsonDecode(extractedString); + var textValues = CRUD().extractTextFromLines(json); + + DocumentType detectedType = checkDocumentType(textValues); + String expectedDocument = getExpectedDocument(imagePath); + String detectedDocument = getDetectedDocument(detectedType); + + bool isCorrectDocument = (detectedType == getExpectedType(imagePath)); + + if (!isCorrectDocument) { + MyDialog().getDialog('incorrect_document_title'.tr, + '${'expected'.tr}: $expectedDocument\n${'detected'.tr}: $detectedDocument', + () { + Get.back(); + }); + } else { + // Process the correct document + await Get.put(AI()).anthropicAI(textValues, prompt, imagePath); + } + } catch (e) { + MyDialog().getDialog('error'.tr, 'error_processing_document'.tr, () { + Get.back(); + }); + } finally { + isLoading = false; + update(); + } + } + String getExpectedDocument(String imagePath) { switch (imagePath) { case 'car_front': diff --git a/lib/controller/functions/sms_egypt_controller.dart b/lib/controller/functions/sms_egypt_controller.dart index d172e90..13169cf 100644 --- a/lib/controller/functions/sms_egypt_controller.dart +++ b/lib/controller/functions/sms_egypt_controller.dart @@ -30,8 +30,8 @@ class SmsEgyptController extends GetxController { Future sendSmsEgypt(String phone, otp) async { String sender = await getSender(); var body = jsonEncode({ - "username": AppInformation.appName, - "password": AK.smsPasswordEgypt, //'E)Pu=an/@Z', + "username": 'Sefer', + "password": AK.smsPasswordEgypt, "message": "${AppInformation.appName} app code is $otp\ncopy it to app", "language": box.read(BoxName.lang) == 'en' ? "e" : 'r', "sender": sender, //"Sefer Egy", // todo add sefer sender name diff --git a/lib/controller/functions/upload_image.dart b/lib/controller/functions/upload_image.dart index 09339c0..f2d11cf 100644 --- a/lib/controller/functions/upload_image.dart +++ b/lib/controller/functions/upload_image.dart @@ -139,8 +139,8 @@ class ImageController extends GetxController { File compressedImage = await compressImage(processedImage); print('link =$link'); - Log.print('link: ${link}'); - + // Log.print('link: ${link}'); +//n8u22456 await uploadImage( compressedImage, { @@ -160,6 +160,65 @@ class ImageController extends GetxController { } } + choosImageNewCAr(String link, String imageType) async { + try { + final pickedImage = await picker.pickImage( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.rear, + ); + + if (pickedImage == null) return; + + image = File(pickedImage.path); + + croppedFile = await ImageCropper().cropImage( + sourcePath: image!.path, + uiSettings: [ + AndroidUiSettings( + toolbarTitle: 'Cropper'.tr, + toolbarColor: AppColor.blueColor, + toolbarWidgetColor: AppColor.yellowColor, + initAspectRatio: CropAspectRatioPreset.original, + lockAspectRatio: false, + ), + IOSUiSettings( + title: 'Cropper'.tr, + ), + ], + ); + + if (croppedFile == null) return; + + myImage = File(croppedFile!.path); + isloading = true; + update(); + + // Rotate the compressed image + File processedImage = await rotateImageIfNeeded(File(croppedFile!.path)); + File compressedImage = await compressImage(processedImage); + + print('link =$link'); + // Log.print('link: ${link}'); +//n8u22456 + await uploadNewCar( + compressedImage, + { + 'driverID': + box.read(BoxName.driverID) ?? box.read(BoxName.passengerID), + 'imageType': imageType, + }, + link, + ); + } catch (e) { + print('Error in choosImage: $e'); + Get.snackbar('Image Upload Failed'.tr, e.toString(), + backgroundColor: AppColor.primaryColor); + } finally { + isloading = false; + update(); + } + } + // choosFaceFromDriverLicense(String link, String imageType) async { // final pickedImage = await picker.pickImage( // source: ImageSource.camera, @@ -278,6 +337,47 @@ class ImageController extends GetxController { } } + uploadNewCar(File file, Map data, String link) async { + var request = http.MultipartRequest( + 'POST', + Uri.parse(link), + ); + + var length = await file.length(); + var stream = http.ByteStream(file.openRead()); + var multipartFile = http.MultipartFile( + 'image', + stream, + length, + filename: basename(file.path), + ); + request.headers.addAll({ + 'Authorization': + 'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}', + }); + // Set the file name to the driverID + request.files.add( + http.MultipartFile( + 'image', + stream, + length, + filename: '${box.read(BoxName.driverID)}.jpg', + ), + ); + data.forEach((key, value) { + request.fields[key] = value; + }); + var myrequest = await request.send(); + var res = await http.Response.fromStream(myrequest); + if (res.statusCode == 200) { + Log.print('jsonDecode(res.body): ${jsonDecode(res.body)}'); + return jsonDecode(res.body); + } else { + throw Exception( + 'Failed to upload image: ${res.statusCode} - ${res.body}'); + } + } + choosImagePicture(String link, String imageType) async { final pickedImage = await picker.pickImage( source: ImageSource.gallery, diff --git a/lib/controller/home/captin/map_driver_controller.dart b/lib/controller/home/captin/map_driver_controller.dart index 3c5133c..e4ff59b 100644 --- a/lib/controller/home/captin/map_driver_controller.dart +++ b/lib/controller/home/captin/map_driver_controller.dart @@ -300,10 +300,11 @@ class MapDriverController extends GetxController { } // Get.find().changeToAppliedRide('Applied'); - FirebaseMessagesController().sendNotificationToAnyWithoutData( + FirebaseMessagesController().sendNotificationToDriverMAP( 'DriverIsGoingToPassenger', box.read(BoxName.name).toString(), tokenPassenger, + [], 'start.wav'); } @@ -390,11 +391,8 @@ class MapDriverController extends GetxController { 'status': 'Begin', }); } - FirebaseMessagesController().sendNotificationToAnyWithoutData( - 'RideIsBegin', - box.read(BoxName.name).toString(), - tokenPassenger, - 'start.wav'); + FirebaseMessagesController().sendNotificationToDriverMAP('RideIsBegin', + box.read(BoxName.name).toString(), tokenPassenger, [], 'start.wav'); rideIsBeginPassengerTimer(); // var d = jsonDecode(res); @@ -673,7 +671,7 @@ class MapDriverController extends GetxController { 'driverID': box.read(BoxName.driverID).toString(), }); Future.delayed(const Duration(milliseconds: 300)); - FirebaseMessagesController().sendNotificationToPassengerToken( + FirebaseMessagesController().sendNotificationToDriverMAP( 'Driver Finish Trip', '${'you will pay to Driver'.tr} $paymentAmount \$', tokenPassenger, diff --git a/lib/controller/local/translations.dart b/lib/controller/local/translations.dart index 81205de..62ac7bf 100644 --- a/lib/controller/local/translations.dart +++ b/lib/controller/local/translations.dart @@ -196,14 +196,22 @@ class MyTranslation extends Translations { "Total Earnings": "إجمالي الأرباح", "Choose from contact": "اختر من جهات الاتصال", "Cancel": "إلغاء", + "Open App": "افتح التطبيق", + "Add new car": "أضف سيارة جديدة", + "Open the app to stay updated and ready for upcoming tasks.": + "افتح التطبيق لتبقى على اطلاع واستعداد للمهام القادمة.", "No invitation found": "لم يتم العثور على دعوة", 'You are not near the passenger location': "أنت لست بالقرب من موقع الراكب", + 'Please upload this license.': "يرجى تحميل هذه الرخصة.", + 'If your car license has the new design, upload the front side with two images.': + "إذا كانت رخصة سيارتك ذات التصميم الجديد، يرجى تحميل الوجه الأمامي بصورتين.", 'If you need assistance, contact us': "إذا كنت بحاجة إلى المساعدة، تواصل معنا", 'You Can Cancel the Trip and get Cost From ': "يمكنك إلغاء الرحلة والحصول على التكلفة من", - + 'Please make sure to read the license carefully.': + "يرجى التأكد من قراءة الرخصة بعناية", 'Videos Tutorials': "فيديوهات تعليمية", 'Please go to the pickup location exactly': "يرجى الذهاب إلى موقع الالتقاط بالضبط", diff --git a/lib/controller/rate/rate_conroller.dart b/lib/controller/rate/rate_conroller.dart index 780dabe..81669c8 100644 --- a/lib/controller/rate/rate_conroller.dart +++ b/lib/controller/rate/rate_conroller.dart @@ -87,10 +87,11 @@ class RateController extends GetxController { // 'token': paymentToken4, // 'driverID': box.read(BoxName.driverID).toString(), // }); - FirebaseMessagesController().sendNotificationToAnyWithoutData( + FirebaseMessagesController().sendNotificationToDriverMAP( 'Wallet Added'.tr, 'Wallet Added${(remainingFee).toStringAsFixed(0)}'.tr, Get.find().tokenPassenger, + [], 'tone2.wav'); walletChecked = 'true'; // } diff --git a/lib/main.dart b/lib/main.dart index 37f3565..5b16a68 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:math'; import 'package:SEFER/constant/box_name.dart'; import 'package:SEFER/controller/payment/paymob/paymob_response.dart'; import 'package:SEFER/views/home/Captin/orderCaptin/order_request_page.dart'; @@ -18,6 +19,7 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; import 'constant/api_key.dart'; import 'constant/info.dart'; +import 'constant/notification.dart'; import 'controller/firebase/firbase_messge.dart'; import 'controller/firebase/local_notification.dart'; import 'controller/functions/location_controller.dart'; @@ -58,14 +60,13 @@ Future backgroundMessageHandler(RemoteMessage message) async { Log.print('Error decoding JSON: $e'); myList = []; } - - await Future.delayed(const Duration(seconds: 1)); NotificationController().showNotification( message.notification!.title.toString(), message.notification!.body.toString(), 'order', myListString, ); + await Future.delayed(const Duration(seconds: 1)); bool isOverlayActive = await FlutterOverlayWindow.isActive(); if (isOverlayActive) { @@ -137,9 +138,23 @@ void main() async { FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); // NotificationController1().initNotifications(); // NotificationController().initNotifications(); - if (Platform.isAndroid) { - await Get.put(NotificationController()).initNotifications(); - } + // if (Platform.isAndroid) { + // await Get.put(NotificationController()).initNotifications(); + // } + NotificationController notificationController = + Get.put(NotificationController()); + await notificationController.initNotifications(); + + // Generate a random index to pick a message + final random = Random(); + final randomMessage = driverMessages[random.nextInt(driverMessages.length)]; + + // Schedule the notification with the random message + notificationController.scheduleDailyNotifications( + randomMessage.split(':')[0], + randomMessage.split(':')[1], + "ding", + ); await Future.wait([ FirebaseMessagesController().getNotificationSettings(), diff --git a/lib/views/auth/captin/driver_car_controller.dart b/lib/views/auth/captin/driver_car_controller.dart new file mode 100644 index 0000000..04fad6c --- /dev/null +++ b/lib/views/auth/captin/driver_car_controller.dart @@ -0,0 +1,76 @@ +import 'dart:convert'; + +import 'package:SEFER/constant/box_name.dart'; +import 'package:SEFER/constant/colors.dart'; +import 'package:SEFER/constant/links.dart'; +import 'package:SEFER/controller/functions/crud.dart'; +import 'package:SEFER/main.dart'; +import 'package:get/get.dart'; + +class DriverCarController extends GetxController { + bool isLoading = false; + List cars = []; + int? carId; + fetchCatrsForDrivers() async { + isLoading = true; + update(); + var res = await CRUD().get(link: AppLink.getNewCarsDrivers, payload: { + "driverID": box.read(BoxName.driverID).toString(), + }); + if (res != 'failure') { + var d = jsonDecode(res)['message']; + cars = d; + carId = cars.isEmpty ? 1 : cars.length + 1; + } + isLoading = false; + update(); + } + + addCarsForDrivers( + String vin, + String car_plate, + String make, + String model, + String year, + String expiration_date, + String color, + String color_hex, + String address, + String owner, + String registration_date, + String displacement, + String fuel) async { + var res = await CRUD().post( + link: AppLink.addNewCarsDrivers, + payload: { + "driverID": box.read(BoxName.driverID).toString(), + "vin": vin, + "car_plate": car_plate, + "make": make, + "model": model, + "year": year, + "expiration_date": expiration_date, + "color": color, + "owner": owner, + "color_hex": color_hex, + "address": address, + "displacement": displacement, + "fuel": fuel, + "registration_date": registration_date, + }, + ); + if (res != 'failure') { + Get.snackbar('Success'.tr, '', backgroundColor: AppColor.greenColor); + fetchCatrsForDrivers(); + } else { + Get.snackbar('Error'.tr, '', backgroundColor: AppColor.redColor); + } + } + + removeCar(String car) async {} + @override + void onInit() { + fetchCatrsForDrivers(); + super.onInit(); + } +} diff --git a/lib/views/home/Captin/home_captain/drawer_captain.dart b/lib/views/home/Captin/home_captain/drawer_captain.dart index 7b21e99..ec3acf3 100644 --- a/lib/views/home/Captin/home_captain/drawer_captain.dart +++ b/lib/views/home/Captin/home_captain/drawer_captain.dart @@ -98,7 +98,7 @@ class CupertinoDrawerCaptain extends StatelessWidget { _buildDrawerItem( icon: CupertinoIcons.mail, text: "Contact Us".tr, - onTap: () => Get.to(() => const SettingsCaptain()), + onTap: () => Get.to(() => ContactUsPage()), ), _buildDivider(), _buildDrawerItem( 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 346f368..1a945e7 100644 --- 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 @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:math'; import 'package:SEFER/constant/box_name.dart'; import 'package:SEFER/controller/firebase/local_notification.dart'; @@ -10,8 +11,12 @@ import 'package:get/get.dart'; import 'package:SEFER/controller/home/captin/home_captain_controller.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:timezone/data/latest.dart' as tz; +import 'package:timezone/timezone.dart' as tz; import '../../../../../constant/colors.dart'; +import '../../../../../constant/notification.dart'; import '../../../../../controller/functions/audio_controller.dart'; +import '../../../../../print.dart'; import '../../../../Rate/ride_calculate_driver.dart'; import '../../../../../controller/functions/location_controller.dart'; import '../../driver_map_page.dart'; @@ -180,30 +185,53 @@ GetBuilder leftMainMenuCaptainIcons() { ), // Platform.isAndroid // ? - // AnimatedContainer( - // duration: const Duration(microseconds: 200), - // width: controller.widthMapTypeAndTraffic, - // decoration: BoxDecoration( - // color: AppColor.secondaryColor, - // border: Border.all(color: AppColor.blueColor), - // borderRadius: BorderRadius.circular(15)), - // child: Builder(builder: (context) { - // return IconButton( - // onPressed: () async { - // // NotificationController().showNotification( - // // ' message.notification!.title.toString()', - // // ' message.notification!.body.toString()', - // // 'order', - // // ''); - // }, - // icon: const Icon( - // FontAwesome5.window_close, - // size: 29, - // color: AppColor.blueColor, - // ), - // ); - // }), - // ), + AnimatedContainer( + duration: const Duration(microseconds: 200), + width: controller.widthMapTypeAndTraffic, + decoration: BoxDecoration( + color: AppColor.secondaryColor, + border: Border.all(color: AppColor.blueColor), + borderRadius: BorderRadius.circular(15)), + child: Builder(builder: (context) { + return IconButton( + onPressed: () async { + // NotificationController().showNotification( + // ' message.notification!.title.toString()', + // ' message.notification!.body.toString()', + // 'order', + // ''); + + NotificationController notificationController = + Get.put(NotificationController()); + await notificationController.initNotifications(); + final random = Random(); + final randomMessage = + driverMessages[random.nextInt(driverMessages.length)]; + Log.print( + ' randomMessage.split[0]: ${randomMessage.split(':')[0]}'); + Log.print( + ' randomMessage.split([1]: ${randomMessage.split(':')[1]}'); + // Schedule the notification with the random message + notificationController.showNotification( + randomMessage.split(':')[0], + randomMessage.split(':')[1], + "ding", + ''); + + // notificationController.scheduleNotificationEvery10Hours( + // "افتح التطبيق".tr, + // "افتح التطبيق لتبقى على اطلاع واستعداد للمهام القادمة.".tr, + // "ding", + // ); + }, + icon: const Icon( + FontAwesome5.window_close, + size: 29, + color: AppColor.blueColor, + ), + ); + }), + ), // : const SizedBox(), // AnimatedContainer( // duration: const Duration(microseconds: 200), diff --git a/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart b/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart index 8f45804..4a4cfe2 100644 --- a/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart +++ b/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart @@ -101,12 +101,13 @@ class PassengerInfoWindow extends StatelessWidget { children: [ InkWell( onTap: () { - FirebaseMessagesController().sendNotificationToAnyWithoutData( + FirebaseMessagesController().sendNotificationToDriverMAP( 'message From Driver', "Where are you, sir?" .tr, controller .tokenPassenger, + [], 'ding.wav'); Get.back(); }, @@ -132,12 +133,13 @@ class PassengerInfoWindow extends StatelessWidget { ), InkWell( onTap: () { - FirebaseMessagesController().sendNotificationToAnyWithoutData( + FirebaseMessagesController().sendNotificationToDriverMAP( 'message From Driver', "I've been trying to reach you but your phone is off." .tr, controller .tokenPassenger, + [], 'ding.wav'); Get.back(); }, @@ -163,12 +165,13 @@ class PassengerInfoWindow extends StatelessWidget { ), InkWell( onTap: () { - FirebaseMessagesController().sendNotificationToAnyWithoutData( + FirebaseMessagesController().sendNotificationToDriverMAP( 'message From Driver', "Please don't be late, I'm waiting for you at the specified location." .tr, controller .tokenPassenger, + [], 'ding.wav'); Get.back(); }, @@ -194,13 +197,14 @@ class PassengerInfoWindow extends StatelessWidget { ), InkWell( onTap: () { - FirebaseMessagesController().sendNotificationToAnyWithoutData( + FirebaseMessagesController().sendNotificationToDriverMAP( 'message From Driver', "Please don't be late" .tr, controller .tokenPassenger, - 'ding.wav'); + [], + 'cancel.wav'); Get.back(); }, child: Container( @@ -247,10 +251,11 @@ class PassengerInfoWindow extends StatelessWidget { IconButton( onPressed: () { - FirebaseMessagesController().sendNotificationToAnyWithoutData( - 'message From Driver'.tr, + FirebaseMessagesController().sendNotificationToDriverMAP( + 'message From Driver', controller.messageToPassenger.text, controller.tokenPassenger, + [], 'ding.wav'); controller .messageToPassenger @@ -471,13 +476,13 @@ class PassengerInfoWindow extends StatelessWidget { 140) { // Notify Passenger FirebaseMessagesController() - .sendNotificationToPassengerToken( - 'Hi, I Arrive at your site', + .sendNotificationToDriverMAP( + 'Hi ,I Arrive your site', 'I Arrive at your site' .tr, controller.tokenPassenger, [], - 'start.wav', + 'ding.wav', ); controller .startTimerToShowDriverWaitPassengerDuration(); @@ -553,7 +558,7 @@ class PassengerInfoWindow extends StatelessWidget { 'Are you sure to cancel?'.tr, '', () async { FirebaseMessagesController() - .sendNotificationToPassengerToken( + .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, diff --git a/lib/views/home/Captin/orderCaptin/order_speed_request.dart b/lib/views/home/Captin/orderCaptin/order_speed_request.dart index 8c1da67..4b46d93 100644 --- a/lib/views/home/Captin/orderCaptin/order_speed_request.dart +++ b/lib/views/home/Captin/orderCaptin/order_speed_request.dart @@ -330,7 +330,7 @@ class OrderSpeedRequest extends StatelessWidget { if (AppLink.endPoint != AppLink.seferCairoServer) { CRUD().post( link: - "${AppLink.endPoint}/rides/updateStausFromSpeed.php", + "${AppLink.endPoint}/ride/rides/updateStausFromSpeed.php", payload: { 'id': orderRequestController.myList[16], 'rideTimeStart': DateTime.now().toString(), @@ -364,6 +364,17 @@ class OrderSpeedRequest extends StatelessWidget { box.read(BoxName.nameDriver).toString(), box.read(BoxName.tokenDriver).toString(), ]; + FirebaseMessagesController() + .sendNotificationToPassengerToken( + 'Accepted Ride', + 'your ride is applied'.tr, + // arguments['DriverList'][9].toString(), + orderRequestController + .arguments['DriverList'][9] + .toString(), + // box.read(BoxName.tokenDriver).toString(), + bodyToPassenger, + 'start.wav'); await CRUD().postFromDialogue( link: AppLink.addDriverOrder, payload: { @@ -388,7 +399,7 @@ class OrderSpeedRequest extends StatelessWidget { if (AppLink.endPoint != AppLink.seferCairoServer) { CRUD().post( link: - "${AppLink.endPoint}/driver_order/add.php", + "${AppLink.endPoint}/ride/driver_order/add.php", payload: { 'driver_id': orderRequestController .myList[6] @@ -400,17 +411,7 @@ class OrderSpeedRequest extends StatelessWidget { 'status': 'Apply' }); } - FirebaseMessagesController() - .sendNotificationToPassengerToken( - 'Apply Ride', - 'your ride is applied'.tr, - // arguments['DriverList'][9].toString(), - orderRequestController - .arguments['DriverList'][9] - .toString(), - // box.read(BoxName.tokenDriver).toString(), - bodyToPassenger, - 'start.wav'); + Get.back(); // 'Arguments passed to PassengerLocationMapPage:'); diff --git a/lib/views/home/Captin/orderCaptin/vip_order_page.dart b/lib/views/home/Captin/orderCaptin/vip_order_page.dart index fb268a6..cf1fe8d 100644 --- a/lib/views/home/Captin/orderCaptin/vip_order_page.dart +++ b/lib/views/home/Captin/orderCaptin/vip_order_page.dart @@ -1,16 +1,69 @@ +import 'dart:convert'; + +import 'package:SEFER/constant/box_name.dart'; +import 'package:SEFER/constant/links.dart'; +import 'package:SEFER/controller/functions/crud.dart'; import 'package:SEFER/views/widgets/my_scafold.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import '../../../../main.dart'; + class VipOrderPage extends StatelessWidget { const VipOrderPage({super.key}); @override Widget build(BuildContext context) { + Get.put(VipOrderController()); return MyScafolld( title: 'VIP Order'.tr, - body: [], + body: [ + GetBuilder(builder: (vipOrderController) { + return SafeArea( + child: Column( + children: [], + )); + }) + ], isleading: true, ); } } + +class VipOrderController extends GetxController { + bool isLoading = false; + final arguments = Get.arguments; + late String body; + List tripData = []; + var myList; + + initilize() { + final myListString = arguments['myListString']; + + if (arguments['DriverList'] == null || arguments['DriverList'].isEmpty) { + myList = jsonDecode(myListString); + } else { + myList = arguments['DriverList']; + } + + body = arguments['body']; + update(); + } + + fetchOrder() async { + var res = await CRUD().get(link: AppLink.getMishwari, payload: { + 'driverId': box.read(BoxName.driverID).toString(), + }); + if (res != 'failure') { + tripData = jsonDecode(res)['message']; + update(); + } + } + + @override + void onInit() async { + await initilize(); + fetchOrder(); + super.onInit(); + } +} diff --git a/lib/views/home/profile/captains_cars.dart b/lib/views/home/profile/captains_cars.dart new file mode 100644 index 0000000..01150b4 --- /dev/null +++ b/lib/views/home/profile/captains_cars.dart @@ -0,0 +1,105 @@ +import 'package:SEFER/constant/colors.dart'; +import 'package:SEFER/constant/style.dart'; +import 'package:SEFER/views/widgets/my_scafold.dart'; +import 'package:SEFER/views/widgets/mycircular.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_font_icons/flutter_font_icons.dart'; +import 'package:get/get.dart'; + +import '../../auth/captin/driver_car_controller.dart'; +import '../../widgets/elevated_btn.dart'; +import 'cars_inserting_page.dart'; + +class CaptainsCars extends StatelessWidget { + const CaptainsCars({super.key}); + + @override + Widget build(BuildContext context) { + Get.put(DriverCarController()); + return MyScafolld( + title: "Add new car".tr, + body: [ + Column( + children: [ + MyElevatedButton( + title: "Add new car".tr, + onPressed: () async { + Get.to(() => CarsInsertingPage()); + }, + ), + Expanded( + child: GetBuilder( + builder: (controller) { + return controller.isLoading + ? const MyCircularProgressIndicator() + : ListView.builder( + itemCount: controller.cars.length, + itemBuilder: (context, index) { + final car = controller.cars[index]; + return Padding( + padding: const EdgeInsets.all(4.0), + child: Card( + elevation: 2, + child: ListTile( + leading: Icon( + Fontisto.car, + size: 50, + color: Color(int.parse(car['color_hex'] + .replaceFirst('#', '0xff'))), + ), + title: Text( + car['make'], + style: AppStyle.title, + ), // Assuming `make` is a field in each car item + subtitle: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + car['model'], + style: AppStyle.title, + ), + Container( + decoration: BoxDecoration( + border: Border.all( + color: AppColor.blueColor)), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 4), + child: Text( + car['car_plate'], + style: AppStyle.title, + ), + ), + ), + Text( + car['year'], + style: AppStyle.title, + ), + ], + ), // Assuming `model` is a field in each car item + trailing: IconButton( + icon: const Icon(Icons.delete), + onPressed: () { + // Add logic here to remove a car + controller + .removeCar(car['id'].toString()); + }, + ), + onTap: () { + // Add logic to view or edit the car details + }, + ), + ), + ); + }, + ); + }, + ), + ), + ], + ) + ], + isleading: true); + } +} diff --git a/lib/views/home/profile/cars_inserting_page.dart b/lib/views/home/profile/cars_inserting_page.dart new file mode 100644 index 0000000..2af3b11 --- /dev/null +++ b/lib/views/home/profile/cars_inserting_page.dart @@ -0,0 +1,300 @@ +import 'package:SEFER/splash_screen_page.dart'; +import 'package:SEFER/views/widgets/elevated_btn.dart'; +import 'package:SEFER/views/widgets/my_scafold.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../../constant/colors.dart'; +import '../../../constant/links.dart'; +import '../../../constant/style.dart'; +import '../../../controller/functions/gemeni.dart'; +import '../../auth/captin/driver_car_controller.dart'; + +class CarsInsertingPage extends StatelessWidget { + CarsInsertingPage({super.key}); + final driverCarController = Get.put(DriverCarController()); + @override + Widget build(BuildContext context) { + Get.put(AI()); + return MyScafolld( + title: 'Insert New Car'.tr, + body: [ + Container( + color: AppColor.accentColor.withOpacity(.2), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + egyptCarLicenceFront(), + egyptCarLicenceBack(), + const SizedBox(height: 10), + Text('Please make sure to read the license carefully.'.tr), + Text( + 'If your car license has the new design, upload the front side with two images.' + .tr), + const SizedBox(height: 10), + MyElevatedButton( + title: 'Please upload this license.'.tr, + onPressed: () { + final aiFront = + Get.find().responseIdCardDriverEgyptFront; + final aiBack = + Get.find().responseIdCardDriverEgyptBack; + driverCarController.addCarsForDrivers( + aiBack['vin'].toString(), + aiBack['car_plate'].toString(), + aiBack['make'].toString(), + aiBack['model'].toString(), + aiBack['year'].toString(), + aiFront['expiration_date'].toString(), + aiBack['color'].toString(), + aiBack['color_hex'].toString(), + aiFront['address'].toString(), + aiFront['owner'].toString(), + aiBack['registration_date'].toString(), + aiBack['displacement'].toString(), + aiBack['fuel'].toString(), + ); + }) + ], + ), + ), + ) + ], + isleading: true); + } +} + +GetBuilder egyptCarLicenceFront() { + return GetBuilder( + builder: (ai) { + if (ai.responseIdCardDriverEgyptFront.isNotEmpty) { + // No need to access ai.responseIdCardDriverEgyptBack anymore + final licenseExpiryDate = DateTime.parse( + ai.responseIdCardDriverEgyptFront['LicenseExpirationDate']); + + // Check if license has expired + final today = DateTime.now(); + final isLicenseExpired = licenseExpiryDate.isBefore(today); + + return Card( + elevation: 4.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text('Vehicle Details Front'.tr, + style: AppStyle.headTitle2), + IconButton( + onPressed: () async { + ai.allMethodForAI(ai.prompts[3]['prompt'].toString(), + AppLink.uploadEgypt, 'car_front'); + }, + icon: const Icon(Icons.refresh), + ), + ], + ), + const SizedBox(height: 8.0), + const Divider(color: AppColor.accentColor), + const SizedBox(height: 8.0), + // Removed Make, Model, etc. as they are not available + + Text( + '${'Plate Number'.tr}: ${ai.responseIdCardDriverEgyptFront['car_plate']}', + ), + const SizedBox(height: 8.0), + Text( + '${'Owner Name'.tr}: ${ai.responseIdCardDriverEgyptFront['owner']}', + ), + const SizedBox(height: 8.0), + Text( + '${'Address'.tr}: ${ai.responseIdCardDriverEgyptFront['address']}', + ), + const SizedBox(height: 8.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${'License Expiry Date'.tr}: ${licenseExpiryDate.toString().substring(0, 10)}', + style: TextStyle( + color: isLicenseExpired ? Colors.red : Colors.green, + ), + ), + // Removed Fuel as it's not available + ], + ), + // Removed Inspection Date as it's not available + ], + ), + ), + ); + } + return Card( + child: InkWell( + onTap: () async { + ai.allMethodForAINewCar(ai.prompts[3]['prompt'].toString(), + AppLink.uploadEgypt, 'car_front', 'carId'); //todo + }, + child: Column( + children: [ + Image.asset( + 'assets/images/3.png', + height: Get.height * .25, + width: double.maxFinite, + fit: BoxFit.fitHeight, + ), + Text( + 'Capture an Image of Your car license front '.tr, + style: AppStyle.title, + ), + ], + ), + ), + ); + }, + ); +} + +GetBuilder egyptCarLicenceBack() { + return GetBuilder( + builder: (ai) { + if (ai.responseIdCardDriverEgyptBack.isNotEmpty) { + // Get the tax expiry date from the response + final taxExpiryDate = + ai.responseIdCardDriverEgyptBack['tax_expiry'].toString(); + // final displacement = ai.responseIdCardDriverEgyptBack['displacement']; + // if (int.parse(displacement) < 1000) {} + // Get the inspection date from the response + final inspectionDate = + ai.responseIdCardDriverEgyptBack['inspection_date'].toString(); + final year = int.parse(inspectionDate.toString().split('-')[0]); + +// Set inspectionDateTime to December 31st of the given year + final inspectionDateTime = DateTime(year, 12, 31); + String carBackLicenseExpired = + inspectionDateTime.toString().split(' ')[0]; +// Get the current date + final today = DateTime.now(); + +// Try parsing the tax expiry date. If it fails, set it to null. + final taxExpiryDateTime = DateTime.tryParse(taxExpiryDate ?? ''); + final isExpired = + taxExpiryDateTime != null && taxExpiryDateTime.isBefore(today); +// Check if the inspection date is before today + bool isInspectionExpired = inspectionDateTime.isBefore(today); + + return Card( + elevation: 4.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Vehicle Details Back'.tr, style: AppStyle.headTitle2), + IconButton( + onPressed: () async { + ai.allMethodForAI(ai.prompts[4]['prompt'].toString(), + AppLink.uploadEgypt, 'car_back'); + }, + icon: const Icon(Icons.refresh), + ), + ], + ), + const SizedBox(height: 8.0), + const Divider(color: AppColor.accentColor), + const SizedBox(height: 8.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${'Make'.tr}: ${ai.responseIdCardDriverEgyptBack['make']}'), + Text( + '${'Model'.tr}: ${ai.responseIdCardDriverEgyptBack['model']}'), + ], + ), + const SizedBox(height: 8.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${'Year'.tr}: ${ai.responseIdCardDriverEgyptBack['year']}'), + Text( + '${'Chassis'.tr}: ${ai.responseIdCardDriverEgyptBack['chassis']}'), + ], + ), + const SizedBox(height: 8.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${'Color'.tr}: ${ai.responseIdCardDriverEgyptBack['color']}'), + Text( + '${'Displacement'.tr}: ${ai.responseIdCardDriverEgyptBack['displacement']} cc'), + ], + ), + const SizedBox(height: 8.0), + Text( + '${'Fuel'.tr}: ${ai.responseIdCardDriverEgyptBack['fuel']}'), + const SizedBox(height: 8.0), + if (taxExpiryDateTime != null) + Text( + '${'Tax Expiry Date'.tr}: $taxExpiryDate', + style: TextStyle( + color: isExpired ? Colors.red : Colors.green, + ), + ), + const SizedBox(height: 8.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${'Inspection Date'.tr}: $carBackLicenseExpired', + style: TextStyle( + color: isInspectionExpired ? Colors.red : Colors.green, + ), + ), + ], + ), + ], + ), + ), + ); + } + return Card( + child: InkWell( + onTap: () async { + ai.allMethodForAI(ai.prompts[4]['prompt'].toString(), + AppLink.uploadEgypt, 'car_back'); + }, + child: Column( + children: [ + Image.asset( + 'assets/images/4.png', + height: Get.height * .25, + width: double.maxFinite, + fit: BoxFit.fitHeight, + ), + Text( + 'Capture an Image of Your car license back'.tr, + style: AppStyle.title, + ), + ], + ), + ), + ); + }, + ); +} diff --git a/lib/views/home/profile/profile_captain.dart b/lib/views/home/profile/profile_captain.dart index d65eb71..3409167 100644 --- a/lib/views/home/profile/profile_captain.dart +++ b/lib/views/home/profile/profile_captain.dart @@ -1,5 +1,6 @@ import 'package:SEFER/constant/style.dart'; import 'package:SEFER/controller/home/payment/captain_wallet_controller.dart'; +import 'package:SEFER/views/widgets/elevated_btn.dart'; import 'package:SEFER/views/widgets/mycircular.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -7,6 +8,7 @@ import 'package:SEFER/controller/profile/captain_profile_controller.dart'; import 'package:SEFER/views/widgets/my_scafold.dart'; import '../my_wallet/walet_captain.dart'; +import 'captains_cars.dart'; class ProfileCaptain extends StatelessWidget { ProfileCaptain({super.key}); @@ -41,6 +43,15 @@ class ProfileCaptain extends StatelessWidget { ), ), ), + const SizedBox( + height: 5, + ), + MyElevatedButton( + title: 'Show my Cars'.tr, + onPressed: () async { + Get.to(() => CaptainsCars()); + }, + ), SizedBox( height: Get.height * .8, child: DriverProfileCard(