diff --git a/android/app/build.gradle b/android/app/build.gradle index 2dafa76..155c906 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -55,8 +55,8 @@ android { // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion 23 targetSdkVersion 34 - versionCode 55 - versionName '1.5.55' + versionCode 56 + versionName '1.5.56' // manifestPlaceholders = [mapsApiKey: 'android/app/src/main/AndroidManifest.xml'] } diff --git a/lib/constant/box_name.dart b/lib/constant/box_name.dart index 3e1e04e..e6332df 100644 --- a/lib/constant/box_name.dart +++ b/lib/constant/box_name.dart @@ -6,12 +6,14 @@ class BoxName { static const String lang = "lang"; static const String gender = "gender"; static const String carType = "carType"; + static const String isFirstTime = "isFirstTime"; static const String deviceInfo = "deviceInfo"; static const String packagInfo = "packagInfo"; static const String phoneVerified = "phoneVerified"; static const String carPlate = "carPlate"; static const String statusDriverLocation = "statusDriverLocation"; static const String rideStatus = "rideStatus"; + static const String nameArabic = "nameArabic"; static const String password = "password"; static const String isVerified = '0'; static const String arrivalTime = "arrivalTime"; diff --git a/lib/constant/info.dart b/lib/constant/info.dart index 4cc090b..0f4b47e 100644 --- a/lib/constant/info.dart +++ b/lib/constant/info.dart @@ -7,6 +7,8 @@ class AppInformation { 'https://www.linkedin.com/in/hamza-ayed/'; static const String website = 'https://sefer.live'; static const String email = 'hamzaayed@sefer.live'; + static const String complaintPrompt = + 'for this data for complaint from driver or passenger i collect all data i want you analyze this complaint and show what is reason and what is solution .this data collected from many table to find solution if payment in visa not complete and if ride status is finished it will be paymnet in payment table if ride status is not finished there is no need to pay and payment table is null for this ride and if paymentFromPaymentTable not null and visa type not cash the payment sucssessed . if ratingpassenger is low or passengr rating drivers low grade then dont mine of this passenger ,look at driver too like passengerratingdriver with rating or ratingtopassenger .in json add status of complaint and message to passenger and message to driver and message to call center write in arabic in json output with key in english .for output please just json i want'; static const String privacyPolicy = ''' diff --git a/lib/constant/links.dart b/lib/constant/links.dart index 5bfc4d7..d96e78e 100644 --- a/lib/constant/links.dart +++ b/lib/constant/links.dart @@ -198,6 +198,12 @@ class AppLink { //===================Auth============ + static String addInviteDriver = "$server/ride/invitor/add.php"; + static String getInviteDriver = "$server/ride/invitor/get.php"; + static String updateInviteDriver = "$server/ride/invitor/update.php"; + + //===================Auth============ + static String auth = '$server/auth'; static String login = "$auth/login.php"; static String signUp = "$auth/signup.php"; @@ -211,6 +217,7 @@ class AppLink { static String loginFromGoogleCaptin = "$authCaptin/loginFromGoogle.php"; static String packageInfo = "$server/auth/packageInfo.php"; static String signUpCaptin = "$authCaptin/register.php"; + static String addCriminalDocuments = "$authCaptin/addCriminalDocuments.php"; static String sendVerifyEmailCaptin = "$authCaptin/sendVerifyEmail.php"; static String sendVerifyOtpMessage = "$server/auth/captin/sendOtpMessageDriver.php"; @@ -244,4 +251,11 @@ class AppLink { static String sendmany = "https://sms.kazumi.me/api/sms/send-many"; static String checkCredit = "https://sms.kazumi.me/api/sms/check-credit"; static String checkStatus = "https://sms.kazumi.me/api/sms/check-status"; + + //////////////service/////////// + + static String serviceApp = "$server/serviceApp"; + static String getComplaintAllData = "$serviceApp/getComplaintAllData.php"; + static String getComplaintAllDataForDriver = + "$serviceApp/getComplaintAllDataForDriver.php"; } diff --git a/lib/controller/auth/captin/invit_controller.dart b/lib/controller/auth/captin/invit_controller.dart new file mode 100644 index 0000000..baa037c --- /dev/null +++ b/lib/controller/auth/captin/invit_controller.dart @@ -0,0 +1,119 @@ +import 'dart:convert'; + +import 'package:SEFER/constant/box_name.dart'; +import 'package:SEFER/constant/links.dart'; +import 'package:SEFER/controller/functions/crud.dart'; +import 'package:SEFER/controller/home/payment/captain_wallet_controller.dart'; +import 'package:SEFER/views/widgets/mydialoug.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../../main.dart'; +import '../../functions/launch.dart'; +import '../../notification/notification_captain_controller.dart'; + +class InviteController extends GetxController { + final TextEditingController invitePhoneController = TextEditingController(); + List driverInvitationData = []; + + @override + void onInit() { + super.onInit(); + // fetchDriverStats(); + } + + void fetchDriverStats() async { + try { + var response = await CRUD().get(link: AppLink.getInviteDriver, payload: { + "driverId": box.read(BoxName.driverID), + }); + if (response != 'failure') { + var data = jsonDecode(response); + driverInvitationData = data['message']; + update(); + // print('driverInitationData: $driverInitationData'); + } + } catch (e) { + print('Error fetching driver stats: $e'); + } + } + + void onSelectDriverInvitation(int index) async { + MyDialog().getDialog( + driverInvitationData[index]['countOfInvitDriver'] < 100 + ? '${'When'.tr} ${driverInvitationData[index]['invitorName']} ${"complete, you can claim your gift".tr} ' + : 'You deserve the gift'.tr, + '${driverInvitationData[index]['invitorName']} ${driverInvitationData[index]['countOfInvitDriver']} / 100 ${'Trip'.tr}', + () async { + if (driverInvitationData[index]['countOfInvitDriver'] < 100) { + Get.back(); + } else { + //claim your gift + if (driverInvitationData[index]['isGiftToken'].toString() == '0') { + Get.back(); + await Get.find() + .addDriverWallet('paymentMethod', '500'); + // add for invitor too + await Get.find().addDriverWalletToInvitor( + 'paymentMethod', + driverInvitationData[index]['driverInviterId'], + '500'); + await CRUD().post( + link: AppLink.updateInviteDriver, + payload: {'id': driverInvitationData[index]['id']}); + NotificationCaptainController().addNotificationCaptain( + driverInvitationData[index]['driverInviterId'].toString(), + "You have got a gift for invitation".tr, + '${"You have 500".tr} ${'LE'}', + false); + } else { + Get.back(); + MyDialog().getDialog("You have got a gift".tr, + "Share the app with another new driver".tr, () { + Get.back(); + }); + } + } + }, + ); + } + + void sendInvite() async { + if (invitePhoneController.text.isEmpty) { + Get.snackbar('Error', 'Please enter an phone address'.tr); + return; + } + + // try { + var response = await CRUD().post(link: AppLink.addInviteDriver, payload: { + "driverId": box.read(BoxName.driverID), + "inviterDriverPhone": '+2${invitePhoneController.text}' + }); + + if (response != 'failure') { + var d = jsonDecode(response); + Get.snackbar('Success', 'Invite sent successfully'.tr); + + String message = '${'*SEFER DRIVER CODE*'.tr}\n\n' + '${"Use this code in registration".tr}\n' + '${"To get a gift for both".tr}\n\n' + '${"The period of this code is 1 hour".tr}\n\n' + '${'before'.tr} *${d['message']['expirationTime'].toString()}*\n\n' + '_*${d['message']['inviteCode'].toString()}*_\n\n' + '${"Install our app:".tr}\n' + 'Android: https://play.google.com/store/apps/details?id=com.sefer_driver\n' + 'iOS: https://apps.apple.com/ae/app/sefer-driver/id6502189302'; + + launchCommunication( + 'whatsapp', '+2${invitePhoneController.text}', message); + + invitePhoneController.clear(); + } else { + Get.snackbar('Error', 'Failed to send invite'.tr); + } + // } catch (e) { + // print('Error sending invite: $e'); + // Get.snackbar('Error', 'An error occurred'.tr); + // } + } +} diff --git a/lib/controller/auth/captin/login_captin_controller.dart b/lib/controller/auth/captin/login_captin_controller.dart index 9c1ebe2..505bf56 100644 --- a/lib/controller/auth/captin/login_captin_controller.dart +++ b/lib/controller/auth/captin/login_captin_controller.dart @@ -76,6 +76,7 @@ class LoginDriverController extends GetxController { box.write(BoxName.phoneVerified, jsonDecoeded['data'][0]['is_verified'].toString()); box.write(BoxName.phoneDriver, jsonDecoeded['data'][0]['phone']); + box.write(BoxName.nameArabic, jsonDecoeded['data'][0]['name_arabic']); box.write( BoxName.bankCodeDriver, jsonDecoeded['data'][0]['bankCode']); box.write(BoxName.accountBankNumberDriver, diff --git a/lib/controller/auth/captin/register_captin_controller.dart b/lib/controller/auth/captin/register_captin_controller.dart index 8c6db90..6a478bc 100644 --- a/lib/controller/auth/captin/register_captin_controller.dart +++ b/lib/controller/auth/captin/register_captin_controller.dart @@ -106,7 +106,8 @@ class RegisterCaptainController extends GetxController { await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: { 'phone_number': '+2${phoneController.text}', 'token_code': randomNumber.toString(), - "driverId": box.read(BoxName.driverID) + "driverId": box.read(BoxName.driverID), + "email": box.read(BoxName.emailDriver), }); await smsEgyptController.sendSmsEgypt( @@ -120,7 +121,8 @@ class RegisterCaptainController extends GetxController { await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: { 'phone_number': '+2${phoneController.text}', 'token_code': randomNumber.toString(), - "driverId": box.read(BoxName.driverID) + "driverId": box.read(BoxName.driverID), + "email": box.read(BoxName.emailDriver), }); await smsEgyptController.sendSmsEgypt( diff --git a/lib/controller/firebase/firbase_messge.dart b/lib/controller/firebase/firbase_messge.dart index 34e80ee..71fbf0d 100644 --- a/lib/controller/firebase/firbase_messge.dart +++ b/lib/controller/firebase/firbase_messge.dart @@ -13,6 +13,7 @@ import '../../constant/box_name.dart'; import '../../constant/colors.dart'; import '../../constant/style.dart'; import '../../main.dart'; +import '../../views/auth/captin/criminal_documents_page.dart'; import '../../views/home/Captin/home_captain/home_captin.dart'; import '../../views/home/Captin/orderCaptin/order_speed_request.dart'; import '../../views/home/Captin/orderCaptin/order_request_page.dart'; @@ -167,6 +168,13 @@ class FirebaseMessagesController extends GetxController { // // remoteID: driverList[2].toString(), // )); } catch (e) {} + } else if (message.notification!.title! == "Criminal Document Required") { + NotificationController().showNotification( + "Criminal Document Required".tr, + message.notification!.body!, + 'tone2', + ); + Get.to(() => const CriminalDocumemtPage()); } else if (message.notification!.title! == 'Call End'.tr) { try { var myListString = message.data['passengerList']; diff --git a/lib/controller/functions/crud.dart b/lib/controller/functions/crud.dart index d7f32a8..6db4302 100644 --- a/lib/controller/functions/crud.dart +++ b/lib/controller/functions/crud.dart @@ -27,6 +27,7 @@ class CRUD { 'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}', }, ); + print(response); // if (response.statusCode == 200) { var jsonData = jsonDecode(response.body); if (jsonData['status'] == 'success') { diff --git a/lib/controller/functions/gemeni.dart b/lib/controller/functions/gemeni.dart index 66f7322..1799716 100644 --- a/lib/controller/functions/gemeni.dart +++ b/lib/controller/functions/gemeni.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:SEFER/constant/box_name.dart'; +import 'package:SEFER/constant/info.dart'; import 'package:SEFER/constant/links.dart'; import 'package:SEFER/constant/style.dart'; import 'package:SEFER/controller/functions/crud.dart'; @@ -283,6 +284,7 @@ class AI extends GetxController { // backgroundColor: Colors.red); // } } + // Future addDriverEgypt() async { // // try { // // Extract values from box or set defaults @@ -367,6 +369,16 @@ class AI extends GetxController { // // backgroundColor: Colors.red); // // } // } + addCriminalDeocuments() async { + var res = await CRUD().post(link: AppLink.addCriminalDocuments, payload: { + "driverId": box.read(BoxName.driverID), + "IssueDate": responseCriminalRecordEgypt['IssueDate'], + "InspectionResult": responseCriminalRecordEgypt['InspectionResult'], + }); + if (res != 'failure') { + Get.snackbar('uploaded sucssefuly'.tr, ''); + } + } Future addRegistrationCarEgypt() async { try { @@ -407,6 +419,7 @@ class AI extends GetxController { Map responseBackCarLicenseMap = {}; Map responseIdCardMap = {}; Map responseIdCardDriverEgyptBack = {}; + Map responseForComplaint = {}; Map responseIdCardDriverEgyptFront = {}; Map responseIdEgyptFront = {}; Map responseCriminalRecordEgypt = {}; @@ -560,6 +573,59 @@ class AI extends GetxController { } else {} } + Future getComplaintDataToAI() async { + var res = await CRUD().get( + link: AppLink.getComplaintAllDataForDriver, + payload: {'driver_id': box.read(BoxName.driverID).toString()}, + ); + if (res != 'failure') { + var d = jsonDecode(res)['message']; + return d; + } else { + return [ + {'data': 'no data'} + ]; + } + } + + Future anthropicAIForComplaint() async { + var dataComplaint = await getComplaintDataToAI(); + var messagesData = [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "$dataComplaint ${AppInformation.complaintPrompt} " + } + ] + } + ]; + var requestBody = jsonEncode({ + "model": "claude-3-haiku-20240307", + "max_tokens": 1024, + "temperature": 0, + "system": "Json output only without any additional ", + "messages": messagesData, + }); + final response = await http.post( + Uri.parse('https://api.anthropic.com/v1/messages'), + headers: { + 'x-api-key': AK.anthropicAIkeySeferNew, + 'anthropic-version': '2023-06-01', + 'content-type': 'application/json' + }, + body: requestBody, + ); + if (response.statusCode == 200) { + var responseData = jsonDecode(utf8.decode(response.bodyBytes)); + // Process the responseData as needed + print(responseData); + + responseForComplaint = jsonDecode(responseData['content'][0]['text']); + } + } + Future anthropicAI( String payload, String prompt, String idType) async { var messagesData = [ diff --git a/lib/controller/home/payment/captain_wallet_controller.dart b/lib/controller/home/payment/captain_wallet_controller.dart index 7a5148d..ad468ff 100644 --- a/lib/controller/home/payment/captain_wallet_controller.dart +++ b/lib/controller/home/payment/captain_wallet_controller.dart @@ -181,6 +181,17 @@ class CaptainWalletController extends GetxController { }); } + Future addDriverWalletToInvitor(String paymentMethod, driverID, point) async { + paymentToken = await generateToken(point); + await CRUD().post(link: AppLink.addDriversWalletPoints, payload: { + 'driverID': driverID, + 'paymentID': paymentID.toString(), + 'amount': point, + 'token': paymentToken, + 'paymentMethod': paymentMethod.toString(), + }); + } + Future addSeferWallet(String paymentMethod, String point) async { var seferToken = await generateToken(point.toString()); await CRUD().post(link: AppLink.addSeferWallet, payload: { diff --git a/lib/controller/home/splash_screen_controlle.dart b/lib/controller/home/splash_screen_controlle.dart index b83ad14..4dfe7fa 100644 --- a/lib/controller/home/splash_screen_controlle.dart +++ b/lib/controller/home/splash_screen_controlle.dart @@ -8,7 +8,6 @@ import 'package:package_info_plus/package_info_plus.dart'; import '../../constant/box_name.dart'; import '../../main.dart'; -import '../../onbording_page.dart'; import '../../views/auth/captin/login_captin.dart'; class SplashScreenController extends GetxController diff --git a/lib/controller/local/translations.dart b/lib/controller/local/translations.dart index 5d67a83..190c415 100644 --- a/lib/controller/local/translations.dart +++ b/lib/controller/local/translations.dart @@ -249,6 +249,42 @@ class MyTranslation extends Translations { "Occupation": "المهنة", "Gender": "الجنس", "Religion": "الدين", + "You have 500": "لديك 500", + "You have got a gift for invitation": "لقد حصلت على هدية للدعوة", + "You have got a gift": "لقد حصلت على هدية", + "Share the app with another new driver": + "شارك التطبيق مع سائق جديد آخر", + "for your first registration!": "للتسجيل الأول!", + "Get it Now!": "احصل عليه الآن!", + "before": "قبل", + "3000 LE": "3000 جنيه مصري", + "Install our app:": "قم بتثبيت تطبيقنا:", + "Invite another driver and both get a gift after he completes 100 trips!": + "ادع صديقًا ليكون سائقًا واحصلا على هدية بعد إكماله 100 مشوار!", + "Share App": "شارك التطبيق", + 'You deserve the gift': "أنت تستحق الهدية", + "complete, you can claim your gift": " يمكنك المطالبة بهديتك", + "When": "‏عندما يكمل", + "Enter driver's phone": "أدخل رقم هاتف السائق", + "Send Invite": "أرسل الدعوة", "Show Invitations": "عرض الدعوات", + "Trip": "مشوار", + "No invitation found yet!": "لم يتم العثور على أي دعوات حتى الآن!", + "The period of this code is 1 hour": + "فترة صلاحية هذا الكود هي ساعة واحدة", + "SEFER DRIVER CODE": "كود سائق سفر", + "Use this code in registration": "استخدم هذا الكود عند التسجيل", + "To get a gift for both": "للحصول على هدية لكليكما", + "Invite a Driver": "ادع سائقًا", + // 'Invite another driver and both get a gift after he complete 100 trips!':"" + "As a new driver, you're eligible for a special offer!": + "بصفتك سائقًا جديدًا، فأنت مؤهل للحصول على عرض خاص!", + "Welcome Offer!": "عرض ترحيبي!", + "Please enter a phone number": "من فضلك أدخل رقم هاتف", + "Invite sent successfully": "تم إرسال الدعوة بنجاح", + "Failed to send invite": "فشل إرسال الدعوة", + "An error occurred": "حدث خطأ", + "Criminal Document Required": "الفيش الجنائي مطلوب", + "Criminal Document": "الفيش الجنائي", "Marital Status": "الحالة الاجتماعية", "Full Name (Marital)": "الاسم الكامل (الزوجي)", "Expiration Date": "تاريخ الانتهاء", diff --git a/lib/controller/payment/payment_controller.dart b/lib/controller/payment/payment_controller.dart index 78b7fd4..5e66cbe 100644 --- a/lib/controller/payment/payment_controller.dart +++ b/lib/controller/payment/payment_controller.dart @@ -2,7 +2,6 @@ import 'dart:convert'; import 'package:SEFER/constant/api_key.dart'; import 'package:SEFER/constant/style.dart'; import 'package:SEFER/controller/functions/tts.dart'; -import 'package:SEFER/controller/home/captin/map_driver_controller.dart'; import 'package:SEFER/controller/payment/paymob/paymob_response.dart'; import 'package:SEFER/views/widgets/elevated_btn.dart'; import 'package:http/http.dart' as http; diff --git a/lib/main.dart b/lib/main.dart index e7ac128..b877471 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,7 +17,6 @@ import 'constant/info.dart'; import 'controller/firebase/firbase_messge.dart'; import 'controller/firebase/local_notification.dart'; import 'controller/functions/location_controller.dart'; -import 'controller/functions/package_info.dart'; import 'controller/local/local_controller.dart'; import 'controller/local/translations.dart'; import 'controller/payment/paymob/paymob_wallet.dart'; diff --git a/lib/views/auth/captin/cards/egypt_card_a_i.dart b/lib/views/auth/captin/cards/egypt_card_a_i.dart index 4318595..a418f0b 100644 --- a/lib/views/auth/captin/cards/egypt_card_a_i.dart +++ b/lib/views/auth/captin/cards/egypt_card_a_i.dart @@ -1,5 +1,8 @@ +import 'package:SEFER/constant/box_name.dart'; +import 'package:SEFER/controller/functions/crud.dart'; import 'package:SEFER/controller/functions/gemeni.dart'; import 'package:SEFER/controller/functions/tts.dart'; +import 'package:SEFER/main.dart'; import 'package:SEFER/views/widgets/elevated_btn.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -814,7 +817,7 @@ Please fill in the JSON object with the extracted information, following these g final inspectionDate = ai.responseIdCardDriverEgyptBack['inspection_date']; final year = int.parse(inspectionDate.split('-')[0]); - final inspectionDateTime = DateTime(year, 1, 1); + final inspectionDateTime = DateTime(year, 12, 31); // Check if the tax expiry date is before today final today = DateTime.now(); diff --git a/lib/views/auth/captin/criminal_documents_page.dart b/lib/views/auth/captin/criminal_documents_page.dart new file mode 100644 index 0000000..113f206 --- /dev/null +++ b/lib/views/auth/captin/criminal_documents_page.dart @@ -0,0 +1,210 @@ +import 'package:SEFER/constant/box_name.dart'; +import 'package:SEFER/constant/style.dart'; +import 'package:SEFER/main.dart'; +import 'package:SEFER/views/widgets/my_scafold.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../../constant/colors.dart'; +import '../../../constant/links.dart'; +import '../../../controller/functions/gemeni.dart'; +import '../../../controller/functions/tts.dart'; +import '../../widgets/elevated_btn.dart'; + +class CriminalDocumemtPage extends StatelessWidget { + const CriminalDocumemtPage({super.key}); + + @override + Widget build(BuildContext context) { + Get.put(AI()); + return MyScafolld( + title: "Criminal Document".tr, + isleading: false, + body: [ + GetBuilder(builder: (controller) { + return Column( + children: [ + Container( + decoration: AppStyle.boxDecoration, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('You have upload Criminal documents'.tr), + )), + egyptCriminalRecord(), + controller.responseCriminalRecordEgypt.isNotEmpty + ? MyElevatedButton( + title: 'Next'.tr, + onPressed: () async { + if (controller + .responseCriminalRecordEgypt['FullName'] != + box.read(BoxName.nameArabic)) //todo get from server + { + Get.defaultDialog( + barrierDismissible: false, + title: 'Criminal Record Mismatch', + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.warning, + size: 48, color: Colors.red), + const SizedBox(height: 16), + Text( + 'The full name on your criminal record does not match the one on your driver’s license. Please verify and provide the correct documents.' + .tr, + textAlign: TextAlign.center, + style: AppStyle.title, + ), + const SizedBox(height: 16), + IconButton( + onPressed: () async { + await Get.find() + .speakText( + 'The full name on your criminal record does not match the one on your driver’s license. Please verify and provide the correct documents.' + .tr, + ); + }, + icon: const Icon(Icons.volume_up), + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Get.back(); + }, + child: const Text('OK'), + ), + ], + ); + } else { + await controller.addCriminalDeocuments(); + } + }) + : const SizedBox(), + ], + ); + }) + ], + ); + } + + GetBuilder egyptCriminalRecord() { + return GetBuilder( + builder: (ai) { + if (ai.responseCriminalRecordEgypt.isNotEmpty) { + return Card( + elevation: 4.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Criminal Record'.tr, style: AppStyle.headTitle2), + IconButton( + onPressed: () async { + await ai.allMethodForAI( + """ +Write a JSON object from the following information extracted from the provided Arabic text: + +{ + "InspectionResult": "", + "NationalID": "", + "FullName": "", + "IssueDate": "" // Format: YYYY-MM-DD +} + +Important notes: +1. For the IssueDate, ensure the date is in YYYY-MM-DD format using Latin numerals (0-9). +2. Add appropriate spaces in all text fields to ensure readability. +3. If any information is missing, leave the corresponding field as an empty string. +4. Ensure all text is properly formatted and spaces are used correctly. +5. Convert any Arabic numerals to Latin numerals (0-9) where applicable. + +Please fill in the JSON object with the extracted information, following these guidelines. +""", + AppLink.uploadEgypt, + 'criminalRecord', + ); + }, + icon: const Icon(Icons.refresh), + ), + ], + ), + const SizedBox(height: 8.0), + const Divider(color: AppColor.accentColor), + const SizedBox(height: 8.0), + Text( + '${'InspectionResult'.tr}: ${ai.responseCriminalRecordEgypt['InspectionResult']}'), + const SizedBox(height: 8.0), + Text( + '${'FullName'.tr}: ${ai.responseCriminalRecordEgypt['FullName']}', + style: AppStyle.title.copyWith( + color: ai.responseCriminalRecordEgypt['FullName'] == + ai.responseIdEgyptDriverLicense['name_arabic'] + ? AppColor.greenColor + : AppColor.redColor), + ), + const SizedBox(height: 8.0), + Text( + '${'NationalID'.tr}: ${ai.responseCriminalRecordEgypt['NationalID']}'), + const SizedBox(height: 8.0), + Text( + '${'IssueDate'.tr}: ${ai.responseCriminalRecordEgypt['IssueDate']}'), + ], + ), + ), + ); + } + return Card( + child: InkWell( + onTap: () async { + await ai.allMethodForAI( + """ +Write a JSON object from the following information extracted from the provided Arabic text: + +{ + "InspectionResult": "", + "NationalID": "", + "FullName": "", + "IssueDate": "" // Format: YYYY-MM-DD +} + +Important notes: +1. For the IssueDate, ensure the date is in YYYY-MM-DD format using Latin numerals (0-9). +2. Add appropriate spaces in all text fields to ensure readability. +3. If any information is missing, leave the corresponding field as an empty string. +4. Ensure all text is properly formatted and spaces are used correctly. +5. Convert any Arabic numerals to Latin numerals (0-9) where applicable. + +Please fill in the JSON object with the extracted information, following these guidelines. +""", + AppLink.uploadEgypt, + 'criminalRecord', + ); + }, + child: Column( + children: [ + Image.asset( + 'assets/images/6.png', + height: Get.height * .25, + width: double.maxFinite, + fit: BoxFit.fitHeight, + ), + Text( + 'Capture an Image of Your Criminal Record'.tr, + style: AppStyle.title, + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/views/auth/captin/invite_driver_screen.dart b/lib/views/auth/captin/invite_driver_screen.dart new file mode 100644 index 0000000..ac02ce0 --- /dev/null +++ b/lib/views/auth/captin/invite_driver_screen.dart @@ -0,0 +1,122 @@ +import 'package:SEFER/constant/colors.dart'; +import 'package:SEFER/constant/style.dart'; +import 'package:SEFER/views/widgets/elevated_btn.dart'; +import 'package:SEFER/views/widgets/my_textField.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../../controller/auth/captin/invit_controller.dart'; + +class InviteDriverScreen extends StatelessWidget { + final InviteController controller = Get.put(InviteController()); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('Invite a Driver'.tr)), + body: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Invite another driver and both get a gift after he completes 100 trips!" + .tr, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 20), + MyTextForm( + controller: controller.invitePhoneController, + label: 'Enter driver\'s phone'.tr, + hint: 'Enter driver\'s phone'.tr, + type: TextInputType.phone), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + MyElevatedButton( + title: 'Send Invite'.tr, + onPressed: controller.sendInvite, + ), + MyElevatedButton( + title: 'Show Invitations'.tr, + onPressed: () async { + controller.fetchDriverStats(); + }, + ), + ], + ), + const SizedBox(height: 20), + GetBuilder(builder: (controller) { + return SizedBox( + // decoration: AppStyle.boxDecoration, + height: Get.height * .4, + child: controller.driverInvitationData.isEmpty + ? Center( + child: Text( + "No invitation found yet!".tr, + style: AppStyle.title, + ), + ) + : ListView.builder( + itemCount: controller.driverInvitationData.length, + itemBuilder: (context, index) { + // Ensure the 'countOfInvitDriver' key exists and is parseable as an int + int countOfInvitDriver = 0; + if (controller.driverInvitationData[index] + .containsKey('countOfInvitDriver')) { + countOfInvitDriver = int.tryParse(controller + .driverInvitationData[index] + ['countOfInvitDriver'] + .toString()) ?? + 0; + } + + // Calculate the progress value, ensuring it is between 0 and 1 + double progressValue = countOfInvitDriver / 100.0; + if (progressValue > 1.0) progressValue = 1.0; + if (progressValue < 0.0) progressValue = 0.0; + + return Container( + margin: const EdgeInsets.symmetric(vertical: 8.0), + child: Stack( + alignment: AlignmentDirectional.center, + children: [ + InkWell( + onTap: () async { + controller.onSelectDriverInvitation(index); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: AppColor.accentColor.withOpacity( + .5), // Background color of the container + ), + width: Get.width * .85, + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: LinearProgressIndicator( + value: progressValue, + color: AppColor.blueColor, + backgroundColor: AppColor.accentColor + .withOpacity(.3), + minHeight: 35, + ), + ), + ), + ), + Text( + '${controller.driverInvitationData[index]['invitorName']} ${controller.driverInvitationData[index]['countOfInvitDriver']} / 100 ${'Trip'.tr}'), + ], + ), + ); + }, + ), + ); + }) + ], + ), + ), + ); + } +} diff --git a/lib/views/home/Captin/home_captain/drawer_captain.dart b/lib/views/home/Captin/home_captain/drawer_captain.dart index 907b84f..aa329c5 100644 --- a/lib/views/home/Captin/home_captain/drawer_captain.dart +++ b/lib/views/home/Captin/home_captain/drawer_captain.dart @@ -2,6 +2,7 @@ import 'package:SEFER/constant/api_key.dart'; import 'package:SEFER/constant/links.dart'; import 'package:SEFER/constant/style.dart'; import 'package:SEFER/controller/home/captin/home_captain_controller.dart'; +import 'package:SEFER/views/auth/captin/invite_driver_screen.dart'; import 'package:SEFER/views/notification/available_rides_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; @@ -72,6 +73,13 @@ class DrawerCaptain extends StatelessWidget { Get.to(() => HelpCaptain(), transition: Transition.size), ), _buildDivider(), + _buildDrawerItem( + icon: Icons.share_outlined, + text: 'Share App'.tr, + onTap: () => + Get.to(() => InviteDriverScreen(), transition: Transition.size), + ), + _buildDivider(), _buildDrawerItem( icon: Icons.settings, text: 'Settings'.tr, diff --git a/lib/views/home/Captin/home_captain/home_captin.dart b/lib/views/home/Captin/home_captain/home_captin.dart index 2bab04c..8b69777 100644 --- a/lib/views/home/Captin/home_captain/home_captin.dart +++ b/lib/views/home/Captin/home_captain/home_captin.dart @@ -34,6 +34,7 @@ class HomeCaptain extends StatelessWidget { Get.put(HomeCaptainController()); WidgetsBinding.instance.addPostFrameCallback((_) { checkForUpdate(context); + _showFirstTimeOfferNotification(context); }); return Scaffold( appBar: AppBar( @@ -276,7 +277,7 @@ class HomeCaptain extends StatelessWidget { ), ), ) - : SizedBox() + : const SizedBox() // callPage(), // Positioned( @@ -297,35 +298,131 @@ class HomeCaptain extends StatelessWidget { } } -// class CameraContainer extends StatelessWidget { -// TextMLGoogleRecognizerController controller = -// Get.put(TextMLGoogleRecognizerController()); +void _showFirstTimeOfferNotification(BuildContext context) { + bool isFirstTime = _checkIfFirstTime(); -// CameraContainer({super.key}); -// @override -// Widget build(BuildContext context) { -// return Stack( -// children: [ -// // The camera preview -// SizedBox( -// height: Get.height * 0.3, -// width: Get.width * 0.9, -// child: CameraPreview(controller.imagePicker as CameraController), -// ), + if (isFirstTime) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showDialog( + context: context, + builder: (BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: const [ + BoxShadow( + color: Colors.black26, + blurRadius: 10.0, + offset: Offset(0.0, 10.0), + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Welcome Offer!'.tr, + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.w700, + ), + ), + const SizedBox(height: 15), + Text( + 'As a new driver, you\'re eligible for a special offer!'.tr, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 20), + Stack( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.green, + borderRadius: BorderRadius.circular(15), + ), + child: Text( + '3000 LE'.tr, + style: const TextStyle( + color: Colors.white, + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + ), + Positioned( + right: -10, + top: -10, + child: Container( + padding: const EdgeInsets.all(5), + decoration: const BoxDecoration( + color: Colors.red, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.attach_money, + color: Colors.white, + size: 20, + ), + ), + ), + ], + ), + const SizedBox(height: 20), + Text( + 'for your first registration!'.tr, + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 20), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 10), + child: Text( + "Get it Now!".tr, + style: + const TextStyle(fontSize: 18, color: Colors.white), + ), + ), + onPressed: () { + Navigator.of(context).pop(); + _markAsNotFirstTime(); + }, + ), + ], + ), + ), + ); + }, + ); + }); + } +} -// // The lines on the side of the name and national number -// const Positioned( -// bottom: 0, -// left: 0, -// right: 0, -// child: Column( -// children: [ -// Text('Name'), -// Text('National Number'), -// ], -// ), -// ), -// ], -// ); -// } -// } +bool _checkIfFirstTime() { + if (box.read(BoxName.isFirstTime) == null) { + return true; + } else { + return false; + } +} + +void _markAsNotFirstTime() { + box.write(BoxName.isFirstTime, true); +} diff --git a/lib/views/home/Captin/home_captain/widget/left_menu_map_captain.dart b/lib/views/home/Captin/home_captain/widget/left_menu_map_captain.dart index a3a6091..31953da 100644 --- a/lib/views/home/Captin/home_captain/widget/left_menu_map_captain.dart +++ b/lib/views/home/Captin/home_captain/widget/left_menu_map_captain.dart @@ -190,7 +190,7 @@ GetBuilder leftMainMenuCaptainIcons() { // borderRadius: BorderRadius.circular(15)), // child: IconButton( // onPressed: () { - // print(box.read(BoxName.rideStatus)); + // print(box.read(BoxName.tokenDriver)); // }, // icon: const Icon( // FontAwesome5.grin_tears, diff --git a/lib/views/home/my_wallet/transfer_budget_page.dart b/lib/views/home/my_wallet/transfer_budget_page.dart index 22f7aad..a04100f 100644 --- a/lib/views/home/my_wallet/transfer_budget_page.dart +++ b/lib/views/home/my_wallet/transfer_budget_page.dart @@ -1,6 +1,4 @@ -import 'package:SEFER/constant/links.dart'; import 'package:SEFER/constant/style.dart'; -import 'package:SEFER/controller/functions/crud.dart'; import 'package:SEFER/views/widgets/elevated_btn.dart'; import 'package:SEFER/views/widgets/my_scafold.dart'; import 'package:SEFER/views/widgets/my_textField.dart';