diff --git a/android/app/build.gradle b/android/app/build.gradle index 15619f0..6c13091 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -148,8 +148,8 @@ android { // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdk = 23 targetSdk = flutter.targetSdkVersion - versionCode = 71 - versionName = '1.5.71' + versionCode = 82 + versionName = '1.5.82' multiDexEnabled =true // manifestPlaceholders can be specified here if needed diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 545d524..65245cb 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,6 +1,7 @@ My App - default_channel + + high_importance_channel AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0 \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index fccf2e6..9c0b524 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -37,11 +37,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 52 + 59 CFBundleSignature ???? CFBundleVersion - 4.3.52 + 4.3.59 + NSHumanReadableCopyright + FirebaseAppDelegateProxyEnabled NO GMSApiKey diff --git a/lib/constant/box_name.dart b/lib/constant/box_name.dart index c6dced8..7db29cd 100644 --- a/lib/constant/box_name.dart +++ b/lib/constant/box_name.dart @@ -10,9 +10,14 @@ class BoxName { static const String carType = "carType"; static const String carPlate = "carPlate"; static const String packagInfo = "packagInfo"; - static const String isVerified = '0'; + static const String isVerified = 'isVerified'; + static const String isFirstTime = 'isFirstTime'; static const String statusDriverLocation = "statusDriverLocation"; + static const String isTest = "isTest"; static const String password = "password"; + static const String validity = "validity"; + static const String promo = "promo"; + static const String discount = "discount"; static const String arrivalTime = "arrivalTime"; static const String passwordDriver = "passwordDriver"; static const String agreeTerms = "agreeTerms"; @@ -25,6 +30,10 @@ class BoxName { static const String sosPhoneDriver = "sosPhoneDriver"; static const String passengerID = "pasengerID"; static const String phone = "phone"; + static const String package = "package"; + static const String isInstall = "isInstall"; + static const String isGiftToken = "isGiftToken"; + static const String inviteCode = "inviteCode"; static const String phoneWallet = "phoneWallet"; static const String phoneDriver = "phoneDriver"; static const String dobDriver = "dobDriver"; diff --git a/lib/constant/links.dart b/lib/constant/links.dart index a06a4c4..f8a36b7 100644 --- a/lib/constant/links.dart +++ b/lib/constant/links.dart @@ -59,21 +59,27 @@ class AppLink { ////=======================cancelRide=================== static String ride = '$server/ride'; static String addCancelRideFromPassenger = - "$endPoint/ride/cancelRide/add.php"; - static String cancelRide = "$endPoint/ride/cancelRide/get.php"; + "${box.read(BoxName.serverChosen)}/ride/cancelRide/add.php"; + static String cancelRide = + "${box.read(BoxName.serverChosen)}/ride/cancelRide/get.php"; //-----------------ridessss------------------ static String addRides = "$ride/rides/add.php"; - static String getRides = "$endPoint/ride/rides/get.php"; - static String getRideOrderID = "$endPoint/ride/rides/getRideOrderID.php"; - static String getRideStatus = "$endPoint/ride/rides/getRideStatus.php"; + static String getRides = + "${box.read(BoxName.serverChosen)}/ride/rides/get.php"; + static String getRideOrderID = + "${box.read(BoxName.serverChosen)}/ride/rides/getRideOrderID.php"; + static String getRideStatus = + "${box.read(BoxName.serverChosen)}/ride/rides/getRideStatus.php"; static String getRideStatusBegin = - "$endPoint/ride/rides/getRideStatusBegin.php"; + "${box.read(BoxName.serverChosen)}/ride/rides/getRideStatusBegin.php"; static String getRideStatusFromStartApp = "$ride/rides/getRideStatusFromStartApp.php"; - static String updateRides = "$endPoint/ride/rides/update.php"; + static String updateRides = + "${box.read(BoxName.serverChosen)}/ride/rides/update.php"; static String updateStausFromSpeed = - "$endPoint/ride/rides/updateStausFromSpeed.php"; - static String deleteRides = "$endPoint/ride/rides/delete.php"; + "${box.read(BoxName.serverChosen)}/ride/rides/updateStausFromSpeed.php"; + static String deleteRides = + "${box.read(BoxName.serverChosen)}/ride/rides/delete.php"; //-----------------DriverPayment------------------ static String adddriverScam = "$ride/driver_scam/add.php"; @@ -105,8 +111,12 @@ class AppLink { "$ride/notificationPassenger/update.php"; //-----------------Driver NotificationCaptain------------------ static String addNotificationCaptain = "$ride/notificationCaptain/add.php"; - static String addWaitingRide = "$ride/notificationCaptain/addWaitingRide.php"; - static String getRideWaiting = "$ride/notificationCaptain/getRideWaiting.php"; + static String addWaitingRide = + "$endPoint/ride/notificationCaptain/addWaitingRide.php"; + static String updateWaitingTrip = + "$endPoint/ride/notificationCaptain/updateWaitingTrip.php"; + static String getRideWaiting = + "$endPoint/ride/notificationCaptain/getRideWaiting.php"; static String getNotificationCaptain = "$ride/notificationCaptain/get.php"; static String updateNotificationCaptain = "$ride/notificationCaptain/update.php"; @@ -142,7 +152,8 @@ class AppLink { static String updateLicense = "$ride/license/updateFeedBack.php"; //-----------------RegisrationCar------------------ static String addRegisrationCar = "$ride/RegisrationCar/add.php"; - static String getRegisrationCar = "$endPoint/ride/RegisrationCar/get.php"; + static String getRegisrationCar = + "${box.read(BoxName.serverChosen)}/ride/RegisrationCar/get.php"; static String selectDriverAndCarForMishwariTrip = "$ride/RegisrationCar/selectDriverAndCarForMishwariTrip.php"; static String updateRegisrationCar = "$ride/RegisrationCar/update.php"; @@ -183,7 +194,7 @@ class AppLink { static String uploadEgypt = "$server/uploadEgypt.php"; //==================certifcate========== - static String location = '$endPoint/ride/location'; + static String location = '${box.read(BoxName.serverChosen)}/ride/location'; static String getCarsLocationByPassenger = "$location/get.php"; static String addpassengerLocation = "$location/addpassengerLocation.php"; static String getCarsLocationByPassengerSpeed = "$location/getSpeed.php"; @@ -241,7 +252,8 @@ class AppLink { static String deletecaptainAccounr = "$authCaptin/deletecaptainAccounr.php"; static String updateAccountBank = "$authCaptin/updateAccountBank.php"; static String getAccount = "$authCaptin/getAccount.php"; - + static String updatePassengersInvitation = + "$server/ride/invitor/updatePassengersInvitation.php"; //===================Admin Captin============ static String getPassengerDetailsByPassengerID = @@ -250,6 +262,7 @@ class AppLink { static String getPassengerbyEmail = "$server/Admin/getPassengerbyEmail.php"; static String addAdminUser = "$server/Admin/adminUser/add.php"; static String getAdminUser = "$server/Admin/adminUser/get.php"; + static String addError = "$server/Admin/errorApp.php"; static String getCaptainDetailsByEmailOrIDOrPhone = "$server/Admin/AdminCaptain/getCaptainDetailsByEmailOrIDOrPhone.php"; static String getCaptainDetails = "$server/Admin/AdminCaptain/get.php"; diff --git a/lib/constant/univeries_polygon.dart b/lib/constant/univeries_polygon.dart new file mode 100644 index 0000000..8358b9f --- /dev/null +++ b/lib/constant/univeries_polygon.dart @@ -0,0 +1,83 @@ +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +class UniversitiesPolygons { + // AUC polygon points + static const List> universityPolygons = [ + // AUC Polygon + [ + LatLng(30.013431, 31.502572), + LatLng(30.018469, 31.497478), + LatLng(30.023158, 31.495870), + LatLng(30.025084, 31.496781), + LatLng(30.018701, 31.511393), + LatLng(30.015312, 31.508310), + ], + // Example polygon for University 'German University in Cairo (GUC)' + [ + LatLng(29.984554, 31.437829), + LatLng(29.990363, 31.438390), + LatLng(29.990560, 31.445643), + LatLng(29.984436, 31.445825), + ], + //Future University in Egypt (FUE) + [ + LatLng(30.025794, 31.490946), + LatLng(30.028341, 31.491014), + LatLng(30.028341, 31.492586), + LatLng(30.025844, 31.492491), + ], + //'British University in Egypt (BUE)' + [ + LatLng(30.117423, 31.605834), + LatLng(30.118224, 31.605543), + LatLng(30.118649, 31.607361), + LatLng(30.118932, 31.608033), + LatLng(30.119592, 31.612159), + LatLng(30.119372, 31.612958), + LatLng(30.120017, 31.617102), + LatLng(30.119435, 31.617193), + ], + //Misr International University (MIU) + [ + LatLng(30.166498, 31.491663), + LatLng(30.171956, 31.491060), + LatLng(30.172212, 31.495754), + LatLng(30.167112, 31.496108), + ], + // Canadian International College (CIC) + [ + LatLng(30.034312, 31.428963), + LatLng(30.035661, 31.429037), + LatLng(30.036074, 31.430522), + LatLng(30.036017, 31.431146), + LatLng(30.034580, 31.431117), + ], + // October 6 University (O6U) + [ + LatLng(29.974102, 30.946934), + LatLng(29.976620, 30.944925), + LatLng(29.979848, 30.949832), + LatLng(29.977372, 30.951950), + ], + [ + LatLng(30.029312, 31.210046), + LatLng(30.027124, 31.201393), + LatLng(30.014523, 31.205087), + LatLng(30.015416, 31.212218), + LatLng(30.027325, 31.210661), + ], + // Add polygons for 8 more universities... + ]; + + static const List universityNames = [ + "American University in Cairo (AUC)", + 'German University in Cairo (GUC)', + 'Future University in Egypt (FUE)', + 'British University in Egypt (BUE)', + 'Misr International University (MIU)', + 'Canadian International College (CIC)', + 'October 6 University (O6U)', + "Cairo University", + // Add names for 8 more universities... + ]; +} diff --git a/lib/controller/auth/google_sign.dart b/lib/controller/auth/google_sign.dart index b46f940..f02d2e6 100644 --- a/lib/controller/auth/google_sign.dart +++ b/lib/controller/auth/google_sign.dart @@ -1,10 +1,17 @@ +import 'dart:io'; + import 'package:SEFER/constant/box_name.dart'; import 'package:SEFER/controller/auth/login_controller.dart'; import 'package:SEFER/main.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:google_sign_in/google_sign_in.dart'; +import 'package:url_launcher/url_launcher.dart'; +import '../../constant/links.dart'; import '../../onbording_page.dart'; +import '../functions/crud.dart'; class GoogleSignInHelper { static final GoogleSignIn _googleSignIn = GoogleSignIn( @@ -32,26 +39,114 @@ class GoogleSignInHelper { } } - static Future signInFromLogin() async { + Future signInFromLogin() async { try { final GoogleSignInAccount? googleUser = await _googleSignIn.signIn(); if (googleUser != null) { await _handleSignUp(googleUser); - // if (box.read(BoxName.countryCode) == 'Egypt') { await Get.put(LoginController()).loginUsingCredentials( box.read(BoxName.passengerID).toString(), box.read(BoxName.email).toString(), ); - // } else if (box.read(BoxName.countryCode) == 'Jordan') { - // // Get.to(() => AiPage()); - // } } return googleUser; } catch (error) { + // if (error is GoogleSignInAuthenticationException) { + // // Handle authentication errors from Google Sign-In + // addError("Google sign-in authentication error: ${error.message}", + // ' signInFromLogin()'); + // } else if (error is GoogleSignInAccountNotFoundException) { + // // Handle the case where the user is not found (if applicable) + // addError("Google sign-in account not found error: ${error.message}", + // ' signInFromLogin()'); + // } + // else + if (error is SocketException) { + // Handle network issues, like SSL certificate issues + addError("Network error (SSL certificate issue): ${error.message}", + ' signInFromLogin()'); + } else if (error is PlatformException) { + // Handle platform-specific errors, like Google Play Services issues + if (error.code == 'sign_in_required') { + // Google Play Services are required but not installed or outdated + showGooglePlayServicesError(); + } else { + addError("Platform error: ${error.message}", + ' signInFromLogin()'); + } + } else { + // Catch all other unknown errors + addError("Unknown error: ${error.toString()}", + ' signInFromLogin()'); + } return null; } } + void showGooglePlayServicesError() async { + const playStoreUrl = + 'https://play.google.com/store/apps/details?id=com.google.android.gms&hl=en_US'; + + if (await canLaunchUrl(Uri.parse(playStoreUrl))) { + await launchUrl(Uri.parse(playStoreUrl)); + } else { + // Fallback if the URL can't be opened + showDialog( + context: Get.context!, + builder: (BuildContext context) { + return AlertDialog( + title: Text('Error'.tr), + content: Text( + 'Could not open the Google Play Store. Please update Google Play Services manually.' + .tr), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('Close'.tr), + ), + ], + ); + }, + ); + } + } + + // Future signInFromLogin() async { + // try { + // final GoogleSignInAccount? googleUser = await _googleSignIn.signIn(); + // if (googleUser != null) { + // await _handleSignUp(googleUser); + // // if (box.read(BoxName.countryCode) == 'Egypt') { + // await Get.put(LoginController()).loginUsingCredentials( + // box.read(BoxName.passengerID).toString(), + // box.read(BoxName.email).toString(), + // ); + // // } else if (box.read(BoxName.countryCode) == 'Jordan') { + // // // Get.to(() => AiPage()); + // // } + // } + // return googleUser; + // } catch (error) { + // addError(error.toString(), ' signInFromLogin()'); + // return null; + // } + // } + + addError(String error, where) async { + CRUD().post(link: AppLink.addError, payload: { + 'error': error.toString(), // Example error description + 'userId': box.read(BoxName.driverID) ?? + box.read(BoxName.passengerID), // Example user ID + 'userType': box.read(BoxName.driverID) != null + ? 'Driver' + : 'passenger', // Example user type + 'phone': box.read(BoxName.phone) ?? + box.read(BoxName.phoneDriver), // Example phone number + + 'device': where + }); + } + // Method to handle Google Sign-Out static Future signOut() async { try { diff --git a/lib/controller/auth/login_controller.dart b/lib/controller/auth/login_controller.dart index b74a538..20aa194 100644 --- a/lib/controller/auth/login_controller.dart +++ b/lib/controller/auth/login_controller.dart @@ -1,9 +1,11 @@ import 'dart:convert'; +import 'dart:io'; import 'package:SEFER/constant/info.dart'; import 'package:SEFER/controller/firebase/firbase_messge.dart'; import 'package:SEFER/views/auth/login_page.dart'; import 'package:SEFER/views/auth/sms_verfy_page.dart'; +import 'package:SEFER/views/widgets/my_dialog.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:SEFER/constant/box_name.dart'; @@ -13,6 +15,8 @@ import 'package:SEFER/main.dart'; import 'package:SEFER/views/home/map_page_passenger.dart'; import 'package:location/location.dart'; +import '../functions/package_info.dart'; + class LoginController extends GetxController { final formKey = GlobalKey(); final formKeyAdmin = GlobalKey(); @@ -29,9 +33,20 @@ class LoginController extends GetxController { update(); } - getAppTester(String appPlatform) async { - var res = await CRUD() - .get(link: AppLink.getTesterApp, payload: {'appPlatform': appPlatform}); + @override + void onInit() async { + box.read(BoxName.isTest) == null || + box.read(BoxName.isTest).toString() == '0' + ? await getAppTester() + : null; + + super.onInit(); + } + + getAppTester() async { + var res = await CRUD().get( + link: AppLink.getTesterApp, + payload: {'appPlatform': AppInformation.appName}); if (res != 'failure') { var d = jsonDecode(res); @@ -64,6 +79,8 @@ class LoginController extends GetxController { await CRUD().get(link: AppLink.loginFromGooglePassenger, payload: { 'email': email, 'id': passengerID, + "platform": Platform.isAndroid ? 'android' : 'ios', + "appName": AppInformation.appName, }); if (res == 'Failure') { Get.offAll(SmsSignupEgypt()); @@ -79,6 +96,17 @@ class LoginController extends GetxController { box.write(BoxName.isVerified, '1'); box.write(BoxName.email, jsonDecoeded['data'][0]['email']); box.write(BoxName.phone, jsonDecoeded['data'][0]['phone']); + box.write(BoxName.isTest, '1'); + box.write(BoxName.package, jsonDecoeded['data'][0]['package']); + box.write(BoxName.promo, jsonDecoeded['data'][0]['promo']); + box.write(BoxName.discount, jsonDecoeded['data'][0]['discount']); + box.write(BoxName.validity, jsonDecoeded['data'][0]['validity']); + box.write(BoxName.isInstall, + jsonDecoeded['data'][0]['isInstall'] ?? 'none'); + box.write(BoxName.isGiftToken, + jsonDecoeded['data'][0]['isGiftToken'] ?? 'none'); + box.write(BoxName.inviteCode, + jsonDecoeded['data'][0]['inviteCode'] ?? 'none'); var token = await CRUD().get(link: AppLink.getTokens, payload: { 'passengerID': box.read(BoxName.passengerID).toString() @@ -94,10 +122,25 @@ class LoginController extends GetxController { 'cancel.wav', ); Future.delayed(const Duration(seconds: 1)); - await CRUD().post(link: AppLink.addTokens, payload: { - 'token': box.read(BoxName.tokenFCM), - 'passengerID': box.read(BoxName.passengerID).toString() - }); + await CRUD().post( + link: "${AppLink.server}/ride/firebase/add.php", + payload: { + 'token': box.read(BoxName.tokenFCM), + 'passengerID': box.read(BoxName.passengerID).toString() + }); + CRUD().post( + link: + "${AppLink.seferAlexandriaServer}/ride/firebase/add.php", + payload: { + 'token': box.read(BoxName.tokenFCM), + 'passengerID': box.read(BoxName.passengerID).toString() + }); + CRUD().post( + link: "${AppLink.seferGizaServer}/ride/firebase/add.php", + payload: { + 'token': box.read(BoxName.tokenFCM), + 'passengerID': box.read(BoxName.passengerID).toString() + }); Get.defaultDialog( title: 'Device Change Detected'.tr, middleText: @@ -111,8 +154,31 @@ class LoginController extends GetxController { }, ); } + } // Logging to check if inviteCode is written correctly + print("Invite Code in Box: ${box.read(BoxName.inviteCode)}"); + print("Is Install: ${box.read(BoxName.isInstall)}"); + + if (box.read(BoxName.inviteCode).toString() != 'none' && + box.read(BoxName.isInstall).toString() != '1') { + await CRUD() + .post(link: AppLink.updatePassengersInvitation, payload: { + "inviteCode": box.read(BoxName.inviteCode).toString(), + "passengerID": box.read(BoxName.passengerID).toString(), + }); + Get.defaultDialog( + title: 'Invitation Used' + .tr, // Automatically translates based on the current locale + middleText: "Your invite code was successfully applied!" + .tr, // Automatically translates based on the current locale + onConfirm: () { + Get.offAll(() => + const MapPagePassenger()); // Navigate to MapPagePassenger after confirmation + }, + textConfirm: "OK".tr, // Confirm button text + ); + } else { + Get.offAll(() => const MapPagePassenger()); } - Get.offAll(() => const MapPagePassenger()); } else { Get.offAll(() => SmsSignupEgypt()); // Get.snackbar(jsonDecoeded['status'], jsonDecoeded['data'], @@ -241,15 +307,4 @@ class LoginController extends GetxController { } update(); } - - @override - void onInit() async { - // permissionLocation = await Permission.locationWhenInUse.isGranted; - await getAppTester(AppInformation.appName); - // if (isTest == 0 && box.read(BoxName.passengerID) != null) { - // await loginUsingCredentials( - // box.read(BoxName.passengerID), box.read(BoxName.email)); - // } - super.onInit(); - } } diff --git a/lib/controller/auth/register_controller.dart b/lib/controller/auth/register_controller.dart index 7ff0d90..cb03dcc 100644 --- a/lib/controller/auth/register_controller.dart +++ b/lib/controller/auth/register_controller.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:math'; import 'package:SEFER/constant/colors.dart'; +import 'package:SEFER/controller/auth/login_controller.dart'; import 'package:SEFER/controller/local/phone_intel/phone_number.dart'; import 'package:SEFER/views/home/map_page_passenger.dart'; import 'package:SEFER/views/widgets/my_dialog.dart'; @@ -214,6 +215,8 @@ class RegisterController extends GetxController { await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: { 'phone_number': phoneNumber, 'token': otp.toString(), + // 'urlImage': box.read(BoxName.passengerPhotoUrl), + // 'name': box.read(BoxName.name), }); await controller.sendSmsEgypt(phoneNumber, otp.toString()); @@ -257,7 +260,7 @@ class RegisterController extends GetxController { 'password': 'unknown', 'gender': 'unknown', 'birthdate': '2002-01-01', - 'site': 'unknown', + 'site': box.read(BoxName.passengerPhotoUrl) ?? 'unknown', 'first_name': box.read(BoxName.name).toString().split(' ')[0], 'last_name': box.read(BoxName.name).toString().split(' ')[1], }; @@ -276,8 +279,13 @@ class RegisterController extends GetxController { payload: payload, ); box.write(BoxName.isVerified, '1'); + box.write(BoxName.isFirstTime, '0'); box.write(BoxName.phone, phoneController.text); - Get.offAll(const MapPagePassenger()); + // Get.offAll(const MapPagePassenger()); + Get.put(LoginController()).loginUsingCredentials( + box.read(BoxName.passengerID).toString(), + box.read(BoxName.email).toString(), + ); } } else { Get.snackbar( diff --git a/lib/controller/firebase/firbase_messge.dart b/lib/controller/firebase/firbase_messge.dart index ebaba41..60ec7e2 100644 --- a/lib/controller/firebase/firbase_messge.dart +++ b/lib/controller/firebase/firbase_messge.dart @@ -1,12 +1,8 @@ import 'dart:convert'; import 'dart:io'; -import 'package:SEFER/env/env.dart'; -import 'package:SEFER/views/widgets/my_dialog.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:googleapis_auth/auth_io.dart'; -import 'package:googleapis_auth/googleapis_auth.dart'; import 'package:http/http.dart' as http; import 'package:SEFER/controller/functions/toast.dart'; import 'package:SEFER/views/widgets/elevated_btn.dart'; @@ -131,16 +127,22 @@ class FirebaseMessagesController extends GetxController { Get.find().statusRide == 'Apply'; Get.find().isSearchingWindow == false; Get.find().update(); - NotificationController().showNotification( - 'Apply Order'.tr, 'Driver Applied the Ride for You'.tr, 'order1'); + if (Platform.isAndroid) { + NotificationController().showNotification( + 'Apply Order'.tr, 'Driver Applied the Ride for You'.tr, 'order1'); + } // driverAppliedTripSnakBar(); } else if (message.notification!.title! == 'Promo'.tr) { - NotificationController() - .showNotification('Promo', 'Show latest promo'.tr, 'promo'); + if (Platform.isAndroid) { + NotificationController() + .showNotification('Promo', 'Show latest promo'.tr, 'promo'); + } Get.to(const PromosPassengerPage()); } else if (message.notification!.title! == 'Trip Monitoring'.tr) { - NotificationController() - .showNotification('Trip Monitoring'.tr, '', 'iphone_ringtone'); + if (Platform.isAndroid) { + NotificationController() + .showNotification('Trip Monitoring'.tr, '', 'iphone_ringtone'); + } var myListString = message.data['passengerList']; var myList = jsonDecode(myListString) as List; Get.toNamed('/tripmonitor', arguments: { @@ -148,46 +150,59 @@ class FirebaseMessagesController extends GetxController { 'driverId': myList[1].toString(), }); } else if (message.notification!.title! == 'token change'.tr) { - NotificationController() - .showNotification('token change'.tr, 'token change'.tr, 'cancel'); + if (Platform.isAndroid) { + NotificationController() + .showNotification('token change'.tr, 'token change'.tr, 'cancel'); + } GoogleSignInHelper.signOut(); } else if (message.notification!.title! == 'DriverIsGoingToPassenger'.tr) { Get.find().isDriverInPassengerWay = true; Get.find().update(); - NotificationController().showNotification('Driver is Going To You'.tr, - 'Please stay on the picked point.'.tr, 'tone1'); + if (Platform.isAndroid) { + NotificationController().showNotification('Driver is Going To You'.tr, + 'Please stay on the picked point.'.tr, 'tone1'); + } // Get.snackbar('Driver is Going To Passenger', '', // backgroundColor: AppColor.greenColor); } else if (message.notification!.title! == 'message From passenger') { - NotificationController() - .showNotification('message From passenger'.tr, ''.tr, 'tone2'); + if (Platform.isAndroid) { + NotificationController() + .showNotification('message From passenger'.tr, ''.tr, 'tone2'); + } passengerDialog(message.notification!.body!); update(); } else if (message.notification!.title! == 'message From Driver') { - NotificationController() - .showNotification('message From passenger'.tr, ''.tr, 'tone2'); passengerDialog(message.notification!.body!); + if (Platform.isAndroid) { + NotificationController() + .showNotification('message From passenger'.tr, ''.tr, 'tone2'); + } update(); } else if (message.notification!.title! == 'RideIsBegin'.tr) { Get.find().getBeginRideFromDriver(); // Get.snackbar('RideIsBegin', '', backgroundColor: AppColor.greenColor); box.write(BoxName.passengerWalletTotal, '0'); - NotificationController() - .showNotification('Trip is Begin'.tr, ''.tr, 'start'); update(); + if (Platform.isAndroid) { + NotificationController() + .showNotification('Trip is Begin'.tr, ''.tr, 'start'); + } } else if (message.notification!.title! == 'Hi ,I will go now'.tr) { // Get.snackbar('Hi ,I will go now', '', // backgroundColor: AppColor.greenColor); - NotificationController().showNotification( - 'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'tone2'); + if (Platform.isAndroid) { + NotificationController().showNotification( + 'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'tone2'); + } update(); } else if (message.notification!.title! == 'Hi ,I Arrive your site'.tr) { - NotificationController() - .showNotification('Hi ,I Arrive your site'.tr, ''.tr, 'tone2'); driverArrivePassengerDialoge(); - + if (Platform.isAndroid) { + NotificationController() + .showNotification('Hi ,I Arrive your site'.tr, ''.tr, 'tone2'); + } update(); } else if (message.notification!.title! == "Cancel Trip from driver".tr) { Get.back(); @@ -214,10 +229,12 @@ class FirebaseMessagesController extends GetxController { } else if (message.notification!.title! == 'Driver Finish Trip'.tr) { var myListString = message.data['passengerList']; var driverList = jsonDecode(myListString) as List; - NotificationController().showNotification( - 'Driver Finish Trip'.tr, - 'you will pay to Driver'.tr + ' ${driverList[3].toString()} \$'.tr, - 'tone1'); + if (Platform.isAndroid) { + NotificationController().showNotification( + 'Driver Finish Trip'.tr, + 'you will pay to Driver'.tr + ' ${driverList[3].toString()} \$'.tr, + 'tone1'); + } Get.find().stopRecording(); if (double.parse(box.read(BoxName.passengerWalletTotal)) < 0) { box.write(BoxName.passengerWalletTotal, 0); @@ -249,11 +266,13 @@ class FirebaseMessagesController extends GetxController { var myListString = message.data['passengerList']; var driverList = jsonDecode(myListString) as List; // if (Platform.isAndroid) { - NotificationController().showNotification( - 'Call Income'.tr, - message.notification!.body!, - 'iphone_ringtone', - ); + 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( @@ -267,12 +286,13 @@ class FirebaseMessagesController extends GetxController { var myListString = message.data['passengerList']; var driverList = jsonDecode(myListString) as List; // if (Platform.isAndroid) { - NotificationController().showNotification( - 'Call Income'.tr, - message.notification!.body!, - 'iphone_ringtone', - ); - // } + 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(), @@ -325,11 +345,13 @@ class FirebaseMessagesController extends GetxController { // } else if (message.notification!.title! == 'Order Applied'.tr) { - NotificationController().showNotification( - 'The order Accepted by another Driver'.tr, - 'We regret to inform you that another driver has accepted this order.' - .tr, - 'order'); + 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'); + } } } @@ -645,7 +667,7 @@ class FirebaseMessagesController extends GetxController { if (response.statusCode == 200) { print( 'Notification sent successfully. Status code: ${response.statusCode}'); - print('Response body: ${response.body}'); + print('Response token: ${token}'); } else { print( 'Failed to send notification. Status code: ${response.statusCode}'); @@ -696,8 +718,9 @@ class FirebaseMessagesController extends GetxController { // } // } - Future sendNotificationToDriverMAP(String title, String body, - String token, List data, String tone) async { + Future sendNotificationToDriverMAP( + String title, String body, String token, List data, String tone, + {int retryCount = 2}) async { try { String serviceAccountKeyJson = '''{ "type": "service_account", @@ -719,7 +742,7 @@ class FirebaseMessagesController extends GetxController { // Obtain an OAuth 2.0 access token final accessToken = await accessTokenManager.getAccessToken(); - Log.print('accessToken: ${accessToken}'); + // Log.print('accessToken: ${accessToken}'); // Send the notification final response = await http.post( @@ -762,14 +785,28 @@ class FirebaseMessagesController extends GetxController { if (response.statusCode == 200) { print( 'Notification sent successfully. Status code: ${response.statusCode}'); - print('Response body: ${response.body}'); + 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); + } } } diff --git a/lib/controller/firebase/local_notification.dart b/lib/controller/firebase/local_notification.dart index d98b6db..5fc0484 100644 --- a/lib/controller/firebase/local_notification.dart +++ b/lib/controller/firebase/local_notification.dart @@ -17,7 +17,7 @@ class NotificationController extends GetxController { // Displays a notification with the given title and message void showNotification(String title, String message, String tone) async { AndroidNotificationDetails android = AndroidNotificationDetails( - 'your channel id', 'your channel name', + 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, priority: Priority.high, showWhen: false, diff --git a/lib/controller/functions/crud.dart b/lib/controller/functions/crud.dart index c642116..1525659 100644 --- a/lib/controller/functions/crud.dart +++ b/lib/controller/functions/crud.dart @@ -109,7 +109,7 @@ class CRUD { print(await response.stream.bytesToString()); Get.defaultDialog( title: 'You will receive a code in WhatsApp Messenger'.tr, - middleText: '', + middleText: 'wait 1 minute to recive message'.tr, confirm: MyElevatedButton( title: 'OK'.tr, onPressed: () { diff --git a/lib/controller/functions/package_info.dart b/lib/controller/functions/package_info.dart index ca4933b..bfcef9c 100644 --- a/lib/controller/functions/package_info.dart +++ b/lib/controller/functions/package_info.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:SEFER/constant/links.dart'; import 'package:SEFER/controller/functions/crud.dart'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -17,7 +16,7 @@ Future checkForUpdate(BuildContext context) async { final version = packageInfo.version; print('currentVersion is : $currentVersion'); // Fetch the latest version from your server - String latestVersion = await getPackageInfo(); + String latestVersion = box.read(BoxName.package); box.write(BoxName.packagInfo, version); if (latestVersion.isNotEmpty && latestVersion != currentVersion) { @@ -25,18 +24,22 @@ Future checkForUpdate(BuildContext context) async { } } -Future getPackageInfo() async { - final response = await CRUD().get(link: AppLink.packageInfo, payload: { - "platform": Platform.isAndroid ? 'android' : 'ios', - "appName": AppInformation.appName, - }); - - if (response != 'failure') { - return jsonDecode(response)['message'][0]['version']; - } - return ''; +checkForBounusInvitation() { + if (box.read(BoxName.inviteCode) != null) {} } +// Future getPackageInfo() async { +// final response = await CRUD().get(link: AppLink.packageInfo, payload: { +// "platform": Platform.isAndroid ? 'android' : 'ios', +// "appName": AppInformation.appName, +// }); + +// if (response != 'failure') { +// return jsonDecode(response)['message'][0]['version']; +// } +// return ''; +// } + void showUpdateDialog(BuildContext context) { final String storeUrl = Platform.isAndroid ? 'https://play.google.com/store/apps/details?id=com.mobileapp.store.ride' diff --git a/lib/controller/home/blinking_promo_controller.dart.dart b/lib/controller/home/blinking_promo_controller.dart.dart new file mode 100644 index 0000000..df0bc82 --- /dev/null +++ b/lib/controller/home/blinking_promo_controller.dart.dart @@ -0,0 +1,91 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../constant/links.dart'; +import '../../views/widgets/elevated_btn.dart'; +import '../functions/crud.dart'; + +class BlinkingController extends GetxController { + final promoFormKey = GlobalKey(); + + final promo = TextEditingController(); + bool promoTaken = false; + void applyPromoCodeToPassenger() async { + //TAWJIHI + if (promoFormKey.currentState!.validate()) { + CRUD().get(link: AppLink.getPassengersPromo, payload: { + 'promo_code': promo.text, + }).then((value) { + if (value == 'failure') { + Get.defaultDialog( + title: 'Promo End !'.tr, + confirm: MyElevatedButton( + title: 'Back', + onPressed: () { + Get.back(); + Get.back(); + }, + )); + } + var decode = jsonDecode(value); + + // if (decode["status"] == "success") { + // var firstElement = decode["message"][0]; + // if (double.parse(box.read(BoxName.passengerWalletTotal)) < 0) { + // totalPassenger = totalCostPassenger - + // (totalCostPassenger * int.parse(firstElement['amount']) / 100); + // update(); + // } else { + // totalPassenger = totalCostPassenger - + // (totalCostPassenger * int.parse(firstElement['amount']) / 100); + // update(); + // } + + // totalDriver = totalDriver - + // (totalDriver * int.parse(firstElement['amount']) / 100); + // promoTaken = true; + // update(); + // Get.back(); + // } + }); + } + } + + // Reactive variable for blinking (on/off) + var isLightOn = false.obs; + + // To animate the border color + var borderColor = Colors.black.obs; + + Timer? _blinkingTimer; + + // Method to start blinking for 5 seconds + void startBlinking() { + int count = 0; + + _blinkingTimer = Timer.periodic(const Duration(seconds: 1), (timer) { + // Toggle light on/off + isLightOn.value = !isLightOn.value; + borderColor.value = isLightOn.value + ? Colors.yellow + : Colors.black; // Animate border color + + count++; + + // Stop blinking after 5 seconds + if (count >= 35) { + timer.cancel(); + isLightOn.value = false; // Ensure light turns off + borderColor.value = Colors.black; // Reset the border color + } + }); + } + + @override + void onClose() { + _blinkingTimer?.cancel(); + super.onClose(); + } +} diff --git a/lib/controller/home/contact_us_controller.dart b/lib/controller/home/contact_us_controller.dart new file mode 100644 index 0000000..afc879f --- /dev/null +++ b/lib/controller/home/contact_us_controller.dart @@ -0,0 +1,78 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_font_icons/flutter_font_icons.dart'; +import 'package:get/get.dart'; + +import '../../../constant/colors.dart'; +import '../functions/launch.dart'; + +class ContactUsController extends GetxController { + final String phone1 = '+201018805430'; + final String phone2 = '+201080182934'; + final TimeOfDay workStartTime = const TimeOfDay(hour: 12, minute: 0); + final TimeOfDay workEndTime = const TimeOfDay(hour: 19, minute: 0); + + bool _isWithinWorkTime(TimeOfDay now) { + return (now.hour > workStartTime.hour || + (now.hour == workStartTime.hour && + now.minute >= workStartTime.minute)) && + (now.hour < workEndTime.hour || + (now.hour == workEndTime.hour && now.minute <= workEndTime.minute)); + } + + void showContactDialog(BuildContext context) { + TimeOfDay now = TimeOfDay.now(); + + showCupertinoModalPopup( + context: context, + builder: (context) => CupertinoActionSheet( + title: Text('Contact Us'.tr), + message: Text('Choose a contact option'.tr), + actions: [ + if (_isWithinWorkTime(now)) + CupertinoActionSheetAction( + child: Text(phone1), + onPressed: () => makePhoneCall( + phone1, + ), + ), + if (_isWithinWorkTime(now)) + CupertinoActionSheetAction( + child: Text(phone2), + onPressed: () => makePhoneCall(phone2), + ), + if (!_isWithinWorkTime(now)) + CupertinoActionSheetAction( + child: Text( + 'Work time is from 12:00 - 19:00.\nYou can send a WhatsApp message or email.' + .tr), + onPressed: () => Navigator.pop(context), + ), + CupertinoActionSheetAction( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + const Icon( + FontAwesome.whatsapp, + color: AppColor.greenColor, + ), + Text('Send WhatsApp Message'.tr), + ], + ), + onPressed: () => + launchCommunication('whatsapp', phone1, 'Hello'.tr), + ), + CupertinoActionSheetAction( + child: Text('Send Email'.tr), + onPressed: () => + launchCommunication('email', 'support@sefer.live', 'Hello'.tr), + ), + ], + cancelButton: CupertinoActionSheetAction( + child: Text('Cancel'.tr), + onPressed: () => Navigator.pop(context), + ), + ), + ); + } +} diff --git a/lib/controller/home/map_passenger_controller.dart b/lib/controller/home/map_passenger_controller.dart index ae93a0c..35a3da5 100644 --- a/lib/controller/home/map_passenger_controller.dart +++ b/lib/controller/home/map_passenger_controller.dart @@ -2,6 +2,8 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math' show Random, cos, pi, pow, sin, sqrt; import 'dart:math' as math; +import 'package:SEFER/constant/univeries_polygon.dart'; +import 'package:flutter_confetti/flutter_confetti.dart'; import 'package:vector_math/vector_math.dart' show radians, degrees; import 'package:SEFER/controller/functions/tts.dart'; @@ -26,6 +28,7 @@ import '../../constant/links.dart'; import '../../constant/table_names.dart'; import '../../main.dart'; import '../../models/model/locations.dart'; +import '../../models/model/painter_copoun.dart'; import '../../print.dart'; import '../../views/home/map_widget.dart/car_details_widget_to_go.dart'; import '../../views/home/map_widget.dart/select_driver_mishwari.dart'; @@ -51,6 +54,7 @@ class MapPassengerController extends GetxController { TextEditingController whatsAppLocationText = TextEditingController(); TextEditingController messageToDriver = TextEditingController(); final sosFormKey = GlobalKey(); + final promoFormKey = GlobalKey(); final messagesFormKey = GlobalKey(); final increaseFeeFormKey = GlobalKey(); List data = []; @@ -362,9 +366,15 @@ class MapPassengerController extends GetxController { "id": rideId.toString(), // Convert to String "status": 'waiting' }); + CRUD().post(link: AppLink.updateWaitingTrip, payload: { + "id": rideId.toString(), // Convert to String + "status": 'wait' + }); tick = 0; } - confirmRideForAllDriverAvailable(); + await getCarForFirstConfirm(box.read(BoxName.carType)); + // confirmRideForAllDriverAvailable(); + icreaseForSameRideAndDelay(); } } } @@ -734,7 +744,7 @@ class MapPassengerController extends GetxController { if (res != 'failure') { var decode = jsonDecode(res); - if (decode['data']['status'] == 'Begin') { + if (decode['data']['status'] != 'Apply') { timeToPassengerFromDriverAfterApplied = 0; remainingTime = 0; remainingTimeToPassengerFromDriverAfterApplied = 0; @@ -747,7 +757,7 @@ class MapPassengerController extends GetxController { // isCancelRidePageShown = true; rideIsBeginPassengerTimer(); runWhenRideIsBegin(); - } + } else {} } } catch (e) { // Handle the error or perform any necessary actions @@ -921,7 +931,7 @@ class MapPassengerController extends GetxController { // Extract the URL part from the link by finding the first occurrence of "http" int urlStartIndex = link.indexOf(RegExp(r'https?://')); if (urlStartIndex == -1) { - throw FormatException('No URL found in the provided link.'); + throw const FormatException('No URL found in the provided link.'); } // Extract the URL and clean it @@ -1016,44 +1026,69 @@ class MapPassengerController extends GetxController { late String model = ''; late String make = ''; late String licensePlate = ''; + confirmRideForFirstDriver() async { // startCarLocationSearch(box.read(BoxName.carType)); // await getCarsLocationByPassengerAndReloadMarker( - // box.read(BoxName.carType), 7000); - // await getNearestDriverByPassengerLocationAPIGOOGLE(); - Log.print('dataCarsLocationByPassenger: ${dataCarsLocationByPassenger}'); + // box.read(BoxName.carType), 7000); + // var nearestCar = await getNearestDriverByPassengerLocation(); + + // if (nearestCar != null) { + // // Find the corresponding driver data in dataCarsLocationByPassenger + // var nearestDriverData = dataCarsLocationByPassenger['message'].firstWhere( + // (car) => car['driver_id'] == nearestCar.id, + // orElse: () => null, + // ); + + // // if (nearestDriverData != null) { + // driverToken = nearestDriverData['token'].toString(); + // Log.print('driverToken: ${driverToken}'); + // driverPhone = nearestDriverData['phone'].toString(); + // firstName = nearestDriverData['first_name'].toString(); + // carColor = nearestDriverData['color'].toString(); + // driverRate = nearestDriverData['ratingDriver'].toString(); + // carYear = nearestDriverData['year'].toString(); + // model = '${nearestDriverData['model']} - ${nearestDriverData['make']}'; + // licensePlate = nearestDriverData['car_plate'].toString(); + // startCarLocationSearch(box.read(BoxName.carType)); + await getCarsLocationByPassengerAndReloadMarker( + box.read(BoxName.carType), 4500); + // await getCarsLocationByPassengerAndReloadMarker( + // box.read(BoxName.carType), 7000); + // await getNearestDriverByPassengerLocation(); + Log.print('dataCarsLocationByPassenger: $dataCarsLocationByPassenger'); if (dataCarsLocationByPassenger != 'failure' || dataCarsLocationByPassenger != null) { driverToken = - dataCarsLocationByPassenger['message'][carsOrder]['token'].toString(); + dataCarsLocationByPassenger['data'][carsOrder]['token'].toString(); driverPhone = - dataCarsLocationByPassenger['message'][carsOrder]['phone'].toString(); - firstName = dataCarsLocationByPassenger['message'][carsOrder] + dataCarsLocationByPassenger['data'][carsOrder]['phone'].toString(); + firstName = dataCarsLocationByPassenger['data'][carsOrder] ['first_name'] // driverName .toString(); carColor = - dataCarsLocationByPassenger['message'][carsOrder]['color'].toString(); - driverRate = dataCarsLocationByPassenger['message'][carsOrder] + dataCarsLocationByPassenger['data'][carsOrder]['color'].toString(); + driverRate = dataCarsLocationByPassenger['data'][carsOrder] ['ratingDriver'] .toString(); carYear = - dataCarsLocationByPassenger['message'][carsOrder]['year'].toString(); + dataCarsLocationByPassenger['data'][carsOrder]['year'].toString(); model = - '${dataCarsLocationByPassenger['message'][carsOrder]['model']} - ${dataCarsLocationByPassenger['message'][carsOrder]['make']}'; - licensePlate = dataCarsLocationByPassenger['message'][carsOrder] - ['car_plate'] + '${dataCarsLocationByPassenger['data'][carsOrder]['model']} - ${dataCarsLocationByPassenger['data'][carsOrder]['make']}'; + licensePlate = dataCarsLocationByPassenger['data'][carsOrder]['car_plate'] .toString(); - PaymentController paymentController = Get.find(); rideConfirm = true; shouldFetch = true; isBottomSheetShown = false; + // timeToPassengerFromDriverAfterApplied = nearestCar.duration.toInt(); timeToPassengerFromDriverAfterApplied = durationToPassenger; //60 todo durationToPassenger;/ isDriversTokensSend = false; update(); - await CRUD().post(link: AppLink.addRides, payload: { + await CRUD() + .post(link: "${AppLink.endPoint}/ride/rides/add.php", payload: { "start_location": //'${data[0]['start_address']}', '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', "end_location": //'${data[0]['end_address']}', @@ -1063,8 +1098,7 @@ class MapPassengerController extends GetxController { "endtime": durationToAdd.toString(), "price": totalPassenger.toStringAsFixed(2), "passenger_id": box.read(BoxName.passengerID).toString(), - "driver_id": dataCarsLocationByPassenger['message'][carsOrder] - ['driver_id'] + "driver_id": dataCarsLocationByPassenger['data'][carsOrder]['driver_id'] .toString(), "status": "waiting", 'carType': box.read(BoxName.carType), @@ -1082,7 +1116,7 @@ class MapPassengerController extends GetxController { totalDriver.toStringAsFixed(2), durationToRide.toString(), distance.toStringAsFixed(2), - dataCarsLocationByPassenger['message'][carsOrder]['driver_id'] + dataCarsLocationByPassenger['data'][carsOrder]['driver_id'] .toString(), box.read(BoxName.passengerID).toString(), box.read(BoxName.name).toString(), @@ -1091,11 +1125,11 @@ class MapPassengerController extends GetxController { durationByPassenger.toString(), distanceByPassenger.toString(), paymentController.isWalletChecked.toString(), - dataCarsLocationByPassenger['message'][carsOrder]['token'].toString(), + dataCarsLocationByPassenger['data'][carsOrder]['token'].toString(), durationToPassenger.toString(), rideId, rideTimerBegin.toString(), - dataCarsLocationByPassenger['message'][carsOrder]['driver_id'] + dataCarsLocationByPassenger['data'][carsOrder]['driver_id'] .toString(), durationToRide.toString(), Get.find().wayPoints.length > 1 @@ -1112,73 +1146,24 @@ class MapPassengerController extends GetxController { .toStringAsFixed(2) : '0', box.read(BoxName.email).toString(), - startNameAddress, - endNameAddress, + data[0]['start_address'], + data[0]['end_address'], box.read(BoxName.carType), kazan.toStringAsFixed(0), passengerRate.toStringAsFixed(2), ]; - Log.print('body: ${body}'); + Log.print('bodyOf order: $body'); FirebaseMessagesController().sendNotificationToDriverMAP( 'Order'.tr, 'from: $startNameAddress\nto: $startNameAddress\ndistanceFromMe: $distanceByPassenger\nDistance :$distance\nPrice ; $totalPassenger', // jsonDecode(value)['message'].toString(), - dataCarsLocationByPassenger['message'][carsOrder]['token'] - .toString(), + driverToken.toString(), body, - 'order.wav' - - // polylineCoordinates.toString() - ); + 'order.wav'); Log.print( - 'body: ${dataCarsLocationByPassenger['message'][carsOrder]['token']}'); + 'dataCarsLocationByPassenger[data]: ${dataCarsLocationByPassenger['data'][carsOrder]['token']}'); }); - CRUD().post( - link: '${AppLink.seferAlexandriaServer}/ride/rides/add.php', - payload: { - "start_location": //'${data[0]['start_address']}', - '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', - "end_location": //'${data[0]['end_address']}', - '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', - "date": DateTime.now().toString(), - "time": DateTime.now().toString(), - "endtime": durationToAdd.toString(), - "price": totalPassenger.toStringAsFixed(2), - "passenger_id": box.read(BoxName.passengerID).toString(), - "driver_id": dataCarsLocationByPassenger['message'][carsOrder] - ['driver_id'] - .toString(), - "status": "waiting", - 'carType': box.read(BoxName.carType), - "price_for_driver": totalPassenger.toString(), - "price_for_passenger": totalME.toString(), - "distance": distance.toString(), - "paymentMethod": paymentController.isWalletChecked.toString(), - }); - CRUD().post( - link: '${AppLink.seferGizaServer}/ride/rides/add.php', - payload: { - "start_location": //'${data[0]['start_address']}', - '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', - "end_location": //'${data[0]['end_address']}', - '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', - "date": DateTime.now().toString(), - "time": DateTime.now().toString(), - "endtime": durationToAdd.toString(), - "price": totalPassenger.toStringAsFixed(2), - "passenger_id": box.read(BoxName.passengerID).toString(), - "driver_id": dataCarsLocationByPassenger['message'][carsOrder] - ['driver_id'] - .toString(), - "status": "waiting", - 'carType': box.read(BoxName.carType), - "price_for_driver": totalPassenger.toString(), - "price_for_passenger": totalME.toString(), - "distance": distance.toString(), - "paymentMethod": paymentController.isWalletChecked.toString(), - }); - - delayAndFetchRideStatus(rideId); + delayAndFetchRideStatus(rideId, box.read(BoxName.carType)); if (shouldFetch == false) { startTimer(); update(); @@ -1204,15 +1189,154 @@ class MapPassengerController extends GetxController { bool isDriversTokensSend = false; confirmRideForAllDriverAvailable() async { await getCarsLocationByPassengerAndReloadMarker( - box.read(BoxName.carType), 7000); + box.read(BoxName.carType), 4500); if (dataCarsLocationByPassenger != 'failure') { - driversToken.remove(driverToken); + // driversToken.remove(driverToken); PaymentController paymentController = Get.find(); rideConfirm = true; shouldFetch = true; isBottomSheetShown = false; timeToPassengerFromDriverAfterApplied = 60; + await CRUD().post( + link: "${AppLink.seferCairoServer}/ride/rides/add.php", + payload: { + "start_location": //'${data[0]['start_address']}', + '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', + "end_location": //'${data[0]['end_address']}', + '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', + "date": DateTime.now().toString(), + "time": DateTime.now().toString(), + "endtime": durationToAdd.toString(), + "price": totalPassenger.toStringAsFixed(2), + "passenger_id": box.read(BoxName.passengerID).toString(), + "driver_id": dataCarsLocationByPassenger['data'][carsOrder] + ['driver_id'] + .toString(), + "status": "waiting", + 'carType': box.read(BoxName.carType), + "price_for_driver": totalPassenger.toString(), + "price_for_passenger": totalME.toString(), + "distance": distance.toString(), + "paymentMethod": paymentController.isWalletChecked.toString(), + }).then((value) { + // List body = [ + rideId = jsonDecode(value)['message']; + for (var i = 0; i < dataCarsLocationByPassenger['data'].length; i++) { + List body = [ + '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', + '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', + totalPassenger.toStringAsFixed(2), + totalDriver.toStringAsFixed(2), + durationToRide.toString(), + distance.toStringAsFixed(2), + dataCarsLocationByPassenger['data'][i]['driver_id'].toString(), + box.read(BoxName.passengerID).toString(), + box.read(BoxName.name).toString(), + box.read(BoxName.tokenFCM).toString(), + box.read(BoxName.phone).toString(), + durationByPassenger.toString(), + distanceByPassenger.toString(), + paymentController.isWalletChecked.toString(), + dataCarsLocationByPassenger['data'][i]['token'].toString(), + durationToPassenger.toString(), + rideId, + rideTimerBegin.toString(), + dataCarsLocationByPassenger['data'][i]['driver_id'].toString(), + durationToRide.toString(), + Get.find().wayPoints.length > 1 + ? 'haveSteps' + : 'startEnd', + placesCoordinate[0], + placesCoordinate[1], + placesCoordinate[2], + placesCoordinate[3], + placesCoordinate[4], + costForDriver.toStringAsFixed(2), + double.parse(box.read(BoxName.passengerWalletTotal)) < 0 + ? double.parse(box.read(BoxName.passengerWalletTotal)) + .toStringAsFixed(2) + : '0', + box.read(BoxName.email).toString(), + data[0]['start_address'], + data[0]['end_address'], + box.read(BoxName.carType), + kazan.toStringAsFixed(0), + passengerRate.toStringAsFixed(2), + ]; + // Log.print('body: ${body}'); + FirebaseMessagesController().sendNotificationToDriverMAP( + 'OrderSpeed', + rideId.toString(), + dataCarsLocationByPassenger['data'][i]['token'].toString(), + body, + 'order.wav'); + } + }); + (rideId); // + CRUD().post( + link: '${AppLink.seferAlexandriaServer}/ride/rides/add.php', + payload: { + "start_location": //'${data[0]['start_address']}', + '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', + "end_location": //'${data[0]['end_address']}', + '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', + "date": DateTime.now().toString(), + "time": DateTime.now().toString(), + "endtime": durationToAdd.toString(), + "price": totalPassenger.toStringAsFixed(2), + "passenger_id": box.read(BoxName.passengerID).toString(), + "driver_id": dataCarsLocationByPassenger['data'][carsOrder] + ['driver_id'] + .toString(), + "status": "waiting", + 'carType': box.read(BoxName.carType), + "price_for_driver": totalPassenger.toString(), + "price_for_passenger": totalME.toString(), + "distance": distance.toString(), + "paymentMethod": paymentController.isWalletChecked.toString(), + }); + CRUD().post( + link: '${AppLink.seferGizaServer}/ride/rides/add.php', + payload: { + "start_location": //'${data[0]['start_address']}', + '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', + "end_location": //'${data[0]['end_address']}', + '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', + "date": DateTime.now().toString(), + "time": DateTime.now().toString(), + "endtime": durationToAdd.toString(), + "price": totalPassenger.toStringAsFixed(2), + "passenger_id": box.read(BoxName.passengerID).toString(), + "driver_id": dataCarsLocationByPassenger['data'][carsOrder] + ['driver_id'] + .toString(), + "status": "waiting", + 'carType': box.read(BoxName.carType), + "price_for_driver": totalPassenger.toString(), + "price_for_passenger": totalME.toString(), + "distance": distance.toString(), + "paymentMethod": paymentController.isWalletChecked.toString(), + }); + + delayAndFetchRideStatusForAllDriverAvailable(rideId); + update(); + } else { + MyDialog().getDialog("No Car or Driver Found in your area.".tr, + "No Car or Driver Found in your area.".tr, () { + Get.back(); + Get.offAll(const MapPagePassenger()); + }); + } + } + + icreaseForSameRideAndDelay() { + PaymentController paymentController = Get.find(); + rideConfirm = true; + shouldFetch = true; + isBottomSheetShown = false; + timeToPassengerFromDriverAfterApplied = 60; + for (var i = 0; i < dataCarsLocationByPassenger['data'].length; i++) { List body = [ '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', @@ -1220,8 +1344,7 @@ class MapPassengerController extends GetxController { totalDriver.toStringAsFixed(2), durationToRide.toString(), distance.toStringAsFixed(2), - dataCarsLocationByPassenger['message'][carsOrder]['driver_id'] - .toString(), + dataCarsLocationByPassenger['data'][i]['driver_id'].toString(), box.read(BoxName.passengerID).toString(), box.read(BoxName.name).toString(), box.read(BoxName.tokenFCM).toString(), @@ -1229,12 +1352,11 @@ class MapPassengerController extends GetxController { durationByPassenger.toString(), distanceByPassenger.toString(), paymentController.isWalletChecked.toString(), - dataCarsLocationByPassenger['message'][carsOrder]['token'].toString(), + dataCarsLocationByPassenger['data'][i]['token'].toString(), durationToPassenger.toString(), rideId, rideTimerBegin.toString(), - dataCarsLocationByPassenger['message'][carsOrder]['driver_id'] - .toString(), + dataCarsLocationByPassenger['data'][i]['driver_id'].toString(), durationToRide.toString(), Get.find().wayPoints.length > 1 ? 'haveSteps' @@ -1250,33 +1372,26 @@ class MapPassengerController extends GetxController { .toStringAsFixed(2) : '0', box.read(BoxName.email).toString(), - startNameAddress, - endNameAddress, + data[0]['start_address'], + data[0]['end_address'], box.read(BoxName.carType), kazan.toStringAsFixed(0), passengerRate.toStringAsFixed(2), ]; - Log.print('body: ${body}'); - for (var i = 1; i < driversToken.length; i++) { - FirebaseMessagesController().sendNotificationToDriverMAP('OrderSpeed', - rideId.toString(), driversToken[i], body, 'order.wav'); - } + // Log.print('body: ${body}'); - (rideId); - - update(); - } else { - MyDialog().getDialog("No Car or Driver Found in your area.".tr, - "No Car or Driver Found in your area.".tr, () { - Get.back(); - Get.offAll(const MapPagePassenger()); - }); + FirebaseMessagesController().sendNotificationToDriverMAP( + 'OrderSpeed', + rideId.toString(), + dataCarsLocationByPassenger['data'][i]['token'].toString(), + body, + 'order.wav'); } } int tick = 0; // Move tick outside the function to maintain its state - void delayAndFetchRideStatus(String rideId) { + void delayAndFetchRideStatus(String rideId, carType) { Timer.periodic(const Duration(seconds: 1), (timer) async { if (shouldFetch) { if (remainingTimeToPassengerFromDriverAfterApplied > 0) { @@ -1284,17 +1399,23 @@ class MapPassengerController extends GetxController { Log.print('tick: $tick'); - if (res.toString() == 'waiting' && tick >= 15) { + if ((res.toString() == 'waiting' || res.toString() == 'Refused') && + tick >= 15) { timer.cancel(); // Stop the current timer showAndResearchForCaptain(); //TODO add to wait + await getCarsLocationByPassengerAndReloadMarker(carType, 4500); + // await getNearestDriverByPassengerLocationAPIGOOGLE(); + // getCarForFirstConfirm(carType); confirmRideForAllDriverAvailable(); // delayAndFetchRideStatusForAllDriverAvailable(rideId); } else if (res.toString() == 'Apply') { + Log.print('res.toString() == Apply: ${res.toString()}'); // todo play sound Get.find() .playSoundFromAssets('assets/start.wav'); timer.cancel(); // Stop the current timer + await getUpdatedRideForDriverApply(rideId); shouldFetch = false; // Stop further fetches statusRide = 'Apply'; rideConfirm = false; @@ -1314,6 +1435,9 @@ class MapPassengerController extends GetxController { // } if (tick < 19) { tick++; + } else { + timer.cancel(); + // Stop the timer if remainingTimeToPassengerFromDriverAfterApplied <= 0 } } else { timer.cancel(); @@ -1333,6 +1457,8 @@ class MapPassengerController extends GetxController { duration: const Duration(seconds: 5), backgroundColor: AppColor.yellowColor, ); + isSearchingWindow == true; + update(); } void delayAndFetchRideStatusForAllDriverAvailable(String rideId) async { @@ -1340,16 +1466,16 @@ class MapPassengerController extends GetxController { int attemptCounter = 0; bool isApplied = false; tick = 0; - Log.print('tick delayAndFetchRideStatusForAllDriverAvailable: ${tick}'); + Log.print('tick delayAndFetchRideStatusForAllDriverAvailable: $tick'); void fetchRideStatus() async { - if (attemptCounter < maxAttempts && !isApplied || tick < 20) { + if (attemptCounter < maxAttempts && isApplied == false || tick < 15) { attemptCounter++; tick++; var res = await getRideStatus(rideId); - if (res.toString() == 'Apply') { - getUpdatedRideForDriverApply(rideId); + if (res.toString() == 'Apply' || res.toString() == 'Applied') { + await getUpdatedRideForDriverApply(rideId); isApplied = true; shouldFetch = false; statusRide = 'Apply'; @@ -1421,9 +1547,9 @@ class MapPassengerController extends GetxController { actions: [ MyElevatedButton( title: "No, thanks", - onPressed: () { + onPressed: () async { + await cancelRide(); Get.back(); - cancelRide(); }), MyElevatedButton( title: "Increase Fee".tr, @@ -1447,7 +1573,7 @@ class MapPassengerController extends GetxController { reSearchAfterCanceledFromDriver() async { await getCarsLocationByPassengerAndReloadMarker( - box.read(BoxName.carType), 7000); + box.read(BoxName.carType), 4500); confirmRideForAllDriverAvailable(); shouldFetch = true; // Stop further fetches @@ -1485,7 +1611,7 @@ class MapPassengerController extends GetxController { void timerEnded() async { runEvery30SecondsUntilConditionMet(); isCancelRidePageShown = false; - print('isCancelRidePageShown: ${isCancelRidePageShown}'); + print('isCancelRidePageShown: $isCancelRidePageShown'); update(); } @@ -1503,6 +1629,7 @@ class MapPassengerController extends GetxController { await CRUD().get(link: AppLink.getRideOrderID, payload: {'id': rideId}); if (res != 'failure') { var response = jsonDecode(res); + Log.print('getUpdatedRideForDriverApply: $response'); driverId = response['data']['driver_id']; driverPhone = response['data']['phone']; driverCarMake = response['data']['make']; @@ -1510,19 +1637,21 @@ class MapPassengerController extends GetxController { make = response['data']['make']; licensePlate = response['data']['car_plate']; firstName = response['data']['first_name']; + driverName = response['data']['driverName']; driverToken = response['data']['token']; + Log.print('driverToken updated: $driverToken'); carYear = response['data']['year']; - driverRate = response['data']['ratingDriver']; - } - driversToken.remove(driverToken); - for (var i = 1; i < driversToken.length; i++) { - FirebaseMessagesController().sendNotificationToAnyWithoutData( - 'Order Applied'.tr, - '$driverName Apply order\nTake attention in other order'.tr, - driversToken[i], - 'start.wav', - ); + driverRate = response['data']['ratingDriver'].toString(); } + // driversToken.remove(driverToken); + // for (var i = 1; i < driversToken.length; i++) { + FirebaseMessagesController().sendNotificationToAnyWithoutData( + 'Order Applied'.tr, + '$driverName Apply order\nTake attention in other order'.tr, + driverToken, + 'start.wav', + ); + // } // } } @@ -1645,34 +1774,71 @@ class MapPassengerController extends GetxController { final int updateIntervalMs = 100; // Update every 100ms final double minMovementThreshold = 10; // Minimum movement in meters to trigger update + Future getCarForFirstConfirm(String carType) async { + bool foundCars = false; + int attempt = 0; + + // Set up the periodic timer + Timer? timer = Timer.periodic(const Duration(seconds: 4), (Timer t) async { + // Attempt to get car location + foundCars = await getCarsLocationByPassengerAndReloadMarker( + carType, attempt * 2000); + Log.print('foundCars: $foundCars'); + + if (foundCars) { + // If cars are found, cancel the timer and exit the search + t.cancel(); + } else if (attempt >= 4) { + // After 4 attempts, stop the search + t.cancel(); + + // No cars found after 4 attempts + // MyDialog().getDialog( + // "No Car or Driver Found in your area.".tr, + // "No Car or Driver Found in your area.".tr, + // () { + // Get.back(); + // }, + // ); + if (!foundCars) { + noCarString = true; + dataCarsLocationByPassenger = 'failure'; + } + + update(); + } + + attempt++; // Increment attempt + }); + } void startCarLocationSearch(String carType) { int searchInterval = 5; // Interval in seconds - Log.print('searchInterval: ${searchInterval}'); + Log.print('searchInterval: $searchInterval'); int boundIncreaseStep = 2500; // Initial bounds in meters - Log.print('boundIncreaseStep: ${boundIncreaseStep}'); + Log.print('boundIncreaseStep: $boundIncreaseStep'); int maxAttempts = 3; // Maximum attempts to increase bounds int maxBoundIncreaseStep = 6000; // Maximum bounds increase step int attempt = 0; // Current attempt - Log.print('initial attempt: ${attempt}'); + Log.print('initial attempt: $attempt'); Timer.periodic(Duration(seconds: searchInterval), (Timer timer) async { - Log.print('Current attempt: ${attempt}'); // Log current attempt + Log.print('Current attempt: $attempt'); // Log current attempt bool foundCars = false; if (attempt >= maxAttempts) { timer.cancel(); if (foundCars == false) { noCarString = true; - dataCarsLocationByPassenger = 'failure'; + // dataCarsLocationByPassenger = 'failure'; update(); } - return; + // return; } else if (reloadStartApp == true) { - Log.print('reloadStartApp: ${reloadStartApp}'); + Log.print('reloadStartApp: $reloadStartApp'); foundCars = await getCarsLocationByPassengerAndReloadMarker( carType, boundIncreaseStep); - Log.print('foundCars: ${foundCars}'); + Log.print('foundCars: $foundCars'); if (foundCars) { timer.cancel(); @@ -1682,7 +1848,7 @@ class MapPassengerController extends GetxController { timer.cancel(); } Log.print( - 'Incrementing attempt to: ${attempt}'); // Log incremented attempt + 'Incrementing attempt to: $attempt'); // Log incremented attempt if (boundIncreaseStep < maxBoundIncreaseStep) { boundIncreaseStep += 1500; // Increase bounds @@ -1691,7 +1857,7 @@ class MapPassengerController extends GetxController { maxBoundIncreaseStep; // Ensure it does not exceed the maximum } Log.print( - 'New boundIncreaseStep: ${boundIncreaseStep}'); // Log new bounds + 'New boundIncreaseStep: $boundIncreaseStep'); // Log new bounds } } } @@ -1708,7 +1874,7 @@ class MapPassengerController extends GetxController { } else if (latitude >= 29.904975 && latitude <= 30.143372 && longitude >= 30.787030 && - longitude <= 31.238843) { + longitude <= 31.215009) { box.write(BoxName.serverChosen, AppLink.seferGizaServer); return 'Giza'; } else if (latitude >= 30.396286 && @@ -1719,141 +1885,139 @@ class MapPassengerController extends GetxController { return 'Alexandria'; } else { box.write(BoxName.serverChosen, AppLink.seferCairoServer); - return 'Outside'; + return 'Cairo'; } } Future getCarsLocationByPassengerAndReloadMarker( String carType, int boundIncreaseStep) async { - if (statusRide == 'wait') { - carsLocationByPassenger = []; - LatLngBounds bounds = calculateBounds(passengerLocation.latitude, - passengerLocation.longitude, boundIncreaseStep.toDouble()); - var res; - // await getLocation(); + // if (statusRide == 'wait') { + carsLocationByPassenger = []; + LatLngBounds bounds = calculateBounds(passengerLocation.latitude, + passengerLocation.longitude, boundIncreaseStep.toDouble()); + var res; + // await getLocation(); - switch (carType) { - case 'Lady': - res = await CRUD() - .get(link: AppLink.getFemalDriverLocationByPassenger, payload: { - 'southwestLat': bounds.southwest.latitude.toString(), - 'southwestLon': bounds.southwest.longitude.toString(), - 'northeastLat': bounds.northeast.latitude.toString(), - 'northeastLon': bounds.northeast.longitude.toString(), - }); - break; - case 'Comfort': - res = await CRUD() - .get(link: AppLink.getCarsLocationByPassengerComfort, payload: { - 'southwestLat': bounds.southwest.latitude.toString(), - 'southwestLon': bounds.southwest.longitude.toString(), - 'northeastLat': bounds.northeast.latitude.toString(), - 'northeastLon': bounds.northeast.longitude.toString(), - }); - break; - case 'Speed': - res = await CRUD() - .get(link: AppLink.getCarsLocationByPassengerSpeed, payload: { - 'southwestLat': bounds.southwest.latitude.toString(), - 'southwestLon': bounds.southwest.longitude.toString(), - 'northeastLat': bounds.northeast.latitude.toString(), - 'northeastLon': bounds.northeast.longitude.toString(), - }); - break; - case 'Scooter': - res = await CRUD() - .get(link: AppLink.getCarsLocationByPassengerDelivery, payload: { - 'southwestLat': bounds.southwest.latitude.toString(), - 'southwestLon': bounds.southwest.longitude.toString(), - 'northeastLat': bounds.northeast.latitude.toString(), - 'northeastLon': bounds.northeast.longitude.toString(), - }); - break; - case 'Awfar Car': - res = await CRUD() - .get(link: AppLink.getCarsLocationByPassengerBalash, payload: { - 'southwestLat': bounds.southwest.latitude.toString(), - 'southwestLon': bounds.southwest.longitude.toString(), - 'northeastLat': bounds.northeast.latitude.toString(), - 'northeastLon': bounds.northeast.longitude.toString(), - }); - break; - case 'Pink Bike': - res = await CRUD() - .get(link: AppLink.getCarsLocationByPassengerPinkBike, payload: { - 'southwestLat': bounds.southwest.latitude.toString(), - 'southwestLon': bounds.southwest.longitude.toString(), - 'northeastLat': bounds.northeast.latitude.toString(), - 'northeastLon': bounds.northeast.longitude.toString(), - }); - break; - default: - res = await CRUD() - .get(link: AppLink.getCarsLocationByPassenger, payload: { - 'southwestLat': bounds.southwest.latitude.toString(), - 'southwestLon': bounds.southwest.longitude.toString(), - 'northeastLat': bounds.northeast.latitude.toString(), - 'northeastLon': bounds.northeast.longitude.toString(), - }); - } - - if (res == 'failure') { - noCarString = true; - dataCarsLocationByPassenger = 'failure'; - update(); - return false; - } else { - noCarString = false; - dataCarsLocationByPassenger = jsonDecode(res); - - // Check if 'message' is present and not null - if (dataCarsLocationByPassenger['message'] != null && - dataCarsLocationByPassenger['message'].isNotEmpty) { - // Check if carsOrder is within bounds - if (carsOrder < dataCarsLocationByPassenger['message'].length) { - driverId = dataCarsLocationByPassenger['message'][carsOrder] - ['driver_id'] - .toString(); - gender = dataCarsLocationByPassenger['message'][carsOrder]['gender'] - .toString(); - driverToken = dataCarsLocationByPassenger['message'][carsOrder] - ['token'] - .toString(); - } else { - print('carsOrder is out of bounds for message array'); - return false; - } - } else { - // Get.defaultDialog(title: 'No cars available '); - print('No cars available or message is null'); - return false; - } - - carsLocationByPassenger.clear(); // Clear existing markers - - for (var i = 0; - i < dataCarsLocationByPassenger['message'].length; - i++) { - var json = dataCarsLocationByPassenger['message'][i]; - _updateOrCreateMarker( - MarkerId(json['latitude']).toString(), - LatLng(double.parse(json['latitude']), - double.parse(json['longitude'])), - double.parse(json['heading']), - _getIconForCar(json), - ); - - driversToken.add(json['token']); - } - - // Add fake car markers - _addFakeCarMarkers(passengerLocation, 2); - - update(); - return true; - } + switch (carType) { + case 'Lady': + res = await CRUD() + .get(link: AppLink.getFemalDriverLocationByPassenger, payload: { + 'southwestLat': bounds.southwest.latitude.toString(), + 'southwestLon': bounds.southwest.longitude.toString(), + 'northeastLat': bounds.northeast.latitude.toString(), + 'northeastLon': bounds.northeast.longitude.toString(), + }); + break; + case 'Comfort': + res = await CRUD() + .get(link: AppLink.getCarsLocationByPassengerComfort, payload: { + 'southwestLat': bounds.southwest.latitude.toString(), + 'southwestLon': bounds.southwest.longitude.toString(), + 'northeastLat': bounds.northeast.latitude.toString(), + 'northeastLon': bounds.northeast.longitude.toString(), + }); + break; + case 'Speed': + res = await CRUD() + .get(link: AppLink.getCarsLocationByPassengerSpeed, payload: { + 'southwestLat': bounds.southwest.latitude.toString(), + 'southwestLon': bounds.southwest.longitude.toString(), + 'northeastLat': bounds.northeast.latitude.toString(), + 'northeastLon': bounds.northeast.longitude.toString(), + }); + break; + case 'Scooter': + res = await CRUD() + .get(link: AppLink.getCarsLocationByPassengerDelivery, payload: { + 'southwestLat': bounds.southwest.latitude.toString(), + 'southwestLon': bounds.southwest.longitude.toString(), + 'northeastLat': bounds.northeast.latitude.toString(), + 'northeastLon': bounds.northeast.longitude.toString(), + }); + break; + case 'Awfar Car': + res = await CRUD() + .get(link: AppLink.getCarsLocationByPassengerBalash, payload: { + 'southwestLat': bounds.southwest.latitude.toString(), + 'southwestLon': bounds.southwest.longitude.toString(), + 'northeastLat': bounds.northeast.latitude.toString(), + 'northeastLon': bounds.northeast.longitude.toString(), + }); + break; + case 'Pink Bike': + res = await CRUD() + .get(link: AppLink.getCarsLocationByPassengerPinkBike, payload: { + 'southwestLat': bounds.southwest.latitude.toString(), + 'southwestLon': bounds.southwest.longitude.toString(), + 'northeastLat': bounds.northeast.latitude.toString(), + 'northeastLon': bounds.northeast.longitude.toString(), + }); + break; + default: + res = await CRUD() + .get(link: AppLink.getCarsLocationByPassenger, payload: { + 'southwestLat': bounds.southwest.latitude.toString(), + 'southwestLon': bounds.southwest.longitude.toString(), + 'northeastLat': bounds.northeast.latitude.toString(), + 'northeastLon': bounds.northeast.longitude.toString(), + }); } - return false; + + if (res == 'failure') { + noCarString = true; + // dataCarsLocationByPassenger = 'failure'; + update(); + return false; + } else { + noCarString = false; + dataCarsLocationByPassenger = jsonDecode(res); + + // Check if 'message' is present and not null + if (dataCarsLocationByPassenger['message'] != null && + dataCarsLocationByPassenger['message'].isNotEmpty) { + // Check if carsOrder is within bounds + // if (carsOrder < dataCarsLocationByPassenger['message'].length) { + // driverId = dataCarsLocationByPassenger['message'][carsOrder] + // ['driver_id'] + // .toString(); + // gender = dataCarsLocationByPassenger['message'][carsOrder]['gender'] + // .toString(); + // driverToken = dataCarsLocationByPassenger['message'][carsOrder] + // ['token'] + // .toString(); + // } else { + // print('carsOrder is out of bounds for message array'); + // return false; + // } + } else { + // Get.defaultDialog(title: 'No cars available '); + print('No cars available or message is null'); + return false; + } + + carsLocationByPassenger.clear(); // Clear existing markers + + for (var i = 0; i < dataCarsLocationByPassenger['message'].length; i++) { + var json = dataCarsLocationByPassenger['message'][i]; + _updateOrCreateMarker( + MarkerId(json['latitude']).toString(), + LatLng( + double.parse(json['latitude']), double.parse(json['longitude'])), + double.parse(json['heading']), + _getIconForCar(json), + ); + + driversToken.add(json['token']); + } + + // Add fake car markers + _addFakeCarMarkers(passengerLocation, 1); + + update(); + return true; + } + // } + // return false; } final List> fakeCarData = []; @@ -1861,7 +2025,7 @@ class MapPassengerController extends GetxController { void _addFakeCarMarkers(LatLng center, int count) { if (fakeCarData.isEmpty) { Random random = Random(); - double radiusInKm = 1.5; // 3 km diameter, so 1.5 km radius + double radiusInKm = 2.5; // 3 km diameter, so 1.5 km radius for (int i = 0; i < count; i++) { // Generate a random angle and distance within the circle @@ -2024,6 +2188,93 @@ class MapPassengerController extends GetxController { } } + // Function to check if the point is inside the polygon + bool isPointInPolygon(LatLng point, List polygon) { + int intersections = 0; + for (int i = 0; i < polygon.length; i++) { + LatLng vertex1 = polygon[i]; + LatLng vertex2 = + polygon[(i + 1) % polygon.length]; // Loop back to the start + + if (_rayIntersectsSegment(point, vertex1, vertex2)) { + intersections++; + } + } + + // If the number of intersections is odd, the point is inside + return intersections % 2 != 0; + } + +// Helper function to check if a ray from the point intersects with a polygon segment + bool _rayIntersectsSegment(LatLng point, LatLng vertex1, LatLng vertex2) { + double px = point.longitude; + double py = point.latitude; + + double v1x = vertex1.longitude; + double v1y = vertex1.latitude; + double v2x = vertex2.longitude; + double v2y = vertex2.latitude; + + // Check if the point is outside the vertical bounds of the segment + if ((py < v1y && py < v2y) || (py > v1y && py > v2y)) { + return false; + } + + // Calculate the intersection of the ray and the segment + double intersectX = v1x + (py - v1y) * (v2x - v1x) / (v2y - v1y); + + // Check if the intersection is to the right of the point + return intersectX > px; + } + + bool isInUniversity = false; +// Function to check if the passenger is in any university polygon + // Function to check if the passenger is in any university polygon and return the university name + String checkPassengerLocation(LatLng passengerLocation, + List> universityPolygons, List universityNames) { + for (int i = 0; i < universityPolygons.length; i++) { + if (isPointInPolygon(passengerLocation, universityPolygons[i])) { + isInUniversity = true; + return "Passenger is in ${universityNames[i]}"; + } + } + return "Passenger is not in any university"; + } + + String passengerLocationStringUnvirsity = 'unKnown'; + void getPassengerLocationUniversity() { + // Check if the passenger is inside any of the university polygons and get the university name + passengerLocationStringUnvirsity = checkPassengerLocation( + passengerLocation, + UniversitiesPolygons.universityPolygons, + UniversitiesPolygons.universityNames, + ); + if (passengerLocationStringUnvirsity != 'unKnown') { + // Get.snackbar('you are in $passengerLocationStringUnvirsity', ""); + } + print(passengerLocationStringUnvirsity); + } + + var polygons = {}.obs; + + // Initialize polygons from UniversitiesPolygons + void _initializePolygons() { + List> universityPolygons = + UniversitiesPolygons.universityPolygons; + List universityNames = UniversitiesPolygons.universityNames; + + for (int i = 0; i < universityPolygons.length; i++) { + Polygon polygon = Polygon( + polygonId: PolygonId(universityNames[i]), + points: universityPolygons[i], + strokeColor: Colors.blueAccent, + fillColor: Colors.blueAccent.withOpacity(0.2), + strokeWidth: 2, + ); + polygons.add(polygon); // Add polygon to observable set + } + } + void handleResponse(Map res1) { if (res1['message'] == "No passenger found for the given phone number") { Get.defaultDialog( @@ -2131,7 +2382,7 @@ class MapPassengerController extends GetxController { for (var i = 0; i < loopCount; i++) { // Wait for 50 seconds. await Future.delayed(const Duration(seconds: 4)); - if (rideTimerBegin == true) { + if (rideTimerBegin == true && statusRide == 'Apply') { await getDriverCarsLocationToPassengerAfterApplied(); } reloadMarkerDriverCarsLocationToPassengerAfterApplied(); @@ -2235,18 +2486,6 @@ class MapPassengerController extends GetxController { update(); } - searchNewDriverAfterRejectingFromDriver() { -// - - shouldFetch = true; // Stop further fetches - statusRide = 'wait'; - rideConfirm = true; - isSearchingWindow = true; - confirmRideForFirstDriver(); - - update(); - } - Future cancelRideAfterRejectFromAll() async { clearPlacesDestination(); clearPolyline(); @@ -2271,7 +2510,9 @@ class MapPassengerController extends GetxController { } Future cancelRide() async { - if (rideConfirm == false && statusRide == 'Apply') { + if (rideConfirm == false && statusRide == 'Apply' || + statusRide == 'Applied' || + statusRide == 'waiting') { clearPlacesDestination(); clearPolyline(); // clearPolylineAll(); @@ -2286,6 +2527,10 @@ class MapPassengerController extends GetxController { "id": rideId.toString(), // Convert to String "status": 'Cancel' }); + CRUD().post(link: AppLink.updateWaitingTrip, payload: { + "id": rideId.toString(), // Convert to String + "status": 'Cancel' + }); print('Cancel'); FirebaseMessagesController().sendNotificationToDriverMAP( 'Cancel Trip', @@ -2718,7 +2963,7 @@ class MapPassengerController extends GetxController { if (reloadStartApp == false) { Timer.periodic(const Duration(seconds: 5), (timer) async { reloadCount++; - Log.print('reloadCount: ${reloadCount}'); + Log.print('reloadCount: $reloadCount'); if (!rideConfirm) { clearMarkersExceptStartEnd(); @@ -2751,35 +2996,42 @@ class MapPassengerController extends GetxController { if (polyLines.isEmpty || data.isEmpty) { return null; // Early return if data is empty } + if (!rideConfirm) { if (dataCarsLocationByPassenger != 'failure') { if (dataCarsLocationByPassenger != null) { if (dataCarsLocationByPassenger['message'].length > 0) { + double nearestDistance = double + .infinity; // Initialize nearest distance to a large number + CarLocation? nearestCar; + for (var i = 0; i < dataCarsLocationByPassenger['message'].length; i++) { var carLocation = dataCarsLocationByPassenger['message'][i]; - // Calculate the distance between the passenger's location and the current driver's location + // Calculate the distance between passenger's location and current driver's location final distance = Geolocator.distanceBetween( passengerLocation.latitude, passengerLocation.longitude, double.parse(carLocation['latitude']), double.parse(carLocation['longitude']), ); - durationToPassenger = (distance * 25 * (1000 / 3600)) - .round(); //////35 is avg of speed in city - // Update the UI with the distance and duration + + // Calculate duration assuming an average speed of 25 km/h (adjust as needed) + int durationToPassenger = + (distance * 25 * (1000 / 3600)).round(); // 25 km/h in m/s + + // Update the UI with the distance and duration for each car update(); - // If the distance is less than the nearest distance, update the nearest driver + // If this distance is smaller than the nearest distance found so far, update nearestCar if (distance < nearestDistance) { nearestDistance = distance; nearestCar = CarLocation( distance: distance, - duration: - 0, // We don't have duration information from Geolocator + duration: durationToPassenger.toDouble(), id: carLocation['driver_id'], latitude: double.parse(carLocation['latitude']), longitude: double.parse(carLocation['longitude']), @@ -2789,13 +3041,16 @@ class MapPassengerController extends GetxController { update(); } } + + // Return the nearest car found + return nearestCar; } } } } - // Return the nearest driver - return nearestCar; + // Return null if no drivers are found or if ride is confirmed + return null; } getNearestDriverByPassengerLocationAPIGOOGLE() async { @@ -2943,7 +3198,8 @@ class MapPassengerController extends GetxController { update(); remainingTime = 25; //to make cancel every call // startCarLocationSearch(box.read(BoxName.carType)); - getCarsLocationByPassengerAndReloadMarker(box.read(BoxName.carType), 7000); + await getCarsLocationByPassengerAndReloadMarker( + box.read(BoxName.carType), 7000); // await getCarsLocationByPassengerAndReloadMarker(); var coordDestination = destination.split(','); double latPassengerDestination = double.parse(coordDestination[0]); @@ -3241,44 +3497,150 @@ class MapPassengerController extends GetxController { final promo = TextEditingController(); bool promoTaken = false; - void applyPromoCodeToPassenger() async { - //TAWJIHI - - CRUD().get(link: AppLink.getPassengersPromo, payload: { - 'promo_code': promo.text, - }).then((value) { - if (value == 'failure') { - Get.defaultDialog( - title: 'Promo End !'.tr, - confirm: MyElevatedButton( - title: 'Back', - onPressed: () { - Get.back(); + applyPromoCodeToPassenger(BuildContext context) async { + if (promoTaken == false) { + if (promoFormKey.currentState!.validate()) { + CRUD().get(link: AppLink.getPassengersPromo, payload: { + 'promo_code': promo.text, + }).then((value) { + if (value == 'failure') { + MyDialog().getDialog( + 'Promo Ended'.tr, + 'The promotion period has ended.'.tr, + () { Get.back(); }, - )); + ); + } else if (totalPassengerComfort > 30 || + totalPassengerLady > 30 || + totalPassengerSpeed > 20 || + totalPassengerBalash > 20) { + var decode = jsonDecode(value); + + if (decode["status"] == "success") { + Get.snackbar('Promo Code Accepted'.tr, '', + backgroundColor: AppColor.greenColor); + var firstElement = decode["message"][0]; + double burc = + double.parse(box.read(BoxName.passengerWalletTotal)); + if (burc < 0) { + int discountPercentage = int.parse(firstElement['amount']); + +// 1. Calculate and apply discount for totalPassengerComfort + totalPassengerComfortDiscount = + totalPassengerComfort * discountPercentage / 100; + Log.print( + 'totalPassengerComfortDiscount: $totalPassengerComfortDiscount'); + +// Apply the formula: totalPassengerComfort + (-1 * burc) - discount + totalPassengerComfort = totalPassengerComfort + + (-1 * burc) - + totalPassengerComfortDiscount; + +// 2. Calculate and apply discount for totalPassengerLady + totalPassengerLadyDiscount = + totalPassengerLady * discountPercentage / 100; + +// Apply the formula: totalPassengerLady + (-1 * burc) - discount + totalPassengerLady = totalPassengerLady + + (-1 * burc) - + totalPassengerLadyDiscount; + +// 3. Calculate and apply discount for totalPassengerSpeed + totalPassengerSpeedDiscount = + totalPassengerSpeed * discountPercentage / 100; + +// Apply the formula: totalPassengerSpeed + (-1 * burc) - discount + totalPassengerSpeed = totalPassengerSpeed + + (-1 * burc) - + totalPassengerSpeedDiscount; + +// 4. Calculate and apply discount for totalPassengerBalash + totalPassengerBalashDiscount = + totalPassengerBalash * discountPercentage / 100; + +// Apply the formula: totalPassengerBalash + (-1 * burc) - discount + totalPassengerBalash = totalPassengerBalash + + (-1 * burc) - + totalPassengerBalashDiscount; + +// Mark promo as taken + promoTaken = true; + +// Update UI + update(); + } else { + int discountPercentage = int.parse(firstElement['amount']); + +// Calculate discounts for each category, ensuring they don't exceed 25 + totalPassengerComfortDiscount = + totalPassengerComfort * discountPercentage / 100; + if (totalPassengerComfortDiscount > 25) { + totalPassengerComfortDiscount = + 25; // Limit the discount to 25 + } + Log.print( + 'totalPassengerComfortDiscount: $totalPassengerComfortDiscount'); + totalPassengerComfort = + totalPassengerComfort - totalPassengerComfortDiscount; + + totalPassengerLadyDiscount = + totalPassengerLady * discountPercentage / 100; + if (totalPassengerLadyDiscount > 25) { + totalPassengerLadyDiscount = 25; // Limit the discount to 25 + } + totalPassengerLady = + totalPassengerLady - totalPassengerLadyDiscount; + + totalPassengerSpeedDiscount = + totalPassengerSpeed * discountPercentage / 100; + if (totalPassengerSpeedDiscount > 25) { + totalPassengerSpeedDiscount = 25; // Limit the discount to 25 + } + totalPassengerSpeed = + totalPassengerSpeed - totalPassengerSpeedDiscount; + + totalPassengerBalashDiscount = + totalPassengerBalash * discountPercentage / 100; + if (totalPassengerBalashDiscount > 25) { + totalPassengerBalashDiscount = 25; // Limit the discount to 25 + } + totalPassengerBalash = + totalPassengerBalash - totalPassengerBalashDiscount; + +// Trigger UI update + update(); + } + + totalDriver = totalDriver - + (totalDriver * int.parse(firstElement['amount']) / 100); + promoTaken = true; + + // Launch confetti for success feedback + Confetti.launch( + context, + options: const ConfettiOptions( + particleCount: 100, spread: 70, y: 0.6), + ); + + update(); + Get.back(); + Future.delayed(const Duration(microseconds: 111)); + } + } else { + Get.snackbar('Lowest Price Achieved'.tr, + 'Cannot apply further discounts.'.tr, + backgroundColor: AppColor.yellowColor); + } + }); } - var decode = jsonDecode(value); - - if (decode["status"] == "success") { - var firstElement = decode["message"][0]; - if (double.parse(box.read(BoxName.passengerWalletTotal)) < 0) { - totalPassenger = totalCostPassenger - - (totalCostPassenger * int.parse(firstElement['amount']) / 100); - update(); - } else { - totalPassenger = totalCostPassenger - - (totalCostPassenger * int.parse(firstElement['amount']) / 100); - update(); - } - - totalDriver = totalDriver - - (totalDriver * int.parse(firstElement['amount']) / 100); - promoTaken = true; - update(); + } else { + MyDialog().getDialog( + 'Promo Already Used'.tr, 'You have already used this promo code.'.tr, + () { Get.back(); - } - }); + }); + } } double getDistanceFromText(String distanceText) { @@ -3318,6 +3680,7 @@ class MapPassengerController extends GetxController { costRayehGaiBalash, costRayehGaiComfort = 0; update(); + if (startNameAddress.toLowerCase().contains('airport') || endNameAddress.toLowerCase().contains('airport') || startNameAddress.contains('مطار') || @@ -3457,45 +3820,92 @@ class MapPassengerController extends GetxController { var totalDriver1 = costDistance + costDuration; totalCostPassenger = totalDriver1 + (totalDriver1 * kazan / 100); totalPassenger = costSpeed + (costSpeed * kazan / 100); - totalPassengerComfort = - (costComfort + (costComfort * kazan / 100)).ceilToDouble(); - totalPassengerLady = (costLady + (costLady * kazan / 100)).ceilToDouble(); - totalPassengerSpeed = - (costSpeed + (costSpeed * kazan / 100)).ceilToDouble(); - totalPassengerBalash = - (costBalash + (costBalash * kazan / 100)).ceilToDouble(); - totalPassengerRayehGai = - (costRayehGai + (costRayehGai * kazan / 100)).ceilToDouble(); - totalPassengerRayehGaiComfort = - (costRayehGaiComfort + (costRayehGaiComfort * kazan / 100)) - .ceilToDouble(); - totalPassengerRayehGaiBalash = - (costRayehGaiBalash + (costRayehGaiBalash * kazan / 100)) - .ceilToDouble(); - totalPassengerComfortDiscount = - totalPassengerComfort + totalPassengerComfort * (kazan - 0) / 100; - totalPassengerLadyDiscount = - totalPassengerLady + totalPassengerLady * (kazan - 0) / 100; - totalPassengerSpeedDiscount = - totalPassengerSpeed + totalPassengerSpeed * (kazan) / 100; - totalPassengerBalashDiscount = - totalPassengerBalash + totalPassengerBalash * (kazan) / 100; - totalPassengerRaihGaiDiscount = - totalPassengerRayehGai + totalPassengerRayehGai * (kazan) / 100; - totalPassengerScooter = - (costDelivery + (costDelivery * kazan / 100)).ceilToDouble(); - totalPassengerComfort = totalPassengerComfortDiscount - - (totalPassengerComfortDiscount * kazan / 100); - totalPassengerSpeed = totalPassengerSpeedDiscount - - (totalPassengerSpeedDiscount * kazan / 100); - totalPassengerBalash = totalPassengerBalashDiscount - - (totalPassengerBalashDiscount * kazan / 100); - totalPassengerLady = totalPassengerLadyDiscount - - (totalPassengerLadyDiscount * kazan / 100); - totalDriver = totalDriver1 + (totalDriver1 * kazan / 100); - tax = totalCostPassenger * kazan / 100; - totalME = totalCostPassenger - tax; - costForDriver = fuelPrice * (20 / 210) * distance; + if (isInUniversity) { + Log.print('isInUniversity: ${isInUniversity}'); + totalPassengerComfort = + 20 + (costComfort + (costComfort * kazan / 100)).ceilToDouble(); + totalPassengerLady = + 20 + (costLady + (costLady * kazan / 100)).ceilToDouble(); + totalPassengerSpeed = + 20 + (costSpeed + (costSpeed * kazan / 100)).ceilToDouble(); + totalPassengerBalash = + 20 + (costBalash + (costBalash * kazan / 100)).ceilToDouble(); + totalPassengerRayehGai = + (costRayehGai + (costRayehGai * kazan / 100)).ceilToDouble(); + totalPassengerRayehGaiComfort = + (costRayehGaiComfort + (costRayehGaiComfort * kazan / 100)) + .ceilToDouble(); + totalPassengerRayehGaiBalash = + (costRayehGaiBalash + (costRayehGaiBalash * kazan / 100)) + .ceilToDouble(); + totalPassengerComfortDiscount = + totalPassengerComfort + totalPassengerComfort * (kazan - 0) / 100; + totalPassengerLadyDiscount = + totalPassengerLady + totalPassengerLady * (kazan - 0) / 100; + totalPassengerSpeedDiscount = + totalPassengerSpeed + totalPassengerSpeed * (kazan) / 100; + totalPassengerBalashDiscount = + totalPassengerBalash + totalPassengerBalash * (kazan) / 100; + totalPassengerRaihGaiDiscount = + totalPassengerRayehGai + totalPassengerRayehGai * (kazan) / 100; + totalPassengerScooter = + (costDelivery + (costDelivery * kazan / 100)).ceilToDouble(); + totalPassengerComfort = totalPassengerComfortDiscount - + (totalPassengerComfortDiscount * kazan / 100); + totalPassengerSpeed = totalPassengerSpeedDiscount - + (totalPassengerSpeedDiscount * kazan / 100); + totalPassengerBalash = totalPassengerBalashDiscount - + (totalPassengerBalashDiscount * kazan / 100); + totalPassengerLady = totalPassengerLadyDiscount - + (totalPassengerLadyDiscount * kazan / 100); + totalDriver = totalDriver1 + (totalDriver1 * kazan / 100); + tax = totalCostPassenger * kazan / 100; + totalME = totalCostPassenger - tax; + costForDriver = fuelPrice * (20 / 210) * distance; + } else { + Log.print('isInUniversity: ${isInUniversity}'); + totalPassengerComfort = + (costComfort + (costComfort * kazan / 100)).ceilToDouble(); + totalPassengerLady = + (costLady + (costLady * kazan / 100)).ceilToDouble(); + totalPassengerSpeed = + (costSpeed + (costSpeed * kazan / 100)).ceilToDouble(); + totalPassengerBalash = + (costBalash + (costBalash * kazan / 100)).ceilToDouble(); + totalPassengerRayehGai = + (costRayehGai + (costRayehGai * kazan / 100)).ceilToDouble(); + totalPassengerRayehGaiComfort = + (costRayehGaiComfort + (costRayehGaiComfort * kazan / 100)) + .ceilToDouble(); + totalPassengerRayehGaiBalash = + (costRayehGaiBalash + (costRayehGaiBalash * kazan / 100)) + .ceilToDouble(); + totalPassengerComfortDiscount = + totalPassengerComfort + totalPassengerComfort * (kazan - 0) / 100; + totalPassengerLadyDiscount = + totalPassengerLady + totalPassengerLady * (kazan - 0) / 100; + totalPassengerSpeedDiscount = + totalPassengerSpeed + totalPassengerSpeed * (kazan) / 100; + totalPassengerBalashDiscount = + totalPassengerBalash + totalPassengerBalash * (kazan) / 100; + totalPassengerRaihGaiDiscount = + totalPassengerRayehGai + totalPassengerRayehGai * (kazan) / 100; + totalPassengerScooter = + (costDelivery + (costDelivery * kazan / 100)).ceilToDouble(); + totalPassengerComfort = totalPassengerComfortDiscount - + (totalPassengerComfortDiscount * kazan / 100); + totalPassengerSpeed = totalPassengerSpeedDiscount - + (totalPassengerSpeedDiscount * kazan / 100); + totalPassengerBalash = totalPassengerBalashDiscount - + (totalPassengerBalashDiscount * kazan / 100); + totalPassengerLady = totalPassengerLadyDiscount - + (totalPassengerLadyDiscount * kazan / 100); + totalDriver = totalDriver1 + (totalDriver1 * kazan / 100); + tax = totalCostPassenger * kazan / 100; + totalME = totalCostPassenger - tax; + costForDriver = fuelPrice * (20 / 210) * distance; + } + if (totalPassengerSpeed < 20) { // for eygpt 20 le open ride totalCostPassenger = 20; @@ -3531,10 +3941,23 @@ class MapPassengerController extends GetxController { } addToken() async { - await CRUD().post(link: AppLink.addTokens, payload: { + await CRUD() + .post(link: "${AppLink.server}/ride/firebase/add.php", payload: { 'token': box.read(BoxName.tokenFCM), 'passengerID': box.read(BoxName.passengerID).toString() }); + CRUD().post( + link: "${AppLink.seferAlexandriaServer}/ride/firebase/add.php", + payload: { + 'token': box.read(BoxName.tokenFCM), + 'passengerID': box.read(BoxName.passengerID).toString() + }); + CRUD().post( + link: "${AppLink.seferGizaServer}/ride/firebase/add.php", + payload: { + 'token': box.read(BoxName.tokenFCM), + 'passengerID': box.read(BoxName.passengerID).toString() + }); } List polylineCoordinate = []; @@ -3724,7 +4147,7 @@ class MapPassengerController extends GetxController { } void startFetchingData() { - Timer.periodic(Duration(milliseconds: 50), (Timer timer) async { + Timer.periodic(const Duration(milliseconds: 50), (Timer timer) async { await getKazanPercent(); }); } @@ -3744,6 +4167,30 @@ class MapPassengerController extends GetxController { } } + firstTimeRunToGetCoupon(String promo, validity, discount) { + // Check if it's the first time and the app is installed and gift token is available + if (box.read(BoxName.isFirstTime).toString() == '0' && + box.read(BoxName.isInstall).toString() == '1' && + box.read(BoxName.isGiftToken).toString() == '0') { + // Show a full-screen modal styled as an ad + Get.dialog( + AlertDialog( + contentPadding: + EdgeInsets.zero, // Removes the padding around the content + content: SizedBox( + width: 300, // Match the width of PromoBanner + // height: 250, // Match the height of PromoBanner + child: PromoBanner( + promoCode: promo, + discountPercentage: discount, + validity: validity, + ), + ), + ), + ); + } + } + @override void onInit() async { mapAPIKEY = await storage.read(key: BoxName.mapAPIKEY); @@ -3756,8 +4203,10 @@ class MapPassengerController extends GetxController { addCustomStepIcon(); addCustomStartIcon(); addCustomEndIcon(); + addToken(); getLocation(); - + getPassengerLocationUniversity(); + _initializePolygons(); // await addToken(); getKazanPercent(); getPassengerRate(); @@ -3769,7 +4218,7 @@ class MapPassengerController extends GetxController { box.write(BoxName.tipPercentage, '0'); Get.put(AudioRecorderController()); // await getNearestDriverByPassengerLocation(); - + firstTimeRunToGetCoupon('SEFER25', '1 WEEEK', '25%'); initilizeGetStorage(); cardNumber = await SecureStorage().readData(BoxName.cardNumber); @@ -3779,9 +4228,9 @@ class MapPassengerController extends GetxController { uploadPassengerLocation() async { await CRUD().post(link: AppLink.addpassengerLocation, payload: { "passengerId": box.read(BoxName.passengerID), - "lat": passengerLocation.latitude, - "lng": passengerLocation.longitude, - "rideId": rideId + "lat": passengerLocation.latitude.toString(), + "lng": passengerLocation.longitude.toString(), + "rideId": rideId.toString() }); } } diff --git a/lib/controller/local/translations.dart b/lib/controller/local/translations.dart index 72ed9ef..5a8e001 100644 --- a/lib/controller/local/translations.dart +++ b/lib/controller/local/translations.dart @@ -606,6 +606,45 @@ iOS [https://getapp.cc/app/6458734951] 'الرَّجَاء التَّحَرُّك إِلَى السَّيَّارَة الآن', 'You will receive a code in WhatsApp Messenger': "سوف تتلقى رمزًا في واتساب ماسنجر", + 'If you need assistance, contact us': + "إذا كنت بحاجة إلى المساعدة، تواصل معنا", + "Promo Ended": "انتهى العرض", + 'Enter the promo code and get': 'أدخل رمز الترويج واحصل على', + 'DISCOUNT': 'خصم', + 'No wallet record found': 'لم يتم العثور على سجل محفظة', + 'for': 'لمدة', + "SEFER is the safest ride-sharing app that introduces many features for both captains and passengers. We offer the lowest commission rate of just 8%, ensuring you get the best value for your rides. Our app includes insurance for the best captains, regular maintenance of cars with top engineers, and on-road services to ensure a respectful and high-quality experience for all users.": + "سفر هو التطبيق الأكثر أمانًا لمشاركة الركوب الذي يقدم العديد من الميزات لكل من السائقين والركاب. نحن نقدم أقل عمولة بنسبة 8% فقط، مما يضمن حصولك على أفضل قيمة لرحلاتك. يتضمن تطبيقنا التأمين لأفضل السائقين، الصيانة المنتظمة للسيارات مع أفضل المهندسين، والخدمات على الطريق لضمان تجربة محترمة وعالية الجودة لجميع المستخدمين.", + "You can contact us during working hours from 12:00 - 19:00.": + "يمكنك الاتصال بنا خلال ساعات العمل من 12:00 - 7:00.", + "Contact Us": "اتصل بنا", + 'Choose a contact option': 'اختر خيار الاتصال', + 'Work time is from 12:00 - 19:00.\nYou can send a WhatsApp message or email.': + 'ساعات العمل من 12:00 - 19:00.\nيمكنك إرسال رسالة عبر واتساب أو بريد إلكتروني.', + 'Promo code copied to clipboard!': "'تم نسخ رمز العرض إلى الحافظة!'", + 'Copy Code': 'نسخ الرمز', + "Your invite code was successfully applied!": + "تم تطبيق رمز الدعوة بنجاح!", + "Payment Options": " خيارات الدفع", + "wait 1 minute to receive message": + "انتظر دقيقة واحدة لاستلام الرسالة", + 'Promo Copied!': 'تم نسخ العرض!', + 'You have copied the promo code.': 'لقد قمت بنسخ رمز العرض.', + 'Valid Until:': 'لمدة:', + "Select Payment Amount": " اختر مبلغ الدفع", + "The promotion period has ended.": "انتهت فترة العرض.", + "Promo Code Accepted": "تم قبول كود العرض", + 'Tap on the promo code to copy it!': 'اضغط على رمز العرض لنسخه!', + "Lowest Price Achieved": "تم الوصول إلى أدنى سعر", + "Cannot apply further discounts.": + "لا يمكن تطبيق المزيد من الخصومات.", + "Promo Already Used": "تم استخدام كود العرض بالفعل", + 'Invitation Used': "تم استخدام الدعوة", + "You have already used this promo code.": + "لقد استخدمت هذا الكود بالفعل.", + "Insert Your Promo Code": "أدخل كود العرض الخاص بك", + "Enter promo code here": "أدخل كود العرض هنا", + "Please enter a valid promo code": "يرجى إدخال كود عرض صالح", 'Awfar Car': 'أوفر كار', "Old and affordable, perfect for budget rides.": "سيارة ميسورة التكلفة، مثالية للرحلات الاقتصادية.", diff --git a/lib/controller/notification/passenger_notification_controller.dart b/lib/controller/notification/passenger_notification_controller.dart index 39a725b..062e162 100644 --- a/lib/controller/notification/passenger_notification_controller.dart +++ b/lib/controller/notification/passenger_notification_controller.dart @@ -1,13 +1,12 @@ import 'dart:convert'; +import 'package:SEFER/views/widgets/my_dialog.dart'; import 'package:get/get.dart'; import 'package:SEFER/controller/firebase/firbase_messge.dart'; import '../../constant/box_name.dart'; import '../../constant/links.dart'; -import '../../constant/style.dart'; import '../../main.dart'; -import '../../views/widgets/elevated_btn.dart'; import '../functions/crud.dart'; class PassengerNotificationController extends GetxController { @@ -21,22 +20,17 @@ class PassengerNotificationController extends GetxController { link: AppLink.getNotificationPassenger, payload: {'passenger_id': box.read(BoxName.passengerID)}); if (res == "failure") { - Get.defaultDialog( - title: 'There is no notification yet'.tr, - titleStyle: AppStyle.title, - middleText: '', - confirm: MyElevatedButton( - title: 'Back', - onPressed: () { - Get.back(); - Get.back(); - })); + MyDialog().getDialog('There is no notification yet'.tr, '', () { + Get.back(); + Get.back(); + }); + } else { + notificationData = jsonDecode(res); + isloading = false; + update(); } - notificationData = jsonDecode(res); - // sql.insertData(notificationData['message'], TableName.captainNotification); - isloading = false; - update(); + // sql.insertData(notificationData['message'], TableName.captainNotification); } updateNotification(String id) async { diff --git a/lib/controller/payment/passenger_wallet_history_controller.dart b/lib/controller/payment/passenger_wallet_history_controller.dart index 3ca4db3..0f7abd6 100644 --- a/lib/controller/payment/passenger_wallet_history_controller.dart +++ b/lib/controller/payment/passenger_wallet_history_controller.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:SEFER/constant/style.dart'; import 'package:SEFER/views/widgets/elevated_btn.dart'; +import 'package:SEFER/views/widgets/my_dialog.dart'; import 'package:get/get.dart'; import 'package:SEFER/constant/box_name.dart'; import 'package:SEFER/constant/links.dart'; @@ -23,17 +24,10 @@ class PassengerWalletHistoryController extends GetxController { isLoading = false; update(); } else { - Get.defaultDialog( - barrierDismissible: false, - title: 'No wallet record found'.tr, - titleStyle: AppStyle.title, - middleText: '', - confirm: MyElevatedButton( - title: 'OK'.tr, - onPressed: () { - Get.back(); - Get.back(); - })); + MyDialog().getDialog('No wallet record found'.tr, '', () { + Get.back(); + Get.back(); + }); } } diff --git a/lib/controller/payment/payment_controller.dart b/lib/controller/payment/payment_controller.dart index 6d39df7..b698d24 100644 --- a/lib/controller/payment/payment_controller.dart +++ b/lib/controller/payment/payment_controller.dart @@ -167,7 +167,7 @@ class PaymentController extends GetxController { ? '1140' : '0'); - getPassengerWallet(); + // getPassengerWallet(); isLoading = false; update(); @@ -698,24 +698,28 @@ class PaymentController extends GetxController { onPayment: (PaymobResponseWallet response) {}, ); - if (response!.success == true && response.responseCode == '200') { - Get.defaultDialog( - barrierDismissible: false, - title: 'Payment Successful'.tr, - titleStyle: AppStyle.title, - content: Text( - 'The payment was approved.'.tr, - style: AppStyle.title, - ), - confirm: MyElevatedButton( - title: 'OK'.tr, - kolor: AppColor.greenColor, - onPressed: () async { - Get.back(); - method(); - }, - ), - ); + // if (response!.success == true && response.responseCode == '200') { + if (response!.responseCode == '200' && response.success == true) { + // Log.print('transactionID wewer: ${response.transactionID}'); + Toast.show(context, 'Payment Successful'.tr, AppColor.greenColor); + method(); + // Get.defaultDialog( + // barrierDismissible: false, + // title: 'Payment Successful'.tr, + // titleStyle: AppStyle.title, + // content: Text( + // 'The payment was approved.'.tr, + // style: AppStyle.title, + // ), + // confirm: MyElevatedButton( + // title: 'OK'.tr, + // kolor: AppColor.greenColor, + // onPressed: () async { + // Get.back(); + // method(); + // }, + // ), + // ); } else { Get.defaultDialog( barrierDismissible: false, @@ -763,46 +767,49 @@ class PaymentController extends GetxController { billingData: PaymobBillingData(), onPayment: (PaymobResponse response) {}, ); - if (response!.success == true && response.responseCode == '200') { - if (response!.responseCode == 'APPROVED') { - Get.defaultDialog( - barrierDismissible: false, - title: 'Payment Successful'.tr, - titleStyle: AppStyle.title, - // backgroundColor: AppColor.greenColor, - content: Text( - 'The payment was approved.'.tr, - style: AppStyle.title, - ), - confirm: MyElevatedButton( - kolor: AppColor.greenColor, - title: 'OK'.tr, - onPressed: () async { - Get.back(); - method(); - }, - ), - ); - } else { - Get.defaultDialog( - barrierDismissible: false, - // backgroundColor: AppColor.redColor, - title: 'Payment Failed'.tr, - content: Text( - 'The payment was not approved. Please try again.'.tr, - textAlign: TextAlign.center, - style: AppStyle.title, - ), - confirm: MyElevatedButton( - title: 'OK'.tr, - kolor: AppColor.redColor, - onPressed: () async { - Get.back(); - }, - ), - ); - } + if (response!.responseCode == '200' && response.success == true) { + // if (response!.success == true && response.responseCode == '200') { + // if (response!.responseCode == 'APPROVED') { + Toast.show(context, 'Payment Successful'.tr, AppColor.greenColor); + method(); + // Get.defaultDialog( + // barrierDismissible: false, + // title: 'Payment Successful'.tr, + // titleStyle: AppStyle.title, + // // backgroundColor: AppColor.greenColor, + // content: Text( + // 'The payment was approved.'.tr, + // style: AppStyle.title, + // ), + // confirm: MyElevatedButton( + // kolor: AppColor.greenColor, + // title: 'OK'.tr, + // onPressed: () async { + // Get.back(); + // method(); + // }, + // ), + // ); + } else { + Get.defaultDialog( + barrierDismissible: false, + // backgroundColor: AppColor.redColor, + title: 'Payment Failed'.tr, + content: Text( + 'The payment was not approved. Please try again.'.tr, + textAlign: TextAlign.center, + style: AppStyle.title, + ), + confirm: MyElevatedButton( + title: 'OK'.tr, + kolor: AppColor.redColor, + onPressed: () async { + Get.back(); + }, + ), + ); } + // } } } catch (e) { Get.defaultDialog( diff --git a/lib/controller/rate/rate_conroller.dart b/lib/controller/rate/rate_conroller.dart index aa130b0..7a4531a 100644 --- a/lib/controller/rate/rate_conroller.dart +++ b/lib/controller/rate/rate_conroller.dart @@ -79,13 +79,33 @@ class RateController extends GetxController { } } } - await CRUD().post(link: AppLink.addRateToDriver, payload: { - 'passenger_id': box.read(BoxName.passengerID).toString(), - 'driver_id': driverId, - 'ride_id': rideId, - 'rating': selectedRateItemId.toString(), - 'comment': comment.text, - }).then((value) { + await CRUD().post( + link: "${AppLink.seferCairoServer}/rate/addRateToDriver.php", + payload: { + 'passenger_id': box.read(BoxName.passengerID).toString(), + 'driver_id': driverId, + 'ride_id': rideId, + 'rating': selectedRateItemId.toString(), + 'comment': comment.text, + }).then((value) { + CRUD().post( + link: "${AppLink.seferAlexandriaServer}/rate/addRateToDriver.php", + payload: { + 'passenger_id': box.read(BoxName.passengerID).toString(), + 'driver_id': driverId, + 'ride_id': rideId, + 'rating': selectedRateItemId.toString(), + 'comment': comment.text, + }); + CRUD().post( + link: "${AppLink.seferGizaServer}/rate/addRateToDriver.php", + payload: { + 'passenger_id': box.read(BoxName.passengerID).toString(), + 'driver_id': driverId, + 'ride_id': rideId, + 'rating': selectedRateItemId.toString(), + 'comment': comment.text, + }); Get.find().restCounter(); Get.offAll(const MapPagePassenger()); }); diff --git a/lib/models/model/painter_copoun.dart b/lib/models/model/painter_copoun.dart new file mode 100644 index 0000000..57cb560 --- /dev/null +++ b/lib/models/model/painter_copoun.dart @@ -0,0 +1,275 @@ +import 'dart:math' as math; +import 'package:SEFER/constant/box_name.dart'; +import 'package:SEFER/main.dart'; +import 'package:SEFER/splash_screen_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; + +class CouponPainter extends CustomPainter { + final Color primaryColor; + final Color secondaryColor; + + CouponPainter({ + required this.primaryColor, + required this.secondaryColor, + }); + + @override + void paint(Canvas canvas, Size size) { + final Paint primaryPaint = Paint() + ..color = primaryColor + ..style = PaintingStyle.fill; + + final Paint secondaryPaint = Paint() + ..color = secondaryColor + ..style = PaintingStyle.fill; + + final Path path = Path(); + + // Draw the main ticket shape + path.moveTo(0, size.height * 0.1); + path.lineTo(size.width * 0.93, size.height * 0.1); + path.arcToPoint( + Offset(size.width, size.height * 0.2), + radius: const Radius.circular(20), + clockwise: false, + ); + path.lineTo(size.width, size.height * 0.8); + path.arcToPoint( + Offset(size.width * 0.93, size.height * 0.9), + radius: const Radius.circular(20), + clockwise: false, + ); + path.lineTo(0, size.height * 0.9); + path.close(); + + canvas.drawPath(path, primaryPaint); + + // Draw decorative circles on the left side + for (int i = 0; i < 5; i++) { + canvas.drawCircle( + Offset(0, size.height * (0.2 + i * 0.15)), + 10, + secondaryPaint, + ); + } + + // Draw a wavy pattern on the right side + final wavePaint = Paint() + ..color = secondaryColor.withOpacity(0.3) + ..style = PaintingStyle.stroke + ..strokeWidth = 2; + + for (int i = 0; i < 20; i++) { + canvas.drawLine( + Offset(size.width * 0.8, i * 10.0), + Offset( + size.width, + i * 10.0 + math.sin(i * 0.5) * 10, + ), + wavePaint, + ); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => false; +} + +class PromoBanner extends StatelessWidget { + final String promoCode; + final String discountPercentage; + final String validity; + + const PromoBanner({ + Key? key, + required this.promoCode, + required this.discountPercentage, + required this.validity, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return CustomPaint( + painter: CouponPainter( + primaryColor: Colors.blue[800]!, + secondaryColor: Colors.white, + ), + child: Container( + width: 320, + height: 240, + padding: const EdgeInsets.all(16), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + const SizedBox( + height: 10, + ), + Text( + 'Enter the promo code and get'.tr, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + textAlign: TextAlign.center, + ), + Text( + '${'DISCOUNT'.tr} $discountPercentage ${'for'.tr} $validity' + .toUpperCase(), + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 10), + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Text( + promoCode, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.blue[800], + ), + ), + ), + const SizedBox(height: 10), + ElevatedButton( + onPressed: () { + // Copy promo code to clipboard + Clipboard.setData(ClipboardData(text: promoCode)); + // Show a Snackbar or other feedback to the user + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Promo code copied to clipboard!'.tr)), + ); + box.write(BoxName.isGiftToken, '1'); + Get.back(); + }, + style: ElevatedButton.styleFrom( + foregroundColor: Colors.blue[800], // Customize the color + backgroundColor: Colors.white, // Customize the background color + ), + child: Text('Copy Code'.tr), + ) + ], + ), + ), + ); + } +} + + + + + +// import 'package:SEFER/constant/colors.dart'; +// import 'package:flutter/cupertino.dart'; +// import 'package:flutter/material.dart'; + +// class CouponPainter extends CustomPainter { +// @override +// void paint(Canvas canvas, Size size) { +// final Paint paint = Paint() +// ..color = AppColor.blueColor +// ..style = PaintingStyle.fill; + +// final Path path = Path(); + +// // Draw the ticket shape (like the image) +// path.moveTo(0, 0); +// path.lineTo(size.width * 0.7, 0); // top left to top right edge + +// // Draw curve for the cut on the right side (ticket look) +// path.arcToPoint(Offset(size.width, size.height * 0.15), +// radius: const Radius.circular(15), clockwise: false); +// path.lineTo(size.width, size.height * 0.85); +// path.arcToPoint(Offset(size.width * 0.7, size.height), +// radius: const Radius.circular(15), clockwise: false); +// path.lineTo(0, size.height); + +// canvas.drawPath(path, paint); +// } + +// @override +// bool shouldRepaint(CustomPainter oldDelegate) { +// return false; +// } +// } + +// class PromoBanner extends StatelessWidget { +// final String promoCode; +// final String discountPercentage; +// final String validity; + +// const PromoBanner({ +// required this.promoCode, +// required this.discountPercentage, +// required this.validity, +// }); + +// @override +// Widget build(BuildContext context) { +// return CustomPaint( +// painter: CouponPainter(), +// child: Container( +// width: 300, // Fixed width for the promo banner +// height: 180, // Set the desired height for your banner +// padding: const EdgeInsets.all(16), +// child: Column( +// mainAxisAlignment: MainAxisAlignment.spaceAround, +// children: [ +// Text( +// 'Enter the promo code and get'.toUpperCase(), +// style: const TextStyle( +// fontSize: 16, +// fontWeight: FontWeight.bold, +// color: Colors.white, +// ), +// textAlign: TextAlign.center, +// ), +// Text( +// '$discountPercentage OFF for $validity'.toUpperCase(), +// style: const TextStyle( +// fontSize: 18, +// fontWeight: FontWeight.bold, +// color: Colors.white, +// ), +// textAlign: TextAlign.center, +// ), +// const SizedBox(height: 10), +// Container( +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(10), +// ), +// padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), +// child: Text( +// promoCode, +// style: TextStyle( +// fontSize: 20, +// fontWeight: FontWeight.bold, +// color: Colors.blue[800], +// ), +// ), +// ), +// ], +// ), +// ), +// ); +// } +// } diff --git a/lib/views/auth/login_page.dart b/lib/views/auth/login_page.dart index b8d14ce..b4d6405 100644 --- a/lib/views/auth/login_page.dart +++ b/lib/views/auth/login_page.dart @@ -17,6 +17,7 @@ import '../../constant/info.dart'; import '../../controller/auth/apple_signin_controller.dart'; import '../../controller/auth/google_sign.dart'; import '../../controller/auth/login_controller.dart'; +import '../home/HomePage/contact_us.dart'; import '../home/profile/passenger_profile_page.dart'; import '../widgets/mycircular.dart'; @@ -218,7 +219,7 @@ class LoginPage extends StatelessWidget { // ), InkWell( onTap: () async { - await GoogleSignInHelper.signInFromLogin(); + await GoogleSignInHelper().signInFromLogin(); }, child: Container( padding: const EdgeInsets.symmetric( @@ -303,6 +304,14 @@ class LoginPage extends StatelessWidget { SizedBox( height: Get.height * .1, ), + GestureDetector( + onTap: () => Get.to(() => ContactUsPage()), + child: Text( + 'If you need assistance, contact us' + .tr, // Improved wording + style: AppStyle.subtitle, + ), + ), // Text( // 'if you dont have account'.tr, // style: AppStyle.subtitle, diff --git a/lib/views/home/HomePage/contact_us.dart b/lib/views/home/HomePage/contact_us.dart new file mode 100644 index 0000000..58a104c --- /dev/null +++ b/lib/views/home/HomePage/contact_us.dart @@ -0,0 +1,102 @@ +import 'package:SEFER/constant/colors.dart'; +import 'package:SEFER/constant/style.dart'; +// ignore: unused_import +import 'package:SEFER/controller/functions/launch.dart'; +import 'package:SEFER/views/widgets/my_scafold.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_font_icons/flutter_font_icons.dart'; +import 'package:get/get.dart'; + +import '../../../controller/functions/tts.dart'; +import '../../../controller/home/contact_us_controller.dart'; + +class ContactUsPage extends StatelessWidget { + ContactUsPage({super.key}); + + @override + Widget build(BuildContext context) { + Get.put(ContactUsController()); + return GetBuilder(builder: (controller) { + return MyScafolld( + title: "Contact Us".tr, + body: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + decoration: AppStyle.boxDecoration1, + child: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(15), + child: Image.asset('assets/images/logo.gif')), + IconButton( + onPressed: () async { + Get.put(TextToSpeechController()).speakText( + 'SEFER is the safest ride-sharing app that introduces many features for both captains and passengers. We offer the lowest commission rate of just 8%, ensuring you get the best value for your rides. Our app includes insurance for the best captains, regular maintenance of cars with top engineers, and on-road services to ensure a respectful and high-quality experience for all users.' + .tr); + }, + icon: const Icon(Icons.headphones), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'SEFER is the safest ride-sharing app that introduces many features for both captains and passengers. We offer the lowest commission rate of just 8%, ensuring you get the best value for your rides. Our app includes insurance for the best captains, regular maintenance of cars with top engineers, and on-road services to ensure a respectful and high-quality experience for all users.' + .tr, + style: AppStyle.title, + textAlign: TextAlign.center, + ), + ), + ], + ), + ), + const SizedBox( + height: 30, + ), + Container( + decoration: AppStyle.boxDecoration1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "You can contact us during working hours from 12:00 - 19:00." + .tr, + style: AppStyle.title, + textAlign: TextAlign.center, + ), + ), + ), + InkWell( + onTap: () => controller.showContactDialog(context), + child: const Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Icon( + Icons.phone, + color: AppColor.blueColor, + ), + Icon( + FontAwesome.whatsapp, + color: AppColor.greenColor, + ), + Icon( + Icons.email, + color: AppColor.redColor, + ), + ], + ), + ), + const SizedBox( + height: 30, + ) + ], + ), + ) + ], + isleading: true); + }); + } +} diff --git a/lib/views/home/map_page_passenger.dart b/lib/views/home/map_page_passenger.dart index 29d8a81..b30a0f2 100644 --- a/lib/views/home/map_page_passenger.dart +++ b/lib/views/home/map_page_passenger.dart @@ -51,6 +51,7 @@ class MapPagePassenger extends StatelessWidget { CarDetailsTypeToChoose(), const HeaderDestination(), const BurcMoney(), + const PromoCode(), const ApplyOrderWidget(), const MapMenuWidget(), // hexagonClipper(), const CancelRidePageShow(), diff --git a/lib/views/home/map_widget.dart/apply_order_widget.dart b/lib/views/home/map_widget.dart/apply_order_widget.dart index b850503..fdbe9c8 100644 --- a/lib/views/home/map_widget.dart/apply_order_widget.dart +++ b/lib/views/home/map_widget.dart/apply_order_widget.dart @@ -33,6 +33,7 @@ class ApplyOrderWidget extends StatelessWidget { InkWell( onTap: () { if (box.read(BoxName.carType) == 'Speed' || + box.read(BoxName.carType) == 'Awfar Car' || box.read(BoxName.carType) == 'Delivery') { Get.snackbar( 'This price is'.tr + @@ -117,16 +118,24 @@ class ApplyOrderWidget extends StatelessWidget { : box.read(BoxName.carType) == 'Speed' ? 'assets/images/carspeed.png' : box.read(BoxName.carType) == - 'Delivery' + 'Scooter' ? 'assets/images/moto.png' : box.read(BoxName.carType) == - 'Mashwari' + 'Mishwar Vip' ? 'assets/images/freeRide.png' : box.read(BoxName .carType) == - 'Rayeh Gai' - ? 'assets/images/roundtrip.png' - : 'assets/images/carspeed.png', // Default image if none of the above + 'Awfar Car' + ? 'assets/images/balash.png' + : box.read(BoxName + .carType) == + 'Pink Bike' + ? 'assets/images/pinkBike.png' + : box.read(BoxName + .carType) == + 'Rayeh Gai' + ? 'assets/images/roundtrip.png' + : 'assets/images/carspeed.png', // Default image if none of the above width: 80, ), Column( @@ -159,11 +168,51 @@ class ApplyOrderWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ CircleAvatar( - radius: 30, + radius: 25, backgroundImage: NetworkImage( - // '', - // ), - '${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg'), + '${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg', + ), + child: Builder( + builder: (context) { + return Image.network( + '${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg', + fit: BoxFit.cover, + loadingBuilder: (BuildContext context, + Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) { + return child; // Image is loaded + } else { + return Center( + child: CircularProgressIndicator( + value: loadingProgress + .expectedTotalBytes != + null + ? loadingProgress + .cumulativeBytesLoaded / + (loadingProgress + .expectedTotalBytes ?? + 1) + : null, + ), + ); + } + }, + errorBuilder: (BuildContext context, + Object error, + StackTrace? stackTrace) { + return const Icon( + Icons + .person, // Icon to show when image fails to load + size: + 25, // Adjust the size as needed + color: AppColor + .blueColor, // Color for the error icon + ); + }, + ); + }, + ), ), Column( children: [ @@ -196,7 +245,8 @@ class ApplyOrderWidget extends StatelessWidget { 'message From passenger', 'Hello, I\'m at the agreed-upon location' .tr, - controller.driverToken, + controller.driverToken + .toString(), 'ding.wav', ); Get.back(); diff --git a/lib/views/home/map_widget.dart/car_details_widget_to_go.dart b/lib/views/home/map_widget.dart/car_details_widget_to_go.dart index 118c54f..aa6b2ff 100644 --- a/lib/views/home/map_widget.dart/car_details_widget_to_go.dart +++ b/lib/views/home/map_widget.dart/car_details_widget_to_go.dart @@ -1,11 +1,14 @@ import 'package:SEFER/constant/box_name.dart'; import 'package:SEFER/constant/colors.dart'; import 'package:SEFER/constant/style.dart'; +import 'package:SEFER/controller/home/blinking_promo_controller.dart.dart'; import 'package:SEFER/main.dart'; import 'package:SEFER/views/home/profile/passenger_profile_page.dart'; import 'package:SEFER/views/widgets/elevated_btn.dart'; import 'package:SEFER/views/widgets/my_dialog.dart'; +import 'package:SEFER/views/widgets/my_textField.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_confetti/flutter_confetti.dart'; import 'package:get/get.dart'; import '../../../constant/info.dart'; @@ -158,35 +161,35 @@ class CarDetailsTypeToChoose extends StatelessWidget { carType.carType == 'Comfort' ? mapPassengerController .totalPassengerComfort - .toStringAsFixed(2) + .toStringAsFixed(1) : carType.carType == 'Speed' ? mapPassengerController .totalPassengerSpeed - .toStringAsFixed(2) + .toStringAsFixed(1) : carType.carType == 'Awfar Car' ? mapPassengerController .totalPassengerBalash - .toStringAsFixed(2) + .toStringAsFixed(1) : carType.carType == 'Scooter' ? mapPassengerController .totalPassengerScooter - .toStringAsFixed(2) + .toStringAsFixed(1) : carType.carType == 'Lady' ? mapPassengerController .totalPassengerLady - .toStringAsFixed(2) + .toStringAsFixed(1) : carType.carType == 'Pink Bike' ? mapPassengerController .totalPassengerScooter .toStringAsFixed( - 2) + 1) : carType.carType == 'Rayeh Gai' ? mapPassengerController .totalPassengerRayehGai .toStringAsFixed( - 2) + 1) : '50', style: AppStyle.title.copyWith(fontSize: 20), @@ -203,7 +206,18 @@ class CarDetailsTypeToChoose extends StatelessWidget { decoration: AppStyle.boxDecoration1, child: Text( - '-12%', + mapPassengerController + .promoTaken + ? mapPassengerController + .totalPassengerComfortDiscount + .toStringAsFixed( + 1) + : (mapPassengerController + .totalPassengerComfortDiscount - + mapPassengerController + .totalPassengerComfort) + .toStringAsFixed( + 1), style: AppStyle.subtitle .copyWith( color: AppColor @@ -214,8 +228,15 @@ class CarDetailsTypeToChoose extends StatelessWidget { ), Text( mapPassengerController - .totalPassengerComfortDiscount - .toStringAsFixed(2), + .promoTaken + ? (mapPassengerController + .totalPassengerComfortDiscount + + mapPassengerController + .totalPassengerComfort) + .toStringAsFixed(1) + : mapPassengerController + .totalPassengerComfortDiscount + .toStringAsFixed(1), style: AppStyle.title.copyWith( color: AppColor.redColor, @@ -235,7 +256,18 @@ class CarDetailsTypeToChoose extends StatelessWidget { decoration: AppStyle .boxDecoration1, child: Text( - '-10%', + mapPassengerController + .promoTaken + ? mapPassengerController + .totalPassengerSpeedDiscount + .toStringAsFixed( + 1) + : (mapPassengerController + .totalPassengerSpeedDiscount - + mapPassengerController + .totalPassengerSpeed) + .toStringAsFixed( + 1), style: AppStyle .subtitle .copyWith( @@ -247,8 +279,17 @@ class CarDetailsTypeToChoose extends StatelessWidget { ), Text( mapPassengerController - .totalPassengerSpeedDiscount - .toStringAsFixed(2), + .promoTaken + ? (mapPassengerController + .totalPassengerSpeedDiscount + + mapPassengerController + .totalPassengerSpeed) + .toStringAsFixed( + 1) + : mapPassengerController + .totalPassengerSpeedDiscount + .toStringAsFixed( + 1), style: AppStyle.title .copyWith( color: @@ -263,14 +304,25 @@ class CarDetailsTypeToChoose extends StatelessWidget { 'Awfar Car' && (mapPassengerController .totalPassengerBalash > - 15) + 20) ? Row( children: [ Container( decoration: AppStyle .boxDecoration1, child: Text( - '-10%', + mapPassengerController + .promoTaken + ? mapPassengerController + .totalPassengerBalashDiscount + .toStringAsFixed( + 1) + : (mapPassengerController + .totalPassengerBalashDiscount - + mapPassengerController + .totalPassengerBalash) + .toStringAsFixed( + 1), style: AppStyle .subtitle .copyWith( @@ -282,9 +334,17 @@ class CarDetailsTypeToChoose extends StatelessWidget { ), Text( mapPassengerController - .totalPassengerBalashDiscount - .toStringAsFixed( - 2), + .promoTaken + ? (mapPassengerController + .totalPassengerBalashDiscount + + mapPassengerController + .totalPassengerBalash) + .toStringAsFixed( + 1) + : mapPassengerController + .totalPassengerBalashDiscount + .toStringAsFixed( + 1), style: AppStyle.title .copyWith( color: AppColor @@ -306,7 +366,15 @@ class CarDetailsTypeToChoose extends StatelessWidget { decoration: AppStyle .boxDecoration1, child: Text( - '-10%', + mapPassengerController + .promoTaken + ? mapPassengerController + .totalPassengerLadyDiscount + .toStringAsFixed( + 1) + : (mapPassengerController.totalPassengerLadyDiscount - + mapPassengerController.totalPassengerLady) + .toStringAsFixed(0), style: AppStyle .subtitle .copyWith( @@ -318,9 +386,17 @@ class CarDetailsTypeToChoose extends StatelessWidget { ), Text( mapPassengerController - .totalPassengerLadyDiscount - .toStringAsFixed( - 2), + .promoTaken + ? (mapPassengerController + .totalPassengerLadyDiscount + + mapPassengerController + .totalPassengerLady) + .toStringAsFixed( + 0) + : mapPassengerController + .totalPassengerLadyDiscount + .toStringAsFixed( + 1), style: AppStyle .title .copyWith( @@ -624,11 +700,88 @@ class CarDetailsTypeToChoose extends StatelessWidget { title: 'Next'.tr, onPressed: () { Get.back(); - mapPassengerController - .isBottomSheetShown = false; - mapPassengerController.update(); - mapPassengerController - .changeCashConfirmPageShown(); + + Get.defaultDialog( + barrierDismissible: false, + title: + "Select betweeen types".tr, + content: Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Container( + decoration: AppStyle + .boxDecoration1, + child: Padding( + padding: + const EdgeInsets + .all(8.0), + child: Column( + children: [ + Text('Awfar Car' + .tr), + Text(mapPassengerController + .totalPassengerRayehGaiBalash + .toStringAsFixed( + 0)), + ], + ), + )), + Container( + decoration: AppStyle + .boxDecoration1, + child: Padding( + padding: + const EdgeInsets + .all(8.0), + child: Column( + children: [ + Text('Speed'.tr), + Text(mapPassengerController + .totalPassengerRayehGai + .toStringAsFixed( + 0)), + ], + ), + )), + Container( + decoration: AppStyle + .boxDecoration1, + child: Padding( + padding: + const EdgeInsets + .all(8.0), + child: Column( + children: [ + Text( + 'Comfort'.tr), + Text(mapPassengerController + .totalPassengerRayehGaiComfort + .toStringAsFixed( + 0)), + ], + ), + )) + ], + ), + cancel: MyElevatedButton( + kolor: AppColor.redColor, + title: 'Cancel'.tr, + onPressed: () => + Get.back()), + confirm: MyElevatedButton( + kolor: AppColor.greenColor, + title: 'Next'.tr, + onPressed: () { + mapPassengerController + .isBottomSheetShown = + false; + mapPassengerController + .update(); + mapPassengerController + .changeCashConfirmPageShown(); + })); }), cancel: MyElevatedButton( title: 'Cancel'.tr, @@ -656,6 +809,87 @@ class CarDetailsTypeToChoose extends StatelessWidget { } } +class PromoCode extends StatelessWidget { + const PromoCode({super.key}); + + @override + Widget build(BuildContext context) { + Get.put(BlinkingController()); + return GetBuilder( + builder: (mapPassengerController) { + return mapPassengerController.data.isNotEmpty && + mapPassengerController.isBottomSheetShown && + mapPassengerController.rideConfirm == false && + mapPassengerController.promoTaken == false + ? GetBuilder(builder: (blinkingController) { + blinkingController.startBlinking(); + return Positioned( + right: 5, + bottom: Get.height * 0.5, + child: Obx(() { + return AnimatedContainer( + duration: const Duration(milliseconds: 500), + width: 70, // Circle size + height: 70, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: blinkingController.isLightOn.value + ? Colors.yellow + : Colors.grey, // Light on/off effect + border: Border.all( + color: blinkingController + .borderColor.value, // Animated border color + width: 3, + ), + ), + child: IconButton( + onPressed: () { + Get.defaultDialog( + title: 'Insert Your Promo Code'.tr, + content: Form( + key: mapPassengerController.promoFormKey, + child: MyTextForm( + controller: mapPassengerController.promo, + label: 'Insert Your Promo Code'.tr, + hint: 'Enter promo code here'.tr, + type: TextInputType.name, + ), + ), + confirm: MyElevatedButton( + title: 'Ok'.tr, + onPressed: () { + if (mapPassengerController + .promoFormKey.currentState! + .validate()) { + mapPassengerController + .applyPromoCodeToPassenger(context); + Get.back(); + } + })); + }, + icon: const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.local_offer, size: 24), // Promo icon + SizedBox(height: 4), + Text( + "Promo", + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.bold), + ), + ], + ), + ), + ); + }), + ); + }) + : const SizedBox(); + }, + ); + } +} + class BurcMoney extends StatelessWidget { const BurcMoney({super.key}); diff --git a/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart b/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart index 0db1089..f306cb1 100644 --- a/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart +++ b/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart @@ -168,7 +168,8 @@ class CashConfirmPageShown extends StatelessWidget { paymentController.update(); controller.changeCashConfirmPageShown(); controller.isSearchingWindow = true; - controller.confirmRideForFirstDriver(); + controller + .confirmRideForAllDriverAvailable(); controller.update(); }, ), @@ -179,7 +180,7 @@ class CashConfirmPageShown extends StatelessWidget { onPressed: () { controller.changeCashConfirmPageShown(); controller.isSearchingWindow = true; - controller.confirmRideForFirstDriver(); + controller.confirmRideForAllDriverAvailable(); controller.update(); }, ), // Add a fallback widget if none of the conditions are met diff --git a/lib/views/home/map_widget.dart/google_map_passenger_widget.dart b/lib/views/home/map_widget.dart/google_map_passenger_widget.dart index 3b439b9..bd2417b 100644 --- a/lib/views/home/map_widget.dart/google_map_passenger_widget.dart +++ b/lib/views/home/map_widget.dart/google_map_passenger_widget.dart @@ -318,7 +318,7 @@ class GoogleMapPassengerWidget extends StatelessWidget { // icon: controller.endIcon, // ), // }, - + polygons: controller.polygons, polylines: { Polyline( zIndex: 2, diff --git a/lib/views/home/map_widget.dart/left_main_menu_icons.dart b/lib/views/home/map_widget.dart/left_main_menu_icons.dart index 65478ee..4ec375f 100644 --- a/lib/views/home/map_widget.dart/left_main_menu_icons.dart +++ b/lib/views/home/map_widget.dart/left_main_menu_icons.dart @@ -9,6 +9,7 @@ import '../../../controller/firebase/firbase_messge.dart'; import '../../../controller/functions/audio_record1.dart'; import '../../../controller/functions/tts.dart'; import '../../../controller/home/map_passenger_controller.dart'; +import '../../../print.dart'; GetBuilder leftMainMenuIcons() { final textToSpeechController = Get.put(TextToSpeechController()); @@ -121,50 +122,58 @@ GetBuilder leftMainMenuIcons() { // borderRadius: BorderRadius.circular(15)), // child: IconButton( // onPressed: () async { - // // Get.to(SmsSignupEgypt()); - // List d = [ - // "30.003028,31.2419628", - // "30.0955661,31.2665336", - // "160.00", - // "25.92", - // "1488", - // "16.93", - // "114243034311436865474", - // "113172279072358305645", - // "hamza ayed", - // "rlMbi4Hc8L1STMPE99iPKqK4Gddwv8r9qZOCadsz9qTEJZ6KLEE9ruTJI6N8dKfK4CXez5pme5WIs14-1QGo29s07fQOniZgIlJV5XFL3yqzPRSUmn3", - // "+201023248456", - // "1 min", - // "1 m", - // "false", - // "QwUMoyUtZ0J3oR6yXKUavrB_gBl9npUZe-qZtax-Raq4QBbdKv0AmtLKm0BfBd6N_592HBv4CVa41ii4122W3hr-BCUKKzJhzZcK8m0YjbWbtpvgJRD8uD_nuMk9", - // "0", - // "238", - // "false", - // "114243034311436865474", - // "1488", - // "startEnd", - // "30.049307749732176,31.274291574954987", - // "", - // "", - // "", - // "", - // "17.73", - // "0", - // "hamzaayedflutter@gmail.com", - // "الفسطاط، حي مصر القديمة، مصر", - // " الزاوية الحمراء، محافظة القاهرة، مصر", - // "Speed", - // "8", - // "5.00" - // ]; - // FirebaseMessagesController().sendNotificationToDriverMAP( - // 'Order'.tr, - // 'from: ', - // // jsonDecode(value)['message'].toString(), - // 'd3JaCCFAQeu8QTxRnlC1sB:APA91bFuRjbVK32obIFYXFTI4iwsZEPrrgwvPouob2bXivID-W4aXz51J_OIJ2nHpNU2ocOvGLD1Ip65rLViAFx5qHVE-c8FabBwBi5fSQ-lDTQfe36xxKsc9DU-sTyj_FoYrrMnLNVi', - // d, - // 'order.wav'); + // Get.to(SmsSignupEgypt()); + // List d = [ + // "30.003028,31.2419628", + // "30.0955661,31.2665336", + // "160.00", + // "25.92", + // "1488", + // "16.93", + // "114243034311436865474", + // "113172279072358305645", + // "hamza ayed", + // "rlMbi4Hc8L1STMPE99iPKqK4Gddwv8r9qZOCadsz9qTEJZ6KLEE9ruTJI6N8dKfK4CXez5pme5WIs14-1QGo29s07fQOniZgIlJV5XFL3yqzPRSUmn3", + // "+201023248456", + // "1 min", + // "1 m", + // "false", + // "QwUMoyUtZ0J3oR6yXKUavrB_gBl9npUZe-qZtax-Raq4QBbdKv0AmtLKm0BfBd6N_592HBv4CVa41ii4122W3hr-BCUKKzJhzZcK8m0YjbWbtpvgJRD8uD_nuMk9", + // "0", + // "238", + // "false", + // "114243034311436865474", + // "1488", + // "startEnd", + // "30.049307749732176,31.274291574954987", + // "", + // "", + // "", + // "", + // "17.73", + // "0", + // "hamzaayedflutter@gmail.com", + // "الفسطاط، حي مصر القديمة، مصر", + // " الزاوية الحمراء، محافظة القاهرة، مصر", + // "Speed", + // "8", + // "5.00" + // ]; + + // FirebaseMessagesController() + // .sendNotificationToAnyWithoutData( + // 'Cancel'.tr, + // "How much longer will you be?".tr, + // 'fKBBB4_1R0q18-byySHUeG:APA91bHk2RmjjMt6eKr7KQnqh4CK02yW3H5E8g_beVcQFgiCG50j9KCtSU1O8PtvS_gA5xuJLhaorDV9AeslcyLFJFf302tICKMiKgsDP5pWkF5WXNw0-4NsoD-BnJxf0-Do9Vs1Zbpq', + // // d, + // 'ding.wav', + // ); + + // Get.to(SmsSignupEgypt()); + // Log.print( + // 'getUpdatedRideForDriverApply: ${Get.find().driverToken}'); + // Get.find() + // .firstTimeRunToGetCoupon('SEFER25', '1 WEEEK', '25%'); // }, // icon: const Icon( // Icons.chat, diff --git a/lib/views/home/map_widget.dart/map_menu_widget.dart b/lib/views/home/map_widget.dart/map_menu_widget.dart index 01971a6..8082df7 100644 --- a/lib/views/home/map_widget.dart/map_menu_widget.dart +++ b/lib/views/home/map_widget.dart/map_menu_widget.dart @@ -1,3 +1,4 @@ +import 'package:SEFER/views/home/HomePage/contact_us.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_font_icons/flutter_font_icons.dart'; @@ -110,10 +111,10 @@ class MapMenuWidget extends StatelessWidget { ), IconMainPageMap( onTap: () { - Get.to(() => const TaarifPage()); + Get.to(() => ContactUsPage()); }, - title: 'Tariff'.tr, - icon: Icons.money, + title: "Contact Us".tr, + icon: Icons.contact_page, ), ], ), diff --git a/lib/views/home/map_widget.dart/select_driver_mishwari.dart b/lib/views/home/map_widget.dart/select_driver_mishwari.dart index 04dbccb..5e8d466 100644 --- a/lib/views/home/map_widget.dart/select_driver_mishwari.dart +++ b/lib/views/home/map_widget.dart/select_driver_mishwari.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../constant/api_key.dart'; +import '../../../constant/links.dart'; class CupertinoDriverListWidget extends StatelessWidget { MapPassengerController mapPassengerController = @@ -30,9 +31,39 @@ class CupertinoDriverListWidget extends StatelessWidget { leading: CircleAvatar( radius: 25, backgroundImage: NetworkImage( - '${AK.serverPHP}/portrate_captain_image/${driver['id']}.jpg', + '${AppLink.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg', + ), + child: Builder( + builder: (context) { + return Image.network( + '${AppLink.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg', + fit: BoxFit.cover, + loadingBuilder: (BuildContext context, Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) { + return child; // Image is loaded + } else { + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + (loadingProgress.expectedTotalBytes ?? 1) + : null, + ), + ); + } + }, + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return const Icon( + Icons.person, // Icon to show when image fails to load + size: 25, // Adjust the size as needed + color: AppColor.blueColor, // Color for the error icon + ); + }, + ); + }, ), - backgroundColor: CupertinoColors.systemGrey5, ), title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -65,12 +96,12 @@ class CupertinoDriverListWidget extends StatelessWidget { Text('${'Plate'.tr}: ${driver['car_plate']}'), ], ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('${'Education'.tr}: ${driver['education']}'), - ], - ), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Text('${'Education'.tr}: ${driver['education']}'), + // ], + // ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/views/home/my_wallet/passenger_wallet.dart b/lib/views/home/my_wallet/passenger_wallet.dart index de06b3b..1bbe5f9 100644 --- a/lib/views/home/my_wallet/passenger_wallet.dart +++ b/lib/views/home/my_wallet/passenger_wallet.dart @@ -1,3 +1,5 @@ +import 'package:SEFER/views/widgets/my_dialog.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -10,6 +12,8 @@ import '../../../controller/functions/toast.dart'; import '../../../controller/home/payment/credit_card_controller.dart'; import '../../../controller/payment/payment_controller.dart'; import '../../../main.dart'; +import '../../../models/model/painter_copoun.dart'; +import '../../../print.dart'; import '../../widgets/elevated_btn.dart'; import '../../widgets/my_scafold.dart'; import '../../widgets/my_textField.dart'; @@ -29,25 +33,49 @@ class PassengerWallet extends StatelessWidget { GetBuilder( builder: (controller) => Column( mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const CardSeferWallet(), const SizedBox( height: 20, ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Row( - children: [ - MyElevatedButton( - kolor: AppColor.blueColor, - title: 'Payment History'.tr, - onPressed: () { - Get.to(() => const PaymentHistoryPassengerPage(), - transition: Transition.size); - }, - ), - ], + padding: + const EdgeInsets.symmetric(horizontal: 80, vertical: 10), + child: MyElevatedButton( + kolor: AppColor.blueColor, + title: 'Payment History'.tr, + onPressed: () { + Get.to(() => const PaymentHistoryPassengerPage(), + transition: Transition.size); + }, + ), + ), + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 80, vertical: 10), + child: MyElevatedButton( + kolor: AppColor.yellowColor, + title: 'Bounus gift'.tr, + onPressed: () { + Get.dialog( + AlertDialog( + contentPadding: EdgeInsets + .zero, // Removes the padding around the content + content: SizedBox( + width: 300, // Match the width of PromoBanner + // height: 250, // Match the height of PromoBanner + child: PromoBanner( + promoCode: box.read(BoxName.promo), + discountPercentage: box.read(BoxName.discount), + validity: box.read(BoxName.validity), + ), + ), + ), + ); + Log.print( + 'box.read(BoxName.isGiftToken).toString(): ${box.read(BoxName.isGiftToken).toString()}'); + }, ), ) ], @@ -65,6 +93,7 @@ class PassengerWallet extends StatelessWidget { left: Get.width * .2, right: Get.width * .2, child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ MyElevatedButton( title: 'Show Promos to Charge'.tr, @@ -79,36 +108,58 @@ class PassengerWallet extends StatelessWidget { kolor: AppColor.deepPurpleAccent, title: "Add wallet phone you use".tr, onPressed: () { - Get.defaultDialog( - barrierDismissible: false, - title: 'Insert Wallet phone number'.tr, - content: Form( - key: controller.formKey, - child: MyTextForm( + Get.dialog( + CupertinoAlertDialog( + title: Text('Insert Wallet phone number'.tr), + content: Column( + children: [ + const SizedBox(height: 10), + Form( + key: controller.formKey, + child: CupertinoTextField( controller: controller.walletphoneController, - label: 'Insert Wallet phone number'.tr, - hint: 'Insert Wallet phone number'.tr, - type: TextInputType.phone)), - confirm: MyElevatedButton( - kolor: AppColor.greenColor, - title: 'OK'.tr, - onPressed: () async { - Get.back(); - box.write(BoxName.phoneWallet, - controller.walletphoneController.text); - Toast.show( - context, - 'Phone Wallet Saved Successfully'.tr, - AppColor.greenColor); - }, + placeholder: + 'Insert Wallet phone number'.tr, + keyboardType: TextInputType.phone, + padding: const EdgeInsets.symmetric( + vertical: 12, horizontal: 10), + ), + ), + ], ), - cancel: MyElevatedButton( - title: 'Cancel'.tr, - kolor: AppColor.redColor, + actions: [ + CupertinoDialogAction( + child: Text('Cancel'.tr, + style: const TextStyle( + color: CupertinoColors + .destructiveRed)), onPressed: () { - Get.back(); - })); + Get.back(); // Dismiss the dialog + }, + ), + CupertinoDialogAction( + child: Text('OK'.tr, + style: const TextStyle( + color: + CupertinoColors.activeGreen)), + onPressed: () async { + Get.back(); // Close the dialog + box.write( + BoxName.phoneWallet, + controller + .walletphoneController.text); + Toast.show( + context, + 'Phone Wallet Saved Successfully'.tr, + AppColor.greenColor); + }, + ), + ], + ), + barrierDismissible: + false, // Set to prevent dismissing by tapping outside + ); }) ], ), @@ -120,70 +171,71 @@ class PassengerWallet extends StatelessWidget { } class CardSeferWallet extends StatelessWidget { - const CardSeferWallet({ - super.key, - }); + const CardSeferWallet({super.key}); @override Widget build(BuildContext context) { - return GetBuilder(builder: (paymentController) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: Get.width * .85, - height: Get.height * .3, - decoration: BoxDecoration( - color: AppColor.twitterColor.withOpacity(.8), - borderRadius: const BorderRadius.all(Radius.circular(12)), - gradient: const LinearGradient(colors: [ - AppColor.redColor, - AppColor.yellowColor, - AppColor.yellowColor, - ]), - ), + return GetBuilder( + builder: (paymentController) { + return Container( + width: Get.width * 0.9, + height: Get.height * 0.25, + margin: const EdgeInsets.all(16.0), + decoration: BoxDecoration( + color: CupertinoColors.extraLightBackgroundGray, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + offset: const Offset(0, 10), + blurRadius: 20, + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(16.0), child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Text( - '${AppInformation.appName} Wallet', - style: AppStyle.headTitle - .copyWith(color: AppColor.writeColor), - ) - ], + // Wallet Title + Text( + '${AppInformation.appName} Wallet', + style: AppStyle.headTitle.copyWith( + color: CupertinoColors.label, + fontSize: 20, + fontWeight: FontWeight.bold, ), ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - '${box.read(BoxName.passengerWalletTotal)} \$' ?? - '0.0 \$', - style: AppStyle.headTitle2, - ) - ], - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - box.read(BoxName.name), - style: AppStyle.title, - ) - ], + + // Wallet Balance + Center( + child: Text( + '${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${'LE'.tr}', + style: AppStyle.headTitle2.copyWith( + color: CupertinoColors.label, + fontSize: 36, + fontWeight: FontWeight.w600, + ), ), - ) + ), + + // User Name (Bottom Right) + Align( + alignment: Alignment.bottomRight, + child: Text( + box.read(BoxName.name), + style: AppStyle.title.copyWith( + color: CupertinoColors.secondaryLabel, + fontSize: 16, + ), + ), + ), ], ), ), - ], - ); - }); + ); + }, + ); } } diff --git a/lib/views/home/my_wallet/passenger_wallet_dialoge.dart b/lib/views/home/my_wallet/passenger_wallet_dialoge.dart index 531ebae..2cd8009 100644 --- a/lib/views/home/my_wallet/passenger_wallet_dialoge.dart +++ b/lib/views/home/my_wallet/passenger_wallet_dialoge.dart @@ -1,6 +1,6 @@ -import 'package:SEFER/constant/box_name.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; import 'package:get/get.dart'; +import 'package:SEFER/constant/box_name.dart'; import 'package:SEFER/constant/colors.dart'; import 'package:SEFER/constant/style.dart'; import 'package:SEFER/controller/functions/toast.dart'; @@ -8,7 +8,6 @@ import 'package:SEFER/controller/payment/payment_controller.dart'; import 'package:SEFER/views/widgets/elevated_btn.dart'; import '../../../main.dart'; -import '../../widgets/my_textField.dart'; class PassengerWalletDialog extends StatelessWidget { const PassengerWalletDialog({ @@ -19,294 +18,198 @@ class PassengerWalletDialog extends StatelessWidget { Widget build(BuildContext context) { return GetBuilder( builder: (controller) => Positioned( - top: Get.height * .1, - right: Get.width * .15, - left: Get.width * .15, - bottom: Get.height * .1, - child: controller.isPromoSheetDialogue - ? Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(12)), - color: AppColor.secondaryColor, - boxShadow: [ - BoxShadow( - color: AppColor.accentColor, - offset: Offset(-1, -1), - blurRadius: 0, - spreadRadius: 0, - blurStyle: BlurStyle.normal), - BoxShadow( - color: AppColor.accentColor, - offset: Offset(3, 3), - blurRadius: 1, - spreadRadius: 0, - blurStyle: BlurStyle.normal) - ]), - child: Padding( - padding: const EdgeInsets.all(6), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - controller.updateSelectedAmount(10); - }, - child: Row( - children: [ - Radio( - value: box.read(BoxName.countryCode) == 'Egypt' - ? 100 - : 10, - groupValue: controller.selectedAmount, - onChanged: (value) { - controller.updateSelectedAmount(value as int); - }, - ), - Text( - box.read(BoxName.countryCode) == 'Egypt' - ? '100 ${'LE'.tr}'.tr - : '10 ${'JOD'.tr}'.tr, - style: AppStyle.title, - ), - ], + top: Get.height * .1, + right: Get.width * .15, + left: Get.width * .15, + bottom: Get.height * .1, + child: controller.isPromoSheetDialogue + ? CupertinoActionSheet( + title: Text('Select Payment Amount'.tr), + actions: [ + CupertinoActionSheetAction( + onPressed: () { + controller.updateSelectedAmount( + box.read(BoxName.countryCode) == 'Egypt' ? 100 : 10, + ); + showPaymentOptions(context, controller); + }, + child: Text( + box.read(BoxName.countryCode) == 'Egypt' + ? '100 ${'LE'.tr}' + : '10 ${'JOD'.tr}', + ), + ), + CupertinoActionSheetAction( + onPressed: () { + controller.updateSelectedAmount( + box.read(BoxName.countryCode) == 'Egypt' ? 200 : 20, + ); + showPaymentOptions(context, controller); + }, + child: Text( + box.read(BoxName.countryCode) == 'Egypt' + ? '200 ${'LE'.tr} = 205 ${'LE'.tr}' + : '20 ${'JOD'.tr}', + ), + ), + CupertinoActionSheetAction( + onPressed: () { + controller.updateSelectedAmount( + box.read(BoxName.countryCode) == 'Egypt' ? 400 : 40, + ); + showPaymentOptions(context, controller); + }, + child: Text( + box.read(BoxName.countryCode) == 'Egypt' + ? '400 ${'LE'.tr} = 415 ${'LE'.tr}' + : '40 ${'JOD'.tr}', + ), + ), + CupertinoActionSheetAction( + onPressed: () { + controller.updateSelectedAmount( + box.read(BoxName.countryCode) == 'Egypt' ? 1000 : 50, + ); + showPaymentOptions(context, controller); + }, + child: Text( + box.read(BoxName.countryCode) == 'Egypt' + ? '1000 ${'LE'.tr} = 1100 ${'LE'.tr}' + : '50 ${'JOD'.tr}', + ), + ), + ], + cancelButton: CupertinoActionSheetAction( + onPressed: () { + controller.changePromoSheetDialogue(); + }, + child: Text('Cancel'.tr), + ), + ) + : const SizedBox(), + ), + ); + } +} + +void showPaymentOptions(BuildContext context, PaymentController controller) { + showCupertinoModalPopup( + context: context, + builder: (context) => CupertinoActionSheet( + title: Text('Payment Options'.tr), + actions: [ + box.read(BoxName.countryCode) == 'Egypt' + ? CupertinoActionSheetAction( + child: Text('💳 Pay with Credit Card'.tr), + onPressed: () { + if (controller.selectedAmount != 0) { + controller.payWithPayMob( + context, + controller.selectedAmount.toString(), + box.read(BoxName.countryCode) == 'Egypt' ? 'EGP' : 'JOD', + () async { + await controller.addPassengerWallet(); + controller.changePromoSheetDialogue(); + await controller.getPassengerWallet(); + }, + ); + } else { + Toast.show(context, '⚠️ You need to choose an amount!'.tr, + AppColor.redColor); + } + }, + ) + : const SizedBox(), + box.read(BoxName.countryCode) != 'Egypt' + ? CupertinoActionSheetAction( + child: Text('Pay with PayPal'.tr), + onPressed: () { + if (controller.selectedAmount != 0) { + controller.makePaymentPayPal(context); + } else { + Toast.show(context, 'You will choose one of above!'.tr, + AppColor.redColor); + } + }, + ) + : const SizedBox(), + box.read(BoxName.phoneWallet) != null + ? CupertinoActionSheetAction( + child: Text('💰 Pay with Wallet'.tr), + onPressed: () { + if (controller.selectedAmount != 0) { + controller.payWithPayMobWallet( + context, + controller.selectedAmount.toString(), + box.read(BoxName.countryCode) == 'Egypt' ? 'EGP' : 'JOD', + () async { + await controller.addPassengerWallet(); + controller.changePromoSheetDialogue(); + await controller.getPassengerWallet(); + }, + ); + } else { + Toast.show(context, '⚠️ You need to choose an amount!'.tr, + AppColor.redColor); + } + }, + ) + : CupertinoActionSheetAction( + child: Text('Add wallet phone you use'.tr), + onPressed: () { + Get.dialog( + CupertinoAlertDialog( + title: Text('Insert Wallet phone number'.tr), + content: Column( + children: [ + const SizedBox(height: 10), + CupertinoTextField( + controller: controller.walletphoneController, + placeholder: 'Insert Wallet phone number'.tr, + keyboardType: TextInputType.phone, + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 10, + ), ), - ), - GestureDetector( - onTap: () { - controller.updateSelectedAmount(20); - }, - child: Row( - children: [ - Radio( - value: - box.read(BoxName.countryCode) == 'Egypt' - ? 210 - : 20, - groupValue: controller.selectedAmount, - onChanged: (value) { - controller - .updateSelectedAmount(value as int); - }, - ), - Text( - box.read(BoxName.countryCode) == 'Egypt' - ? '${'200 ${'LE'.tr} '.tr} = 205 ${'LE'.tr}' - : '20 ${'JOD'.tr}'.tr, - style: AppStyle.title, - ), - ], - )), - GestureDetector( - onTap: () { - controller.updateSelectedAmount(40); - }, - child: Row( - children: [ - Radio( - value: - box.read(BoxName.countryCode) == 'Egypt' - ? 415 - : 40, - groupValue: controller.selectedAmount, - onChanged: (value) { - controller - .updateSelectedAmount(value as int); - }, - ), - Text( - box.read(BoxName.countryCode) == 'Egypt' - ? '${'400 ${'LE'.tr} '.tr} = 415 ${'LE'.tr}' - : '40 ${'JOD'.tr}'.tr, - style: AppStyle.title, - ), - ], - )), - GestureDetector( - onTap: () { - controller.updateSelectedAmount(100); - }, - child: Row( - children: [ - Radio( - value: - box.read(BoxName.countryCode) == 'Egypt' - ? 1100 - : 50, - groupValue: controller.selectedAmount, - onChanged: (value) { - controller - .updateSelectedAmount(value as int); - }, - ), - Text( - box.read(BoxName.countryCode) == 'Egypt' - ? '${'1000 ${'LE'.tr} '.tr} = 1100 ${'LE'.tr}' - : '50 ${'JOD'.tr}'.tr, - style: AppStyle.title, - ), - ], - )), - const Spacer(), - box.read(BoxName.countryCode) == 'Egypt' - ? const SizedBox() - : MyElevatedButton( - kolor: AppColor.blueColor, - title: '${'Pay with Your'.tr} PayPal', - onPressed: () { - if (controller.selectedAmount != 0) { - controller.makePaymentPayPal(context); - } else { - Toast.show( - context, - 'You will choose one of above !'.tr, - AppColor.redColor); - } - }, - ), - box.read(BoxName.countryCode) == 'Egypt' - ? box.read(BoxName.phoneWallet) != null - ? Column( - children: [ - MyElevatedButton( - title: '💳 Pay with Credit Card'.tr, - onPressed: () { - if (controller.selectedAmount != 0) { - controller.payWithPayMob( - context, - controller.selectedAmount - .toString(), // Convert int to double - box.read(BoxName.countryCode) == - 'Egypt' - ? 'EGP' - : 'JOD', - () async { - await controller - .addPassengerWallet(); - controller - .changePromoSheetDialogue(); - await controller - .getPassengerWallet(); - }, - ); - } else { - Toast.show( - context, - '⚠️ You need to choose an amount!' - .tr, - AppColor.redColor, - ); - } - }, - ), - // Add some spacing between buttons - MyElevatedButton( - kolor: AppColor.yellowColor, - title: '💰 Pay with Wallet'.tr, - onPressed: () { - if (controller.selectedAmount != 0) { - controller.payWithPayMobWallet( - context, - controller.selectedAmount - .toString(), // Convert int to double - box.read(BoxName.countryCode) == - 'Egypt' - ? 'EGP' - : 'JOD', - () async { - await controller - .addPassengerWallet(); - controller - .changePromoSheetDialogue(); - await controller - .getPassengerWallet(); - }, - ); - } else { - Toast.show( - context, - '⚠️ You need to choose an amount!' - .tr, - AppColor.redColor, - ); - } - }, - ), - ], - ) - : MyElevatedButton( - title: 'Pay with Credit Card'.tr, - onPressed: () { - if (controller.selectedAmount != 0) { - controller.makePaymentStripe( - controller.selectedAmount! - .toDouble(), // Convert int to double - box.read(BoxName.countryCode) != - 'Egypt' - ? 'usd' - : 'jod', () { - controller.addPassengerWallet(); - controller.changePromoSheetDialogue(); - controller.getPassengerWallet(); - }); - } else { - Toast.show( - context, - 'You will choose one of above !'.tr, - AppColor.redColor); - } - }) - : MyElevatedButton( - kolor: AppColor.deepPurpleAccent, - title: "Add wallet phone you use".tr, - onPressed: () { - Get.defaultDialog( - barrierDismissible: false, - title: 'Insert Wallet phone number'.tr, - content: Form( - key: controller.formKey, - child: MyTextForm( - controller: controller - .walletphoneController, - label: - 'Insert Wallet phone number' - .tr, - hint: 'Insert Wallet phone number' - .tr, - type: TextInputType.phone)), - confirm: MyElevatedButton( - kolor: AppColor.greenColor, - title: 'OK'.tr, - onPressed: () async { - Get.back(); - box.write( - BoxName.phoneWallet, - controller - .walletphoneController.text); - Toast.show( - context, - 'Phone Wallet Saved Successfully' - .tr, - AppColor.greenColor); - }, - ), - cancel: MyElevatedButton( - title: 'Cancel'.tr, - kolor: AppColor.redColor, - onPressed: () { - Get.back(); - })); - }), - MyElevatedButton( - title: 'Cancel'.tr, - kolor: AppColor.redColor, + ], + ), + actions: [ + CupertinoDialogAction( + child: Text('Cancel'.tr, + style: const TextStyle( + color: CupertinoColors.destructiveRed)), onPressed: () { - controller.changePromoSheetDialogue(); + Get.back(); + }, + ), + CupertinoDialogAction( + child: Text('OK'.tr, + style: const TextStyle( + color: CupertinoColors.activeGreen)), + onPressed: () async { + Get.back(); + box.write(BoxName.phoneWallet, + controller.walletphoneController.text); + Toast.show( + context, + 'Phone Wallet Saved Successfully'.tr, + AppColor.greenColor); }, ), ], ), - )) - : const SizedBox()), - ); - } + barrierDismissible: false, + ); + }, + ), + ], + cancelButton: CupertinoActionSheetAction( + child: Text('Cancel'.tr), + onPressed: () { + controller.changePromoSheetDialogue(); + }, + ), + ), + ); } diff --git a/lib/views/home/my_wallet/payment_history_passenger_page.dart b/lib/views/home/my_wallet/payment_history_passenger_page.dart index 5a33d50..f3ab954 100644 --- a/lib/views/home/my_wallet/payment_history_passenger_page.dart +++ b/lib/views/home/my_wallet/payment_history_passenger_page.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:SEFER/constant/colors.dart'; @@ -17,7 +18,7 @@ class PaymentHistoryPassengerPage extends StatelessWidget { body: [ GetBuilder( builder: (controller) => controller.isLoading - ? const MyCircularProgressIndicator() + ? const MyCircularProgressIndicator() // iOS-style loading indicator : controller.archive.isEmpty ? Center( child: Text( @@ -25,37 +26,33 @@ class PaymentHistoryPassengerPage extends StatelessWidget { style: AppStyle.title, ), ) - : ListView.builder( - itemCount: controller.archive.length, - itemBuilder: (BuildContext context, int index) { - var list = controller.archive[index]; - return Padding( - padding: const EdgeInsets.all(4), - child: Container( - decoration: BoxDecoration( - color: double.parse(list['balance']) < 0 - ? AppColor.redColor.withOpacity(.4) - : AppColor.greenColor.withOpacity(.4)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - list['balance'], - style: AppStyle.title, - ), - Text( - list['created_at'], - style: AppStyle.title, - ), - ], + : CupertinoListSection.insetGrouped( + children: List.generate( + controller.archive.length, + (index) { + var list = controller.archive[index]; + return CupertinoListTile( + backgroundColor: double.parse(list['balance']) < 0 + ? AppColor.redColor.withOpacity(.2) + : AppColor.greenColor.withOpacity(.2), + title: Text( + list['balance'], + style: AppStyle.title.copyWith( + color: CupertinoColors.black, ), ), - ), - ); - }, + additionalInfo: Text( + list['created_at'], + style: AppStyle.title.copyWith( + fontSize: 12, + color: CupertinoColors.systemGrey, + ), + ), + padding: const EdgeInsets.symmetric( + vertical: 8, horizontal: 16), + ); + }, + ), ), ) ], diff --git a/lib/views/home/profile/promos_passenger_page.dart b/lib/views/home/profile/promos_passenger_page.dart index e22b8ce..1d995d4 100644 --- a/lib/views/home/profile/promos_passenger_page.dart +++ b/lib/views/home/profile/promos_passenger_page.dart @@ -1,5 +1,7 @@ import 'package:animated_text_kit/animated_text_kit.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:SEFER/controller/home/profile/promos_controller.dart'; import 'package:SEFER/views/widgets/my_scafold.dart'; @@ -106,13 +108,26 @@ class PromosPassengerPage extends StatelessWidget { } else { // Promo items final rides = orderHistoryController.promoList[index - 1]; + return Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(12.0), child: Container( - decoration: AppStyle.boxDecoration, + decoration: BoxDecoration( + color: CupertinoColors.systemGrey6, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: + CupertinoColors.systemGrey.withOpacity(0.5), + blurRadius: 8, + offset: Offset(0, 4), + ), + ], + ), child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(16.0), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: @@ -122,50 +137,88 @@ class PromosPassengerPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ - AnimatedTextKit( - animatedTexts: [ - ScaleAnimatedText( - rides['promo_code'], - textStyle: AppStyle.title), - WavyAnimatedText( - rides['promo_code'], - textStyle: AppStyle.title), - FlickerAnimatedText( - rides['promo_code'], - textStyle: AppStyle.title), - WavyAnimatedText( - rides['promo_code'], - textStyle: AppStyle.title), - ], - isRepeatingAnimation: true, + GestureDetector( onTap: () {}, + child: AnimatedTextKit( + animatedTexts: [ + ScaleAnimatedText( + rides['promo_code'], + textStyle: + AppStyle.title.copyWith( + fontSize: + 32, // Increased font size for emphasis + color: CupertinoColors + .activeBlue, + fontWeight: FontWeight.bold, + ), + ), + WavyAnimatedText( + rides['promo_code'], + textStyle: + AppStyle.title.copyWith( + fontSize: + 32, // Increased font size for emphasis + color: CupertinoColors + .activeBlue, + fontWeight: FontWeight.bold, + ), + ), + ], + isRepeatingAnimation: true, + ), ), + const SizedBox(height: 8), + // Description Text Text( rides['description'], - style: AppStyle.title, + style: AppStyle.title.copyWith( + fontSize: 22, + color: CupertinoColors.systemGrey, + ), ), ], ), Column( children: [ + // Only displaying end date Text( - rides['validity_start_date'], - style: AppStyle.title, - ), - Text( - rides['validity_end_date'], - style: AppStyle.title, + '${'Valid Until:'.tr} ${rides['validity_end_date']}', + style: AppStyle.subtitle.copyWith( + fontWeight: FontWeight.bold, + fontSize: 20, + color: CupertinoColors.systemGrey, + ), ), ], ), ], ), - Text( - 'Copy this Promo to use it in your Ride!'.tr, - textAlign: TextAlign.center, - style: AppStyle.headTitle2 - .copyWith(color: AppColor.accentColor), - ) + // const SizedBox(height: 16), + // Copy Promo Text + Center( + child: GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData( + text: rides['promo_code'])); + Get.snackbar( + 'Promo Copied!'.tr, + 'You have copied the promo code.'.tr, + snackPosition: SnackPosition.BOTTOM, + backgroundColor: + CupertinoColors.systemGrey, + colorText: CupertinoColors.white, + ); + }, + child: Text( + 'Copy Code'.tr, + textAlign: TextAlign.center, + style: AppStyle.headTitle2.copyWith( + color: CupertinoColors.systemBlue, + fontWeight: FontWeight.bold, + ), + ), + ), + ), ], ), ), diff --git a/lib/views/notification/notification_page.dart b/lib/views/notification/notification_page.dart index 873479a..5752137 100644 --- a/lib/views/notification/notification_page.dart +++ b/lib/views/notification/notification_page.dart @@ -1,10 +1,10 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:SEFER/constant/colors.dart'; import 'package:SEFER/constant/style.dart'; import '../../controller/notification/passenger_notification_controller.dart'; -import '../widgets/elevated_btn.dart'; import '../widgets/my_scafold.dart'; import '../widgets/mycircular.dart'; @@ -19,64 +19,82 @@ class NotificationPage extends StatelessWidget { title: 'Notifications', body: [ GetBuilder( - builder: (notificationCaptainController) => - notificationCaptainController.isloading - ? const MyCircularProgressIndicator() - : SafeArea( - child: ListView.builder( - itemCount: notificationCaptainController - .notificationData['message'].length, - itemBuilder: (BuildContext context, int index) { - if (notificationCaptainController - .notificationData['message'] == - "No notification data found") { - Get.defaultDialog(); - } - var res = notificationCaptainController - .notificationData['message'][index]; - return Card( - elevation: 4, - color: res['isShown'] == 'true' - ? AppColor.secondaryColor.withOpacity(.5) - : AppColor.secondaryColor.withOpacity(.9), - child: ListTile( - onTap: () { - Get.defaultDialog( - title: res['title'], - titleStyle: AppStyle.title, - content: SizedBox( - width: Get.width * .8, - // height: Get.height * .4, - child: Text( - res['body'], - style: AppStyle.title, - ), - ), - confirm: MyElevatedButton( - title: 'Ok', - onPressed: () { - notificationCaptainController - .updateNotification( - res['id'].toString()); - })); - }, - leading: res['isShown'] == 'true' - ? const Icon( - Icons.notifications_off_outlined) - : const Icon(Icons.notifications_active), - title: Text( - res['title'], - style: AppStyle.title, - ), - subtitle: Text( - res['body'], - style: AppStyle.subtitle, - ), - ), + builder: (notificationCaptainController) => notificationCaptainController + .isloading + ? const MyCircularProgressIndicator() // iOS-style loading indicator + : SafeArea( + child: ListView.builder( + itemCount: notificationCaptainController + .notificationData['message'].length, + itemBuilder: (BuildContext context, int index) { + if (notificationCaptainController + .notificationData['message'] == + "No notification data found") { + Get.defaultDialog( + title: 'No Notifications'.tr, + content: Text( + 'No notification data found.'.tr, + ), + ); + } + var res = notificationCaptainController + .notificationData['message'][index]; + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + child: CupertinoListTile( + backgroundColor: res['isShown'] == 'true' + ? AppColor.secondaryColor.withOpacity(.2) + : AppColor.secondaryColor.withOpacity(.8), + leading: res['isShown'] == 'true' + ? const Icon(CupertinoIcons.bell_slash_fill) + : const Icon(CupertinoIcons.bell_fill), + title: Text( + res['title'], + style: AppStyle.title.copyWith( + color: CupertinoColors.black, + ), + ), + subtitle: Text( + res['body'], + style: AppStyle.subtitle.copyWith( + color: CupertinoColors.systemGrey, + ), + ), + onTap: () { + showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text( + res['title'], + style: AppStyle.title, + ), + content: Text( + res['body'], + style: AppStyle.subtitle, + ), + actions: [ + CupertinoDialogAction( + child: const Text('Ok'), + onPressed: () { + notificationCaptainController + .updateNotification( + res['id'].toString()); + Get.back(); + }, + ), + ], + ); + }, ); }, ), - )) + ); + }, + ), + ), + ) ], ); } diff --git a/lib/views/widgets/my_dialog.dart b/lib/views/widgets/my_dialog.dart index 0608a88..335d8e4 100644 --- a/lib/views/widgets/my_dialog.dart +++ b/lib/views/widgets/my_dialog.dart @@ -1,5 +1,6 @@ import 'dart:ui'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -11,34 +12,98 @@ import 'elevated_btn.dart'; class MyDialog extends GetxController { void getDialog(String title, String? midTitle, VoidCallback onPressed) { final textToSpeechController = Get.put(TextToSpeechController()); - Get.defaultDialog( - title: title, - titleStyle: AppStyle.title, - barrierDismissible: false, - middleTextStyle: AppStyle.title, - content: Column( - children: [ - IconButton( + + Get.dialog( + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: CupertinoAlertDialog( + title: Text( + title, + style: AppStyle.title.copyWith( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + content: Column( + children: [ + CupertinoButton( onPressed: () async { await textToSpeechController.speakText(title ?? midTitle!); }, - icon: const Icon(Icons.headphones)), - Text( - midTitle!, - style: AppStyle.title, - ) + child: const Icon(CupertinoIcons.headphones, + color: AppColor.primaryColor), + ), + Text( + midTitle!, + style: AppStyle.title.copyWith(fontSize: 16), + ), + ], + ), + actions: [ + CupertinoDialogAction( + child: const Text('Cancel', + style: TextStyle(color: AppColor.redColor)), + onPressed: () { + Get.back(); + }, + ), + CupertinoDialogAction( + onPressed: onPressed, + child: Text('OK'.tr, + style: const TextStyle(color: AppColor.greenColor)), + ), ], ), - confirm: MyElevatedButton( - title: 'Ok'.tr, - onPressed: onPressed, - kolor: AppColor.greenColor, - ), - cancel: MyElevatedButton( - title: 'Cancel', - kolor: AppColor.redColor, - onPressed: () { - Get.back(); - })); + ), + barrierDismissible: false, + ); + } +} + +class MyDialogContent extends GetxController { + void getDialog(String title, Widget? content, VoidCallback onPressed) { + final textToSpeechController = Get.put(TextToSpeechController()); + + Get.dialog( + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: CupertinoAlertDialog( + title: Text( + title, + style: AppStyle.title.copyWith( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + content: Column( + children: [ + CupertinoButton( + onPressed: () async { + await textToSpeechController.speakText(title); + }, + child: const Icon(CupertinoIcons.headphones, + color: AppColor.primaryColor), + ), + content! + ], + ), + actions: [ + CupertinoDialogAction( + child: const Text('Cancel', + style: TextStyle(color: AppColor.redColor)), + onPressed: () { + Get.back(); + }, + ), + CupertinoDialogAction( + onPressed: onPressed, + child: Text('OK'.tr, + style: const TextStyle(color: AppColor.greenColor)), + ), + ], + ), + ), + barrierDismissible: false, + ); } } diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index d53ef64..8e02df2 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true diff --git a/pubspec.lock b/pubspec.lock index 7633e1c..b7ac582 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -491,6 +491,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" + flutter_confetti: + dependency: "direct main" + description: + name: flutter_confetti + sha256: "7a0f586a0295b1dad6be364a82c59b8579e1cc8af99b0cba0461b6fabd60ff78" + url: "https://pub.dev" + source: hosted + version: "0.3.0" flutter_font_icons: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 392b1fb..cb6fd4d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -61,6 +61,7 @@ dependencies: package_info_plus: ^8.0.0 uni_links: ^0.5.1 googleapis_auth: ^1.6.0 + flutter_confetti: ^0.3.0 # intl_phone_field: ^3.1.0 dev_dependencies: