diff --git a/android/app/build.gradle b/android/app/build.gradle index 76907e3..519e006 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -47,8 +47,8 @@ android { // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = 29 targetSdk = 36 - versionCode = 7 - versionName = '1.0.7' + versionCode = 11 + versionName = '1.0.11' multiDexEnabled = true ndk { abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml index 490be17..629161f 100644 --- a/android/app/src/main/res/xml/network_security_config.xml +++ b/android/app/src/main/res/xml/network_security_config.xml @@ -1,26 +1,27 @@ - - - + intaleq.xyz - - + + + pXmP2hTQLxDEvlTVmP5N7xpiA32sycBsxB6hBFT2uL4= + + C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHESsl= + - + \ No newline at end of file diff --git a/assets/images/bus.png b/assets/images/bus.png new file mode 100644 index 0000000..a1e3958 Binary files /dev/null and b/assets/images/bus.png differ diff --git a/assets/images/electric.png b/assets/images/electric.png new file mode 100644 index 0000000..b2889b8 Binary files /dev/null and b/assets/images/electric.png differ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 976b1f9..e0e8b89 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -322,10 +322,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -339,10 +343,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 1fc46d4..e346993 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5 + 6 CFBundleSignature ???? CFBundleURLTypes @@ -35,7 +35,7 @@ CFBundleVersion - 1.0.5 + 1.0.6 FirebaseAppDelegateProxyEnabled NO GMSApiKey diff --git a/lib/constant/box_name.dart b/lib/constant/box_name.dart index ef7ce6b..8435425 100644 --- a/lib/constant/box_name.dart +++ b/lib/constant/box_name.dart @@ -8,6 +8,8 @@ class BoxName { static const String serverChosen = "serverChosen"; static const String gender = "gender"; static const String jwt = "jwt"; + static const String lowEndMode = "lowEndMode"; + static const String appVersionChecked = "appVersionChecked"; static const String lastName = "lastName"; static const String fingerPrint = "fingerPrint"; static const String payMobApikey = "payMobApikey"; diff --git a/lib/constant/info.dart b/lib/constant/info.dart index fda5cb0..63f35f1 100644 --- a/lib/constant/info.dart +++ b/lib/constant/info.dart @@ -4,184 +4,39 @@ class AppInformation { static const String phoneNumber = '962798583052'; static const String linkedInProfile = 'https://www.linkedin.com/in/hamza-ayed/'; - static const String website = 'https://tripz-egypt.com'; - static const String email = 'hamzaayed@tripz-egypt.com'; + static const String website = 'https://intaleqapp.com'; + static const String email = 'hamzaayed@intaleqapp.com'; static const String addd = 'BlBlNl'; - static const String privacyPolicyArabic = ''' - - - - - إنطلق - سياسة الخصوصية والشروط والأحكام - - - -

سياسة الخصوصية والشروط والأحكام لتطبيق إنطلق

- -
-

آخر تحديث: 19-07-2025

-

باستخدامك لتطبيق إنطلق ("التطبيق")، فإنك توافق على هذه الشروط والأحكام وسياسة الخصوصية.

-
- -

1. شروط الاستخدام

-

عند تحميل أو تصفح أو استخدام تطبيق إنطلق ("التطبيق")، فإنك توافق على الالتزام بهذه الشروط والأحكام. يحق لإنطلق تعديل هذه الشروط في أي وقت. إذا لم توافق على أي جزء من هذه الشروط، يجب عليك التوقف فورًا عن استخدام التطبيق. استمرارك في الاستخدام يعني موافقتك على الشروط وأي تعديلات لاحقة.

- -

2. التعريفات

- - -

3. عن إنطلق

-

إنطلق هو منصة حجز رحلات تربط بين الركاب والسائقين. يعمل التطبيق كوسيط ولا يوظف السائقين مباشرة. يمكن للمستخدمين:

- -

يدفع مقدمو الخدمة رسوم عمولة عن كل رحلة مكتملة، كما تحددها إنطلق.

- -

4. الاستخدام العام للتطبيق والخدمات

-

4.1 نطاق الاستخدام

- - -

4.2 متطلبات الجهاز والإنترنت

- - -

5. التزامات المستخدمين

-

5.1 معلومات دقيقة

- - -

5.2 السلوكيات المحظورة

-

يمنع على المستخدمين:

- - -

6. إخلاء المسؤولية

- - -

7. سياسة الخصوصية

-

7.1 جمع البيانات واستخدامها

-

نجمع البيانات الشخصية (الاسم، الهاتف، الموقع، معلومات الدفع) فقط لأغراض:

- - -

7.2 حماية البيانات

- - -

7.3 حذف الحساب والبيانات

-

لحذف حسابك أو بياناتك، راسلنا على: support@intaleqapp.com.

- - -

8. سياسات الرحلات

-

8.1 سياسة منع التدخين

- - -

8.2 إجراءات السلامة لكوفيد-19

- - -
-

اتصل بنا: لأي استفسارات حول هذه الشروط، يرجى التواصل عبر support@intaleqapp.com.

-
- -'''; - static const String privacyPolicyEnglish = ''' + static const String privacyPolicy = ''' - Intaleq - Privacy Policy & Terms and Conditions + Intaleq - Privacy Policy & Terms of Use -

Intaleq Privacy Policy & Terms and Conditions

+

Privacy Policy & Terms of Use

-

Last Updated: [Insert Date]

-

By using the Intaleq ride-hailing application ("the App"), you agree to these Terms and Conditions and our Privacy Policy.

+

Effective Date: August 9, 2025

+

Last Updated: August 9, 2025

-

1. Terms of Use

-

By downloading, browsing, or using the Intaleq mobile application ("the App"), you agree to comply with these Terms and Conditions. Intaleq reserves the right to modify these terms at any time. If you do not agree with any part of these terms, you must immediately stop using the App. Continued use constitutes acceptance of the terms and any future amendments.

+

1. Introduction and Acceptance

+

By downloading, registering, or using the Intaleq application ("App"), you agree to be bound by this Privacy Policy and our Terms of Use. If you do not agree, you must stop using the App immediately. Your continued use constitutes acceptance of these terms and any future updates.

2. Definitions

-

3. About Intaleq

-

Intaleq is a ride-hailing platform that connects passengers with drivers. The App acts as an intermediary and does not employ drivers directly. Users can:

+

3. Privacy Policy

+ +

3.1 Information We Collect

+

We collect information necessary to provide and improve our Services.

+ +

A. Information You Provide:

-

Service Providers pay a commission fee per completed ride, as determined by Intaleq.

-

4. General App Usage & Services

-

4.1 Scope of Use

+

B. Information Collected Automatically:

-

4.2 Device & Network Requirements

+

3.2 Payment Information

+

We do not collect, process, or store any sensitive payment information like credit/debit card numbers. We facilitate payments by connecting you to licensed, local third-party providers:

- -

5. User Obligations

-

5.1 Accurate Information

+ +

3.3 How We Use Your Information

-

5.2 Prohibited Conduct

-

Users must not:

+

3.4 Data Sharing

+

We do not sell your personal data. We only share it in the following limited circumstances:

-

6. Liability Disclaimer

+

3.5 Policy for Minors

+

Our services are intended for individuals over the age of 18. + For Drivers: We strictly verify the identity and age of all drivers to ensure no minors are operating on our platform. + For Passengers: While we do not verify passenger identity, the service is not directed at children under 18. If a parent or guardian becomes aware that their child has provided us with information without their consent, they should contact us immediately.

+ +

4. User Obligations & Conduct

-

7. Privacy Policy

-

7.1 Data Collection & Use

-

We collect personal data (name, phone, location, payment info) only for:

- +

5. Disclaimer of Liability

+

The App is provided "as is". Intaleq is an intermediary platform and is not liable for the actions of Drivers or Passengers, accidents, delays, or any disputes between users. Our liability is limited to the fullest extent permitted by law.

+ +

6. Policy Updates

+

We may update these terms. If we make significant changes, we will notify you within the App. You will be required to review and accept the new terms to continue using the Services, ensuring your consent is active and informed.

-

7.2 Data Protection

- +

7. Account Deletion & Contact

+

You have the right to request the deletion of your account and personal data. To do so, or for any other questions, please contact us. We will respond to deletion requests within 30 days.

+

Email: support@intaleqapp.com

-

7.3 Account & Data Deletion

-

To delete your account or data, email: support@intaleqapp.com.

- - -

8. Ride Policies

-

8.1 No-Smoking Policy

- - -

8.2 COVID-19 Safety

- - -
-

Contact Us: For any questions about these Terms, please contact us at support@intaleqapp.com.

-
'''; - static const String privacyPolicy = ''' + static const String privacyPolicyArabic = ''' + + + + + + انطلق - سياسة الخصوصية وشروط الاستخدام + + + +

سياسة الخصوصية وشروط الاستخدام

- - - - - - - - - - - -
-
-
-
-
-
-

Terms and Conditions

-

1 TERMS OF USE

-

By downloading, browsing, accessing or using the Mobile Application; “Intaleq”, Users agree to be bound by these Terms and Conditions of Use. We reserve the right to amend these terms and conditions at any time. If the User disagrees with any of these Terms and Conditions of Use, the User must immediately discontinue their access to the Mobile Application and their use of the services offered on the Mobile Application. Continued use of the Mobile Application will constitute acceptance of these Terms and Conditions of Use, as may be amended from time to time.

-

2.1. DEFINITIONS

-

In these Terms and Conditions of Use, the following capitalized terms shall have the following meanings, except where the context otherwise requires:

-

“Mobile Application” or “Intaleq” refers to the smartphone software through which the company mediates services between Users and Service Providers.

-

"Account" means an account created by a User or a Service Provider on the Mobile Application as part of Registration.

-

“Service Providers” refers to the individuals or companies registered within the Company to provide products or services approved and mediated by the Company/Mobile Application and that are requested/purchased by “Users”. “Service Provider” means any one of them.

-

"Users" means users of the Mobile Application, including you and "User" means any one of them. “Users” also includes Service Providers using the Mobile Application version dedicated to the use of Service Providers.

-

"Privacy Policy" means the privacy policy set out in Clause 14 of these Terms and Conditions of Use.

-

"Redeem" means to redeem a company’s products or services on these Terms and Conditions of Use and

-

"Redemption" means the act of redeeming such products or services.

-

"Register" means to create an Account on the Mobile Application and "Registration" means the act of creating such an Account.

-

"Services" means all the services provided by Service Providers via the Mobile Application and mediated by the Company to Users, and "Service" means any one of them.

-

2.2. WHAT IS THE MOBILE APPLICATION, “Intaleq”?

-

The “Intaleq” Mobile Application consists in a specialize service with the purpose to schedule/match the Service Provider with the User, however without creating any employee relationship with the Service Provider, meaning that the Mobile Application should be considered only as a service mediator with the purpose of scheduling/matching between Users and Service Providers for the latter to fulfill the service requested by Users. Through the system, the Company allows, totally free of charge, the Users to sign up and request the desired available services from Service Providers in a more efficient way than the conventional existing methods. The Service Providers, by their means, can register on the Mobile Application dedicated for Service Providers through the methods indicated by the Company, pending an evaluation from the Company and the necessary documentation when signing up in accordance with guidelines set by the Transportation General Authority (TGA) to provide services through the Mobile Application. The Service Provider will pay a profit margin fee determined by the Company -in knowledge of the Service Provider- per completed service. Users can pay their ride fare using Apple Pay as an additional payment method in Saudi Arabia on iPhones

-

-

3. GENERAL ISSUES ABOUT THE MOBILE APPLICATION AND THE SERVICES

-

3.1 Applicability of terms and conditions: The use of any Services and/or the Mobile Application and the making of any Redemptions are subject to these Terms and Conditions of Use.

-

3.2 Location: The Mobile Application, the Services and any Redemptions are intended solely for use by Users who access the Mobile Application where it operates and provides its services regionally. We make no representation that the Services (or any goods or services) are available or otherwise suitable for use outside of the regions indicated by the Company. Notwithstanding the above, if the User accesses the Mobile Application, use the Services or make any Redemptions from locations outside the regions indicated by the Service Provider, the User does so on their own initiative and are responsible for the consequences and for compliance with all applicable laws.

-

3.3 Scope: The Mobile Application, the Services and any Redemptions are for Users’ non-commercial, personal use only and must not be used for business purposes unless an official written permission is granted by the Company.

-

3.4 Prevention on use: We reserve the right to prevent the User using the Mobile Application and the Service (or any part of them) and to prevent the User from making any Redemptions.

-

3.5 Equipment and Networks: The provision of the Services and the Mobile Application does not include the provision of a mobile telephone or handheld device or other necessary equipment to access the Mobile Application or the Services or make any Redemptions. To use the Mobile Application or Services or to make Redemptions, the User will require Internet connectivity and appropriate telecommunication links. The User acknowledges that the terms of agreement with their respective mobile network provider will continue to apply when using the Mobile Application. As a result, the User may be charged by the Mobile Provider for access to network connection services for the duration of the connection while accessing the Mobile Application or any such third party charges as may arise. The User accepts responsibility for any such charges that arise.

-

3.6 Permission to use Mobile Application: If the User is not the bill payer for the mobile telephone or handheld device being used to access the Mobile Application, the User will be assumed to have received permission from the bill payer for using the Mobile Application.

-

3.7 License to Use Material: By submitting any text or images (including photographs) via the Application, the User represents that they are the owner of the Material, or have proper authorization from the owner of the Material to use, reproduce and distribute it. The User hereby grants us a worldwide, royalty-free, non-exclusive license to use the Material to promote any products or services.

-

4. REDEMPTIONS

-

4.1 Need for registration: a) Users must Register to make a Redemption from the Mobile Application. b) The Service Provider agrees that by registering they will be scrutinized to be accepted by the Company who may refuse or cancel the Service Provider account at any time, whether by complaints or by internal policy.

-

4.2 Application of these Terms and Conditions of Use: By making any Redemption, the User acknowledges that the Redemption is subject to these Terms and Conditions of Use.

-

4.3 Redemption: Any attempted Redemption not consistent with these Terms and Conditions of Use may be disallowed or rendered void at our or the relevant Service Provider’s discretion.

-

4.4 Responsibility for Redemptions of perishable products of services: Each Service Provider shall be responsible to ensure that any of its products or services for Redemption that are perishable has not expired.

-

4.5 Restrictions: (a) Reproduction, sale, resale or trading of any products or services or Redeemed products is prohibited. (b) If any product or service is Redeemed for less than its face value, there is no entitlement to a credit, cash or Sample equal to the difference between the face value and the amount Redeemed. (c) Redemption of products or services is subject to availability of the relevant Service Providers’ stocks.

-

4.6 Company Not Liable: For the avoidance of doubt, the Company shall not be liable for any losses or damages suffered by Users resulting from a failure by the relevant Service Provider to fulfil any Redemptions in accordance with Clause 4.4 or for a failure by us to deliver any products or services to Users due to the unavailability of such products or services pursuant to Clause 4.5(c). Users accept that the Mobile Application acts solely as a scheduling/matching service between its Users and Service Providers, and that it is not responsible for any issues that arise, including but not limited to accidents, delays, car discomfort, and unavailability of products or services.

-

4.7 Lost/stolen services: Neither we nor any Service Provider shall be responsible for lost or stolen Samples or products that have been Redeemed.

-

-

5. LOCATION ALERTS AND NOTIFICATIONS

-

5.1 The USer agrees to receive pre-programmed notifications (“Location Alerts”) on the Mobile Application from Service Providers if the User has turned on locational services on their mobile telephone or other handheld devices (as the case may be).

-

-

6. USERS’ OBLIGATIONS

-

6.1 Service Provider terms: Users agree to (and shall) abide by the terms and conditions of the relevant Service Provider for which their Redemption relates to, as may be amended from time to time.

-

6.2 Accurate information: The User warrants that all information provided on Registration and contained as part of their Account is true, complete and accurate and that the User will promptly inform us of any changes to such information by updating the information in their Account.

-

6.3 Content on the Mobile Application and Service: It is the User’s responsibility to ensure that any products, services or information available through the Mobile Application or the Services meet their specific requirements before making any Redemption.

-

6.4 Prohibitions in relation to usage of Services or Mobile Application: Without limitation, the User undertakes not to use or permit anyone else to use the Services or Mobile Application:-

-

6.4.1 to send or receive any material which is not civil or tasteful

-

6.4.2 to send or receive any material which is threatening, grossly offensive, of an indecent, obscene or menacing character, blasphemous or defamatory of any person, in contempt of court or in breach of confidence, copyright, rights of personality, publicity or privacy or any other third party rights;

-

6.4.3 to send or receive any material for which the User has not obtained all necessary licenses and/or approvals (from us or third parties); or which constitutes or encourages conduct that would be considered a criminal offence, give rise to civil liability, or otherwise be contrary to the law of or infringe the rights of any third party in any country in the world;

-

6.4.4 to send or receive any material which is technically harmful (including computer viruses, logic bombs, Trojan horses, worms, harmful components, corrupted data or other malicious software or harmful data);

-

6.4.5 to cause annoyance, inconvenience or needless anxiety;

-

6.4.6 to intercept or attempt to intercept any communications transmitted by way of a telecommunications system;

-

6.4.7 for a purpose other than which we have designed them or intended them to be used;

-

6.4.8 for any fraudulent purpose;

-

6.4.9 other than in conformance with accepted Internet practices and practices of any connected networks;

-

6.4.10 in any way which is calculated to incite hatred against any ethnic, religious or any other minority or is otherwise calculated to adversely affect any individual, group or entity; or

-

6.4.11 in such a way as to, or commit any act that would or does, impose an unreasonable or disproportionately large load on our infrastructure.

-

6.5 Prohibitions in relation to usage of Services, Mobile Application: Without limitation, the User further undertakes not to or permit anyone else to:-

-

6.5.1 resell any products or services;

-

6.5.2 furnish false data including false names, addresses and contact details and fraudulently use credit/debit card numbers;

-

6.5.3 attempt to circumvent our security or network including to access data not intended for the User, log into a server or account the User is not expressly authorized to access, or probe the security of other networks (such as running a port scan);

-

6.5.4 execute any form of network monitoring which will intercept data not intended for the User;

-

6.5.5 enter into fraudulent interactions or transactions with us or a Service Provider (including interacting or transacting purportedly on behalf of a third party where the User has no authority to bind that third party or the User is pretending to be a third party);

-

6.5.6 extract data from or hack into the Mobile Application;

-

6.5.7 use the Services or Mobile Application in breach of these Terms and Conditions of Use;

-

6.5.8 engage in any unlawful activity in connection with the use of the Mobile Application or the Services; or

-

6.5.9 engage in any conduct which, in our exclusive reasonable opinion, restricts or inhibits any other customer from properly using or enjoying the Mobile Application or Services.

-

-

7. RULES ABOUT USE OF THE SERVICE AND THE MOBILE APPLICATION

-

7.1 We will use reasonable endeavors to correct any errors or omissions as soon as practicable after being notified of them. However, we do not guarantee that the Services or the Mobile Application will be free of faults, and we do not accept liability for any such faults, errors or omissions. In the event of any such error, fault or omission, Users should report it by contacting us at JORDAN: 962798583052 .

-

7.2 We do not warrant that Users’ use of the Services or the Mobile Application will be uninterrupted and we do not warrant that any information (or messages) transmitted via the Services or the Mobile Application will be transmitted accurately, reliably, in a timely manner or at all. Notwithstanding that we will try to allow uninterrupted access to the Services and the Mobile Application, access to the Services and the Mobile Application may be suspended, restricted or terminated at any time.

-

7.3 We do not give any warranty that the Services and the Mobile Application are free from viruses or anything else which may have a harmful effect on any technology.

-

7.4 We reserve the right to change, modify, substitute, suspend or remove without notice any information or Services on the Mobile Application from time to time. Users’ access to the Mobile Application and/or the Services may also be occasionally restricted to allow for repairs, maintenance or the introduction of new facilities or services. We will attempt to restore such access as soon as we reasonably can. For the avoidance of doubt, we reserve the right to withdraw any information or Services from the Mobile Application at any time.

-

7.5 We reserve the right to block access to and/or to edit or remove any material which in our reasonable opinion may give rise to a breach of these Terms and Conditions of Use.

-

7.6 The acceptance and denial of the service request may occur at first by the Service Provider, who can accept or deny the service when receiving a notification for a request. The User may cancel the contract for any reason which may or may not apply cancellation fees for which the conditions and amount is determined and communicated by the Company. Both recognize that “Intaleq” is not liable for any delays, cancellations, failure to cancel the contract and miscommunication between the User and the Service Provider, nor for any delay or failure in the delivery of services from the Service Provider.

-

-

8. SUSPENSION AND TERMINATION

-

8.1 If the User uses (or others, with the User’s permission use) the Mobile Application, any Services in contravention of these Terms and Conditions of Use, we may suspend their use of the Services and/or Mobile Application.

-

8.2 If we suspend the Services or Mobile Application, we may refuse to restore the Services or Mobile Application for the User’s use until we receive an assurance from them, in a form we deem acceptable, that there will be no further breach of the provisions of these Terms and Conditions of Use.

-

8.3 The Company shall fully co-operate with any law enforcement authorities or court order requesting or directing the Company to disclose the identity or locate anyone in breach of these Terms and Conditions of Use.

-

8.4 Without limitation to anything else in this Clause 8, we shall be entitled immediately or at any time (in whole or in part) to: (a) suspend the Services and/or Mobile Application; (b) suspend Users’ use of the Services and/or Mobile Application; and/or (c) suspend the use of the Services and/or Mobile Application for persons we believe to be connected (in whatever manner) to the concerned User, if:

-

8.4.1 the User commits any breach of these Terms and Conditions of Use;

-

8.4.2 we suspect, on reasonable grounds, that the User has, might or will commit a breach of these Terms and Conditions of Use; or

-

8.4.3 we suspect, on reasonable grounds, that the User may have committed or will be committing any fraud against us or any person.

-

8.5 Our rights under this Clause 8 shall not prejudice any other right or remedy we may have in respect of any breach or any rights, obligations or liabilities accrued prior to termination.

-

-

9. DISCLAIMER AND EXCLUSION OF LIABILITY

-

9.1 The Mobile Application, the Services, the information on the Mobile Application and use of all related facilities are provided on an "as is, as available" basis without any warranties whether express or implied.

-

9.2 The credit balance shall remain valid for the specific period. The credit in the wallet will be expired after 6 months of inactivity.

-

9.3 To the fullest extent permitted by applicable law, we disclaim all representations and warranties relating to the Mobile Application and its contents, including in relation to any inaccuracies or omissions in the Mobile Application, warranties of merchantability, quality, fitness for a particular purpose, accuracy, availability, non-infringement or implied warranties from course of dealing or usage of trade.

-

9.4 We do not warrant that the Mobile Application will always be accessible, uninterrupted, timely, secure, error free or free from computer virus or other invasive or damaging code or that the Mobile Application will not be affected by any acts of nature or other force majeure events, including inability to obtain or shortage of necessary materials, equipment facilities, power or telecommunications, lack of telecommunications equipment or facilities and failure of information technology or telecommunications equipment or facilities.

-

9.5 While we may use reasonable efforts to include accurate and up-to-date information on the Mobile Application, we make no warranties or representations as to its accuracy, timeliness or completeness.

-

9.6 We shall not be liable for any acts or omissions of any third parties howsoever caused, and for any direct, indirect, incidental, special, consequential or punitive damages, howsoever caused, resulting from or in connection with the Mobile Application and the services offered in the mobile application, Users’ access to, use of or inability to use the mobile application or the services offered in the mobile application, reliance on or downloading from the mobile application and/or services, or any delays, inaccuracies in the information or in its transmission including but not limited to damages for loss of business or profits, use, data or other intangible, even if we have been advised of the possibility of such damages.

-

9.7 We shall not be liable in contract, tort (including negligence or breach of statutory duty) or otherwise howsoever and whatever the cause thereof, for any indirect, consequential, collateral, special or incidental loss or damage suffered or incurred by the User in connection with the Mobile Application and these Terms and Conditions of Use. For the purposes of these Terms and Conditions of Use, indirect or consequential loss or damage includes, without limitation, loss of revenue, profits, anticipated savings or business, loss of data or goodwill, loss of use or value of any equipment including software, claims of third parties, and all associated and incidental costs and expenses.

-

9.8 The above exclusions and limitations apply only to the extent permitted by law. None of the User’s statutory rights as a consumer that cannot be excluded or limited are affected.

-

9.9 Notwithstanding our efforts to ensure that our system is secure, the User acknowledges that all electronic data transfers are potentially susceptible to interception by others. We cannot, and do not, warrant that data transfers pursuant to the Mobile Application, or electronic mail transmitted to and from us, will not be monitored or read by others.

-

-

10. INDEMNITY

-

The User agrees to indemnify and keep us indemnified against any claim, action, suit or proceeding brought or threatened to be brought against us which is caused by or arising out of (a) the User’s use of the Services, (b) any other party’s use of the Services using the User’s user ID, verification PIN and/or any identifier number allocated by the Company, and/or (c) the User’s breach of any of these Terms and Conditions of Use, and to pay us damages, costs and interest in connection with such claim, action, suit or proceeding.

-

-

11. INTELLECTUAL PROPERTY RIGHTS

-

11.1 All editorial content, information, photographs, illustrations, artwork and other graphic materials, and names, logos and trade marks on the Mobile Application are protected by copyright laws and/or other laws and/or international treaties, and belong to us and/or our suppliers, as the case may be. These works, logos, graphics, sounds or images may not be copied, reproduced, retransmitted, distributed, disseminated, sold, published, broadcasted or circulated whether in whole or in part, unless expressly permitted by us and/or our suppliers, as the case may be.

-

11.2 Nothing contained on the Mobile Application should be construed as granting by implication, estoppel, or otherwise, any license or right to use any trademark displayed on the Mobile Application without our written permission. Misuse of any trademarks or any other content displayed on the Mobile Application is prohibited.

-

11.3 We will not hesitate to take legal action against any unauthorized usage of our trade marks, name or symbols to preserve and protect its rights in the matter. All rights not expressly granted herein are reserved. Other product and company names mentioned herein may also be the trademarks of their respective owners.

-

-

12. AMENDMENTS

-

12.1 We may periodically make changes to the contents of the Mobile Application, including to the descriptions and prices of goods and services advertised, at any time and without notice. We assume no liability or responsibility for any errors or omissions in the content of the Mobile Application.

-

12.2 We reserve the right to amend these Terms and Conditions of Use from time to time without notice. The revised Terms and Conditions of Use will be posted on the Mobile Application and shall take effect from the date of such posting. The User is advised to review these terms and conditions periodically as they are binding upon the User.

-

-

13. APPLICABLE LAW AND JURISDICTION

-

13.1 These Terms and Conditions of Use shall be governed by and construed in accordance with the applicable Federal laws of Kingdom of Saudi Arabia.

-

13.2 The Mobile Application can be accessed from all countries around the world where the local technology permits. As each of these places have differing laws, by accessing the Mobile Application both the User and we agree that the laws of the country where accessed, without regard to the conflicts of laws principles thereof, will apply to all matters relating to the use of the Mobile Application.

-

13.3 the User accepts and agrees that both the User and we shall submit to the exclusive jurisdiction of the courts of the country where accessed in respect of any dispute arising out of and/or in connection with these Terms and Conditions of Use.

-

-

14. PRIVACY POLICY

-

14.1 Access to the Mobile Application and use of the Services offered on the Mobile Application by the Company and/or its group of companies & partners is subject to this Privacy Policy. By accessing the Mobile Application and by continuing to use the Services offered, Users are deemed to have accepted this Privacy Policy, and in particular, they are deemed to have consented to our use and disclosure of their personal information in the manner prescribed in this Privacy Policy and for the purposes set out in Clauses 3.7 and/or 4.1.1 We reserve the right to amend this Privacy Policy from time to time. If the User disagrees with any part of this Privacy Policy, the User must immediately discontinue their access to the Mobile Application and their use of the Services.

-

14.2 As part of the normal operation of our Services, we collect, use and, in some cases, disclose information about the User to third parties. Accordingly, we have developed this Privacy Policy in order for Users to understand how we collect, use, communicate and disclose and make use of their personal information when they use the Services on the Mobile Application:-

-

(a) Before or at the time of collecting personal information, we will identify the purposes for which information is being collected.

-

(b) We will collect and use of personal information solely with the objective of fulfilling those purposes specified by us and for other compatible purposes, unless we obtain the consent of the individual concerned or as required by law.

-

(c) We will only retain personal information as long as necessary for the fulfillment of those purposes.

-

(d) We will collect personal information by lawful and fair means and, where appropriate, with the knowledge or consent of the individual concerned.

-

(e) Personal information should be relevant to the purposes for which it is to be used, and, to the extent necessary for those purposes, should be accurate, complete, and up-to-date.

-

(f) We will protect personal information by reasonable security safeguards against loss or theft, as well as unauthorized access, disclosure, copying, use or modification.

-

(g) The Company further reserves the right to use all legal means possible and to identify the Users, as well as to request, at any time, additional data and documents it considers appropriate in order to verify personal data informed by the user.

-

We are committed to conducting our business in accordance with these principles in order to ensure that the confidentiality of personal information is protected and maintained.

-

14.3 Social logins policy
Our Services offers you the ability to register and login using Facebook. Where you choose to do this, we will receive certain profile information about you from your social media provider. The profile Information may include your name and social token.
We will use the information we receive only to associate your social token with your Intaleq account or for the purposes that are described in this privacy policy.

14.4 Account and data deletion
Based on the applicable laws of your country, you may have the right to request the deletion of your personal data in some circumstances. If you want to delete your account or personal data in the application, please contact us via e-mail: support@mobile-app.store. We will respond to your request within 30 days.

-

15. In-Ride Policy

-

15.1 Smoking Policy:

-

No smoking or other use of tobacco products (including, but not limited to, cigarettes, pipes, cigars, snuff, or chewing tobacco) is permitted during rides. No cigarette butts or other traces of smell, litter, or tobacco use should be present in the vehicle. image

-

15.2 COVID-19 Policy: Face masks must be always worn during rides.

-
-
-
-
-
+
+

تاريخ النفاذ: 9 أغسطس 2025

+

آخر تحديث: 9 أغسطس 2025

+

1. المقدمة والقبول

+

عبر تحميل أو تسجيل أو استخدام تطبيق "انطلق" ("التطبيق")، فإنك توافق على الالتزام بسياسة الخصوصية وشروط الاستخدام هذه. إذا كنت لا توافق، يجب عليك التوقف فورًا عن استخدام التطبيق. استمرارك في الاستخدام يُعد قبولاً لهذه الشروط وأي تحديثات مستقبلية لها.

+

2. التعريفات

+ + +

3. سياسة الخصوصية

- - -
-
- - - - -
-

- All rights reserved. Fast Global Technology Holding Limited. © 2022 -

-
-
- -
- - - - -
- - - +

أ. المعلومات التي تقدمها بنفسك:

+ + +

ب. المعلومات التي تُجمع تلقائيًا:

+ + +

3.2 معلومات الدفع

+

نحن لا نجمع أو نعالج أو نخزن أي معلومات دفع حساسة مثل أرقام بطاقات الائتمان/الخصم. نحن نسهل عمليات الدفع عبر ربطك بمزودي خدمات محليين مرخصين:

+ - - -
+

6. تحديثات السياسة

+

قد نقوم بتحديث هذه الشروط. في حال إجراء تغييرات جوهرية، سنقوم بإعلامك داخل التطبيق. سيُطلب منك مراجعة الشروط الجديدة وقبولها لمواصلة استخدام الخدمات، لضمان أن موافقتك فعالة ومبنية على معرفة.

+

7. حذف الحساب والتواصل

+

لديك الحق في طلب حذف حسابك وبياناتك الشخصية. للقيام بذلك، أو لأي استفسارات أخرى، يرجى التواصل معنا. سنرد على طلبات الحذف في غضون 30 يومًا.

+

البريد الإلكتروني: support@intaleqapp.com

+ + + '''; } diff --git a/lib/controller/auth/certificate.dart b/lib/controller/auth/certificate.dart new file mode 100644 index 0000000..27ba20a --- /dev/null +++ b/lib/controller/auth/certificate.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; +import 'package:crypto/crypto.dart'; + +Future verifyCertificateManually( + String host, int port, String expectedPin) async { + try { + final socket = await SecureSocket.connect(host, port, + timeout: const Duration(seconds: 5)); + + final certificate = socket.peerCertificate; + if (certificate == null) { + print("❌ لا يوجد شهادة."); + return false; + } + + final der = certificate.der; + final actualPin = base64.encode(sha256.convert(der).bytes); + + print("📛 HOST: $host"); + print("📜 Subject: ${certificate.subject}"); + print("📜 Issuer: ${certificate.issuer}"); + print("📅 Valid From: ${certificate.startValidity}"); + print("📅 Valid To: ${certificate.endValidity}"); + print( + "🔐 Server Pin: $actualPin → ${actualPin == expectedPin ? '✅ MATCH' : '❌ MISMATCH'}"); + + socket.destroy(); + return actualPin == expectedPin; + } catch (e) { + print("❌ خطأ أثناء الاتصال أو الفحص: $e"); + return false; + } +} + +/// تحويل المفتاح العام إلى بصمة SHA-256 +List sha256Convert(Uint8List der) { + return sha256.convert(der).bytes; +} diff --git a/lib/controller/auth/otp_controller.dart b/lib/controller/auth/otp_controller.dart index 518357f..2ad926e 100644 --- a/lib/controller/auth/otp_controller.dart +++ b/lib/controller/auth/otp_controller.dart @@ -25,7 +25,7 @@ class PhoneAuthHelper { link: _sendOtpUrl, payload: {'receiver': phoneNumber}, ); - // Log.print('response: ${response}'); + Log.print('response: ${response}'); if (response != 'failure') { final data = (response); // if (data['status'] == 'success') { diff --git a/lib/controller/firebase/firbase_messge.dart b/lib/controller/firebase/firbase_messge.dart index 0ba0091..69e9615 100644 --- a/lib/controller/firebase/firbase_messge.dart +++ b/lib/controller/firebase/firbase_messge.dart @@ -216,7 +216,7 @@ class FirebaseMessagesController extends GetxController { 'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'ding'); } update(); - } else if (message.notification!.title! == 'Hi ,I Arrive your site') { + } else if (message.notification!.title! == 'Hi ,I Arrive your site'.tr) { if (Platform.isAndroid) { notificationController.showNotification( 'Hi ,I Arrive your site'.tr, ''.tr, 'ding'); diff --git a/lib/controller/home/device_tier.dart b/lib/controller/home/device_tier.dart new file mode 100644 index 0000000..02f5f51 --- /dev/null +++ b/lib/controller/home/device_tier.dart @@ -0,0 +1,86 @@ +import 'dart:io'; +import 'package:device_info_plus/device_info_plus.dart'; + +import '../../main.dart'; + +// مفاتيح التخزين (بسيطة) +const _kDeviceTierKey = 'deviceTier'; // 'low' | 'mid' | 'high' +const _kDeviceTierCheckedAtKey = 'deviceTierTime'; // millisSinceEpoch + +Future detectAndCacheDeviceTier({bool force = false}) async { + // لا تعيد الفحص إذا عملناه خلال آخر 24 ساعة + if (!force) { + final last = box.read(_kDeviceTierCheckedAtKey); + if (last is int) { + final dt = DateTime.fromMillisecondsSinceEpoch(last); + if (DateTime.now().difference(dt) < const Duration(hours: 24)) { + final cached = box.read(_kDeviceTierKey); + if (cached is String && cached.isNotEmpty) + return cached; // low/mid/high + } + } + } + + final info = DeviceInfoPlugin(); + int score = 0; + + if (Platform.isAndroid) { + final a = await info.androidInfo; + final int sdk = a.version.sdkInt ?? 0; + final int cores = Platform.numberOfProcessors; + final int abisCount = a.supportedAbis.length; + final bool isEmu = !(a.isPhysicalDevice ?? true); + + // SDK (أقدم = أضعف) + if (sdk <= 26) + score += 3; // 8.0 وأقدم + else if (sdk <= 29) + score += 2; // 9-10 + else if (sdk <= 30) score += 1; // 11 + + // الأنوية + if (cores <= 4) + score += 3; + else if (cores <= 6) + score += 2; + else if (cores <= 8) score += 1; + + // ABI count (القليل غالباً أضعف) + if (abisCount <= 1) + score += 2; + else if (abisCount == 2) score += 1; + + // محاكي + if (isEmu) score += 2; + } else { + // iOS/منصات أخرى: تقدير سريع بالأنوية فقط + final int cores = Platform.numberOfProcessors; + if (cores <= 4) + score += 3; + else if (cores <= 6) + score += 2; + else if (cores <= 8) score += 1; + } + + // تحويل السكور إلى تصنيف + final String tier = (score >= 6) + ? 'low' + : (score >= 3) + ? 'mid' + : 'high'; + + box.write(_kDeviceTierKey, tier); + box.write(_kDeviceTierCheckedAtKey, DateTime.now().millisecondsSinceEpoch); + return tier; +} + +// للقراءة السريعة وقت ما تحتاج: +String getCachedDeviceTier() { + final t = box.read(_kDeviceTierKey); + if (t is String && t.isNotEmpty) return t; + return 'mid'; +} + +bool isLowEnd() => getCachedDeviceTier() == 'low'; +bool isMidEnd() => getCachedDeviceTier() == 'mid'; +bool isHighEnd() => getCachedDeviceTier() == 'high'; diff --git a/lib/controller/home/map_passenger_controller.dart b/lib/controller/home/map_passenger_controller.dart index c532eac..533e6db 100644 --- a/lib/controller/home/map_passenger_controller.dart +++ b/lib/controller/home/map_passenger_controller.dart @@ -5,6 +5,7 @@ import 'dart:math' show Random, atan2, cos, max, min, pi, pow, sin, sqrt; import 'dart:math' as math; import 'dart:ui'; import 'dart:convert'; +import 'package:device_info_plus/device_info_plus.dart'; import 'package:http/http.dart' as http; import 'package:Intaleq/constant/univeries_polygon.dart'; @@ -51,6 +52,7 @@ import '../functions/launch.dart'; import '../functions/package_info.dart'; import '../functions/secure_storage.dart'; import '../payment/payment_controller.dart'; +import 'device_tier.dart'; import 'vip_waitting_page.dart'; class MapPassengerController extends GetxController { @@ -256,6 +258,7 @@ class MapPassengerController extends GetxController { late double totalPassengerBalashDiscount = 0; late double totalPassengerRaihGaiDiscount = 0; late double totalPassengerScooter = 0; + late double totalPassengerVan = 0; late double totalDriver = 0; late double averageDuration = 0; late double costDuration = 0; @@ -2830,6 +2833,23 @@ class MapPassengerController extends GetxController { pow(start.longitude - end.longitude, 2)); } + String formatSyrianPhoneNumber(String phoneNumber) { + // Trim any whitespace from the input. + String trimmedPhone = phoneNumber.trim(); + + // If the number starts with '09', remove the leading '0' and prepend '963'. + if (trimmedPhone.startsWith('09')) { + return '963${trimmedPhone.substring(1)}'; + } + // If the number already starts with '963', return it as is to avoid duplication. + if (trimmedPhone.startsWith('963')) { + return trimmedPhone; + } + // For any other case (e.g., number starts with '9' without a '0'), + // prepend '963' to ensure the correct format. + return '963$trimmedPhone'; + } + Future getTokenForParent() async { if (box.read(BoxName.sosPhonePassenger) == null) { Get.defaultDialog( @@ -2840,7 +2860,7 @@ class MapPassengerController extends GetxController { child: MyTextForm( controller: sosPhonePassengerProfile, label: 'insert sos phone'.tr, - hint: 'insert sos phone'.tr, + hint: 'e.g. 0912345678'.tr, type: TextInputType.phone, ), ), @@ -2849,22 +2869,22 @@ class MapPassengerController extends GetxController { onPressed: () async { if (sosFormKey.currentState!.validate()) { Get.back(); + var numberPhone = + formatSyrianPhoneNumber(sosPhonePassengerProfile.text); await CRUD().post( link: AppLink.updateprofile, payload: { 'id': box.read(BoxName.passengerID), - 'sosPhone': sosPhonePassengerProfile.text, + 'sosPhone': numberPhone, }, ); - box.write( - BoxName.sosPhonePassenger, sosPhonePassengerProfile.text); + box.write(BoxName.sosPhonePassenger, numberPhone); } })); } - + var numberPhone = formatSyrianPhoneNumber(sosPhonePassengerProfile.text); var res = await CRUD().getTokenParent( - link: AppLink.getTokenParent, - payload: {'phone': '+2${box.read(BoxName.sosPhonePassenger)}'}); + link: AppLink.getTokenParent, payload: {'phone': numberPhone}); // Check if `res` is already a map if (res is Map) { @@ -3158,11 +3178,51 @@ class MapPassengerController extends GetxController { mapController?.animateCamera(CameraUpdate.newLatLng(newPosition)); } + // @override + // void onClose() { + // _timer?.cancel(); + // _animationTimers.forEach((_, timer) => timer.cancel()); + // _animationTimers.clear(); + // super.onClose(); + // } @override void onClose() { + print( + "--- MapPassengerController: Closing and cleaning up all resources. ---"); + + // 1. إلغاء المؤقتات الفردية + // Using ?.cancel() is safe even if the timer is null + markerReloadingTimer.cancel(); + markerReloadingTimer1.cancel(); + markerReloadingTimer2.cancel(); + timerToPassengerFromDriverAfterApplied?.cancel(); _timer?.cancel(); - _animationTimers.forEach((_, timer) => timer.cancel()); + + // 2. إلغاء جميع المؤقتات في الخريطة (للتحريكات السلسة) + _animationTimers.forEach((key, timer) { + timer.cancel(); + }); _animationTimers.clear(); + + // 3. إغلاق متحكمات البث (StreamControllers) لمنع تسريب الذاكرة + // Using .close() is the correct way to shut down a stream + if (!_timerStreamController.isClosed) { + _timerStreamController.close(); + } + if (!_beginRideStreamController.isClosed) { + _beginRideStreamController.close(); + } + if (!_rideStatusStreamController.isClosed) { + _rideStatusStreamController.close(); + } + if (!timerController.isClosed) { + timerController.close(); + } + + // 4. التخلص من متحكم الخريطة (ممارسة جيدة) + mapController?.dispose(); + + print("--- Cleanup complete. ---"); super.onClose(); } @@ -3462,55 +3522,85 @@ class MapPassengerController extends GetxController { update(); } + double _haversineKm(double lat1, double lon1, double lat2, double lon2) { + const R = 6371.0; // km + final dLat = (lat2 - lat1) * math.pi / 180.0; + final dLon = (lon2 - lon1) * math.pi / 180.0; + final a = math.sin(dLat / 2) * math.sin(dLat / 2) + + math.cos(lat1 * math.pi / 180.0) * + math.cos(lat2 * math.pi / 180.0) * + math.sin(dLon / 2) * + math.sin(dLon / 2); + final c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)); + return R * c; + } + Future getPlaces() async { - final isTextEmpty = placeDestinationController.text.trim().isEmpty; - if (isTextEmpty) { - placesDestination = []; // لا يوجد نص للبحث + final q = placeDestinationController.text.trim(); + if (q.isEmpty) { + placesDestination = []; update(); return; } - final query = placeDestinationController.text.trim(); final lat = passengerLocation.latitude; final lng = passengerLocation.longitude; - // حدود البحث ±0.2 تقريبًا ~ مسافة 20 كم تقريبًا - final double range = 2.2; - final lat_min = lat - range; - final lat_max = lat + range; - final lng_min = lng - range; - final lng_max = lng + range; + const range = 2.2; + final latMin = lat - range; + final latMax = lat + range; + final lngMin = lng - range; + final lngMax = lng + range; try { final response = await CRUD().post( link: AppLink.getPlacesSyria, payload: { - 'query': query, - 'lat_min': lat_min.toString(), - 'lat_max': lat_max.toString(), - 'lng_min': lng_min.toString(), - 'lng_max': lng_max.toString(), + 'query': q, + 'lat_min': latMin.toString(), + 'lat_max': latMax.toString(), + 'lng_min': lngMin.toString(), + 'lng_max': lngMax.toString(), }, ); - print('response: $response'); - if (response != 'failure') { - final data = (response); - Log.print('data: ${data}'); + final list = (response['message'] as List?) ?? []; - placesDestination = data['message'] ?? []; - Log.print('placesDestination.length: ${placesDestination.length}'); + // احسب المسافة وألصقها بكل عنصر + for (final p in list) { + final plat = double.tryParse(p['latitude']?.toString() ?? '') ?? 0.0; + final plng = double.tryParse(p['longitude']?.toString() ?? '') ?? 0.0; + p['distanceKm'] = _haversineKm(lat, lng, plat, plng); + } + // رتّب حسب الأقرب + list.sort((a, b) { + final da = (a['distanceKm'] ?? 1e9) as double; + final db = (b['distanceKm'] ?? 1e9) as double; + final cmp = da.compareTo(db); + if (cmp != 0) return cmp; + + // تعادل؟ فضّل من يطابق الاسم + final nameA = + (a['name'] ?? a['name_ar'] ?? a['name_en'] ?? '').toString(); + final nameB = + (b['name'] ?? b['name_ar'] ?? b['name_en'] ?? '').toString(); + final qLower = q.toLowerCase(); + final hitA = nameA.toLowerCase().contains(qLower) ? 0 : 1; + final hitB = nameB.toLowerCase().contains(qLower) ? 0 : 1; + return hitA.compareTo(hitB); + }); + + placesDestination = list; update(); } else { - print('Server error: ${response.statusCode}'); + print('Server error'); } } catch (e) { print('Exception: $e'); } - } - // Future getPlaces() async { + } // Future getPlaces() async { // var languageCode; // // تحديد اللغة حسب الإدخال @@ -3713,6 +3803,100 @@ class MapPassengerController extends GetxController { } } +// داخل MapPassengerController + bool lowPerf = false; + Timer? _camThrottle; + DateTime _lastUiUpdate = DateTime.fromMillisecondsSinceEpoch(0); + +// نادِها في onInit مثلاً + Future detectPerfMode() async { + try { + if (GetPlatform.isAndroid) { + final info = await DeviceInfoPlugin().androidInfo; + final sdk = info.version.sdkInt ?? 0; + final ram = info.availableRamSize ?? 0; + lowPerf = (sdk < 28) || (ram > 0 && ram < 3 * 1024 * 1024 * 1024); + } else { + lowPerf = false; + } + } catch (_) { + lowPerf = false; + } + update(); + } + +// تحديث الكاميرا بثروتل + void onCameraMoveThrottled(CameraPosition pos) { + if (_camThrottle?.isActive ?? false) return; + _camThrottle = Timer(const Duration(milliseconds: 160), () { + // ضع فقط المنطق الضروري هنا لتقليل الحمل + int waypointsLength = Get.find().wayPoints.length; + int index = wayPointIndex; + if (waypointsLength > 0) { + placesCoordinate[index] = + '${pos.target.latitude},${pos.target.longitude}'; + } + newMyLocation = pos.target; + }); + } + +// تهيئة polylines خفيفة (استدعها بعد جلب المسار) + Set polyLinesLight = {}; + List simplifyPolyline(List pts, double epsilonMeters) { + if (pts.length <= 2) return pts; + double _perpDist(LatLng p, LatLng a, LatLng b) { + // مسافة عمودية تقريبية بالأمتار + double _toRad(double d) => d * math.pi / 180.0; + // تحويل بسيط للمتر (تقريبي) + final x1 = a.longitude, y1 = a.latitude; + final x2 = b.longitude, y2 = b.latitude; + final x0 = p.longitude, y0 = p.latitude; + final num = ((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1).abs(); + final den = math.sqrt(math.pow(y2 - y1, 2) + math.pow(x2 - x1, 2)); + // تحويل درجات -> أمتار تقريبي (1 درجة ~ 111km) + final degDist = den == 0 ? 0 : num / den; + return degDist * 111000; // متر + } + + List dp(int start, int end) { + double maxDist = 0; + int index = start; + for (int i = start + 1; i < end; i++) { + final d = _perpDist(pts[i], pts[start], pts[end]); + if (d > maxDist) { + maxDist = d; + index = i; + } + } + if (maxDist > epsilonMeters) { + final r1 = dp(start, index); + final r2 = dp(index, end); + return [...r1.sublist(0, r1.length - 1), ...r2]; + } else { + return [pts[start], pts[end]]; + } + } + + return dp(0, pts.length - 1); + } + + void buildLightPolylines(List originalPoints) { + final simplified = simplifyPolyline(originalPoints, lowPerf ? 12 : 3); + polyLinesLight = { + Polyline( + polylineId: const PolylineId('route_light'), + points: simplified, + width: lowPerf ? 4 : 6, + geodesic: true, + color: AppColor.primaryColor, + endCap: Cap.roundCap, + startCap: Cap.roundCap, + jointType: JointType.round, + ), + }; + update(); + } + Future savePlaceToServer( String latitude, String longitude, String name, String rate) async { var data = { @@ -4008,7 +4192,7 @@ class MapPassengerController extends GetxController { await getCarsLocationByPassengerAndReloadMarker( box.read(BoxName.carType), 5000); await getNearestDriverByPassengerLocation(); - Log.print('reloadMarkers: from startMarkerReloading'); + // Log.print('reloadMarkers: from startMarkerReloading'); } else { // runWhenRideIsBegin(); } @@ -4328,7 +4512,7 @@ class MapPassengerController extends GetxController { box.write(BoxName.tripData, response); startNameAddress = shortenAddress(data[0]['start_address']); - print('data[0][start_address]: ${data[0]['start_address']}'); + // print('data[0][start_address]: ${data[0]['start_address']}'); endNameAddress = shortenAddress(data[0]['end_address']); isLoading = false; newStartPointLocation = LatLng( @@ -4387,25 +4571,28 @@ class MapPassengerController extends GetxController { position: LatLng( data[0]["end_location"]['lat'], data[0]["end_location"]['lng']), icon: endIcon, - infoWindow: InfoWindow( - title: endNameAddress, - snippet: - '$distance ${'KM'.tr} ⌛ ${hours > 0 ? '${'Your Ride Duration is '.tr}$hours ${'H and'.tr} $minutes ${'m'.tr}' : '${'Your Ride Duration is '.tr} $minutes ${'m'.tr}'}'), + // infoWindow: InfoWindow( + // title: endNameAddress, + // snippet: + // '$distance ${'KM'.tr} ⌛ ${hours > 0 ? '${'Your Ride Duration is '.tr}$hours ${'H and'.tr} $minutes ${'m'.tr}' : '${'Your Ride Duration is '.tr} $minutes ${'m'.tr}'}'), ), ); // // Show info windows automatically // Future.delayed(const Duration(milliseconds: 500), () { // mapController?.showMarkerInfoWindow(const MarkerId('start')); // }); - Future.delayed(const Duration(milliseconds: 500), () { - mapController?.showMarkerInfoWindow(const MarkerId('end')); - }); - update(); + // Future.delayed(const Duration(milliseconds: 500), () { + // mapController?.showMarkerInfoWindow(const MarkerId('end')); + // }); + // update(); if (polyLines.isNotEmpty) { clearPolyline(); } else { - _animatePolyline(polylineCoordinates); + // الآن بإمكانك قراءة القيمة من الـBox في أي مكان: + bool lowEndMode = box.read(BoxName.lowEndMode) ?? true; + + animatePolylineLayered(polylineCoordinates); rideConfirm = false; isMarkersShown = true; @@ -4413,50 +4600,95 @@ class MapPassengerController extends GetxController { } } - Future _animatePolyline(List coordinates) async { - const int totalAnimations = 7; +// 1) تقليل النقاط إلى حد أقصى 30 نقطة (مع بداية ونهاية محفوظة وتوزيع متساوٍ) + List _downsampleEven(List coords, {int maxPoints = 30}) { + if (coords.isEmpty) return const []; + if (coords.length <= maxPoints) return List.from(coords); - Color getAnimationColor(int cycle) { - switch (cycle) { - case 0: - return AppColor.primaryColor; - case 1: - return AppColor.writeColor; - case 2: - return AppColor.primaryColor; - default: - return AppColor.primaryColor; - } + final int n = coords.length; + final int keep = maxPoints.clamp(2, n); + final List idx = []; + for (int i = 0; i < keep; i++) { + final double pos = i * (n - 1) / (keep - 1); + idx.add(pos.round()); } + final seen = {}; + final List out = []; + for (final i in idx) { + if (seen.add(i)) out.add(coords[i]); + } + if (out.first != coords.first) out.insert(0, coords.first); + if (out.last != coords.last) out.add(coords.last); + while (out.length > maxPoints) { + out.removeAt(out.length ~/ 2); + } + return out; + } - for (int cycle = 0; cycle < totalAnimations; cycle++) { - polyLines.clear(); - List animatedPoints = []; +// 2) رسم متدرّج بطبقات متراكبة (بدون حذف)، برونزي ↔ أخضر، مع zIndex وعرض مختلف + Future animatePolylineLayered(List coordinates, + {int layersCount = 8, int stepDelayMs = 10}) async { + // امسح أي طبقات قديمة فقط الخاصة بالطريق + polyLines.removeWhere((p) => p.polylineId.value.startsWith('route_layer_')); + update(); + + final List coords = _downsampleEven(coordinates, maxPoints: 20); + if (coords.length < 2) return; + + // ألوان مع شفافية خفيفة للتمييز + Color bronze([int alpha = 220]) => const Color(0xFFCD7F32).withAlpha(alpha); + Color green([int alpha = 220]) => Colors.green.withAlpha(alpha); + + Color _layerColor(int layer) => (layer % 2 == 0) ? bronze() : green(); + + // عرض الخط: البرونزي أعرض، الأخضر أنحف + int _layerWidth(int layer) => (layer % 2 == 0) ? 6 : 4; + + // لكل طبقة: أنشئ Polyline بهوية فريدة وزي إندكس أعلى من السابقة + for (int layer = 0; layer < layersCount; layer++) { + final id = PolylineId('route_layer_$layer'); + polyLines.add(Polyline( + polylineId: id, + points: const [], + width: _layerWidth(layer), + color: _layerColor(layer), + zIndex: layer, // مهم لإظهار جميع الطبقات + endCap: Cap.roundCap, + startCap: Cap.roundCap, + geodesic: true, + visible: true, + )); + } + update(); + + // نبني كل طبقة تدريجيًا فوق التي قبلها — بدون مسح الطبقات السابقة + for (int layer = 0; layer < layersCount; layer++) { + final id = PolylineId('route_layer_$layer'); + final List growing = []; + + for (int i = 0; i < coords.length; i++) { + growing.add(coords[i]); + + // حدّث فقط هذه الطبقة + polyLines.removeWhere((p) => p.polylineId == id); + polyLines.add(Polyline( + polylineId: id, + points: List.from(growing), + width: _layerWidth(layer), + color: _layerColor(layer), + zIndex: layer, + endCap: Cap.roundCap, + startCap: Cap.roundCap, + geodesic: true, + visible: true, + )); - for (int i = 0; i < coordinates.length; i++) { - animatedPoints.add(coordinates[i]); - polyLines.clear(); - polyLines.add( - Polyline( - polylineId: const PolylineId('animated_route'), - points: List.from(animatedPoints), - width: 4, - color: getAnimationColor(cycle), - endCap: Cap.roundCap, - startCap: Cap.roundCap, - geodesic: true, - ), - ); update(); - await Future.delayed(const Duration(milliseconds: 10)); + await Future.delayed(Duration(milliseconds: stepDelayMs)); } - if (cycle < totalAnimations - 1) { - await Future.delayed(const Duration(milliseconds: 500)); - polyLines.clear(); - update(); - await Future.delayed(const Duration(milliseconds: 200)); - } + // مهلة خفيفة بين الطبقات عشان يبان التبديل + await Future.delayed(const Duration(milliseconds: 120)); } } @@ -4518,59 +4750,6 @@ class MapPassengerController extends GetxController { double distanceOfDestination = 0; bool haveSteps = false; late LatLng latestPosition; -// getMapPoints(String originSteps, String destinationSteps, int index) async { -// isWayPointStopsSheetUtilGetMap = false; -// haveSteps = true; -// await getCarsLocationByPassenger(); -// // isLoading = true; -// update(); -// String url = '${AppLink.googleMapsLink}directions/json' -// '?origin=${coordinatesWithoutEmpty.first}' -// '&destination=${coordinatesWithoutEmpty.last}'; -// if (coordinatesWithoutEmpty.length > 2) { -// String waypoints = ""; -// for (int i = 1; i < coordinatesWithoutEmpty.length - 1; i++) { -// waypoints += "${coordinatesWithoutEmpty[i]}|"; -// } -// waypoints = waypoints.substring(0, waypoints.length - 1); -// url += "&waypoints=$waypoints"; -// } -// url += '&language=en' -// '&avoid=tolls|ferries' -// '&key=${AK.mapAPIKEY}'; -// var response = await CRUD().getGoogleApi(link: url, payload: {}); -// data = response['routes'][0]['legs']; -// // isLoading = false; -// int durationToRide0 = data[0]['duration']['value']; -// durationToRide = durationToRide + durationToRide0; -// distance = distanceOfDestnation + (data[0]['distance']['value']) / 1000; -// update(); -// final points = -// decodePolyline(response["routes"][0]["overview_polyline"]["points"]); -// for (int i = 0; i < points.length; i++) { -// if (points[i][0].toString() != '') { -// double lat = points[i][0].toDouble(); -// double lng = points[i][1].toDouble(); -// polylineCoordinatesPointsAll[index].add(LatLng(lat, lng)); -// } -// } -// // Define the northeast and southwest coordinates -// update(); -// if (polyLines.isNotEmpty) { -// // clearPolyline(); -// } else { -// var polyline = Polyline( -// polylineId: PolylineId(response["routes"][0]["summary"]), -// points: polylineCoordinatesPointsAll[index], -// width: 10, -// color: Colors.blue, -// ); -// polyLines.add(polyline); -// rideConfirm = false; -// // isMarkersShown = true; -// update(); -// } -// } getMapPoints(String originSteps, String destinationSteps, int index) async { isWayPointStopsSheetUtilGetMap = false; @@ -4670,161 +4849,149 @@ class MapPassengerController extends GetxController { final promo = TextEditingController(); bool promoTaken = false; 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 || - totalPassengerElectric > 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; - totalPassengerElectricDiscount = - totalPassengerElectric * 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( - 'totalPassengerElectricDiscount: $totalPassengerElectricDiscount'); - totalPassengerElectric = - totalPassengerElectric - totalPassengerElectricDiscount; - totalPassengerElectricDiscount = - totalPassengerElectric * discountPercentage / 100; - if (totalPassengerElectricDiscount > 25) { - totalPassengerElectricDiscount = - 25; // Limit the discount to 25 - } - Log.print( - 'totalPassengerElectricDiscount: $totalPassengerElectricDiscount'); - totalPassengerElectric = - totalPassengerElectric - totalPassengerElectricDiscount; - - 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); - } - }); - } - } else { + if (promoTaken == true) { MyDialog().getDialog( - 'Promo Already Used'.tr, 'You have already used this promo code.'.tr, - () { - Get.back(); - }); + 'Promo Already Used'.tr, + 'You have already used this promo code.'.tr, + () => Get.back(), + ); + return; + } + + if (!promoFormKey.currentState!.validate()) return; + + // عتبات تفعيل البرومو بالليرة السورية + const double minPromoLowSYP = 16000; // Speed / Balash + const double minPromoHighSYP = 20000; // Comfort / Electric / Lady + + try { + final value = await CRUD().get( + link: AppLink.getPassengersPromo, + payload: {'promo_code': promo.text}, + ); + + if (value == 'failure') { + MyDialog().getDialog( + 'Promo Ended'.tr, + 'The promotion period has ended.'.tr, + () => Get.back(), + ); + return; + } + + // تحقق أولي: هل عندنا أي فئة حاليًا فوق العتبات لتفعيل البرومو؟ + final bool eligibleNow = (totalPassengerSpeed >= minPromoLowSYP) || + (totalPassengerBalash >= minPromoLowSYP) || + (totalPassengerComfort >= minPromoHighSYP) || + (totalPassengerElectric >= minPromoHighSYP) || + (totalPassengerLady >= minPromoHighSYP); + + if (!eligibleNow) { + Get.snackbar( + 'Lowest Price Achieved'.tr, 'Cannot apply further discounts.'.tr, + backgroundColor: AppColor.yellowColor); + return; + } + + final decode = jsonDecode(value); + if (decode["status"] != "success") { + MyDialog().getDialog( + 'Promo Ended'.tr, + 'The promotion period has ended.'.tr, + () => Get.back(), + ); + return; + } + + Get.snackbar('Promo Code Accepted'.tr, '', + backgroundColor: AppColor.greenColor); + + final firstElement = decode["message"][0]; + final int discountPercentage = + int.tryParse(firstElement['amount'].toString()) ?? 0; + + // قيمة المحفظة (قد تكون سالبة) + final double walletVal = double.tryParse( + box.read(BoxName.passengerWalletTotal)?.toString() ?? '0') ?? + 0.0; + + // دالة مساعدة: تطبق الخصم لكل فئة حسب عتبتها + double _applyDiscountPerTier({ + required double fare, + required double minThreshold, + required bool isWalletNegative, + }) { + if (fare < minThreshold) return fare; // غير مؤهل + + // منطقك السابق: + // - إذا المحفظة سالبة: fare + (-wallet) - (fare * pct) + // - إذا المحفظة ليست سالبة: fare - (fare * pct) + final double discount = fare * (discountPercentage / 100.0); + + if (isWalletNegative) { + final double neg = (-1) * walletVal; // walletVal < 0 + return (fare + neg - discount).clamp(0, double.infinity); + } else { + return (fare - discount).clamp(0, double.infinity); + } + } + + final bool isWalletNegative = walletVal < 0; + + // Comfort + totalPassengerComfort = _applyDiscountPerTier( + fare: totalPassengerComfort, + minThreshold: minPromoHighSYP, + isWalletNegative: isWalletNegative, + ); + + // Electric + totalPassengerElectric = _applyDiscountPerTier( + fare: totalPassengerElectric, + minThreshold: minPromoHighSYP, + isWalletNegative: isWalletNegative, + ); + + // Lady + totalPassengerLady = _applyDiscountPerTier( + fare: totalPassengerLady, + minThreshold: minPromoHighSYP, + isWalletNegative: isWalletNegative, + ); + + // Speed + totalPassengerSpeed = _applyDiscountPerTier( + fare: totalPassengerSpeed, + minThreshold: minPromoLowSYP, + isWalletNegative: isWalletNegative, + ); + + // Balash + totalPassengerBalash = _applyDiscountPerTier( + fare: totalPassengerBalash, + minThreshold: minPromoLowSYP, + isWalletNegative: isWalletNegative, + ); + + // (اختياري) لو عندك فئات أخرى تريد تطبيق البرومو عليها، أضفها بنفس النمط. + + // تعديل دخل السائق حسب نسبة البرومو (كما كان في كودك) + totalDriver = totalDriver - (totalDriver * discountPercentage / 100.0); + + promoTaken = true; + update(); + + // مؤثرات نجاح + Confetti.launch( + context, + options: const ConfettiOptions(particleCount: 100, spread: 70, y: 0.6), + ); + + Get.back(); + await Future.delayed(const Duration(milliseconds: 120)); + } catch (e) { + Get.snackbar('Error'.tr, e.toString(), + backgroundColor: AppColor.redColor); } } @@ -4847,298 +5014,237 @@ class MapPassengerController extends GetxController { double totalPassengerRayehGaiComfort = 0; double totalPassengerRayehGaiBalash = 0; Future bottomSheet() async { - if (data.isNotEmpty) { - durationToAdd = Duration(seconds: durationToRide); - hours = durationToAdd.inHours; - minutes = (durationToAdd.inMinutes % 60).round(); - DateTime currentTime = DateTime.now(); - newTime = currentTime.add(durationToAdd); - averageDuration = (durationToRide / 60) / distance; - // costDuration = (durationToRide / 60) * averageDuration * 0.016; - costDuration = (durationToRide / 60).floorToDouble(); - 'passengerWalletTotal----- ${box.read(BoxName.passengerWalletTotal)}'; - double costComfort, - costSpeed, - costDelivery, - costBalash, - costLady, - costRayehGai, - costRayehGaiBalash, - costRayehGaiComfort = 0; - update(); + if (data.isEmpty) return; - if (startNameAddress.toLowerCase().contains('airport') || - endNameAddress.toLowerCase().contains('airport') || - startNameAddress.contains('مطار') || - startNameAddress.contains('المطار') || - endNameAddress.contains('مطار') || - endNameAddress.contains('المطار')) { - costComfort = - (distance * comfortPrice) + (costDuration * latePrice) + 20; - costSpeed = (distance * speedPrice) + (costDuration * latePrice) + 20; - costBalash = - (distance * (speedPrice - 1)) + (costDuration * latePrice) + 20; - costDelivery = - (distance * deliveryPrice) + (costDuration * latePrice) + 20; - costLady = - (distance * comfortPrice + 2) + (costDuration * latePrice) + 20; - costRayehGai = (distance * 2 * speedPrice) - - ((distance * 1 * speedPrice) * .4) + - costDuration * 2 * latePrice + - 20; - costRayehGaiComfort = (distance * 2 * comfortPrice) - - ((distance * 1 * comfortPrice) * .4) + - costDuration * 2 * latePrice + - 20; - costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) - - ((distance * 1 * (speedPrice - 1)) * .4) + - costDuration * 2 * latePrice + - 20; + // === إعدادات عامة === + const double minFareSYP = 16000; // حد أدنى + const double minBillableKm = 0.3; // حد أدنى للمسافة المفوترة + const double ladyFlatAddon = 2000; // إضافة ثابتة لـ Lady + const double airportAddonSYP = 20000; // إضافة المطار - update(); - } else if (currentTime.hour >= 21 && currentTime.hour < 0) { - // costDistance = distance * latePrice; - costComfort = (distance * comfortPrice) + costDuration * latePrice; - costSpeed = (distance * speedPrice) + costDuration * latePrice; - costBalash = (distance * (speedPrice - 1)) + costDuration * latePrice; - costDelivery = (distance * deliveryPrice) + costDuration * latePrice; - costLady = (distance * comfortPrice + 2) + costDuration * latePrice; - costRayehGai = (distance * 2 * speedPrice) - - ((distance * 1 * speedPrice) * .4) + - costDuration * 2 * latePrice; - costRayehGaiComfort = (distance * 2 * comfortPrice) - - ((distance * 1 * comfortPrice) * .4) + - costDuration * 2 * latePrice; - costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) - - ((distance * 1 * (speedPrice - 1)) * .4) + - costDuration * 2 * latePrice; + // كهرباء + const double electricPerKmUplift = 400; // زيادة/كم + const double electricFlatAddon = 1000; // زيادة ثابتة - update(); - } else if (currentTime.hour >= 1 && currentTime.hour < 5) { - // costDistance = distance * latePrice; - if (startNameAddress.contains('club') || - startNameAddress.contains('nightclub') || - startNameAddress.contains('ديسكو') || - startNameAddress.contains('ملهى ليلي') || - startNameAddress.contains('Night club')) { - // Your code here - costComfort = - (distance * comfortPrice) + costDuration * (latePrice + .5) * 2; - costSpeed = - (distance * speedPrice) + costDuration * (latePrice + .5) * 2; - costBalash = (distance * (speedPrice - 1)) + - costDuration * (latePrice + .5) * 2; - costDelivery = - (distance * deliveryPrice) + costDuration * (latePrice + .5) * 2; - costLady = (distance * comfortPrice + 2) + - costDuration * (latePrice + .5) * 2; - costRayehGai = (distance * 2 * speedPrice) - - ((distance * 1 * speedPrice) * .4) + - costDuration * 2 * (latePrice + .5) * 2; - costRayehGaiComfort = (distance * 2 * comfortPrice) - - ((distance * 1 * comfortPrice) * .4) + - costDuration * 2 * (latePrice + .5) * 2; - costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) - - ((distance * 1 * (speedPrice - 1)) * .4) + - costDuration * 2 * (latePrice + .5) * 2; + // Long Speed + const double longSpeedThresholdKm = 40.0; + const double longSpeedPerKm = 2600.0; // Speed عند >40كم - update(); - } - costComfort = - (distance * comfortPrice) + costDuration * (latePrice + .5); - costSpeed = (distance * speedPrice) + costDuration * (latePrice + .5); - costBalash = - (distance * (speedPrice - 1)) + costDuration * (latePrice + .5); - costDelivery = - (distance * deliveryPrice) + costDuration * (latePrice + .5); - costLady = - (distance * comfortPrice + 2) + costDuration * (latePrice + .5); - costRayehGai = (distance * 2 * speedPrice) - - ((distance * 1 * speedPrice) * .4) + - costDuration * 2 * latePrice; - costRayehGaiComfort = (distance * 2 * comfortPrice) - - ((distance * 1 * comfortPrice) * .4) + - costDuration * 2 * latePrice; - costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) - - ((distance * 1 * (speedPrice - 1)) * .4) + - costDuration * 2 * latePrice; + // قواعد الرحلات البعيدة للدقائق (تعمل لكل الأوقات) + const double mediumDistThresholdKm = 25.0; // >25كم + const double longDistThresholdKm = 35.0; // >35كم + const double longTripPerMin = 600.0; + const int minuteCapMedium = 60; // سقف دقائق عند >25كم + const int minuteCapLong = 60; // سقف دقائق عند >35كم + const int freeMinutesLong = 10; // عفو 10 دقائق عند >35كم - update(); - } else if (currentTime.hour >= 14 && currentTime.hour <= 17) { - // if (averageDuration > 2.5) { - // costDistance = distance * heavyPrice; - costComfort = (distance * comfortPrice) + costDuration * heavyPrice; - costSpeed = (distance * speedPrice) + costDuration * heavyPrice; - costBalash = (distance * (speedPrice - 1)) + costDuration * heavyPrice; - costDelivery = (distance * deliveryPrice) + costDuration * heavyPrice; - costLady = (distance * comfortPrice + 2) + costDuration * heavyPrice; - costRayehGai = (distance * 2 * speedPrice) - - ((distance * 1 * speedPrice) * .4) + - costDuration * 2 * heavyPrice; - costRayehGaiComfort = (distance * 2 * comfortPrice) - - ((distance * 1 * comfortPrice) * .4) + - costDuration * 2 * heavyPrice; - costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) - - ((distance * 1 * (speedPrice - 1)) * .4) + - costDuration * 2 * heavyPrice; + // تخفيضات المسافات الكبيرة للفئات غير Speed + const double extraReduction100 = 0.07; // +7% فوق تخفيض >40كم للرحلات >100كم + const double maxReductionCap = 0.35; // سقف 35% كحد أقصى - update(); - // } / - } else { - // costDistance = distance * (naturePrice - .1); - costComfort = (distance * comfortPrice) + costDuration; - costSpeed = (distance * speedPrice) + costDuration; - costBalash = (distance * (speedPrice - 1)) + costDuration; - costDelivery = (distance * deliveryPrice) + costDuration; - costLady = (distance * comfortPrice + 2) + costDuration; - costRayehGai = (distance * 2 * speedPrice) - - ((distance * 1 * speedPrice) * .4) + - costDuration * 2; - costRayehGaiComfort = (distance * 2 * comfortPrice) - - ((distance * 1 * comfortPrice) * .4) + - costDuration * 2; - costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) - - ((distance * 1 * (speedPrice - 1)) * .4) + - costDuration * 2; - update(); + // ====== زمن الرحلة ====== + durationToAdd = Duration(seconds: durationToRide); + hours = durationToAdd.inHours; + minutes = (durationToAdd.inMinutes % 60).round(); + final DateTime currentTime = DateTime.now(); + newTime = currentTime.add(durationToAdd); + averageDuration = (durationToRide / 60) / distance; + final int totalMinutes = (durationToRide / 60).floor(); + + // ====== أدوات مساعدة ====== + bool _isAirport(String s) { + final t = s.toLowerCase(); + return t.contains('airport') || + s.contains('مطار') || + s.contains('المطار'); + } + + bool _isClub(String s) { + final t = s.toLowerCase(); + return t.contains('club') || + t.contains('nightclub') || + t.contains('night club') || + s.contains('ديسكو') || + s.contains('ملهى ليلي'); + } + + // أسعار الدقيقة من السيرفر + final double naturePerMin = naturePrice; // طبيعي + final double latePerMin = latePrice; // ليل + final double heavyPerMin = heavyPrice; // ذروة + + // سعر الدقيقة حسب الوقت (أساس قبل قواعد المسافة) + double _perMinuteByTime(DateTime now, bool clubCtx) { + final h = now.hour; + if (h >= 21 || h < 1) return latePerMin; // ليل + if (h >= 1 && h < 5) return clubCtx ? (latePerMin * 2) : latePerMin; + if (h >= 14 && h <= 17) return heavyPerMin; // ذروة + return naturePerMin; // طبيعي + } + + // حد أدنى + double _applyMinFare(double fare) => + (fare < minFareSYP) ? minFareSYP : fare; + + // عمولة الراكب (kazan من السيرفر) + double _withCommission(double base) => + (base * (1 + kazan / 100)).ceilToDouble(); + + // ====== سياق ====== + final bool airportCtx = + _isAirport(startNameAddress) || _isAirport(endNameAddress); + final bool clubCtx = _isClub(startNameAddress) || _isClub(endNameAddress); + + // ====== مسافة مفوترة ====== + final double billableDistance = + (distance < minBillableKm) ? minBillableKm : distance; + + // ====== Speed (قصير/طويل) ====== + final bool isLongSpeed = billableDistance > longSpeedThresholdKm; + final double perKmSpeedBaseFromServer = + speedPrice; // مثال: 2900 يأتي من السيرفر + final double perKmSpeed = + isLongSpeed ? longSpeedPerKm : perKmSpeedBaseFromServer; + + // ====== تخفيضات الفئات الأخرى حسب بُعد الرحلة ====== + // نسبة التخفيض عند >40كم محسوبة مقارنة بسعر Speed الأساسي القادم من السيرفر + double reductionPct40 = 0.0; + if (perKmSpeedBaseFromServer > 0) { + reductionPct40 = (1.0 - (longSpeedPerKm / perKmSpeedBaseFromServer)) + .clamp(0.0, maxReductionCap); + } + // نسبة التخفيض عند >100كم + final double reductionPct100 = + (reductionPct40 + extraReduction100).clamp(0.0, maxReductionCap); + + // نحدد أي تخفيض سنستخدمه + double distanceReduction = 0.0; // لا تخفيض افتراضيًا + if (billableDistance > 100.0) { + distanceReduction = reductionPct100; + } else if (billableDistance > 40.0) { + distanceReduction = reductionPct40; + } + + // ====== منطق الدقيقة يعمل لكل الأوقات ويتكيّف مع المسافة ====== + double effectivePerMin = _perMinuteByTime(currentTime, clubCtx); + int billableMinutes = totalMinutes; + + if (billableDistance > longDistThresholdKm) { + // >35كم: 600/د + سقف 60 + عفو 10 + effectivePerMin = longTripPerMin; + final int capped = + (billableMinutes > minuteCapLong) ? minuteCapLong : billableMinutes; + billableMinutes = capped - freeMinutesLong; + if (billableMinutes < 0) billableMinutes = 0; + } else if (billableDistance > mediumDistThresholdKm) { + // >25كم و≤35كم: 600/د + سقف 60 (بدون عفو) + effectivePerMin = longTripPerMin; + billableMinutes = (billableMinutes > minuteCapMedium) + ? minuteCapMedium + : billableMinutes; + } + // ≤25كم: نبقي السعر حسب الوقت بدون سقف/عفو + + // ====== أسعار/كم قبل التخفيض ====== + final double perKmComfortRaw = comfortPrice; + final double perKmDelivery = deliveryPrice; + final double perKmVanRaw = + (familyPrice > 0 ? familyPrice : (speedPrice + 1300)); + // Electric مبني على Comfort + final double perKmElectricRaw = perKmComfortRaw + electricPerKmUplift; + + // ====== تطبيق التخفيضات على الفئات (نفس نسبة Speed للبعيد) ====== + // ملاحظة: Balash يتبع Speed دائمًا (Speed-500) فلا حاجة لتخفيض إضافي له. + double perKmComfort = perKmComfortRaw * (1.0 - distanceReduction); + double perKmElectric = perKmElectricRaw * (1.0 - distanceReduction); + double perKmVan = perKmVanRaw * (1.0 - distanceReduction); + + // نضمن عدم الهبوط تحت الصفر + perKmComfort = perKmComfort.clamp(0, double.infinity); + perKmElectric = perKmElectric.clamp(0, double.infinity); + perKmVan = perKmVan.clamp(0, double.infinity); + + // Awfar/Balash: مرتبط بسرعة Speed بعد التفعيل + final double perKmBalash = (perKmSpeed - 500).clamp(0, double.infinity); + + // ====== دوال الاحتساب ====== + double _oneWayFare({ + required double perKm, + required bool isLady, + double flatAddon = 0, + }) { + double fare = billableDistance * perKm; + fare += + billableMinutes * effectivePerMin; // دقائق بعد السقف/العفو إن وُجد + fare += flatAddon; + if (isLady) fare += ladyFlatAddon; + if (airportCtx) fare += airportAddonSYP; + return _applyMinFare(fare); + } + + double _roundTripFare({required double perKm}) { + // خصم 40% لمسافة إياب واحدة + زمن مضاعف (بنفس قواعد الدقيقة المعدّلة) + double distPart = + (billableDistance * 2 * perKm) - ((billableDistance * perKm) * 0.4); + double timePart = (billableMinutes * 2) * effectivePerMin; + double fare = distPart + timePart; + if (airportCtx) fare += airportAddonSYP; + return _applyMinFare(fare); + } + + // ====== حساب كل الفئات (Base قبل العمولة) ====== + final double costSpeed = _oneWayFare(perKm: perKmSpeed, isLady: false); + final double costBalash = _oneWayFare(perKm: perKmBalash, isLady: false); + final double costComfort = _oneWayFare(perKm: perKmComfort, isLady: false); + final double costElectric = _oneWayFare( + perKm: perKmElectric, isLady: false, flatAddon: electricFlatAddon); + final double costDelivery = + _oneWayFare(perKm: perKmDelivery, isLady: false); + final double costLady = _oneWayFare( + perKm: perKmComfort, + isLady: true); // Lady تعتمد Comfort بعد التخفيض + إضافة ثابتة + final double costVan = _oneWayFare(perKm: perKmVan, isLady: false); + final double costRayehGai = _roundTripFare(perKm: perKmSpeed); + final double costRayehGaiComfort = _roundTripFare(perKm: perKmComfort); + final double costRayehGaiBalash = _roundTripFare(perKm: perKmBalash); + + // ====== أسعار الراكب بعد العمولة (kazan من السيرفر) ====== + totalPassengerSpeed = _withCommission(costSpeed); + totalPassengerBalash = _withCommission(costBalash); + totalPassengerComfort = _withCommission(costComfort); + totalPassengerElectric = _withCommission(costElectric); + totalPassengerLady = _withCommission(costLady); + totalPassengerScooter = _withCommission(costDelivery); + totalPassengerVan = _withCommission(costVan); + totalPassengerRayehGai = _withCommission(costRayehGai); + totalPassengerRayehGaiComfort = _withCommission(costRayehGaiComfort); + totalPassengerRayehGaiBalash = _withCommission(costRayehGaiBalash); + + // افتراضي للعرض + totalPassenger = totalPassengerSpeed; + totalCostPassenger = totalPassenger; + + // ====== دعم رصيد محفظة سلبي ====== + try { + final walletStr = box.read(BoxName.passengerWalletTotal).toString(); + final walletVal = double.tryParse(walletStr) ?? 0.0; + if (walletVal < 0) { + final neg = (-1) * walletVal; + totalPassenger += neg; + totalPassengerComfort += neg; + totalPassengerElectric += neg; + totalPassengerLady += neg; + totalPassengerBalash += neg; + totalPassengerScooter += neg; + totalPassengerRayehGai += neg; + totalPassengerRayehGaiComfort += neg; + totalPassengerRayehGaiBalash += neg; + totalPassengerVan += neg; } + } catch (_) {} - var totalDriver1 = costDistance + costDuration; - totalCostPassenger = totalDriver1 + (totalDriver1 * kazan / 100); - totalPassenger = costSpeed + (costSpeed * kazan / 100); - if (isInUniversity) { - Log.print('isInUniversity: $isInUniversity'); - totalPassengerComfort = - 20 + (costComfort + (costComfort * kazan / 100)).ceilToDouble(); - totalPassengerElectric = - 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; - totalPassengerElectricDiscount = - totalPassengerElectric + totalPassengerElectric * (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); - totalPassengerElectric = totalPassengerElectricDiscount - - (totalPassengerElectricDiscount * 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(); - totalPassengerElectric = - (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; - totalPassengerElectricDiscount = - 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); - totalPassengerElectric = totalPassengerElectricDiscount - - (totalPassengerElectricDiscount * 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; - totalPassengerSpeed = 20; - totalPassengerBalash = 20; - totalPassengerComfort = 30; - totalPassengerElectric = 30; - totalPassengerLady = 30; - totalPassengerScooter = 18; - } else { - totalPassenger = totalCostPassenger; - update(); - } - if (double.parse(box.read(BoxName.passengerWalletTotal)) < 0) { - totalPassenger = totalPassenger + - (-1) * (double.parse(box.read(BoxName.passengerWalletTotal))); - totalPassengerComfort = totalPassengerComfort + - (-1) * (double.parse(box.read(BoxName.passengerWalletTotal))); - totalPassengerElectric = totalPassengerElectric + - (-1) * (double.parse(box.read(BoxName.passengerWalletTotal))); - totalPassengerLady = totalPassengerLady + - (-1) * (double.parse(box.read(BoxName.passengerWalletTotal))); - totalPassengerBalash = totalPassengerBalash + - (-1) * (double.parse(box.read(BoxName.passengerWalletTotal))); - totalPassengerScooter = totalPassengerScooter + - (-1) * (double.parse(box.read(BoxName.passengerWalletTotal))); - totalPassengerRayehGai = totalPassengerScooter + - (-1) * (double.parse(box.read(BoxName.passengerWalletTotal))); - update(); - } - // } - - // buttomSheetMapPage(); - changeBottomSheetShown(); - } else {} + update(); + changeBottomSheetShown(); } addToken() async { @@ -5507,7 +5613,12 @@ class MapPassengerController extends GetxController { double comfortPrice = 8; double speedPrice = 4; double mashwariPrice = 4; + double familyPrice = 4; double deliveryPrice = 1.2; + double minFareSYP = 16000; // حد أدنى للأجرة (سوريا) + double minBillableKm = 1.0; // حد أدنى للمسافة المفوترة + double commissionPct = 15; // عمولة التطبيق % (راكب) + getKazanPercent() async { var res = await CRUD().get( link: AppLink.getKazanPercent, @@ -5523,16 +5634,11 @@ class MapPassengerController extends GetxController { speedPrice = double.parse(json['message'][0]['speedPrice']); deliveryPrice = double.parse(json['message'][0]['deliveryPrice']); mashwariPrice = double.parse(json['message'][0]['freePrice']); + familyPrice = double.parse(json['message'][0]['familyPrice']); fuelPrice = double.parse(json['message'][0]['fuelPrice']); } } - void startFetchingData() { - Timer.periodic(const Duration(milliseconds: 50), (Timer timer) async { - await getKazanPercent(); - }); - } - getPassengerRate() async { var res = await CRUD().get( link: AppLink.getPassengerRate, @@ -5604,44 +5710,157 @@ class MapPassengerController extends GetxController { } } - var k; @override void onInit() async { + super.onInit(); + + // مرحلة 0: الضروري جداً لعرض الخريطة سريعاً mapAPIKEY = await storage.read(key: BoxName.mapAPIKEY); - k = await getAIKey('HERE_API'); - getFavioratePlaces(); - readyWayPoints(); - addCustomPicker(); - addCustomCarIcon(); - addCustomLadyIcon(); - addCustomMotoIcon(); - addCustomStepIcon(); - addCustomStartIcon(); - addCustomEndIcon(); - addToken(); - await getLocation(); - addFingerPrint(); - getPassengerLocationUniversity(); - _initializePolygons(); - // await addToken(); - getKazanPercent(); - getPassengerRate(); - getRideStatusFromStartApp(); - reloadStartApp = false; - startMarkerReloading(); - Get.put(TextToSpeechController()); - Get.put(FirebaseMessagesController()); + await initilizeGetStorage(); // إعداد سريع + await _initMinimalIcons(); // start/end فقط + await addToken(); // لو لازم للمصادقة + await getLocation(); // لتحديد الكاميرا box.write(BoxName.carType, 'yet'); box.write(BoxName.tipPercentage, '0'); - Get.put(AudioRecorderController()); - // await getNearestDriverByPassengerLocation(); - firstTimeRunToGetCoupon(); - initilizeGetStorage(); - cardNumber = await SecureStorage().readData(BoxName.cardNumber); + await detectAndCacheDeviceTier(); - super.onInit(); + // لا تُنشئ Controllers الثقيلة الآن: + Get.lazyPut(() => TextToSpeechController(), + fenix: true); + Get.lazyPut(() => FirebaseMessagesController(), + fenix: true); + Get.lazyPut(() => AudioRecorderController(), + fenix: true); + + // ابدأ الخريطة الآن (الشاشة ظهرت للمستخدم) + // لاحقاً: استخدم SchedulerBinding.instance.addPostFrameCallback إذا احتجت. + + // مرحلة 1: مهام ضرورية للتسعير لكن غير حرجة لظهور UI + unawaited(_stagePricingAndState()); + + // مرحلة 2: تحسينات/كماليات بالخلفية + unawaited(_stageNiceToHave()); + + // ابدأ إعادة تحميل الماركر لكن بثروتل داخلي + startMarkerReloading(); // تأكد أنه مَخنوق التحديث (throttled) } +// === Helpers === + + Future _initMinimalIcons() async { + addCustomStartIcon(); + addCustomEndIcon(); + // أجّل باقي الأيقونات: + // addCustomCarIcon(), addCustomLadyIcon(), addCustomMotoIcon(), addCustomStepIcon() + } + + Future _stagePricingAndState() async { + try { + await getKazanPercent(); // أسعار السيرفر + } catch (_) {} + try { + await getRideStatusFromStartApp(); + } catch (_) {} + // لو عندك ضبط “وضع خفيف” حسب الجهاز: + _applyLowEndModeIfNeeded(); + } + + Future _stageNiceToHave() async { + // نفّذ بالتوازي + await Future.wait([ + Future(() async { + try { + getFavioratePlaces(); + } catch (_) {} + }), + Future(() async { + try { + readyWayPoints(); + } catch (_) {} + }), + Future(() async { + try { + addCustomPicker(); + } catch (_) {} + }), + Future(() async { + try { + addCustomCarIcon(); + } catch (_) {} + }), + Future(() async { + try { + addCustomLadyIcon(); + } catch (_) {} + }), + Future(() async { + try { + addCustomMotoIcon(); + } catch (_) {} + }), + Future(() async { + try { + addCustomStepIcon(); + } catch (_) {} + }), + Future(() async { + try { + getPassengerRate(); + } catch (_) {} + }), + Future(() async { + try { + firstTimeRunToGetCoupon(); + } catch (_) {} + }), + ]); + try { + cardNumber = await SecureStorage().readData(BoxName.cardNumber); + } catch (_) {} + } + + void _applyLowEndModeIfNeeded() { + // مثال بسيط: يمكنك حفظ فلاج بنظامك (من السيرفر/الإعدادات/الكاش) لتفعيل وضع خفيف + // لاحقاً فعّل: map.trafficEnabled=false, buildingsEnabled=false, تبسيط polylines... + // controller.lowEndMode = true; + } + // @override + // void onInit() async { + // mapAPIKEY = await storage.read(key: BoxName.mapAPIKEY); + // // k = await getAIKey('HERE_API'); + // getFavioratePlaces(); + // readyWayPoints(); + // addCustomPicker(); + // addCustomCarIcon(); + // addCustomLadyIcon(); + // addCustomMotoIcon(); + // addCustomStepIcon(); + // addCustomStartIcon(); + // addCustomEndIcon(); + // addToken(); + // await getLocation(); + // addFingerPrint(); + // // getPassengerLocationUniversity(); + // // _initializePolygons(); + // // await addToken(); + // getKazanPercent(); + // getPassengerRate(); + // getRideStatusFromStartApp(); + // reloadStartApp = false; + // startMarkerReloading(); + // Get.put(TextToSpeechController()); + // Get.put(FirebaseMessagesController()); + // box.write(BoxName.carType, 'yet'); + // box.write(BoxName.tipPercentage, '0'); + // Get.put(AudioRecorderController()); + // // await getNearestDriverByPassengerLocation(); + // firstTimeRunToGetCoupon(); + // initilizeGetStorage(); + // cardNumber = await SecureStorage().readData(BoxName.cardNumber); + + // super.onInit(); + // } + uploadPassengerLocation() async { await CRUD().post(link: AppLink.addpassengerLocation, payload: { "passengerId": box.read(BoxName.passengerID), diff --git a/lib/controller/home/profile/invit_controller.dart b/lib/controller/home/profile/invit_controller.dart index fdec1c2..329270f 100644 --- a/lib/controller/home/profile/invit_controller.dart +++ b/lib/controller/home/profile/invit_controller.dart @@ -4,8 +4,6 @@ import 'package:Intaleq/constant/box_name.dart'; import 'package:Intaleq/constant/colors.dart'; import 'package:Intaleq/constant/links.dart'; import 'package:Intaleq/controller/functions/crud.dart'; -import 'package:Intaleq/controller/functions/encrypt_decrypt.dart'; -import 'package:Intaleq/controller/payment/payment_controller.dart'; import 'package:flutter/material.dart'; import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:get/get.dart'; @@ -17,6 +15,7 @@ import '../../../views/widgets/error_snakbar.dart'; import '../../../views/widgets/mydialoug.dart'; import '../../functions/launch.dart'; import '../../notification/notification_captain_controller.dart'; +import '../../payment/payment_controller.dart'; class InviteController extends GetxController { final TextEditingController invitePhoneController = TextEditingController(); @@ -27,21 +26,31 @@ class InviteController extends GetxController { int selectedTab = 0; PassengerStats passengerStats = PassengerStats(); + + List contacts = []; + RxList> contactMaps = >[].obs; + + @override + void onInit() { + super.onInit(); + // It's good practice to fetch initial data in onInit or onReady + // fetchDriverStats(); + // fetchDriverStatsPassengers(); + } + void updateSelectedTab(int index) { selectedTab = index; update(); } - Future shareCouponCode() async { - // TODO: Implement sharing functionality - // You can use share_plus package to share the coupon code - } + // --- Sharing Methods --- + Future shareDriverCode() async { if (driverCouponCode != null) { final String shareText = ''' -Join Intaleq as a driver using my referral code! -Use code: $driverCouponCode -Download the Intaleq Driver app now and earn rewards! +${'Join Intaleq as a driver using my referral code!'.tr} +${'Use code:'.tr} $driverCouponCode +${'Download the Intaleq Driver app now and earn rewards!'.tr} '''; await Share.share(shareText); } @@ -50,19 +59,15 @@ Download the Intaleq Driver app now and earn rewards! Future sharePassengerCode() async { if (couponCode != null) { final String shareText = ''' -Get a discount on your first Intaleq ride! -Use my referral code: $couponCode -Download the Intaleq app now and enjoy your ride! +${'Get a discount on your first Intaleq ride!'.tr} +${'Use my referral code:'.tr} $couponCode +${'Download the Intaleq app now and enjoy your ride!'.tr} '''; await Share.share(shareText); } } - @override - void onInit() { - super.onInit(); - // fetchDriverStats(); - } + // --- Data Fetching --- void fetchDriverStats() async { try { @@ -74,7 +79,9 @@ Download the Intaleq app now and enjoy your ride! driverInvitationData = data['message']; update(); } - } catch (e) {} + } catch (e) { + Log.print("Error fetching driver stats: $e"); + } } void fetchDriverStatsPassengers() async { @@ -88,216 +95,207 @@ Download the Intaleq app now and enjoy your ride! driverInvitationDataToPassengers = data['message']; update(); } - } catch (e) {} - } - - void selectPhone(String phone) { - if (box.read(BoxName.countryCode) == 'Egypt') { - invitePhoneController.text = phone; - update(); - Get.back(); - } - } - - Future saveContactsToServer() async { - try { - // TODO: Implement the actual server upload logic here - // Simulating a server request - await Future.delayed(Duration(seconds: 2)); - Get.snackbar('Success'.tr, - '${selectedContacts.length} contacts saved to server'.tr); } catch (e) { - Get.snackbar('Error'.tr, - 'An error occurred while saving contacts to server: $e'.tr); + Log.print("Error fetching passenger stats: $e"); } } - List contacts = []; - List selectedContacts = []; - RxList> contactMaps = >[].obs; + // --- Contact Handling --- + /// **IMPROVEMENT**: This function now filters out contacts without any phone numbers. + /// This is the fix for the `RangeError` you were seeing, which happened when the UI + /// tried to access the first phone number of a contact that had none. Future pickContacts() async { try { - // Request contacts permission if (await FlutterContacts.requestPermission(readonly: true)) { - // Fetch all contacts with full properties - final List allContacts = await FlutterContacts.getContacts( - withProperties: true, - withThumbnail: false, - withPhoto: true, - ); + final List allContacts = + await FlutterContacts.getContacts(withProperties: true); + final int totalContactsOnDevice = allContacts.length; - // Check if contacts are available - if (allContacts.isNotEmpty) { - // Store the contacts - contacts = allContacts; - Log.print('contacts: $contacts'); + // **FIX**: Filter contacts to only include those with at least one phone number. + contacts = allContacts.where((c) => c.phones.isNotEmpty).toList(); + final int contactsWithPhones = contacts.length; - // Convert contacts to a list of maps - contactMaps.value = await Future.wait(contacts.map((contact) async { - Log.print('Contact name: ${contact.displayName}'); - - // Fetch phone numbers separately - final phones = await contact.phones; - Log.print('Contact phones: $phones'); - - // Fetch email addresses separately - final emails = await contact.emails; - Log.print('Contact emails: $emails'); - - // Handle empty or null values + if (contactsWithPhones > 0) { + Log.print('Found $contactsWithPhones contacts with phone numbers.'); + contactMaps.value = contacts.map((contact) { return { - 'name': contact.displayName ?? '', - 'phones': phones - .where((phone) => phone.normalizedNumber != null) - .map((phone) => phone.normalizedNumber ?? 'No number') - .toList(), - 'emails': emails - .where((email) => email.address != null) - .map((email) => email.address ?? 'No email') - .toList(), + 'name': contact.displayName, + 'phones': contact.phones.map((p) => p.number).toList(), + 'emails': contact.emails.map((e) => e.address).toList(), }; - }).toList()); - + }).toList(); update(); + + // **IMPROVEMENT**: Provide feedback if some contacts were filtered out. + if (contactsWithPhones < totalContactsOnDevice) { + Get.snackbar('Contacts Loaded'.tr, + '${'Showing'.tr} $contactsWithPhones ${'of'.tr} $totalContactsOnDevice ${'contacts. Others were hidden because they don\'t have a phone number.'.tr}', + snackPosition: SnackPosition.BOTTOM); + } } else { - Get.snackbar('No contacts available'.tr, - 'Please add contacts to your phone.'.tr); + Get.snackbar('No contacts found'.tr, + 'No contacts with phone numbers were found on your device.'.tr); } } else { Get.snackbar('Permission denied'.tr, 'Contact permission is required to pick contacts'.tr); } } catch (e) { + Log.print('Error picking contacts: $e'); Get.snackbar( 'Error'.tr, 'An error occurred while picking contacts: $e'.tr); } } - void onSelectPassengerInvitation(int index) async { - MyDialog().getDialog( - int.parse(driverInvitationDataToPassengers[index]['countOfInvitDriver'] - .toString()) < - 2 - ? '${'When'.tr} ${(driverInvitationDataToPassengers[index]['passengerName'].toString())} ${"complete, you can claim your gift".tr} ' - : 'You deserve the gift'.tr, - '${(driverInvitationDataToPassengers[index]['passengerName'].toString())} ${driverInvitationDataToPassengers[index]['countOfInvitDriver'].toString()} / 2 ${'Trip'.tr}', - () async { - if (int.parse(driverInvitationDataToPassengers[index] - ['countOfInvitDriver'] - .toString()) < - 2) { - Get.back(); - } else { - // Claim the gift if 100 trips are completed - if (driverInvitationDataToPassengers[index]['isGiftToken'] - .toString() == - '0') { - Get.back(); - // Add wallet to the inviter - await Get.find().addPassengersWallet('20'); - // add for invitor too - // await Get.find().addDriverWalletToInvitor( - // 'paymentMethod', - // driverInvitationData[index]['driverInviterId'], - // '50'); - // Update invitation as claimed - await CRUD().post( - link: AppLink.updatePassengerGift, - payload: {'id': driverInvitationDataToPassengers[index]['id']}, - ); - // Notify the inviter - NotificationCaptainController().addNotificationCaptain( - driverInvitationDataToPassengers[index]['passengerInviterId'] - .toString(), - "You have got a gift for invitation".tr, - '${"You have 20".tr} ${'LE'}', - false, - ); - } else { - Get.back(); - MyDialog().getDialog( - "You have got a gift".tr, - "Share the app with another new passenger".tr, - () { - Get.back(); - }, - ); - } - } - }, - ); + void selectPhone(String phone) { + invitePhoneController.text = phone; + update(); + Get.back(); } - savePhoneToServer() async { - for (var i = 0; i < contactMaps.length; i++) { - var phones = contactMaps[i]['phones']; - if (phones != null && phones.isNotEmpty && phones[0].isNotEmpty) { - var res = await CRUD().post(link: AppLink.savePhones, payload: { - "name": contactMaps[i]['name'] ?? 'none', - "phones": phones[0] ?? 'none', - "phones2": phones.join(', ') ?? - 'none', // Convert List to a comma-separated string - }); - if (res != 'failure') {} - } else {} + /// **IMPROVEMENT**: A new robust function to format phone numbers specifically for Syria (+963). + /// It handles various user inputs gracefully to produce a standardized international format. + String _formatSyrianPhoneNumber(String phone) { + // 1. Remove all non-digit characters to clean the input. + String digitsOnly = phone.replaceAll(RegExp(r'\D'), ''); + + // 2. If it already starts with the country code, we assume it's correct. + if (digitsOnly.startsWith('963')) { + return '+$digitsOnly'; } - } - String formatPhoneNumber(String input) { - // Remove any non-digit characters - String digitsOnly = input.replaceAll(RegExp(r'\D'), ''); - - // Ensure the number starts with the country code - if (digitsOnly.startsWith('20')) { + // 3. If it starts with '09' (common local format), remove the leading '0'. + if (digitsOnly.startsWith('09')) { digitsOnly = digitsOnly.substring(1); } - return digitsOnly; + // 4. Prepend the Syrian country code. + return '+963$digitsOnly'; } + /// **IMPROVEMENT**: This method now uses the new phone formatting logic and + /// sends a much-improved, user-friendly WhatsApp message. void sendInviteToPassenger() async { if (invitePhoneController.text.isEmpty || - invitePhoneController.text.length < 11) { + invitePhoneController.text.length < 9) { mySnackeBarError('Please enter a correct phone'.tr); - return; } - // try { - String phoneNumber = formatPhoneNumber(invitePhoneController.text); + try { + // Use the new formatting function to ensure the number is correct. + String formattedPhoneNumber = + _formatSyrianPhoneNumber(invitePhoneController.text); - var response = - await CRUD().post(link: AppLink.addInvitationPassenger, payload: { - "driverId": box.read(BoxName.passengerID), - "inviterPassengerPhone": ('+2$phoneNumber') - }); + var response = + await CRUD().post(link: AppLink.addInvitationPassenger, payload: { + "driverId": box.read(BoxName.passengerID), + "inviterPassengerPhone": formattedPhoneNumber, + }); - if (response != 'failure') { - var d = response; - Get.snackbar('Success', 'Invite sent successfully'.tr); + if (response != 'failure') { + var d = response; + Get.snackbar('Success'.tr, 'Invite sent successfully'.tr, + backgroundColor: Colors.green, colorText: Colors.white); - String message = '${'*Intaleq APP 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.mobileapp.store.ride\n\n\n' - '*iOS:* https://apps.apple.com/us/app/sefer/id6458734951'; + String expirationTime = d['message']['expirationTime'].toString(); + String inviteCode = d['message']['inviteCode'].toString(); - launchCommunication('whatsapp', '+2$phoneNumber', message); + // New and improved WhatsApp message for better user engagement. + String message = + "👋 ${'Hello! I\'m inviting you to try Intaleq.'.tr}\n\n" + "🎁 ${'Use my invitation code to get a special gift on your first ride!'.tr}\n\n" + "${'Your personal invitation code is:'.tr}\n" + "*$inviteCode*\n\n" + "⏳ ${'Be sure to use it quickly! This code expires at'.tr} *$expirationTime*.\n\n" + "📲 ${'Download the app now:'.tr}\n" + "• *Android:* https://play.google.com/store/apps/details?id=com.Intaleq.intaleq\n" + "• *iOS:* https://apps.apple.com/st/app/intaleq-rider/id6748075179\n\n" + "${'See you on the road!'.tr} 🚗"; - invitePhoneController.clear(); - } else { - Get.snackbar('Error'.tr, "Invite code already used".tr, - backgroundColor: AppColor.redColor, - duration: const Duration(seconds: 4)); + launchCommunication('whatsapp', formattedPhoneNumber, message); + invitePhoneController.clear(); + update(); + } else { + Get.snackbar( + 'Error'.tr, "This phone number has already been invited.".tr, + backgroundColor: AppColor.redColor, + duration: const Duration(seconds: 4)); + } + } catch (e) { + Log.print("Error sending invite: $e"); + Get.snackbar( + 'Error'.tr, 'An unexpected error occurred. Please try again.'.tr, + backgroundColor: AppColor.redColor); + } + } + + // This function is dependent on the `pickContacts` method filtering out contacts without phones. + savePhoneToServer() async { + for (var contactMap in contactMaps) { + // The `pickContacts` function ensures the 'phones' list is not empty here. + var phones = contactMap['phones'] as List; + var res = await CRUD().post(link: AppLink.savePhones, payload: { + "name": contactMap['name'] ?? 'No Name', + "phones": phones.first, // Safely access the first phone number + "phones2": phones.join(', '), + }); + if (res == 'failure') { + Log.print('Failed to save contact: ${contactMap['name']}'); + } + } + } + + void onSelectPassengerInvitation(int index) async { + try { + final invitation = driverInvitationDataToPassengers[index]; + final tripCount = + int.tryParse(invitation['countOfInvitDriver'].toString()) ?? 0; + final passengerName = invitation['passengerName'].toString(); + final isGiftTaken = invitation['isGiftToken'].toString() == '1'; + + if (tripCount >= 2) { + // Gift can be claimed + if (!isGiftTaken) { + MyDialog().getDialog( + 'You deserve the gift'.tr, + '${'Claim your 20 LE gift for inviting'.tr} $passengerName!', + () async { + Get.back(); // Close dialog first + await Get.find().addPassengersWallet('20'); + await CRUD().post( + link: AppLink.updatePassengerGift, + payload: {'id': invitation['id']}, + ); + NotificationCaptainController().addNotificationCaptain( + invitation['passengerInviterId'].toString(), + "You have got a gift for invitation".tr, + '${"You have earned 20".tr} ${'LE'}', + false, + ); + fetchDriverStatsPassengers(); // Refresh list + }, + ); + } else { + MyDialog().getDialog( + "Gift Already Claimed".tr, + "You have already received your gift for inviting $passengerName." + .tr, + () => Get.back(), + ); + } + } else { + // Gift not yet earned + MyDialog().getDialog( + '${'Keep it up!'.tr}', + '$passengerName ${'has completed'.tr} $tripCount / 2 ${'trips'.tr}. ${"You can claim your gift once they complete 2 trips.".tr}', + () => Get.back(), + ); + } + } catch (e) { + Log.print("Error in onSelectPassengerInvitation: $e"); } - // } catch (e) { - // Get.snackbar('Error', 'An error occurred'.tr); - // } } } diff --git a/lib/controller/local/translations.dart b/lib/controller/local/translations.dart index 31decb2..4925bef 100644 --- a/lib/controller/local/translations.dart +++ b/lib/controller/local/translations.dart @@ -5,164 +5,269 @@ class MyTranslation extends Translations { Map> get keys => { "ar": { "Syria": "سوريا", - "SYP": "ليرة", + "SYP": "ليرة سورية", "Order": "طلب", "OrderVIP": "طلب VIP", + "Hi ,I Arrive your site": "أنا وصلت لموقعك", "Cancel Trip": "إلغاء الرحلة", - "Passenger Cancel Trip": "الراكب ألغى الرحلة", + "Passenger Cancel Trip": "الراكب لغى الرحلة", "VIP Order": "طلب VIP", - "The driver accepted your trip": "السائق قبل رحلتك", + "The driver accepted your trip": "الكابتن وافق على رحلتك", "message From passenger": "رسالة من الراكب", "Cancel": "إلغاء", "Trip Cancelled. The cost of the trip will be added to your wallet.": - "تم إلغاء الرحلة. سيتم إضافة تكلفة الرحلة إلى محفظتك.", + "تم إلغاء الرحلة. ستتم إضافة تكلفة الرحلة إلى محفظتك.", "token change": "تغيير الرمز", - "face detect": "كشف الوجه", - "Face Detection Result": "نتيجة كشف الوجه", - "similar": "مشابه", - "not similar": "غير مشابه", - "Hi ,I will go now": "مرحبًا، سأذهب الآن", + "face detect": "التحقق من الوجه", + "Face Detection Result": "نتيجة التحقق من الوجه", + "similar": "مطابق", + "not similar": "غير مطابق", + "Hi ,I will go now": "مرحباً، أنا ذاهب الآن", "Passenger come to you": "الراكب قادم إليك", "Call Income": "مكالمة واردة", "Call Income from Passenger": "مكالمة واردة من الراكب", - "Criminal Document Required": "مطلوب وثيقة جنائية", - "You should have upload it .": "يجب عليك تحميلها.", + "Criminal Document Required": "مطلوب وثيقة لا حكم عليه", + "You should have upload it .": "يجب عليك رفعها.", "Call End": "انتهاء المكالمة", "The order has been accepted by another driver.": - "تم قبول الطلب من قبل سائق آخر.", - "The order Accepted by another Driver": - "تم قبول الطلب من قبل سائق آخر", + "تم قبول الطلب من قبل كابتن آخر.", + "The order Accepted by another Driver": "الطلب تم قبوله من كابتن آخر", "We regret to inform you that another driver has accepted this order.": - "نأسف لإعلامك بأن سائقًا آخر قد قبل هذا الطلب.", - "Driver Applied the Ride for You": "السائق قدم الطلب لك", + "نأسف لإبلاغك بأن كابتن آخر قد قبل هذا الطلب.", + "Driver Applied the Ride for You": "الكابتن قام بطلب الرحلة لك", "Applied": "تم التقديم", - "Hi ,I Arrive your site": "مرحبًا، لقد وصلت إلى موقعك", - "Please go to Car Driver": "يرجى الذهاب إلى سائق السيارة", - "Ok I will go now.": "حسنًا، سأذهب الآن.", + "My Wallet": "محفظتي", + "Top up Balance": "تعبئة الرصيد", + "Please go to Car Driver": "الرجاء التوجه إلى سيارة الكابتن", + "Ok I will go now.": "حسناً، أنا ذاهب الآن.", "Accepted Ride": "تم قبول الرحلة", - "Driver Accepted the Ride for You": "السائق قبل الرحلة لك", - "Promo": "عرض ترويجي", - "Show latest promo": "عرض أحدث عرض ترويجي", + "Driver Accepted the Ride for You": "الكابتن قبل رحلتك", + "Promo": "عرض", + "Show latest promo": "عرض آخر العروض", "Trip Monitoring": "مراقبة الرحلة", - "Driver Is Going To Passenger": "السائق في طريقه إليك", - "Please stay on the picked point.": - "يرجى البقاء في نقطة الالتقاط المحددة.", - "message From Driver": "رسالة من السائق", + "Driver Is Going To Passenger": "الكابتن بالطريق إليك", + "Please stay on the picked point.": "الرجاء البقاء في نقطة الانطلاق.", + "message From Driver": "رسالة من الكابتن", "Trip is Begin": "بدأت الرحلة", "welcome to intaleq": "أهلاً بك في انطلق", "login or register subtitle": - "أدخل رقم هاتفك للدخول أو إنشاء حساب جديد", - "phone number label": "رقم الهاتف", - "phone number required": "يرجى إدخال رقم الهاتف", + "أدخل رقم موبايلك لتسجيل الدخول أو لإنشاء حساب جديد", + "phone number label": "رقم الموبايل", + "phone number required": "الرجاء إدخال رقم الموبايل", "send otp button": "إرسال رمز التحقق", - "verify your number title": "التحقق من الرقم", - "otp sent subtitle": "تم إرسال رمز تحقق من 5 أرقام إلى\n@phoneNumber", + "verify your number title": "التحقق من رقمك", + "otp sent subtitle": + "تم إرسال رمز تحقق مؤلف من 5 أرقام إلى\n@phoneNumber", "verify and continue button": "تحقق ومتابعة", "enter otp validation": "الرجاء إدخال رمز التحقق المكون من 5 أرقام", "one last step title": "خطوة أخيرة", - "complete profile subtitle": "أكمل بياناتك الشخصية للبدء", + "complete profile subtitle": "أكمل معلوماتك الشخصية للبدء", "first name label": "الاسم الأول", - "first name required": "يرجى إدخال الاسم الأول", + "first name required": "الرجاء إدخال الاسم الأول", "last name label": "الاسم الأخير", "Verify OTP": "التحقق من الرمز", "Verification Code": "رمز التحقق", "We have sent a verification code to your mobile number:": - "لقد أرسلنا رمز التحقق إلى رقم هاتفك المحمول:", + "لقد أرسلنا رمز التحقق إلى رقم موبايلك:", "Verify": "تحقق", "Resend Code": "إعادة إرسال الرمز", - "You can resend in": "يمكنك إعادة الإرسال خلال", + "You can resend in": "يمكنك إعادة الإرسال بعد", "seconds": "ثانية", "Error": "خطأ", "Please enter the complete 6-digit code.": - "الرجاء إدخال الرمز المكون من 6 أرقام بالكامل.", - "last name required": "يرجى إدخال الاسم الأخير", + "الرجاء إدخال الرمز كاملاً المكون من 6 أرقام.", + "last name required": "الرجاء إدخال الاسم الأخير", "email optional label": "البريد الإلكتروني (اختياري)", - "complete registration button": "إكمال التسجيل", + "complete registration button": "إتمام التسجيل", "User with this phone number or email already exists.": - "المستخدم بهذا الرقم الهاتفي أو البريد الإلكتروني موجود مسبقًا.", + "يوجد حساب مسجل بنفس رقم الموبايل أو البريد الإلكتروني.", "otp sent success": "تم إرسال رمز التحقق إلى واتساب.", "failed to send otp": "فشل إرسال الرمز.", - "server error try again": "حدث خطأ بالخادم، يرجى المحاولة لاحقاً.", + "server error try again": + "حدث خطأ في الخادم، الرجاء المحاولة مرة أخرى.", "an error occurred": "حدث خطأ غير متوقع: @error", "otp verification failed": "رمز التحقق غير صحيح.", "registration failed": "فشلت عملية التسجيل.", "welcome user": "أهلاً بك، @firstName!", - "Cancel Trip from driver": "إلغاء الرحلة من السائق", + "Cancel Trip from driver": "إلغاء الرحلة من قبل الكابتن", "We will look for a new driver.\nPlease wait.": - "سنبحث عن سائق جديد.\nمن فضلك انتظر.", - "The driver canceled your ride.": "السائق ألغى رحلتك.", - "Driver Finish Trip": "السائق أنهى الرحلة", - "you will pay to Driver": "ستدفع للسائق", - "Don't forget your personal belongings.": "لا تنسى أغراضك الشخصية.", + "جاري البحث عن كابتن جديد.\nالرجاء الانتظار.", + "The driver canceled your ride.": "الكابتن ألغى رحلتك.", + "Driver Finish Trip": "الكابتن أنهى الرحلة", + "you will pay to Driver": "ستدفع للكابتن", + "Don't forget your personal belongings.": "لا تنسَ أغراضك الشخصية.", "Please make sure you have all your personal belongings and that any remaining fare, if applicable, has been added to your wallet before leaving. Thank you for choosing the Intaleq app": - "من فضلك تأكد من أن لديك جميع أغراضك الشخصية وأن أي أجر متبقي، إذا كان ينطبق، قد تم إضافته إلى محفظتك قبل المغادرة. شكرًا لاختيارك تطبيق Intaleq", + "يرجى التأكد من أخذ جميع أغراضك الشخصية، وأن أي مبلغ متبقٍ قد أُضيف إلى محفظتك قبل المغادرة. شكراً لاختيارك تطبيق انطلق.", "Finish Monitor": "إنهاء المراقبة", - "Trip finished": "الرحلة انتهت", - "Call Income from Driver": "مكالمة واردة من السائق", - "Driver Cancelled Your Trip": "السائق ألغى رحلتك", + "Trip finished": "انتهت الرحلة", + "Call Income from Driver": "مكالمة واردة من الكابتن", + "Driver Cancelled Your Trip": "الكابتن ألغى رحلتك", "you will pay to Driver you will be pay the cost of driver time look to your Intaleq Wallet": - "ستدفع للسائق، ستقوم بدفع تكلفة وقت السائق، انظر إلى محفظتك في Intaleq", - "Order Applied": "تم تطبيق الطلب", + "ستقوم بدفع تكلفة وقت الكابتن، راجع محفظتك في انطلق", + "Order Applied": "تم تقديم الطلب", "Share App": "مشاركة التطبيق", "Wallet": "المحفظة", + "Balance": "الرصيد", + "Don’t forget your personal belongings.": "لا تنسَ أغراضك الشخصية.", "Profile": "الملف الشخصي", - "Contact Support": "اتصل بالدعم", + "Contact Support": "التواصل مع الدعم", "Session expired. Please log in again.": - "انتهت الجلسة. يرجى تسجيل الدخول مرة أخرى.", + "انتهت صلاحية الجلسة. الرجاء تسجيل الدخول مرة أخرى.", "Security Warning": "⚠️ تحذير أمني", "Potential security risks detected. The application may not function correctly.": - "تم اكتشاف مخاطر أمنية محتملة. قد لا يعمل التطبيق بشكل صحيح.", - "please order now": "الرجاء الطلب الآن", - "Where to": "إلى أين", - "Where are you going?": "إلى أين تذهب؟", + "تم كشف مخاطر أمنية محتملة. قد لا يعمل التطبيق بشكل صحيح.", + "please order now": "اطلب الآن", + "Where to": "إلى أين؟", + "Where are you going?": "لوين رايح؟", "Quick Actions": "إجراءات سريعة", - "My Wallet": "محفظتي", + "My Balance": "رصيدي", "Order History": "سجل الطلبات", - "Contact Us": "اتصل بنا", - "Driver": "السائق", + "Contact Us": "تواصل معنا", + "Driver": "كابتن", "Complaint": "شكوى", "Promos": "العروض", "Recent Places": "الأماكن الأخيرة", "From": "من", - "WhatsApp Location Extractor": "مستخرج موقع واتساب", + "WhatsApp Location Extractor": "استخراج الموقع من واتساب", "Location Link": "رابط الموقع", "Paste location link here": "الصق رابط الموقع هنا", - "Go to this location": "انتقل إلى هذا الموقع", + "Go to this location": "اذهب إلى هذا الموقع", "Paste WhatsApp location link": "الصق رابط موقع واتساب", "Select Order Type": "اختر نوع الطلب", "Choose who this order is for": "اختر لمن هذا الطلب", - "I want to order for myself": "أريد الطلب لنفسي", - "I want to order for someone else": "أريد الطلب لشخص آخر", + "I want to order for myself": "أريد أن أطلب لنفسي", + "I want to order for someone else": "أريد أن أطلب لشخص آخر", "Order for someone else": "اطلب لشخص آخر", "Order for myself": "اطلب لنفسي", "Are you want to go this site": "هل تريد الذهاب إلى هذا الموقع؟", "No": "لا", "Intaleq Wallet": "محفظة انطلق", - 'Have a promo code?': "هل لديك رمز ترويجي؟", - "Your Wallet balance is ": "رصيدك في المحفظة هو ", + "Have a promo code?": "هل لديك رمز خصم؟", + "Your Wallet balance is ": "رصيد محفظتك هو ", "Cash": "كاش", - "Pay directly to the captain": "ادفع للكابتن مباشرةً", + "Pay directly to the captain": "ادفع للكابتن مباشرة", "Top up Wallet to continue": "اشحن المحفظة للمتابعة", - "Or pay with Cash instead": "أو ادفع بالكاش بدلاً من ذلك", - "Confirm & Find a Ride": "تأكيد والبحث عن مشوار", + "Or pay with Cash instead": "أو ادفع كاش بدلاً من ذلك", + "Confirm & Find a Ride": "تأكيد وإيجاد رحلة", "Balance:": "الرصيد:", - 'Alerts': "تنبيهات", - "Welcome Back!": "مرحبًا بعودتك!", + "Alerts": "الإشعارات", + "Welcome Back!": "أهلاً بعودتك!", "Current Balance": "الرصيد الحالي", - 'Set Wallet Phone Number': "تعيين رقم هاتف المحفظة", - 'Link a phone number for transfers': "ربط رقم هاتف للتحويلات", - 'Payment History': "سجل المدفوعات", - 'View your past transactions': "عرض معاملاتك السابقة", - 'Top up Wallet': "اشحن المحفظة", - 'Add funds using our secure methods': - "أضف أموالًا باستخدام طرقنا الآمنة", + "Set Wallet Phone Number": "تعيين رقم هاتف للمحفظة", + "Link a phone number for transfers": "اربط رقم هاتف لإجراء التحويلات", + "Payment History": "سجل الدفعات", + "View your past transactions": "عرض معاملاتك السابقة", + "Top up Wallet": "تعبئة المحفظة", + "Add funds using our secure methods": + "أضف رصيداً باستخدام طرقنا الآمنة", + "Speed": "سرعة", + "Comfort": "راحة", + "Electric": "كهربائية", + "Lady": "سيدة", + "Van": "عائلية", + "Rayeh Gai": "رايح جاي", + "Join Intaleq as a driver using my referral code!": + "انضم إلى 'انطلق' ككابتن باستخدام رمز دعوتي!", + "Use code:": "استخدم الرمز:", + "Download the Intaleq Driver app now and earn rewards!": + "حمّل تطبيق 'انطلق' للكباتن الآن واحصل على مكافآت!", + "Get a discount on your first Intaleq ride!": + "احصل على خصم على رحلتك الأولى مع 'انطلق'!", + "Use my referral code:": "استخدم رمز دعوتي:", + "Download the Intaleq app now and enjoy your ride!": + "حمّل تطبيق 'انطلق' الآن واستمتع برحلتك!", + "Contacts Loaded": "تم تحميل جهات الاتصال", + "Showing": "يتم عرض", + "of": "من", + "contacts. Others were hidden because they don't have a phone number.": + "جهة اتصال. تم إخفاء البقية لعدم وجود أرقام هواتف لديهم.", + "No contacts found": "لم يتم العثور على جهات اتصال", + "No contacts with phone numbers were found on your device.": + "لم يتم العثور على جهات اتصال لديها أرقام هواتف في جهازك.", + "Permission denied": "تم رفض الإذن", + "Contact permission is required to pick contacts": + "مطلوب إذن الوصول لجهات الاتصال لاختيار الأسماء.", + "An error occurred while picking contacts:": + "حدث خطأ أثناء اختيار جهات الاتصال:", + "Please enter a correct phone": "الرجاء إدخال رقم هاتف صحيح", + "Success": "نجاح", + "Invite sent successfully": "تم إرسال الدعوة بنجاح", + "Hello! I'm inviting you to try Intaleq.": + "مرحباً! أدعوك لتجربة تطبيق 'انطلق'.", + "Use my invitation code to get a special gift on your first ride!": + "استخدم رمز دعوتي لتحصل على هدية خاصة في رحلتك الأولى!", + "Your personal invitation code is:": "رمز دعوتك الشخصي هو:", + "Be sure to use it quickly! This code expires at": + "لا تتأخر! صلاحية هذا الرمز تنتهي في", + "Download the app now:": "حمّل التطبيق الآن:", + "See you on the road!": "نلتقي على الطريق!", + "This phone number has already been invited.": + "لقد تم إرسال دعوة لهذا الرقم مسبقاً.", + "An unexpected error occurred. Please try again.": + "حدث خطأ غير متوقع. الرجاء المحاولة مرة أخرى.", + "You deserve the gift": "أنت تستحق الهدية", + "Claim your 20 LE gift for inviting": + "اطلب هديتك بقيمة 20 جنيه لدعوة", + "You have got a gift for invitation": "لقد حصلت على هدية لدعوتك", + "You have earned 20": "لقد ربحت 20", + "LE": "ل.س", + "Vibration feedback for all buttons": "تفعيل الاهتزاز لجميع الأزرار", + "Share with friends and earn rewards": + "شارك التطبيق مع أصدقائك واحصل على مكافآت", + "Gift Already Claimed": "تم استلام الهدية مسبقاً", + "You have already received your gift for inviting": + "لقد استلمت هديتك بالفعل مقابل هذه الدعوة", + "Keep it up!": "استمر!", + "has completed": "أكمل", + "trips": "رحلات", + "Personal Information": "المعلومات الشخصية", + "Name": "الاسم", + "Not set": "غير محدد", + "Gender": "الجنس", + "Education": "التحصيل العلمي", + "Work & Contact": "العمل والاتصال", + "Employment Type": "نوع العمل", + "Marital Status": "الحالة الاجتماعية", + "SOS Phone": "رقم الطوارئ", + "Sign Out": "تسجيل الخروج", + "Delete My Account": "حذف حسابي", + "Update Gender": "تحديث الجنس", + "Update": "تحديث", + "Update Education": "تحديث التحصيل العلمي", + "Are you sure? This action cannot be undone.": + "هل أنت متأكد؟ لا يمكن التراجع عن هذا الإجراء.", + "Confirm your Email": "تأكيد بريدك الإلكتروني", + "Type your Email": "اكتب بريدك الإلكتروني", + "Delete Permanently": "حذف نهائي", + "Male": "ذكر", + "Female": "أنثى", + "Other": "آخر", + "High School Diploma": "شهادة ثانوية", + "Associate Degree": "دبلوم", + "Bachelor's Degree": "إجازة جامعية", + "Master's Degree": "ماجستير", + "Doctoral Degree": "دكتوراه", + "Select your preferred language for the app interface.": + "اختر لغتك المفضلة لواجهة التطبيق.", + "Language Options": "خيارات اللغة", + "You can claim your gift once they complete 2 trips.": + "يمكنك طلب هديتك بعد إتمامه لرحلتين.", + "Closest & Cheapest": "الأقرب والأرخص", + "Comfort choice": "خيار الراحة", + "Travel in a modern, silent electric car. A premium, eco-friendly choice for a smooth ride.": + "تنقّل في سيارة كهربائية حديثة وصامتة. خيار مميز وصديق للبيئة لرحلة هادئة.", + "Spacious van service ideal for families and groups. Comfortable, safe, and cost-effective travel together.": + "خدمة فان واسعة ومثالية للعائلات والمجموعات. سفر مريح، آمن، واقتصادي.", + "Quiet & Eco-Friendly": "هادئة وصديقة للبيئة", + "Lady Captain for girls": "كابتن سيدة للبنات", + "Van for familly": "سيارة فان للعائلة", "Are you sure to delete this location?": "هل أنت متأكد من حذف هذا الموقع؟", "Submit a Complaint": "تقديم شكوى", - "Submit Complaint": "تقديم شكوى", + "Submit Complaint": "إرسال الشكوى", "No trip history found": "لا يوجد سجل للرحلات", - "Your past trips will appear here.": "رحلاتك السابقة ستظهر هنا.", - "1. Describe Your Issue": "١. صف مشكلتك", + "Your past trips will appear here.": "ستظهر رحلاتك السابقة هنا.", + "1. Describe Your Issue": "١. اشرح مشكلتك", "Enter your complaint here...": "اكتب شكواك هنا...", "2. Attach Recorded Audio": "٢. إرفاق تسجيل صوتي", "No audio files found.": "لم يتم العثور على ملفات صوتية.", @@ -173,466 +278,448 @@ class MyTranslation extends Translations { "Date": "التاريخ", "Today's Promos": "عروض اليوم", "No promos available right now.": "لا توجد عروض متاحة حالياً.", - "Check back later for new offers!": - "تحقق مرة أخرى لاحقاً للعروض الجديدة!", - "Valid Until:": "صالح لغاية:", - "CODE": "الكود", + "Check back later for new offers!": "تحقق لاحقاً من وجود عروض جديدة!", + "Valid Until:": "صالح حتى:", + "CODE": "الرمز", "Login": "تسجيل الدخول", - "Sign in for a seamless experience": "سجل دخولك لتجربة سلسة", - "Sign In with Google": "الدخول باستخدام جوجل", - "Sign in with Apple": "الدخول باستخدام أبل", + "Sign in for a seamless experience": "سجل دخولك لتجربة سلسلة", + "Sign In with Google": "الدخول عبر جوجل", + "Sign in with Apple": "الدخول عبر آبل", "User not found": "المستخدم غير موجود", "Need assistance? Contact us": "هل تحتاج مساعدة؟ تواصل معنا", "Email": "البريد الإلكتروني", - "Your email address": "عنوان بريدك الإلكتروني", + "Your email address": "بريدك الإلكتروني", "Enter a valid email": "أدخل بريداً إلكترونياً صالحاً", "Password": "كلمة المرور", - "Your password": "كلمة المرور الخاصة بك", + "Your password": "كلمة مرورك", "Enter your password": "أدخل كلمة المرور", "Submit": "إرسال", - "Terms of Use & Privacy Notice": "شروط الاستخدام وإشعار الخصوصية", + "Terms of Use & Privacy Notice": "شروط الاستخدام وبيان الخصوصية", "By selecting \"I Agree\" below, I confirm that I have read and agree to the ": "باختيار \"أوافق\" أدناه، أؤكد أنني قرأت ووافقت على ", "Terms of Use": "شروط الاستخدام", " and acknowledge the ": " وأقر بـ ", - "Privacy Notice": "إشعار الخصوصية", - ". I am at least 18 years old.": ". عمري لا يقل عن 18 عاماً.", - "I Agree": "أوافق", + "Privacy Notice": "بيان الخصوصية", + ". I am at least 18 years old.": ". عمري 18 عاماً على الأقل.", + "I Agree": "أوافق على الشروط والأحكام", "Continue": "متابعة", "Enable Location": "تفعيل الموقع", "To give you the best experience, we need to know where you are. Your location is used to find nearby captains and for pickups.": - "لنمنحك أفضل تجربة، نحتاج لمعرفة موقعك. يتم استخدام موقعك للعثور على الكباتن القريبين ولعمليات الالتقاء.", + "لنمنحك أفضل تجربة، نحتاج لمعرفة موقعك. يتم استخدام موقعك للعثور على الكباتن القريبين ولتحديد نقاط الانطلاق.", "Allow Location Access": "السماح بالوصول للموقع", "Welcome to Intaleq!": "أهلاً بك في انطلق!", "Before we start, please review our terms.": "قبل أن نبدأ، يرجى مراجعة شروطنا.", "Your journey starts here": "رحلتك تبدأ هنا", "Cancel Search": "إلغاء البحث", - "Set pickup location": "حدد موقع الانطلاق", - "Move the map to adjust the pin": "حرّك الخريطة لتعديل موضع الدبوس", + "Set pickup location": "تحديد موقع الانطلاق", + "Move the map to adjust the pin": "حرّك الخريطة لتحديد الموقع", "Searching for the nearest captain...": "جاري البحث عن أقرب كابتن...", "No one accepted? Try increasing the fare.": - "لم يقبل أحد؟ حاول زيادة أجرة المشوار.", - "Increase Your Trip Fee (Optional)": "زيادة أجرة المشوار (اختياري)", + "لم يقبل أحد؟ حاول زيادة الأجرة.", + "Increase Your Trip Fee (Optional)": "زيادة أجرة رحلتك (اختياري)", "We haven't found any drivers yet. Consider increasing your trip fee to make your offer more attractive to drivers.": - "لم نتمكن من العثور على أي كابتن حتى الآن. ننصحك بزيادة أجرة المشوار لجعل عرضك أكثر جاذبية للكباتن.", + "لم نعثر على أي كابتن حتى الآن. يمكنك زيادة أجرة الرحلة لجعل عرضك أكثر جاذبية.", "No, thanks": "لا، شكراً", "Increase Fee": "زيادة الأجرة", "Copy": "نسخ", - "Promo Copied!": "تم نسخ الكود!", - "Code": "الكود", + "Promo Copied!": "تم نسخ العرض!", + "Code": "الرمز", "copied to clipboard": "تم نسخه إلى الحافظة", "Price": "السعر", "Intaleq's Response": "رد فريق انطلق", "Awaiting response...": "بانتظار الرد...", "Audio file not attached": "الملف الصوتي غير مرفق", "The audio file is not uploaded yet.\\nDo you want to submit without it?": - "الملف الصوتي لم يتم رفعه بعد.\\nهل تريد الإرسال بدونه؟", + "لم يتم رفع الملف الصوتي بعد.\\nهل تريد الإرسال بدونه؟", "deleted": "تم الحذف", "To Work": "إلى العمل", - "Work Saved": "تم حفظ مكان العمل", - "To Home": "إلى المنزل", - "Home Saved": "تم حفظ مكان المنزل", + "Work Saved": "تم حفظ موقع العمل", + "To Home": "إلى البيت", + "Home Saved": "تم حفظ موقع البيت", "Destination selected": "تم اختيار الوجهة", - "Now select start pick": "الآن اختر نقطة البداية", + "Now select start pick": "الآن حدد نقطة الانطلاق", "OK": "موافق", - "Confirm Pick-up Location": "تأكيد موقع الالتقاط", + "Confirm Pick-up Location": "تأكيد موقع الانطلاق", "Set Location on Map": "حدد الموقع على الخريطة", "Nearest Car: ~": "أقرب سيارة: ~", "Nearest Car": "أقرب سيارة", "No cars nearby": "لا توجد سيارات قريبة", "Favorite Places": "الأماكن المفضلة", "No favorite places yet!": "لا توجد أماكن مفضلة بعد!", - "from your favorites": "من مفضلاتك", + "from your favorites": "من مفضلتك", "Back": "رجوع", - 'Enter your code below to apply the discount.': - 'أدخل رمزك أدناه لتطبيق الخصم', + "Enter your code below to apply the discount.": + "أدخل الرمز أدناه لتطبيق الخصم", "By selecting \"I Agree\" below, I confirm that I have read and agree to the": - "بالنقر على \"أوافق\" أدناه، أؤكد أنني قد قرأت وأوافق على", - "and acknowledge the": "وأعترف بـ", - "Enable Location Access": "تمكين الوصول إلى الموقع", + "باختياري \"أوافق\" أدناه، أؤكد أنني قرأت ووافقت على", + "and acknowledge the": "وأقر بـ", + "Enable Location Access": "تفعيل الوصول إلى الموقع", "We need your location to find nearby drivers for pickups and drop-offs.": - "نحتاج إلى موقعك للعثور على سائقيين قريبين للاستلام والتوصيل.", + "نحتاج موقعك للعثور على كباتن قريبين لنقاط الانطلاق والوصول.", "You should restart app to change language": "يجب إعادة تشغيل التطبيق لتغيير اللغة", "Home Page": "الصفحة الرئيسية", "To change Language the App": "لتغيير لغة التطبيق", "Learn more about our app and mission": - "تعرف أكثر على تطبيقنا ومهمتنا", + "تعرف أكثر على تطبيقنا ورؤيتنا", "Promos For Today": "عروض اليوم", "Choose your ride": "اختر رحلتك", "Your Journey Begins Here": "رحلتك تبدأ من هنا", "Bonus gift": "هدية إضافية", "Pay": "ادفع", "Get": "احصل على", - "Send to Driver Again": "إرسال إلى السائق مرة أخرى", - "Driver Name:": "اسم السائق:", - "No trip data available": "لا توجد بيانات رحلة متاحة", - "Car Plate:": "لوحة السيارة:", - "remaining": "متبقي", + "Send to Driver Again": "أرسل للكابتن مرة أخرى", + "Driver Name:": "اسم الكابتن:", + "No trip data available": "لا تتوفر بيانات للرحلة", + "Car Plate:": "رقم لوحة السيارة:", + "remaining": "متبقٍ", "Order Cancelled": "تم إلغاء الطلب", - "You canceled VIP trip": "لقد ألغيت رحلة VIP", + "You canceled VIP trip": "لقد ألغيت رحلة الـ VIP", "Passenger cancelled order": "الراكب ألغى الطلب", "Your trip is scheduled": "رحلتك مجدولة", - "Don't forget your ride!": "لا تنسى رحلتك!", + "Don't forget your ride!": "لا تنسَ رحلتك!", "Trip updated successfully": "تم تحديث الرحلة بنجاح", - "Car Make:": "ماركة السيارة:", + "Car Make:": "نوع السيارة:", "Car Model:": "موديل السيارة:", "Car Color:": "لون السيارة:", - "Driver Phone:": "هاتف السائق:", + "Driver Phone:": "رقم الكابتن:", "Pre-booking": "حجز مسبق", - "Waiting VIP": "انتظار VIP", - "Driver List": "قائمة السائقين", + "Waiting VIP": "بانتظار VIP", + "Driver List": "قائمة الكباتن", "Confirm Trip": "تأكيد الرحلة", "Select date and time of trip": "اختر تاريخ ووقت الرحلة", "Date and Time Picker": "اختيار التاريخ والوقت", "Trip Status:": "حالة الرحلة:", "pending": "قيد الانتظار", - "accepted": "تم القبول", - "rejected": "تم الرفض", + "accepted": "مقبولة", + "rejected": "مرفوضة", "Apply": "تطبيق", - "Enter your promo code": "أدخل رمز الترويج الخاص بك", - "Apply Promo Code": "تطبيق رمز الترويج", - "Scheduled Time:": "الوقت المحدد:", - "No drivers available": "لا يوجد سائقون متاحون", + "Enter your promo code": "أدخل رمز العرض", + "Apply Promo Code": "تطبيق رمز العرض", + "Scheduled Time:": "الوقت المجدول:", + "No drivers available": "لا يوجد كباتن متاحون", "No drivers available at the moment. Please try again later.": - "لا يوجد سائقون متاحون حاليًا. يرجى المحاولة مرة أخرى لاحقًا.", - "you have a negative balance of": "لديك رصيد سلبي بقيمة", + "لا يوجد كباتن متاحون حالياً. الرجاء المحاولة مرة أخرى.", + "you have a negative balance of": "لديك رصيد سالب بقيمة", "Please try again in a few moments": - "يرجى المحاولة مرة أخرى بعد قليل", - "Unknown Driver": "سائق غير معروف", + "الرجاء المحاولة بعد لحظات قليلة", + "Unknown Driver": "كابتن غير معروف", "in your": "في محفظتك", - "The driver accepted your order for": "قبل السائق طلبك مقابل", + "The driver accepted your order for": "الكابتن قبل طلبك مقابل", "wallet due to a previous trip.": "بسبب رحلة سابقة.", "rides": "رحلات", - "Add Work": "إضافة عمل", + "Add Work": "إضافة العمل", "The reason is": "السبب هو", "User does not have a wallet #1652": "المستخدم ليس لديه محفظة #1652", "Price of trip": "سعر الرحلة", "From:": "من:", "For Intaleq and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance": - "لرحلات Intaleq والتوصيل، يتم حساب السعر ديناميكيًا. لرحلات الراحة، يعتمد السعر على الوقت والمسافة.", - "Phone Wallet Saved Successfully": "تم حفظ محفظة الهاتف بنجاح", - "Add wallet phone you use": "أضف هاتف المحفظة الذي تستخدمه", - "Update Available": "تحديث متاح", + "لرحلات انطلق والتوصيل، يتم حساب السعر بشكل متغير. أما لرحلات الراحة، فيعتمد السعر على الوقت والمسافة.", + "Phone Wallet Saved Successfully": "تم حفظ رقم هاتف المحفظة بنجاح", + "Add wallet phone you use": "أضف رقم هاتف المحفظة الذي تستخدمه", + "Update Available": "يتوفر تحديث", "Phone number must be exactly 11 digits long": - "يجب أن يكون رقم الهاتف 11 رقمًا بالضبط", + "يجب أن يتكون رقم الهاتف من 11 رقماً بالضبط", "Insert Wallet phone number": "أدخل رقم هاتف المحفظة", "Phone number isn't an Egyptian phone number": - "رقم الهاتف ليس رقمًا مصريًا", + "رقم الهاتف ليس رقماً مصرياً", "A new version of the app is available. Please update to the latest version.": - "يتوفر إصدار جديد من التطبيق. يرجى التحديث إلى أحدث إصدار.", + "يتوفر إصدار جديد من التطبيق. الرجاء التحديث إلى آخر إصدار.", "We use location to get accurate and nearest passengers for you": - "نستخدم الموقع للحصول على ركاب دقيقين وأقرب لك", + "نستخدم الموقع لنجد لك الركاب الأقرب وبدقة", "This ride is already applied by another driver.": - "هذه الرحلة قد تم التقديم عليها من قبل سائق آخر.", + "هذه الرحلة تم قبولها من قبل كابتن آخر.", "We use your precise location to find the nearest available driver and provide accurate pickup and dropoff information. You can manage this in Settings.": - "نستخدم موقعك الدقيق للعثور على أقرب سائق متاح وتقديم معلومات دقيقة عن الاستلام والتوصيل. يمكنك إدارة هذا في الإعدادات.", + "نستخدم موقعك الدقيق للعثور على أقرب كابتن متاح وتوفير معلومات دقيقة عن نقاط الانطلاق والوصول. يمكنك إدارة ذلك في الإعدادات.", "Where are you, sir?": "أين أنت يا سيدي؟", "I've been trying to reach you but your phone is off.": - "كنت أحاول الوصول إليك ولكن هاتفك مغلق.", + "كنت أحاول الاتصال بك لكن هاتفك مغلق.", "Please don't be late": "من فضلك لا تتأخر", "Please don't be late, I'm waiting for you at the specified location.": - "من فضلك لا تتأخر، أنا في انتظارك في الموقع المحدد.", + "من فضلك لا تتأخر، أنا بانتظارك في الموقع المحدد.", "My location is correct. You can search for me using the navigation app": - "موقعي صحيح. يمكنك البحث عني باستخدام تطبيق الملاحة", + "موقعي صحيح. يمكنك إيجادي باستخدام تطبيق الخرائط", "Hello, I'm at the agreed-upon location": - "مرحبًا، أنا في الموقع المتفق عليه", - "How much longer will you be?": "كم من الوقت ستبقى؟", - "Phone number is verified before": "تم التحقق من رقم الهاتف من قبل", + "مرحباً، أنا في الموقع المتفق عليه", + "How much longer will you be?": "كم من الوقت تحتاج بعد؟", + "Phone number is verified before": "تم التحقق من رقم الهاتف مسبقاً", "Change Ride": "تغيير الرحلة", "You can change the destination by long-pressing any point on the map": - "يمكنك تغيير الوجهة بالضغط مطولًا على أي نقطة على الخريطة", + "يمكنك تغيير الوجهة بالضغط المطول على أي نقطة على الخريطة", "Pick from map destination": "اختر الوجهة من الخريطة", "Pick or Tap to confirm": "اختر أو اضغط للتأكيد", "Accepted your order": "تم قبول طلبك", "Order Accepted": "تم قبول الطلب", - "with type": "مع النوع", - "accepted your order at price": "قبل طلبك بالسعر", + "with type": "من نوع", + "accepted your order at price": "وافق على طلبك بسعر", "you canceled order": "لقد ألغيت الطلب", "If you want order to another person": "إذا كنت تريد الطلب لشخص آخر", - "upgrade price": "ترقية السعر", - "Please enter a correct phone": "الرجاء إدخال هاتف صحيح", + "upgrade price": "رفع السعر", "airport": "مطار", "Best choice for a comfortable car with a flexible route and stop points. This airport offers visa entry at this price.": - "أفضل خيار لسيارة مريحة مع مسار مرن ونقاط توقف. هذا المطار يوفر دخول التأشيرة بهذا السعر.", + "الخيار الأفضل لسيارة مريحة مع مسار مرن ونقاط توقف. هذا المطار يوفر تأشيرة دخول بهذا السعر.", "You can upgrade price to may driver accept your order": - "يمكنك ترقية السعر حتى يقبل السائق طلبك", + "يمكنك رفع السعر ليقبل الكابتن طلبك", "Change Route": "تغيير المسار", "No Captain Accepted Your Order": "لم يقبل أي كابتن طلبك", "We are looking for a captain but the price may increase to let a captain accept": - "نحن نبحث عن كابتن ولكن قد يزيد السعر ليتم قبول الطلب", + "نبحث عن كابتن ولكن قد يرتفع السعر ليوافق أحدهم", "No, I want to cancel this trip": "لا، أريد إلغاء هذه الرحلة", "Attention": "انتباه", "Trip Cancelled. The cost of the trip will be deducted from your wallet.": - "تم إلغاء الرحلة. سيتم خصم تكلفة الرحلة من محفظتك.", + "تم إلغاء الرحلة. سيتم خصم تكلفتها من محفظتك.", "You will be charged for the cost of the driver coming to your location.": - "سيتم تحميلك تكلفة قدوم السائق إلى موقعك.", + "سيتم تحميلك تكلفة قدوم الكابتن إلى موقعك.", "reject your order.": "رفض طلبك.", "Order Under Review": "الطلب قيد المراجعة", "is reviewing your order. They may need more information or a higher price.": - "يقوم بمراجعة طلبك. قد يحتاج إلى مزيد من المعلومات أو سعر أعلى.", - "Increase Your Trip Fee (Optional)": "زيادة رسوم رحلتك (اختياري)", + "يقوم بمراجعة طلبك. قد يحتاج لمعلومات إضافية أو سعر أعلى.", "Vibration": "اهتزاز", "Resend code": "إعادة إرسال الرمز", "change device": "تغيير الجهاز", - "Device Change Detected": "تم اكتشاف تغيير الجهاز", + "Device Change Detected": "تم اكتشاف تغيير في الجهاز", "You can only use one device at a time. This device will now be set as your active device.": - "يمكنك استخدام جهاز واحد فقط في كل مرة. سيتم تعيين هذا الجهاز الآن كجهازك النشط.", - "Click here point": "انقر هنا", + "يمكنك استخدام جهاز واحد فقط في كل مرة. سيتم الآن تعيين هذا الجهاز كجهازك النشط.", + "Click here point": "اضغط هنا", "Are you want to change": "هل تريد التغيير؟", "by": "بواسطة", "Enter your complaint here": "أدخل شكواك هنا", "Please enter your complaint.": "الرجاء إدخال شكواك.", "Complaint data saved successfully": "تم حفظ بيانات الشكوى بنجاح", "Trip Monitor": "مراقبة الرحلة", - "Insert SOS Phone": "إدخال هاتف الطوارئ", - "Add SOS Phone": "إضافة هاتف الطوارئ", + "Insert SOS Phone": "إدخال رقم الطوارئ", + "Add SOS Phone": "إضافة رقم الطوارئ", "Dear ,\n\n 🚀 I have just started an exciting trip and I would like to share the details of my journey and my current location with you in real-time! Please download the Intaleq app. It will allow you to view my trip details and my latest location.\n\n 👉 Download link: \n Android [https://play.google.com/store/apps/details?id=com.mobileapp.store.ride]\n iOS [https://getapp.cc/app/6458734951]\n\n I look forward to keeping you close during my adventure!\n\n Intaleq ,": - "عزيزي،\n\n🚀 لقد بدأت للتو رحلة مثيرة وأود مشاركة تفاصيل رحلتي وموقعي الحالي معك في الوقت الفعلي! يرجى تنزيل تطبيق Intaleq. سيسمح لك بمشاهدة تفاصيل رحلتي وموقعي الأخير.\n\n👉 رابط التحميل:\nAndroid [https://play.google.com/store/apps/details?id=com.mobileapp.store.ride]\niOS [https://getapp.cc/app/6458734951]\n\nأتطلع إلى إبقائك قريبًا خلال مغامرتي!\n\nIntaleq،", - "Send Intaleq app to him": "إرسال تطبيق Intaleq إليه", + "عزيزي،\n\n🚀 لقد بدأت رحلة شيقة وأود أن أشاركك تفاصيلها وموقعي الحالي بشكل مباشر! حمّل تطبيق انطلق لتتمكن من متابعة تفاصيل رحلتي وآخر موقع لي.\n\n👈 رابط التحميل:\nأندرويد [https://play.google.com/store/apps/details?id=com.mobileapp.store.ride]\nآيفون [https://getapp.cc/app/6458734951]\n\nيسعدني أن تبقى على اطلاع بمغامرتي!\n\nانطلق،", + "Send Intaleq app to him": "أرسل له تطبيق انطلق", "No passenger found for the given phone number": - "لم يتم العثور على راكب لرقم الهاتف المحدد", + "لم يتم العثور على راكب بهذا الرقم", "No user found for the given phone number": - "لم يتم العثور على مستخدم لرقم الهاتف المحدد", + "لم يتم العثور على مستخدم بهذا الرقم", "This price is": "هذا السعر هو", - "Work": "عمل", - "Add Home": "إضافة منزل", + "Work": "العمل", + "Add Home": "إضافة المنزل", "Notifications": "الإشعارات", - "💳 Pay with Credit Card": "💳 الدفع ببطاقة الائتمان", - "⚠️ You need to choose an amount!": "⚠️ تحتاج إلى اختيار مبلغ!", + "💳 Pay with Credit Card": "💳 الدفع بالبطاقة الائتمانية", + "⚠️ You need to choose an amount!": "⚠️ يجب اختيار مبلغ!", "💰 Pay with Wallet": "💰 الدفع بالمحفظة", "You must restart the app to change the language.": "يجب إعادة تشغيل التطبيق لتغيير اللغة.", "joined": "انضم", - "Driver joined the channel": "انضم السائق إلى القناة", - "Driver left the channel": "غادر السائق القناة", + "Driver joined the channel": "الكابتن انضم إلى القناة", + "Driver left the channel": "الكابتن غادر القناة", "Call Page": "صفحة الاتصال", "Call Left": "مكالمات متبقية", - "\$ Next as Cash \$!": "!التالي نقدًا\$", + " Next as Cash !": " التالي كاش!", "To use Wallet charge it": "لاستخدام المحفظة، قم بشحنها", "We are searching for the nearest driver to you": - "نحن نبحث عن أقرب سائق لك", - "Best choice for cities": "أفضل خيار للمدن", + "نبحث لك عن أقرب كابتن", + "Best choice for cities": "الخيار الأفضل للمدن", "Rayeh Gai: Round trip service for convenient travel between cities, easy and reliable.": - "رايح جاي: خدمة الذهاب والعودة لرحلة مريحة بين المدن، سهلة وموثوقة.", - "Rayeh Gai": "رايح جاي", + "رايح جاي: خدمة ذهاب وإياب مريحة بين المدن، سهلة وموثوقة.", "This trip is for women only": "هذه الرحلة للنساء فقط", "Total budgets on month": "إجمالي الميزانية الشهرية", - "You have call from driver": "لديك مكالمة من السائق", - "Comfort": " مريحة", - "Intaleq": "Intaleq", + "You have call from driver": "لديك مكالمة من الكابتن", + "Intaleq": "انطلق", "passenger agreement": "اتفاقية الراكب", "To become a passenger, you must review and agree to the ": - "لتصبح راكبًا، يجب عليك مراجعة والموافقة على", + "لتصبح راكباً، يجب عليك مراجعة والموافقة على", "agreement subtitle": - "للمتابعة، يجب عليك مراجعة شروط الاستخدام وسياسة الخصوصية والموافقة عليها.", + "للمتابعة، يجب مراجعة شروط الاستخدام وسياسة الخصوصية والموافقة عليها.", "terms of use": "شروط الاستخدام", " and acknowledge our Privacy Policy.": "والإقرار بسياسة الخصوصية الخاصة بنا.", - "and acknowledge our": " والإقرار بـ ", + "and acknowledge our": "والإقرار بـ", "privacy policy": "سياسة الخصوصية.", "i agree": "أوافق على الشروط والأحكام", - "continue": "متابعة", "Driver already has 2 trips within the specified period.": - "لدى السائق بالفعل رحلتين خلال الفترة المحددة.", + "لدى الكابتن رحلتان بالفعل خلال الفترة المحددة.", "The invitation was sent successfully": "تم إرسال الدعوة بنجاح", - "Lady": "سيدة", "You should select your country": "يجب عليك اختيار بلدك", "Scooter": "سكوتر", "A trip with a prior reservation, allowing you to choose the best captains and cars.": - "رحلة مع حجز مسبق، تتيح لك اختيار أفضل الكابتنات والسيارات.", + "رحلة بحجز مسبق، تتيح لك اختيار أفضل الكباتن والسيارات.", "Mishwar Vip": "مشوار VIP", "The driver waiting you in picked location .": - "السائق في انتظارك في الموقع المحدد.", - "About Us": "معلومات عنا", + "الكابتن بانتظارك في موقع الانطلاق.", + "About Us": "من نحن", "You can change the vibration feedback for all buttons": - "يمكنك تغيير ردود الاهتزاز لجميع الأزرار", - "Most Secure Methods": "أكثر الطرق أمانًا", - "In-App VOIP Calls": "مكالمات VOIP داخل التطبيق", + "يمكنك تغيير استجابة الاهتزاز لجميع الأزرار", + "Most Secure Methods": "أكثر الطرق أماناً", + "In-App VOIP Calls": "مكالمات صوتية داخل التطبيق", "Recorded Trips for Safety": "رحلات مسجلة للأمان", "\nWe also prioritize affordability, offering competitive pricing to make your rides accessible.": - "\nنحن نولي أيضًا القدرة على تحمل التكاليف أولوية، ونقدم أسعارًا تنافسية لجعل رحلاتك في متناول الجميع.", + "\nنهتم أيضاً بأن تكون الأسعار مناسبة للجميع، حيث نقدم أسعاراً تنافسية لجعل رحلاتك في متناول اليد.", "Intaleq is a ride-sharing app designed with your safety and affordability in mind. We connect you with reliable drivers in your area, ensuring a convenient and stress-free travel experience.\n\nHere are some of the key features that set us apart:": - "Intaleq هو تطبيق لمشاركة الرحلات مصمم مع مراعاة سلامتك وقدرتك على تحمل التكاليف. نحن نوصلك بسائقين موثوقين في منطقتك، مما يضمن تجربة سفر مريحة وخالية من التوتر.\n\nإليك بعض الميزات الرئيسية التي تميزنا:", - "Sign In by Apple": "تسجيل الدخول باستخدام Apple", - "Sign In by Google": "تسجيل الدخول باستخدام Google", - "How do I request a ride?": "كيف يمكنني طلب رحلة؟", + "انطلق هو تطبيق لمشاركة الرحلات مصمم مع الأخذ بعين الاعتبار سلامتك وميزانيتك. نصلك بكباتن موثوقين في منطقتك، لنضمن لك تجربة تنقل مريحة وخالية من التوتر.\n\nإليك بعض الميزات الرئيسية التي تميزنا:", + "Sign In by Apple": "الدخول عبر Apple", + "Sign In by Google": "الدخول عبر Google", + "How do I request a ride?": "كيف أطلب رحلة؟", "Step-by-step instructions on how to request a ride through the Intaleq app.": - "تعليمات خطوة بخطوة حول كيفية طلب رحلة من خلال تطبيق Intaleq.", - "What types of vehicles are available?": "ما أنواع المركبات المتاحة؟", + "تعليمات مفصلة خطوة بخطوة حول كيفية طلب رحلة عبر تطبيق انطلق.", + "What types of vehicles are available?": + "ما هي أنواع السيارات المتاحة؟", "Intaleq offers a variety of vehicle options to suit your needs, including economy, comfort, and luxury. Choose the option that best fits your budget and passenger count.": - "يقدم Intaleq مجموعة متنوعة من خيارات المركبات لتلبية احتياجاتك، بما في ذلك الاقتصادية والراحة والفاخرة. اختر الخيار الذي يناسب ميزانيتك وعدد الركاب.", - "How can I pay for my ride?": "كيف يمكنني الدفع مقابل رحلتي؟", + "يوفر انطلق مجموعة متنوعة من خيارات السيارات لتناسب احتياجاتك، بما في ذلك الاقتصادية، والمريحة، والفاخرة. اختر الخيار الذي يناسب ميزانيتك وعدد الركاب.", + "How can I pay for my ride?": "كيف يمكنني الدفع لرحلتي؟", "Intaleq offers multiple payment methods for your convenience. Choose between cash payment or credit/debit card payment during ride confirmation.": - "يقدم Intaleq طرق دفع متعددة لراحتك. اختر بين الدفع نقدًا أو ببطاقة الائتمان/الخصم أثناء تأكيد الرحلة.", + "يوفر انطلق طرق دفع متعددة لراحتك. اختر بين الدفع نقداً أو ببطاقة الائتمان/الخصم عند تأكيد الرحلة.", "Can I cancel my ride?": "هل يمكنني إلغاء رحلتي؟", "Yes, you can cancel your ride under certain conditions (e.g., before driver is assigned). See the Intaleq cancellation policy for details.": - "نعم، يمكنك إلغاء رحلتك تحت ظروف معينة (مثلًا، قبل تعيين السائق). راجع سياسة إلغاء Intaleq للحصول على التفاصيل.", - "Driver Registration & Requirements": "تسجيل السائق والمتطلبات", - "How can I register as a driver?": "كيف يمكنني التسجيل كسائق؟", + "نعم، يمكنك إلغاء رحلتك بشروط معينة (مثلاً، قبل تعيين الكابتن). راجع سياسة الإلغاء في انطلق لمعرفة التفاصيل.", + "Driver Registration & Requirements": "تسجيل الكباتن والمتطلبات", + "How can I register as a driver?": "كيف يمكنني التسجيل ككابتن؟", "What are the requirements to become a driver?": - "ما هي متطلبات أن تصبح سائقًا؟", + "ما هي متطلبات الانضمام ككابتن؟", "Visit our website or contact Intaleq support for information on driver registration and requirements.": - "قم بزيارة موقعنا على الإنترنت أو اتصل بدعم Intaleq للحصول على معلومات حول تسجيل السائق والمتطلبات.", + "لمعلومات حول التسجيل والمتطلبات، تفضل بزيارة موقعنا الإلكتروني أو تواصل مع دعم انطلق.", "Intaleq provides in-app chat functionality to allow you to communicate with your driver or passenger during your ride.": - "يوفر Intaleq وظيفة الدردشة داخل التطبيق للسماح لك بالتواصل مع سائقك أو راكبك أثناء رحلتك.", + "يوفر انطلق ميزة الدردشة داخل التطبيق للتواصل مع الكابتن أو الراكب أثناء الرحلة.", "Intaleq prioritizes your safety. We offer features like driver verification, in-app trip tracking, and emergency contact options.": - "Intaleq يعطي الأولوية لسلامتك. نحن نقدم ميزات مثل التحقق من السائق، وتتبع الرحلة داخل التطبيق، وخيارات الاتصال في حالات الطوارئ.", - "Frequently Questions": "أسئلة متكررة", + "سلامتك أولويتنا في انطلق. نوفر ميزات مثل التحقق من الكابتن، تتبع الرحلة داخل التطبيق، وخيارات الاتصال بالطوارئ.", + "Frequently Questions": "الأسئلة الشائعة", "User does not exist.": "المستخدم غير موجود.", "We need your phone number to contact you and to help you.": - "نحتاج إلى رقم هاتفك للاتصال بك ومساعدتك.", - "You will recieve code in sms message": - "سوف تتلقى رمزًا في رسالة SMS", + "نحتاج رقم هاتفك لنتواصل معك ونساعدك.", + "You will recieve code in sms message": "ستتلقى رمزاً في رسالة نصية", "Please enter": "الرجاء إدخال", "We need your phone number to contact you and to help you receive orders.": - "نحتاج إلى رقم هاتفك للاتصال بك ومساعدتك في استلام الطلبات.", + "نحتاج رقم هاتفك لنتواصل معك ولمساعدتك في استقبال الطلبات.", "The full name on your criminal record does not match the one on your driver's license. Please verify and provide the correct documents.": - "الاسم الكامل في سجلك الجنائي لا يتطابق مع الاسم الموجود في رخصة القيادة الخاصة بك. يرجى التحقق وتقديم الوثائق الصحيحة.", + "الاسم الكامل في وثيقة لا حكم عليه لا يطابق الاسم في رخصة القيادة. الرجاء التحقق وتقديم المستندات الصحيحة.", "The national number on your driver's license does not match the one on your ID document. Please verify and provide the correct documents.": - "الرقم الوطني على رخصة القيادة الخاصة بك لا يتطابق مع الرقم الموجود على وثيقة هويتك. يرجى التحقق وتقديم الوثائق الصحيحة.", + "الرقم الوطني في رخصة القيادة لا يطابق الرقم في هويتك. الرجاء التحقق وتقديم المستندات الصحيحة.", "Capture an Image of Your Criminal Record": - "التقاط صورة لسجلك الجنائي", + "التقط صورة لوثيقة لا حكم عليه", "IssueDate": "تاريخ الإصدار", "Capture an Image of Your car license front": - "التقاط صورة للوجه الأمامي لرخصة سيارتك", + "التقط صورة للوجه الأمامي لرخصة سيارتك", "Capture an Image of Your ID Document front": - "التقاط صورة للوجه الأمامي لوثيقة هويتك", - "NationalID": "الرقم القومي", + "التقط صورة للوجه الأمامي لهويتك", + "NationalID": "الرقم الوطني", "You can share the Intaleq App with your friends and earn rewards for rides they take using your code": - "يمكنك مشاركة تطبيق Intaleq مع أصدقائك وكسب مكافآت عن الرحلات التي يقومون بها باستخدام رمزك.", + "يمكنك مشاركة تطبيق انطلق مع أصدقائك وكسب مكافآت على الرحلات التي يقومون بها باستخدام رمزك.", "FullName": "الاسم الكامل", "No invitation found yet!": "لم يتم العثور على دعوات بعد!", "InspectionResult": "نتيجة الفحص", - "Criminal Record": "السجل الجنائي", - "Share App": "مشاركة التطبيق", + "Criminal Record": "لا حكم عليه", "The email or phone number is already registered.": - "البريد الإلكتروني أو رقم الهاتف مسجل بالفعل.", + "البريد الإلكتروني أو رقم الهاتف مسجل مسبقاً.", "To become a ride-sharing driver on the Intaleq app, you need to upload your driver's license, ID document, and car registration document. Our AI system will instantly review and verify their authenticity in just 2-3 minutes. If your documents are approved, you can start working as a driver on the Intaleq app. Please note, submitting fraudulent documents is a serious offense and may result in immediate termination and legal consequences.": - "لتصبح سائق مشاركة رحلات على تطبيق Intaleq، تحتاج إلى تحميل رخصة القيادة الخاصة بك، وثيقة الهوية، ووثيقة تسجيل السيارة. سيقوم نظام الذكاء الاصطناعي الخاص بنا بمراجعة وتأكيد صحتها على الفور في غضون 2-3 دقائق فقط. إذا تمت الموافقة على وثائقك، يمكنك البدء في العمل كسائق على تطبيق Intaleq. يرجى ملاحظة أن تقديم وثائق مزورة جريمة خطيرة وقد يؤدي إلى إنهاء فوري وعواقب قانونية.", + "لتصبح كابتن في تطبيق انطلق، يجب عليك رفع رخصة القيادة، الهوية الشخصية، ورخصة السيارة. سيقوم نظام الذكاء الاصطناعي لدينا بمراجعة وثائقك والتحقق من صحتها خلال 2-3 دقائق. في حال الموافقة، يمكنك البدء بالعمل مباشرة. يرجى العلم أن تقديم وثائق مزورة يعتبر مخالفة خطيرة وقد يؤدي إلى إنهاء حسابك وملاحقات قانونية.", "Documents check": "فحص الوثائق", "Driver's License": "رخصة القيادة", "for your first registration!": "لتسجيلك الأول!", "Get it Now!": "احصل عليه الآن!", "before": "قبل", - "Code not approved": "الرمز غير معتمد", - "3000 LE": "3000 جنيه", + "Code not approved": "الرمز غير مقبول", + "3000 LE": "3000 ل.س", "Do you have an invitation code from another driver?": - "هل لديك رمز دعوة من سائق آخر؟", + "هل لديك رمز دعوة من كابتن آخر؟", "Paste the code here": "الصق الرمز هنا", "No, I don't have a code": "لا، ليس لدي رمز", - "Code approved": "تمت الموافقة على الرمز", - "Install our app:": "قم بتثبيت تطبيقنا:", + "Code approved": "تم قبول الرمز", + "Install our app:": "حمّل تطبيقنا:", "Invite another driver and both get a gift after he completes 100 trips!": - "ادعُ سائقًا آخر واحصلا على هدية بعد إكماله 100 رحلة!", + "ادعُ كابتن آخر واحصلوا على هدية بعد إكماله 100 رحلة!", "Invite": "دعوة", "Are you sure?": "هل أنت متأكد؟", "This will delete all recorded files from your device.": "سيؤدي هذا إلى حذف جميع الملفات المسجلة من جهازك.", - "Select a file": "اختر ملفًا", - "Select a File": "اختر ملفًا", + "Select a file": "اختر ملفاً", + "Select a File": "اختر ملفاً", "Delete": "حذف", - "attach audio of complain": "إرفاق صوت للشكوى", - "Phone Number Check": "فحص رقم الهاتف", - "Drivers received orders": "استلم السائقون الطلبات", + "attach audio of complain": "إرفاق تسجيل صوتي للشكوى", + "Phone Number Check": "التحقق من رقم الهاتف", + "Drivers received orders": "الكباتن استلموا الطلبات", "No audio files recorded.": "لا توجد ملفات صوتية مسجلة.", "This is for delivery or a motorcycle.": - "هذا للتوصيل أو للدراجة النارية.", - "Intaleq Reminder": "تذكير Intaleq", - "It's time to check the Intaleq app!": - "حان الوقت للتحقق من تطبيق Intaleq!", - "you must insert token code": "يجب عليك إدخال رمز الرمز المميز", + "هذا لطلبات التوصيل أو الدراجات النارية.", + "Intaleq Reminder": "تذكير من انطلق", + "It's time to check the Intaleq app!": "حان وقت تفقد تطبيق انطلق!", + "you must insert token code": "يجب إدخال الرمز", "Something went wrong. Please try again.": - "حدث خطأ ما. يرجى المحاولة مرة أخرى.", + "حدث خطأ ما. الرجاء المحاولة مرة أخرى.", "Trip Details": "تفاصيل الرحلة", "The context does not provide any complaint details, so I cannot provide a solution to this issue. Please provide the necessary information, and I will be happy to assist you.": - "لا يوفر السياق أي تفاصيل عن الشكوى، لذا لا يمكنني تقديم حل لهذه المشكلة. يرجى تقديم المعلومات اللازمة، وسأكون سعيدًا بمساعدتك.", - "Submit Your Complaint": "تقديم شكواك", - "Date": "التاريخ", - "Price": "السعر", + "لا توجد تفاصيل كافية عن الشكوى لتقديم حل. يرجى تزويدنا بالمعلومات اللازمة، وسنسعد بمساعدتك.", + "Submit Your Complaint": "قدّم شكواك", "Status": "الحالة", "Choose from contact": "اختر من جهات الاتصال", - "attach correct audio": "إرفاق صوت صحيح", - "be sure": "كن متأكدًا", - "Audio uploaded successfully.": "تم تحميل الصوت بنجاح.", + "attach correct audio": "إرفاق الصوت الصحيح", + "be sure": "تأكد", + "Audio uploaded successfully.": "تم رفع الملف الصوتي بنجاح.", "Perfect for passengers seeking the latest car models with the freedom to choose any route they desire": - "مثالي للركاب الذين يبحثون عن أحدث طرازات السيارات مع حرية اختيار أي مسار يرغبون فيه", + "مثالي للركاب الذين يبحثون عن أحدث موديلات السيارات مع حرية اختيار أي مسار يرغبون به", "Share this code with your friends and earn rewards when they use it!": - "شارك هذا الرمز مع أصدقائك واكسب مكافآت عندما يستخدمونه!", - "Enter phone": "أدخل الهاتف", - "You deserve the gift": "أنت تستحق الهدية", - "complete, you can claim your gift": "اكتمل، يمكنك المطالبة بهديتك", + "شارك هذا الرمز مع أصدقائك واحصل على مكافآت عند استخدامه!", + "Enter phone": "أدخل الرقم", + "complete, you can claim your gift": "اكتمل، يمكنك طلب هديتك", "When": "عندما", - "Enter driver's phone": "أدخل هاتف السائق", + "Enter driver's phone": "أدخل رقم الكابتن", "Send Invite": "إرسال دعوة", "Show Invitations": "عرض الدعوات", "License Type": "نوع الرخصة", "National Number": "الرقم الوطني", - "Name (Arabic)": "الاسم (عربي)", - "Name (English)": "الاسم (إنجليزي)", + "Name (Arabic)": "الاسم (بالعربية)", + "Name (English)": "الاسم (بالإنكليزية)", "Address": "العنوان", "Issue Date": "تاريخ الإصدار", "Expiry Date": "تاريخ الانتهاء", "License Categories": "فئات الرخصة", "driver_license": "رخصة القيادة", - "Capture an Image of Your Driver License": - "التقاط صورة لرخصة القيادة الخاصة بك", - "ID Documents Back": "الوجه الخلفي لوثائق الهوية", - "National ID": "الهوية الوطنية", + "Capture an Image of Your Driver License": "التقط صورة لرخصة قيادتك", + "ID Documents Back": "الوجه الخلفي للهوية", + "National ID": "الرقم الوطني", "Occupation": "المهنة", - "Gender": "الجنس", "Religion": "الدين", - "Marital Status": "الحالة الاجتماعية", "Full Name (Marital)": "الاسم الكامل (حسب الحالة الاجتماعية)", "Expiration Date": "تاريخ الانتهاء", "Capture an Image of Your ID Document Back": - "التقاط صورة للوجه الخلفي لوثيقة هويتك", - "ID Documents Front": "الوجه الأمامي لوثائق الهوية", + "التقط صورة للوجه الخلفي لهويتك", + "ID Documents Front": "الوجه الأمامي للهوية", "First Name": "الاسم الأول", "CardID": "رقم البطاقة", - "Vehicle Details Front": "تفاصيل المركبة (الوجه الأمامي)", + "Vehicle Details Front": "تفاصيل المركبة (الأمام)", "Plate Number": "رقم اللوحة", "Owner Name": "اسم المالك", - "Vehicle Details Back": "تفاصيل المركبة (الوجه الخلفي)", - "Make": "الصنع", + "Vehicle Details Back": "تفاصيل المركبة (الخلف)", + "Make": "الشركة المصنعة", "Model": "الموديل", - "Year": "السنة", - "Chassis": "الشاسيه", + "Year": "سنة الصنع", + "Chassis": "رقم الشاسيه", "Color": "اللون", - "Displacement": "السعة", - "Fuel": "الوقود", + "Displacement": "سعة المحرك", + "Fuel": "نوع الوقود", "Tax Expiry Date": "تاريخ انتهاء الضريبة", "Inspection Date": "تاريخ الفحص", "Capture an Image of Your car license back": - "التقاط صورة للوجه الخلفي لرخصة سيارتك", + "التقط صورة للوجه الخلفي لرخصة سيارتك", "Capture an Image of Your Driver's License": - "التقاط صورة لرخصة القيادة الخاصة بك", + "التقط صورة لرخصة قيادتك", "Sign in with Google for easier email and name entry": - "تسجيل الدخول باستخدام Google لتسهيل إدخال البريد الإلكتروني والاسم", + "سجل الدخول عبر جوجل لتسهيل إدخال الاسم والبريد الإلكتروني", "You will choose allow all the time to be ready receive orders": - "ستختار السماح طوال الوقت لتكون جاهزًا لاستلام الطلبات", - "Welcome to Intaleq!": "مرحبًا بكم في Intaleq!", + "اختر 'السماح طوال الوقت' لتكون جاهزاً لاستقبال الطلبات", "Get to your destination quickly and easily.": - "الوصول إلى وجهتك بسرعة وسهولة.", + "صل إلى وجهتك بسرعة وسهولة.", "Enjoy a safe and comfortable ride.": "استمتع برحلة آمنة ومريحة.", "Choose Language": "اختر اللغة", - "Login": "تسجيل الدخول", "Pay with Wallet": "الدفع بالمحفظة", - "Invalid MPIN": "MPIN غير صالح", - "Invalid OTP": "OTP غير صالح", - "Enter your email address": "أدخل عنوان بريدك الإلكتروني", + "Invalid MPIN": "رمز MPIN غير صالح", + "Invalid OTP": "رمز التحقق غير صالح", + "Enter your email address": "أدخل بريدك الإلكتروني", "Please enter Your Email.": "الرجاء إدخال بريدك الإلكتروني.", "Enter your phone number": "أدخل رقم هاتفك", "Please enter your phone number.": "الرجاء إدخال رقم هاتفك.", - "Please enter Your Password.": "الرجاء إدخال كلمة المرور الخاصة بك.", + "Please enter Your Password.": "الرجاء إدخال كلمة المرور.", "if you dont have account": "إذا لم يكن لديك حساب", "Register": "تسجيل", "Accept Ride's Terms & Review Privacy Notice": - "قبول شروط الرحلة ومراجعة إشعار الخصوصية", + "قبول شروط الرحلة ومراجعة بيان الخصوصية", "By selecting 'I Agree' below, I have reviewed and agree to the Terms of Use and acknowledge the Privacy Notice. I am at least 18 years of age.": - "بالنقر على 'أوافق' أدناه، أكدت أنني قد راجعت وأوافق على شروط الاستخدام وأعترف بإشعار الخصوصية. أنا عمري 18 سنة على الأقل.", - "I Agree": "أوافق", + "باختياري 'أوافق' أدناه، أكون قد راجعت ووافقت على شروط الاستخدام وأقررت ببيان الخصوصية. وعمري لا يقل عن 18 عاماً.", "First name": "الاسم الأول", "Enter your first name": "أدخل اسمك الأول", "Please enter your first name.": "الرجاء إدخال اسمك الأول.", @@ -641,94 +728,93 @@ class MyTranslation extends Translations { "Please enter your last name.": "الرجاء إدخال اسمك الأخير.", "City": "المدينة", "Please enter your City.": "الرجاء إدخال مدينتك.", - "Male": "ذكر", - "Female": "أنثى", "Verify Email": "التحقق من البريد الإلكتروني", "We sent 5 digit to your Email provided": - "أرسلنا 5 أرقام إلى بريدك الإلكتروني المقدم", + "أرسلنا رمزاً من 5 أرقام إلى بريدك الإلكتروني", "5 digit": "5 أرقام", "Send Verification Code": "إرسال رمز التحقق", "Your Ride Duration is ": "مدة رحلتك هي ", - "You will be thier in": "ستكون هناك في", + "You will be thier in": "ستصل خلال", "You trip distance is": "مسافة رحلتك هي", - "Fee is": "الرسوم هي", + "Fee is": "الأجرة هي", "From : ": "من: ", "To : ": "إلى: ", - "Add Promo": "إضافة عرض ترويجي", + "Add Promo": "إضافة عرض", "Confirm Selection": "تأكيد الاختيار", "distance is": "المسافة هي", - "Intaleq LLC": "شركة Intaleq", - "Egypt's pioneering ride-sharing service, proudly developed by Arabian and local owners. We prioritize being near you – both our valued passengers and our dedicated captains.": - "خدمة مشاركة الرحلات الرائدة في مصر، تم تطويرها بفخر من قبل مالكين عرب ومحليين. نولي الأولوية لكوننا قريبين منك - سواء كنت راكبًا عزيزًا أو كابتنًا مخلصًا.", - "Why Choose Intaleq?": "لماذا تختار Intaleq؟", + "Privacy Policy": "سياسة الخصوصية", + "Intaleq LLC": "شركة انطلق", + "Syria's pioneering ride-sharing service, proudly developed by Arabian and local owners. We prioritize being near you – both our valued passengers and our dedicated captains.": + "خدمة مشاركة الرحلات الرائدة في سوريا، تم تطويرها بفخر من قبل ملاك عرب ومحليين. أولويتنا هي أن نكون بالقرب منك - ركابنا الكرام وكباتننا المتفانين.", + "Intaleq is the first ride-sharing app in Syria, designed to connect you with the nearest drivers for a quick and convenient travel experience.": + "انطلق هو أول تطبيق لمشاركة الرحلات في سوريا، مصمم ليوصلك بأقرب الكباتن لتجربة تنقل سريعة ومريحة.", + "Why Choose Intaleq?": "لماذا تختار انطلق؟", "Closest to You": "الأقرب إليك", "We connect you with the nearest drivers for faster pickups and quicker journeys.": - "نحن نوصلك بأقرب السائقين لعمليات استلام أسرع ورحلات أسرع.", + "نوصلك بأقرب الكباتن لوصول أسرع ورحلات أسرع.", "Uncompromising Security": "أمان لا هوادة فيه", - "Lady Captains Available": "كابتنات سيدات متاحات", + "Lady Captains Available": "كباتن سيدات متاحات", "Recorded Trips (Voice & AI Analysis)": "رحلات مسجلة (تحليل صوتي وذكاء اصطناعي)", "Fastest Complaint Response": "أسرع استجابة للشكاوى", "Our dedicated customer service team ensures swift resolution of any issues.": - "يضمن فريق خدمة العملاء المخصص لدينا حلًا سريعًا لأي مشكلات.", - "Affordable for Everyone": "بأسعار معقولة للجميع", - "Frequently Asked Questions": "أسئلة شائعة", - "Getting Started": "البدء", + "فريق خدمة العملاء لدينا يضمن حلاً سريعاً لأي مشكلة.", + "Affordable for Everyone": "أسعار مناسبة للجميع", + "Frequently Asked Questions": "الأسئلة المتكررة", + "Getting Started": "البداية", "Simply open the Intaleq app, enter your destination, and tap \"Request Ride\". The app will connect you with a nearby driver.": - "ببساطة افتح تطبيق Intaleq، أدخل وجهتك، واضغط على \"طلب رحلة\". سيتصل التطبيق بسائق قريب.", + "ببساطة افتح تطبيق انطلق، أدخل وجهتك، واضغط \"اطلب رحلة\". سيقوم التطبيق بتوصيلك بكابتن قريب.", "Vehicle Options": "خيارات المركبات", "Intaleq offers a variety of options including Economy, Comfort, and Luxury to suit your needs and budget.": - "يقدم Intaleq مجموعة متنوعة من الخيارات بما في ذلك الاقتصادية والراحة والفاخرة لتلبية احتياجاتك وميزانيتك.", - "Payments": "المدفوعات", + "يقدم انطلق خيارات متنوعة تشمل الاقتصادية، والمريحة، والفاخرة لتناسب احتياجاتك وميزانيتك.", + "Payments": "الدفع", "You can pay for your ride using cash or credit/debit card. You can select your preferred payment method before confirming your ride.": - "يمكنك الدفع مقابل رحلتك نقدًا أو ببطاقة الائتمان/الخصم. يمكنك اختيار طريقة الدفع المفضلة لديك قبل تأكيد رحلتك.", + "يمكنك الدفع لرحلتك نقداً أو ببطاقة الائتمان/الخصم. اختر طريقة الدفع المفضلة لديك قبل تأكيد الرحلة.", "Ride Management": "إدارة الرحلات", "Yes, you can cancel your ride, but please note that cancellation fees may apply depending on how far in advance you cancel.": - "نعم، يمكنك إلغاء رحلتك، ولكن يرجى ملاحظة أن رسوم الإلغاء قد تنطبق اعتمادًا على مدى تقدمك في الإلغاء.", - "For Drivers": "للسائقين", - "Driver Registration": "تسجيل السائق", + "نعم، يمكنك إلغاء رحلتك، ولكن قد يتم تطبيق رسوم إلغاء حسب توقيت الإلغاء.", + "For Drivers": "للكباتن", + "Driver Registration": "تسجيل الكابتن", "To register as a driver or learn about the requirements, please visit our website or contact Intaleq support directly.": - "لتسجيل كسائق أو معرفة المتطلبات، يرجى زيارة موقعنا على الإنترنت أو الاتصال بدعم Intaleq مباشرة.", - "Visit Website/Contact Support": "زيارة الموقع/الاتصال بالدعم", + "للتسجيل ككابتن أو لمعرفة المتطلبات، يرجى زيارة موقعنا أو التواصل مع دعم انطلق مباشرة.", + "Visit Website/Contact Support": "زيارة الموقع / التواصل مع الدعم", "Close": "إغلاق", - "We are searching for the nearest driver": "نحن نبحث عن أقرب سائق", - "Communication": "الاتصال", + "We are searching for the nearest driver": "نبحث عن أقرب كابتن", + "Communication": "التواصل", "How do I communicate with the other party (passenger/driver)?": - "كيف يمكنني التواصل مع الطرف الآخر (الراكب/السائق)؟", + "كيف أتواصل مع الطرف الآخر (الراكب/الكابتن)؟", "You can communicate with your driver or passenger through the in-app chat feature once a ride is confirmed.": - "يمكنك التواصل مع سائقك أو راكبك من خلال ميزة الدردشة داخل التطبيق بمجرد تأكيد الرحلة.", + "يمكنك التواصل مع الكابتن أو الراكب عبر ميزة الدردشة داخل التطبيق بعد تأكيد الرحلة.", "Safety & Security": "السلامة والأمان", "What safety measures does Intaleq offer?": - "ما هي إجراءات السلامة التي يقدمها Intaleq؟", + "ما هي إجراءات السلامة التي يوفرها انطلق؟", "Intaleq offers various safety features including driver verification, in-app trip tracking, emergency contact options, and the ability to share your trip status with trusted contacts.": - "يقدم Intaleq ميزات أمان متنوعة بما في ذلك التحقق من السائق، وتتبع الرحلة داخل التطبيق، وخيارات الاتصال في حالات الطوارئ، والقدرة على مشاركة حالة رحلتك مع جهات اتصال موثوقة.", + "يوفر انطلق ميزات أمان متنوعة تشمل التحقق من الكابتن، تتبع الرحلة داخل التطبيق، خيارات الاتصال بالطوارئ، وإمكانية مشاركة حالة رحلتك مع جهات اتصال موثوقة.", "Enjoy competitive prices across all trip options, making travel accessible.": - "استمتع بأسعار تنافسية عبر جميع خيارات الرحلات، مما يجعل السفر في متناول الجميع.", + "استمتع بأسعار تنافسية لجميع خيارات الرحلات، مما يجعل التنقل في متناول الجميع.", "Variety of Trip Choices": "تنوع خيارات الرحلات", "Choose the trip option that perfectly suits your needs and preferences.": - "اختر خيار الرحلة الذي يناسب احتياجاتك وتفضيلاتك تمامًا.", - "Your Choice, Our Priority": "اختيارك هو أولويتنا", + "اختر خيار الرحلة الذي يناسب احتياجاتك ورغباتك تماماً.", + "Your Choice, Our Priority": "اختيارك أولويتنا", "Because we are near, you have the flexibility to choose the ride that works best for you.": - "لأننا قريبون، لديك المرونة لاختيار الرحلة التي تناسبك أفضل.", + "لأننا قريبون، لديك المرونة لاختيار الرحلة الأنسب لك.", "duration is": "المدة هي", "Setting": "الإعدادات", "Find answers to common questions": "ابحث عن إجابات للأسئلة الشائعة", - "I don't need a ride anymore": "لم أعد بحاجة إلى رحلة", + "I don't need a ride anymore": "لم أعد بحاجة لرحلة", "I was just trying the application": "كنت أجرب التطبيق فقط", - "No driver accepted my request": "لم يقبل أي سائق طلبي", + "No driver accepted my request": "لم يوافق أي كابتن على طلبي", "I added the wrong pick-up/drop-off location": - "أضفت موقع الاستلام/التوصيل الخاطئ", + "أضفت موقع انطلاق/وصول خاطئ", "I don't have a reason": "ليس لدي سبب", - "Other": "أخرى", "Can we know why you want to cancel Ride ?": "هل يمكننا معرفة سبب رغبتك في إلغاء الرحلة؟", "Cancel Ride": "إلغاء الرحلة", "Add Payment Method": "إضافة طريقة دفع", - "Your Wallet balance is ": "رصيد محفظتك هو ", "Ride Wallet": "محفظة الرحلة", "Payment Method": "طريقة الدفع", - "Type here Place": "اكتب هنا المكان", - "Are You sure to ride to": "هل أنت متأكد من الركوب إلى", + "Type here Place": "اكتب المكان هنا", + "Are You sure to ride to": "هل أنت متأكد من الذهاب إلى", "Confirm": "تأكيد", "You are Delete": "أنت تحذف", "Deleted": "تم الحذف", @@ -736,451 +822,423 @@ class MyTranslation extends Translations { "From : Current Location": "من: الموقع الحالي", "My Cared": "بطاقاتي", "Add Card": "إضافة بطاقة", - "Add Credit Card": "إضافة بطاقة ائتمان", - "Please enter the cardholder name": "الرجاء إدخال اسم حامل البطاقة", - "Please enter the expiry date": "الرجاء إدخال تاريخ الانتهاء", + "Add Credit Card": "إضافة بطاقة ائتمانية", + "Please enter the cardholder name": "الرجاء إدخال اسم صاحب البطاقة", + "Please enter the expiry date": "الرجاء إدخال تاريخ انتهاء الصلاحية", "Please enter the CVV code": "الرجاء إدخال رمز CVV", "Go To Favorite Places": "الذهاب إلى الأماكن المفضلة", - "Go to this Target": "الذهاب إلى هذا الهدف", + "Go to this Target": "اذهب إلى هذه الوجهة", "My Profile": "ملفي الشخصي", - "Sign Out": "تسجيل الخروج", "Are you want to go to this site": "هل تريد الذهاب إلى هذا الموقع؟", "MyLocation": "موقعي", "my location": "موقعي", - "Target": "هدف", - "Update": "تحديث", - "You Should choose rate figure": "يجب عليك اختيار رقم التقييم", + "Target": "الوجهة", + "You Should choose rate figure": "يجب عليك اختيار تقييم", "Login Captin": "تسجيل دخول الكابتن", - "Register Captin": "تسجيل الكابتن", + "Register Captin": "تسجيل كابتن", "Send Verfication Code": "إرسال رمز التحقق", "KM": "كم", "End Ride": "إنهاء الرحلة", "Minute": "دقيقة", "Go to passenger Location now": "اذهب إلى موقع الراكب الآن", - "Duration of the Ride is ": "مدة الرحلة هي ", - "Distance of the Ride is ": "مسافة الرحلة هي ", - "Name of the Passenger is ": "اسم الراكب هو ", - "Hello this is Captain": "مرحبًا، هذا الكابتن", - "Start the Ride": "بدء الرحلة", + "Duration of the Ride is ": "مدة الرحلة ", + "Distance of the Ride is ": "مسافة الرحلة ", + "Name of the Passenger is ": "اسم الراكب ", + "Hello this is Captain": "مرحباً، معك الكابتن", + "Start the Ride": "ابدأ الرحلة", "Please Wait If passenger want To Cancel!": - "الرجاء الانتظار إذا أراد الراكب الإلغاء!", + "الرجاء الانتظار في حال أراد الراكب الإلغاء!", "Total Duration:": "المدة الإجمالية:", "Active Duration:": "المدة النشطة:", - "Waiting for Captin ...": "في انتظار الكابتن ...", - "Age is ": "العمر هو ", - "Rating is ": "التقييم هو ", + "Waiting for Captin ...": "بانتظار الكابتن...", + "Age is ": "العمر: ", + "Rating is ": "التقييم: ", " to arrive you.": "للوصول إليك.", - "Tariff": "التعريفة", + "Tariff": "التعرفة", "Settings": "الإعدادات", - "Feed Back": "ردود الفعل", + "Feed Back": "التقييمات", "Please enter a valid 16-digit card number": - "الرجاء إدخال رقم بطاقة صالح مكون من 16 رقمًا", - "Add Phone": "إضافة هاتف", + "الرجاء إدخال رقم بطاقة صالح مكون من 16 رقماً", + "Add Phone": "إضافة رقم", "Please enter a phone number": "الرجاء إدخال رقم هاتف", - "You dont Add Emergency Phone Yet!": - "لم تقم بإضافة هاتف الطوارئ بعد!", + "You dont Add Emergency Phone Yet!": "لم تقم بإضافة رقم طوارئ بعد!", "You will arrive to your destination after ": "ستصل إلى وجهتك بعد ", "You can cancel Ride now": "يمكنك إلغاء الرحلة الآن", "You Can cancel Ride After Captain did not come in the time": - "يمكنك إلغاء الرحلة بعد أن لم يأت الكابتن في الوقت المحدد", + "يمكنك إلغاء الرحلة إذا لم يأتِ الكابتن في الوقت المحدد", "If you in Car Now. Press Start The Ride": - "إذا كنت في السيارة الآن. اضغط على بدء الرحلة", - "You Dont Have Any amount in": "ليس لديك أي مبلغ في", + "إذا كنت في السيارة الآن، اضغط على 'ابدأ الرحلة'", + "You Dont Have Any amount in": "ليس لديك أي رصيد في", "Wallet!": "المحفظة!", "You Have": "لديك", - "Save Credit Card": "حفظ بطاقة الائتمان", - "Show Promos": "عرض العروض الترويجية", + "Save Credit Card": "حفظ البطاقة الائتمانية", + "Show Promos": "عرض العروض", "10 and get 4% discount": "10 واحصل على خصم 4%", "20 and get 6% discount": "20 واحصل على خصم 6%", "40 and get 8% discount": "40 واحصل على خصم 8%", "100 and get 11% discount": "100 واحصل على خصم 11%", - "Pay with Your PayPal": "الدفع باستخدام PayPal", - "You will choose one of above !": "ستختار أحد الخيارات أعلاه!", - "Delete My Account": "حذف حسابي", + "Pay with Your PayPal": "ادفع عبر PayPal", + "You will choose one of above !": "اختر أحد الخيارات أعلاه!", "Edit Profile": "تعديل الملف الشخصي", - "Name": "الاسم", - "Update Gender": "تحديث الجنس", - "Education": "التعليم", - "Update Education": "تحديث التعليم", - "Employment Type": "نوع التوظيف", - "SOS Phone": "هاتف الطوارئ", - "High School Diploma": "دبلوم المدرسة الثانوية", - "Associate Degree": "درجة الزمالة", - "Bachelor's Degree": "درجة البكالوريوس", - "Master's Degree": "درجة الماجستير", - "Doctoral Degree": "درجة الدكتوراه", "Copy this Promo to use it in your Ride!": - "انسخ هذا العرض الترويجي لاستخدامه في رحلتك!", + "انسخ هذا العرض واستخدمه في رحلتك!", "To change some Settings": "لتغيير بعض الإعدادات", - "Order Request Page": "صفحة طلب الطلب", - "Rouats of Trip": "طرق الرحلة", - "Passenger Name is ": "اسم الراكب هو ", - "Total From Passenger is ": "المجموع من الراكب هو ", - "Duration To Passenger is ": "المدة للراكب هي ", - "Distance To Passenger is ": "المسافة للراكب هي ", - "Total For You is ": "المجموع لك هو ", - "Distance is ": "المسافة هي ", + "Order Request Page": "صفحة طلب الرحلة", + "Rouats of Trip": "مسارات الرحلة", + "Passenger Name is ": "اسم الراكب: ", + "Total From Passenger is ": "الإجمالي من الراكب: ", + "Duration To Passenger is ": "المدة للوصول للراكب: ", + "Distance To Passenger is ": "المسافة للوصول للراكب: ", + "Total For You is ": "الإجمالي لك: ", + "Distance is ": "المسافة: ", " KM": " كم", - "Duration of Trip is ": "مدة الرحلة هي ", + "Duration of Trip is ": "مدة الرحلة: ", " Minutes": " دقائق", - "Apply Order": "تطبيق الطلب", + "Apply Order": "قبول الطلب", "Refuse Order": "رفض الطلب", "Rate Captain": "تقييم الكابتن", "Enter your Note": "أدخل ملاحظتك", - "Type something...": "اكتب شيئًا...", + "Type something...": "اكتب شيئاً...", "Submit rating": "إرسال التقييم", "Rate Passenger": "تقييم الراكب", "Ride Summary": "ملخص الرحلة", - "welcome_message": "مرحبًا بك في Intaleq!", + "welcome_message": "أهلاً بك في انطلق!", "app_description": - "Intaleq هو تطبيق مشاركة ركوب موثوق وآمن وسهل الوصول إليه.", - "get_to_destination": "اذهب إلى وجهتك بسرعة وسهولة.", - "get_a_ride": "مع Intaleq، يمكنك الحصول على رحلة إلى وجهتك في دقائق.", + "انطلق هو تطبيق لمشاركة الرحلات، موثوق، آمن، وفي متناول اليد.", + "get_to_destination": "صل إلى وجهتك بسرعة وسهولة.", + "get_a_ride": "مع انطلق، يمكنك الحصول على توصيلة لوجهتك في دقائق.", "safe_and_comfortable": "استمتع برحلة آمنة ومريحة.", "committed_to_safety": - "Intaleq ملتزمة بالسلامة، وكل كابتناتنا يتم فحصهم بعناية والتحقق من خلفيتهم.", + "تلتزم انطلق بالسلامة، وجميع كباتننا يتم فحصهم بعناية والتحقق من سجلاتهم.", "your ride is Accepted": "تم قبول رحلتك", - "Driver is waiting at pickup.": - "السائق في انتظارك عند نقطة الاستلام.", - "Driver is on the way": "السائق في الطريق", - "Contact Options": "خيارات الاتصال", + "Driver is waiting at pickup.": "الكابتن بانتظارك في نقطة الانطلاق.", + "Driver is on the way": "الكابتن في الطريق", + "Contact Options": "خيارات التواصل", "Send a custom message": "إرسال رسالة مخصصة", "Type your message": "اكتب رسالتك", - "I will go now": "سأذهب الآن", - "You Have Tips": "لديك بقشيش", - " tips\nTotal is": " بقشيش\nالمجموع هو", + "I will go now": "أنا ذاهب الآن", + "You Have Tips": "لديك إكرامية", + " tips\nTotal is": " إكرامية\nالإجمالي هو", "Your fee is ": "أجرتك هي ", "Do you want to pay Tips for this Driver": - "هل تريد دفع بقشيش لهذا السائق؟", - "Tip is ": "البقشيش هو ", + "هل تريد دفع إكرامية لهذا الكابتن؟", + "Tip is ": "الإكرامية: ", "Are you want to wait drivers to accept your order": - "هل تريد الانتظار حتى يقبل السائقون طلبك؟", + "هل تريد انتظار الكباتن ليقبلوا طلبك؟", "This price is fixed even if the route changes for the driver.": - "هذا السعر ثابت حتى لو تغير المسار للسائق.", + "هذا السعر ثابت حتى لو تغير مسار الكابتن.", "The price may increase if the route changes.": - "قد يزيد السعر إذا تغير المسار.", + "قد يرتفع السعر إذا تغير المسار.", "The captain is responsible for the route.": - "الكابتن مسؤول عن المسار.", - "We are search for nearst driver": "نحن نبحث عن أقرب سائق", - "Your order is being prepared": "يتم تحضير طلبك", - "The drivers are reviewing your request": "السائقون يراجعون طلبك", - "Your order sent to drivers": "تم إرسال طلبك إلى السائقين", + "الكابتن هو المسؤول عن المسار.", + "We are search for nearst driver": "نبحث عن أقرب كابتن", + "Your order is being prepared": "طلبك قيد التحضير", + "The drivers are reviewing your request": "يقوم الكباتن بمراجعة طلبك", + "Your order sent to drivers": "تم إرسال طلبك للكباتن", "You can call or record audio of this trip": "يمكنك الاتصال أو تسجيل صوت لهذه الرحلة", "The trip has started! Feel free to contact emergency numbers, share your trip, or activate voice recording for the journey": - "بدأت الرحلة! لا تتردد في الاتصال بأرقام الطوارئ، مشاركة رحلتك، أو تفعيل التسجيل الصوتي للرحلة.", + "بدأت الرحلة! يمكنك الآن الاتصال بأرقام الطوارئ، مشاركة رحلتك، أو تفعيل التسجيل الصوتي.", "Camera Access Denied.": "تم رفض الوصول إلى الكاميرا.", "Open Settings": "فتح الإعدادات", - "GPS Required Allow !.": "يجب السماح بـ GPS!", + "GPS Required Allow !.": "مطلوب تفعيل GPS!", "Your Account is Deleted": "تم حذف حسابك", "Are you sure to delete your account?": "هل أنت متأكد من حذف حسابك؟", "Your data will be erased after 2 weeks\nAnd you will can't return to use app after 1 month ": - "سيتم حذف بياناتك بعد أسبوعين\nولن تتمكن من العودة لاستخدام التطبيق بعد شهر", + "سيتم حذف بياناتك بعد أسبوعين\nولن تتمكن من استخدام التطبيق مرة أخرى بعد شهر واحد.", "Enter Your First Name": "أدخل اسمك الأول", "Are you Sure to LogOut?": "هل أنت متأكد من تسجيل الخروج؟", "Email Wrong": "البريد الإلكتروني خاطئ", "Email you inserted is Wrong.": "البريد الإلكتروني الذي أدخلته خاطئ.", - "You have finished all times ": "لقد انتهيت من كل المحاولات", + "You have finished all times ": "لقد استنفدت كل المحاولات", "if you want help you can email us here": - "إذا كنت تريد المساعدة يمكنك مراسلتنا هنا", - "Thanks": "شكرًا", + "إذا كنت بحاجة للمساعدة، يمكنك مراسلتنا هنا", + "Thanks": "شكراً", "Email Us": "راسلنا عبر البريد الإلكتروني", "I cant register in your app in face detection ": - "لا يمكنني التسجيل في تطبيقك في كشف الوجه", - "Hi": "مرحبًا", - "No face detected": "لم يتم اكتشاف أي وجه", - "Image detecting result is ": "نتيجة اكتشاف الصورة هي ", - "from 3 times Take Attention": "من 3 مرات انتبه", + "لا أستطيع التسجيل في تطبيقكم بسبب مشكلة في التحقق من الوجه", + "Hi": "مرحباً", + "No face detected": "لم يتم التعرف على أي وجه", + "Image detecting result is ": "نتيجة التعرف على الصورة هي ", + "from 3 times Take Attention": "من 3 محاولات، انتبه", "Be sure for take accurate images please\nYou have": - "كن متأكدًا من التقاط صور دقيقة من فضلك\nلديك", + "الرجاء التأكد من التقاط صور دقيقة\nلديك", "image verified": "تم التحقق من الصورة", "Next": "التالي", "There is no help Question here": "لا يوجد سؤال مساعدة هنا", "You dont have Points": "ليس لديك نقاط", - "You Are Stopped For this Day !": "تم إيقافك لهذا اليوم!", + "You Are Stopped For this Day !": "لقد تم إيقافك لهذا اليوم!", "You must be charge your Account": "يجب عليك شحن حسابك", "You Refused 3 Rides this Day that is the reason \nSee you Tomorrow!": - "لقد رفضت 3 رحلات هذا اليوم وهذا هو السبب\nنراكم غدًا!", + "لقد رفضت 3 رحلات اليوم، ولهذا السبب تم إيقافك.\nنراك غداً!", "Recharge my Account": "إعادة شحن حسابي", - "Ok , See you Tomorrow": "حسنًا، أراك غدًا", - "You are Stopped": "تم إيقافك", + "Ok , See you Tomorrow": "حسناً، أراك غداً", + "You are Stopped": "أنت موقوف", "Connected": "متصل", "Not Connected": "غير متصل", "Your are far from passenger location": "أنت بعيد عن موقع الراكب", "go to your passenger location before\nPassenger cancel trip": - "اذهب إلى موقع الراكب قبل\nأن يلغي الراكب الرحلة", + "اذهب إلى موقع الراكب قبل أن يلغي الرحلة", "You will get cost of your work for this trip": "ستحصل على تكلفة عملك لهذه الرحلة", " in your wallet": "في محفظتك", "you gain": "لقد ربحت", "Order Cancelled by Passenger": "تم إلغاء الطلب من قبل الراكب", - "Success": "نجاح", - "Feedback data saved successfully": "تم حفظ بيانات التعليقات بنجاح", - "No Promo for today .": "لا يوجد عرض ترويجي لهذا اليوم.", + "Feedback data saved successfully": "تم حفظ التقييم بنجاح", + "No Promo for today .": "لا يوجد عرض لليوم.", "Select your destination": "اختر وجهتك", - "Search for your Start point": "ابحث عن نقطة البداية", - "Search for waypoint": "ابحث عن النقطة الوسيطة", + "Search for your Start point": "ابحث عن نقطة انطلاقك", + "Search for waypoint": "ابحث عن نقطة توقف", "Current Location": "الموقع الحالي", - "Add Location 1": "إضافة الموقع 1", + "Add Location 1": "إضافة موقع 1", "You must Verify email !.": "يجب عليك التحقق من البريد الإلكتروني!", - "Cropper": "القاطع", + "Cropper": "قص الصورة", "Saved Sucssefully": "تم الحفظ بنجاح", "Select Date": "اختر التاريخ", "Birth Date": "تاريخ الميلاد", - "Ok": "موافق", - "the 500 points equal 30 JOD": "500 نقطة تساوي 30 دينار أردني", + "Ok": "حسناً", + "the 500 points equal 30 JOD": "500 نقطة تساوي 30 ديناراً أردنياً", "the 500 points equal 30 JOD for you \nSo go and gain your money": - "500 نقطة تساوي 30 دينار أردني لك\nلذا اذهب واكسب أموالك", - "token updated": "تم تحديث الرمز المميز", - "Add Location 2": "إضافة الموقع 2", - "Add Location 3": "إضافة الموقع 3", - "Add Location 4": "إضافة الموقع 4", - "Waiting for your location": "في انتظار موقعك", + "500 نقطة تساوي 30 ديناراً أردنياً لك\nاذهب الآن واكسب أموالك", + "token updated": "تم تحديث الرمز", + "Add Location 2": "إضافة موقع 2", + "Add Location 3": "إضافة موقع 3", + "Add Location 4": "إضافة موقع 4", + "Waiting for your location": "بانتظار موقعك", "Search for your destination": "ابحث عن وجهتك", - "Hi! This is": "مرحبًا! هذا هو", + "Hi! This is": "مرحباً! هذا", " I am using": " أنا أستخدم", - " to ride with": " للركوب مع", - " as the driver.": " كسائق.", - "is driving a ": "يقود ", - " with license plate ": " بلوحة ترخيص ", - " I am currently located at ": " أنا حاليًا في ", - "Please go to Car now ": "الرجاء الذهاب إلى السيارة الآن", + " to ride with": " للتنقل مع", + " as the driver.": " ككابتن.", + "is driving a ": "يقود سيارة ", + " with license plate ": " رقم لوحتها ", + " I am currently located at ": " أنا حالياً في ", + "Please go to Car now ": "الرجاء التوجه إلى السيارة الآن", "You will receive a code in WhatsApp Messenger": - "سوف تتلقى رمزًا في WhatsApp Messenger", + "سوف تستلم الرمز عبر واتساب", "If you need assistance, contact us": - "إذا كنت بحاجة إلى مساعدة، اتصل بنا", - "Promo Ended": "انتهى العرض الترويجي", - "Enter the promo code and get": "أدخل رمز العرض الترويجي واحصل على", + "إذا احتجت للمساعدة، تواصل معنا", + "Promo Ended": "انتهى العرض", + "Enter the promo code and get": "أدخل رمز العرض واحصل على", "DISCOUNT": "خصم", - "No wallet record found": "لم يتم العثور على سجل محفظة", - "for": "لمدة", + "No wallet record found": "لم يتم العثور على سجل للمحفظة", + "for": "لـ", "Intaleq 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.": - "Intaleq هو تطبيق مشاركة ركوب الأكثر أمانًا الذي يقدم العديد من الميزات لكل من الكابتنات والركاب. نقدم أقل معدل عمولة بنسبة 8٪ فقط، مما يضمن لك الحصول على أفضل قيمة مقابل رحلاتك. يتضمن تطبيقنا تأمينًا لأفضل الكابتنات، وصيانة دورية للسيارات مع كبار المهندسين، وخدمات على الطريق لضمان تجربة محترمة وعالية الجودة لجميع المستخدمين.", + "انطلق هو تطبيق مشاركة الرحلات الأكثر أماناً، ويقدم ميزات عديدة للكباتن والركاب. نقدم أقل نسبة عمولة، 8% فقط، لنضمن لك أفضل قيمة لرحلاتك. يشمل تطبيقنا تأميناً لأفضل الكباتن، صيانة دورية للسيارات مع أفضل المهندسين، وخدمات على الطريق لتجربة محترمة وعالية الجودة لجميع المستخدمين.", "You can contact us during working hours from 12:00 - 19:00.": - "يمكنك الاتصال بنا خلال ساعات العمل من 12:00 إلى 19:00.", - "Choose a contact option": "اختر خيار الاتصال", + "يمكنك التواصل معنا خلال ساعات العمل من 12:00 ظهراً حتى 7:00 مساءً.", + "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يمكنك إرسال رسالة WhatsApp أو بريد إلكتروني.", - "Promo code copied to clipboard!": - "تم نسخ رمز العرض الترويجي إلى الحافظة!", + "أوقات العمل من 12:00 ظهراً حتى 7: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:": "صالح حتى:", + "You have copied the promo code.": "لقد نسخت رمز العرض.", "Select Payment Amount": "اختر مبلغ الدفع", - "The promotion period has ended.": "انتهت فترة الترويج.", - "Promo Code Accepted": "تم قبول رمز العرض الترويجي", - "Tap on the promo code to copy it!": - "اضغط على رمز العرض الترويجي لنسخه!", - "Lowest Price Achieved": "تم تحقيق أقل سعر", + "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": "تم استخدام العرض الترويجي بالفعل", + "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": "الرجاء إدخال رمز عرض ترويجي صالح", + "لقد استخدمت هذا العرض مسبقاً.", + "Insert Your Promo Code": "أدخل رمز العرض الخاص بك", + "Enter promo code here": "أدخل رمز العرض هنا", + "Please enter a valid promo code": "الرجاء إدخال رمز عرض صالح", "Awfar Car": "سيارة أوفر", "Old and affordable, perfect for budget rides.": - "قديمة وبأسعار معقولة، مثالية للرحلات المحدودة الميزانية.", + "قديمة واقتصادية، مثالية للرحلات الموفّرة.", " If you need to reach me, please contact the driver directly at": - "إذا كنت بحاجة إلى الوصول إلي، يرجى الاتصال بالسائق مباشرة على", + "إذا احتجت للتواصل معي، يرجى الاتصال بالكابتن مباشرة على", "No Car or Driver Found in your area.": - "لم يتم العثور على سيارة أو سائق في منطقتك.", + "لم يتم العثور على سيارة أو كابتن في منطقتك.", "Please Try anther time ": "الرجاء المحاولة في وقت آخر", "There no Driver Aplly your order sorry for that ": - "لا يوجد سائق ينفذ طلبك، نأسف لذلك", + "لم يتقدم أي كابتن لطلبك، نعتذر عن ذلك", "Trip Cancelled": "تم إلغاء الرحلة", "The Driver Will be in your location soon .": - "سيكون السائق في موقعك قريبًا.", + "سيصل الكابتن إلى موقعك قريباً.", "The distance less than 500 meter.": "المسافة أقل من 500 متر.", - "Promo End !": "انتهى العرض الترويجي!", + "Promo End !": "انتهى العرض!", "There is no notification yet": "لا توجد إشعارات بعد", "Use Touch ID or Face ID to confirm payment": - "استخدم Touch ID أو Face ID لتأكيد الدفع", + "استخدم بصمة الإصبع أو الوجه لتأكيد الدفع", "Contact us for any questions on your order.": - "اتصل بنا لأي أسئلة حول طلبك.", + "تواصل معنا لأي استفسار حول طلبك.", "Pyament Cancelled .": "تم إلغاء الدفع.", "type here": "اكتب هنا", "Scan Driver License": "مسح رخصة القيادة", "Please put your licence in these border": - "الرجاء وضع رخصتك داخل هذه الحدود", - "Camera not initialized yet": "لم يتم تهيئة الكاميرا بعد", - "Take Image": "التقاط صورة", + "الرجاء وضع رخصتك ضمن هذه الحدود", + "Camera not initialized yet": "لم يتم تفعيل الكاميرا بعد", + "Take Image": "التقط صورة", "AI Page": "صفحة الذكاء الاصطناعي", - "Take Picture Of ID Card": "التقاط صورة لبطاقة الهوية", - "Take Picture Of Driver License Card": - "التقاط صورة لبطاقة رخصة القيادة", + "Take Picture Of ID Card": "التقط صورة للهوية", + "Take Picture Of Driver License Card": "التقط صورة لرخصة القيادة", "We are process picture please wait ": - "نحن نعالج الصورة، يرجى الانتظار", + "جاري معالجة الصورة، يرجى الانتظار", "There is no data yet.": "لا توجد بيانات بعد.", "Name :": "الاسم:", - "Drivers License Class: ": "فئة رخصة القيادة: ", - "Document Number: ": "رقم المستند: ", - "Address: ": "العنوان: ", - "Height: ": "الطول: ", - "Expiry Date: ": "تاريخ الانتهاء: ", - "Date of Birth: ": "تاريخ الميلاد: ", + "Drivers License Class: ": "فئة الرخصة:", + "Document Number: ": "رقم الوثيقة:", + "Address: ": "العنوان:", + "Height: ": "الطول:", + "Expiry Date: ": "تاريخ الانتهاء:", + "Date of Birth: ": "تاريخ الميلاد:", "You can't continue with us .\nYou should renew Driver license": - "لا يمكنك الاستمرار معنا.\nيجب عليك تجديد رخصة القيادة", - "Detect Your Face ": "اكتشف وجهك", + "لا يمكنك المتابعة معنا.\nيجب عليك تجديد رخصة القيادة", + "Detect Your Face ": "التحقق من وجهك", "Go to next step\nscan Car License.": - "انتقل إلى الخطوة التالية\nمسح رخصة السيارة.", + "انتقل للخطوة التالية\nمسح رخصة السيارة.", "Name in arabic": "الاسم بالعربية", "Drivers License Class": "فئة رخصة القيادة", "Selected Date": "التاريخ المحدد", "Select Time": "اختر الوقت", "Selected Time": "الوقت المحدد", - "Selected Date and Time": "التاريخ والوقت المحددين", - "Lets check Car license ": "دعونا نتحقق من رخصة السيارة", - "Car": "السيارة", - "Plate": "اللوحة", - "Rides": "الرحلات", - "Selected driver": "السائق المحدد", - "Lets check License Back Face": "دعونا نتحقق من الوجه الخلفي للرخصة", - "Car License Card": "بطاقة رخصة السيارة", - "No image selected yet": "لم يتم اختيار أي صورة بعد", + "Selected Date and Time": "التاريخ والوقت المحددان", + "Lets check Car license ": "لنتحقق من رخصة السيارة", + "Car": "سيارة", + "Plate": "لوحة", + "Rides": "رحلات", + "Selected driver": "الكابتن المختار", + "Lets check License Back Face": "لنتحقق من الوجه الخلفي للرخصة", + "Car License Card": "رخصة السيارة", + "No image selected yet": "لم يتم اختيار صورة بعد", "Made :": "الصنع:", "model :": "الموديل:", - "VIN :": "VIN:", + "VIN :": "رقم الهيكل:", "year :": "السنة:", "ُExpire Date": "تاريخ الانتهاء", - "Login Driver": "تسجيل دخول السائق", + "Login Driver": "دخول الكابتن", "Password must br at least 6 character.": - "يجب أن تكون كلمة المرور مكونة من 6 أحرف على الأقل.", + "يجب أن تتكون كلمة المرور من 6 أحرف على الأقل.", "if you don't have account": "إذا لم يكن لديك حساب", - "Here recorded trips audio": "هنا تسجيلات صوتية للرحلات", - "Register as Driver": "التسجيل كسائق", + "Here recorded trips audio": "هنا التسجيلات الصوتية للرحلات", + "Register as Driver": "التسجيل ككابتن", "By selecting \"I Agree\" below, I have reviewed and agree to the Terms of Use and acknowledge the ": - "بالنقر على \"أوافق\" أدناه، أكدت أنني قد راجعت وأوافق على شروط الاستخدام وأعترف بـ ", + "باختياري \"أوافق\" أدناه، أكون قد راجعت ووافقت على شروط الاستخدام وأقر بـ", "Log Out Page": "صفحة تسجيل الخروج", "Log Off": "تسجيل الخروج", - "Register Driver": "تسجيل السائق", - "Verify Email For Driver": "التحقق من البريد الإلكتروني للسائق", - "Admin DashBoard": "لوحة تحكم المدير", + "Register Driver": "تسجيل كابتن", + "Verify Email For Driver": "التحقق من بريد الكابتن الإلكتروني", + "Admin DashBoard": "لوحة تحكم المشرف", "Your name": "اسمك", - "your ride is applied": "تم تطبيق رحلتك", - "Your password": "كلمة المرور الخاصة بك", - "H and": "ساعة و", - "LE": "جنيه", + "your ride is applied": "تم قبول رحلتك", + "H and": "س و", "JOD": "دينار", - "m": "دقيقة", - "We search nearst Driver to you": "نحن نبحث عن أقرب سائق لك", + "m": "د", + "We search nearst Driver to you": "نبحث لك عن أقرب كابتن", "please wait till driver accept your order": - "الرجاء الانتظار حتى يقبل السائق طلبك", + "الرجاء الانتظار حتى يقبل الكابتن طلبك", "No accepted orders? Try raising your trip fee to attract riders.": - "لا توجد طلبات مقبولة؟ حاول زيادة رسوم رحلتك لجذب الركاب.", + "لا يوجد قبول للطلبات؟ حاول رفع أجرة رحلتك لجذب الكباتن.", "You should select one": "يجب عليك اختيار واحد", - "The driver accept your order for": "قبل السائق طلبك مقابل", - "Increase Fee": "زيادة الرسوم", - "No, thanks": "لا، شكرًا", - "The driver on your way": "السائق في طريقه إليك", + "The driver accept your order for": "الكابتن قبل طلبك مقابل", + "The driver on your way": "الكابتن في طريقه إليك", "Total price from ": "السعر الإجمالي من ", - "Order Details Intaleq": "تفاصيل الطلب Intaleq", - "accepted your order": "قبل طلبك", - "Selected file:": "الملف المحدد:", + "Order Details Intaleq": "تفاصيل طلب انطلق", + "Selected file:": "الملف المختار:", "Your trip cost is": "تكلفة رحلتك هي", "this will delete all files from your device": "سيؤدي هذا إلى حذف جميع الملفات من جهازك", "Exclusive offers and discounts always with the Intaleq app": - "عروض وخصومات حصرية دائمًا مع تطبيق Intaleq", + "عروض وخصومات حصرية دائماً مع تطبيق انطلق", "Submit Question": "إرسال سؤال", "Please enter your Question.": "الرجاء إدخال سؤالك.", "Help Details": "تفاصيل المساعدة", "No trip yet found": "لم يتم العثور على رحلة بعد", - "No Response yet.": "لا توجد استجابة بعد.", - " You Earn today is ": "ما كسبته اليوم هو ", + "No Response yet.": "لا يوجد رد بعد.", + " You Earn today is ": "أرباحك اليوم هي ", " You Have in": " لديك في", - "Total points is ": "إجمالي النقاط هو ", + "Total points is ": "إجمالي النقاط: ", "Total Connection Duration:": "إجمالي مدة الاتصال:", "Passenger name : ": "اسم الراكب: ", - "Cost Of Trip IS ": "تكلفة الرحلة هي ", + "Cost Of Trip IS ": "تكلفة الرحلة: ", "Arrival time": "وقت الوصول", "arrival time to reach your point": "وقت الوصول إلى وجهتك", "For Intaleq and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance": - "لرحلات Intaleq والدراجات البخارية، يتم حساب السعر ديناميكيًا. لرحلات الراحة، يعتمد السعر على الوقت والمسافة.", - "Hello this is Driver": "مرحبًا، هذا هو السائق", + "لرحلات انطلق والسكوتر، يتم حساب السعر بشكل متغير. أما لرحلات الراحة، فيعتمد السعر على الوقت والمسافة.", + "Hello this is Driver": "مرحباً، معك الكابتن", "Is the Passenger in your Car ?": "هل الراكب في سيارتك؟", "Please wait for the passenger to enter the car before starting the trip.": - "الرجاء الانتظار حتى يدخل الراكب السيارة قبل بدء الرحلة.", - "No ,still Waiting.": "لا، ما زال في الانتظار.", - "I arrive you": "وصلت إليك", - "I Arrive your site": "وصلت إلى موقعك", + "الرجاء انتظار دخول الراكب إلى السيارة قبل بدء الرحلة.", + "No ,still Waiting.": "لا، ما زلت أنتظر.", + "I arrive you": "أنا وصلتك", + "I Arrive your site": "أنا وصلت لموقعك", "You are not in near to passenger location": - "أنت لست قريبًا من موقع الراكب", + "أنت لست قريباً من موقع الراكب", "please go to picker location exactly": - "الرجاء الذهاب إلى موقع المنتقي بالضبط", + "الرجاء الذهاب إلى موقع الانطلاق بدقة", "You Can Cancel Trip And get Cost of Trip From": - "يمكنك إلغاء الرحلة والحصول على تكلفة الرحلة من", + "يمكنك إلغاء الرحلة والحصول على تكلفتها من", "Are you sure to cancel?": "هل أنت متأكد من الإلغاء؟", "Insert Emergincy Number": "إدخال رقم الطوارئ", "Best choice for comfort car and flexible route and stops point": - "أفضل خيار لسيارة مريحة ومسار مرن ونقاط توقف", - "Insert": "إدراج", + "الخيار الأفضل لسيارة مريحة ومسار مرن ونقاط توقف", + "Insert": "إدخال", "This is for scooter or a motorcycle.": - "هذا للدراجة البخارية أو الدراجة النارية.", + "هذا للسكوتر أو الدراجة النارية.", "This trip goes directly from your starting point to your destination for a fixed price. The driver must follow the planned route": - "تذهب هذه الرحلة مباشرة من نقطة البداية إلى وجهتك بسعر ثابت. يجب على السائق اتباع المسار المخطط.", + "هذه الرحلة مباشرة من نقطة انطلاقك إلى وجهتك بسعر ثابت. يجب على الكابتن اتباع المسار المحدد.", "You can decline a request without any cost": - "يمكنك رفض طلب بدون أي تكلفة", + "يمكنك رفض الطلب دون أي تكلفة", "Perfect for adventure seekers who want to experience something new and exciting": - "مثالي لطالبي المغامرة الذين يريدون تجربة شيء جديد ومثير", + "مثالي لمحبي المغامرات الذين يرغبون في تجربة شيء جديد ومثير", "My current location is:": "موقعي الحالي هو:", "and I have a trip on": "ولدي رحلة على", "App with Passenger": "التطبيق مع الراكب", "You will be pay the cost to driver or we will get it from you on next trip": - "ستدفع التكلفة للسائق أو سنحصل عليها منك في الرحلة التالية", - "Trip has Steps": "الرحلة لديها خطوات", + "ستدفع التكلفة للكابتن أو سنحصل عليها منك في الرحلة القادمة", + "Trip has Steps": "الرحلة لها عدة وجهات", "Distance from Passenger to destination is ": - "المسافة من الراكب إلى الوجهة هي ", + "المسافة من الراكب للوجهة: ", "price is": "السعر هو", "This ride type does not allow changes to the destination or additional stops": - "هذا النوع من الرحلة لا يسمح بتغيير الوجهة أو إيقافات إضافية", + "هذا النوع من الرحلات لا يسمح بتغيير الوجهة أو إضافة نقاط توقف", "This price may be changed": "قد يتغير هذا السعر", "No SIM card, no problem! Call your driver directly through our app. We use advanced technology to ensure your privacy.": - "لا توجد بطاقة SIM، لا مشكلة! اتصل بسائقك مباشرة من خلال تطبيقنا. نستخدم تقنية متقدمة لضمان خصوصيتك.", + "لا حاجة لبطاقة SIM! اتصل بالكابتن مباشرة عبر تطبيقنا. نستخدم تقنية متقدمة لضمان خصوصيتك.", "This ride type allows changes, but the price may increase": - "هذا النوع من الرحلة يسمح بالتغييرات، ولكن قد يزيد السعر", + "هذا النوع من الرحلات يسمح بالتغييرات، ولكن قد يرتفع السعر", "Select one message": "اختر رسالة واحدة", - "I'm waiting for you": "أنا في انتظارك", + "I'm waiting for you": "أنا بانتظارك", "We noticed the Intaleq is exceeding 100 km/h. Please slow down for your safety. If you feel unsafe, you can share your trip details with a contact or call the police using the red SOS button.": - "لاحظنا أن Intaleq يتجاوز 100 كم/ساعة. يرجى التباطؤ لسلامتك. إذا شعرت بعدم الأمان، يمكنك مشاركة تفاصيل رحلتك مع جهة اتصال أو الاتصال بالشرطة باستخدام زر SOS الأحمر.", - "Warning: Intaleqing detected!": "تحذير: تم اكتشاف Intaleqing!", + "لاحظنا أن السرعة تجاوزت 100 كم/ساعة. الرجاء تخفيف السرعة من أجل سلامتك. إذا شعرت بعدم الأمان، يمكنك مشاركة تفاصيل رحلتك مع جهة اتصال أو الاتصال بالشرطة باستخدام زر الطوارئ الأحمر.", + "Warning: Intaleqing detected!": "تحذير: تم كشف سرعة زائدة!", "Please help! Contact me as soon as possible.": - "من فضلك ساعد! اتصل بي في أقرب وقت ممكن.", + "الرجاء المساعدة! تواصل معي بأسرع وقت ممكن.", "Share Trip Details": "مشاركة تفاصيل الرحلة", - "Car Plate is ": "لوحة السيارة هي ", + "Car Plate is ": "رقم لوحة السيارة: ", "the 300 points equal 300 L.E for you \nSo go and gain your money": - "300 نقطة تساوي 300 جنيه لك\nلذا اذهب واكسب أموالك", - "the 300 points equal 300 L.E": "300 نقطة تساوي 300 جنيه", + "300 نقطة تساوي 300 ليرة لك\nاذهب الآن واكسب أموالك", + "the 300 points equal 300 L.E": "300 نقطة تساوي 300 ليرة", "The payment was not approved. Please try again.": - "لم يتم الموافقة على الدفع. يرجى المحاولة مرة أخرى.", + "لم تتم الموافقة على الدفع. الرجاء المحاولة مرة أخرى.", "Payment Failed": "فشل الدفع", - "Error": "خطأ", "This is a scheduled notification.": "هذا إشعار مجدول.", "An error occurred during the payment process.": "حدث خطأ أثناء عملية الدفع.", "The payment was approved.": "تمت الموافقة على الدفع.", - "Payment Successful": "نجاح الدفع", + "Payment Successful": "تم الدفع بنجاح", "No ride found yet": "لم يتم العثور على رحلة بعد", "Accept Order": "قبول الطلب", - "Bottom Bar Example": "مثال الشريط السفلي", - "Driver phone": "هاتف السائق", + "Bottom Bar Example": "مثال للشريط السفلي", + "Driver phone": "رقم الكابتن", "Statistics": "الإحصائيات", - "Origin": "الأصل", + "Origin": "نقطة الانطلاق", "Destination": "الوجهة", - "Driver Name": "اسم السائق", - "Driver Car Plate": "لوحة سيارة السائق", + "Driver Name": "اسم الكابتن", + "Driver Car Plate": "رقم لوحة سيارة الكابتن", "Available for rides": "متاح للرحلات", "Scan Id": "مسح الهوية", - "Camera not initilaized yet": "لم يتم تهيئة الكاميرا بعد", + "Camera not initilaized yet": "لم يتم تفعيل الكاميرا بعد", "Scan ID MklGoogle": "مسح هوية MklGoogle", "Language": "اللغة", "Jordan": "الأردن", @@ -1191,176 +1249,168 @@ class MyTranslation extends Translations { "Qatar": "قطر", "Bahrain": "البحرين", "Kuwait": "الكويت", - "But you have a negative salary of": "لكن لديك راتب سلبي بقيمة", - "Promo Code": "رمز الترويج", + "But you have a negative salary of": "لكن لديك رصيد سالب بقيمة", + "Promo Code": "رمز العرض", "Your trip distance is": "مسافة رحلتك هي", - "Enter promo code": "أدخل رمز الترويج", - "You have promo!": "لديك عرض ترويجي!", + "Enter promo code": "أدخل رمز العرض", + "You have promo!": "لديك عرض!", "Cost Duration": "تكلفة المدة", "Duration is": "المدة هي", "Leave": "مغادرة", "Join": "انضمام", "Heading your way now. Please be ready.": - "في طريقي إليك الآن. يرجى الاستعداد.", + "أنا في طريقي إليك الآن. يرجى الاستعداد.", "Approaching your area. Should be there in 3 minutes.": - "أقترب من منطقتك. يجب أن أكون هناك في 3 دقائق.", + "أقترب من منطقتك. سأكون هناك خلال 3 دقائق.", "There's heavy traffic here. Can you suggest an alternate pickup point?": - "هناك زحمة مرورية شديدة هنا. هل يمكنك اقتراح نقطة استلام بديلة؟", + "هناك ازدحام مروري شديد. هل يمكنك اقتراح نقطة انطلاق بديلة؟", "This ride is already taken by another driver.": - "هذه الرحلة قد تم أخذها من قبل سائق آخر.", + "هذه الرحلة قد أخذها كابتن آخر.", "You Should be select reason.": "يجب عليك اختيار السبب.", - " \$": " \$", - "Waiting for Driver ...": "في انتظار السائق ...", + "Waiting for Driver ...": "بانتظار الكابتن...", "Latest Recent Trip": "آخر رحلة حديثة", "from your list": "من قائمتك", "Do you want to change Work location": "هل تريد تغيير موقع العمل؟", "Do you want to change Home location": "هل تريد تغيير موقع المنزل؟", "We Are Sorry That we dont have cars in your Location!": - "نحن آسفون لأنه لا توجد سيارات في موقعك!", + "نأسف لعدم توفر سيارات في موقعك!", "Choose from Map": "اختر من الخريطة", "Pick your ride location on the map - Tap to confirm": "اختر موقع رحلتك على الخريطة - اضغط للتأكيد", - "Closest & Cheapest": "الأقرب والأرخص", "Intaleq is the ride-hailing app that is safe, reliable, and accessible.": - "Intaleq هو تطبيق طلب الركوب الآمن والموثوق والمتاح.", + "انطلق هو تطبيق طلب السيارات الآمن، الموثوق، وفي متناول اليد.", "With Intaleq, you can get a ride to your destination in minutes.": - "مع Intaleq، يمكنك الحصول على رحلة إلى وجهتك في دقائق.", + "مع انطلق، يمكنك الوصول إلى وجهتك في دقائق.", "Intaleq is committed to safety, and all of our captains are carefully screened and background checked.": - "Intaleq ملتزم بالسلامة، وجميع كابتناتنا يتم فحصهم بعناية والتحقق من خلفيتهم.", + "تلتزم انطلق بالسلامة، وجميع كباتننا يتم فحصهم بعناية والتحقق من سجلاتهم.", "Pick from map": "اختر من الخريطة", - "No Car in your site. Sorry!": "لا توجد سيارة في موقعك. آسف!", - "Nearest Car for you about ": "أقرب سيارة لك حوالي ", + "No Car in your site. Sorry!": "لا توجد سيارة في موقعك. نعتذر!", + "Nearest Car for you about ": "أقرب سيارة لك على بعد ", "From :": "من:", "Get Details of Trip": "الحصول على تفاصيل الرحلة", - "If you want add stop click here": "إذا كنت تريد إضافة توقف اضغط هنا", - "Where you want go ": "إلى أين تريد الذهاب ", + "If you want add stop click here": + "إذا أردت إضافة نقطة توقف، اضغط هنا", + "Where you want go ": "إلى أين تريد الذهاب؟", "My Card": "بطاقتي", "Start Record": "بدء التسجيل", - "History of Trip": "سجل الرحلة", + "History of Trip": "سجل الرحلات", "Helping Center": "مركز المساعدة", "Record saved": "تم حفظ التسجيل", - "Trips recorded": "رحلات مسجلة", + "Trips recorded": "الرحلات المسجلة", "Select Your Country": "اختر بلدك", "To ensure you receive the most accurate information for your location, please select your country below. This will help tailor the app experience and content to your country.": - "لضمان حصولك على المعلومات الأكثر دقة لموقعك، يرجى اختيار بلدك أدناه. سيساعد هذا في تخصيص تجربة التطبيق والمحتوى لبلدك.", + "لضمان حصولك على أدق المعلومات لموقعك، يرجى اختيار بلدك أدناه. سيساعد هذا في تخصيص تجربة التطبيق ومحتواه لبلدك.", "Are you sure to delete recorded files": "هل أنت متأكد من حذف الملفات المسجلة؟", "Select recorded trip": "اختر رحلة مسجلة", "Card Number": "رقم البطاقة", - "Hi, Where to ": "مرحبًا، إلى أين ", + "Hi, Where to ": "مرحباً، إلى أين؟", "Pick your destination from Map": "اختر وجهتك من الخريطة", - "Add Stops": "إضافة توقفات", - "Get Direction": "الحصول على الاتجاه", + "Add Stops": "إضافة نقاط توقف", + "Get Direction": "الحصول على الاتجاهات", "Add Location": "إضافة موقع", "Switch Rider": "تبديل الراكب", "You will arrive to your destination after timer end.": "ستصل إلى وجهتك بعد انتهاء المؤقت.", "You can cancel trip": "يمكنك إلغاء الرحلة", "The driver waitting you in picked location .": - "السائق في انتظارك في الموقع المحدد.", - "10\$ and get 3% discount": "10\$ واحصل على خصم 3%", - "20\$ and get 4% discount": "20\$ واحصل على خصم 4%", - "40\$ and get 6% discount": "40\$ واحصل على خصم 6%", - "100\$ and get 9% discount": "100\$ واحصل على خصم 9%", - "Pay with Your": "الدفع باستخدام", - "Pay with Credit Card": "الدفع ببطاقة الائتمان", - "Payment History": "سجل الدفع", - "Show Promos to Charge": "عرض العروض الترويجية للشحن", + "الكابتن بانتظارك في موقع الانطلاق.", + "Pay with Your": "ادفع باستخدام", + "Pay with Credit Card": "الدفع بالبطاقة الائتمانية", + "Show Promos to Charge": "عرض العروض للشحن", "Point": "نقطة", - "How many hours would you like to wait?": "كم ساعة تريد الانتظار؟", - "Driver Wallet": "محفظة السائق", - "Choose between those Type Cars": "اختر بين تلك الأنواع من السيارات", + "How many hours would you like to wait?": "كم ساعة تود الانتظار؟", + "Driver Wallet": "محفظة الكابتن", + "Choose between those Type Cars": "اختر بين أنواع السيارات هذه", "hour": "ساعة", "Select Waiting Hours": "اختر ساعات الانتظار", - "Total Points is": "إجمالي النقاط هو", + "Total Points is": "إجمالي النقاط", "You will receive a code in SMS message": - "سوف تتلقى رمزًا في رسالة SMS", + "ستستلم رمزاً في رسالة نصية", "Done": "تم", - "Total Budget from trips is ": "إجمالي الميزانية من الرحلات هو ", + "Total Budget from trips is ": "إجمالي الميزانية من الرحلات: ", "Total Amount:": "المبلغ الإجمالي:", "Total Budget from trips by\nCredit card is ": - "إجمالي الميزانية من الرحلات بواسطة\nبطاقة الائتمان هو ", + "إجمالي الميزانية من الرحلات بالبطاقة الائتمانية: ", "This amount for all trip I get from Passengers": - "هذا المبلغ لجميع الرحلات التي أحصل عليها من الركاب", - "Pay from my budget": "الدفع من ميزانيتي", + "هذا المبلغ هو لكل الرحلات التي أحصل عليها من الركاب", + "Pay from my budget": "ادفع من ميزانيتي", "This amount for all trip I get from Passengers and Collected For me in": - "هذا المبلغ لجميع الرحلات التي أحصل عليها من الركاب والمجمعة لي في", - "You can buy points from your budget": - "يمكنك شراء النقاط من ميزانيتك", - "insert amount": "إدراج المبلغ", + "هذا المبلغ هو لكل الرحلات التي أحصل عليها من الركاب والمجمعة لي في", + "You can buy points from your budget": "يمكنك شراء نقاط من ميزانيتك", + "insert amount": "أدخل المبلغ", "You can buy Points to let you online\nby this list below": - "يمكنك شراء النقاط للسماح لك بالاتصال\nمن خلال هذه القائمة أدناه", - "Create Wallet to receive your money": "إنشاء محفظة لاستلام أموالك", - "Enter your feedback here": "أدخل ملاحظاتك هنا", - "Please enter your feedback.": "الرجاء إدخال ملاحظاتك.", - "Feedback": "ملاحظات", + "يمكنك شراء نقاط لتكون متصلاً\nمن القائمة أدناه", + "Create Wallet to receive your money": "أنشئ محفظة لاستلام أموالك", + "Enter your feedback here": "أدخل تقييمك هنا", + "Please enter your feedback.": "الرجاء إدخال تقييمك.", + "Feedback": "تقييم", "Submit ": "إرسال ", - "Click here to Show it in Map": "انقر هنا لعرضه على الخريطة", + "Click here to Show it in Map": "اضغط هنا لعرضه على الخريطة", "Canceled": "تم الإلغاء", - "Type your Email": "اكتب بريدك الإلكتروني", "No I want": "لا أريد", - "Email is": "البريد الإلكتروني هو", - "Phone Number is": "رقم الهاتف هو", - "Date of Birth is": "تاريخ الميلاد هو", - "Sex is ": "الجنس هو ", + "Email is": "البريد الإلكتروني:", + "Phone Number is": "رقم الهاتف:", + "Date of Birth is": "تاريخ الميلاد:", + "Sex is ": "الجنس: ", "Car Details": "تفاصيل السيارة", - "VIN is": "VIN هو", - "Color is ": "اللون هو ", - "Make is ": "الصنع هو ", - "Model is": "الموديل هو", - "Year is": "السنة هي", - "Expiration Date ": "تاريخ الانتهاء ", + "VIN is": "رقم الهيكل:", + "Color is ": "اللون: ", + "Make is ": "الشركة المصنعة: ", + "Model is": "الموديل:", + "Year is": "السنة:", + "Expiration Date ": "تاريخ الانتهاء: ", "Edit Your data": "تعديل بياناتك", - "write vin for your car": "اكتب VIN لسيارتك", - "VIN": "VIN", + "write vin for your car": "اكتب رقم هيكل سيارتك", + "VIN": "رقم الهيكل", "write Color for your car": "اكتب لون سيارتك", - "write Make for your car": "اكتب صنع سيارتك", + "write Make for your car": "اكتب الشركة المصنعة لسيارتك", "write Model for your car": "اكتب موديل سيارتك", - "write Year for your car": "اكتب سنة سيارتك", + "write Year for your car": "اكتب سنة صنع سيارتك", "write Expiration Date for your car": "اكتب تاريخ انتهاء صلاحية سيارتك", - "Tariffs": "التعريفات", + "Tariffs": "التعرفات", "Minimum fare": "الحد الأدنى للأجرة", "Maximum fare": "الحد الأقصى للأجرة", - "Flag-down fee": "رسوم العلم", - "Including Tax": "بما في ذلك الضريبة", + "Flag-down fee": "رسوم بدء الرحلة", + "Including Tax": "شامل الضريبة", "BookingFee": "رسوم الحجز", - "Morning": "الصباح", + "Morning": "صباحاً", "from 07:30 till 10:30 (Thursday, Friday, Saturday, Monday)": - "من 07:30 حتى 10:30 (الخميس، الجمعة، السبت، الاثنين)", - "Evening": "المساء", + "من 7:30 صباحاً حتى 10:30 صباحاً (الخميس، الجمعة، السبت، الاثنين)", + "Evening": "مساءً", "from 12:00 till 15:00 (Thursday, Friday, Saturday, Monday)": - "من 12:00 حتى 15:00 (الخميس، الجمعة، السبت، الاثنين)", - "Night": "الليل", + "من 12:00 ظهراً حتى 3:00 عصراً (الخميس، الجمعة، السبت، الاثنين)", + "Night": "ليلاً", "You have in account": "لديك في الحساب", "Select Country": "اختر البلد", - "Ride Today : ": "الرحلة اليوم: ", + "Ride Today : ": "رحلة اليوم: ", "After this period\nYou can't cancel!": "بعد هذه الفترة\nلا يمكنك الإلغاء!", - "from 23:59 till 05:30": "من 23:59 حتى 05:30", - "Rate Driver": "تقييم السائق", - "Total Cost is ": "التكلفة الإجمالية هي ", + "from 23:59 till 05:30": "من 11:59 مساءً حتى 5:30 صباحاً", + "Rate Driver": "تقييم الكابتن", + "Total Cost is ": "التكلفة الإجمالية: ", "Write note": "اكتب ملاحظة", "Time to arrive": "وقت الوصول", "Ride Summaries": "ملخصات الرحلات", "Total Cost": "التكلفة الإجمالية", "Average of Hours of": "متوسط ساعات", - " is ON for this month": "يعمل هذا الشهر", + " is ON for this month": " متصل لهذا الشهر", "Days": "أيام", "Total Hours on month": "إجمالي الساعات في الشهر", - "Counts of Hours on days": "عدد ساعات الأيام", - "OrderId": "معرف الطلب", + "Counts of Hours on days": "عدد الساعات في الأيام", + "OrderId": "رقم الطلب", "created time": "وقت الإنشاء", - "Intaleq Over": "انتهت Intaleq", - "I will slow down": "سوف أبطئ", + "Intaleq Over": "انتهت رحلة انطلق", + "I will slow down": "سأخفف السرعة", "Map Passenger": "خريطة الراكب", - "Be Slowly": "كن بطيئًا", + "Be Slowly": "تمهل", "If you want to make Google Map App run directly when you apply order": - "إذا كنت تريد تشغيل تطبيق خرائط Google مباشرة عند تقديم الطلب", + "إذا أردت تشغيل خرائط جوجل مباشرة عند قبول الطلب", "You can change the language of the app": "يمكنك تغيير لغة التطبيق", - "Your Budget less than needed": "ميزانيتك أقل من المطلوب", + "Your Budget less than needed": "رصيدك أقل من المطلوب", "You can change the Country to get all features": - "يمكنك تغيير البلد للحصول على جميع الميزات", + "يمكنك تغيير البلد للحصول على كل الميزات", "Change Country": "تغيير البلد" }, "ar-main": { @@ -1569,9 +1619,25 @@ class MyTranslation extends Translations { "Phone Wallet Saved Successfully": "تم حفظ محفظة الهاتف بنجاح", "Add wallet phone you use": "ضيف رقم محفظة هاتفك اللي بتستخدمها", "Update Available": "تحديث متاح", + 'Intaleq Balance': "رصيد Intaleq", + 'Van for familly': "فان للعائلات", + "Electric": "سيارة كهربائية", + "Van": "فان للعائلات", + "Closest & Cheapest": "الأقرب والأرخص", + "Comfort choice": "خيار الراحة", + "Lady Captain for girls": "سائقة خاصة للسيدات", + "Best choice for cities": "أفضل خيار بين المدن", + "Quiet & Eco-Friendly": "هادئة وصديقة للبيئة", + "Travel in a modern, silent electric car. A premium, eco-friendly choice for a smooth ride.": + "سافر في سيارة كهربائية حديثة وهادئة. خيار مميز وصديق للبيئة لرحلة مريحة وسلسة.", + "Spacious van service ideal for families and groups. Comfortable, safe, and cost-effective travel together.": + "خدمة فان واسعة مثالية للعائلات والمجموعات. رحلة مريحة وآمنة واقتصادية للتنقل معًا.", "Phone number must be exactly 11 digits long": "رقم التليفون لازم يكون 11 رقم بالظبط", - "Insert Wallet phone number": "أدخل رقم محفظة هاتفك", + 'Set Phone Number': "تعيين رقم الهاتف", + 'Top up Balance to continue': "اشحن الرصيد للمتابعة", + "Insert Wallet phone number": "أدخل رقم محفظة الهاتف", + 'Set Wallet Phone Number': 'تعيين رقم الهاتف', "Phone number isn't an Egyptian phone number": "رقم التليفون ده مش رقم مصري", "A new version of the app is available. Please update to the latest version.": @@ -2532,7 +2598,7 @@ class MyTranslation extends Translations { "This ride is already taken by another driver.": "المشوار ده أخده سواق تاني خلاص.", "You Should be select reason.": "يجب أن تختار سبب.", - " \$": " دينار ", + "Waiting for Driver ...": "في انتظار السواق...", "Latest Recent Trip": "آخر مشوار عملته", "from your list": "من قائمتك", @@ -2592,10 +2658,7 @@ class MyTranslation extends Translations { "You can cancel trip": "تقدر تلغي الرحلة", "The driver waitting you in picked location .": "السواق منتظرك في المكان اللي اخترته.", - "10\$ and get 3% discount": "10 دينار واحصل على خصم 3%", - "20\$ and get 4% discount": "20 دينار واحصل على خصم 4%", - "40\$ and get 6% discount": "40 دينار واحصل على خصم 6%", - "100\$ and get 9% discount": "100 دولار واحصل على خصم 9%", + "Pay with Your": "ادفع بـ", "Pay with Credit Card": "ادفع ببطاقة الائتمان", "Payment History": "سجل المدفوعات", @@ -3826,7 +3889,7 @@ class MyTranslation extends Translations { "This ride is already taken by another driver.": "Bu yolculuk başka bir sürücü tarafından alındı.", "You Should be select reason.": "Bir sebep seçmelisiniz.", - " \$": " \$", + "Waiting for Driver ...": "Sürücü Bekleniyor ...", "Latest Recent Trip": "En Son Yolculuk", "from your list": "listenizden", @@ -3889,10 +3952,6 @@ class MyTranslation extends Translations { "You can cancel trip": "Yolculuğu iptal edebilirsiniz", "The driver waitting you in picked location .": "Sürücü sizi seçilen yerde bekliyor.", - "10\$ and get 3% discount": "10\$ ve %3 indirim", - "20\$ and get 4% discount": "20\$ ve %4 indirim", - "40\$ and get 6% discount": "40\$ ve %6 indirim", - "100\$ and get 9% discount": "100\$ ve %9 indirim", "Pay with Your": "Ödeme Yönteminiz", "Pay with Credit Card": "Kredi Kartı ile Öde", "Payment History": "Ödeme Geçmişi", @@ -17020,7 +17079,7 @@ class MyTranslation extends Translations { "Call Page": "صفحة الاتصال", // "Call End": "انتهاء المكالمة", "Call Left": "مكالمات متبقية", - r"$ Next as Cash $!": " بعدين كاش \$!", + "To use Wallet charge it": "عشان تستخدم المحفظة اشحنها", "We are searching for the nearest driver to you": "بندور لك على أقرب سواق ليك", @@ -17867,7 +17926,7 @@ class MyTranslation extends Translations { "This ride is already taken by another driver.": "المشوار هذا أخذه سواق ثاني خلاص.", "You Should be select reason.": "يجب أن تختار سبب.", - " \$": " دينار ", + "Waiting for Driver ...": "في انتظار السواق...", "Latest Recent Trip": "آخر مشوار سويته", "from your list": "من قائمتك", @@ -17927,10 +17986,7 @@ class MyTranslation extends Translations { "You can cancel trip": "تقدر تلغي الرحلة", "The driver waitting you in picked location .": "السواق ينتظرك في المكان اللي اخترته.", - "10\$ and get 3% discount": "10 دولار واحصل على خصم 3%", - "20\$ and get 4% discount": "20 دولار واحصل على خصم 4%", - "40\$ and get 6% discount": "40 دولار واحصل على خصم 6%", - "100\$ and get 9% discount": "100 دولار واحصل على خصم 9%", + "Pay with Your": "ادفع بـ", "Pay with Credit Card": "ادفع ببطاقة الائتمان", "Payment History": "سجل المدفوعات", @@ -18338,7 +18394,7 @@ class MyTranslation extends Translations { "Call Page": "صفحة الاتصال", // "Call End": "نهاية المكالمة", "Call Left": "مكالمات باقية", - r"$ Next as Cash $!": " من بعد كاش \$!", + "To use Wallet charge it": "باش تستعمل الجيب شحنو", "We are searching for the nearest driver to you": "كنقلبوا ليك على أقرب سائق ليك", @@ -19196,7 +19252,7 @@ class MyTranslation extends Translations { "This ride is already taken by another driver.": "المشوار هذا خداه سائق آخر خلاص.", "You Should be select reason.": "خاصك تختار سبب.", - " \$": " دينار ", + "Waiting for Driver ...": "كنتسناو السائق...", "Latest Recent Trip": "آخر مشوار درت", "from your list": "من اللائحة ديالك", @@ -19257,10 +19313,7 @@ class MyTranslation extends Translations { "You can cancel trip": "تقدر تلغي الرحلة", "The driver waitting you in picked location .": "السائق كيتسناك في المكان اللي اختاريتي.", - "10\$ and get 3% discount": "10 دولار وربح خصم 3%", - "20\$ and get 4% discount": "20 دولار وربح خصم 4%", - "40\$ and get 6% discount": "40 دولار وربح خصم 6%", - "100\$ and get 9% discount": "100 دولار وربح خصم 9%", + "Pay with Your": "خلص بـ", "Pay with Credit Card": "خلص ببطاقة الائتمان", "Payment History": "سجل المدفوعات", diff --git a/lib/views/auth/login_page.dart b/lib/views/auth/login_page.dart index 2aaec75..2cc5e07 100644 --- a/lib/views/auth/login_page.dart +++ b/lib/views/auth/login_page.dart @@ -8,6 +8,8 @@ import 'package:Intaleq/constant/colors.dart'; import 'package:Intaleq/constant/style.dart'; import 'package:Intaleq/main.dart'; import 'package:Intaleq/views/widgets/my_scafold.dart'; +import 'package:path/path.dart'; +import 'package:url_launcher/url_launcher.dart'; import '../../constant/info.dart'; import '../../controller/auth/apple_signin_controller.dart'; @@ -73,7 +75,11 @@ class LoginPage extends StatelessWidget { decoration: TextDecoration.underline, color: AppColor.blueColor, fontWeight: FontWeight.bold), - recognizer: TapGestureRecognizer()..onTap = () {}), + recognizer: TapGestureRecognizer() + ..onTap = () { + launchUrl(Uri.parse( + 'https://intaleq.xyz/intaleq/privacy_policy.php')); + }), TextSpan(text: " and acknowledge our Privacy Policy.".tr), ], ), @@ -88,7 +94,7 @@ class LoginPage extends StatelessWidget { padding: const EdgeInsets.all(12), child: HtmlWidget(box.read(BoxName.lang).toString() == 'ar' ? AppInformation.privacyPolicyArabic - : AppInformation.privacyPolicyEnglish), + : AppInformation.privacyPolicy), ), ), ), diff --git a/lib/views/auth/otp_page.dart b/lib/views/auth/otp_page.dart index 08a64c3..b76f1d6 100644 --- a/lib/views/auth/otp_page.dart +++ b/lib/views/auth/otp_page.dart @@ -43,6 +43,12 @@ class AuthScreen extends StatelessWidget { children: [ Image.asset('assets/images/logo.gif', height: 120), const SizedBox(height: 20), + // IconButton( + // onPressed: () { + // Get.find().getJWT(); + // }, + // icon: const Icon(Icons.add), + // ), Text( title, style: const TextStyle( diff --git a/lib/views/home/HomePage/about_page.dart b/lib/views/home/HomePage/about_page.dart index dde7d4c..c4fad0b 100644 --- a/lib/views/home/HomePage/about_page.dart +++ b/lib/views/home/HomePage/about_page.dart @@ -28,13 +28,13 @@ class AboutPage extends StatelessWidget { // Company Name and Introduction Text( - 'Tripz LLC', + 'Intaleq LLC', style: CupertinoTheme.of(context).textTheme.navTitleTextStyle, textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( - 'Egypt\'s pioneering ride-sharing service, proudly developed by Arabian and local owners. We prioritize being near you – both our valued passengers and our dedicated captains.' + "Syria's pioneering ride-sharing service, proudly developed by Arabian and local owners. We prioritize being near you – both our valued passengers and our dedicated captains." .tr, style: CupertinoTheme.of(context).textTheme.textStyle, textAlign: TextAlign.center, @@ -43,7 +43,7 @@ class AboutPage extends StatelessWidget { // Key Features Section Text( - 'Why Choose Tripz?'.tr, + 'Why Choose Intaleq?'.tr, style: CupertinoTheme.of(context).textTheme.navTitleTextStyle, textAlign: TextAlign.center, ), diff --git a/lib/views/home/HomePage/share_app_page.dart b/lib/views/home/HomePage/share_app_page.dart index bd85525..cd88458 100644 --- a/lib/views/home/HomePage/share_app_page.dart +++ b/lib/views/home/HomePage/share_app_page.dart @@ -432,8 +432,7 @@ class ShareAppPage extends StatelessWidget { ), ), Text( - controller.formatPhoneNumber( - contact['phones'][0].toString()), + (contact['phones'][0].toString()), style: const TextStyle( color: CupertinoColors.secondaryLabel, fontSize: 15, diff --git a/lib/views/home/HomePage/trip_record_page.dart b/lib/views/home/HomePage/trip_record_page.dart index 0dd09f8..3f965fe 100644 --- a/lib/views/home/HomePage/trip_record_page.dart +++ b/lib/views/home/HomePage/trip_record_page.dart @@ -1,5 +1,3 @@ -import 'package:Intaleq/views/widgets/my_scafold.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:path/path.dart' as path; @@ -8,205 +6,258 @@ import 'package:share_plus/share_plus.dart'; import '../../../controller/functions/audio_record1.dart'; class TripsRecordedPage extends StatelessWidget { - const TripsRecordedPage({ - super.key, - }); + const TripsRecordedPage({super.key}); @override Widget build(BuildContext context) { - return MyScafolld( - title: 'Trips recorded'.tr, - body: [ - GetBuilder(builder: (audio) { - return SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - FutureBuilder>( - future: audio.getRecordedFiles(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center( - child: CupertinoActivityIndicator()); - } else if (snapshot.hasData) { - final recordedFiles = snapshot.data!; - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: () async { - String? selectedFile = - await showCupertinoModalPopup( - context: context, - builder: (BuildContext context) { - return CupertinoActionSheet( - title: Text('Select a File'.tr), - actions: recordedFiles - .map( - (file) => CupertinoActionSheetAction( - child: Text(path.basename(file)), - onPressed: () { - Navigator.of(context).pop(file); - }, - ), - ) - .toList(), - ); - }, - ); - if (selectedFile != null) { - audio.selectedFilePath = selectedFile; - audio.playRecordedFile(selectedFile); - audio.update(); - } - }, - child: Text( - audio.selectedFilePath != null - ? path.basename(audio.selectedFilePath!) - : 'Select a File'.tr, - style: CupertinoTheme.of(context) - .textTheme - .actionTextStyle - .copyWith(color: CupertinoColors.activeBlue), - ), - ), - ); - } else { - return Padding( - padding: const EdgeInsets.all(16.0), - child: Text('Error: ${snapshot.error}'), - ); - } - }, - ), + // Ensure the controller is available. + // If it's not initialized elsewhere, you can use Get.put() or Get.lazyPut() here. + // Get.lazyPut(() => AudioRecorderController()); - // Cupertino-style slider for seeking audio - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: CupertinoSlider( - value: audio.totalDuration > 0 - ? audio.currentPosition / audio.totalDuration - : 0.0, // Normalize to a value between 0.0 and 1.0 - min: 0.0, - max: 1.0, // Maximum value is now 1.0 - activeColor: CupertinoColors.activeBlue, - onChanged: (value) { - final newPosition = value * audio.totalDuration; - audio.currentPosition = newPosition; - audio.audioPlayer - .seek(Duration(seconds: newPosition.toInt())); - audio.update(); - }, - ), - ), + return Scaffold( + appBar: AppBar( + title: Text('Trips recorded'.tr), + backgroundColor: Colors.white, + elevation: 1, + actions: [ + GetBuilder( + builder: (controller) => IconButton( + tooltip: 'Delete All'.tr, + icon: const Icon(Icons.delete_sweep_outlined), + onPressed: () { + _showDeleteConfirmation(context, controller, isDeleteAll: true); + }, + ), + ) + ], + ), + body: GetBuilder( + builder: (controller) { + return Column( + children: [ + Expanded( + child: _buildRecordingsList(controller), + ), + // Show player controls only when a file is selected + if (controller.selectedFilePath != null) + _buildPlayerControls(context, controller), + ], + ); + }, + ), + ); + } - // iOS-style playback controls - Padding( - padding: const EdgeInsets.symmetric( - vertical: 16.0, horizontal: 16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: Icon( - audio.isPlaying - ? CupertinoIcons.pause - : CupertinoIcons.play_arrow, - color: CupertinoColors.activeBlue, - ), - onPressed: () { - if (audio.isPlaying) { - audio.pausePlayback(); - } else { - audio.resumePlayback(); - } - audio.update(); - }, - ), - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon(CupertinoIcons.stop, - color: CupertinoColors.destructiveRed), - onPressed: () { - audio.stopPlayback(); - audio.update(); - }, - ), - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon(CupertinoIcons.delete, - color: CupertinoColors.destructiveRed), - onPressed: () async { - showCupertinoModalPopup( - context: context, - builder: (BuildContext context) { - return CupertinoActionSheet( - title: Text('Are you sure?'.tr), - message: Text( - 'This will delete all recorded files from your device.' - .tr, - textAlign: TextAlign.center, - ), - actions: [ - CupertinoActionSheetAction( - isDestructiveAction: true, - onPressed: () async { - await audio.deleteAllRecordedFiles(); - Navigator.pop(context); - audio.update(); - }, - child: Text('Delete'.tr), - ), - ], - cancelButton: CupertinoActionSheetAction( - onPressed: () { - Navigator.pop(context); - }, - child: Text('Cancel'.tr), - ), - ); - }, - ); - }, - ), - ], - ), + /// Builds the list of recorded audio files. + Widget _buildRecordingsList(AudioRecorderController controller) { + return FutureBuilder>( + future: controller.getRecordedFiles(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } + if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}'.tr)); + } + if (!snapshot.hasData || snapshot.data!.isEmpty) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.mic_off_outlined, size: 80, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + 'No Recordings Found'.tr, + style: TextStyle(fontSize: 18, color: Colors.grey[600]), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 40.0), + child: Text( + 'Record your trips to see them here.'.tr, + textAlign: TextAlign.center, + style: TextStyle(color: Colors.grey[500]), ), + ), + ], + ), + ); + } - // File selection and sharing - if (audio.selectedFilePath != null) - Align( - alignment: Alignment.bottomCenter, - child: Container( - padding: const EdgeInsets.all(16.0), - color: CupertinoColors.systemGrey6, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Selected file: ${path.basename(audio.selectedFilePath!)}', - style: CupertinoTheme.of(context) - .textTheme - .textStyle, - ), - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon(CupertinoIcons.share), - onPressed: () { - Share.shareXFiles( - [XFile(audio.selectedFilePath!)]); - }, - ), - ], - ), - ), - ), - ], + final recordedFiles = snapshot.data!; + return ListView.builder( + padding: const EdgeInsets.only(top: 8, bottom: 8), + itemCount: recordedFiles.length, + itemBuilder: (context, index) { + final file = recordedFiles[index]; + final fileName = path.basename(file); + final isSelected = controller.selectedFilePath == file; + + return Card( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), + elevation: isSelected ? 4 : 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + child: ListTile( + leading: Icon( + isSelected && controller.isPlaying + ? Icons.pause_circle_filled + : Icons.play_circle_fill, + color: + isSelected ? Theme.of(context).primaryColor : Colors.grey, + size: 40, + ), + title: Text(fileName, + style: const TextStyle(fontWeight: FontWeight.w500)), + subtitle: Text("Audio Recording".tr), + onTap: () { + if (isSelected) { + controller.isPlaying + ? controller.pausePlayback() + : controller.resumePlayback(); + } else { + controller.playRecordedFile(file); + } + }, + selected: isSelected, + selectedTileColor: + Theme.of(context).primaryColor.withOpacity(0.1), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), ), ); - }) - ], - isleading: true); + }, + ); + }, + ); + } + + /// Builds the player UI at the bottom of the screen. + Widget _buildPlayerControls( + BuildContext context, AudioRecorderController controller) { + final fileName = path.basename(controller.selectedFilePath!); + final positionText = Duration(seconds: controller.currentPosition.toInt()) + .toString() + .split('.') + .first + .padLeft(8, '0') + .substring(3); + final durationText = Duration(seconds: controller.totalDuration.toInt()) + .toString() + .split('.') + .first + .padLeft(8, '0') + .substring(3); + + return Material( + elevation: 10, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(fileName, + style: + const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + textAlign: TextAlign.center), + const SizedBox(height: 8), + Row( + children: [ + Text(positionText), + Expanded( + child: Slider( + value: (controller.totalDuration > 0) + ? controller.currentPosition / controller.totalDuration + : 0.0, + onChanged: (value) { + final newPosition = value * controller.totalDuration; + controller.audioPlayer + .seek(Duration(seconds: newPosition.toInt())); + }, + ), + ), + Text(durationText), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + icon: const Icon(Icons.share_outlined), + tooltip: 'Share'.tr, + onPressed: () { + Share.shareXFiles([XFile(controller.selectedFilePath!)]); + }, + iconSize: 28, + ), + IconButton( + icon: Icon(controller.isPlaying + ? Icons.pause_circle_filled + : Icons.play_circle_filled), + onPressed: () { + controller.isPlaying + ? controller.pausePlayback() + : controller.resumePlayback(); + }, + iconSize: 56, + color: Theme.of(context).primaryColor, + ), + IconButton( + icon: + const Icon(Icons.delete_outline, color: Colors.redAccent), + tooltip: 'Delete'.tr, + onPressed: () { + _showDeleteConfirmation(context, controller, + isDeleteAll: false); + }, + iconSize: 28, + ), + ], + ) + ], + ), + ), + ); + } + + /// Shows a confirmation dialog for deleting one or all files. + void _showDeleteConfirmation( + BuildContext context, + AudioRecorderController controller, { + required bool isDeleteAll, + }) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text(isDeleteAll + ? 'Delete All Recordings?'.tr + : 'Delete Recording?'.tr), + content: Text(isDeleteAll + ? 'This action cannot be undone.'.tr + : 'Are you sure you want to delete this file?'.tr), + actions: [ + TextButton( + child: Text('Cancel'.tr), + onPressed: () => Navigator.of(context).pop(), + ), + TextButton( + child: + Text('Delete'.tr, style: const TextStyle(color: Colors.red)), + onPressed: () async { + if (isDeleteAll) { + await controller.deleteAllRecordedFiles(); + } else { + // NOTE: You may need to add this method to your controller + // if it doesn't exist. + // await controller.deleteFile(controller.selectedFilePath!); + } + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); } } diff --git a/lib/views/home/map_page_passenger.dart b/lib/views/home/map_page_passenger.dart index b201197..fcc6f05 100644 --- a/lib/views/home/map_page_passenger.dart +++ b/lib/views/home/map_page_passenger.dart @@ -71,7 +71,7 @@ class MapPagePassenger extends StatelessWidget { const RideFromStartApp(), // cancelRidePage(), - const MenuIconMapPageWidget(), + // const MenuIconMapPageWidget(), PointsPageForRider() ], ), 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 86ef193..e757e66 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 @@ -40,15 +40,19 @@ List carTypes = [ carType: 'Electric', carDetail: 'Quiet & Eco-Friendly'.tr, image: - 'assets/images/electric_car.jpg'), // Third choice - NOTE: Use your actual image path + 'assets/images/electric.png'), // Third choice - NOTE: Use your actual image path CarType( carType: 'Lady', carDetail: 'Lady Captain for girls'.tr, image: 'assets/images/lady.png'), CarType( - carType: 'Scooter', - carDetail: 'Delivery service'.tr, - image: 'assets/images/moto.png'), + carType: 'Van', + carDetail: 'Van for familly'.tr, + image: 'assets/images/bus.png'), + // CarType( + // carType: 'Scooter', + // carDetail: 'Delivery service'.tr, + // image: 'assets/images/moto.png'), CarType( carType: 'Rayeh Gai', carDetail: "Best choice for cities".tr, @@ -365,6 +369,8 @@ class CarDetailsTypeToChoose extends StatelessWidget { return mapPassengerController.totalPassengerBalash.toStringAsFixed(1); case 'Scooter': return mapPassengerController.totalPassengerScooter.toStringAsFixed(1); + case 'Van': + return mapPassengerController.totalPassengerVan.toStringAsFixed(1); case 'Lady': return mapPassengerController.totalPassengerLady.toStringAsFixed(1); case 'Pink Bike': @@ -476,6 +482,9 @@ class CarDetailsTypeToChoose extends StatelessWidget { return 'Travel in a modern, silent electric car. A premium, eco-friendly choice for a smooth ride.' .tr; case 'Scooter': + case 'Van': + return "Spacious van service ideal for families and groups. Comfortable, safe, and cost-effective travel together." + .tr; case 'Pink Bike': return 'This is for delivery or a motorcycle.'.tr; case 'Mishwar Vip': @@ -556,6 +565,8 @@ class CarDetailsTypeToChoose extends StatelessWidget { return mapPassengerController.totalPassengerElectric; case 'Awfar Car': return mapPassengerController.totalPassengerBalash; + case 'Van': + return mapPassengerController.totalPassengerVan; case 'Lady': return mapPassengerController.totalPassengerLady; default: 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 c8faf53..3575fda 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 @@ -78,7 +78,7 @@ class CashConfirmPageShown extends StatelessWidget { // بطاقة المحفظة _buildPaymentOptionCard( icon: Icons.account_balance_wallet_outlined, - title: '${AppInformation.appName} Wallet'.tr, + title: '${AppInformation.appName} Balance'.tr, subtitle: '${'Balance:'.tr} ${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${'SYP'.tr}', isSelected: paymentCtrl.isWalletChecked, @@ -115,7 +115,7 @@ class CashConfirmPageShown extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ MyElevatedButton( - title: 'Top up Wallet to continue'.tr, + title: 'Top up Balance to continue'.tr, onPressed: () => Get.to(() => const PassengerWallet()), kolor: AppColor.redColor, 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 3fec334..52e93a5 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 @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; @@ -6,15 +8,15 @@ import 'package:Intaleq/controller/home/points_for_rider_controller.dart'; import '../../../constant/colors.dart'; import '../../../constant/style.dart'; import '../../../controller/functions/location_controller.dart'; +import '../../../controller/home/device_tier.dart'; import '../../../controller/home/map_passenger_controller.dart'; import '../../widgets/mycircular.dart'; import '../../widgets/mydialoug.dart'; class GoogleMapPassengerWidget extends StatelessWidget { - GoogleMapPassengerWidget({ - super.key, - }); - WayPointController wayPointController = Get.put(WayPointController()); + GoogleMapPassengerWidget({super.key}); + + final WayPointController wayPointController = Get.put(WayPointController()); final LocationController locationController = Get.find(); @override @@ -30,19 +32,25 @@ class GoogleMapPassengerWidget extends StatelessWidget { child: GoogleMap( onMapCreated: controller.onMapCreated, + // ✅ حدود الكاميرا كما هي cameraTargetBounds: CameraTargetBounds(controller.boundsdata), - minMaxZoomPreference: const MinMaxZoomPreference(6, 18), + + // ✅ Zoom أهدأ للأجهزة الضعيفة + minMaxZoomPreference: controller.lowPerf + ? const MinMaxZoomPreference(6, 17) + : const MinMaxZoomPreference(6, 18), + onLongPress: (argument) { MyDialog().getDialog('Are you want to go to this site'.tr, '', () async { controller.clearPolyline(); if (controller.dataCarsLocationByPassenger != null) { await controller.getDirectionMap( - '${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}', - '${argument.latitude.toString()},${argument.longitude.toString()}'); - + '${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}', + '${argument.latitude},${argument.longitude}', + ); Get.back(); - controller.bottomSheet(); + await controller.bottomSheet(); controller.showBottomSheet1(); } else { Get.back(); @@ -54,15 +62,12 @@ class GoogleMapPassengerWidget extends StatelessWidget { duration: const Duration(seconds: 11), instantInit: true, snackPosition: SnackPosition.TOP, - titleText: Text( - 'Error'.tr, - style: const TextStyle(color: AppColor.redColor), - ), + titleText: Text('Error'.tr, + style: const TextStyle(color: AppColor.redColor)), messageText: Text( - 'We Are Sorry That we dont have cars in your Location!' - .tr, - style: AppStyle.title, - ), + 'We Are Sorry That we dont have cars in your Location!' + .tr, + style: AppStyle.title), icon: const Icon(Icons.error), shouldIconPulse: true, maxWidth: double.infinity, @@ -86,370 +91,98 @@ class GoogleMapPassengerWidget extends StatelessWidget { begin: Alignment.topLeft, end: Alignment.bottomRight, ), - // mainButton: TextButton( - // onPressed: () { - // controller.getCarsLocationByPassenger(); - // }, - // child: Text( - // 'Try Again'.tr, - // style: const TextStyle( - // color: AppColor.secondaryColor), - // ), - // ), - onTap: (GetSnackBar snackBar) { - // Do something when the snackbar is tapped. - }, isDismissible: true, showProgressIndicator: false, dismissDirection: DismissDirection.up, - progressIndicatorController: null, - progressIndicatorBackgroundColor: Colors.transparent, - progressIndicatorValueColor: null, snackStyle: SnackStyle.GROUNDED, forwardAnimationCurve: Curves.easeInToLinear, reverseAnimationCurve: Curves.easeInOut, animationDuration: const Duration(milliseconds: 4000), barBlur: 8, - overlayBlur: 0, - snackbarStatus: null, overlayColor: AppColor.primaryColor.withOpacity(0.5), - userInputForm: null, ); } - - // }); - // Get.defaultDialog( - // title: 'Are you want to go to this site'.tr, - // content: Column( - // children: [ - // Text('${argument.latitude},${argument.longitude}'), - // ], - // ), - // confirm: MyElevatedButton( - // title: 'Ok'.tr, - // onPressed: () async { - // controller.clearPolyline(); - // if (controller.dataCarsLocationByPassenger != null) { - // await controller.getMap( - // '${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}', - // '${argument.latitude.toString()},${argument.longitude.toString()}'); - - // Get.back(); - // controller.bottomSheet(); - // controller.showBottomSheet1(); - // } else { - // Get.back(); - // Get.snackbar( - // 'We Are Sorry That we dont have cars in your Location!' - // .tr, - // '', - // colorText: AppColor.redColor, - // duration: const Duration(seconds: 11), - // instantInit: true, - // snackPosition: SnackPosition.TOP, - // titleText: Text( - // 'Error'.tr, - // style: - // const TextStyle(color: AppColor.redColor), - // ), - // messageText: Text( - // 'We Are Sorry That we dont have cars in your Location!' - // .tr, - // style: AppStyle.title, - // ), - // icon: const Icon(Icons.error), - // shouldIconPulse: true, - // maxWidth: double.infinity, - // margin: const EdgeInsets.all(16), - // padding: const EdgeInsets.all(16), - // borderRadius: 8, - // borderColor: AppColor.redColor, - // borderWidth: 2, - // backgroundColor: AppColor.secondaryColor, - // leftBarIndicatorColor: AppColor.redColor, - // boxShadows: [ - // BoxShadow( - // color: Colors.black.withOpacity(0.25), - // blurRadius: 4, - // spreadRadius: 2, - // offset: const Offset(0, 4), - // ), - // ], - // backgroundGradient: const LinearGradient( - // colors: [ - // AppColor.redColor, - // AppColor.accentColor - // ], - // begin: Alignment.topLeft, - // end: Alignment.bottomRight, - // ), - // // mainButton: TextButton( - // // onPressed: () { - // // controller.getCarsLocationByPassenger(); - // // }, - // // child: Text( - // // 'Try Again'.tr, - // // style: const TextStyle( - // // color: AppColor.secondaryColor), - // // ), - // // ), - // onTap: (GetSnackBar snackBar) { - // // Do something when the snackbar is tapped. - // }, - // isDismissible: true, - // showProgressIndicator: false, - // dismissDirection: DismissDirection.up, - // progressIndicatorController: null, - // progressIndicatorBackgroundColor: - // Colors.transparent, - // progressIndicatorValueColor: null, - // snackStyle: SnackStyle.GROUNDED, - // forwardAnimationCurve: Curves.easeInToLinear, - // reverseAnimationCurve: Curves.easeInOut, - // animationDuration: - // const Duration(milliseconds: 4000), - // barBlur: 8, - // overlayBlur: 0, - // snackbarStatus: null, - // overlayColor: - // AppColor.primaryColor.withOpacity(0.5), - // userInputForm: null, - // ); - // } - - // // - // }), - // ); }, onTap: (argument) { controller.hidePlaces(); - - // controller.changeBottomSheetShown(); - // controller.bottomSheet(); }, + initialCameraPosition: CameraPosition( target: controller.passengerLocation, - zoom: 15, + zoom: controller.lowPerf ? 14.5 : 15, ), + // ✅ ماركرز (احرص أن الأيقونات محجّمة ومخزّنة Cache في الكنترولر) markers: controller.markers.toSet(), - // { - // if (controller.statusRide != 'Apply' || - // !controller.rideTimerBegin) - // for (var carLocation in controller.carLocationsModels) - // // Marker( - // // // anchor: const Offset(4, 4), - // // position: LatLng( - // // carLocation.latitude, - // // carLocation.longitude, - // // ), - // // icon: controller.carIcon, - // // markerId: MarkerId(carLocation.toString()), - // // rotation: carLocation.heading, - // // ), - // // controller.carMarrkerAplied, - // if (controller.statusRide == 'Apply') - // // for (var carLocation - // // in controller.driverCarsLocationToPassengerAfterApplied) - // Marker( - // // anchor: const Offset(4, 4), - // position: LatLng( - // double.parse( - // controller - // .datadriverCarsLocationToPassengerAfterApplied[ - // 'message'][0]['latitude'], - // ), - // double.parse( - // controller - // .datadriverCarsLocationToPassengerAfterApplied[ - // 'message'][0]['longitude'], - // ), - // ), //carLocation, - // icon: controller.carIcon, - // rotation: double.parse(controller - // .datadriverCarsLocationToPassengerAfterApplied[ - // 'message'][0]['heading']), - // markerId: MarkerId(controller - // .datadriverCarsLocationToPassengerAfterApplied[ - // 'message'][0]['longitude'] - // .toString())), - // for (int i = 1; - // i < controller.coordinatesWithoutEmpty.length - 1; - // i++) - // Marker( - // // anchor: const Offset(4, 4), - // position: LatLng( - // double.parse(controller.coordinatesWithoutEmpty[i] - // .split(',')[0]), - // double.parse(controller.coordinatesWithoutEmpty[i] - // .split(',')[1])), - // icon: controller.tripIcon, - // markerId: MarkerId( - // controller.coordinatesWithoutEmpty[i].toString())), - // if (controller.isMarkersShown) - // Marker( - // markerId: MarkerId('MyLocation'.tr), - // position: controller.newStartPointLocation, - // draggable: true, - // icon: controller.startIcon, - // ), - // if (controller.isMarkersShown) - // Marker( - // markerId: MarkerId('Destination'.tr), - // position: controller.myDestination, - // draggable: true, - // icon: controller.endIcon, - // ), - // if (controller.haveSteps) - // Marker( - // markerId: MarkerId('StartSteps'.tr), - // position: LatLng( - // double.parse( - // controller.placesCoordinate[0].split(',')[0]), - // double.parse( - // controller.placesCoordinate[0].split(',')[1])), - // draggable: true, - // icon: controller.startIcon, - // ), - // if (controller.haveSteps) - // Marker( - // markerId: MarkerId('EndSteps'.tr), - // position: controller.latestPosition, - // draggable: true, - // icon: controller.endIcon, - // ), - // }, + // ✅ بوليغونز كما هي polygons: controller.polygons, - polylines: controller.polyLines.toSet(), - // { - // Polyline( - // polylineId: const PolylineId('route'), - // points: controller.polylineCoordinates, - // color: AppColor.primaryColor, - // width: 4, - // // patterns: [ - // // PatternItem.dot, - // // PatternItem.gap(10), - // // ], - // endCap: Cap.roundCap, - // startCap: Cap.roundCap, - // geodesic: true, - // ), - // Polyline( - // zIndex: 1, - // consumeTapEvents: true, - // geodesic: true, - // endCap: Cap.buttCap, - // startCap: Cap.buttCap, - // visible: true, - // polylineId: const PolylineId('route0'), - // points: controller.polylineCoordinatesPointsAll[0], - // color: AppColor.blueColor, - // width: 5, - // ), - // Polyline( - // zIndex: 2, - // consumeTapEvents: true, - // geodesic: true, - // endCap: Cap.buttCap, - // startCap: Cap.buttCap, - // visible: true, - // polylineId: const PolylineId('route1'), - // points: controller.polylineCoordinatesPointsAll[1], - // color: AppColor.yellowColor, - // width: 5, - // ), - // Polyline( - // zIndex: 2, - // consumeTapEvents: true, - // geodesic: true, - // endCap: Cap.buttCap, - // startCap: Cap.buttCap, - // visible: true, - // polylineId: const PolylineId('route2'), - // points: controller.polylineCoordinatesPointsAll[2], - // color: AppColor.greenColor, - // width: 5, - // ), - // Polyline( - // zIndex: 2, - // consumeTapEvents: true, - // geodesic: true, - // endCap: Cap.buttCap, - // startCap: Cap.buttCap, - // visible: true, - // polylineId: const PolylineId('route3'), - // points: controller.polylineCoordinatesPointsAll[2], - // color: AppColor.deepPurpleAccent, - // width: 5, - // ), - // // Polyline( - // // zIndex: 2, - // // consumeTapEvents: true, - // // geodesic: true, - // // endCap: Cap.buttCap, - // // startCap: Cap.buttCap, - // // visible: true, - // // polylineId: PolylineId('g'), - // // points: [ - // // LatLng(controller.southwest.latitude, - // // controller.southwest.longitude), - // // LatLng(controller.northeast.latitude, - // // controller.northeast.longitude) - // // ], - // // color: AppColor.primaryColor, - // // width: 5, - // // ), - // }, + // ✅ Polyline مُبسّطة للأجهزة الضعيفة (الكنترولر يجهّز مجموعة مبسطة عند lowPerf) + polylines: controller.lowPerf + ? controller.polyLinesLight + .toSet() // <- استخدم مجموعة خفيفة + : controller.polyLines.toSet(), + + // ✅ دوائر خفيفة على الأجهزة الضعيفة // circles: { // Circle( - // circleId: const CircleId('kk'), - // center: controller.mylocation, - // radius: 60, - // fillColor: AppColor.primaryColor,) + // circleId: const CircleId('circle_id'), + // center: controller.passengerLocation, + // radius: controller.lowPerf ? 80 : 100, + // fillColor: + // Colors.blue.withOpacity(controller.lowPerf ? 0.2 : 0.3), + // strokeColor: Colors.blue, + // strokeWidth: controller.lowPerf ? 1 : 2, + // ), // }, - circles: { - Circle( - circleId: const CircleId('circle_id'), - center: controller.passengerLocation, - radius: 100, - fillColor: Colors.blue.withOpacity(0.3), - strokeColor: Colors.blue, - strokeWidth: 2, - ), - }, + // ✅ الوضع الخفيف: liteMode + تعطيل الطبقات المكلفة + خريطة Normal + mapType: controller.lowPerf + ? MapType.normal + : (controller.mapType + ? MapType.satellite + : MapType.terrain), - mapType: - controller.mapType ? MapType.satellite : MapType.terrain, - myLocationButtonEnabled: true, - // liteModeEnabled: true, tiltGesturesEnabled: false, + myLocationButtonEnabled: false, - // indoorViewEnabled: true, - trafficEnabled: controller.mapTrafficON, - buildingsEnabled: true, - mapToolbarEnabled: true, + // ⚠️ liteMode (Android فقط): فعّله على الأجهزة الضعيفة + // liteModeEnabled: controller.lowPerf, + liteModeEnabled: Platform.isAndroid ? isLowEnd() : false, + trafficEnabled: controller.mapTrafficON && !isLowEnd(), + buildingsEnabled: !isLowEnd(), + // ✅ تقليل الكلفة الرسومية + + mapToolbarEnabled: false, + rotateGesturesEnabled: isLowEnd() ? false : true, + tiltGesturesEnabled: false, // تعطيل الميلان لتقليل الحمل + + // ✅ Throttle لحركة الكاميرا على الأجهزة الضعيفة onCameraMove: (position) { - int waypointsLength = - Get.find().wayPoints.length; - int index = controller.wayPointIndex; - if (waypointsLength > 0) { - controller.placesCoordinate[index] = - '${position.target.latitude.toString()},${position.target.longitude}'; + if (controller.lowPerf) { + controller.onCameraMoveThrottled(position); + } else { + // منطقك الحالي + int waypointsLength = + Get.find().wayPoints.length; + int index = controller.wayPointIndex; + if (waypointsLength > 0) { + controller.placesCoordinate[index] = + '${position.target.latitude},${position.target.longitude}'; + } + if (controller.startLocationFromMap == true) { + controller.newStartPointLocation = position.target; + } else if (controller.passengerStartLocationFromMap == + true) { + controller.newStartPointLocation = position.target; + } + controller.newMyLocation = position.target; } - if (controller.startLocationFromMap == true) { - controller.newStartPointLocation = position.target; - } else if (controller.passengerStartLocationFromMap == true) { - controller.newStartPointLocation = position.target; - } - controller.newMyLocation = position.target; }, + myLocationEnabled: true, - // liteModeEnabled: true, ), ), ); 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 ea2f536..252c119 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 @@ -1,25 +1,16 @@ -import 'package:Intaleq/constant/box_name.dart'; import 'package:Intaleq/controller/firebase/firbase_messge.dart'; -import 'package:Intaleq/env/env.dart'; -import 'package:Intaleq/main.dart'; -import 'package:Intaleq/views/auth/login_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_font_icons/flutter_font_icons.dart'; import 'package:get/get.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:secure_string_operations/secure_string_operations.dart'; import 'dart:ui'; // مهم لإضافة تأثير الضبابية -import '../../../constant/char_map.dart'; import '../../../constant/colors.dart'; import '../../../controller/auth/login_controller.dart'; -import '../../../controller/functions/encrypt_decrypt.dart'; import '../../../controller/functions/tts.dart'; import '../../../controller/home/map_passenger_controller.dart'; import '../../../controller/home/vip_waitting_page.dart'; -import '../../../print.dart'; import '../../auth/otp_page.dart'; -import '../../auth/otp_token_page.dart'; // --- الدالة الرئيسية بالتصميم الجديد --- GetBuilder leftMainMenuIcons() { 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 5d53f57..c4fc4c1 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,5 @@ +import 'dart:ui'; // مهم لإضافة تأثير الضبابية + import 'package:Intaleq/constant/box_name.dart'; import 'package:Intaleq/main.dart'; import 'package:flutter/foundation.dart'; @@ -10,12 +12,13 @@ import 'package:Intaleq/views/home/profile/complaint_page.dart'; import 'package:Intaleq/views/home/profile/order_history.dart'; import 'package:Intaleq/views/home/profile/promos_passenger_page.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'dart:ui'; // مهم لإضافة تأثير الضبابية import '../../../constant/colors.dart'; +import '../../../constant/links.dart'; import '../../../controller/home/map_passenger_controller.dart'; import '../../notification/notification_page.dart'; import '../HomePage/contact_us.dart'; +import '../HomePage/share_app_page.dart'; import '../setting_page.dart'; import '../profile/passenger_profile_page.dart'; @@ -25,17 +28,25 @@ class MapMenuWidget extends StatelessWidget { @override Widget build(BuildContext context) { - // استخدام Get.lazyPut لضمان وجود الكنترولر Get.lazyPut(() => MapPassengerController()); return GetBuilder( builder: (controller) => Stack( children: [ + // --- خلفية معتمة عند فتح القائمة --- + if (controller.widthMenu > 0) + GestureDetector( + onTap: controller.getDrawerMenu, + child: Container( + color: Colors.black.withOpacity(0.4), + ), + ), + // --- القائمة الجانبية المنزلقة --- _buildSideMenu(controller), // --- زر القائمة العائم --- - // _buildMenuButton(controller), + _buildMenuButton(controller), ], ), ); @@ -48,7 +59,7 @@ class MapMenuWidget extends StatelessWidget { left: 16, child: SafeArea( child: InkWell( - onTap: controller.getDrawerMenu, // نفس دالتك القديمة + onTap: controller.getDrawerMenu, borderRadius: BorderRadius.circular(50), child: ClipRRect( borderRadius: BorderRadius.circular(50), @@ -64,9 +75,7 @@ class MapMenuWidget extends StatelessWidget { Border.all(color: AppColor.writeColor.withOpacity(0.2)), ), child: Icon( - controller.widthMenu > 0 - ? Icons.close_rounded - : Icons.menu_rounded, + controller.widthMenu > 0 ? Icons.close : Icons.menu, color: AppColor.writeColor, size: 26, ), @@ -85,63 +94,100 @@ class MapMenuWidget extends StatelessWidget { curve: Curves.fastOutSlowIn, top: 0, bottom: 0, - // تحريك القائمة من خارج الشاشة إلى داخلها left: controller.widthMenu > 0 ? 0 : -Get.width, child: ClipRRect( child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), child: Container( - width: Get.width * 0.75, // عرض القائمة - constraints: const BoxConstraints(maxWidth: 300), - color: AppColor.secondaryColor.withOpacity(0.9), + width: Get.width * 0.8, + constraints: const BoxConstraints(maxWidth: 320), + decoration: BoxDecoration( + color: AppColor.secondaryColor.withOpacity(0.95), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 20, + ) + ], + ), child: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // --- 1. رأس القائمة (معلومات المستخدم) --- _buildMenuHeader(), - - // --- 2. الأزرار السريعة المدمجة --- _buildQuickActionButtons(), const Divider( - color: AppColor.writeColor, + color: Colors.white24, indent: 16, endIndent: 16, - height: 1), - - // --- 3. قائمة الخيارات الرئيسية --- + height: 24), Expanded( child: ListView( - padding: const EdgeInsets.symmetric(vertical: 8), + padding: const EdgeInsets.symmetric(horizontal: 8), children: [ - IconMainPageMap( - title: 'My Wallet'.tr, + MenuListItem( + title: 'My Balance'.tr, icon: Icons.account_balance_wallet_outlined, onTap: () => Get.to(() => const PassengerWallet())), - IconMainPageMap( + MenuListItem( title: 'Order History'.tr, - icon: Icons.history_edu_rounded, + icon: Icons.history_rounded, onTap: () => Get.to(() => const OrderHistory())), - IconMainPageMap( - title: 'Contact Us'.tr, - icon: Icons.contact_support_outlined, - onTap: () => Get.to(() => ContactUsPage())), - IconMainPageMap( - title: 'Driver'.tr, - icon: Ionicons.car_sport_outline, - onTap: () => _launchDriverAppUrl()), - IconMainPageMap( - title: 'Complaint'.tr, - icon: Icons.feedback_outlined, - onTap: () => Get.to(() => ComplaintPage())), - IconMainPageMap( + MenuListItem( title: 'Promos'.tr, icon: Icons.local_offer_outlined, onTap: () => Get.to(() => const PromosPassengerPage())), + MenuListItem( + title: 'Contact Us'.tr, + icon: Icons.contact_support_outlined, + onTap: () => Get.to(() => ContactUsPage())), + MenuListItem( + title: 'Complaint'.tr, + icon: Icons.flag_outlined, + onTap: () => Get.to(() => ComplaintPage())), + MenuListItem( + title: 'Driver'.tr, + icon: Ionicons.car_sport_outline, + onTap: () => _launchDriverAppUrl()), + MenuListItem( + title: 'Share App'.tr, + icon: Icons.share_outlined, + onTap: () => Get.to(() => ShareAppPage())), + MenuListItem( + title: 'Privacy Policy'.tr, + icon: Icons.shield_outlined, + onTap: () => launchUrl(Uri.parse( + '${AppLink.server}/privacy_policy.php')), + ), ], ), ), + const Divider( + color: Colors.white24, + indent: 16, + endIndent: 16, + height: 1), + Padding( + padding: const EdgeInsets.all(8.0), + child: MenuListItem( + title: 'Logout'.tr, + icon: Icons.logout_rounded, + onTap: () { + Get.defaultDialog( + title: "Logout".tr, + middleText: "Are you sure you want to logout?".tr, + textConfirm: "Logout".tr, + textCancel: "Cancel".tr, + onConfirm: () { + // controller.logout(); + Get.back(); + }, + ); + }, + color: Colors.red.shade300, + ), + ), ], ), ), @@ -151,49 +197,57 @@ class MapMenuWidget extends StatelessWidget { ); } - // --- ويدجت مساعدة لرأس القائمة --- + // --- ويدجت رأس القائمة --- Widget _buildMenuHeader() { return Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + padding: const EdgeInsets.fromLTRB(20, 30, 20, 16), + child: Row( children: [ - // CircleAvatar( - // radius: 30, - // backgroundColor: AppColor.primaryColor, - // child: - // const Icon(Icons.person, color: AppColor.writeColor, size: 35), - // ), - // const SizedBox(height: 12), - Text( - "Welcome Back!".tr, // يمكنك تغييرها لاسم المستخدم - style: AppStyle.title - .copyWith(color: AppColor.writeColor.withOpacity(0.7)), + const CircleAvatar( + radius: 30, + backgroundColor: AppColor.primaryColor, + child: Icon(Icons.person, color: AppColor.writeColor, size: 35), ), - Text( - box.read(BoxName.name), // يمكنك تغييرها لاسم المستخدم - style: AppStyle.headTitle.copyWith(fontSize: 22), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + box.read(BoxName.name) ?? 'Guest', + style: AppStyle.headTitle.copyWith(fontSize: 20), + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 4), + Text( + "Intaleq Passenger".tr, + style: AppStyle.title.copyWith( + color: AppColor.writeColor.withOpacity(0.7), + fontSize: 14), + ), + ], + ), ), ], ), ); } - // --- ويدجت مساعدة للأزرار السريعة --- + // --- ويدجت الأزرار السريعة --- Widget _buildQuickActionButtons() { return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - _buildSmallActionButton( - icon: Icons.notifications_none_rounded, - label: 'Alerts'.tr, - onTap: () => Get.to(() => const NotificationPage())), _buildSmallActionButton( icon: Icons.person_outline_rounded, label: 'Profile'.tr, onTap: () => Get.to(() => PassengerProfilePage())), + _buildSmallActionButton( + icon: Icons.notifications_none_rounded, + label: 'Alerts'.tr, + onTap: () => Get.to(() => const NotificationPage())), _buildSmallActionButton( icon: Icons.settings_outlined, label: 'Settings'.tr, @@ -209,29 +263,31 @@ class MapMenuWidget extends StatelessWidget { required VoidCallback onTap}) { return InkWell( onTap: onTap, - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(12), child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ - Icon(icon, color: AppColor.writeColor, size: 24), - const SizedBox(height: 4), - Text(label, style: AppStyle.subtitle.copyWith(fontSize: 12)), + Icon(icon, color: AppColor.writeColor.withOpacity(0.9), size: 24), + const SizedBox(height: 6), + Text(label, + style: AppStyle.subtitle.copyWith( + fontSize: 12, color: AppColor.writeColor.withOpacity(0.9))), ], ), ), ); } - // --- نفس دالتك القديمة لفتح رابط تطبيق السائق --- void _launchDriverAppUrl() async { final String driverAppUrl; if (defaultTargetPlatform == TargetPlatform.android) { driverAppUrl = - 'https://play.google.com/store/apps/details?id=com.sefer_driver'; + 'https://play.google.com/store/apps/details?id=com.intaleq_driver'; } else if (defaultTargetPlatform == TargetPlatform.iOS) { - driverAppUrl = 'https://apps.apple.com/eg/app/tripz-driver/id6502189302'; + driverAppUrl = + 'https://apps.apple.com/st/app/intaleq-driver/id6482995159'; } else { return; } @@ -248,28 +304,39 @@ class MapMenuWidget extends StatelessWidget { } } -// --- كلاس عناصر القائمة بالتصميم الجديد (يستخدم ListTile) --- -class IconMainPageMap extends StatelessWidget { - const IconMainPageMap({ +// --- ويدجت عناصر القائمة بتصميم محسن --- +class MenuListItem extends StatelessWidget { + const MenuListItem({ super.key, required this.title, required this.onTap, required this.icon, + this.color, }); final String title; final IconData icon; final VoidCallback onTap; + final Color? color; @override Widget build(BuildContext context) { return ListTile( onTap: onTap, - leading: - Icon(icon, size: 26, color: AppColor.writeColor.withOpacity(0.8)), + leading: Icon( + icon, + size: 26, + color: color ?? AppColor.writeColor.withOpacity(0.8), + ), title: Text( title.tr, - style: AppStyle.title.copyWith(fontSize: 16), + style: AppStyle.title.copyWith( + fontSize: 16, + color: color ?? AppColor.writeColor, + ), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), ), splashColor: AppColor.primaryColor.withOpacity(0.2), ); diff --git a/lib/views/home/map_widget.dart/ride_begin_passenger.dart b/lib/views/home/map_widget.dart/ride_begin_passenger.dart index 332a3b7..033241c 100644 --- a/lib/views/home/map_widget.dart/ride_begin_passenger.dart +++ b/lib/views/home/map_widget.dart/ride_begin_passenger.dart @@ -193,7 +193,7 @@ class RideBeginPassenger extends StatelessWidget { box.write(BoxName.sosPhonePassenger, profileController.prfoileData['sosPhone']); } else { - makePhoneCall('122'); + makePhoneCall('112'); } }), _buildActionButton( @@ -211,18 +211,17 @@ class RideBeginPassenger extends StatelessWidget { } else { final phoneNumber = box.read(BoxName.sosPhonePassenger).toString(); - final phone = box.read(BoxName.countryCode) == 'Egypt' - ? '+2$phoneNumber' - : '+962$phoneNumber'; + + final phone = controller.formatSyrianPhoneNumber(phoneNumber); controller.sendWhatsapp(phone); } }), _buildActionButton( - icon: Foundation.video, - label: 'Video Call'.tr, + icon: Icons.share_location_outlined, // أيقونة جديدة ومناسبة + label: 'Share'.tr, // اسم جديد وواضح color: AppColor.blueColor, onTap: () async { - // --- نفس منطقك القديم --- + // نفس الوظيفة السابقة التي كانت تحت اسم "Video Call" await controller.getTokenForParent(); }), _buildActionButton( diff --git a/lib/views/home/my_wallet/passenger_wallet.dart b/lib/views/home/my_wallet/passenger_wallet.dart index 9d76994..9301b9a 100644 --- a/lib/views/home/my_wallet/passenger_wallet.dart +++ b/lib/views/home/my_wallet/passenger_wallet.dart @@ -27,7 +27,7 @@ class PassengerWallet extends StatelessWidget { Get.put(CreditCardController()); return MyScafolld( - title: 'My Wallet'.tr, + title: 'My Balance'.tr, isleading: true, body: [ // استخدام Stack فقط لعرض الـ Dialog فوق المحتوى عند الحاجة @@ -53,7 +53,7 @@ class PassengerWallet extends StatelessWidget { // --- 2. قائمة الخيارات المنظمة --- _buildActionTile( icon: Icons.add_card_rounded, - title: 'Top up Wallet'.tr, + title: 'Top up Balance'.tr, subtitle: 'Add funds using our secure methods'.tr, onTap: () => showPaymentBottomSheet(context), // نفس دالتك القديمة @@ -68,7 +68,7 @@ class PassengerWallet extends StatelessWidget { ), _buildActionTile( icon: Icons.phone_iphone_rounded, - title: 'Set Wallet Phone Number'.tr, + title: 'Set Phone Number'.tr, subtitle: 'Link a phone number for transfers'.tr, onTap: () => _showWalletPhoneDialog(context, Get.find()), // نفس دالتك القديمة @@ -132,7 +132,7 @@ class PassengerWallet extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '${AppInformation.appName} Wallet'.tr, + '${AppInformation.appName} ${'Balance'.tr}', style: AppStyle.headTitle.copyWith( color: Colors.white, fontSize: 20, diff --git a/lib/views/home/profile/passenger_profile_page.dart b/lib/views/home/profile/passenger_profile_page.dart index fcd1868..e4fe7e7 100644 --- a/lib/views/home/profile/passenger_profile_page.dart +++ b/lib/views/home/profile/passenger_profile_page.dart @@ -1,5 +1,3 @@ -import 'package:Intaleq/controller/functions/encrypt_decrypt.dart'; -import 'package:Intaleq/views/auth/login_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -8,8 +6,8 @@ import 'package:Intaleq/constant/colors.dart'; import 'package:Intaleq/constant/style.dart'; import 'package:Intaleq/controller/profile/profile_controller.dart'; import 'package:Intaleq/main.dart'; +import 'package:Intaleq/views/auth/login_page.dart'; import 'package:Intaleq/views/widgets/elevated_btn.dart'; -import 'package:Intaleq/views/widgets/my_scafold.dart'; import 'package:Intaleq/views/widgets/my_textField.dart'; import 'package:Intaleq/views/widgets/mycircular.dart'; @@ -18,239 +16,319 @@ import '../../../controller/functions/log_out.dart'; class PassengerProfilePage extends StatelessWidget { PassengerProfilePage({super.key}); - LogOutController logOutController = Get.put(LogOutController()); + + final LogOutController logOutController = Get.put(LogOutController()); + @override Widget build(BuildContext context) { Get.put(ProfileController()); - return MyScafolld( - isleading: true, - title: 'My Profile'.tr, - body: [ - GetBuilder( - builder: (controller) => controller.isloading - ? const MyCircularProgressIndicator() - : Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: SizedBox( - height: Get.height, - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Edit Profile'.tr, - style: AppStyle.headTitle2, - ), - ListTile( - title: Text( - 'Name'.tr, - style: AppStyle.title, - ), - leading: const Icon( - Icons.person_pin_rounded, - size: 35, - ), - trailing: const Icon(Icons.arrow_forward_ios), - subtitle: Text( - '${(controller.prfoileData['first_name'])} ${(controller.prfoileData['last_name'])}'), - onTap: () { - controller.updatField( - 'first_name', TextInputType.name); - }, - ), - ListTile( - title: Text( - 'Gender'.tr, - style: AppStyle.title, - ), - leading: Image.asset( - 'assets/images/gender.png', - width: 35, - ), - trailing: const Icon(Icons.arrow_forward_ios), - subtitle: Text((controller.prfoileData['gender'] - .toString())), - onTap: () { - Get.defaultDialog( - title: 'Update Gender'.tr, - content: Column( - children: [ - GenderPicker(), - MyElevatedButton( - title: 'Update'.tr, - onPressed: () { - controller.updateColumn({ - 'id': controller.prfoileData['id'] - .toString(), - 'gender': (controller.gender), - }); - Get.back(); - }, - ) - ], - )); - // controller.updatField('gender'); - }, - ), - ListTile( - title: Text( - 'Education'.tr, - style: AppStyle.title, - ), - leading: Image.asset( - 'assets/images/education.png', - width: 35, - ), - trailing: const Icon(Icons.arrow_forward_ios), - subtitle: Text(controller.prfoileData['education'] - .toString()), - onTap: () { - Get.defaultDialog( - barrierDismissible: true, - title: 'Update Education'.tr, - content: SizedBox( - height: 200, - child: Column( - children: [ - EducationDegreePicker(), - ], - ), - ), - confirm: MyElevatedButton( - title: 'Update Education'.tr, - onPressed: () { - controller.updateColumn({ - 'id': controller.prfoileData['id'] - .toString(), - 'education': - controller.selectedDegree, - }); - Get.back(); - }, - )); - }, - ), - ListTile( - title: Text( - 'Employment Type'.tr, - style: AppStyle.title, - ), - leading: Image.asset( - 'assets/images/employmentType.png', - width: 35, - ), - trailing: const Icon(Icons.arrow_forward_ios), - subtitle: Text(controller - .prfoileData['employmentType'] - .toString()), - onTap: () { - controller.updatField( - 'employmentType', TextInputType.name); - }, - ), - ListTile( - title: Text( - 'Marital Status'.tr, - style: AppStyle.title, - ), - leading: Image.asset( - 'assets/images/maritalStatus.png', - width: 35, - ), - trailing: const Icon(Icons.arrow_forward_ios), - subtitle: Text(controller - .prfoileData['maritalStatus'] - .toString()), - onTap: () { - controller.updatField( - 'maritalStatus', TextInputType.name); - }, - ), - ListTile( - title: Text( - 'SOS Phone'.tr, - style: AppStyle.title, - ), - leading: const Icon( - Icons.sos, - color: AppColor.redColor, - size: 35, - ), - trailing: const Icon(Icons.arrow_forward_ios), - subtitle: Text( - (controller.prfoileData['sosPhone']) - .toString()), - onTap: () async { - await controller.updatField( - 'sosPhone', TextInputType.phone); - box.write(BoxName.sosPhonePassenger, - controller.prfoileData['sosPhone']); - }, - ), - // const Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - MyElevatedButton( - title: 'Sign Out'.tr, - onPressed: () { - LogOutController().logOutPassenger(); - }), - GetBuilder( - builder: (logOutController) { - return MyElevatedButton( - title: 'Delete My Account'.tr, - onPressed: () { - Get.defaultDialog( - title: - 'Are you sure to delete your account?' - .tr, - content: Form( - key: logOutController.formKey1, - child: MyTextForm( - controller: logOutController - .emailTextController, - label: 'Type your Email'.tr, - hint: 'Type your Email'.tr, - type: - TextInputType.emailAddress, - ), - ), - confirm: MyElevatedButton( - title: 'Delete My Account'.tr, - kolor: AppColor.redColor, - onPressed: () async { - await logOutController - .deletePassengerAccount(); - }), - cancel: MyElevatedButton( - title: 'No I want'.tr, - onPressed: () { - logOutController - .emailTextController - .clear(); - logOutController.update(); - Get.back(); - })); - }); - }), - ], - ), - ], - ), - ), - ), - )), + return Scaffold( + backgroundColor: Colors.grey[100], + appBar: AppBar( + title: Text('My Profile'.tr, + style: const TextStyle(fontWeight: FontWeight.bold)), + backgroundColor: Colors.grey[100], + elevation: 0, + centerTitle: true, + ), + body: GetBuilder( + builder: (controller) { + if (controller.isloading) { + return const MyCircularProgressIndicator(); + } + return ListView( + padding: + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0), + children: [ + _buildProfileHeader(controller), + const SizedBox(height: 24), + _buildSectionCard( + 'Personal Information'.tr, + [ + _buildProfileTile( + icon: Icons.person_outline, + color: Colors.blue, + title: 'Name'.tr, + subtitle: + '${controller.prfoileData['first_name'] ?? ''} ${controller.prfoileData['last_name'] ?? ''}', + onTap: () => + controller.updatField('first_name', TextInputType.name), + ), + _buildProfileTile( + icon: Icons.wc_outlined, + color: Colors.pink, + title: 'Gender'.tr, + subtitle: controller.prfoileData['gender']?.toString() ?? + 'Not set'.tr, + onTap: () => _showGenderDialog(controller), + ), + _buildProfileTile( + icon: Icons.school_outlined, + color: Colors.orange, + title: 'Education'.tr, + subtitle: controller.prfoileData['education']?.toString() ?? + 'Not set'.tr, + onTap: () => _showEducationDialog(controller), + ), + ], + ), + const SizedBox(height: 24), + _buildSectionCard( + 'Work & Contact'.tr, + [ + _buildProfileTile( + icon: Icons.work_outline, + color: Colors.green, + title: 'Employment Type'.tr, + subtitle: + controller.prfoileData['employmentType']?.toString() ?? + 'Not set'.tr, + onTap: () => controller.updatField( + 'employmentType', TextInputType.name), + ), + _buildProfileTile( + icon: Icons.favorite_border, + color: Colors.purple, + title: 'Marital Status'.tr, + subtitle: + controller.prfoileData['maritalStatus']?.toString() ?? + 'Not set'.tr, + onTap: () => controller.updatField( + 'maritalStatus', TextInputType.name), + ), + _buildProfileTile( + icon: Icons.sos_outlined, + color: Colors.red, + title: 'SOS Phone'.tr, + subtitle: controller.prfoileData['sosPhone']?.toString() ?? + 'Not set'.tr, + onTap: () async { + await controller.updatField( + 'sosPhone', TextInputType.phone); + box.write(BoxName.sosPhonePassenger, + controller.prfoileData['sosPhone']); + }, + ), + ], + ), + const SizedBox(height: 32), + _buildAccountActions(context, logOutController), + ], + ); + }, + ), + ); + } + + Widget _buildProfileHeader(ProfileController controller) { + String fullName = + '${controller.prfoileData['first_name'] ?? ''} ${controller.prfoileData['last_name'] ?? ''}'; + String initials = (fullName.isNotEmpty && fullName.contains(" ")) + ? fullName.split(" ").map((e) => e.isNotEmpty ? e[0] : "").join() + : (fullName.isNotEmpty ? fullName[0] : ""); + + // Logic to hide email if it contains 'intaleqapp.com' + String email = box.read(BoxName.email) ?? ''; + if (email.contains('intaleqapp.com')) { + email = ''; // Clear the email if it contains the domain + } + + return Center( + child: Column( + children: [ + CircleAvatar( + radius: 50, + backgroundColor: AppColor.primaryColor.withOpacity(0.2), + child: Text( + initials, + style: + const TextStyle(fontSize: 40, color: AppColor.primaryColor), + ), + ), + const SizedBox(height: 12), + Text( + fullName, + style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold), + ), + if (email + .isNotEmpty) // Only show the Text widget if the email is not empty + Text( + email, + style: TextStyle(fontSize: 16, color: Colors.grey[600]), + ), + ], + ), + ); + } + + Widget _buildSectionCard(String title, List children) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0, bottom: 8.0), + child: Text( + title, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.grey[700]), + ), + ), + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + ), + child: Column( + children: children, + ), + ), ], ); } + + Widget _buildProfileTile({ + required IconData icon, + required Color color, + required String title, + required String subtitle, + required VoidCallback onTap, + }) { + return ListTile( + onTap: onTap, + leading: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: Icon(icon, color: color, size: 24), + ), + title: Text(title, style: const TextStyle(fontWeight: FontWeight.w500)), + subtitle: Text(subtitle, style: TextStyle(color: Colors.grey[600])), + trailing: + Icon(Icons.arrow_forward_ios, size: 16, color: Colors.grey[400]), + ); + } + + Widget _buildAccountActions( + BuildContext context, LogOutController logOutController) { + return Column( + children: [ + SizedBox( + width: double.infinity, + child: TextButton.icon( + icon: const Icon(Icons.logout), + label: Text('Sign Out'.tr), + style: TextButton.styleFrom( + foregroundColor: Colors.blueGrey, + padding: const EdgeInsets.symmetric(vertical: 12), + ), + onPressed: () { + logOutController.logOutPassenger(); + }, + ), + ), + const SizedBox(height: 8), + SizedBox( + width: double.infinity, + child: TextButton.icon( + icon: const Icon(Icons.delete_forever_outlined), + label: Text('Delete My Account'.tr), + style: TextButton.styleFrom( + foregroundColor: Colors.red, + padding: const EdgeInsets.symmetric(vertical: 12), + ), + onPressed: () => + _showDeleteAccountDialog(context, logOutController), + ), + ), + ], + ); + } + + void _showGenderDialog(ProfileController controller) { + Get.defaultDialog( + title: 'Update Gender'.tr, + content: Column( + children: [ + GenderPicker(), + const SizedBox(height: 16), + MyElevatedButton( + title: 'Update'.tr, + onPressed: () { + controller.updateColumn({ + 'id': controller.prfoileData['id'].toString(), + 'gender': controller.gender, + }); + Get.back(); + }, + ) + ], + ), + ); + } + + void _showEducationDialog(ProfileController controller) { + Get.defaultDialog( + title: 'Update Education'.tr, + content: Column( + children: [ + EducationDegreePicker(), + const SizedBox(height: 16), + MyElevatedButton( + title: 'Update'.tr, + onPressed: () { + controller.updateColumn({ + 'id': controller.prfoileData['id'].toString(), + 'education': controller.selectedDegree, + }); + Get.back(); + }, + ), + ], + ), + ); + } + + void _showDeleteAccountDialog( + BuildContext context, LogOutController logOutController) { + Get.defaultDialog( + title: 'Delete My Account'.tr, + middleText: 'Are you sure? This action cannot be undone.'.tr, + content: Form( + key: logOutController.formKey1, + child: MyTextForm( + controller: logOutController.emailTextController, + label: 'Confirm your Email'.tr, + hint: 'Type your Email'.tr, + type: TextInputType.emailAddress, + ), + ), + confirm: MyElevatedButton( + title: 'Delete Permanently'.tr, + kolor: AppColor.redColor, + onPressed: () async { + await logOutController.deletePassengerAccount(); + }, + ), + cancel: TextButton( + child: Text('Cancel'.tr), + onPressed: () { + logOutController.emailTextController.clear(); + Get.back(); + }, + ), + ); + } } -class GenderPicker extends StatelessWidget { - final ProfileController controller = Get.put(ProfileController()); +// --- Helper Widgets for Pickers --- +class GenderPicker extends StatelessWidget { + final ProfileController controller = Get.find(); final List genderOptions = ['Male'.tr, 'Female'.tr, 'Other'.tr]; GenderPicker({super.key}); @@ -258,14 +336,14 @@ class GenderPicker extends StatelessWidget { @override Widget build(BuildContext context) { return SizedBox( - height: 100, + height: 150, child: CupertinoPicker( - itemExtent: 32.0, + itemExtent: 40.0, onSelectedItemChanged: (int index) { controller.setGender(genderOptions[index]); }, children: genderOptions.map((String value) { - return Text(value); + return Center(child: Text(value)); }).toList(), ), ); @@ -273,216 +351,34 @@ class GenderPicker extends StatelessWidget { } class EducationDegreePicker extends StatelessWidget { - final ProfileController controller = Get.put(ProfileController()); - + final ProfileController controller = Get.find(); final List degreeOptions = [ 'High School Diploma'.tr, 'Associate Degree'.tr, - 'Bachelor\'s Degree'.tr, - 'Master\'s Degree'.tr, + "Bachelor's Degree".tr, + "Master's Degree".tr, 'Doctoral Degree'.tr, ]; - EducationDegreePicker({Key? key}) : super(key: key); + EducationDegreePicker({super.key}); @override Widget build(BuildContext context) { return SizedBox( - height: 200, + height: 180, child: CupertinoPicker( - // backgroundColor: AppColor.accentColor, - // looping: true, - squeeze: 2, - // diameterRatio: 5, - itemExtent: 32, + itemExtent: 40.0, onSelectedItemChanged: (int index) { controller.setDegree(degreeOptions[index]); }, children: degreeOptions.map((String value) { - return Text(value); + return Center(child: Text(value)); }).toList(), ), ); } } -class CountryPicker extends StatelessWidget { - final ProfileController controller = Get.put(ProfileController()); - - final List countryOptions = [ - 'Jordan', - 'Syria', - 'Egypt', - 'Turkey', - 'Saudi Arabia', - 'Qatar', - 'Bahrain', - 'Kuwait', - 'USA' - ]; - - CountryPicker({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return GetBuilder(builder: (controller) { - return Padding( - padding: const EdgeInsets.all(20), - child: ListView( - children: [ - const SizedBox( - height: 20, - ), - Text( - "Select Your Country".tr, - style: AppStyle.headTitle2, - textAlign: TextAlign.center, - ), - // const SizedBox( - // height: 20, - // ), - Padding( - padding: const EdgeInsets.all(10), - child: Text( - "To ensure you receive the most accurate information for your location, please select your country below. This will help tailor the app experience and content to your country." - .tr, - style: AppStyle.title, - textAlign: TextAlign.center, - ), - ), - SizedBox( - height: 200, - child: CupertinoPicker( - itemExtent: 32, - onSelectedItemChanged: (int index) { - controller.setCountry(countryOptions[index]); - box.write(BoxName.countryCode, - countryOptions[index]); // Save in English - }, - children: List.generate( - countryOptions.length, - (index) => Center( - child: Text( - countryOptions[index] - .tr, // Display translated if not English - style: AppStyle.title, - ), - ), - ), - ), - ), - - MyElevatedButton( - title: 'Select Country'.tr, // Use translated text for button - onPressed: () { - Get.find().saveCountryCode(controller - .selectedCountry - .toString()); // No conversion needed - box.write( - BoxName.countryCode, // - controller.selectedCountry); // Already saved in English - if (controller.selectedCountry == null) { - Get.snackbar("You should select your country".tr, ''); - } else { - Get.snackbar(controller.selectedCountry.toString().tr, ''); - Get.off(LoginPage()); - } - }, - ) - ], - ), - ); - }); - } -} - -class CountryPickerFromSetting extends StatelessWidget { - final ProfileController controller = Get.put(ProfileController()); - final LoginController loginController = Get.put(LoginController()); - - final List countryOptions = [ - 'Jordan', - 'USA', - 'Egypt', - 'Turkey', - 'Saudi Arabia', - 'Qatar', - 'Bahrain', - 'Kuwait', - ]; - - CountryPickerFromSetting({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return GetBuilder(builder: (controller) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text('Select Your Country'.tr), - ), - child: Padding( - padding: const EdgeInsets.all(20.0), - child: ListView( - children: [ - const SizedBox( - height: 20, - ), - // Text( - // "Select Your Country".tr, - // style: AppStyle.headTitle2, - // textAlign: TextAlign.center, - // ), - // const SizedBox( - // height: 20, - // ), - Padding( - padding: const EdgeInsets.all(10), - child: Text( - "To ensure you receive the most accurate information for your location, please select your country below. This will help tailor the app experience and content to your country." - .tr, - style: AppStyle.headTitle2, - textAlign: TextAlign.center, - ), - ), - SizedBox( - height: 200, - child: CupertinoPicker( - itemExtent: 32, - onSelectedItemChanged: (int index) { - controller.setCountry(countryOptions[index]); - box.write(BoxName.countryCode, - countryOptions[index]); // Save in English - }, - children: List.generate( - countryOptions.length, - (index) => Center( - child: Text( - countryOptions[index] - .tr, // Display translated if not English - style: AppStyle.title, - ), - ), - ), - ), - ), - - MyElevatedButton( - title: 'Select Country'.tr, // Use translated text for button - onPressed: () async { - loginController.saveCountryCode(controller.selectedCountry - .toString()); // No conversion needed - box.write( - BoxName.countryCode, // - controller.selectedCountry); // Already saved in English - Get.snackbar(controller.selectedCountry.toString().tr, '', - backgroundColor: AppColor.greenColor); - // Get.back();// - // Get.back(); - }, - ) - ], - )), - ); - }); - } -} +// NOTE: The CountryPicker and CountryPickerFromSetting widgets were not part of the main +// profile page UI, so they are excluded here to keep the file focused. +// If they are needed elsewhere, they should be moved to their own files. diff --git a/lib/views/home/setting_page.dart b/lib/views/home/setting_page.dart index 66d236a..65a55c1 100644 --- a/lib/views/home/setting_page.dart +++ b/lib/views/home/setting_page.dart @@ -1,5 +1,4 @@ import 'package:Intaleq/controller/home/home_page_controller.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:Intaleq/views/lang/languages.dart'; @@ -8,109 +7,207 @@ import 'HomePage/about_page.dart'; import 'HomePage/frequentlyQuestionsPage.dart'; import 'HomePage/share_app_page.dart'; import 'HomePage/trip_record_page.dart'; -import 'profile/passenger_profile_page.dart'; + +// NOTE: This is a placeholder for your actual CountryPickerFromSetting widget. +// You should remove this and import your own widget. +class CountryPickerFromSetting extends StatelessWidget { + const CountryPickerFromSetting({super.key}); + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('Change Country'.tr)), + body: Center( + child: Text('Country Picker Page Placeholder'.tr), + ), + ); + } +} class SettingPage extends StatelessWidget { const SettingPage({super.key}); @override Widget build(BuildContext context) { - Get.put(HomePageController()); - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text('Setting'.tr), - leading: CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon(CupertinoIcons.back), - onPressed: () { - Navigator.pop(context); - }, + // Using lazyPut to ensure the controller is available when needed. + Get.lazyPut(() => HomePageController()); + + return Scaffold( + backgroundColor: + const Color(0xFFF5F5F7), // A slightly off-white background + appBar: AppBar( + title: Text('Setting'.tr, + style: const TextStyle( + color: Colors.black87, fontWeight: FontWeight.bold)), + backgroundColor: Colors.white, + elevation: 0.5, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black87), + onPressed: () => Get.back(), ), ), - child: SafeArea( + body: SafeArea( child: ListView( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 20.0), children: [ - CupertinoListTile( - onTap: () { - Get.to(() => const Language()); - }, - leading: const Icon(CupertinoIcons.globe, - color: CupertinoColors.activeBlue), - title: Text('Language'.tr), - subtitle: Text('To change Language the App'.tr), - trailing: const CupertinoListTileChevron(), + _buildSectionHeader('General'.tr), + _buildSettingsCard( + children: [ + _buildSettingsTile( + icon: Icons.language, + color: Colors.blue, + title: 'Language'.tr, + subtitle: 'To change Language the App'.tr, + onTap: () => Get.to(() => const Language()), + ), + // const Divider(height: 1, indent: 68, endIndent: 16), + // _buildSettingsTile( + // icon: Icons.map_outlined, + // color: Colors.green, + // title: 'Change Country'.tr, + // subtitle: 'You can change the Country to get all features'.tr, + // onTap: () => Get.to(() => const CountryPickerFromSetting()), + // ), + ], ), - CupertinoListTile( - onTap: () { - Get.to(() => CountryPickerFromSetting()); - }, - leading: const Icon(CupertinoIcons.location, - color: CupertinoColors.activeBlue), - title: Text('Change Country'.tr), - subtitle: - Text('You can change the Country to get all features'.tr), - trailing: const CupertinoListTileChevron(), + const SizedBox(height: 24), + _buildSectionHeader('Preferences'.tr), + _buildSettingsCard( + children: [ + GetBuilder( + builder: (controller) { + return _buildSettingsSwitchTile( + icon: Icons.vibration, + color: Colors.purple, + title: 'Vibration'.tr, + subtitle: 'Vibration feedback for all buttons'.tr, + value: controller.isVibrate, + onChanged: controller.changeVibrateOption, + ); + }, + ), + const Divider(height: 1, indent: 68, endIndent: 16), + _buildSettingsTile( + icon: Icons.mic_none, + color: Colors.orange, + title: 'Trips recorded'.tr, + subtitle: 'Here recorded trips audio'.tr, + onTap: () => Get.to(() => const TripsRecordedPage()), + ), + ], ), - CupertinoListTile( - onTap: () { - Get.to(() => const FrequentlyQuestionsPage()); - }, - leading: const Icon(CupertinoIcons.question, - color: CupertinoColors.activeBlue), - title: Text('Frequently Questions'.tr), - subtitle: Text('Find answers to common questions'.tr), - trailing: const CupertinoListTileChevron(), - ), - CupertinoListTile( - leading: const Icon(Icons.vibration, - color: CupertinoColors.activeBlue), - title: Text('Vibration'.tr), - trailing: GetBuilder( - builder: (controller) { - return CupertinoSwitch( - value: controller.isVibrate, - onChanged: controller.changeVibrateOption, - ); - }, - ), - subtitle: Text( - 'You can change the vibration feedback for all buttons'.tr), - ), - CupertinoListTile( - onTap: () { - Get.to(() => const TripsRecordedPage()); - }, - leading: const Icon(CupertinoIcons.mic_circle, - color: CupertinoColors.activeBlue), - title: Text('Trips recorded'.tr), - subtitle: Text('Here recorded trips audio'.tr), - trailing: const CupertinoListTileChevron(), - ), - CupertinoListTile( - onTap: () { - Get.to(() => const AboutPage()); - }, - leading: const Icon(CupertinoIcons.info_circle, - color: CupertinoColors.activeBlue), - title: Text('About Us'.tr), - subtitle: Text('Learn more about our app and mission'.tr), - trailing: const CupertinoListTileChevron(), - ), - CupertinoListTile( - onTap: () { - Get.to(() => ShareAppPage()); - }, - leading: const Icon(CupertinoIcons.share, - color: CupertinoColors.activeBlue), - title: Text('Share App'.tr), - subtitle: Text( - 'You can share the Intaleq App with your friends and earn rewards for rides they take using your code' - .tr), - trailing: const CupertinoListTileChevron(), + const SizedBox(height: 24), + _buildSectionHeader('Support & Info'.tr), + _buildSettingsCard( + children: [ + _buildSettingsTile( + icon: Icons.help_outline, + color: Colors.cyan, + title: 'Frequently Questions'.tr, + subtitle: 'Find answers to common questions'.tr, + onTap: () => Get.to(() => const FrequentlyQuestionsPage()), + ), + const Divider(height: 1, indent: 68, endIndent: 16), + _buildSettingsTile( + icon: Icons.info_outline, + color: Colors.indigo, + title: 'About Us'.tr, + subtitle: 'Learn more about our app and mission'.tr, + onTap: () => Get.to(() => const AboutPage()), + ), + const Divider(height: 1, indent: 68, endIndent: 16), + _buildSettingsTile( + icon: Icons.share_outlined, + color: Colors.redAccent, + title: 'Share App'.tr, + subtitle: 'Share with friends and earn rewards'.tr, + onTap: () => Get.to(() => ShareAppPage()), + ), + ], ), ], ), ), ); } + + Widget _buildSectionHeader(String title) { + return Padding( + padding: const EdgeInsets.only(bottom: 12.0, left: 8.0), + child: Text( + title, + style: TextStyle( + color: Colors.grey[700], + fontWeight: FontWeight.bold, + fontSize: 15, + ), + ), + ); + } + + Widget _buildSettingsCard({required List children}) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + ), + clipBehavior: Clip.antiAlias, + child: Column( + children: children, + ), + ); + } + + Widget _buildSettingsTile({ + required IconData icon, + required Color color, + required String title, + required String subtitle, + required VoidCallback onTap, + }) { + return ListTile( + onTap: onTap, + leading: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: Icon(icon, color: color, size: 22), + ), + title: Text(title, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 16)), + subtitle: Text(subtitle, + style: TextStyle(color: Colors.grey[600], fontSize: 13)), + trailing: Icon(Icons.chevron_right, color: Colors.grey[400]), + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), + ); + } + + Widget _buildSettingsSwitchTile({ + required IconData icon, + required Color color, + required String title, + required String subtitle, + required bool value, + required ValueChanged onChanged, + }) { + return SwitchListTile( + secondary: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + ), + child: Icon(icon, color: color, size: 22), + ), + title: Text(title, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 16)), + subtitle: Text(subtitle, + style: TextStyle(color: Colors.grey[600], fontSize: 13)), + value: value, + onChanged: onChanged, + activeColor: const Color(0xFF007AFF), // iOS-like blue + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), + ); + } } diff --git a/lib/views/lang/languages.dart b/lib/views/lang/languages.dart index 50a0f53..53cd755 100644 --- a/lib/views/lang/languages.dart +++ b/lib/views/lang/languages.dart @@ -89,7 +89,7 @@ class Language extends StatelessWidget { ), const SizedBox(height: 8), Text( - 'Select your preferred language for the app interface.', + "Select your preferred language for the app interface.".tr, style: TextStyle( fontSize: 16, color: CupertinoColors.secondaryLabel, diff --git a/pubspec.lock b/pubspec.lock index 3ec43dc..34b2a6d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -50,7 +50,7 @@ packages: source: hosted version: "2.7.0" asn1lib: - dependency: transitive + dependency: "direct main" description: name: asn1lib sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" diff --git a/pubspec.yaml b/pubspec.yaml index 0e17791..8f1cbe1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -74,6 +74,7 @@ dependencies: dotted_line: ^3.2.3 shimmer: ^3.0.0 share_plus: ^11.0.0 + asn1lib: ^1.6.5 # home_widget: ^0.7.0+1 dev_dependencies: