This commit is contained in:
Hamza-Ayed
2024-09-15 09:53:40 +03:00
parent e23709c924
commit 9752d61230
24 changed files with 9002 additions and 221 deletions

2
.env
View File

@@ -18,7 +18,7 @@ serverPHP=https://api.sefer.live/sefer
seferAlexandriaServer=https://seferalexandria.site/sefer
seferPaymentServer=https://seferpw.shop/sefer
seferCairoServer=https://sefer.click/sefer
seferGizaServer=https://sefergiza.site/sefer
seferGizaServer=https://gizasefer.online/sefer
whatappID=369939736211879
whatsapp=EAAOtbZBSUK74BO6yE1QwIBsRCjPDANdum66xap0ZA7OZA8LqEu8MZAts1kwr12eRiNXtvpJ2ZAFSY5dw3KVSyrUuH8boLjynxdFI4Gh1Q7BCHx275X2uZBwKWZCSrsVN17i6mZAFNYYd25sQv0ZBomeTk02ZCIJot4UqWxK9ZBvxsq1k2yS7lD2NsjZB5EHbpaYGLzxFJ2FCCSX6iHyKXab6ckfK7m19wo77in7Dl3YZD
cohere=Aulwd8y5SPWos0hJhG0toUf8gOhUUrpf5Q2TPmVGXrXlBl

View File

@@ -1,4 +1,91 @@
//
//def localProperties = new Properties()
//def localPropertiesFile = rootProject.file('local.properties')
//if (localPropertiesFile.exists()) {
// localPropertiesFile.withReader('UTF-8') { reader ->
// localProperties.load(reader)
// }
//}
//
//def flutterRoot = localProperties.getProperty('flutter.sdk')
//if (flutterRoot == null) {
// throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
//}
//
//def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
//if (flutterVersionCode == null) {
// flutterVersionCode = '12'
//}
//
//def flutterVersionName = localProperties.getProperty('flutter.versionName')
//if (flutterVersionName == null) {
// flutterVersionName = '1.1.2'
//}
//
//apply plugin: 'com.android.application'
//apply plugin: 'kotlin-android'
//// apply plugin: 'com.google.gms.google-services'
//apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
//def keystoreProperties = new Properties()
//def keystorePropertiesFile = rootProject.file('key.properties')
//
//
//android {
// namespace "com.mobileapp.store.ride"
// compileSdkVersion 34
// ndkVersion flutter.ndkVersion
//
// compileOptions {
// sourceCompatibility JavaVersion.VERSION_1_8
// targetCompatibility JavaVersion.VERSION_1_8
// }
//
// kotlinOptions {
// jvmTarget = '1.8'
// }
//
// sourceSets {
// main.java.srcDirs += 'src/main/kotlin'
// }
//
// defaultConfig {
// // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
// applicationId "com.mobileapp.store.ride"
// // You can update the following values to match your application needs.
// // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
// minSdkVersion 23
// targetSdkVersion 34
// versionCode 67
// versionName '1.5.67'
// // manifestPlaceholders = [mapsApiKey: 'android/app/src/main/AndroidManifest.xml']
// }
//
// signingConfigs {
// release {
// keyAlias keystoreProperties['keyAlias']
// keyPassword keystoreProperties['keyPassword']
// storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
// storePassword keystoreProperties['storePassword']
// }
// }
// buildTypes {
// release {
// signingConfig signingConfigs.release
// }
// }
//
//
//}
//
//flutter {
// source '../..'
//}
//
//dependencies {
// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// // implementation platform('com.google.firebase:firebase-bom:32.1.1')
//
//}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
@@ -26,18 +113,24 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
// apply plugin: 'com.google.gms.google-services'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystorePropertiesFile.withReader('UTF-8') { reader ->
keystoreProperties.load(reader)
}
}
android {
namespace "com.mobileapp.store.ride"
compileSdkVersion 34
ndkVersion flutter.ndkVersion
compileSdk 34
ndkVersion "26.1.10909125"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true
}
kotlinOptions {
@@ -49,32 +142,33 @@ android {
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.mobileapp.store.ride"
// Specify your unique Application ID
applicationId = "com.mobileapp.store.ride"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 23
targetSdkVersion 34
versionCode 61
versionName '1.5.61'
// manifestPlaceholders = [mapsApiKey: 'android/app/src/main/AndroidManifest.xml']
minSdk = 23
targetSdk = flutter.targetSdkVersion
versionCode = 68
versionName = '1.5.68'
multiDexEnabled =true
// manifestPlaceholders can be specified here if needed
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
flutter {
@@ -83,6 +177,13 @@ flutter {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2'
// Optional dependencies like Firebase can be uncommented if needed
// implementation platform('com.google.firebase:firebase-bom:32.1.1')
implementation "com.stripe:stripe-android:20.47.0"
implementation 'com.stripe:paymentsheet:20.47.0'
// If push provisioning is needed, make sure you have the correct version:
implementation "com.stripe:stripe-android-pushprovisioning:VERSION" // Replace VERSION with the correct one.
}

View File

@@ -12,7 +12,7 @@ buildscript {
// classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.15'
// END: FlutterFire Configuration
classpath 'com.android.tools.build:gradle:7.3.0'
classpath 'com.android.tools.build:gradle:8.4.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

View File

@@ -1,3 +1,6 @@
org.gradle.jvmargs=-Xmx4096M
android.useAndroidX=true
android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

View File

@@ -4,4 +4,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip

Binary file not shown.

Before

Width:  |  Height:  |  Size: 713 KiB

After

Width:  |  Height:  |  Size: 82 KiB

BIN
assets/images/pinkBike.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

View File

@@ -4,7 +4,7 @@ import FirebaseCore
import GoogleMaps
// import Constants
@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(

View File

@@ -22,7 +22,7 @@ class OnBoardingControllerImp extends OnBoardingController {
if (currentPage > onBoardingList.length - 1) {
box.write(BoxName.onBoarding, 'yes');
Get.offAll(LoginPage());
Get.offAll(() => LoginPage());
} else {
pageController.animateToPage(currentPage,
duration: const Duration(milliseconds: 900), curve: Curves.easeInOut);

View File

@@ -4,6 +4,7 @@ import 'dart:math';
import 'package:SEFER/constant/colors.dart';
import 'package:SEFER/views/home/map_page_passenger.dart';
import 'package:SEFER/views/widgets/my_dialog.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:SEFER/constant/links.dart';
@@ -14,6 +15,7 @@ import 'package:SEFER/views/widgets/elevated_btn.dart';
import '../../constant/box_name.dart';
import '../../main.dart';
import '../../print.dart';
import '../../views/auth/verify_email_page.dart';
import '../functions/sms_controller.dart';
@@ -113,80 +115,125 @@ class RegisterController extends GetxController {
}
sendOtpMessage() async {
SmsEgyptController smsEgyptController = Get.put(SmsEgyptController());
SmsEgyptController smsEgyptController;
int randomNumber = Random().nextInt(100000) + 1;
isLoading = true;
update();
if (formKey3.currentState!.validate()) {
if (box.read(BoxName.countryCode) == 'Egypt') {
if (isValidEgyptianPhoneNumber(phoneController.text) == true) {
var responseCheker = await CRUD()
.post(link: AppLink.checkPhoneNumberISVerfiedPassenger, payload: {
'phone_number': '+2${phoneController.text}',
try {
// Initialize SmsEgyptController
smsEgyptController = Get.put(SmsEgyptController());
// Generate a random OTP
int randomNumber = Random().nextInt(100000) + 1;
isLoading = true;
update();
// Get phone number from controller
String phoneNumber = phoneController.text;
// Check if the phone number is from Egypt (Assuming Egyptian numbers start with +20)
bool isEgyptianNumber = phoneNumber.startsWith('+20');
// print('dfdf${phoneNumber.toString().split('+2')[1]}');
if (isEgyptianNumber && phoneNumber.length == 13) {
// Check if the phone number is already verified
var responseChecker = await CRUD().post(
link: AppLink.checkPhoneNumberISVerfiedPassenger,
payload: {
'phone_number': phoneNumber,
'email': box.read(BoxName.email),
});
if (responseCheker != 'failure') {
var d = jsonDecode(responseCheker);
if (d['message'][0]['verified'].toString() == '1') {
Get.snackbar('Phone number is verified before'.tr, '',
backgroundColor: AppColor.greenColor);
box.write(BoxName.isVerified, '1');
box.write(BoxName.phone, '+2${phoneController.text}');
Get.offAll(const MapPagePassenger());
} else {
await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: {
'phone_number': '+2${phoneController.text}',
'token': randomNumber.toString(),
});
},
);
await smsEgyptController.sendSmsEgypt(
phoneController.text.toString(), randomNumber.toString());
isSent = true;
remainingTime = 300; // Reset to 5 minutes
startTimer();
isLoading = false;
update();
}
if (responseChecker != 'failure') {
var data = jsonDecode(responseChecker);
// If the phone number is already verified
if (data['message'][0]['verified'].toString() == '1') {
Get.snackbar('Phone number is verified before'.tr, '',
backgroundColor: AppColor.greenColor);
box.write(BoxName.isVerified, '1');
box.write(BoxName.phone, phoneNumber);
Get.offAll(const MapPagePassenger());
} else {
await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: {
'phone_number': '+2${phoneController.text}',
'token': randomNumber.toString(),
});
await smsEgyptController.sendSmsEgypt(
phoneController.text.toString(), randomNumber.toString());
isSent = true;
remainingTime = 300; // Reset to 5 minutes
startTimer();
isLoading = false;
update();
// Get.snackbar(responseCheker, 'message');
// If the phone number is not verified, send OTP
if (isEgyptianNumber) {
if (isValidEgyptianPhoneNumber(
phoneNumber.toString().split('+2')[1])) {
await sendOtp(phoneNumber, randomNumber, isEgyptianNumber,
smsEgyptController);
}
}
}
} else if (isValidPhoneNumber(phoneController.text)) {
await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: {
'phone_number': '+${phoneController.text}',
'token': randomNumber.toString(),
});
await smsEgyptController.sendWhatsAppAuth(
phoneController.text, randomNumber.toString());
// await smsEgyptController.sendSmsEgypt(
// phoneController.text.toString(), randomNumber.toString());
isSent = true;
remainingTime = 300; // Reset to 5 minutes
startTimer();
isLoading = false;
update();
} else {
Get.snackbar('Phone Number wrong'.tr, '',
backgroundColor: AppColor.redColor,
duration: const Duration(seconds: 5));
// If verification check fails, still send OTP
if (isEgyptianNumber) {
if (isValidEgyptianPhoneNumber(
phoneNumber.toString().split('+2')[1])) {
await sendOtp(phoneNumber, randomNumber, isEgyptianNumber,
smsEgyptController);
} else {
MyDialog().getDialog(
'Error'.tr, "Phone number isn't an Egyptian phone number".tr,
() {
Get.back();
});
}
}
}
} else {
// MyDialog().getDialog(
// 'Error'.tr, 'Phone number must be exactly 11 digits long'.tr, () {
// Get.back();
// });
sendOtp(
phoneNumber, randomNumber, isEgyptianNumber, smsEgyptController);
print(phoneNumber);
}
} catch (e) {
// Handle error
print('Error: $e');
} finally {
isLoading = false;
update();
}
}
// Helper function to send OTP or WhatsApp message based on phone number location
Future<void> sendOtp(String phoneNumber, int otp, bool isEgyptian,
SmsEgyptController controller) async {
// Trim any leading or trailing whitespace from the phone number
phoneNumber = phoneNumber.trim();
Log.print('phoneNumber: ${phoneNumber}');
if (isEgyptian) {
// Check if the phone number has exactly 11 digits
if (phoneNumber.length == 11 &&
RegExp(r'^\d{11}$').hasMatch(phoneNumber)) {
// Send SMS for Egyptian phone numbers
await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: {
'phone_number': phoneNumber,
'token': otp.toString(),
});
await controller.sendSmsEgypt(phoneNumber, otp.toString());
print('SMS sent to Egyptian phone number: $phoneNumber');
} else {
// Show error dialog if phone number is invalid
MyDialog().getDialog('Invalid Phone Number',
'The phone number must be exactly 11 digits long.', () {
Get.back();
});
}
} else {
// Send WhatsApp message for non-Egyptian phone numbers
await CRUD().sendWhatsAppAuth(phoneNumber, otp.toString());
print('WhatsApp message sent to non-Egyptian phone number: $phoneNumber');
}
isSent = true;
remainingTime = 300; // Reset to 5 minutes
startTimer();
}
verifySMSCode() async {
// if (formKey3.currentState!.validate()) {
if (isValidEgyptianPhoneNumber(phoneController.text)) {

View File

@@ -9,6 +9,7 @@ import 'package:SEFER/env/env.dart';
import '../../constant/api_key.dart';
import '../../print.dart';
import '../../views/widgets/elevated_btn.dart';
import 'upload_image.dart';
class CRUD {
@@ -71,6 +72,54 @@ class CRUD {
}
}
Future sendWhatsAppAuth(String to, String token) async {
var headers = {
'Authorization': 'Bearer ${Env.whatsapp}',
'Content-Type': 'application/json'
};
var request = http.Request(
'POST',
Uri.parse(
'https://graph.facebook.com/v20.0/${Env.whatappID}/messages'));
request.body = json.encode({
"messaging_product": "whatsapp",
"to": to, //"962798583052",
"type": "template",
"template": {
"name": "sefer1",
"language": {"code": "en"},
"components": [
{
"type": "body",
"parameters": [
{
"type": "text",
"text": token,
}
]
}
]
}
});
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
Get.defaultDialog(
title: 'You will receive a code in WhatsApp Messenger'.tr,
middleText: '',
confirm: MyElevatedButton(
title: 'OK'.tr,
onPressed: () {
Get.back();
}));
} else {
print(response.reasonPhrase);
}
}
Future<dynamic> getAgoraToken({
required String channelName,
required String uid,

View File

@@ -64,6 +64,12 @@ void showUpdateDialog(BuildContext context) {
Navigator.of(context).pop();
},
),
CupertinoDialogAction(
child: Text('Cancel'.tr),
onPressed: () async {
Navigator.of(context).pop();
},
),
],
);
},

View File

@@ -233,7 +233,7 @@ class MapPassengerController extends GetxController {
late double totalPassengerSpeedDiscount = 0;
late double totalPassengerBalashDiscount = 0;
late double totalPassengerRaihGaiDiscount = 0;
late double totalPassengerMotoDelivery = 0;
late double totalPassengerScooter = 0;
late double totalDriver = 0;
late double averageDuration = 0;
late double costDuration = 0;
@@ -3269,6 +3269,8 @@ class MapPassengerController extends GetxController {
double totalPassengerBalash = 0;
double totalPassengerLady = 0;
double totalPassengerRayehGai = 0;
double totalPassengerRayehGaiComfort = 0;
double totalPassengerRayehGaiBalash = 0;
Future bottomSheet() async {
if (data.isNotEmpty) {
durationToAdd = Duration(seconds: durationToRide);
@@ -3285,9 +3287,40 @@ class MapPassengerController extends GetxController {
costDelivery,
costBalash,
costLady,
costRayehGai = 0;
costRayehGai,
costRayehGaiBalash,
costRayehGaiComfort = 0;
update();
if (currentTime.hour >= 22 && currentTime.hour < 5) {
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;
update();
} else if (currentTime.hour >= 21 && currentTime.hour < 0) {
// costDistance = distance * latePrice;
costComfort = (distance * comfortPrice) + costDuration * latePrice;
costSpeed = (distance * speedPrice) + costDuration * latePrice;
@@ -3297,9 +3330,65 @@ class MapPassengerController extends GetxController {
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;
update();
} else if (currentTime.hour >= 13 && currentTime.hour <= 16) {
} 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;
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;
update();
} else if (currentTime.hour >= 14 && currentTime.hour <= 17) {
// if (averageDuration > 2.5) {
// costDistance = distance * heavyPrice;
costComfort = (distance * comfortPrice) + costDuration * heavyPrice;
@@ -3310,6 +3399,12 @@ class MapPassengerController extends GetxController {
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;
update();
// } /
@@ -3323,6 +3418,12 @@ class MapPassengerController extends GetxController {
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();
}
@@ -3338,6 +3439,12 @@ class MapPassengerController extends GetxController {
(costBalash + (costBalash * kazan / 100)).ceilToDouble();
totalPassengerRayehGai =
(costRayehGai + (costRayehGai * kazan / 100)).ceilToDouble();
totalPassengerRayehGaiComfort =
(costRayehGaiComfort + (costRayehGaiComfort * kazan / 100))
.ceilToDouble();
totalPassengerRayehGaiBalash =
(costRayehGaiBalash + (costRayehGaiBalash * kazan / 100))
.ceilToDouble();
totalPassengerComfortDiscount =
totalPassengerComfort + totalPassengerComfort * (kazan - 0) / 100;
totalPassengerLadyDiscount =
@@ -3348,7 +3455,7 @@ class MapPassengerController extends GetxController {
totalPassengerBalash + totalPassengerBalash * (kazan) / 100;
totalPassengerRaihGaiDiscount =
totalPassengerRayehGai + totalPassengerRayehGai * (kazan) / 100;
totalPassengerMotoDelivery =
totalPassengerScooter =
(costDelivery + (costDelivery * kazan / 100)).ceilToDouble();
totalPassengerComfort = totalPassengerComfortDiscount -
(totalPassengerComfortDiscount * kazan / 100);
@@ -3369,7 +3476,7 @@ class MapPassengerController extends GetxController {
totalPassengerBalash = 20;
totalPassengerComfort = 30;
totalPassengerLady = 30;
totalPassengerMotoDelivery = 18;
totalPassengerScooter = 18;
} else {
totalPassenger = totalCostPassenger;
update();
@@ -3383,7 +3490,9 @@ class MapPassengerController extends GetxController {
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
totalPassengerBalash = totalPassengerBalash +
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
totalPassengerMotoDelivery = totalPassengerMotoDelivery +
totalPassengerScooter = totalPassengerScooter +
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
totalPassengerRayehGai = totalPassengerScooter +
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
update();
}
@@ -3620,7 +3729,7 @@ class MapPassengerController extends GetxController {
addCustomStepIcon();
addCustomStartIcon();
addCustomEndIcon();
await getLocation();
getLocation();
// await addToken();
getKazanPercent();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,168 @@
import 'package:SEFER/controller/local/phone_intel/helpers.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'countries.dart';
class PickerDialogStyle {
final Color? backgroundColor;
final TextStyle? countryCodeStyle;
final TextStyle? countryNameStyle;
final Widget? listTileDivider;
final EdgeInsets? listTilePadding;
final EdgeInsets? padding;
final Color? searchFieldCursorColor;
final InputDecoration? searchFieldInputDecoration;
final EdgeInsets? searchFieldPadding;
final double? width;
PickerDialogStyle({
this.backgroundColor,
this.countryCodeStyle,
this.countryNameStyle,
this.listTileDivider,
this.listTilePadding,
this.padding,
this.searchFieldCursorColor,
this.searchFieldInputDecoration,
this.searchFieldPadding,
this.width,
});
}
class CountryPickerDialog extends StatefulWidget {
final List<Country> countryList;
final Country selectedCountry;
final ValueChanged<Country> onCountryChanged;
final String searchText;
final List<Country> filteredCountries;
final PickerDialogStyle? style;
final String languageCode;
const CountryPickerDialog({
Key? key,
required this.searchText,
required this.languageCode,
required this.countryList,
required this.onCountryChanged,
required this.selectedCountry,
required this.filteredCountries,
this.style,
}) : super(key: key);
@override
State<CountryPickerDialog> createState() => _CountryPickerDialogState();
}
class _CountryPickerDialogState extends State<CountryPickerDialog> {
late List<Country> _filteredCountries;
late Country _selectedCountry;
@override
void initState() {
_selectedCountry = widget.selectedCountry;
_filteredCountries = widget.filteredCountries.toList()
..sort(
(a, b) => a
.localizedName(widget.languageCode)
.compareTo(b.localizedName(widget.languageCode)),
);
super.initState();
}
@override
Widget build(BuildContext context) {
final mediaWidth = MediaQuery.of(context).size.width;
final width = widget.style?.width ?? mediaWidth;
const defaultHorizontalPadding = 40.0;
const defaultVerticalPadding = 24.0;
return Dialog(
insetPadding: EdgeInsets.symmetric(
vertical: defaultVerticalPadding,
horizontal: mediaWidth > (width + defaultHorizontalPadding * 2)
? (mediaWidth - width) / 2
: defaultHorizontalPadding),
backgroundColor: widget.style?.backgroundColor,
child: Container(
padding: widget.style?.padding ?? const EdgeInsets.all(10),
child: Column(
children: <Widget>[
Padding(
padding:
widget.style?.searchFieldPadding ?? const EdgeInsets.all(0),
child: TextField(
cursorColor: widget.style?.searchFieldCursorColor,
decoration: widget.style?.searchFieldInputDecoration ??
InputDecoration(
suffixIcon: const Icon(Icons.search),
labelText: widget.searchText,
),
onChanged: (value) {
_filteredCountries = widget.countryList.stringSearch(value)
..sort(
(a, b) => a
.localizedName(widget.languageCode)
.compareTo(b.localizedName(widget.languageCode)),
);
if (mounted) setState(() {});
},
),
),
const SizedBox(height: 20),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: _filteredCountries.length,
itemBuilder: (ctx, index) => Column(
children: <Widget>[
ListTile(
leading: kIsWeb
? Image.asset(
'assets/flags/${_filteredCountries[index].code.toLowerCase()}.png',
package: 'intl_phone_field',
width: 32,
)
: Text(
_filteredCountries[index].flag,
style: const TextStyle(fontSize: 18),
),
contentPadding: widget.style?.listTilePadding,
title: Text(
_filteredCountries[index]
.localizedName(widget.languageCode),
style: widget.style?.countryNameStyle ??
const TextStyle(fontWeight: FontWeight.w700),
),
trailing: Text(
'+${_filteredCountries[index].dialCode}',
style: widget.style?.countryCodeStyle ??
const TextStyle(fontWeight: FontWeight.w700),
),
onTap: () {
_selectedCountry = _filteredCountries[index];
widget.onCountryChanged(_selectedCountry);
Navigator.of(context).pop();
},
),
widget.style?.listTileDivider ??
const Divider(thickness: 1),
],
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,31 @@
import 'countries.dart';
bool isNumeric(String s) =>
s.isNotEmpty && int.tryParse(s.replaceAll("+", "")) != null;
String removeDiacritics(String str) {
var withDia =
'ÀÁÂÃÄÅàáâãäåÒÓÔÕÕÖØòóôõöøÈÉÊËèéêëðÇçÐÌÍÎÏìíîïÙÚÛÜùúûüÑñŠšŸÿýŽž';
var withoutDia =
'AAAAAAaaaaaaOOOOOOOooooooEEEEeeeeeCcDIIIIiiiiUUUUuuuuNnSsYyyZz';
for (int i = 0; i < withDia.length; i++) {
str = str.replaceAll(withDia[i], withoutDia[i]);
}
return str;
}
extension CountryExtensions on List<Country> {
List<Country> stringSearch(String search) {
search = removeDiacritics(search.toLowerCase());
return where(
(country) => isNumeric(search) || search.startsWith("+")
? country.dialCode.contains(search)
: removeDiacritics(country.name.replaceAll("+", "").toLowerCase())
.contains(search) ||
country.nameTranslations.values.any((element) =>
removeDiacritics(element.toLowerCase()).contains(search)),
).toList();
}
}

View File

@@ -0,0 +1,521 @@
library intl_phone_field;
import 'dart:async';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import './countries.dart';
import './phone_number.dart';
import 'country_picker_dialog.dart';
import 'helpers.dart';
class IntlPhoneField extends StatefulWidget {
/// The TextFormField key.
final GlobalKey<FormFieldState>? formFieldKey;
/// Whether to hide the text being edited (e.g., for passwords).
final bool obscureText;
/// How the text should be aligned horizontally.
final TextAlign textAlign;
/// How the text should be aligned vertically.
final TextAlignVertical? textAlignVertical;
final VoidCallback? onTap;
/// {@macro flutter.widgets.editableText.readOnly}
final bool readOnly;
final FormFieldSetter<PhoneNumber>? onSaved;
/// {@macro flutter.widgets.editableText.onChanged}
///
/// See also:
///
/// * [inputFormatters], which are called before [onChanged]
/// runs and can validate and change ("format") the input value.
/// * [onEditingComplete], [onSubmitted], [onSelectionChanged]:
/// which are more specialized input change notifications.
final ValueChanged<PhoneNumber>? onChanged;
final ValueChanged<Country>? onCountryChanged;
/// An optional method that validates an input. Returns an error string to display if the input is invalid, or null otherwise.
///
/// A [PhoneNumber] is passed to the validator as argument.
/// The validator can handle asynchronous validation when declared as a [Future].
/// Or run synchronously when declared as a [Function].
///
/// By default, the validator checks whether the input number length is between selected country's phone numbers min and max length.
/// If `disableLengthCheck` is not set to `true`, your validator returned value will be overwritten by the default validator.
/// But, if `disableLengthCheck` is set to `true`, your validator will have to check phone number length itself.
final FutureOr<String?> Function(PhoneNumber?)? validator;
/// {@macro flutter.widgets.editableText.keyboardType}
final TextInputType keyboardType;
/// Controls the text being edited.
///
/// If null, this widget will create its own [TextEditingController].
final TextEditingController? controller;
/// Defines the keyboard focus for this widget.
///
/// The [focusNode] is a long-lived object that's typically managed by a
/// [StatefulWidget] parent. See [FocusNode] for more information.
///
/// To give the keyboard focus to this widget, provide a [focusNode] and then
/// use the current [FocusScope] to request the focus:
///
/// ```dart
/// FocusScope.of(context).requestFocus(myFocusNode);
/// ```
///
/// This happens automatically when the widget is tapped.
///
/// To be notified when the widget gains or loses the focus, add a listener
/// to the [focusNode]:
///
/// ```dart
/// focusNode.addListener(() { print(myFocusNode.hasFocus); });
/// ```
///
/// If null, this widget will create its own [FocusNode].
///
/// ## Keyboard
///
/// Requesting the focus will typically cause the keyboard to be shown
/// if it's not showing already.
///
/// On Android, the user can hide the keyboard - without changing the focus -
/// with the system back button. They can restore the keyboard's visibility
/// by tapping on a text field. The user might hide the keyboard and
/// switch to a physical keyboard, or they might just need to get it
/// out of the way for a moment, to expose something it's
/// obscuring. In this case requesting the focus again will not
/// cause the focus to change, and will not make the keyboard visible.
///
/// This widget builds an [EditableText] and will ensure that the keyboard is
/// showing when it is tapped by calling [EditableTextState.requestKeyboard()].
final FocusNode? focusNode;
/// {@macro flutter.widgets.editableText.onSubmitted}
///
/// See also:
///
/// * [EditableText.onSubmitted] for an example of how to handle moving to
/// the next/previous field when using [TextInputAction.next] and
/// [TextInputAction.previous] for [textInputAction].
final void Function(String)? onSubmitted;
/// If false the widget is "disabled": it ignores taps, the [TextFormField]'s
/// [decoration] is rendered in grey,
/// [decoration]'s [InputDecoration.counterText] is set to `""`,
/// and the drop down icon is hidden no matter [showDropdownIcon] value.
///
/// If non-null this property overrides the [decoration]'s
/// [Decoration.enabled] property.
final bool enabled;
/// The appearance of the keyboard.
///
/// This setting is only honored on iOS devices.
///
/// If unset, defaults to the brightness of [ThemeData.brightness].
final Brightness? keyboardAppearance;
/// Initial Value for the field.
/// This property can be used to pre-fill the field.
final String? initialValue;
final String languageCode;
/// 2 letter ISO Code or country dial code.
///
/// ```dart
/// initialCountryCode: 'IN', // India
/// initialCountryCode: '+225', // Côte d'Ivoire
/// ```
final String? initialCountryCode;
/// List of Country to display see countries.dart for format
final List<Country>? countries;
/// The decoration to show around the text field.
///
/// By default, draws a horizontal line under the text field but can be
/// configured to show an icon, label, hint text, and error text.
///
/// Specify null to remove the decoration entirely (including the
/// extra padding introduced by the decoration to save space for the labels).
final InputDecoration decoration;
/// The style to use for the text being edited.
///
/// This text style is also used as the base style for the [decoration].
///
/// If null, defaults to the `subtitle1` text style from the current [Theme].
final TextStyle? style;
/// Disable view Min/Max Length check
final bool disableLengthCheck;
/// Won't work if [enabled] is set to `false`.
final bool showDropdownIcon;
final BoxDecoration dropdownDecoration;
/// The style use for the country dial code.
final TextStyle? dropdownTextStyle;
/// {@macro flutter.widgets.editableText.inputFormatters}
final List<TextInputFormatter>? inputFormatters;
/// The text that describes the search input field.
///
/// When the input field is empty and unfocused, the label is displayed on top of the input field (i.e., at the same location on the screen where text may be entered in the input field).
/// When the input field receives focus (or if the field is non-empty), the label moves above (i.e., vertically adjacent to) the input field.
final String searchText;
/// Position of an icon [leading, trailing]
final IconPosition dropdownIconPosition;
/// Icon of the drop down button.
///
/// Default is [Icon(Icons.arrow_drop_down)]
final Icon dropdownIcon;
/// Whether this text field should focus itself if nothing else is already focused.
final bool autofocus;
/// Autovalidate mode for text form field.
///
/// If [AutovalidateMode.onUserInteraction], this FormField will only auto-validate after its content changes.
/// If [AutovalidateMode.always], it will auto-validate even without user interaction.
/// If [AutovalidateMode.disabled], auto-validation will be disabled.
///
/// Defaults to [AutovalidateMode.onUserInteraction].
final AutovalidateMode? autovalidateMode;
/// Whether to show or hide country flag.
///
/// Default value is `true`.
final bool showCountryFlag;
/// Message to be displayed on autoValidate error
///
/// Default value is `Invalid Mobile Number`.
final String? invalidNumberMessage;
/// The color of the cursor.
final Color? cursorColor;
/// How tall the cursor will be.
final double? cursorHeight;
/// How rounded the corners of the cursor should be.
final Radius? cursorRadius;
/// How thick the cursor will be.
final double cursorWidth;
/// Whether to show cursor.
final bool? showCursor;
/// The padding of the Flags Button.
///
/// The amount of insets that are applied to the Flags Button.
///
/// If unset, defaults to [EdgeInsets.zero].
final EdgeInsetsGeometry flagsButtonPadding;
/// The type of action button to use for the keyboard.
final TextInputAction? textInputAction;
/// Optional set of styles to allow for customizing the country search
/// & pick dialog
final PickerDialogStyle? pickerDialogStyle;
/// The margin of the country selector button.
///
/// The amount of space to surround the country selector button.
///
/// If unset, defaults to [EdgeInsets.zero].
final EdgeInsets flagsButtonMargin;
/// Enable the autofill hint for phone number.
final bool disableAutoFillHints;
/// If null, default magnification configuration will be used.
final TextMagnifierConfiguration? magnifierConfiguration;
const IntlPhoneField({
Key? key,
this.formFieldKey,
this.initialCountryCode,
this.languageCode = 'en',
this.disableAutoFillHints = false,
this.obscureText = false,
this.textAlign = TextAlign.left,
this.textAlignVertical,
this.onTap,
this.readOnly = false,
this.initialValue,
this.keyboardType = TextInputType.phone,
this.controller,
this.focusNode,
this.decoration = const InputDecoration(),
this.style,
this.dropdownTextStyle,
this.onSubmitted,
this.validator,
this.onChanged,
this.countries,
this.onCountryChanged,
this.onSaved,
this.showDropdownIcon = true,
this.dropdownDecoration = const BoxDecoration(),
this.inputFormatters,
this.enabled = true,
this.keyboardAppearance,
@Deprecated('Use searchFieldInputDecoration of PickerDialogStyle instead')
this.searchText = 'Search country',
this.dropdownIconPosition = IconPosition.leading,
this.dropdownIcon = const Icon(Icons.arrow_drop_down),
this.autofocus = false,
this.textInputAction,
this.autovalidateMode = AutovalidateMode.onUserInteraction,
this.showCountryFlag = true,
this.cursorColor,
this.disableLengthCheck = false,
this.flagsButtonPadding = EdgeInsets.zero,
this.invalidNumberMessage = 'Invalid Mobile Number',
this.cursorHeight,
this.cursorRadius = Radius.zero,
this.cursorWidth = 2.0,
this.showCursor = true,
this.pickerDialogStyle,
this.flagsButtonMargin = EdgeInsets.zero,
this.magnifierConfiguration,
}) : super(key: key);
@override
State<IntlPhoneField> createState() => _IntlPhoneFieldState();
}
class _IntlPhoneFieldState extends State<IntlPhoneField> {
late List<Country> _countryList;
late Country _selectedCountry;
late List<Country> filteredCountries;
late String number;
String? validatorMessage;
@override
void initState() {
super.initState();
_countryList = widget.countries ?? countries;
filteredCountries = _countryList;
number = widget.initialValue ?? '';
if (widget.initialCountryCode == null && number.startsWith('+')) {
number = number.substring(1);
// parse initial value
_selectedCountry = countries.firstWhere(
(country) => number.startsWith(country.fullCountryCode),
orElse: () => _countryList.first);
// remove country code from the initial number value
number = number.replaceFirst(
RegExp("^${_selectedCountry.fullCountryCode}"), "");
} else {
_selectedCountry = _countryList.firstWhere(
(item) => item.code == (widget.initialCountryCode ?? 'US'),
orElse: () => _countryList.first);
// remove country code from the initial number value
if (number.startsWith('+')) {
number = number.replaceFirst(
RegExp("^\\+${_selectedCountry.fullCountryCode}"), "");
} else {
number = number.replaceFirst(
RegExp("^${_selectedCountry.fullCountryCode}"), "");
}
}
if (widget.autovalidateMode == AutovalidateMode.always) {
final initialPhoneNumber = PhoneNumber(
countryISOCode: _selectedCountry.code,
countryCode: '+${_selectedCountry.dialCode}',
number: widget.initialValue ?? '',
);
final value = widget.validator?.call(initialPhoneNumber);
if (value is String) {
validatorMessage = value;
} else {
(value as Future).then((msg) {
validatorMessage = msg;
});
}
}
}
Future<void> _changeCountry() async {
filteredCountries = _countryList;
await showDialog(
context: context,
useRootNavigator: false,
builder: (context) => StatefulBuilder(
builder: (ctx, setState) => CountryPickerDialog(
languageCode: widget.languageCode.toLowerCase(),
style: widget.pickerDialogStyle,
filteredCountries: filteredCountries,
searchText: widget.searchText,
countryList: _countryList,
selectedCountry: _selectedCountry,
onCountryChanged: (Country country) {
_selectedCountry = country;
widget.onCountryChanged?.call(country);
setState(() {});
},
),
),
);
if (mounted) setState(() {});
}
@override
Widget build(BuildContext context) {
return TextFormField(
key: widget.formFieldKey,
initialValue: (widget.controller == null) ? number : null,
autofillHints: widget.disableAutoFillHints
? null
: [AutofillHints.telephoneNumberNational],
readOnly: widget.readOnly,
obscureText: widget.obscureText,
textAlign: widget.textAlign,
textAlignVertical: widget.textAlignVertical,
cursorColor: widget.cursorColor,
onTap: widget.onTap,
controller: widget.controller,
focusNode: widget.focusNode,
cursorHeight: widget.cursorHeight,
cursorRadius: widget.cursorRadius,
cursorWidth: widget.cursorWidth,
showCursor: widget.showCursor,
onFieldSubmitted: widget.onSubmitted,
magnifierConfiguration: widget.magnifierConfiguration,
decoration: widget.decoration.copyWith(
prefixIcon: _buildFlagsButton(),
counterText: !widget.enabled ? '' : null,
),
style: widget.style,
onSaved: (value) {
widget.onSaved?.call(
PhoneNumber(
countryISOCode: _selectedCountry.code,
countryCode:
'+${_selectedCountry.dialCode}${_selectedCountry.regionCode}',
number: value!,
),
);
},
onChanged: (value) async {
final phoneNumber = PhoneNumber(
countryISOCode: _selectedCountry.code,
countryCode: '+${_selectedCountry.fullCountryCode}',
number: value,
);
if (widget.autovalidateMode != AutovalidateMode.disabled) {
validatorMessage = await widget.validator?.call(phoneNumber);
}
widget.onChanged?.call(phoneNumber);
},
validator: (value) {
if (value == null || !isNumeric(value)) return validatorMessage;
if (!widget.disableLengthCheck) {
return value.length >= _selectedCountry.minLength &&
value.length <= _selectedCountry.maxLength
? null
: widget.invalidNumberMessage;
}
return validatorMessage;
},
maxLength: widget.disableLengthCheck ? null : _selectedCountry.maxLength,
keyboardType: widget.keyboardType,
inputFormatters: widget.inputFormatters,
enabled: widget.enabled,
keyboardAppearance: widget.keyboardAppearance,
autofocus: widget.autofocus,
textInputAction: widget.textInputAction,
autovalidateMode: widget.autovalidateMode,
);
}
Container _buildFlagsButton() {
return Container(
margin: widget.flagsButtonMargin,
child: DecoratedBox(
decoration: widget.dropdownDecoration,
child: InkWell(
borderRadius: widget.dropdownDecoration.borderRadius as BorderRadius?,
onTap: widget.enabled ? _changeCountry : null,
child: Padding(
padding: widget.flagsButtonPadding,
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const SizedBox(
width: 4,
),
if (widget.enabled &&
widget.showDropdownIcon &&
widget.dropdownIconPosition == IconPosition.leading) ...[
widget.dropdownIcon,
const SizedBox(width: 4),
],
if (widget.showCountryFlag) ...[
kIsWeb
? Image.asset(
'assets/flags/${_selectedCountry.code.toLowerCase()}.png',
package: 'intl_phone_field',
width: 32,
)
: Text(
_selectedCountry.flag,
style: const TextStyle(fontSize: 18),
),
const SizedBox(width: 8),
],
FittedBox(
child: Text(
'+${_selectedCountry.dialCode}',
style: widget.dropdownTextStyle,
),
),
if (widget.enabled &&
widget.showDropdownIcon &&
widget.dropdownIconPosition == IconPosition.trailing) ...[
const SizedBox(width: 4),
widget.dropdownIcon,
],
const SizedBox(width: 8),
],
),
),
),
),
);
}
}
enum IconPosition {
leading,
trailing,
}

View File

@@ -0,0 +1,79 @@
import 'countries.dart';
class NumberTooLongException implements Exception {}
class NumberTooShortException implements Exception {}
class InvalidCharactersException implements Exception {}
class PhoneNumber {
String countryISOCode;
String countryCode;
String number;
PhoneNumber({
required this.countryISOCode,
required this.countryCode,
required this.number,
});
factory PhoneNumber.fromCompleteNumber({required String completeNumber}) {
if (completeNumber == "") {
return PhoneNumber(countryISOCode: "", countryCode: "", number: "");
}
try {
Country country = getCountry(completeNumber);
String number;
if (completeNumber.startsWith('+')) {
number = completeNumber.substring(1 + country.dialCode.length + country.regionCode.length);
} else {
number = completeNumber.substring(country.dialCode.length + country.regionCode.length);
}
return PhoneNumber(
countryISOCode: country.code, countryCode: country.dialCode + country.regionCode, number: number);
} on InvalidCharactersException {
rethrow;
// ignore: unused_catch_clause
} on Exception catch (e) {
return PhoneNumber(countryISOCode: "", countryCode: "", number: "");
}
}
bool isValidNumber() {
Country country = getCountry(completeNumber);
if (number.length < country.minLength) {
throw NumberTooShortException();
}
if (number.length > country.maxLength) {
throw NumberTooLongException();
}
return true;
}
String get completeNumber {
return countryCode + number;
}
static Country getCountry(String phoneNumber) {
if (phoneNumber == "") {
throw NumberTooShortException();
}
final validPhoneNumber = RegExp(r'^[+0-9]*[0-9]*$');
if (!validPhoneNumber.hasMatch(phoneNumber)) {
throw InvalidCharactersException();
}
if (phoneNumber.startsWith('+')) {
return countries
.firstWhere((country) => phoneNumber.substring(1).startsWith(country.dialCode + country.regionCode));
}
return countries.firstWhere((country) => phoneNumber.startsWith(country.dialCode + country.regionCode));
}
@override
String toString() => 'PhoneNumber(countryISOCode: $countryISOCode, countryCode: $countryCode, number: $number)';
}

View File

@@ -5,6 +5,10 @@ class MyTranslation extends Translations {
Map<String, Map<String, String>> get keys => {
"ar": {
"Update Available": "تحديث متوفر",
'Phone number must be exactly 11 digits long':
"رقم الهاتف يجب أن يكون بطول 11 رقماً",
"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":
@@ -154,11 +158,15 @@ iOS [https://getapp.cc/app/6458734951]
"You have call from driver": " لديك مكالمة من السائق",
"Comfort": "كمفورت",
"Speed": "سبيد",
"Driver already has 2 trips within the specified period.":
'السائق لديه بالفعل رحلتان خلال الفترة المحددة.',
"The invitation was sent successfully": "تم إرسال الدعوة بنجاح",
"Lady": "ليدي",
"You should select your country": "يجب عليك اختيار بلدك",
"Delivery": "توصيل",
"Mashwari": "‏مشواري",
"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': "نبذة عنا",
@@ -592,7 +600,7 @@ iOS [https://getapp.cc/app/6458734951]
'الرَّجَاء التَّحَرُّك إِلَى السَّيَّارَة الآن',
'You will receive a code in WhatsApp Messenger':
"سوف تتلقى رمزًا في واتساب ماسنجر",
'Balash': 'أوفر كار',
'Awfar Car': 'أوفر كار',
"Old and affordable, perfect for budget rides.":
"سيارة ميسورة التكلفة، مثالية للرحلات الاقتصادية.",
" If you need to reach me, please contact the driver directly at":
@@ -740,7 +748,7 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": 'وَقْتُ الْوُصُولِ ',
"arrival time to reach your point":
'الْوَقْتُ المُتَوَقَّعُ لِلْوُصُولِ إِلَى وَجْهَتِكَ ',
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
'بِالنِّسْبَةِ لِرِحْلَاتِ السُّرْعَةِ وَالتَّوْصِيلِ، يَتِمُّ حِسَابُ السِّعْرِ بِشَكْلٍ دِينَامِيكِيٍّ. أَمَّا بِالنِّسْبَةِ لِرِحْلَاتِ الرَّاحَةِ، فَيَتِمُّ حِسَابُ السِّعْرِ بِنَاءً عَلَى الْوَقْتِ وَالْمَسَافَةِ.',
"Hello this is Driver": "مَرْحَبًا هَذَا السَّائِقُ",
"Is the Passenger in your Car ?": "هَلِ الرَّاكِبُ فِي سَيَّارَتِكَ؟",
@@ -762,7 +770,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"رحلة مكيفة ومسار متغير لرغبة العميل ونقاط توقف",
"Insert": "إِدْرَاجُ",
"This is for delivery or a motorcycle.":
"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":
'‏رحلة محددة السعر والشريك السائق ملتزم بالمسار المحدد من خلال التطبيق',
@@ -801,6 +809,7 @@ iOS [https://getapp.cc/app/6458734951]
"الرَّجَاء الْمُسَاعَدَة! اِتَّصِل بِي فِي أَقْرَب وَقْت مُمْكِن",
"Share Trip Details": "مُشَارَكَة تَفَاصِيل الرِّحْلَة",
"Car Plate is ": "‏رَقْم اللَّوْحَة",
"VIP Order": "طلب VIP",
"the 300 points equal 300 L.E for you \nSo go and gain your money":
"اِرْبَح ٣٠٠ جُنَيه! كُلّ ٣٠٠ نُقْطَة تُمْنِحُك ٣٠٠ جُنَيه. اِذْهَب وَاِسْتَفِد مِن نُقَاطِك!",
"the 300 points equal 300 L.E":
@@ -809,6 +818,7 @@ iOS [https://getapp.cc/app/6458734951]
'لم يتم الموافقة على الدفع. الرجاء المحاولة مرة أخرى.',
"Payment Failed": 'فشل الدفع',
"Error": 'خطأ',
'This is a scheduled notification.': "هذا إشعار مجدول.",
"An error occurred during the payment process.":
'حدث خطأ أثناء عملية الدفع.',
"The payment was approved.": 'تمت الموافقة على الدفع.',
@@ -923,10 +933,17 @@ iOS [https://getapp.cc/app/6458734951]
"Payment History": "تاريخ المدفوعات",
"Show Promos to Charge": "إظهار العروض للشحن",
"Point": "نقطة",
'How many hours would you like to wait?':
"كم عدد الساعات التي تود الانتظار؟",
"Driver Wallet": "محفظة السائق",
"Choose between those Type Cars":
'اختر من بين أنواع السيارات التالية',
"hour": ' ساعه',
'Select Waiting Hours': "• اختر ساعات الانتظار",
"Total Points is": "إجمالي النقاط هو",
"You will receive a code in SMS message":
"سوف تتلقى رمزًا في رسالة SMS",
"Done": 'تم',
"Total Budget from trips is ": "إجمالي الميزانية من الرحلات هو ",
"Total Amount:": "المبلغ الإجمالي:",
"Total Budget from trips by\nCredit card is ":
@@ -1558,7 +1575,7 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "Varış zamanı",
"arrival time to reach your point":
"varış noktanıza ulaşmak için varış zamanı",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Hızlı ve Teslimat seferlerinde fiyat dinamik olarak hesaplanır. Konfor gezileri için fiyat, zamana ve mesafeye bağlıdır",
"Hello this is Driver": "Merhaba ben Sürücü",
"Is the Passenger in your Car ?": "Yolcu Arabanızda mı?",
@@ -1579,7 +1596,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"Konforlu araç ve esnek rota ve durak noktaları için en iyi seçim",
"Insert": "Sokmak",
"This is for delivery or a motorcycle.":
"This is for scooter or a motorcycle.":
"Bu teslimat veya motosiklet içindir.",
"This trip goes directly from your starting point to your destination for a fixed price. The driver must follow the planned route":
"Bu yolculuk, sabit bir ücret karşılığında doğrudan başlangıç noktanızdan varış noktanıza gider. Sürücü planlanan rotayı takip etmelidir",
@@ -2388,8 +2405,8 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "Heure d'arrivée",
"arrival time to reach your point":
"heure d'arrivée pour atteindre votre point",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Pour les courses Speed et Delivery, le prix est calculé dynamiquement. Pour les trajets Confort, le prix est fonction du temps et de la distance",
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Pour les courses Speed et scooter, le prix est calculé dynamiquement. Pour les trajets Confort, le prix est fonction du temps et de la distance",
"Hello this is Driver": "Bonjour, c'est Driver",
"Is the Passenger in your Car ?":
"Le passager est-il dans votre voiture ?",
@@ -2410,7 +2427,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"Meilleur choix pour une voiture de confort et un itinéraire et un point d'arrêt flexibles",
"Insert": "Insérer",
"This is for delivery or a motorcycle.":
"This is for scooter or a motorcycle.":
"C'est pour une livraison ou une moto.",
"This trip goes directly from your starting point to your destination for a fixed price. The driver must follow the planned route":
"Ce voyage va directement de votre point de départ à votre destination pour un prix fixe. Le chauffeur doit suivre l'itinéraire prévu",
@@ -3230,8 +3247,8 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "Ankunftszeit",
"arrival time to reach your point":
"Ankunftszeit, um Ihren Punkt zu erreichen",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Für Speed- und Delivery-Fahrten wird der Preis dynamisch berechnet. Bei Komfortfahrten richtet sich der Preis nach Zeit und Entfernung",
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Für Speed- und scooter-Fahrten wird der Preis dynamisch berechnet. Bei Komfortfahrten richtet sich der Preis nach Zeit und Entfernung",
"Hello this is Driver": "Hallo, hier ist Driver",
"Is the Passenger in your Car ?":
"Befindet sich der Beifahrer in Ihrem Auto?",
@@ -3252,7 +3269,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"Beste Wahl für ein komfortables Auto und eine flexible Route und Haltestellen",
"Insert": "Einfügen",
"This is for delivery or a motorcycle.":
"This is for scooter or a motorcycle.":
"Dies ist für die Lieferung oder ein Motorrad.",
"This trip goes directly from your starting point to your destination for a fixed price. The driver must follow the planned route":
"Diese Reise führt zum Festpreis direkt von Ihrem Startpunkt zu Ihrem Ziel. Der Fahrer muss der geplanten Route folgen",
@@ -4063,7 +4080,7 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "Hora de llegada",
"arrival time to reach your point":
"Hora de llegada para llegar a tu punto.",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Para viajes de Velocidad y Entrega, el precio se calcula dinámicamente. Para viajes Comfort, el precio se basa en tiempo y distancia.",
"Hello this is Driver": "Hola, este es el conductor.",
"Is the Passenger in your Car ?":
@@ -4085,7 +4102,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"La mejor opción para un vehículo cómodo y una ruta y un punto de parada flexibles",
"Insert": "Insertar",
"This is for delivery or a motorcycle.":
"This is for scooter or a motorcycle.":
"Esto es para entrega o una motocicleta.",
"This trip goes directly from your starting point to your destination for a fixed price. The driver must follow the planned route":
"Este viaje va directamente desde su punto de partida a su destino por un precio fijo. El conductor debe seguir la ruta planificada.",
@@ -4881,7 +4898,7 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "زمان رسیدن",
"arrival time to reach your point":
"زمان رسیدن برای رسیدن به نقطه خود",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"برای سفرهای سرعت و تحویل، قیمت به صورت پویا محاسبه می شود. برای سفرهای Comfort، قیمت بر اساس زمان و مسافت است",
"Hello this is Driver": "سلام این راننده است",
"Is the Passenger in your Car ?": "آیا مسافر در ماشین شماست؟",
@@ -4902,7 +4919,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"بهترین انتخاب برای ماشین راحت و مسیر انعطاف پذیر و نقطه توقف",
"Insert": "درج کنید",
"This is for delivery or a motorcycle.":
"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":
"این سفر مستقیماً از نقطه شروع شما به مقصد شما با قیمت ثابت می رود. راننده باید مسیر برنامه ریزی شده را دنبال کند",
@@ -5708,7 +5725,7 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "Ωρα άφιξης",
"arrival time to reach your point":
"ώρα άφιξης για να φτάσετε στο σημείο σας",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Για ταξίδια Ταχύτητας και Παράδοσης, η τιμή υπολογίζεται δυναμικά. Για Comfort ταξίδια, η τιμή βασίζεται σε χρόνο και απόσταση",
"Hello this is Driver": "Γεια σας, αυτός είναι ο οδηγός",
"Is the Passenger in your Car ?":
@@ -5730,7 +5747,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"Η καλύτερη επιλογή για αυτοκίνητο άνεσης και ευέλικτη διαδρομή και σημείο στάσεων",
"Insert": "Εισάγετε",
"This is for delivery or a motorcycle.":
"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":
"Αυτό το ταξίδι πηγαίνει απευθείας από το σημείο εκκίνησης στον προορισμό σας για μια σταθερή τιμή. Ο οδηγός πρέπει να ακολουθήσει την προγραμματισμένη διαδρομή",
@@ -6539,7 +6556,7 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "آمد کے وقت",
"arrival time to reach your point":
"آپ کے نقطہ تک پہنچنے کے لئے آمد کا وقت",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"سپیڈ اور ڈیلیوری ٹرپس کے لیے، قیمت کا حساب متحرک طور پر کیا جاتا ہے۔ آرام دہ دوروں کے لیے، قیمت وقت اور فاصلے پر مبنی ہے۔",
"Hello this is Driver": "ہیلو یہ ڈرائیور ہے۔",
"Is the Passenger in your Car ?": "کیا مسافر آپ کی گاڑی میں ہے؟",
@@ -6560,7 +6577,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"آرام دہ کار اور لچکدار روٹ اور اسٹاپ پوائنٹ کے لیے بہترین انتخاب",
"Insert": "داخل کریں",
"This is for delivery or a motorcycle.":
"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":
"یہ سفر ایک مقررہ قیمت پر آپ کے نقطہ آغاز سے براہ راست آپ کی منزل تک جاتا ہے۔ ڈرائیور کو منصوبہ بند راستے پر چلنا چاہیے۔",
@@ -7357,7 +7374,7 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "आगमन का समय",
"arrival time to reach your point":
"अपनी बात तक पहुंचने के लिए आगमन का समय",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"स्पीड और डिलीवरी ट्रिप के लिए, कीमत की गणना गतिशील रूप से की जाती है। आरामदायक यात्राओं के लिए, कीमत समय और दूरी पर आधारित होती है",
"Hello this is Driver": "नमस्ते, मैं ड्राइवर हूं",
"Is the Passenger in your Car ?": "क्या यात्री आपकी कार में है?",
@@ -7379,7 +7396,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"आरामदायक कार और लचीले मार्ग और स्टॉप पॉइंट के लिए सर्वोत्तम विकल्प",
"Insert": "डालना",
"This is for delivery or a motorcycle.":
"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":
"यह यात्रा एक निश्चित कीमत पर आपके शुरुआती बिंदु से सीधे आपके गंतव्य तक जाती है। चालक को नियोजित मार्ग का पालन करना होगा",
@@ -8183,7 +8200,7 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "Время прибытия",
"arrival time to reach your point":
"время прибытия, чтобы добраться до вашей точки",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Для поездок «Скорость» и «Доставка» цена рассчитывается динамически. Для поездок Комфорт цена зависит от времени и расстояния.",
"Hello this is Driver": "Привет, это Драйвер",
"Is the Passenger in your Car ?": "Пассажир в вашей машине?",
@@ -8204,7 +8221,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"Лучший выбор для комфортного автомобиля, гибкого маршрута и остановок.",
"Insert": "Вставлять",
"This is for delivery or a motorcycle.":
"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":
"Эта поездка идет прямо от отправной точки до пункта назначения по фиксированной цене. Водитель должен следовать запланированному маршруту",
@@ -9014,8 +9031,8 @@ iOS [https://getapp.cc/app/6458734951]
"Arrival time": "Orario di arrivo",
"arrival time to reach your point":
"orario di arrivo per raggiungere il tuo punto",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Per i viaggi Speed e Delivery il prezzo viene calcolato dinamicamente. Per i viaggi Comfort il prezzo dipende dal tempo e dalla distanza",
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"Per i viaggi Speed e scooter il prezzo viene calcolato dinamicamente. Per i viaggi Comfort il prezzo dipende dal tempo e dalla distanza",
"Hello this is Driver": "Ciao, sono Driver",
"Is the Passenger in your Car ?": "Il passeggero è nella tua auto?",
"Please wait for the passenger to enter the car before starting the trip.":
@@ -9035,7 +9052,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"La scelta migliore per un'auto confortevole e un percorso flessibile e punti di sosta",
"Insert": "Inserire",
"This is for delivery or a motorcycle.":
"This is for scooter or a motorcycle.":
"Questo è per la consegna o una moto.",
"This trip goes directly from your starting point to your destination for a fixed price. The driver must follow the planned route":
"Questo viaggio va direttamente dal tuo punto di partenza alla tua destinazione a un prezzo fisso. L'autista deve seguire il percorso previsto",
@@ -9776,7 +9793,7 @@ iOS [https://getapp.cc/app/6458734951]
"Cost Of Trip IS": "旅行费用是",
"Arrival time": "到达时间",
"arrival time to reach your point": "到达目的地的到达时间",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"For Speed and scooter trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"对于速度和送货行程,价格是动态计算的。对于舒适旅行,价格根据时间和距离而定",
"Hello this is Driver": "你好,这是司机",
"Is the Passenger in your Car ?": "乘客在你的车里吗?",
@@ -9794,7 +9811,7 @@ iOS [https://getapp.cc/app/6458734951]
"Best choice for comfort car and flexible route and stops point":
"舒适用车、灵活路线和停靠点的最佳选择",
"Insert": "插入",
"This is for delivery or a motorcycle.": "这是用于送货或摩托车。",
"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": "您可以拒绝请求,无需支付任何费用",

View File

@@ -1,11 +1,16 @@
import 'package:SEFER/constant/style.dart';
import 'package:SEFER/controller/auth/register_controller.dart';
import 'package:SEFER/views/widgets/elevated_btn.dart';
import 'package:SEFER/views/widgets/my_dialog.dart';
import 'package:SEFER/views/widgets/my_scafold.dart';
import 'package:SEFER/views/widgets/my_textField.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../controller/local/phone_intel/intl_phone_field.dart';
import '../../print.dart';
// import 'package:intl_phone_field/intl_phone_field.dart';
class SmsSignupEgypt extends StatelessWidget {
SmsSignupEgypt({super.key});
@@ -17,7 +22,6 @@ class SmsSignupEgypt extends StatelessWidget {
body: [
GetBuilder<RegisterController>(builder: (registerController) {
return ListView(
// mainAxisAlignment: MainAxisAlignment.center,
children: [
// Logo at the top
Padding(
@@ -38,54 +42,59 @@ class SmsSignupEgypt extends StatelessWidget {
style: AppStyle.title,
),
),
// Enter phone number text
// Phone number input field with country code dropdown
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Text(
'Enter your phone number'.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
padding: const EdgeInsets.all(16.0),
child: IntlPhoneField(
decoration: InputDecoration(
labelText: 'Phone Number'.tr,
border: const OutlineInputBorder(
borderSide: BorderSide(),
),
),
initialCountryCode: 'EG',
onChanged: (phone) {
// Properly concatenate country code and number
registerController.phoneController.text =
phone.completeNumber.toString();
Log.print(' phone.number: ${phone.number}');
print(
"Formatted phone number: ${registerController.phoneController.text}");
},
validator: (phone) {
// Check if the phone number is not null and is valid
if (phone == null || phone.completeNumber.isEmpty) {
return 'Please enter your phone number';
}
// Extract the phone number (excluding the country code)
final number = phone.completeNumber.toString();
// Check if the number length is exactly 11 digits
if (number.length != 13) {
return 'Phone number must be exactly 11 digits long';
}
// If all validations pass, return null
return null;
},
),
),
// Phone number input field
Padding(
padding: const EdgeInsets.all(16.0),
child: !registerController.isSent
? Form(
key: registerController.formKey3,
child: MyTextForm(
controller: registerController.phoneController,
label: 'Enter your phone number'.tr,
hint: 'Enter your phone number'.tr,
type: TextInputType.phone),
)
: Container(
decoration: AppStyle.boxDecoration1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
registerController.phoneController.text,
style: AppStyle.title,
),
),
)),
const SizedBox(
height: 10,
),
if (registerController.isSent)
Padding(
padding: const EdgeInsets.all(16.0),
child: registerController.isSent
? Form(
key: registerController.formKey3,
child: MyTextForm(
controller: registerController.verifyCode,
label: '5 digit'.tr,
hint: '5 digit'.tr,
type: TextInputType.number),
)
: const SizedBox()),
padding: const EdgeInsets.all(16.0),
child: Form(
key: registerController.formKey3,
child: MyTextForm(
controller: registerController.verifyCode,
label: '5 digit'.tr,
hint: '5 digit'.tr,
type: TextInputType.number),
),
),
// Submit button
MyElevatedButton(
onPressed: () async {

View File

@@ -35,7 +35,7 @@ List<CarType> carTypes = [
image: 'assets/images/carspeed.png',
),
CarType(
carType: 'Balash',
carType: 'Awfar Car',
carDetail: "Old and affordable, perfect for budget rides.".tr,
image: 'assets/images/balash.png',
),
@@ -45,15 +45,20 @@ List<CarType> carTypes = [
image: 'assets/images/lady.png',
),
CarType(
carType: 'Delivery',
carType: 'Scooter',
carDetail: 'Delivery service'.tr,
image: 'assets/images/moto.png',
),
CarType(
carType: 'Mashwari',
carType: 'Mishwar Vip',
carDetail: 'Mashwari without end point'.tr,
image: 'assets/images/freeRide.png',
),
CarType(
carType: 'Pink Bike',
carDetail: "Best choice for cities".tr,
image: 'assets/images/pinkBike.png',
),
CarType(
carType: 'Rayeh Gai',
carDetail: "Best choice for cities".tr,
@@ -68,6 +73,26 @@ class CarDetailsTypeToChoose extends StatelessWidget {
Widget build(BuildContext context) {
return GetBuilder<MapPassengerController>(
builder: (mapPassengerController) {
if (mapPassengerController.distance > 40) {
carTypes.add(
CarType(
carType: 'Rayeh Gai',
carDetail: "Best choice for cities".tr,
image: 'assets/images/roundtrip.png',
),
);
if (carTypes.length > 8) {
carTypes.removeRange(8, carTypes.length);
}
} // Create a Set to remove duplicates based on the `carType` field
else if (carTypes.length > 7) {
carTypes.removeRange(7, carTypes.length);
}
Set<CarType> uniqueCarTypes = {};
uniqueCarTypes.addAll(carTypes);
// Convert the Set back to a List
carTypes = uniqueCarTypes.toList();
return mapPassengerController.data.isNotEmpty &&
mapPassengerController.isBottomSheetShown &&
mapPassengerController.rideConfirm == false
@@ -138,25 +163,31 @@ class CarDetailsTypeToChoose extends StatelessWidget {
? mapPassengerController
.totalPassengerSpeed
.toStringAsFixed(2)
: carType.carType == 'Balash'
: carType.carType == 'Awfar Car'
? mapPassengerController
.totalPassengerBalash
.toStringAsFixed(2)
: carType.carType == 'Delivery'
: carType.carType == 'Scooter'
? mapPassengerController
.totalPassengerMotoDelivery
.totalPassengerScooter
.toStringAsFixed(2)
: carType.carType == 'Lady'
? mapPassengerController
.totalPassengerLady
.toStringAsFixed(2)
: carType.carType ==
'Rayeh Gai'
'Pink Bike'
? mapPassengerController
.totalPassengerRayehGai
.totalPassengerScooter
.toStringAsFixed(
2)
: '50',
: carType.carType ==
'Rayeh Gai'
? mapPassengerController
.totalPassengerRayehGai
.toStringAsFixed(
2)
: '50',
style:
AppStyle.title.copyWith(fontSize: 20),
),
@@ -228,7 +259,8 @@ class CarDetailsTypeToChoose extends StatelessWidget {
)
],
)
: carType.carType == 'Balash' &&
: carType.carType ==
'Awfar Car' &&
(mapPassengerController
.totalPassengerBalash >
15)
@@ -400,12 +432,12 @@ class CarDetailsTypeToChoose extends StatelessWidget {
} else if (mapPassengerController
.selectedIndex ==
4) {
box.write(BoxName.carType, 'Delivery');
box.write(BoxName.carType, 'Scooter');
mapPassengerController.totalPassenger =
mapPassengerController
.totalPassengerMotoDelivery;
.totalPassengerScooter;
Get.defaultDialog(
title: 'Delivery'.tr,
title: 'Scooter'.tr,
titleStyle: AppStyle.title,
content: CarDialogue(
textToSpeechController:
@@ -431,13 +463,47 @@ class CarDetailsTypeToChoose extends StatelessWidget {
onPressed: () {
Get.back();
}));
} else if (mapPassengerController
.selectedIndex ==
6) {
box.write(BoxName.carType, 'Pink Bike');
mapPassengerController.totalPassenger =
mapPassengerController
.totalPassengerScooter;
Get.defaultDialog(
title: 'Pink Bike'.tr,
titleStyle: AppStyle.title,
content: CarDialogue(
textToSpeechController:
textToSpeechController,
image: 'assets/images/pinkBike.png',
text:
'This is for delivery or a motorcycle.'
.tr),
confirm: MyElevatedButton(
kolor: AppColor.greenColor,
title: 'Next'.tr,
onPressed: () {
Get.back();
mapPassengerController
.isBottomSheetShown = false;
mapPassengerController.update();
mapPassengerController
.changeCashConfirmPageShown();
}),
cancel: MyElevatedButton(
title: 'Cancel'.tr,
kolor: AppColor.redColor,
onPressed: () {
Get.back();
}));
} else if (mapPassengerController
.selectedIndex ==
5) {
box.write(BoxName.carType, 'Mashwari');
box.write(BoxName.carType, 'Mishwar Vip');
mapPassengerController.totalPassenger = 50;
Get.defaultDialog(
title: 'Mashwari'.tr,
title: 'Mishwar Vip'.tr,
titleStyle: AppStyle.title,
content: CarDialogue(
textToSpeechController:
@@ -463,12 +529,12 @@ class CarDetailsTypeToChoose extends StatelessWidget {
} else if (mapPassengerController
.selectedIndex ==
2) {
box.write(BoxName.carType, 'Balash');
box.write(BoxName.carType, 'Awfar Car');
mapPassengerController.totalPassenger =
mapPassengerController
.totalPassengerBalash;
Get.defaultDialog(
title: 'Balash'.tr,
title: 'Awfar Car'.tr,
titleStyle: AppStyle.title,
content: CarDialogue(
textToSpeechController:
@@ -539,7 +605,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
}));
} else if (mapPassengerController
.selectedIndex ==
6) {
7) {
box.write(BoxName.carType, 'Rayeh Gai');
mapPassengerController.totalPassenger =
mapPassengerController.totalPassengerLady;

View File

@@ -112,23 +112,23 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
// ),
// ),
// ),
AnimatedContainer(
duration: const Duration(microseconds: 200),
width: controller.widthMapTypeAndTraffic,
decoration: BoxDecoration(
color: AppColor.secondaryColor,
border: Border.all(),
borderRadius: BorderRadius.circular(15)),
child: IconButton(
onPressed: () async {
Get.to(SmsSignupEgypt());
},
icon: const Icon(
Icons.chat,
size: 29,
),
),
),
// AnimatedContainer(
// duration: const Duration(microseconds: 200),
// width: controller.widthMapTypeAndTraffic,
// decoration: BoxDecoration(
// color: AppColor.secondaryColor,
// border: Border.all(),
// borderRadius: BorderRadius.circular(15)),
// child: IconButton(
// onPressed: () async {
// Get.to(SmsSignupEgypt());
// },
// icon: const Icon(
// Icons.chat,
// size: 29,
// ),
// ),
// ),
// AnimatedContainer(
// duration: const Duration(microseconds: 200),
// width: controller.widthMapTypeAndTraffic,

View File

@@ -1132,18 +1132,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.4"
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
@@ -1244,18 +1244,18 @@ packages:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.8.0"
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.15.0"
mime:
dependency: transitive
description:
@@ -1728,10 +1728,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
version: "0.7.2"
timezone:
dependency: transitive
description:
@@ -1944,10 +1944,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
version: "14.2.1"
version: "14.2.5"
wakelock_plus:
dependency: "direct main"
description:

View File

@@ -61,6 +61,7 @@ dependencies:
package_info_plus: ^8.0.0
uni_links: ^0.5.1
googleapis_auth: ^1.6.0
# intl_phone_field: ^3.1.0
dev_dependencies:
flutter_test: