12/17/2
This commit is contained in:
5
.env
5
.env
@@ -5,6 +5,7 @@ accountSIDTwillo=QFx0qy456juj3839xuy2194q629q1fj0y7XrXlBl
|
|||||||
serverAPI=QQQQobSrrFi:QVQ87xU7zwCvmZzZdaxuS2f23Y4mz7MzyOzr8od2br6KYyeFaTVLG3K3hx5ZaUyx7eYvAYpAVdKk-286NTRi3zs9iSOnXtXRIxswg3KecBmsl3VxJ9wO-vIpwu4Pv7dkHkXniuxMSDgWXrXlBl
|
serverAPI=QQQQobSrrFi:QVQ87xU7zwCvmZzZdaxuS2f23Y4mz7MzyOzr8od2br6KYyeFaTVLG3K3hx5ZaUyx7eYvAYpAVdKk-286NTRi3zs9iSOnXtXRIxswg3KecBmsl3VxJ9wO-vIpwu4Pv7dkHkXniuxMSDgWXrXlBl
|
||||||
mapAPIKEY=QOmqZsFsutLDCtZCRIUAZAkB5v6AMkKEPMbJGa3XrXlBl
|
mapAPIKEY=QOmqZsFsutLDCtZCRIUAZAkB5v6AMkKEPMbJGa3XrXlBl
|
||||||
twilloRecoveryCode=CAU79DHPH1BE9PUH4ETXTSXZXrXlBl
|
twilloRecoveryCode=CAU79DHPH1BE9PUH4ETXTSXZXrXlBl
|
||||||
|
apiKeyHere=g_WNUb5L-7-F8oHpUmgIzH7ETeH9xZ8RwGG9_G8zX9A
|
||||||
authTokenTwillo=70u98ju0214xx4q0u74028u021u4qu65XrXlBl
|
authTokenTwillo=70u98ju0214xx4q0u74028u021u4qu65XrXlBl
|
||||||
chatGPTkey=zg-4C26q4SYBKQeHZDqkWowC9XrxgUEfUy9JRw2rm6Q2adb3kjwXrXlBl
|
chatGPTkey=zg-4C26q4SYBKQeHZDqkWowC9XrxgUEfUy9JRw2rm6Q2adb3kjwXrXlBl
|
||||||
transactionCloude=Qhcwilomqcoib:QVO_JNYED2XWA26YXKC2TP:YK1DVH6SJB31N3PE1UXrXlBl
|
transactionCloude=Qhcwilomqcoib:QVO_JNYED2XWA26YXKC2TP:YK1DVH6SJB31N3PE1UXrXlBl
|
||||||
@@ -18,9 +19,9 @@ serverPHP=https://api.sefer.live/sefer
|
|||||||
seferAlexandriaServer=https://seferalexandria.site/sefer
|
seferAlexandriaServer=https://seferalexandria.site/sefer
|
||||||
seferPaymentServer=https://seferpw.shop/sefer
|
seferPaymentServer=https://seferpw.shop/sefer
|
||||||
seferCairoServer=https://sefer.click/sefer
|
seferCairoServer=https://sefer.click/sefer
|
||||||
seferGizaServer=https://sefergiza.site/sefer
|
seferGizaServer=https://gizasefer.online/sefer
|
||||||
whatappID=369939736211879
|
whatappID=369939736211879
|
||||||
whatsapp=EEAAOtbZBSUK74BO93qYEsBTetiT5qGCHCdxDRXEH1cGUrlbHN2ZB4bVrFCR1ZC8xEVDtHeLUH6yHej2RPMpmoLD69AlqBJJDtQ7nrsmbeIRZCBGPoKueLQUaEMWPC2R6EJdZArqdFy1rv4ZAGJZBV9ifxvwwTAlw7dbzA3WEZBvWKPXswUkPP9UWM1fWEPL86buyH0IvEd6j9grk6l7rG6CAZD
|
whatsapp=EAAOtbZBSUK74BO6yE1QwIBsRCjPDANdum66xap0ZA7OZA8LqEu8MZAts1kwr12eRiNXtvpJ2ZAFSY5dw3KVSyrUuH8boLjynxdFI4Gh1Q7BCHx275X2uZBwKWZCSrsVN17i6mZAFNYYd25sQv0ZBomeTk02ZCIJot4UqWxK9ZBvxsq1k2yS7lD2NsjZB5EHbpaYGLzxFJ2FCCSX6iHyKXab6ckfK7m19wo77in7Dl3YZD
|
||||||
cohere=Aulwd8y5SPWos0hJhG0toUf8gOhUUrpf5Q2TPmVGXrXlBl
|
cohere=Aulwd8y5SPWos0hJhG0toUf8gOhUUrpf5Q2TPmVGXrXlBl
|
||||||
claudeAiAPI=zg-qbc-qvo39-xWOxIGwWTOzCFBnIYSKKhfyz_KVAvrH-6_4ZEJL68G_QBH26oeTOMMoQug9KuOjjKSP_A4S3SUDlbxR9duVzoQ-MkX_UQQQXrXlBl
|
claudeAiAPI=zg-qbc-qvo39-xWOxIGwWTOzCFBnIYSKKhfyz_KVAvrH-6_4ZEJL68G_QBH26oeTOMMoQug9KuOjjKSP_A4S3SUDlbxR9duVzoQ-MkX_UQQQXrXlBl
|
||||||
payPalClientId=QALymfNI5Tzt4s-ysoz6vD4_nqX0SUtkC_qYV-Ugk5gaM_8Z-kg4L53k8Uux_4jEWXDkNpXGSWPpIzDFXrXlBl
|
payPalClientId=QALymfNI5Tzt4s-ysoz6vD4_nqX0SUtkC_qYV-Ugk5gaM_8Z-kg4L53k8Uux_4jEWXDkNpXGSWPpIzDFXrXlBl
|
||||||
|
|||||||
BIN
Archive.zip
Normal file
BIN
Archive.zip
Normal file
Binary file not shown.
@@ -26,18 +26,24 @@ apply plugin: 'com.android.application'
|
|||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
// apply plugin: 'com.google.gms.google-services'
|
// apply plugin: 'com.google.gms.google-services'
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
def keystoreProperties = new Properties()
|
def keystoreProperties = new Properties()
|
||||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keystorePropertiesFile.withReader('UTF-8') { reader ->
|
||||||
|
keystoreProperties.load(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace "com.mobileapp.store.ride"
|
namespace "com.mobileapp.store.ride"
|
||||||
compileSdkVersion 34
|
compileSdk 35
|
||||||
ndkVersion flutter.ndkVersion
|
ndkVersion "26.1.10909125"
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
@@ -49,33 +55,45 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// Specify your unique Application ID
|
||||||
applicationId "com.mobileapp.store.ride"
|
applicationId = "com.mobileapp.store.ride"
|
||||||
// You can update the following values to match your application needs.
|
// 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.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
|
<<<<<<< HEAD
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 65
|
versionCode 65
|
||||||
versionName '1.5.65'
|
versionName '1.5.65'
|
||||||
multiDexEnabled =true
|
multiDexEnabled =true
|
||||||
// manifestPlaceholders = [mapsApiKey: 'android/app/src/main/AndroidManifest.xml']
|
// manifestPlaceholders = [mapsApiKey: 'android/app/src/main/AndroidManifest.xml']
|
||||||
|
=======
|
||||||
|
minSdk = 23
|
||||||
|
targetSdk = flutter.targetSdkVersion
|
||||||
|
versionCode = 108
|
||||||
|
versionName = '1.6.108'
|
||||||
|
multiDexEnabled =true
|
||||||
|
|
||||||
|
// manifestPlaceholders can be specified here if needed
|
||||||
|
>>>>>>> 8813b4d
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
release {
|
release {
|
||||||
keyAlias keystoreProperties['keyAlias']
|
keyAlias keystoreProperties['keyAlias']
|
||||||
keyPassword keystoreProperties['keyPassword']
|
keyPassword keystoreProperties['keyPassword']
|
||||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||||
storePassword keystoreProperties['storePassword']
|
storePassword keystoreProperties['storePassword']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
signingConfig signingConfigs.release
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
signingConfig signingConfigs.release
|
||||||
|
// minifyEnabled true
|
||||||
|
// shrinkResources true
|
||||||
|
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
@@ -84,6 +102,14 @@ flutter {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
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 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.
|
||||||
|
|
||||||
|
}
|
||||||
30
android/app/proguard-rules.pro
vendored
Normal file
30
android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Suppress warnings for specific Google ML Kit and Stripe classes
|
||||||
|
-dontwarn com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions$Builder
|
||||||
|
-dontwarn com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
|
||||||
|
-dontwarn com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions$Builder
|
||||||
|
-dontwarn com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions
|
||||||
|
-dontwarn com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions$Builder
|
||||||
|
-dontwarn com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions
|
||||||
|
-dontwarn com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions$Builder
|
||||||
|
-dontwarn com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions
|
||||||
|
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivity$g
|
||||||
|
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Args
|
||||||
|
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Error
|
||||||
|
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter
|
||||||
|
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningEphemeralKeyProvider
|
||||||
|
|
||||||
|
# Keep rules for Google ML Kit
|
||||||
|
-keep class com.google.mlkit.vision.** { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.** { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions$Builder { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions$Builder { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions$Builder { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions { *; }
|
||||||
|
-keep class com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions$Builder { *; }
|
||||||
|
|
||||||
|
# Keep rules for Stripe
|
||||||
|
-keep class com.stripe.android.** { *; }
|
||||||
|
-keep class com.stripe.android.pushProvisioning.** { *; }
|
||||||
@@ -10,6 +10,12 @@
|
|||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||||
|
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.QUICKBOOT_POWERON" />
|
||||||
|
<uses-permission android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera" />
|
<uses-feature android:name="android.hardware.camera" />
|
||||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||||
@@ -25,6 +31,7 @@
|
|||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
@@ -58,6 +65,17 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
|
<receiver android:exported="false"
|
||||||
|
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
|
||||||
|
<receiver android:exported="false"
|
||||||
|
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
<activity
|
<activity
|
||||||
android:name="com.yalantis.ucrop.UCropActivity"
|
android:name="com.yalantis.ucrop.UCropActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
|
|||||||
BIN
android/app/src/main/res/raw/app_icon.png
Normal file
BIN
android/app/src/main/res/raw/app_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
@@ -1,6 +1,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">My App</string>
|
<string name="app_name">My App</string>
|
||||||
<!-- <string name="default_notification_channel_id">ride_channel</string> -->
|
<!-- <string name="default_notification_channel_id">ride_channel</string> -->
|
||||||
<string name="default_notification_channel_id">default_channel</string>
|
<!-- <string name="default_notification_channel_id">default_channel</string> -->
|
||||||
|
<string name="default_notification_channel_id">high_importance_channel</string>
|
||||||
<string name="api_key">AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0</string>
|
<string name="api_key">AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -12,7 +12,7 @@ buildscript {
|
|||||||
// classpath 'com.android.tools.build:gradle:7.3.1'
|
// classpath 'com.android.tools.build:gradle:7.3.1'
|
||||||
classpath 'com.google.gms:google-services:4.3.15'
|
classpath 'com.google.gms:google-services:4.3.15'
|
||||||
// END: FlutterFire Configuration
|
// 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"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
org.gradle.jvmargs=-Xmx4096M
|
org.gradle.jvmargs=-Xmx4096M
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
android.defaults.buildfeatures.buildconfig=true
|
||||||
|
android.nonTransitiveRClass=false
|
||||||
|
android.nonFinalResIds=false
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
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
|
||||||
|
|||||||
BIN
assets/images/car3.png
Normal file
BIN
assets/images/car3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 713 KiB After Width: | Height: | Size: 82 KiB |
BIN
assets/images/pinkBike.png
Normal file
BIN
assets/images/pinkBike.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
256
ios/Podfile.lock
256
ios/Podfile.lock
@@ -9,54 +9,61 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- device_info_plus (0.0.1):
|
- device_info_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Firebase/Auth (10.28.0):
|
- Firebase/Auth (11.0.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseAuth (~> 10.28.0)
|
- FirebaseAuth (~> 11.0.0)
|
||||||
- Firebase/CoreOnly (10.28.0):
|
- Firebase/CoreOnly (11.0.0):
|
||||||
- FirebaseCore (= 10.28.0)
|
- FirebaseCore (= 11.0.0)
|
||||||
- Firebase/Messaging (10.28.0):
|
- Firebase/Messaging (11.0.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseMessaging (~> 10.28.0)
|
- FirebaseMessaging (~> 11.0.0)
|
||||||
- firebase_auth (5.1.2):
|
- firebase_auth (5.2.0):
|
||||||
- Firebase/Auth (= 10.28.0)
|
- Firebase/Auth (= 11.0.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_core (3.2.0):
|
- firebase_core (3.4.0):
|
||||||
- Firebase/CoreOnly (= 10.28.0)
|
- Firebase/CoreOnly (= 11.0.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_messaging (15.0.3):
|
- firebase_messaging (15.1.0):
|
||||||
- Firebase/Messaging (= 10.28.0)
|
- Firebase/Messaging (= 11.0.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- FirebaseAppCheckInterop (10.29.0)
|
- FirebaseAppCheckInterop (11.5.0)
|
||||||
- FirebaseAuth (10.28.0):
|
- FirebaseAuth (11.0.0):
|
||||||
- FirebaseAppCheckInterop (~> 10.17)
|
- FirebaseAppCheckInterop (~> 11.0)
|
||||||
- FirebaseCore (~> 10.0)
|
- FirebaseAuthInterop (~> 11.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
|
- FirebaseCore (~> 11.0)
|
||||||
- GoogleUtilities/Environment (~> 7.8)
|
- FirebaseCoreExtension (~> 11.0)
|
||||||
- GTMSessionFetcher/Core (< 4.0, >= 2.1)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||||
|
- GoogleUtilities/Environment (~> 8.0)
|
||||||
|
- GTMSessionFetcher/Core (~> 3.4)
|
||||||
- RecaptchaInterop (~> 100.0)
|
- RecaptchaInterop (~> 100.0)
|
||||||
- FirebaseCore (10.28.0):
|
- FirebaseAuthInterop (11.5.0)
|
||||||
- FirebaseCoreInternal (~> 10.0)
|
- FirebaseCore (11.0.0):
|
||||||
- GoogleUtilities/Environment (~> 7.12)
|
- FirebaseCoreInternal (~> 11.0)
|
||||||
- GoogleUtilities/Logger (~> 7.12)
|
- GoogleUtilities/Environment (~> 8.0)
|
||||||
- FirebaseCoreInternal (10.29.0):
|
- GoogleUtilities/Logger (~> 8.0)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 7.8)"
|
- FirebaseCoreExtension (11.4.1):
|
||||||
- FirebaseInstallations (10.29.0):
|
- FirebaseCore (~> 11.0)
|
||||||
- FirebaseCore (~> 10.0)
|
- FirebaseCoreInternal (11.5.0):
|
||||||
- GoogleUtilities/Environment (~> 7.8)
|
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||||
- GoogleUtilities/UserDefaults (~> 7.8)
|
- FirebaseInstallations (11.4.0):
|
||||||
- PromisesObjC (~> 2.1)
|
- FirebaseCore (~> 11.0)
|
||||||
- FirebaseMessaging (10.28.0):
|
- GoogleUtilities/Environment (~> 8.0)
|
||||||
- FirebaseCore (~> 10.0)
|
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||||
- FirebaseInstallations (~> 10.0)
|
- PromisesObjC (~> 2.4)
|
||||||
- GoogleDataTransport (~> 9.3)
|
- FirebaseMessaging (11.0.0):
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
|
- FirebaseCore (~> 11.0)
|
||||||
- GoogleUtilities/Environment (~> 7.8)
|
- FirebaseInstallations (~> 11.0)
|
||||||
- GoogleUtilities/Reachability (~> 7.8)
|
- GoogleDataTransport (~> 10.0)
|
||||||
- GoogleUtilities/UserDefaults (~> 7.8)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
- GoogleUtilities/Environment (~> 8.0)
|
||||||
|
- GoogleUtilities/Reachability (~> 8.0)
|
||||||
|
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
|
- flutter_contacts (0.0.1):
|
||||||
|
- Flutter
|
||||||
- flutter_local_notifications (0.0.1):
|
- flutter_local_notifications (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_secure_storage (6.0.0):
|
- flutter_secure_storage (6.0.0):
|
||||||
@@ -65,8 +72,11 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- geolocator_apple (1.2.0):
|
- geolocator_apple (1.2.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- Google-Maps-iOS-Utils (5.0.0):
|
||||||
|
- GoogleMaps (~> 8.0)
|
||||||
- google_maps_flutter_ios (0.0.1):
|
- google_maps_flutter_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- Google-Maps-iOS-Utils (< 7.0, >= 5.0)
|
||||||
- GoogleMaps (< 10.0, >= 8.4)
|
- GoogleMaps (< 10.0, >= 8.4)
|
||||||
- google_sign_in_ios (0.0.1):
|
- google_sign_in_ios (0.0.1):
|
||||||
- AppAuth (>= 1.7.4)
|
- AppAuth (>= 1.7.4)
|
||||||
@@ -74,10 +84,9 @@ PODS:
|
|||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- GoogleSignIn (~> 7.1)
|
- GoogleSignIn (~> 7.1)
|
||||||
- GTMSessionFetcher (>= 3.4.0)
|
- GTMSessionFetcher (>= 3.4.0)
|
||||||
- GoogleDataTransport (9.4.1):
|
- GoogleDataTransport (10.1.0):
|
||||||
- GoogleUtilities/Environment (~> 7.7)
|
- nanopb (~> 3.30910.0)
|
||||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
- PromisesObjC (~> 2.4)
|
||||||
- PromisesObjC (< 3.0, >= 1.2)
|
|
||||||
- GoogleMaps (8.4.0):
|
- GoogleMaps (8.4.0):
|
||||||
- GoogleMaps/Maps (= 8.4.0)
|
- GoogleMaps/Maps (= 8.4.0)
|
||||||
- GoogleMaps/Base (8.4.0)
|
- GoogleMaps/Base (8.4.0)
|
||||||
@@ -87,29 +96,28 @@ PODS:
|
|||||||
- AppAuth (< 2.0, >= 1.7.3)
|
- AppAuth (< 2.0, >= 1.7.3)
|
||||||
- GTMAppAuth (< 5.0, >= 4.1.1)
|
- GTMAppAuth (< 5.0, >= 4.1.1)
|
||||||
- GTMSessionFetcher/Core (~> 3.3)
|
- GTMSessionFetcher/Core (~> 3.3)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (7.13.3):
|
- GoogleUtilities/AppDelegateSwizzler (8.0.2):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network
|
- GoogleUtilities/Network
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
- GoogleUtilities/Environment (7.13.3):
|
- GoogleUtilities/Environment (8.0.2):
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
- PromisesObjC (< 3.0, >= 1.2)
|
- GoogleUtilities/Logger (8.0.2):
|
||||||
- GoogleUtilities/Logger (7.13.3):
|
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
- GoogleUtilities/Network (7.13.3):
|
- GoogleUtilities/Network (8.0.2):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- "GoogleUtilities/NSData+zlib"
|
- "GoogleUtilities/NSData+zlib"
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
- GoogleUtilities/Reachability
|
- GoogleUtilities/Reachability
|
||||||
- "GoogleUtilities/NSData+zlib (7.13.3)":
|
- "GoogleUtilities/NSData+zlib (8.0.2)":
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
- GoogleUtilities/Privacy (7.13.3)
|
- GoogleUtilities/Privacy (8.0.2)
|
||||||
- GoogleUtilities/Reachability (7.13.3):
|
- GoogleUtilities/Reachability (8.0.2):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
- GoogleUtilities/UserDefaults (7.13.3):
|
- GoogleUtilities/UserDefaults (8.0.2):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
- GTMAppAuth (4.1.1):
|
- GTMAppAuth (4.1.1):
|
||||||
@@ -129,13 +137,14 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- local_auth_darwin (0.0.1):
|
- local_auth_darwin (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
- location (0.0.1):
|
- location (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- nanopb (2.30910.0):
|
- nanopb (3.30910.0):
|
||||||
- nanopb/decode (= 2.30910.0)
|
- nanopb/decode (= 3.30910.0)
|
||||||
- nanopb/encode (= 2.30910.0)
|
- nanopb/encode (= 3.30910.0)
|
||||||
- nanopb/decode (2.30910.0)
|
- nanopb/decode (3.30910.0)
|
||||||
- nanopb/encode (2.30910.0)
|
- nanopb/encode (3.30910.0)
|
||||||
- package_info_plus (0.4.5):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
@@ -155,42 +164,42 @@ PODS:
|
|||||||
- sqflite (0.0.3):
|
- sqflite (0.0.3):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- Stripe (23.27.6):
|
- Stripe (23.28.3):
|
||||||
- StripeApplePay (= 23.27.6)
|
- StripeApplePay (= 23.28.3)
|
||||||
- StripeCore (= 23.27.6)
|
- StripeCore (= 23.28.3)
|
||||||
- StripePayments (= 23.27.6)
|
- StripePayments (= 23.28.3)
|
||||||
- StripePaymentsUI (= 23.27.6)
|
- StripePaymentsUI (= 23.28.3)
|
||||||
- StripeUICore (= 23.27.6)
|
- StripeUICore (= 23.28.3)
|
||||||
- stripe_ios (0.0.1):
|
- stripe_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Stripe (~> 23.27.0)
|
- Stripe (~> 23.28.0)
|
||||||
- StripeApplePay (~> 23.27.0)
|
- StripeApplePay (~> 23.28.0)
|
||||||
- StripeFinancialConnections (~> 23.27.0)
|
- StripeFinancialConnections (~> 23.28.0)
|
||||||
- StripePayments (~> 23.27.0)
|
- StripePayments (~> 23.28.0)
|
||||||
- StripePaymentSheet (~> 23.27.0)
|
- StripePaymentSheet (~> 23.28.0)
|
||||||
- StripePaymentsUI (~> 23.27.0)
|
- StripePaymentsUI (~> 23.28.0)
|
||||||
- StripeApplePay (23.27.6):
|
- StripeApplePay (23.28.3):
|
||||||
- StripeCore (= 23.27.6)
|
- StripeCore (= 23.28.3)
|
||||||
- StripeCore (23.27.6)
|
- StripeCore (23.28.3)
|
||||||
- StripeFinancialConnections (23.27.6):
|
- StripeFinancialConnections (23.28.3):
|
||||||
- StripeCore (= 23.27.6)
|
- StripeCore (= 23.28.3)
|
||||||
- StripeUICore (= 23.27.6)
|
- StripeUICore (= 23.28.3)
|
||||||
- StripePayments (23.27.6):
|
- StripePayments (23.28.3):
|
||||||
- StripeCore (= 23.27.6)
|
- StripeCore (= 23.28.3)
|
||||||
- StripePayments/Stripe3DS2 (= 23.27.6)
|
- StripePayments/Stripe3DS2 (= 23.28.3)
|
||||||
- StripePayments/Stripe3DS2 (23.27.6):
|
- StripePayments/Stripe3DS2 (23.28.3):
|
||||||
- StripeCore (= 23.27.6)
|
- StripeCore (= 23.28.3)
|
||||||
- StripePaymentSheet (23.27.6):
|
- StripePaymentSheet (23.28.3):
|
||||||
- StripeApplePay (= 23.27.6)
|
- StripeApplePay (= 23.28.3)
|
||||||
- StripeCore (= 23.27.6)
|
- StripeCore (= 23.28.3)
|
||||||
- StripePayments (= 23.27.6)
|
- StripePayments (= 23.28.3)
|
||||||
- StripePaymentsUI (= 23.27.6)
|
- StripePaymentsUI (= 23.28.3)
|
||||||
- StripePaymentsUI (23.27.6):
|
- StripePaymentsUI (23.28.3):
|
||||||
- StripeCore (= 23.27.6)
|
- StripeCore (= 23.28.3)
|
||||||
- StripePayments (= 23.27.6)
|
- StripePayments (= 23.28.3)
|
||||||
- StripeUICore (= 23.27.6)
|
- StripeUICore (= 23.28.3)
|
||||||
- StripeUICore (23.27.6):
|
- StripeUICore (23.28.3):
|
||||||
- StripeCore (= 23.27.6)
|
- StripeCore (= 23.28.3)
|
||||||
- TOCropViewController (2.7.4)
|
- TOCropViewController (2.7.4)
|
||||||
- uni_links (0.0.1):
|
- uni_links (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -205,6 +214,7 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- webview_flutter_wkwebview (0.0.1):
|
- webview_flutter_wkwebview (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
||||||
@@ -213,6 +223,7 @@ DEPENDENCIES:
|
|||||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
|
- flutter_contacts (from `.symlinks/plugins/flutter_contacts/ios`)
|
||||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||||
- flutter_tts (from `.symlinks/plugins/flutter_tts/ios`)
|
- flutter_tts (from `.symlinks/plugins/flutter_tts/ios`)
|
||||||
@@ -237,7 +248,7 @@ DEPENDENCIES:
|
|||||||
- vibration (from `.symlinks/plugins/vibration/ios`)
|
- vibration (from `.symlinks/plugins/vibration/ios`)
|
||||||
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
|
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
|
||||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||||
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
|
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
@@ -245,10 +256,13 @@ SPEC REPOS:
|
|||||||
- Firebase
|
- Firebase
|
||||||
- FirebaseAppCheckInterop
|
- FirebaseAppCheckInterop
|
||||||
- FirebaseAuth
|
- FirebaseAuth
|
||||||
|
- FirebaseAuthInterop
|
||||||
- FirebaseCore
|
- FirebaseCore
|
||||||
|
- FirebaseCoreExtension
|
||||||
- FirebaseCoreInternal
|
- FirebaseCoreInternal
|
||||||
- FirebaseInstallations
|
- FirebaseInstallations
|
||||||
- FirebaseMessaging
|
- FirebaseMessaging
|
||||||
|
- Google-Maps-iOS-Utils
|
||||||
- GoogleDataTransport
|
- GoogleDataTransport
|
||||||
- GoogleMaps
|
- GoogleMaps
|
||||||
- GoogleSignIn
|
- GoogleSignIn
|
||||||
@@ -281,6 +295,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
|
flutter_contacts:
|
||||||
|
:path: ".symlinks/plugins/flutter_contacts/ios"
|
||||||
flutter_local_notifications:
|
flutter_local_notifications:
|
||||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
@@ -330,41 +346,45 @@ EXTERNAL SOURCES:
|
|||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||||
webview_flutter_wkwebview:
|
webview_flutter_wkwebview:
|
||||||
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
|
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa
|
AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa
|
||||||
audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207
|
audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207
|
||||||
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
|
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
|
||||||
Firebase: 5121c624121af81cbc81df3bda414b3c28c4f3c3
|
Firebase: 9f574c08c2396885b5e7e100ed4293d956218af9
|
||||||
firebase_auth: e778ee89483b86fe4200d1f8e9a1c52aa5fb64a8
|
firebase_auth: 16ac5db3d064db837ecd845080d7e18e4be7c66d
|
||||||
firebase_core: a9d0180d5285527884d07a41eb4a9ec9ed12cdb6
|
firebase_core: ceec591a66629daaee82d3321551692c4a871493
|
||||||
firebase_messaging: ccc82a143a74de75f440a4e413dbbb37ec3fddbc
|
firebase_messaging: 15d8b557010f3bb7b98d0302e1c7c8fbcd244425
|
||||||
FirebaseAppCheckInterop: 6a1757cfd4067d8e00fccd14fcc1b8fd78cfac07
|
FirebaseAppCheckInterop: d265d9f4484e7ec1c591086408840fdd383d1213
|
||||||
FirebaseAuth: 3d872fbbfc4223edeb72769e488f325fa8b0a4a9
|
FirebaseAuth: d5cf28be74d7e82257f6a3f717509eff70d3cf4a
|
||||||
FirebaseCore: 857dc1c6dd1255675047404d8466f7dfaac5d779
|
FirebaseAuthInterop: 1219bee9b23e6ebe84c256a0d95adab53d11c331
|
||||||
FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934
|
FirebaseCore: 3cf438f431f18c12cdf2aaf64434648b63f7e383
|
||||||
FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd
|
FirebaseCoreExtension: f1bc67a4702931a7caa097d8e4ac0a1b0d16720e
|
||||||
FirebaseMessaging: 087a7c7cadef7b9239f005bc4db823894844f323
|
FirebaseCoreInternal: f47dd28ae7782e6a4738aad3106071a8fe0af604
|
||||||
|
FirebaseInstallations: 6ef4a1c7eb2a61ee1f74727d7f6ce2e72acf1414
|
||||||
|
FirebaseMessaging: d2d1d9c62c46dd2db49a952f7deb5b16ad2c9742
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
|
flutter_contacts: edb1c5ce76aa433e20e6cb14c615f4c0b66e0983
|
||||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||||
flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d
|
flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d
|
||||||
geolocator_apple: 6cbaf322953988e009e5ecb481f07efece75c450
|
geolocator_apple: 6cbaf322953988e009e5ecb481f07efece75c450
|
||||||
google_maps_flutter_ios: 5bc2be60ad012e79b182ce0fb0ef5030a50fb03e
|
Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321
|
||||||
|
google_maps_flutter_ios: e31555a04d1986ab130f2b9f24b6cdc861acc6d3
|
||||||
google_sign_in_ios: 07375bfbf2620bc93a602c0e27160d6afc6ead38
|
google_sign_in_ios: 07375bfbf2620bc93a602c0e27160d6afc6ead38
|
||||||
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
|
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||||
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
|
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
|
||||||
GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db
|
GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db
|
||||||
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
|
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
|
||||||
GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
|
GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
|
||||||
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
|
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
|
||||||
image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
|
image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
|
||||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
|
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
|
||||||
local_auth_darwin: 4d56c90c2683319835a61274b57620df9c4520ab
|
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
|
||||||
location: d5cf8598915965547c3f36761ae9cc4f4e87d22e
|
location: d5cf8598915965547c3f36761ae9cc4f4e87d22e
|
||||||
nanopb: 438bc412db1928dac798aa6fd75726007be04262
|
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||||
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||||
@@ -374,22 +394,22 @@ SPEC CHECKSUMS:
|
|||||||
share: 0b2c3e82132f5888bccca3351c504d0003b3b410
|
share: 0b2c3e82132f5888bccca3351c504d0003b3b410
|
||||||
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
|
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
|
||||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||||
Stripe: 9fec845645e39f371e6898926d096fd9c2feb5a5
|
Stripe: cdf416cf2efe286f532a6306de0fcaa0ecc8c71a
|
||||||
stripe_ios: 03c617acee72e48a2d055d096a4b0ed2afebb256
|
stripe_ios: 91946e5c07e0a0dc0e1484ee6659e1f90a302cf3
|
||||||
StripeApplePay: 5f017e8dfe259fafbab70137776189deef754bb2
|
StripeApplePay: efb62ffc08e6cd4f161d77ddb45de2451075c54e
|
||||||
StripeCore: 01ec57f0dddfe742054dc6a322f811426c25313d
|
StripeCore: 9731f05e327c3dcaf7d7abd116840ceaa9482bbe
|
||||||
StripeFinancialConnections: 56698cb6274bf89fb8c76b934f6156f368e97765
|
StripeFinancialConnections: 46c0049aaab3a179193502bce4a8096eb7b73f55
|
||||||
StripePayments: 6adf11faf1b7038e77aa97019410305c6adca79d
|
StripePayments: dd1867a620b0b8b5e294e9ff2f1f7b7770765f47
|
||||||
StripePaymentSheet: 3eaf870c4388e44b0cc37e4c69d00b6957fd8bd7
|
StripePaymentSheet: d155dfde74e90784d054deffb4f561a1f6dd638f
|
||||||
StripePaymentsUI: 59ccddeacad592b09fa67e8d641340820ddb4751
|
StripePaymentsUI: c24f990b03a68a7f6fe704b15dd487e7bb6b603e
|
||||||
StripeUICore: 879bbf5889265db13f52fac8aad7a176ba62481f
|
StripeUICore: f2d514e900c37436dc5427fdf2c29d68ab1c2935
|
||||||
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
|
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
|
||||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
vibration: 7d883d141656a1c1a6d8d238616b2042a51a1241
|
vibration: 7d883d141656a1c1a6d8d238616b2042a51a1241
|
||||||
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
|
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
|
||||||
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||||
webview_flutter_wkwebview: 2a23822e9039b7b1bc52e5add778e5d89ad488d1
|
webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4
|
||||||
|
|
||||||
PODFILE CHECKSUM: d9271c147dd54ffd9ca5d77bf00ca21a1c9a5961
|
PODFILE CHECKSUM: d9271c147dd54ffd9ca5d77bf00ca21a1c9a5961
|
||||||
|
|
||||||
|
|||||||
@@ -467,6 +467,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
@@ -594,6 +595,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
@@ -651,6 +653,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import FirebaseCore
|
|||||||
import GoogleMaps
|
import GoogleMaps
|
||||||
// import Constants
|
// import Constants
|
||||||
|
|
||||||
@UIApplicationMain
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
|
|
||||||
override func application(
|
override func application(
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>NSContactsUsageDescription</key>
|
||||||
|
<string>This app requires contacts access to function properly.</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>12.0</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
@@ -37,11 +41,21 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<<<<<<< HEAD
|
||||||
<string>51</string>
|
<string>51</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>4.3.51</string>
|
<string>4.3.51</string>
|
||||||
|
=======
|
||||||
|
<string>78</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>4.3.78</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string></string>
|
||||||
|
>>>>>>> 8813b4d
|
||||||
<key>FirebaseAppDelegateProxyEnabled</key>
|
<key>FirebaseAppDelegateProxyEnabled</key>
|
||||||
<string>NO</string>
|
<string>NO</string>
|
||||||
<key>GMSApiKey</key>
|
<key>GMSApiKey</key>
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ class AK {
|
|||||||
X.r(X.r(X.r(Env.payMobApikey, cn), cC), cs);
|
X.r(X.r(X.r(Env.payMobApikey, cn), cC), cs);
|
||||||
static final String integrationIdPayMobWallet =
|
static final String integrationIdPayMobWallet =
|
||||||
X.r(X.r(X.r(Env.integrationIdPayMobWallet, cn), cC), cs);
|
X.r(X.r(X.r(Env.integrationIdPayMobWallet, cn), cC), cs);
|
||||||
|
static final String apiKeyHere = Env.apiKeyHere;
|
||||||
static final String smsPasswordEgypt =
|
static final String smsPasswordEgypt =
|
||||||
X.r(X.r(X.r(Env.smsPasswordEgypt, cn), cC), cs);
|
X.r(X.r(X.r(Env.smsPasswordEgypt, cn), cC), cs);
|
||||||
static final String ocpApimSubscriptionKey = Env.ocpApimSubscriptionKey;
|
static final String ocpApimSubscriptionKey = Env.ocpApimSubscriptionKey;
|
||||||
|
|||||||
@@ -10,14 +10,21 @@ class BoxName {
|
|||||||
static const String carType = "carType";
|
static const String carType = "carType";
|
||||||
static const String carPlate = "carPlate";
|
static const String carPlate = "carPlate";
|
||||||
static const String packagInfo = "packagInfo";
|
static const String packagInfo = "packagInfo";
|
||||||
static const String isVerified = '0';
|
static const String isVerified = 'isVerified';
|
||||||
|
static const String isFirstTime = 'isFirstTime';
|
||||||
|
static const String isSavedPhones = 'isSavedPhones';
|
||||||
static const String statusDriverLocation = "statusDriverLocation";
|
static const String statusDriverLocation = "statusDriverLocation";
|
||||||
|
static const String isTest = "isTest";
|
||||||
static const String password = "password";
|
static const String password = "password";
|
||||||
|
static const String validity = "validity";
|
||||||
|
static const String promo = "promo";
|
||||||
|
static const String discount = "discount";
|
||||||
static const String arrivalTime = "arrivalTime";
|
static const String arrivalTime = "arrivalTime";
|
||||||
static const String passwordDriver = "passwordDriver";
|
static const String passwordDriver = "passwordDriver";
|
||||||
static const String agreeTerms = "agreeTerms";
|
static const String agreeTerms = "agreeTerms";
|
||||||
static const String addWork = 'addWork';
|
static const String addWork = 'addWork';
|
||||||
static const String addHome = 'addHome';
|
static const String addHome = 'addHome';
|
||||||
|
static const String placesDestination = 'placesDestination';
|
||||||
static const String tipPercentage = 'tipPercentage';
|
static const String tipPercentage = 'tipPercentage';
|
||||||
static const String accountIdStripeConnect = "accountIdStripeConnect";
|
static const String accountIdStripeConnect = "accountIdStripeConnect";
|
||||||
static const String faceDetectTimes = "faceDetectTimes";
|
static const String faceDetectTimes = "faceDetectTimes";
|
||||||
@@ -25,6 +32,11 @@ class BoxName {
|
|||||||
static const String sosPhoneDriver = "sosPhoneDriver";
|
static const String sosPhoneDriver = "sosPhoneDriver";
|
||||||
static const String passengerID = "pasengerID";
|
static const String passengerID = "pasengerID";
|
||||||
static const String phone = "phone";
|
static const String phone = "phone";
|
||||||
|
static const String package = "package";
|
||||||
|
static const String isInstall = "isInstall";
|
||||||
|
static const String isGiftToken = "isGiftToken";
|
||||||
|
static const String inviteCode = "inviteCode";
|
||||||
|
static const String phoneWallet = "phoneWallet";
|
||||||
static const String phoneDriver = "phoneDriver";
|
static const String phoneDriver = "phoneDriver";
|
||||||
static const String dobDriver = "dobDriver";
|
static const String dobDriver = "dobDriver";
|
||||||
static const String sexDriver = "sexDriver";
|
static const String sexDriver = "sexDriver";
|
||||||
@@ -68,7 +80,6 @@ class BoxName {
|
|||||||
static const String vin = "vin";
|
static const String vin = "vin";
|
||||||
static const String isvibrate = "isvibrate";
|
static const String isvibrate = "isvibrate";
|
||||||
static const String make = "make";
|
static const String make = "make";
|
||||||
static const String hourWait = "hourWait";
|
|
||||||
static const String model = "model";
|
static const String model = "model";
|
||||||
static const String year = "year";
|
static const String year = "year";
|
||||||
static const String expirationDate = "expirationDate";
|
static const String expirationDate = "expirationDate";
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ class AppLink {
|
|||||||
// static final String server = Env.serverPHP;
|
// static final String server = Env.serverPHP;
|
||||||
|
|
||||||
static String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
|
static String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
|
||||||
|
static String searcMaps =
|
||||||
|
'https://autosuggest.search.hereapi.com/v1/autosuggest';
|
||||||
static String llama = 'https://api.llama-api.com/chat/completions';
|
static String llama = 'https://api.llama-api.com/chat/completions';
|
||||||
static String gemini =
|
static String gemini =
|
||||||
'https://generativelanguage.googleapis.com/v1beta3/models/text-bison-001:generateText';
|
'https://generativelanguage.googleapis.com/v1beta3/models/text-bison-001:generateText';
|
||||||
@@ -51,16 +53,20 @@ class AppLink {
|
|||||||
//=======================promo===================ride.mobile-app.store/ride/promo/get.php
|
//=======================promo===================ride.mobile-app.store/ride/promo/get.php
|
||||||
static String promo = '$server/ride/promo';
|
static String promo = '$server/ride/promo';
|
||||||
static String getPassengersPromo = "$promo/get.php";
|
static String getPassengersPromo = "$promo/get.php";
|
||||||
|
static String getPromoFirst = "$promo/getPromoFirst.php";
|
||||||
static String getPromoBytody = "$promo/getPromoBytody.php";
|
static String getPromoBytody = "$promo/getPromoBytody.php";
|
||||||
static String addPassengersPromo = "$promo/add.php";
|
static String addPassengersPromo = "$promo/add.php";
|
||||||
static String deletePassengersPromo = "$promo/delete.php";
|
static String deletePassengersPromo = "$promo/delete.php";
|
||||||
static String updatePassengersPromo = "$promo/update.php";
|
static String updatePassengersPromo = "$promo/update.php";
|
||||||
|
|
||||||
|
//===============contact==========================
|
||||||
|
static String savePhones = "$server/ride/egyptPhones/add.php";
|
||||||
|
static String getPhones = "$server/ride/egyptPhones/get.php";
|
||||||
|
|
||||||
////=======================cancelRide===================
|
////=======================cancelRide===================
|
||||||
static String ride = '$server/ride';
|
static String ride = '$server/ride';
|
||||||
static String addCancelRideFromPassenger =
|
static String addCancelRideFromPassenger = "$server/ride/cancelRide/add.php";
|
||||||
"$endPoint/ride/cancelRide/add.php";
|
static String cancelRide = "$server/ride/cancelRide/get.php";
|
||||||
static String cancelRide = "$endPoint/ride/cancelRide/get.php";
|
|
||||||
//-----------------ridessss------------------
|
//-----------------ridessss------------------
|
||||||
static String addRides = "$ride/rides/add.php";
|
static String addRides = "$ride/rides/add.php";
|
||||||
static String getRides = "$endPoint/ride/rides/get.php";
|
static String getRides = "$endPoint/ride/rides/get.php";
|
||||||
@@ -70,10 +76,10 @@ class AppLink {
|
|||||||
"$endPoint/ride/rides/getRideStatusBegin.php";
|
"$endPoint/ride/rides/getRideStatusBegin.php";
|
||||||
static String getRideStatusFromStartApp =
|
static String getRideStatusFromStartApp =
|
||||||
"$ride/rides/getRideStatusFromStartApp.php";
|
"$ride/rides/getRideStatusFromStartApp.php";
|
||||||
static String updateRides = "$endPoint/ride/rides/update.php";
|
static String updateRides = "$server/ride/rides/update.php";
|
||||||
static String updateStausFromSpeed =
|
static String updateStausFromSpeed =
|
||||||
"$endPoint/ride/rides/updateStausFromSpeed.php";
|
"$server/ride/rides/updateStausFromSpeed.php";
|
||||||
static String deleteRides = "$endPoint/ride/rides/delete.php";
|
static String deleteRides = "$server/ride/rides/delete.php";
|
||||||
|
|
||||||
//-----------------DriverPayment------------------
|
//-----------------DriverPayment------------------
|
||||||
static String adddriverScam = "$ride/driver_scam/add.php";
|
static String adddriverScam = "$ride/driver_scam/add.php";
|
||||||
@@ -105,13 +111,28 @@ class AppLink {
|
|||||||
"$ride/notificationPassenger/update.php";
|
"$ride/notificationPassenger/update.php";
|
||||||
//-----------------Driver NotificationCaptain------------------
|
//-----------------Driver NotificationCaptain------------------
|
||||||
static String addNotificationCaptain = "$ride/notificationCaptain/add.php";
|
static String addNotificationCaptain = "$ride/notificationCaptain/add.php";
|
||||||
static String addWaitingRide = "$ride/notificationCaptain/addWaitingRide.php";
|
static String addWaitingRide =
|
||||||
static String getRideWaiting = "$ride/notificationCaptain/getRideWaiting.php";
|
"$server/ride/notificationCaptain/addWaitingRide.php";
|
||||||
|
static String updateWaitingTrip =
|
||||||
|
"$server/ride/notificationCaptain/updateWaitingTrip.php";
|
||||||
|
static String getRideWaiting =
|
||||||
|
"$endPoint/ride/notificationCaptain/getRideWaiting.php";
|
||||||
static String getNotificationCaptain = "$ride/notificationCaptain/get.php";
|
static String getNotificationCaptain = "$ride/notificationCaptain/get.php";
|
||||||
static String updateNotificationCaptain =
|
static String updateNotificationCaptain =
|
||||||
"$ride/notificationCaptain/update.php";
|
"$ride/notificationCaptain/update.php";
|
||||||
static String deleteNotificationCaptain =
|
static String deleteNotificationCaptain =
|
||||||
"$ride/notificationCaptain/delete.php";
|
"$ride/notificationCaptain/delete.php";
|
||||||
|
//-----------------invitor------------------
|
||||||
|
|
||||||
|
static String addInviteDriver = "$server/ride/invitor/add.php";
|
||||||
|
static String addInvitationPassenger =
|
||||||
|
"$server/ride/invitor/addInvitationPassenger.php";
|
||||||
|
static String getInviteDriver = "$server/ride/invitor/get.php";
|
||||||
|
static String getDriverInvitationToPassengers =
|
||||||
|
"$server/ride/invitor/getDriverInvitationToPassengers.php";
|
||||||
|
static String updateInviteDriver = "$server/ride/invitor/update.php";
|
||||||
|
static String updatePassengerGift =
|
||||||
|
"$server/ride/invitor/updatePassengerGift.php";
|
||||||
//-----------------Api Key------------------
|
//-----------------Api Key------------------
|
||||||
static String addApiKey = "$ride/apiKey/add.php";
|
static String addApiKey = "$ride/apiKey/add.php";
|
||||||
static String getApiKey = "$ride/apiKey/get.php";
|
static String getApiKey = "$ride/apiKey/get.php";
|
||||||
@@ -121,6 +142,7 @@ class AppLink {
|
|||||||
|
|
||||||
//-----------------Feed Back------------------
|
//-----------------Feed Back------------------
|
||||||
static String addFeedBack = "$ride/feedBack/add.php";
|
static String addFeedBack = "$ride/feedBack/add.php";
|
||||||
|
static String uploadAudio = "$ride/feedBack/upload_audio.php";
|
||||||
static String getFeedBack = "$ride/feedBack/get.php";
|
static String getFeedBack = "$ride/feedBack/get.php";
|
||||||
static String updateFeedBack = "$ride/feedBack/updateFeedBack.php";
|
static String updateFeedBack = "$ride/feedBack/updateFeedBack.php";
|
||||||
|
|
||||||
@@ -142,7 +164,8 @@ class AppLink {
|
|||||||
static String updateLicense = "$ride/license/updateFeedBack.php";
|
static String updateLicense = "$ride/license/updateFeedBack.php";
|
||||||
//-----------------RegisrationCar------------------
|
//-----------------RegisrationCar------------------
|
||||||
static String addRegisrationCar = "$ride/RegisrationCar/add.php";
|
static String addRegisrationCar = "$ride/RegisrationCar/add.php";
|
||||||
static String getRegisrationCar = "$endPoint/ride/RegisrationCar/get.php";
|
static String getRegisrationCar =
|
||||||
|
"${box.read(BoxName.serverChosen)}/ride/RegisrationCar/get.php";
|
||||||
static String selectDriverAndCarForMishwariTrip =
|
static String selectDriverAndCarForMishwariTrip =
|
||||||
"$ride/RegisrationCar/selectDriverAndCarForMishwariTrip.php";
|
"$ride/RegisrationCar/selectDriverAndCarForMishwariTrip.php";
|
||||||
static String updateRegisrationCar = "$ride/RegisrationCar/update.php";
|
static String updateRegisrationCar = "$ride/RegisrationCar/update.php";
|
||||||
@@ -150,6 +173,7 @@ class AppLink {
|
|||||||
//-----------------mishwari------------------
|
//-----------------mishwari------------------
|
||||||
|
|
||||||
static String addMishwari = "$ride/mishwari/add.php";
|
static String addMishwari = "$ride/mishwari/add.php";
|
||||||
|
static String cancelMishwari = "$ride/mishwari/cancel.php";
|
||||||
static String getMishwari = "$ride/mishwari/get.php";
|
static String getMishwari = "$ride/mishwari/get.php";
|
||||||
|
|
||||||
//-----------------DriverOrder------------------
|
//-----------------DriverOrder------------------
|
||||||
@@ -163,6 +187,8 @@ class AppLink {
|
|||||||
|
|
||||||
// =====================================
|
// =====================================
|
||||||
static String addRateToPassenger = "$ride/rate/add.php";
|
static String addRateToPassenger = "$ride/rate/add.php";
|
||||||
|
static String savePlacesServer = "$ride/places/add.php";
|
||||||
|
static String getapiKey = "$ride/apiKey/get.php";
|
||||||
static String addRateToDriver = "$ride/rate/addRateToDriver.php";
|
static String addRateToDriver = "$ride/rate/addRateToDriver.php";
|
||||||
static String getDriverRate = "$ride/rate/getDriverRate.php";
|
static String getDriverRate = "$ride/rate/getDriverRate.php";
|
||||||
static String getPassengerRate = "$ride/rate/getPassengerRate.php";
|
static String getPassengerRate = "$ride/rate/getPassengerRate.php";
|
||||||
@@ -183,12 +209,14 @@ class AppLink {
|
|||||||
static String uploadEgypt = "$server/uploadEgypt.php";
|
static String uploadEgypt = "$server/uploadEgypt.php";
|
||||||
|
|
||||||
//==================certifcate==========
|
//==================certifcate==========
|
||||||
static String location = '$endPoint/ride/location';
|
static String location = '${box.read(BoxName.serverChosen)}/ride/location';
|
||||||
static String getCarsLocationByPassenger = "$location/get.php";
|
static String getCarsLocationByPassenger = "$location/get.php";
|
||||||
static String addpassengerLocation = "$location/addpassengerLocation.php";
|
static String addpassengerLocation = "$location/addpassengerLocation.php";
|
||||||
static String getCarsLocationByPassengerSpeed = "$location/getSpeed.php";
|
static String getCarsLocationByPassengerSpeed = "$location/getSpeed.php";
|
||||||
static String getCarsLocationByPassengerComfort = "$location/getComfort.php";
|
static String getCarsLocationByPassengerComfort = "$location/getComfort.php";
|
||||||
static String getCarsLocationByPassengerBalash = "$location/getBalash.php";
|
static String getCarsLocationByPassengerBalash = "$location/getBalash.php";
|
||||||
|
static String getCarsLocationByPassengerPinkBike =
|
||||||
|
"$location/getPinkBike.php";
|
||||||
static String getCarsLocationByPassengerDelivery =
|
static String getCarsLocationByPassengerDelivery =
|
||||||
"$location/getDelivery.php";
|
"$location/getDelivery.php";
|
||||||
static String getLocationParents = "$location/getLocationParents.php";
|
static String getLocationParents = "$location/getLocationParents.php";
|
||||||
@@ -239,7 +267,10 @@ class AppLink {
|
|||||||
static String deletecaptainAccounr = "$authCaptin/deletecaptainAccounr.php";
|
static String deletecaptainAccounr = "$authCaptin/deletecaptainAccounr.php";
|
||||||
static String updateAccountBank = "$authCaptin/updateAccountBank.php";
|
static String updateAccountBank = "$authCaptin/updateAccountBank.php";
|
||||||
static String getAccount = "$authCaptin/getAccount.php";
|
static String getAccount = "$authCaptin/getAccount.php";
|
||||||
|
static String updatePassengersInvitation =
|
||||||
|
"$server/ride/invitor/updatePassengersInvitation.php";
|
||||||
|
static String updateDriverInvitationDirectly =
|
||||||
|
"$server/ride/invitor/updateDriverInvitationDirectly.php";
|
||||||
//===================Admin Captin============
|
//===================Admin Captin============
|
||||||
|
|
||||||
static String getPassengerDetailsByPassengerID =
|
static String getPassengerDetailsByPassengerID =
|
||||||
@@ -248,6 +279,7 @@ class AppLink {
|
|||||||
static String getPassengerbyEmail = "$server/Admin/getPassengerbyEmail.php";
|
static String getPassengerbyEmail = "$server/Admin/getPassengerbyEmail.php";
|
||||||
static String addAdminUser = "$server/Admin/adminUser/add.php";
|
static String addAdminUser = "$server/Admin/adminUser/add.php";
|
||||||
static String getAdminUser = "$server/Admin/adminUser/get.php";
|
static String getAdminUser = "$server/Admin/adminUser/get.php";
|
||||||
|
static String addError = "$server/Admin/errorApp.php";
|
||||||
static String getCaptainDetailsByEmailOrIDOrPhone =
|
static String getCaptainDetailsByEmailOrIDOrPhone =
|
||||||
"$server/Admin/AdminCaptain/getCaptainDetailsByEmailOrIDOrPhone.php";
|
"$server/Admin/AdminCaptain/getCaptainDetailsByEmailOrIDOrPhone.php";
|
||||||
static String getCaptainDetails = "$server/Admin/AdminCaptain/get.php";
|
static String getCaptainDetails = "$server/Admin/AdminCaptain/get.php";
|
||||||
|
|||||||
22
lib/constant/notification.dart
Normal file
22
lib/constant/notification.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
List<String> messages = [
|
||||||
|
"🚗 عروض مميزة: استمتع بأقل الأسعار وأفضل العروض! افتح تطبيق سفر الآن لتحصل على المزيد من الخيارات. 🌟",
|
||||||
|
"💸 وفر الآن: وفر مع تطبيق سفر! عروض مستمرة وخيارات متعددة تناسب احتياجاتك. 🔥",
|
||||||
|
"🔒 أمان وراحة: مع تطبيق سفر، احصل على أمان وراحة بأفضل الأسعار! 🚕",
|
||||||
|
"💼 خيارات متنوعة: استفد من خيارات متنوعة وأسعار تنافسية على تطبيق سفر، الأفضل دائماً. 🌐",
|
||||||
|
"💵 توفير مضمون: حافظ على ميزانيتك وسافر بأمان مع تطبيق سفر – العروض لا تتوقف! 🎉",
|
||||||
|
"🌍 وجهات مميزة: أفضل وجهات السفر، بأقل الأسعار مع تطبيق سفر – تابعنا الآن! 🛤️",
|
||||||
|
"🛣️ سهولة وراحة: رحلاتك أصبحت أسهل وأرخص – سافر معنا وتمتع بأفضل التجارب. 🎊",
|
||||||
|
"📲 حجز سهل: احجز رحلتك بسهولة وأمان مع سفر – المزيد من الخصومات في انتظارك! 🎁",
|
||||||
|
"👑 فئة مميزة: خليك من الفئة المميزة واستفد بأفضل الأسعار مع تطبيق سفر. 💯",
|
||||||
|
"💡 خيارات متعددة: نوفر لك خيارات متعددة وسعر مناسب – جرب تطبيق سفر الآن! 🚖",
|
||||||
|
"✨ عروض متجددة: العروض لا تتوقف على تطبيق سفر – احجز رحلتك الآن وتمتع بالمزيد! 📅",
|
||||||
|
"🚀 سهولة الوصول: السفر أصبح أسهل وأسرع مع تطبيق سفر – كن مستعدًا لأفضل التجارب! 🌠",
|
||||||
|
"🧳 راحة وأمان: تطبيق سفر يقدم لك أمان وراحة بأقل الأسعار! 📉",
|
||||||
|
"🔥 عروض فورية: احجز الآن واستمتع بعروض لا تُفوّت على تطبيق سفر! 🚘",
|
||||||
|
"🚖 أسعار تنافسية: اختر رحلتك الآن بأسعار تنافسية وتمتع بالراحة والأمان مع تطبيق سفر. ✅",
|
||||||
|
"💥 أسعار خاصة: أسعار خاصة بانتظارك على تطبيق سفر! افتح التطبيق الآن واحجز رحلتك. 🌐",
|
||||||
|
"🌟 راحة البال: انطلق بأمان وراحة مع تطبيق سفر – استمتع بأفضل الأسعار. 💸",
|
||||||
|
"📍 خصومات حصرية: استفد من الخصومات الحصرية والعروض المستمرة على تطبيق سفر! 🛤️",
|
||||||
|
"🛫 تجربة سهلة: رحلاتك أصبحت أفضل وأسهل مع تطبيق سفر – افتح التطبيق واستمتع بالتجربة. ✨",
|
||||||
|
"🔔 عروض لا مثيل لها: كن جاهزًا لعروض لا مثيل لها! تطبيق سفر يقدم لك أفضل الخيارات بأقل الأسعار. 🎉",
|
||||||
|
];
|
||||||
@@ -5,35 +5,39 @@ import 'package:google_fonts/google_fonts.dart';
|
|||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
|
|
||||||
class AppStyle {
|
class AppStyle {
|
||||||
static TextStyle headTitle = TextStyle(
|
static TextStyle headTitle = const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 40,
|
fontSize: 40,
|
||||||
color: AppColor.accentColor,
|
color: AppColor.accentColor,
|
||||||
fontFamily: box.read(BoxName.lang) == 'ar'
|
// fontFamily: box.read(BoxName.lang) == 'ar'
|
||||||
// ?GoogleFonts.notoNaskhArabic().fontFamily
|
// // ?GoogleFonts.notoNaskhArabic().fontFamily
|
||||||
? GoogleFonts.notoNaskhArabic().fontFamily
|
// ? GoogleFonts.notoNaskhArabic().fontFamily
|
||||||
: GoogleFonts.roboto().fontFamily);
|
// : GoogleFonts.roboto().fontFamily,
|
||||||
static TextStyle headTitle2 = TextStyle(
|
);
|
||||||
fontWeight: FontWeight.bold,
|
static TextStyle headTitle2 = const TextStyle(
|
||||||
fontSize: 26,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.writeColor,
|
fontSize: 22,
|
||||||
fontFamily: box.read(BoxName.lang) == 'ar'
|
color: AppColor.writeColor,
|
||||||
? GoogleFonts.notoNaskhArabic().fontFamily
|
// fontFamily: box.read(BoxName.lang) == 'ar'
|
||||||
: GoogleFonts.roboto().fontFamily);
|
// ? GoogleFonts.notoNaskhArabic().fontFamily
|
||||||
|
// : GoogleFonts.roboto().fontFamily
|
||||||
|
);
|
||||||
static TextStyle title = TextStyle(
|
static TextStyle title = TextStyle(
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
fontSize: box.read(BoxName.lang) == 'ar' ? 14 : 16,
|
fontSize: box.read(BoxName.lang) == 'ar' ? 14 : 16,
|
||||||
color: AppColor.writeColor,
|
color: AppColor.writeColor,
|
||||||
fontFamily: box.read(BoxName.lang) == 'ar'
|
// fontFamily: box.read(BoxName.lang) == 'ar'
|
||||||
? GoogleFonts.notoNaskhArabic().fontFamily
|
// ? GoogleFonts.notoNaskhArabic().fontFamily
|
||||||
: GoogleFonts.roboto().fontFamily);
|
// : GoogleFonts.roboto().fontFamily
|
||||||
static TextStyle subtitle = TextStyle(
|
);
|
||||||
fontWeight: FontWeight.bold,
|
static TextStyle subtitle = const TextStyle(
|
||||||
fontSize: 13,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.writeColor,
|
fontSize: 13,
|
||||||
fontFamily: box.read(BoxName.lang) == 'ar'
|
color: AppColor.writeColor,
|
||||||
? GoogleFonts.notoNaskhArabic().fontFamily
|
// fontFamily: box.read(BoxName.lang) == 'ar'
|
||||||
: GoogleFonts.roboto().fontFamily);
|
// ? GoogleFonts.notoNaskhArabic().fontFamily
|
||||||
|
// : GoogleFonts.roboto().fontFamily
|
||||||
|
);
|
||||||
static TextStyle number = const TextStyle(
|
static TextStyle number = const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@@ -43,7 +47,9 @@ class AppStyle {
|
|||||||
static BoxDecoration boxDecoration = const BoxDecoration(
|
static BoxDecoration boxDecoration = const BoxDecoration(
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: AppColor.accentColor, blurRadius: 5, offset: Offset(2, 4)),
|
color: Color.fromARGB(255, 218, 218, 255),
|
||||||
|
blurRadius: 5,
|
||||||
|
offset: Offset(2, 4)),
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: AppColor.accentColor, blurRadius: 5, offset: Offset(-2, -2))
|
color: AppColor.accentColor, blurRadius: 5, offset: Offset(-2, -2))
|
||||||
],
|
],
|
||||||
|
|||||||
83
lib/constant/univeries_polygon.dart
Normal file
83
lib/constant/univeries_polygon.dart
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
|
||||||
|
class UniversitiesPolygons {
|
||||||
|
// AUC polygon points
|
||||||
|
static const List<List<LatLng>> universityPolygons = [
|
||||||
|
// AUC Polygon
|
||||||
|
[
|
||||||
|
LatLng(30.013431, 31.502572),
|
||||||
|
LatLng(30.018469, 31.497478),
|
||||||
|
LatLng(30.023158, 31.495870),
|
||||||
|
LatLng(30.025084, 31.496781),
|
||||||
|
LatLng(30.018701, 31.511393),
|
||||||
|
LatLng(30.015312, 31.508310),
|
||||||
|
],
|
||||||
|
// Example polygon for University 'German University in Cairo (GUC)'
|
||||||
|
[
|
||||||
|
LatLng(29.984554, 31.437829),
|
||||||
|
LatLng(29.990363, 31.438390),
|
||||||
|
LatLng(29.990560, 31.445643),
|
||||||
|
LatLng(29.984436, 31.445825),
|
||||||
|
],
|
||||||
|
//Future University in Egypt (FUE)
|
||||||
|
[
|
||||||
|
LatLng(30.025794, 31.490946),
|
||||||
|
LatLng(30.028341, 31.491014),
|
||||||
|
LatLng(30.028341, 31.492586),
|
||||||
|
LatLng(30.025844, 31.492491),
|
||||||
|
],
|
||||||
|
//'British University in Egypt (BUE)'
|
||||||
|
[
|
||||||
|
LatLng(30.117423, 31.605834),
|
||||||
|
LatLng(30.118224, 31.605543),
|
||||||
|
LatLng(30.118649, 31.607361),
|
||||||
|
LatLng(30.118932, 31.608033),
|
||||||
|
LatLng(30.119592, 31.612159),
|
||||||
|
LatLng(30.119372, 31.612958),
|
||||||
|
LatLng(30.120017, 31.617102),
|
||||||
|
LatLng(30.119435, 31.617193),
|
||||||
|
],
|
||||||
|
//Misr International University (MIU)
|
||||||
|
[
|
||||||
|
LatLng(30.166498, 31.491663),
|
||||||
|
LatLng(30.171956, 31.491060),
|
||||||
|
LatLng(30.172212, 31.495754),
|
||||||
|
LatLng(30.167112, 31.496108),
|
||||||
|
],
|
||||||
|
// Canadian International College (CIC)
|
||||||
|
[
|
||||||
|
LatLng(30.034312, 31.428963),
|
||||||
|
LatLng(30.035661, 31.429037),
|
||||||
|
LatLng(30.036074, 31.430522),
|
||||||
|
LatLng(30.036017, 31.431146),
|
||||||
|
LatLng(30.034580, 31.431117),
|
||||||
|
],
|
||||||
|
// October 6 University (O6U)
|
||||||
|
[
|
||||||
|
LatLng(29.974102, 30.946934),
|
||||||
|
LatLng(29.976620, 30.944925),
|
||||||
|
LatLng(29.979848, 30.949832),
|
||||||
|
LatLng(29.977372, 30.951950),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
LatLng(30.029312, 31.210046),
|
||||||
|
LatLng(30.027124, 31.201393),
|
||||||
|
LatLng(30.014523, 31.205087),
|
||||||
|
LatLng(30.015416, 31.212218),
|
||||||
|
LatLng(30.027325, 31.210661),
|
||||||
|
],
|
||||||
|
// Add polygons for 8 more universities...
|
||||||
|
];
|
||||||
|
|
||||||
|
static const List<String> universityNames = [
|
||||||
|
"American University in Cairo (AUC)",
|
||||||
|
'German University in Cairo (GUC)',
|
||||||
|
'Future University in Egypt (FUE)',
|
||||||
|
'British University in Egypt (BUE)',
|
||||||
|
'Misr International University (MIU)',
|
||||||
|
'Canadian International College (CIC)',
|
||||||
|
'October 6 University (O6U)',
|
||||||
|
"Cairo University",
|
||||||
|
// Add names for 8 more universities...
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:SEFER/constant/box_name.dart';
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
import 'package:SEFER/controller/auth/login_controller.dart';
|
import 'package:SEFER/controller/auth/login_controller.dart';
|
||||||
import 'package:SEFER/main.dart';
|
import 'package:SEFER/main.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:google_sign_in/google_sign_in.dart';
|
import 'package:google_sign_in/google_sign_in.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
import '../../constant/links.dart';
|
||||||
import '../../onbording_page.dart';
|
import '../../onbording_page.dart';
|
||||||
|
import '../functions/crud.dart';
|
||||||
|
|
||||||
class GoogleSignInHelper {
|
class GoogleSignInHelper {
|
||||||
static final GoogleSignIn _googleSignIn = GoogleSignIn(
|
static final GoogleSignIn _googleSignIn = GoogleSignIn(
|
||||||
@@ -32,26 +39,114 @@ class GoogleSignInHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<GoogleSignInAccount?> signInFromLogin() async {
|
Future<GoogleSignInAccount?> signInFromLogin() async {
|
||||||
try {
|
try {
|
||||||
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
|
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
|
||||||
if (googleUser != null) {
|
if (googleUser != null) {
|
||||||
await _handleSignUp(googleUser);
|
await _handleSignUp(googleUser);
|
||||||
// if (box.read(BoxName.countryCode) == 'Egypt') {
|
|
||||||
await Get.put(LoginController()).loginUsingCredentials(
|
await Get.put(LoginController()).loginUsingCredentials(
|
||||||
box.read(BoxName.passengerID).toString(),
|
box.read(BoxName.passengerID).toString(),
|
||||||
box.read(BoxName.email).toString(),
|
box.read(BoxName.email).toString(),
|
||||||
);
|
);
|
||||||
// } else if (box.read(BoxName.countryCode) == 'Jordan') {
|
|
||||||
// // Get.to(() => AiPage());
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
return googleUser;
|
return googleUser;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// if (error is GoogleSignInAuthenticationException) {
|
||||||
|
// // Handle authentication errors from Google Sign-In
|
||||||
|
// addError("Google sign-in authentication error: ${error.message}",
|
||||||
|
// '<GoogleSignInAccount?> signInFromLogin()');
|
||||||
|
// } else if (error is GoogleSignInAccountNotFoundException) {
|
||||||
|
// // Handle the case where the user is not found (if applicable)
|
||||||
|
// addError("Google sign-in account not found error: ${error.message}",
|
||||||
|
// '<GoogleSignInAccount?> signInFromLogin()');
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
if (error is SocketException) {
|
||||||
|
// Handle network issues, like SSL certificate issues
|
||||||
|
addError("Network error (SSL certificate issue): ${error.message}",
|
||||||
|
'<GoogleSignInAccount?> signInFromLogin()');
|
||||||
|
} else if (error is PlatformException) {
|
||||||
|
// Handle platform-specific errors, like Google Play Services issues
|
||||||
|
if (error.code == 'sign_in_required') {
|
||||||
|
// Google Play Services are required but not installed or outdated
|
||||||
|
showGooglePlayServicesError();
|
||||||
|
} else {
|
||||||
|
addError("Platform error: ${error.message}",
|
||||||
|
'<GoogleSignInAccount?> signInFromLogin()');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Catch all other unknown errors
|
||||||
|
addError("Unknown error: ${error.toString()}",
|
||||||
|
'<GoogleSignInAccount?> signInFromLogin()');
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showGooglePlayServicesError() async {
|
||||||
|
const playStoreUrl =
|
||||||
|
'https://play.google.com/store/apps/details?id=com.google.android.gms&hl=en_US';
|
||||||
|
|
||||||
|
if (await canLaunchUrl(Uri.parse(playStoreUrl))) {
|
||||||
|
await launchUrl(Uri.parse(playStoreUrl));
|
||||||
|
} else {
|
||||||
|
// Fallback if the URL can't be opened
|
||||||
|
showDialog(
|
||||||
|
context: Get.context!,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text('Error'.tr),
|
||||||
|
content: Text(
|
||||||
|
'Could not open the Google Play Store. Please update Google Play Services manually.'
|
||||||
|
.tr),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text('Close'.tr),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Future<GoogleSignInAccount?> signInFromLogin() async {
|
||||||
|
// try {
|
||||||
|
// final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
|
||||||
|
// if (googleUser != null) {
|
||||||
|
// await _handleSignUp(googleUser);
|
||||||
|
// // if (box.read(BoxName.countryCode) == 'Egypt') {
|
||||||
|
// await Get.put(LoginController()).loginUsingCredentials(
|
||||||
|
// box.read(BoxName.passengerID).toString(),
|
||||||
|
// box.read(BoxName.email).toString(),
|
||||||
|
// );
|
||||||
|
// // } else if (box.read(BoxName.countryCode) == 'Jordan') {
|
||||||
|
// // // Get.to(() => AiPage());
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
// return googleUser;
|
||||||
|
// } catch (error) {
|
||||||
|
// addError(error.toString(), '<GoogleSignInAccount?> signInFromLogin()');
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
addError(String error, where) async {
|
||||||
|
CRUD().post(link: AppLink.addError, payload: {
|
||||||
|
'error': error.toString(), // Example error description
|
||||||
|
'userId': box.read(BoxName.driverID) ??
|
||||||
|
box.read(BoxName.passengerID), // Example user ID
|
||||||
|
'userType': box.read(BoxName.driverID) != null
|
||||||
|
? 'Driver'
|
||||||
|
: 'passenger', // Example user type
|
||||||
|
'phone': box.read(BoxName.phone) ??
|
||||||
|
box.read(BoxName.phoneDriver), // Example phone number
|
||||||
|
|
||||||
|
'device': where
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Method to handle Google Sign-Out
|
// Method to handle Google Sign-Out
|
||||||
static Future<void> signOut() async {
|
static Future<void> signOut() async {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:SEFER/constant/info.dart';
|
import 'package:SEFER/constant/info.dart';
|
||||||
import 'package:SEFER/controller/firebase/firbase_messge.dart';
|
import 'package:SEFER/controller/firebase/firbase_messge.dart';
|
||||||
|
import 'package:SEFER/controller/functions/add_error.dart';
|
||||||
import 'package:SEFER/views/auth/login_page.dart';
|
import 'package:SEFER/views/auth/login_page.dart';
|
||||||
import 'package:SEFER/views/auth/sms_verfy_page.dart';
|
import 'package:SEFER/views/auth/sms_verfy_page.dart';
|
||||||
|
import 'package:SEFER/views/widgets/my_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/constant/box_name.dart';
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
@@ -13,6 +16,9 @@ import 'package:SEFER/main.dart';
|
|||||||
import 'package:SEFER/views/home/map_page_passenger.dart';
|
import 'package:SEFER/views/home/map_page_passenger.dart';
|
||||||
import 'package:location/location.dart';
|
import 'package:location/location.dart';
|
||||||
|
|
||||||
|
import '../../print.dart';
|
||||||
|
import '../functions/package_info.dart';
|
||||||
|
|
||||||
class LoginController extends GetxController {
|
class LoginController extends GetxController {
|
||||||
final formKey = GlobalKey<FormState>();
|
final formKey = GlobalKey<FormState>();
|
||||||
final formKeyAdmin = GlobalKey<FormState>();
|
final formKeyAdmin = GlobalKey<FormState>();
|
||||||
@@ -29,9 +35,20 @@ class LoginController extends GetxController {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
getAppTester(String appPlatform) async {
|
@override
|
||||||
var res = await CRUD()
|
void onInit() async {
|
||||||
.get(link: AppLink.getTesterApp, payload: {'appPlatform': appPlatform});
|
box.read(BoxName.isTest) == null ||
|
||||||
|
box.read(BoxName.isTest).toString() == '0'
|
||||||
|
? await getAppTester()
|
||||||
|
: null;
|
||||||
|
|
||||||
|
super.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
getAppTester() async {
|
||||||
|
var res = await CRUD().get(
|
||||||
|
link: AppLink.getTesterApp,
|
||||||
|
payload: {'appPlatform': AppInformation.appName});
|
||||||
if (res != 'failure') {
|
if (res != 'failure') {
|
||||||
var d = jsonDecode(res);
|
var d = jsonDecode(res);
|
||||||
|
|
||||||
@@ -64,6 +81,8 @@ class LoginController extends GetxController {
|
|||||||
await CRUD().get(link: AppLink.loginFromGooglePassenger, payload: {
|
await CRUD().get(link: AppLink.loginFromGooglePassenger, payload: {
|
||||||
'email': email,
|
'email': email,
|
||||||
'id': passengerID,
|
'id': passengerID,
|
||||||
|
"platform": Platform.isAndroid ? 'android' : 'ios',
|
||||||
|
"appName": AppInformation.appName,
|
||||||
});
|
});
|
||||||
if (res == 'Failure') {
|
if (res == 'Failure') {
|
||||||
Get.offAll(SmsSignupEgypt());
|
Get.offAll(SmsSignupEgypt());
|
||||||
@@ -73,12 +92,22 @@ class LoginController extends GetxController {
|
|||||||
} else {
|
} else {
|
||||||
var jsonDecoeded = jsonDecode(res);
|
var jsonDecoeded = jsonDecode(res);
|
||||||
if (jsonDecoeded.isNotEmpty) {
|
if (jsonDecoeded.isNotEmpty) {
|
||||||
|
var d = jsonDecoeded['data'][0];
|
||||||
if (jsonDecoeded['status'] == 'success' &&
|
if (jsonDecoeded['status'] == 'success' &&
|
||||||
jsonDecoeded['data'][0]['verified'].toString() == '1') {
|
d['verified'].toString() == '1') {
|
||||||
//
|
//
|
||||||
|
|
||||||
box.write(BoxName.isVerified, '1');
|
box.write(BoxName.isVerified, '1');
|
||||||
box.write(BoxName.email, jsonDecoeded['data'][0]['email']);
|
box.write(BoxName.email, d['email']);
|
||||||
box.write(BoxName.phone, jsonDecoeded['data'][0]['phone']);
|
box.write(BoxName.phone, d['phone']);
|
||||||
|
box.write(BoxName.isTest, '1');
|
||||||
|
box.write(BoxName.package, d['package']);
|
||||||
|
box.write(BoxName.promo, d['promo']);
|
||||||
|
box.write(BoxName.discount, d['discount']);
|
||||||
|
box.write(BoxName.validity, d['validity']);
|
||||||
|
box.write(BoxName.isInstall, d['isInstall'] ?? 'none');
|
||||||
|
box.write(BoxName.isGiftToken, d['isGiftToken'] ?? 'none');
|
||||||
|
box.write(BoxName.inviteCode, d['inviteCode'] ?? 'none');
|
||||||
|
|
||||||
var token = await CRUD().get(link: AppLink.getTokens, payload: {
|
var token = await CRUD().get(link: AppLink.getTokens, payload: {
|
||||||
'passengerID': box.read(BoxName.passengerID).toString()
|
'passengerID': box.read(BoxName.passengerID).toString()
|
||||||
@@ -86,34 +115,85 @@ class LoginController extends GetxController {
|
|||||||
if (token != 'failure') {
|
if (token != 'failure') {
|
||||||
if (jsonDecode(token)['data'][0]['token'] !=
|
if (jsonDecode(token)['data'][0]['token'] !=
|
||||||
box.read(BoxName.tokenFCM)) {
|
box.read(BoxName.tokenFCM)) {
|
||||||
Get.put(FirebaseMessagesController())
|
Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP(
|
||||||
.sendNotificationToAnyWithoutData(
|
|
||||||
'token change'.tr,
|
'token change'.tr,
|
||||||
'change device'.tr,
|
'change device'.tr,
|
||||||
jsonDecode(token)['data'][0]['token'].toString(),
|
jsonDecode(token)['data'][0]['token'].toString(),
|
||||||
|
[],
|
||||||
'cancel.wav',
|
'cancel.wav',
|
||||||
);
|
);
|
||||||
Future.delayed(const Duration(seconds: 1));
|
Future.delayed(const Duration(seconds: 1));
|
||||||
await CRUD().post(link: AppLink.addTokens, payload: {
|
await CRUD().post(
|
||||||
'token': box.read(BoxName.tokenFCM),
|
link: "${AppLink.server}/ride/firebase/add.php",
|
||||||
'passengerID': box.read(BoxName.passengerID).toString()
|
payload: {
|
||||||
});
|
'token': box.read(BoxName.tokenFCM),
|
||||||
// Get.defaultDialog(
|
'passengerID': box.read(BoxName.passengerID).toString()
|
||||||
// title: 'Device Change Detected'.tr,
|
});
|
||||||
// middleText:
|
CRUD().post(
|
||||||
// 'You can only use one device at a time. This device will now be set as your active device.'
|
link:
|
||||||
// .tr,
|
"${AppLink.seferAlexandriaServer}/ride/firebase/add.php",
|
||||||
// textConfirm: 'OK'.tr,
|
payload: {
|
||||||
// confirmTextColor: Colors.white,
|
'token': box.read(BoxName.tokenFCM),
|
||||||
// onConfirm: () {
|
'passengerID': box.read(BoxName.passengerID).toString()
|
||||||
// Get.back();
|
});
|
||||||
// Get.offAll(() => const MapPagePassenger());
|
CRUD().post(
|
||||||
// },
|
link: "${AppLink.seferGizaServer}/ride/firebase/add.php",
|
||||||
// );
|
payload: {
|
||||||
// Get.snackbar('title', 'message');
|
'token': box.read(BoxName.tokenFCM),
|
||||||
|
'passengerID': box.read(BoxName.passengerID).toString()
|
||||||
|
});
|
||||||
|
Get.defaultDialog(
|
||||||
|
title: 'Device Change Detected'.tr,
|
||||||
|
middleText:
|
||||||
|
'You can only use one device at a time. This device will now be set as your active device.'
|
||||||
|
.tr,
|
||||||
|
textConfirm: 'OK'.tr,
|
||||||
|
confirmTextColor: Colors.white,
|
||||||
|
onConfirm: () {
|
||||||
|
Get.back();
|
||||||
|
Get.offAll(() => const MapPagePassenger());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
print('same');
|
||||||
}
|
}
|
||||||
|
} // Logging to check if inviteCode is written correctly
|
||||||
|
|
||||||
|
if (box.read(BoxName.inviteCode).toString() != 'none' &&
|
||||||
|
box.read(BoxName.isInstall).toString() != '1') {
|
||||||
|
await CRUD()
|
||||||
|
.post(link: AppLink.updatePassengersInvitation, payload: {
|
||||||
|
"inviteCode": box.read(BoxName.inviteCode).toString(),
|
||||||
|
"passengerID": box.read(BoxName.passengerID).toString(),
|
||||||
|
});
|
||||||
|
Get.defaultDialog(
|
||||||
|
title: 'Invitation Used'
|
||||||
|
.tr, // Automatically translates based on the current locale
|
||||||
|
middleText: "Your invite code was successfully applied!"
|
||||||
|
.tr, // Automatically translates based on the current locale
|
||||||
|
onConfirm: () {
|
||||||
|
try {
|
||||||
|
CRUD().post(link: AppLink.addPassengersPromo, payload: {
|
||||||
|
"promoCode":
|
||||||
|
'S-${box.read(BoxName.name).toString().split(' ')[0]}',
|
||||||
|
"amount": '25',
|
||||||
|
"passengerID": box.read(BoxName.passengerID).toString(),
|
||||||
|
"description": 'promo first'
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
addError(e.toString(),
|
||||||
|
'passenger Invitation Used dialogu as promo line 185 login_controller');
|
||||||
|
} finally {
|
||||||
|
// Continue with the rest of your flow, regardless of errors
|
||||||
|
// For example, navigate to the next page
|
||||||
|
Get.offAll(() => const MapPagePassenger());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
textConfirm: "OK".tr, // Confirm button text
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Get.offAll(() => const MapPagePassenger());
|
||||||
}
|
}
|
||||||
Get.offAll(() => const MapPagePassenger());
|
|
||||||
} else {
|
} else {
|
||||||
Get.offAll(() => SmsSignupEgypt());
|
Get.offAll(() => SmsSignupEgypt());
|
||||||
// Get.snackbar(jsonDecoeded['status'], jsonDecoeded['data'],
|
// Get.snackbar(jsonDecoeded['status'], jsonDecoeded['data'],
|
||||||
@@ -128,34 +208,6 @@ class LoginController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// void adminDashboardOpen() async {
|
|
||||||
// if (formKeyAdmin.currentState!.validate()) {
|
|
||||||
// await DeviceInfoPlus.getDeviceInfo();
|
|
||||||
// if (Platform.isAndroid) {
|
|
||||||
// // var res = await CRUD().get(link: AppLink.getAdminUser, payload: {
|
|
||||||
// // // 'device_number': DeviceInfoPlus.deviceData['serialNumber'].toString(),
|
|
||||||
// // });
|
|
||||||
// // var d = jsonDecode(res);
|
|
||||||
// // // if (DeviceInfoPlus.deviceData['serialNumber'] ==
|
|
||||||
// // d['message']['device_number']) {
|
|
||||||
// Get.back();
|
|
||||||
// Get.to(() => const AdminHomePage());
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
// if (Platform.isIOS) {
|
|
||||||
// // var res = await CRUD().get(link: AppLink.getAdminUser, payload: {
|
|
||||||
// // 'device_number': DeviceInfoPlus.deviceData['identifierForVendor'].toString(),
|
|
||||||
// // });
|
|
||||||
// // var d = jsonDecode(res);
|
|
||||||
// // if (DeviceInfoPlus.deviceData['serialNumber'] ==
|
|
||||||
// // d['message']['device_number']) {
|
|
||||||
// Get.back();
|
|
||||||
// Get.to(() => const AdminHomePage());
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
void login() async {
|
void login() async {
|
||||||
isloading = true;
|
isloading = true;
|
||||||
update();
|
update();
|
||||||
@@ -204,6 +256,12 @@ class LoginController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goToMapPage() {
|
||||||
|
if (box.read(BoxName.email) != null) {
|
||||||
|
Get.offAll(() => const MapPagePassenger());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final location = Location();
|
final location = Location();
|
||||||
|
|
||||||
// late PermissionStatus permissionGranted = PermissionStatus.denied;
|
// late PermissionStatus permissionGranted = PermissionStatus.denied;
|
||||||
@@ -236,15 +294,4 @@ class LoginController extends GetxController {
|
|||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void onInit() async {
|
|
||||||
// permissionLocation = await Permission.locationWhenInUse.isGranted;
|
|
||||||
await getAppTester(AppInformation.appName);
|
|
||||||
// if (isTest == 0 && box.read(BoxName.passengerID) != null) {
|
|
||||||
// // await loginUsingCredentials(
|
|
||||||
// // box.read(BoxName.passengerID), box.read(BoxName.email));
|
|
||||||
// }
|
|
||||||
super.onInit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class OnBoardingControllerImp extends OnBoardingController {
|
|||||||
|
|
||||||
if (currentPage > onBoardingList.length - 1) {
|
if (currentPage > onBoardingList.length - 1) {
|
||||||
box.write(BoxName.onBoarding, 'yes');
|
box.write(BoxName.onBoarding, 'yes');
|
||||||
Get.offAll(LoginPage());
|
Get.offAll(() => LoginPage());
|
||||||
} else {
|
} else {
|
||||||
pageController.animateToPage(currentPage,
|
pageController.animateToPage(currentPage,
|
||||||
duration: const Duration(milliseconds: 900), curve: Curves.easeInOut);
|
duration: const Duration(milliseconds: 900), curve: Curves.easeInOut);
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ import 'dart:convert';
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:SEFER/constant/colors.dart';
|
import 'package:SEFER/constant/colors.dart';
|
||||||
|
import 'package:SEFER/controller/auth/login_controller.dart';
|
||||||
|
import 'package:SEFER/controller/functions/add_error.dart';
|
||||||
|
import 'package:SEFER/controller/local/phone_intel/phone_number.dart';
|
||||||
import 'package:SEFER/views/home/map_page_passenger.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:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/constant/links.dart';
|
import 'package:SEFER/constant/links.dart';
|
||||||
@@ -14,14 +18,14 @@ import 'package:SEFER/views/widgets/elevated_btn.dart';
|
|||||||
|
|
||||||
import '../../constant/box_name.dart';
|
import '../../constant/box_name.dart';
|
||||||
import '../../main.dart';
|
import '../../main.dart';
|
||||||
|
import '../../print.dart';
|
||||||
import '../../views/auth/verify_email_page.dart';
|
import '../../views/auth/verify_email_page.dart';
|
||||||
import '../functions/sms_controller.dart';
|
import '../functions/sms_controller.dart';
|
||||||
|
|
||||||
class RegisterController extends GetxController {
|
class RegisterController extends GetxController {
|
||||||
final formKey = GlobalKey<FormState>();
|
final formKey = GlobalKey<FormState>();
|
||||||
final formKey3 = GlobalKey<FormState>();
|
final formKey3 = GlobalKey<FormState>();
|
||||||
List<String> countryCodes = ['+1', '+91', '+44'];
|
|
||||||
String selectedCountryCode = '+1';
|
|
||||||
TextEditingController firstNameController = TextEditingController();
|
TextEditingController firstNameController = TextEditingController();
|
||||||
TextEditingController lastNameController = TextEditingController();
|
TextEditingController lastNameController = TextEditingController();
|
||||||
TextEditingController emailController = TextEditingController();
|
TextEditingController emailController = TextEditingController();
|
||||||
@@ -41,11 +45,6 @@ class RegisterController extends GetxController {
|
|||||||
super.onInit();
|
super.onInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateCountryCode(String newCode) {
|
|
||||||
selectedCountryCode = newCode;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void startTimer() {
|
void startTimer() {
|
||||||
_timer?.cancel(); // Cancel any existing timer
|
_timer?.cancel(); // Cancel any existing timer
|
||||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
@@ -119,166 +118,207 @@ class RegisterController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendOtpMessage() async {
|
sendOtpMessage() async {
|
||||||
SmsEgyptController smsEgyptController = Get.put(SmsEgyptController());
|
SmsEgyptController smsEgyptController;
|
||||||
|
|
||||||
int randomNumber = Random().nextInt(100000) + 1;
|
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
update();
|
update();
|
||||||
if (formKey3.currentState!.validate()) {
|
try {
|
||||||
if (box.read(BoxName.countryCode) == 'Egypt') {
|
// Initialize SmsEgyptController
|
||||||
if (isValidEgyptianPhoneNumber(phoneController.text) == true) {
|
smsEgyptController = Get.put(SmsEgyptController());
|
||||||
var responseCheker = await CRUD()
|
|
||||||
.post(link: AppLink.checkPhoneNumberISVerfiedPassenger, payload: {
|
// Generate a random OTP
|
||||||
'phone_number': '+2${phoneController.text}',
|
int randomNumber = Random().nextInt(100000) + 1;
|
||||||
'email': box.read(BoxName.email),
|
|
||||||
});
|
isLoading = true;
|
||||||
if (responseCheker != 'failure') {
|
update();
|
||||||
var d = jsonDecode(responseCheker);
|
|
||||||
if (d['message'][0]['verified'].toString() == '1') {
|
// Get phone number from controller
|
||||||
|
String phoneNumber = phoneController.text;
|
||||||
|
|
||||||
|
// Check if the phone number is from Egypt (Assuming Egyptian numbers start with +20)
|
||||||
|
|
||||||
|
if (phoneController.text.isNotEmpty) {
|
||||||
|
bool isEgyptianNumber = phoneNumber.startsWith('+20');
|
||||||
|
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 (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, '',
|
Get.snackbar('Phone number is verified before'.tr, '',
|
||||||
backgroundColor: AppColor.greenColor);
|
backgroundColor: AppColor.greenColor);
|
||||||
box.write(BoxName.isVerified, '1');
|
box.write(BoxName.isVerified, '1');
|
||||||
box.write(BoxName.phone, '+2${phoneController.text}');
|
box.write(BoxName.phone, phoneNumber);
|
||||||
Get.offAll(const MapPagePassenger());
|
Get.offAll(const MapPagePassenger());
|
||||||
} else {
|
} else {
|
||||||
await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: {
|
await sendOtp(phoneNumber, randomNumber, isEgyptianNumber,
|
||||||
'phone_number': '+2${phoneController.text}',
|
smsEgyptController);
|
||||||
'token': randomNumber.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
await smsEgyptController.sendSmsEgypt(
|
|
||||||
phoneController.text.toString(), randomNumber.toString());
|
|
||||||
isSent = true;
|
|
||||||
remainingTime = 300; // Reset to 5 minutes
|
|
||||||
startTimer();
|
|
||||||
isLoading = false;
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: {
|
await sendOtp(phoneNumber, randomNumber, isEgyptianNumber,
|
||||||
'phone_number': '+2${phoneController.text}',
|
smsEgyptController);
|
||||||
'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');
|
|
||||||
}
|
}
|
||||||
} else if (isValidPhoneNumber(phoneController.text)) {
|
} else if (phoneNumber.length > 9) {
|
||||||
await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: {
|
sendOtp(
|
||||||
'phone_number': '+${phoneController.text}',
|
phoneNumber, randomNumber, isEgyptianNumber, smsEgyptController);
|
||||||
'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));
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
MyDialog().getDialog(
|
||||||
|
'Error'.tr, 'Phone number must be exactly 11 digits long'.tr, () {
|
||||||
|
Get.back();
|
||||||
|
});
|
||||||
|
// sendOtp(
|
||||||
|
// phoneNumber, randomNumber, isEgyptianNumber, smsEgyptController);
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Handle error
|
||||||
|
} finally {
|
||||||
|
isLoading = false;
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verifySMSCode() async {
|
// Helper function to send OTP or WhatsApp message based on phone number location
|
||||||
// if (formKey3.currentState!.validate()) {
|
Future<void> sendOtp(String phoneNumber, int otp, bool isEgyptian,
|
||||||
if (isValidEgyptianPhoneNumber(phoneController.text)) {
|
SmsEgyptController controller) async {
|
||||||
var res = await CRUD().post(link: AppLink.verifyOtpMessage, payload: {
|
// Trim any leading or trailing whitespace from the phone number
|
||||||
'phone_number': '+2${phoneController.text}',
|
phoneNumber = phoneNumber.trim();
|
||||||
'token': verifyCode.text.toString(),
|
var dd = await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: {
|
||||||
|
'phone_number': phoneNumber,
|
||||||
|
'token': otp.toString(),
|
||||||
|
});
|
||||||
|
Log.print('dd: ${dd}');
|
||||||
|
if (isEgyptian) {
|
||||||
|
await CRUD().post(link: AppLink.updatePhoneInvalidSMSPassenger, payload: {
|
||||||
|
"phone_number": Get.find<RegisterController>().phoneController.text
|
||||||
});
|
});
|
||||||
if (res != 'failure') {
|
box.write(BoxName.phoneDriver, phoneController.text);
|
||||||
// var dec = jsonDecode(res);
|
var nameParts = box.read(BoxName.name).toString().split(' ');
|
||||||
box.write(BoxName.phoneDriver, '+2${phoneController.text}');
|
var firstName = nameParts.isNotEmpty ? nameParts[0] : 'unknown';
|
||||||
var payload = {
|
var lastName = nameParts.length > 1 ? nameParts[1] : 'unknown';
|
||||||
'id': box.read(BoxName.passengerID),
|
|
||||||
'phone': '+2${phoneController.text}',
|
|
||||||
'email': box.read(BoxName.email),
|
|
||||||
'password': 'unknown',
|
|
||||||
'gender': 'unknown',
|
|
||||||
'birthdate': '2002-01-01',
|
|
||||||
'site': 'unknown',
|
|
||||||
'first_name': box.read(BoxName.name).toString().split(' ')[0],
|
|
||||||
'last_name': box.read(BoxName.name).toString().split(' ')[1],
|
|
||||||
};
|
|
||||||
|
|
||||||
var res1 = await CRUD().post(
|
var payload = {
|
||||||
link: AppLink.signUp,
|
'id': box.read(BoxName.passengerID),
|
||||||
|
'phone': phoneController.text,
|
||||||
|
'email': box.read(BoxName.email),
|
||||||
|
'password': 'unknown',
|
||||||
|
'gender': 'unknown',
|
||||||
|
'birthdate': '2002-01-01',
|
||||||
|
'site': box.read(BoxName.passengerPhotoUrl) ?? 'unknown',
|
||||||
|
'first_name': firstName,
|
||||||
|
'last_name': lastName,
|
||||||
|
};
|
||||||
|
|
||||||
|
var res1 = await CRUD().post(
|
||||||
|
link: AppLink.signUp,
|
||||||
|
payload: payload,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res1 != 'failure') {
|
||||||
|
await CRUD().post(
|
||||||
|
link: '${AppLink.seferAlexandriaServer}/auth/signup.php',
|
||||||
payload: payload,
|
payload: payload,
|
||||||
);
|
);
|
||||||
if (res1 != 'failure') {
|
await CRUD().post(
|
||||||
CRUD().post(
|
link: '${AppLink.seferGizaServer}/auth/signup.php',
|
||||||
link: '${AppLink.seferAlexandriaServer}/auth/signup.php',
|
payload: payload,
|
||||||
payload: payload,
|
);
|
||||||
);
|
|
||||||
CRUD().post(
|
box.write(BoxName.isVerified, '1');
|
||||||
link: '${AppLink.seferGizaServer}/auth/signup.php',
|
box.write(BoxName.isFirstTime, '0');
|
||||||
payload: payload,
|
box.write(BoxName.phone, phoneController.text);
|
||||||
);
|
|
||||||
box.write(BoxName.isVerified, '1');
|
Get.put(LoginController()).loginUsingCredentials(
|
||||||
box.write(BoxName.phone, '+2${phoneController.text}');
|
box.read(BoxName.passengerID).toString(),
|
||||||
Get.offAll(const MapPagePassenger());
|
box.read(BoxName.email).toString(),
|
||||||
}
|
);
|
||||||
} else {
|
|
||||||
Get.snackbar(
|
|
||||||
'Error'.tr, "The email or phone number is already registered.".tr,
|
|
||||||
backgroundColor: Colors.redAccent);
|
|
||||||
}
|
}
|
||||||
|
// await controller.sendSmsEgypt(phoneNumber, otp.toString());
|
||||||
} else {
|
} else {
|
||||||
var res = await CRUD().post(link: AppLink.verifyOtpMessage, payload: {
|
await CRUD().sendWhatsAppAuth(phoneNumber, otp.toString());
|
||||||
'phone_number': '+${phoneController.text}',
|
}
|
||||||
'token': verifyCode.text.toString(),
|
isLoading = false;
|
||||||
});
|
|
||||||
if (res != 'failure') {
|
|
||||||
// var dec = jsonDecode(res);
|
|
||||||
box.write(BoxName.phoneDriver, '+${phoneController.text}');
|
|
||||||
var payload = {
|
|
||||||
'id': box.read(BoxName.passengerID),
|
|
||||||
'phone': '+${phoneController.text}',
|
|
||||||
'email': box.read(BoxName.email),
|
|
||||||
'password': 'unknown',
|
|
||||||
'gender': 'unknown',
|
|
||||||
'birthdate': '2002-01-01',
|
|
||||||
'site': 'unknown',
|
|
||||||
'first_name': box.read(BoxName.name).toString().split(' ')[0],
|
|
||||||
'last_name': box.read(BoxName.name).toString().split(' ')[1],
|
|
||||||
};
|
|
||||||
|
|
||||||
var res1 = await CRUD().post(
|
isSent = true;
|
||||||
link: AppLink.signUp,
|
remainingTime = 300;
|
||||||
payload: payload,
|
update(); // Reset to 5 minutes
|
||||||
);
|
startTimer();
|
||||||
if (res1 != 'failure') {
|
}
|
||||||
CRUD().post(
|
|
||||||
link: '${AppLink.seferAlexandriaServer}/auth/signup.php',
|
verifySMSCode() async {
|
||||||
|
try {
|
||||||
|
if (formKey3.currentState!.validate()) {
|
||||||
|
var res = await CRUD().post(link: AppLink.verifyOtpMessage, payload: {
|
||||||
|
'phone_number': phoneController.text,
|
||||||
|
'token': verifyCode.text.toString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res != 'failure') {
|
||||||
|
box.write(BoxName.phoneDriver, phoneController.text);
|
||||||
|
var nameParts = box.read(BoxName.name).toString().split(' ');
|
||||||
|
var firstName = nameParts.isNotEmpty ? nameParts[0] : 'unknown';
|
||||||
|
var lastName = nameParts.length > 1 ? nameParts[1] : 'unknown';
|
||||||
|
|
||||||
|
var payload = {
|
||||||
|
'id': box.read(BoxName.passengerID),
|
||||||
|
'phone': phoneController.text,
|
||||||
|
'email': box.read(BoxName.email),
|
||||||
|
'password': 'unknown',
|
||||||
|
'gender': 'unknown',
|
||||||
|
'birthdate': '2002-01-01',
|
||||||
|
'site': box.read(BoxName.passengerPhotoUrl) ?? 'unknown',
|
||||||
|
'first_name': firstName,
|
||||||
|
'last_name': lastName,
|
||||||
|
};
|
||||||
|
|
||||||
|
var res1 = await CRUD().post(
|
||||||
|
link: AppLink.signUp,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
);
|
);
|
||||||
CRUD().post(
|
|
||||||
link: '${AppLink.seferGizaServer}/auth/signup.php',
|
if (res1 != 'failure') {
|
||||||
payload: payload,
|
await CRUD().post(
|
||||||
);
|
link: '${AppLink.seferAlexandriaServer}/auth/signup.php',
|
||||||
box.write(BoxName.isVerified, '1');
|
payload: payload,
|
||||||
box.write(BoxName.phone, '+${phoneController.text}');
|
);
|
||||||
Get.offAll(const MapPagePassenger());
|
await CRUD().post(
|
||||||
|
link: '${AppLink.seferGizaServer}/auth/signup.php',
|
||||||
|
payload: payload,
|
||||||
|
);
|
||||||
|
|
||||||
|
box.write(BoxName.isVerified, '1');
|
||||||
|
box.write(BoxName.isFirstTime, '0');
|
||||||
|
box.write(BoxName.phone, phoneController.text);
|
||||||
|
|
||||||
|
Get.put(LoginController()).loginUsingCredentials(
|
||||||
|
box.read(BoxName.passengerID).toString(),
|
||||||
|
box.read(BoxName.email).toString(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Get.snackbar('Error'.tr,
|
||||||
|
"The email or phone number is already registered.".tr,
|
||||||
|
backgroundColor: Colors.redAccent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Get.snackbar('Error'.tr, "phone not verified".tr,
|
||||||
|
backgroundColor: Colors.redAccent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar(
|
Get.snackbar('Error'.tr, "you must insert token code".tr,
|
||||||
'Error'.tr, "The email or phone number is already registered.".tr,
|
backgroundColor: AppColor.redColor);
|
||||||
backgroundColor: Colors.redAccent);
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
addError(e.toString(), 'passenger sign up ');
|
||||||
|
Get.snackbar('Error'.tr, "Something went wrong. Please try again.".tr,
|
||||||
|
backgroundColor: Colors.redAccent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ class AccessTokenManager {
|
|||||||
|
|
||||||
factory AccessTokenManager(String jsonKey) {
|
factory AccessTokenManager(String jsonKey) {
|
||||||
if (_instance._isServiceAccountKeyInitialized()) {
|
if (_instance._isServiceAccountKeyInitialized()) {
|
||||||
print('Service account key already initialized.');
|
// Prevent re-initialization
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
print('Initializing service account key.');
|
|
||||||
_instance.serviceAccountJsonKey = jsonKey;
|
_instance.serviceAccountJsonKey = jsonKey;
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
@@ -29,45 +28,23 @@ class AccessTokenManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getAccessToken() async {
|
Future<String> getAccessToken() async {
|
||||||
print('Attempting to get a new access token...');
|
if (_accessToken != null && DateTime.now().isBefore(_expiryDate!)) {
|
||||||
|
return _accessToken!.data;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// Parse service account credentials from JSON
|
|
||||||
print('Parsing service account credentials...');
|
|
||||||
final serviceAccountCredentials = ServiceAccountCredentials.fromJson(
|
final serviceAccountCredentials = ServiceAccountCredentials.fromJson(
|
||||||
json.decode(serviceAccountJsonKey));
|
json.decode(serviceAccountJsonKey));
|
||||||
|
|
||||||
// Log service account email (or other non-sensitive information)
|
|
||||||
print('Service account email: ${serviceAccountCredentials.email}');
|
|
||||||
|
|
||||||
// Create an authenticated client via the service account
|
|
||||||
print('Creating authenticated client via service account...');
|
|
||||||
final client = await clientViaServiceAccount(
|
final client = await clientViaServiceAccount(
|
||||||
serviceAccountCredentials,
|
serviceAccountCredentials,
|
||||||
['https://www.googleapis.com/auth/firebase.messaging'],
|
['https://www.googleapis.com/auth/firebase.messaging'],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Log successful client creation
|
|
||||||
print('Authenticated client created successfully.');
|
|
||||||
|
|
||||||
// Update the access token and expiry date
|
|
||||||
_accessToken = client.credentials.accessToken;
|
_accessToken = client.credentials.accessToken;
|
||||||
_expiryDate = client.credentials.accessToken.expiry;
|
_expiryDate = client.credentials.accessToken.expiry;
|
||||||
|
|
||||||
// Log the obtained token and expiry time
|
|
||||||
print('Access token obtained: ${_accessToken!.data}');
|
|
||||||
print('Token expiry date: $_expiryDate');
|
|
||||||
|
|
||||||
// Close the client to prevent resource leaks
|
|
||||||
print('Closing authenticated client...');
|
|
||||||
client.close();
|
client.close();
|
||||||
|
|
||||||
// Return the newly fetched access token
|
|
||||||
return _accessToken!.data;
|
return _accessToken!.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Log error if token fetch fails
|
throw Exception('Failed to obtain access token');
|
||||||
print('Failed to obtain a new access token: $e');
|
|
||||||
throw Exception('Failed to obtain a new access token: $e');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:SEFER/env/env.dart';
|
|
||||||
import 'package:SEFER/views/widgets/my_dialog.dart';
|
import 'package:SEFER/views/widgets/my_dialog.dart';
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:googleapis_auth/auth_io.dart';
|
|
||||||
import 'package:googleapis_auth/googleapis_auth.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:SEFER/controller/functions/toast.dart';
|
import 'package:SEFER/controller/functions/toast.dart';
|
||||||
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
||||||
@@ -69,6 +66,9 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationController notificationController =
|
||||||
|
Get.put(NotificationController());
|
||||||
|
|
||||||
Future getTokens() async {
|
Future getTokens() async {
|
||||||
String? basicAuthCredentials =
|
String? basicAuthCredentials =
|
||||||
await storage.read(key: BoxName.basicAuthCredentials);
|
await storage.read(key: BoxName.basicAuthCredentials);
|
||||||
@@ -122,7 +122,15 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
|
|
||||||
void fireBaseTitles(RemoteMessage message) {
|
void fireBaseTitles(RemoteMessage message) {
|
||||||
if (message.notification!.title! == 'Order'.tr) {
|
if (message.notification!.title! == 'Order'.tr) {
|
||||||
} else if (message.notification!.title! == 'Apply Ride'.tr) {
|
if (Platform.isAndroid) {
|
||||||
|
notificationController.showNotification(
|
||||||
|
'Order', message.notification!.body!, 'Order');
|
||||||
|
}
|
||||||
|
} else if (message.notification!.title! == 'Accepted Ride') {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
notificationController.showNotification(
|
||||||
|
'Apply Order'.tr, 'Driver Applied the Ride for You'.tr, 'ding');
|
||||||
|
}
|
||||||
var passengerList = message.data['passengerList'];
|
var passengerList = message.data['passengerList'];
|
||||||
|
|
||||||
var myList = jsonDecode(passengerList) as List<dynamic>;
|
var myList = jsonDecode(passengerList) as List<dynamic>;
|
||||||
@@ -131,16 +139,20 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
Get.find<MapPassengerController>().statusRide == 'Apply';
|
Get.find<MapPassengerController>().statusRide == 'Apply';
|
||||||
Get.find<MapPassengerController>().isSearchingWindow == false;
|
Get.find<MapPassengerController>().isSearchingWindow == false;
|
||||||
Get.find<MapPassengerController>().update();
|
Get.find<MapPassengerController>().update();
|
||||||
NotificationController().showNotification(
|
Get.find<MapPassengerController>().rideAppliedFromDriver(true);
|
||||||
'Apply Order'.tr, 'Driver Applied the Ride for You'.tr, 'order1');
|
|
||||||
// driverAppliedTripSnakBar();
|
// driverAppliedTripSnakBar();
|
||||||
} else if (message.notification!.title! == 'Promo'.tr) {
|
} else if (message.notification!.title! == 'Promo'.tr) {
|
||||||
NotificationController()
|
if (Platform.isAndroid) {
|
||||||
.showNotification('Promo', 'Show latest promo'.tr, 'promo');
|
notificationController.showNotification(
|
||||||
|
'Promo', 'Show latest promo'.tr, 'promo');
|
||||||
|
}
|
||||||
Get.to(const PromosPassengerPage());
|
Get.to(const PromosPassengerPage());
|
||||||
} else if (message.notification!.title! == 'Trip Monitoring'.tr) {
|
} else if (message.notification!.title! == 'Trip Monitoring'.tr) {
|
||||||
NotificationController()
|
if (Platform.isAndroid) {
|
||||||
.showNotification('Trip Monitoring'.tr, '', 'iphone_ringtone');
|
notificationController.showNotification(
|
||||||
|
'Trip Monitoring'.tr, '', 'iphone_ringtone');
|
||||||
|
}
|
||||||
var myListString = message.data['passengerList'];
|
var myListString = message.data['passengerList'];
|
||||||
var myList = jsonDecode(myListString) as List<dynamic>;
|
var myList = jsonDecode(myListString) as List<dynamic>;
|
||||||
Get.toNamed('/tripmonitor', arguments: {
|
Get.toNamed('/tripmonitor', arguments: {
|
||||||
@@ -148,53 +160,72 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
'driverId': myList[1].toString(),
|
'driverId': myList[1].toString(),
|
||||||
});
|
});
|
||||||
} else if (message.notification!.title! == 'token change'.tr) {
|
} else if (message.notification!.title! == 'token change'.tr) {
|
||||||
NotificationController()
|
if (Platform.isAndroid) {
|
||||||
.showNotification('token change'.tr, 'token change'.tr, 'cancel');
|
notificationController.showNotification(
|
||||||
|
'token change'.tr, 'token change'.tr, 'cancel');
|
||||||
|
}
|
||||||
GoogleSignInHelper.signOut();
|
GoogleSignInHelper.signOut();
|
||||||
} else if (message.notification!.title! == 'DriverIsGoingToPassenger'.tr) {
|
} else if (message.notification!.title! == 'DriverIsGoingToPassenger'.tr) {
|
||||||
Get.find<MapPassengerController>().isDriverInPassengerWay = true;
|
Get.find<MapPassengerController>().isDriverInPassengerWay = true;
|
||||||
Get.find<MapPassengerController>().update();
|
Get.find<MapPassengerController>().update();
|
||||||
NotificationController().showNotification('Driver is Going To You'.tr,
|
if (Platform.isAndroid) {
|
||||||
'Please stay on the picked point.'.tr, 'tone1');
|
notificationController.showNotification('Driver is Going To You'.tr,
|
||||||
|
'Please stay on the picked point.'.tr, 'tone1');
|
||||||
|
}
|
||||||
// Get.snackbar('Driver is Going To Passenger', '',
|
// Get.snackbar('Driver is Going To Passenger', '',
|
||||||
// backgroundColor: AppColor.greenColor);
|
// backgroundColor: AppColor.greenColor);
|
||||||
} else if (message.notification!.title! == 'message From passenger') {
|
} else if (message.notification!.title! == 'message From passenger') {
|
||||||
NotificationController()
|
if (Platform.isAndroid) {
|
||||||
.showNotification('message From passenger'.tr, ''.tr, 'tone2');
|
notificationController.showNotification(
|
||||||
|
'message From passenger'.tr, ''.tr, 'ding');
|
||||||
|
}
|
||||||
passengerDialog(message.notification!.body!);
|
passengerDialog(message.notification!.body!);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
} else if (message.notification!.title! == 'message From Driver') {
|
} else if (message.notification!.title! == 'message From Driver') {
|
||||||
NotificationController()
|
if (Platform.isAndroid) {
|
||||||
.showNotification('message From passenger'.tr, ''.tr, 'tone2');
|
notificationController.showNotification(
|
||||||
|
'message From Driver'.tr, ''.tr, 'ding');
|
||||||
|
}
|
||||||
passengerDialog(message.notification!.body!);
|
passengerDialog(message.notification!.body!);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
} else if (message.notification!.title! == 'RideIsBegin'.tr) {
|
} else if (message.notification!.title! == 'RideIsBegin'.tr) {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
notificationController.showNotification(
|
||||||
|
'Trip is Begin'.tr, ''.tr, 'start');
|
||||||
|
}
|
||||||
Get.find<MapPassengerController>().getBeginRideFromDriver();
|
Get.find<MapPassengerController>().getBeginRideFromDriver();
|
||||||
// Get.snackbar('RideIsBegin', '', backgroundColor: AppColor.greenColor);
|
// Get.snackbar('RideIsBegin', '', backgroundColor: AppColor.greenColor);
|
||||||
box.write(BoxName.passengerWalletTotal, '0');
|
box.write(BoxName.passengerWalletTotal, '0');
|
||||||
NotificationController()
|
|
||||||
.showNotification('Trip is Begin'.tr, ''.tr, 'start');
|
|
||||||
update();
|
update();
|
||||||
} else if (message.notification!.title! == 'Hi ,I will go now'.tr) {
|
} else if (message.notification!.title! == 'Hi ,I will go now'.tr) {
|
||||||
// Get.snackbar('Hi ,I will go now', '',
|
// Get.snackbar('Hi ,I will go now', '',
|
||||||
// backgroundColor: AppColor.greenColor);
|
// backgroundColor: AppColor.greenColor);
|
||||||
NotificationController().showNotification(
|
if (Platform.isAndroid) {
|
||||||
'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'tone2');
|
notificationController.showNotification(
|
||||||
|
'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'ding');
|
||||||
|
}
|
||||||
update();
|
update();
|
||||||
} else if (message.notification!.title! == 'Hi ,I Arrive your site'.tr) {
|
} else if (message.notification!.title! == 'Hi ,I Arrive your site') {
|
||||||
NotificationController()
|
if (Platform.isAndroid) {
|
||||||
.showNotification('Hi ,I Arrive your site'.tr, ''.tr, 'tone2');
|
notificationController.showNotification(
|
||||||
|
'Hi ,I Arrive your site'.tr, ''.tr, 'ding');
|
||||||
|
}
|
||||||
driverArrivePassengerDialoge();
|
driverArrivePassengerDialoge();
|
||||||
|
|
||||||
update();
|
update();
|
||||||
} else if (message.notification!.title! == "Cancel Trip from driver".tr) {
|
} else if (message.notification!.title! == "Cancel Trip from driver") {
|
||||||
Get.back();
|
Get.back();
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
notificationController.showNotification("Cancel Trip from driver".tr,
|
||||||
|
"We will look for a new driver.\nPlease wait.".tr, 'cancel');
|
||||||
|
}
|
||||||
Get.defaultDialog(
|
Get.defaultDialog(
|
||||||
title: "The driver canceled your ride.".tr,
|
title: "The driver canceled your ride.".tr,
|
||||||
middleText: "We will look for a new driver.\\nPlease wait.".tr,
|
middleText: "We will look for a new driver.\nPlease wait.".tr,
|
||||||
confirm: MyElevatedButton(
|
confirm: MyElevatedButton(
|
||||||
|
kolor: AppColor.greenColor,
|
||||||
title: 'Ok'.tr,
|
title: 'Ok'.tr,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Get.back();
|
Get.back();
|
||||||
@@ -204,32 +235,38 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
),
|
),
|
||||||
cancel: MyElevatedButton(
|
cancel: MyElevatedButton(
|
||||||
title: 'Cancel'.tr,
|
title: 'Cancel'.tr,
|
||||||
|
kolor: AppColor.redColor,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.offAll(const MapPagePassenger());
|
Get.offAll(() => const MapPagePassenger());
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// Get.find<MapPassengerController>()
|
// Get.find<MapPassengerController>()
|
||||||
// .searchNewDriverAfterRejectingFromDriver();
|
// .searchNewDriverAfterRejectingFromDriver();
|
||||||
);
|
);
|
||||||
} else if (message.notification!.title! == 'Driver Finish Trip'.tr) {
|
} else if (message.notification!.title! == 'Driver Finish Trip'.tr) {
|
||||||
var myListString = message.data['passengerList'];
|
var myListString = message.data['DriverList'];
|
||||||
var driverList = jsonDecode(myListString) as List<dynamic>;
|
var driverList = jsonDecode(myListString) as List<dynamic>;
|
||||||
NotificationController().showNotification(
|
if (Platform.isAndroid) {
|
||||||
'Driver Finish Trip'.tr,
|
notificationController.showNotification(
|
||||||
'you will pay to Driver'.tr + ' ${driverList[3].toString()} \$'.tr,
|
'Driver Finish Trip'.tr,
|
||||||
'tone1');
|
'you will pay to Driver'.tr + ' ${driverList[3].toString()} \$'.tr,
|
||||||
|
'tone1');
|
||||||
|
}
|
||||||
Get.find<AudioRecorderController>().stopRecording();
|
Get.find<AudioRecorderController>().stopRecording();
|
||||||
if (double.parse(box.read(BoxName.passengerWalletTotal)) < 0) {
|
if (double.parse(box.read(BoxName.passengerWalletTotal)) < 0) {
|
||||||
box.write(BoxName.passengerWalletTotal, 0);
|
box.write(BoxName.passengerWalletTotal, 0);
|
||||||
}
|
}
|
||||||
Get.find<MapPassengerController>().tripFinishedFromDriver();
|
Get.find<MapPassengerController>().tripFinishedFromDriver();
|
||||||
|
notificationController.showNotification(
|
||||||
|
'Don’t forget your personal belongings.'.tr,
|
||||||
|
'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 Sefer app'
|
||||||
|
.tr,
|
||||||
|
'ding');
|
||||||
Get.to(() => RateDriverFromPassenger(), arguments: {
|
Get.to(() => RateDriverFromPassenger(), arguments: {
|
||||||
'driverId': driverList[0].toString(),
|
'driverId': driverList[0].toString(),
|
||||||
'rideId': driverList[1].toString(),
|
'rideId': driverList[1].toString(),
|
||||||
'price': driverList[3].toString()
|
'price': driverList[3].toString()
|
||||||
});
|
});
|
||||||
// }
|
|
||||||
} else if (message.notification!.title! == "Finish Monitor".tr) {
|
} else if (message.notification!.title! == "Finish Monitor".tr) {
|
||||||
Get.defaultDialog(
|
Get.defaultDialog(
|
||||||
titleStyle: AppStyle.title,
|
titleStyle: AppStyle.title,
|
||||||
@@ -249,11 +286,13 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
var myListString = message.data['passengerList'];
|
var myListString = message.data['passengerList'];
|
||||||
var driverList = jsonDecode(myListString) as List<dynamic>;
|
var driverList = jsonDecode(myListString) as List<dynamic>;
|
||||||
// if (Platform.isAndroid) {
|
// if (Platform.isAndroid) {
|
||||||
NotificationController().showNotification(
|
if (Platform.isAndroid) {
|
||||||
'Call Income'.tr,
|
notificationController.showNotification(
|
||||||
message.notification!.body!,
|
'Call Income'.tr,
|
||||||
'iphone_ringtone',
|
message.notification!.body!,
|
||||||
);
|
'iphone_ringtone',
|
||||||
|
);
|
||||||
|
}
|
||||||
// }
|
// }
|
||||||
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
||||||
// Get.to(() => PassengerCallPage(
|
// Get.to(() => PassengerCallPage(
|
||||||
@@ -267,12 +306,13 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
var myListString = message.data['passengerList'];
|
var myListString = message.data['passengerList'];
|
||||||
var driverList = jsonDecode(myListString) as List<dynamic>;
|
var driverList = jsonDecode(myListString) as List<dynamic>;
|
||||||
// if (Platform.isAndroid) {
|
// if (Platform.isAndroid) {
|
||||||
NotificationController().showNotification(
|
if (Platform.isAndroid) {
|
||||||
'Call Income'.tr,
|
notificationController.showNotification(
|
||||||
message.notification!.body!,
|
'Call Income'.tr,
|
||||||
'iphone_ringtone',
|
message.notification!.body!,
|
||||||
);
|
'iphone_ringtone',
|
||||||
// }
|
);
|
||||||
|
}
|
||||||
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
||||||
// Get.to(() => PassengerCallPage(
|
// Get.to(() => PassengerCallPage(
|
||||||
// channelName: driverList[1].toString(),
|
// channelName: driverList[1].toString(),
|
||||||
@@ -285,24 +325,24 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
var myListString = message.data['passengerList'];
|
var myListString = message.data['passengerList'];
|
||||||
var driverList = jsonDecode(myListString) as List<dynamic>;
|
var driverList = jsonDecode(myListString) as List<dynamic>;
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
NotificationController().showNotification(
|
notificationController.showNotification(
|
||||||
'Call End'.tr,
|
'Call End'.tr,
|
||||||
message.notification!.body!,
|
message.notification!.body!,
|
||||||
'tone2',
|
'ding',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
// Assuming GetMaterialApp is initialized and context is valid for navigation
|
||||||
// Get.off(const CallPage());
|
// Get.off(const CallPage());
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
} else if (message.notification!.title! == 'Driver Cancel Your Trip'.tr) {
|
} else if (message.notification!.title! == 'Driver Cancelled Your Trip') {
|
||||||
// Get.snackbar(
|
// Get.snackbar(
|
||||||
// 'You will be pay the cost to driver or we will get it from you on next trip'
|
// 'You will be pay the cost to driver or we will get it from you on next trip'
|
||||||
// .tr,
|
// .tr,
|
||||||
// 'message',
|
// 'message',
|
||||||
// backgroundColor: AppColor.redColor);
|
// backgroundColor: AppColor.redColor);
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
NotificationController().showNotification(
|
notificationController.showNotification(
|
||||||
'Driver Cancel Your Trip'.tr,
|
'Driver Cancelled Your Trip'.tr,
|
||||||
'you will pay to Driver you will be pay the cost of driver time look to your SEFER Wallet'
|
'you will pay to Driver you will be pay the cost of driver time look to your SEFER Wallet'
|
||||||
.tr,
|
.tr,
|
||||||
'cancel');
|
'cancel');
|
||||||
@@ -311,7 +351,7 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
box.remove(BoxName.tokenParent);
|
box.remove(BoxName.tokenParent);
|
||||||
|
|
||||||
Get.find<MapPassengerController>().restCounter();
|
Get.find<MapPassengerController>().restCounter();
|
||||||
Get.offAll(const MapPagePassenger());
|
Get.offAll(() => const MapPagePassenger());
|
||||||
}
|
}
|
||||||
// else if (message.notification!.title! == 'Order Applied') {
|
// else if (message.notification!.title! == 'Order Applied') {
|
||||||
// Get.snackbar(
|
// Get.snackbar(
|
||||||
@@ -325,38 +365,13 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
else if (message.notification!.title! == 'Order Applied'.tr) {
|
else if (message.notification!.title! == 'Order Applied'.tr) {
|
||||||
NotificationController().showNotification(
|
if (Platform.isAndroid) {
|
||||||
'The order Accepted by another Driver'.tr,
|
notificationController.showNotification(
|
||||||
'We regret to inform you that another driver has accepted this order.'
|
'The order Accepted by another Driver'.tr,
|
||||||
.tr,
|
'We regret to inform you that another driver has accepted this order.'
|
||||||
'order');
|
.tr,
|
||||||
} else if (message.notification!.title! == 'VIP Order Accepted'.tr) {
|
'order');
|
||||||
var myListString = message.data['passengerList'];
|
|
||||||
var driverList = jsonDecode(myListString) as List<dynamic>;
|
|
||||||
|
|
||||||
// Assuming driverList[1] contains a valid date string
|
|
||||||
DateTime scheduledTime;
|
|
||||||
try {
|
|
||||||
scheduledTime = DateTime.parse(driverList[1]);
|
|
||||||
} catch (e) {
|
|
||||||
// Handle the error if the date format is incorrect
|
|
||||||
Log.print('Error parsing date: $e');
|
|
||||||
scheduledTime = DateTime.now()
|
|
||||||
.add(const Duration(hours: 1)); // Fallback to 1 hour from now
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationController()
|
|
||||||
.showNotification('The driver accepted your trip'.tr, '', 'order');
|
|
||||||
|
|
||||||
MyDialog().getDialog(
|
|
||||||
'VIP Order Accepted'.tr,
|
|
||||||
'The driver accepted your trip'.tr,
|
|
||||||
() {
|
|
||||||
// Schedule a notification for the parsed date or fallback date
|
|
||||||
NotificationController().scheduleNotification('VIP Order'.tr,
|
|
||||||
'This is a scheduled notification.'.tr, scheduledTime);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +408,7 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
title: 'Ok I will go now.'.tr,
|
title: 'Ok I will go now.'.tr,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
FirebaseMessagesController().sendNotificationToPassengerToken(
|
FirebaseMessagesController().sendNotificationToPassengerToken(
|
||||||
'Hi ,I will go now'.tr,
|
'Hi ,I will go now',
|
||||||
'I will go now'.tr,
|
'I will go now'.tr,
|
||||||
Get.find<MapPassengerController>().driverToken,
|
Get.find<MapPassengerController>().driverToken,
|
||||||
[],
|
[],
|
||||||
@@ -410,7 +425,7 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
Future<dynamic> passengerDialog(String message) {
|
Future<dynamic> passengerDialog(String message) {
|
||||||
return Get.defaultDialog(
|
return Get.defaultDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
title: 'message From passenger'.tr,
|
title: 'message From Driver'.tr,
|
||||||
titleStyle: AppStyle.title,
|
titleStyle: AppStyle.title,
|
||||||
middleTextStyle: AppStyle.title,
|
middleTextStyle: AppStyle.title,
|
||||||
middleText: message.tr,
|
middleText: message.tr,
|
||||||
@@ -456,7 +471,7 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendNotificationAll(String title, body) async {
|
void sendNotificationAll(String title, body, tone) async {
|
||||||
// Get the token you want to subtract.
|
// Get the token you want to subtract.
|
||||||
String token = box.read(BoxName.tokenFCM);
|
String token = box.read(BoxName.tokenFCM);
|
||||||
tokens = box.read(BoxName.tokens);
|
tokens = box.read(BoxName.tokens);
|
||||||
@@ -468,25 +483,41 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
tokens = box.read(BoxName.tokens);
|
tokens = box.read(BoxName.tokens);
|
||||||
for (var i = 0; i < tokens.length; i++) {
|
for (var i = 0; i < tokens.length; i++) {
|
||||||
http
|
http
|
||||||
.post(Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
.post(
|
||||||
headers: <String, String>{
|
Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
||||||
'Content-Type': 'application/json',
|
headers: <String, String>{
|
||||||
'Authorization': 'key=${AK.serverAPI}'
|
'Content-Type': 'application/json',
|
||||||
},
|
'Authorization': 'key=${AK.serverAPI}'
|
||||||
body: jsonEncode({
|
},
|
||||||
'notification': <String, dynamic>{
|
body: jsonEncode({
|
||||||
|
'message': {
|
||||||
|
'token': token,
|
||||||
|
'notification': {
|
||||||
'title': title,
|
'title': title,
|
||||||
'body': body,
|
'body': body,
|
||||||
'sound': 'ding.wav'
|
|
||||||
},
|
},
|
||||||
'priority': 'high',
|
// 'data': {
|
||||||
'data': <String, dynamic>{
|
// 'DriverList': jsonEncode(data),
|
||||||
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
|
// },
|
||||||
'id': '1',
|
'android': {
|
||||||
'status': 'done'
|
'priority': 'high', // Set priority to high
|
||||||
|
'notification': {
|
||||||
|
'sound': tone,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'to': tokens[i],
|
'apns': {
|
||||||
}))
|
'headers': {
|
||||||
|
'apns-priority': '10', // Set APNs priority to 10
|
||||||
|
},
|
||||||
|
'payload': {
|
||||||
|
'aps': {
|
||||||
|
'sound': tone,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
.whenComplete(() {})
|
.whenComplete(() {})
|
||||||
.catchError((e) {});
|
.catchError((e) {});
|
||||||
}
|
}
|
||||||
@@ -521,40 +552,6 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
|
|
||||||
void sendNotificationToPassengerToken(
|
void sendNotificationToPassengerToken(
|
||||||
String title, body, token, List<String> map, String tone) async {
|
String title, body, token, List<String> map, String tone) async {
|
||||||
try {
|
|
||||||
final response = await http.post(
|
|
||||||
Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
|
||||||
headers: <String, String>{
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': 'key=${AK.serverAPI}'
|
|
||||||
},
|
|
||||||
body: jsonEncode({
|
|
||||||
'notification': <String, dynamic>{
|
|
||||||
'title': title,
|
|
||||||
'body': body,
|
|
||||||
'sound': tone
|
|
||||||
},
|
|
||||||
'data': {
|
|
||||||
'passengerList': map,
|
|
||||||
},
|
|
||||||
'priority': 'high',
|
|
||||||
'to': token,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
// Notification sent successfully
|
|
||||||
} else {
|
|
||||||
// Handle error response
|
|
||||||
'Failed to send notification. Status code: ${response.statusCode}';
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// Handle other exceptions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendNotificationToAnyWithoutData(
|
|
||||||
String title, String body, String token, String tone) async {
|
|
||||||
try {
|
try {
|
||||||
String serviceAccountKeyJson = '''{
|
String serviceAccountKeyJson = '''{
|
||||||
"type": "service_account",
|
"type": "service_account",
|
||||||
@@ -594,11 +591,15 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
'body': body,
|
'body': body,
|
||||||
},
|
},
|
||||||
'android': {
|
'android': {
|
||||||
|
'priority': 'high', // Set priority to high
|
||||||
'notification': {
|
'notification': {
|
||||||
'sound': tone,
|
'sound': tone,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'apns': {
|
'apns': {
|
||||||
|
'headers': {
|
||||||
|
'apns-priority': '10', // Set APNs priority to 10
|
||||||
|
},
|
||||||
'payload': {
|
'payload': {
|
||||||
'aps': {
|
'aps': {
|
||||||
'sound': tone,
|
'sound': tone,
|
||||||
@@ -610,75 +611,22 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
print('Notification sent successfully.');
|
print(
|
||||||
|
'Notification sent successfully. Status code: ${response.statusCode}');
|
||||||
print('Response body: ${response.body}');
|
print('Response body: ${response.body}');
|
||||||
} else {
|
} else {
|
||||||
print(
|
print(
|
||||||
'Failed to send notification. Status code: ${response.statusCode}');
|
'Failed to send notification. Status code: ${response.statusCode}');
|
||||||
print('Response body: ${response.body}');
|
print('Response body: ${response.body}');
|
||||||
|
|
||||||
// Parse the response body to handle specific errors like 'UNREGISTERED'
|
|
||||||
final responseBody = jsonDecode(response.body);
|
|
||||||
if (responseBody['error'] != null &&
|
|
||||||
responseBody['error']['status'] == 'NOT_FOUND' &&
|
|
||||||
responseBody['error']['details'] != null) {
|
|
||||||
for (var detail in responseBody['error']['details']) {
|
|
||||||
if (detail['errorCode'] == 'UNREGISTERED') {
|
|
||||||
print(
|
|
||||||
'FCM token is unregistered or invalid. Consider removing this token.');
|
|
||||||
// Remove the unregistered token from your database here.
|
|
||||||
// Example: removeTokenFromDatabase(token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error sending notification: $e');
|
print('Error sending notification: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// void sendNotificationToDriverMAP(String title, String body, String token,
|
Future<void> sendNotificationToDriverMAP(
|
||||||
// List<String> data, String tone) async {
|
String title, String body, String token, List<String> data, String tone,
|
||||||
// try {
|
{int retryCount = 2}) async {
|
||||||
// final response = await http.post(
|
|
||||||
// // Uri.parse(
|
|
||||||
// // 'https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send'),
|
|
||||||
// Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
|
||||||
// headers: <String, String>{
|
|
||||||
// 'Content-Type': 'application/json',
|
|
||||||
// // 'Authorization': 'Bearer 104815009508844392546'
|
|
||||||
// 'Authorization': 'key=${AK.serverAPI}'
|
|
||||||
// },
|
|
||||||
// body: jsonEncode({
|
|
||||||
// 'notification': <String, dynamic>{
|
|
||||||
// 'title': title,
|
|
||||||
// 'body': body,
|
|
||||||
// 'sound': tone
|
|
||||||
// },
|
|
||||||
// 'data': {
|
|
||||||
// 'DriverList': data,
|
|
||||||
// },
|
|
||||||
// 'priority': 'high',
|
|
||||||
// 'to': token,
|
|
||||||
// }),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (response.statusCode == 200) {
|
|
||||||
// Log.print(
|
|
||||||
// 'Notification sent successfully. Status code: ${response.statusCode}');
|
|
||||||
// Log.print('Response body: ${response.body}');
|
|
||||||
// } else {
|
|
||||||
// Log.print(
|
|
||||||
// 'Failed to send notification. Status code: ${response.statusCode}');
|
|
||||||
// Log.print('Response body: ${response.body}');
|
|
||||||
// }
|
|
||||||
// } catch (e) {
|
|
||||||
// Log.print('Error sending notification: $e');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Future<void> sendNotificationToDriverMAP(String title, String body,
|
|
||||||
String token, List<String> data, String tone) async {
|
|
||||||
try {
|
try {
|
||||||
String serviceAccountKeyJson = '''{
|
String serviceAccountKeyJson = '''{
|
||||||
"type": "service_account",
|
"type": "service_account",
|
||||||
@@ -700,7 +648,7 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
|
|
||||||
// Obtain an OAuth 2.0 access token
|
// Obtain an OAuth 2.0 access token
|
||||||
final accessToken = await accessTokenManager.getAccessToken();
|
final accessToken = await accessTokenManager.getAccessToken();
|
||||||
Log.print('accessToken: ${accessToken}');
|
// Log.print('accessToken: ${accessToken}');
|
||||||
|
|
||||||
// Send the notification
|
// Send the notification
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
@@ -721,11 +669,15 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
'DriverList': jsonEncode(data),
|
'DriverList': jsonEncode(data),
|
||||||
},
|
},
|
||||||
'android': {
|
'android': {
|
||||||
|
'priority': 'high', // Set priority to high
|
||||||
'notification': {
|
'notification': {
|
||||||
'sound': tone,
|
'sound': tone,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'apns': {
|
'apns': {
|
||||||
|
'headers': {
|
||||||
|
'apns-priority': '10', // Set APNs priority to 10
|
||||||
|
},
|
||||||
'payload': {
|
'payload': {
|
||||||
'aps': {
|
'aps': {
|
||||||
'sound': tone,
|
'sound': tone,
|
||||||
@@ -735,105 +687,32 @@ class FirebaseMessagesController extends GetxController {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
print('Notification sent successfully.');
|
print(
|
||||||
print('Response body: ${response.body}');
|
'Notification sent successfully. Status code: ${response.statusCode}');
|
||||||
|
print('Response token: ${token}');
|
||||||
} else {
|
} else {
|
||||||
print(
|
print(
|
||||||
'Failed to send notification. Status code: ${response.statusCode}');
|
'Failed to send notification. Status code: ${response.statusCode}');
|
||||||
print('Response body: ${response.body}');
|
print('Response body: ${response.body}');
|
||||||
|
if (retryCount > 0) {
|
||||||
// Parse the response body to handle specific errors like 'UNREGISTERED'
|
print('Retrying... Attempts remaining: $retryCount');
|
||||||
final responseBody = jsonDecode(response.body);
|
await Future.delayed(
|
||||||
if (responseBody['error'] != null &&
|
Duration(seconds: 2)); // Optional delay before retrying
|
||||||
responseBody['error']['status'] == 'NOT_FOUND' &&
|
return sendNotificationToDriverMAP(title, body, token, data, tone,
|
||||||
responseBody['error']['details'] != null) {
|
retryCount: retryCount - 1);
|
||||||
for (var detail in responseBody['error']['details']) {
|
|
||||||
if (detail['errorCode'] == 'UNREGISTERED') {
|
|
||||||
print(
|
|
||||||
'FCM token is unregistered or invalid. Consider removing this token.');
|
|
||||||
// Remove the unregistered token from your database if needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error sending notification: $e');
|
print('Error sending notification: $e');
|
||||||
}
|
if (retryCount > 0) {
|
||||||
}
|
print('Retrying... Attempts remaining: $retryCount');
|
||||||
|
await Future.delayed(
|
||||||
void sendNotificationToDriverMapPolyline(String title, String body,
|
Duration(seconds: 2)); // Optional delay before retrying
|
||||||
String token, List<String> data, String polylineJson) async {
|
return sendNotificationToDriverMAP(title, body, token, data, tone,
|
||||||
try {
|
retryCount: retryCount - 1);
|
||||||
String serviceAccountKeyJson = '''{
|
|
||||||
"type": "service_account",
|
|
||||||
"project_id": "ride-b1bd8",
|
|
||||||
"private_key_id": "75e817c0b902db2ef35edf2c2bd159dec1f13249",
|
|
||||||
"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD0zH9TQGDQHUv3\\na3/JAD1UKPwAp3wNKT0a6fxiIzjI3JxQWI30QvZCcfl6CdMhIcydX1ncSaYTcEeC\\n/AdPVCPkqyJx1YIGGg6P/mRzCWeaN8fsp6z250m5vcObDCZc3dbJEkepbep+6FPY\\n21m3KO+AHh1glgsTGZOTm5xiU8NGXpdk2QEh8wpiIIlR/HuKwVw9g8urNe3Sno+U\\nDm3z37iFqvZdmpqO8aWTJu6beb3hsREK9XK2I9JqC2JUwiGQRo3idOvPP6hkqrWx\\nKSX96vglQFYfakvJdDp2ZATOlpBYPMtS/IWhJ985u58TSS+Kl8qpnpaZBSxgJirf\\nhWzhnKLfAgMBAAECggEAJP785SePGhS7ZN6ltspm+l+hSjYFrPWFCxq+rlQ1YkHZ\\nC9l+RqKSFhOkiPmQI2s4wbXl3kFxLHHlFNoi/q2wKQBmGb8TQfnRJpjjNHGA61Ev\\n0Ue7/6qPvVb9B2MsLw/FxKiTFPuMG3bgKR9pbSFuJLYoaW7zqITOhVnYphGTqwAY\\nBVVcvISSLvELDmH9VZcv/9DVqVlqbbESHWh1Z4W6XGPoEqeDH/upNTyQQ/46Msgm\\nTGE6VqLHpWuSf6SqHp+r0Y0lI3vIPM1vz5FAJDJbOE/enHa0fSup0OHSMxl0HVMn\\nnO1yrGF3vsIPOej5HKr5d71bEIckzk73/yjNC1/mDQKBgQD7RtUvc9omsSsFMJ6e\\nBASAn6Dktx/QY/XNJjFzHQj69cywLDe5t5AL2gUi3phQ2oqB5XJdwnd5bTIEPEPZ\\nDOuOai2802p6FJk6kjmZAMVGx5JtXBH+vs6jrmQQSMiKbjwN1TT6xIWakvLOonUi\\nX6ZvjYYjU/E0YJU3jSiXWEr76wKBgQD5Zn4SouJ6BCDZMbausJVMBkk3qxsYooip\\np89WakC6e7AZinpkRcqjGGV9GOvc8crJs6fyXAA9ORepGP47Mc0ZrDssOkstznsM\\npr8R0S6MKwEZaT9ixOHdOcLZ47ps+JzA2Wr4KN2OvFHksUkB/46ATD1j9WZVgB8M\\namsYp/Y73QKBgHOo+PvsoZ9psVmkNX6abtAdqdtdB0HOoRea2uwXk0ig12TIFaZg\\nfedWpUKVnxqoXVTJHklV99RmlL0qWDiSH+LfsMnXro0e6iDxqZ1po2Se/CFmXcoa\\nXdctsFVmixhdATuExewfhTfPKABA+xWlXWC/jdy5CK+JPWXijaqMM4edAoGAE5Bj\\nsWiPpYyvWvpYX0nA3G7dzX0hqgQN/mkIjbnWDArp3IcNZNJIvBSM2Yxb7EAXbU0n\\njo6DAkp5Pa2VO+WDNlFZbvW/sf8xjeOCt44WPa6d7nVgIIpbQXRngZoopKW3/jTP\\n/FmQT8McFXmGxZ5belsAsdetSGW9icbLUerTGQ0CgYEAmf/G8Ag3XxmqTXvvHuv2\\n14OP7WnrVqkEMnydrftEwn4peXd/Lz+/GYX5Zc4ZoNgbN8IvZ5z0+OmRsallsbiW\\nBw0/tc68CjzxXOvReWxDluUopqWVGj5tlGqE5xUDku9SWJSxbkiQ3rqutzBdPXpr\\noqHwPyDrmK/Zgqn+uiIm4Ck=\\n-----END PRIVATE KEY-----\\n",
|
|
||||||
"client_email": "firebase-adminsdk-o2wqi@ride-b1bd8.iam.gserviceaccount.com",
|
|
||||||
"client_id": "111210077025005706623",
|
|
||||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
||||||
"token_uri": "https://oauth2.googleapis.com/token",
|
|
||||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
|
||||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-o2wqi%40ride-b1bd8.iam.gserviceaccount.com",
|
|
||||||
"universe_domain": "googleapis.com"
|
|
||||||
}
|
|
||||||
'''; // As defined above
|
|
||||||
|
|
||||||
// Initialize AccessTokenManager
|
|
||||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
|
||||||
|
|
||||||
// Obtain an OAuth 2.0 access token
|
|
||||||
final accessToken = await accessTokenManager.getAccessToken();
|
|
||||||
|
|
||||||
// Send the notification
|
|
||||||
final response = await http.post(
|
|
||||||
Uri.parse(
|
|
||||||
'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
|
||||||
headers: <String, String>{
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': 'Bearer $accessToken',
|
|
||||||
},
|
|
||||||
body: jsonEncode({
|
|
||||||
'notification': <String, dynamic>{
|
|
||||||
'title': title,
|
|
||||||
'body': body,
|
|
||||||
// 'sound': 'tone2.wav',
|
|
||||||
'sound': 'order.wav'
|
|
||||||
},
|
|
||||||
'data': {
|
|
||||||
'DriverList': data,
|
|
||||||
'PolylineJson': polylineJson,
|
|
||||||
},
|
|
||||||
'priority': 'high',
|
|
||||||
'to': token,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
print('Notification sent successfully.');
|
|
||||||
print('Response body: ${response.body}');
|
|
||||||
} else {
|
|
||||||
print(
|
|
||||||
'Failed to send notification. Status code: ${response.statusCode}');
|
|
||||||
print('Response body: ${response.body}');
|
|
||||||
|
|
||||||
// Parse the response body to handle specific errors like 'UNREGISTERED'
|
|
||||||
final responseBody = jsonDecode(response.body);
|
|
||||||
if (responseBody['error'] != null &&
|
|
||||||
responseBody['error']['status'] == 'NOT_FOUND' &&
|
|
||||||
responseBody['error']['details'] != null) {
|
|
||||||
for (var detail in responseBody['error']['details']) {
|
|
||||||
if (detail['errorCode'] == 'UNREGISTERED') {
|
|
||||||
print(
|
|
||||||
'FCM token is unregistered or invalid. Consider removing this token.');
|
|
||||||
// Remove the unregistered token from your database if needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
// Handle other exceptions
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:timezone/data/latest.dart' as tz;
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
import 'package:timezone/timezone.dart' as tz;
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
|
|
||||||
|
import '../../main.dart';
|
||||||
|
|
||||||
class NotificationController extends GetxController {
|
class NotificationController extends GetxController {
|
||||||
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
|
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
|
||||||
FlutterLocalNotificationsPlugin();
|
FlutterLocalNotificationsPlugin();
|
||||||
@@ -11,53 +17,315 @@ class NotificationController extends GetxController {
|
|||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
initNotifications();
|
initNotifications();
|
||||||
tz.initializeTimeZones();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the local notifications plugin
|
// Initializes the local notifications plugin
|
||||||
Future<void> initNotifications() async {
|
Future<void> initNotifications() async {
|
||||||
const AndroidInitializationSettings android =
|
const AndroidInitializationSettings android =
|
||||||
AndroidInitializationSettings('@mipmap/launcher_icon');
|
AndroidInitializationSettings('@mipmap/launcher_icon');
|
||||||
const InitializationSettings initializationSettings =
|
DarwinInitializationSettings ios = DarwinInitializationSettings(
|
||||||
InitializationSettings(android: android);
|
requestAlertPermission: true,
|
||||||
|
requestBadgePermission: true,
|
||||||
|
requestSoundPermission: true,
|
||||||
|
onDidReceiveLocalNotification:
|
||||||
|
(int id, String? title, String? body, String? payload) async {},
|
||||||
|
);
|
||||||
|
InitializationSettings initializationSettings =
|
||||||
|
InitializationSettings(android: android, iOS: ios);
|
||||||
await _flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
await _flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
||||||
|
|
||||||
|
tz.initializeTimeZones();
|
||||||
|
print('Notifications initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Displays a notification with the given title and message
|
// Displays a notification with the given title and message
|
||||||
void showNotification(String title, String message, String tone) async {
|
void showNotification(String title, String message, String tone) async {
|
||||||
AndroidNotificationDetails android = AndroidNotificationDetails(
|
final AndroidNotificationDetails android = AndroidNotificationDetails(
|
||||||
'your channel id', 'your channel name',
|
'high_importance_channel',
|
||||||
importance: Importance.max,
|
'High Importance Notifications',
|
||||||
priority: Priority.high,
|
importance: Importance.max,
|
||||||
showWhen: false,
|
priority: Priority.high,
|
||||||
sound: RawResourceAndroidNotificationSound(tone));
|
showWhen: false,
|
||||||
|
sound: RawResourceAndroidNotificationSound(tone),
|
||||||
|
);
|
||||||
|
|
||||||
NotificationDetails details = NotificationDetails(android: android);
|
const DarwinNotificationDetails ios = DarwinNotificationDetails(
|
||||||
|
sound: 'default',
|
||||||
|
presentAlert: true,
|
||||||
|
presentBadge: true,
|
||||||
|
presentSound: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
final NotificationDetails details =
|
||||||
|
NotificationDetails(android: android, iOS: ios);
|
||||||
await _flutterLocalNotificationsPlugin.show(0, title, message, details);
|
await _flutterLocalNotificationsPlugin.show(0, title, message, details);
|
||||||
|
print('Notification shown: $title - $message');
|
||||||
|
}
|
||||||
|
// /Users/hamzaaleghwairyeen/development/App/ride 2/lib/controller/firebase/local_notification.dart
|
||||||
|
|
||||||
|
// Assume _flutterLocalNotificationsPlugin is initialized somewhere in your code
|
||||||
|
|
||||||
|
// void scheduleNotificationsForSevenDays(
|
||||||
|
// String title, String message, String tone) async {
|
||||||
|
// final AndroidNotificationDetails android = AndroidNotificationDetails(
|
||||||
|
// 'high_importance_channel',
|
||||||
|
// 'High Importance Notifications',
|
||||||
|
// importance: Importance.max,
|
||||||
|
// priority: Priority.high,
|
||||||
|
// sound: RawResourceAndroidNotificationSound(tone),
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const DarwinNotificationDetails ios = DarwinNotificationDetails(
|
||||||
|
// sound: 'default',
|
||||||
|
// presentAlert: true,
|
||||||
|
// presentBadge: true,
|
||||||
|
// presentSound: true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// final NotificationDetails details =
|
||||||
|
// NotificationDetails(android: android, iOS: ios);
|
||||||
|
|
||||||
|
// // Check for the exact alarm permission on Android 12 and above
|
||||||
|
// if (Platform.isAndroid) {
|
||||||
|
// if (await Permission.scheduleExactAlarm.isDenied) {
|
||||||
|
// if (await Permission.scheduleExactAlarm.request().isGranted) {
|
||||||
|
// print('SCHEDULE_EXACT_ALARM permission granted');
|
||||||
|
// } else {
|
||||||
|
// print('SCHEDULE_EXACT_ALARM permission denied');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Schedule notifications for the next 7 days
|
||||||
|
// for (int day = 0; day < 7; day++) {
|
||||||
|
// // Schedule for 8:00 AM
|
||||||
|
// await _scheduleNotificationForTime(
|
||||||
|
// day, 8, 0, title, message, details, day * 1000 + 1);
|
||||||
|
|
||||||
|
// // Schedule for 3:00 PM
|
||||||
|
// await _scheduleNotificationForTime(
|
||||||
|
// day, 15, 0, title, message, details, day * 1000 + 2); // Unique ID
|
||||||
|
|
||||||
|
// // Schedule for 8:00 PM
|
||||||
|
// await _scheduleNotificationForTime(
|
||||||
|
// day, 20, 0, title, message, details, day * 1000 + 3); // Unique ID
|
||||||
|
// }
|
||||||
|
|
||||||
|
// print('Notifications scheduled successfully for the next 7 days');
|
||||||
|
// }
|
||||||
|
void scheduleNotificationsForSevenDays(
|
||||||
|
String title, String message, String tone) async {
|
||||||
|
final AndroidNotificationDetails android = AndroidNotificationDetails(
|
||||||
|
'high_importance_channel',
|
||||||
|
'High Importance Notifications',
|
||||||
|
importance: Importance.max,
|
||||||
|
priority: Priority.high,
|
||||||
|
sound: RawResourceAndroidNotificationSound(tone),
|
||||||
|
);
|
||||||
|
|
||||||
|
const DarwinNotificationDetails ios = DarwinNotificationDetails(
|
||||||
|
sound: 'default',
|
||||||
|
presentAlert: true,
|
||||||
|
presentBadge: true,
|
||||||
|
presentSound: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
final NotificationDetails details =
|
||||||
|
NotificationDetails(android: android, iOS: ios);
|
||||||
|
|
||||||
|
// Check for the exact alarm permission on Android 12 and above
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
if (await Permission.scheduleExactAlarm.isDenied) {
|
||||||
|
if (await Permission.scheduleExactAlarm.request().isGranted) {
|
||||||
|
print('SCHEDULE_EXACT_ALARM permission granted');
|
||||||
|
} else {
|
||||||
|
print('SCHEDULE_EXACT_ALARM permission denied');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule notifications for the next 7 days
|
||||||
|
for (int day = 0; day < 7; day++) {
|
||||||
|
// List of notification times
|
||||||
|
final notificationTimes = [
|
||||||
|
{'hour': 8, 'minute': 0, 'id': day * 1000 + 1}, // 8:00 AM
|
||||||
|
{'hour': 15, 'minute': 0, 'id': day * 1000 + 2}, // 3:00 PM
|
||||||
|
{'hour': 20, 'minute': 0, 'id': day * 1000 + 3}, // 8:00 PM
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var time in notificationTimes) {
|
||||||
|
final notificationId = time['id'] as int;
|
||||||
|
|
||||||
|
// Check if this notification ID is already stored
|
||||||
|
bool isScheduled = box.read('notification_$notificationId') ?? false;
|
||||||
|
|
||||||
|
if (!isScheduled) {
|
||||||
|
// Schedule the notification if not already scheduled
|
||||||
|
await _scheduleNotificationForTime(
|
||||||
|
day,
|
||||||
|
time['hour'] as int,
|
||||||
|
time['minute'] as int,
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
details,
|
||||||
|
notificationId,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mark this notification ID as scheduled in GetStorage
|
||||||
|
box.write('notification_$notificationId', true);
|
||||||
|
} else {
|
||||||
|
print('Notification with ID $notificationId is already scheduled.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print('Notifications scheduled successfully for the next 7 days');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedules a notification for a specific time
|
void scheduleNotificationsForTimeSelected(
|
||||||
Future<void> scheduleNotification(
|
String title, String message, String tone, DateTime timeSelected) async {
|
||||||
String title, String body, DateTime scheduledTime) async {
|
final AndroidNotificationDetails android = AndroidNotificationDetails(
|
||||||
await _flutterLocalNotificationsPlugin.zonedSchedule(
|
'high_importance_channel',
|
||||||
0,
|
'High Importance Notifications',
|
||||||
|
importance: Importance.max,
|
||||||
|
priority: Priority.high,
|
||||||
|
sound: RawResourceAndroidNotificationSound(tone),
|
||||||
|
);
|
||||||
|
|
||||||
|
const DarwinNotificationDetails ios = DarwinNotificationDetails(
|
||||||
|
sound: 'default',
|
||||||
|
presentAlert: true,
|
||||||
|
presentBadge: true,
|
||||||
|
presentSound: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
final NotificationDetails details =
|
||||||
|
NotificationDetails(android: android, iOS: ios);
|
||||||
|
|
||||||
|
// Check for the exact alarm permission on Android 12 and above
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
if (await Permission.scheduleExactAlarm.isDenied) {
|
||||||
|
if (await Permission.scheduleExactAlarm.request().isGranted) {
|
||||||
|
print('SCHEDULE_EXACT_ALARM permission granted');
|
||||||
|
} else {
|
||||||
|
print('SCHEDULE_EXACT_ALARM permission denied');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule notifications for 10 and 30 minutes before the timeSelected
|
||||||
|
await _scheduleNotificationForTimeVIP(
|
||||||
|
timeSelected.subtract(const Duration(minutes: 10)), // 10 minutes before
|
||||||
title,
|
title,
|
||||||
body,
|
message,
|
||||||
tz.TZDateTime.from(scheduledTime, tz.local),
|
details,
|
||||||
const NotificationDetails(
|
1, // Unique ID for 10-minute before notification
|
||||||
android: AndroidNotificationDetails(
|
);
|
||||||
'your_channel_id',
|
|
||||||
'your_channel_name',
|
await _scheduleNotificationForTimeVIP(
|
||||||
channelDescription: 'your_channel_description',
|
timeSelected.subtract(const Duration(minutes: 30)), // 30 minutes before
|
||||||
importance: Importance.max,
|
title,
|
||||||
priority: Priority.high,
|
message,
|
||||||
showWhen: false,
|
details,
|
||||||
),
|
2, // Unique ID for 30-minute before notification
|
||||||
),
|
);
|
||||||
androidAllowWhileIdle: true,
|
|
||||||
|
print('Notifications scheduled successfully for the time selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _scheduleNotificationForTimeVIP(
|
||||||
|
DateTime scheduledDate,
|
||||||
|
String title,
|
||||||
|
String message,
|
||||||
|
NotificationDetails details,
|
||||||
|
int notificationId,
|
||||||
|
) async {
|
||||||
|
// Initialize and set Cairo timezone
|
||||||
|
tz.initializeTimeZones();
|
||||||
|
var cairoLocation = tz.getLocation('Africa/Cairo');
|
||||||
|
|
||||||
|
final now = tz.TZDateTime.now(cairoLocation);
|
||||||
|
|
||||||
|
// Convert to Cairo time
|
||||||
|
tz.TZDateTime scheduledTZDateTime =
|
||||||
|
tz.TZDateTime.from(scheduledDate, cairoLocation);
|
||||||
|
|
||||||
|
// Check if 10 minutes before the scheduled time is in the past
|
||||||
|
if (scheduledTZDateTime
|
||||||
|
.subtract(const Duration(minutes: 10))
|
||||||
|
.isBefore(now)) {
|
||||||
|
// If the 10 minutes before the scheduled time is in the past, don't schedule
|
||||||
|
print(
|
||||||
|
'Scheduled time minus 10 minutes is in the past. Skipping notification.');
|
||||||
|
return; // Skip this notification
|
||||||
|
}
|
||||||
|
|
||||||
|
print('Current time (Cairo): $now');
|
||||||
|
print('Scheduling notification for: $scheduledTZDateTime');
|
||||||
|
|
||||||
|
await _flutterLocalNotificationsPlugin.zonedSchedule(
|
||||||
|
notificationId, // Unique ID for each notification
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
scheduledTZDateTime,
|
||||||
|
details,
|
||||||
|
androidScheduleMode: AndroidScheduleMode.exact,
|
||||||
uiLocalNotificationDateInterpretation:
|
uiLocalNotificationDateInterpretation:
|
||||||
UILocalNotificationDateInterpretation.absoluteTime,
|
UILocalNotificationDateInterpretation.absoluteTime,
|
||||||
matchDateTimeComponents: DateTimeComponents.time,
|
matchDateTimeComponents:
|
||||||
|
null, // Don't repeat automatically; we handle manually
|
||||||
);
|
);
|
||||||
|
|
||||||
|
print('Notification scheduled successfully for: $scheduledTZDateTime');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _scheduleNotificationForTime(
|
||||||
|
int dayOffset,
|
||||||
|
int hour,
|
||||||
|
int minute,
|
||||||
|
String title,
|
||||||
|
String message,
|
||||||
|
NotificationDetails details,
|
||||||
|
int notificationId,
|
||||||
|
) async {
|
||||||
|
// Initialize and set Cairo timezone
|
||||||
|
tz.initializeTimeZones();
|
||||||
|
var cairoLocation = tz.getLocation('Africa/Cairo');
|
||||||
|
|
||||||
|
final now = tz.TZDateTime.now(cairoLocation);
|
||||||
|
tz.TZDateTime scheduledDate = tz.TZDateTime(
|
||||||
|
cairoLocation,
|
||||||
|
now.year,
|
||||||
|
now.month,
|
||||||
|
now.day + dayOffset, // Add offset to schedule for the next days
|
||||||
|
hour,
|
||||||
|
minute,
|
||||||
|
);
|
||||||
|
|
||||||
|
// If the scheduled time is in the past, move it to the next day
|
||||||
|
if (scheduledDate.isBefore(now)) {
|
||||||
|
scheduledDate = scheduledDate.add(const Duration(days: 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
print('Current time (Cairo): $now');
|
||||||
|
print('Scheduling notification for: $scheduledDate');
|
||||||
|
|
||||||
|
await _flutterLocalNotificationsPlugin.zonedSchedule(
|
||||||
|
notificationId, // Unique ID for each notification
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
scheduledDate,
|
||||||
|
details,
|
||||||
|
androidScheduleMode: AndroidScheduleMode.exact,
|
||||||
|
uiLocalNotificationDateInterpretation:
|
||||||
|
UILocalNotificationDateInterpretation.absoluteTime,
|
||||||
|
matchDateTimeComponents:
|
||||||
|
null, // Don't repeat automatically; we handle 7 days manually
|
||||||
|
);
|
||||||
|
|
||||||
|
print('Notification scheduled successfully for: $scheduledDate');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
lib/controller/functions/add_error.dart
Normal file
19
lib/controller/functions/add_error.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import '../../constant/box_name.dart';
|
||||||
|
import '../../constant/links.dart';
|
||||||
|
import '../../main.dart';
|
||||||
|
import 'crud.dart';
|
||||||
|
|
||||||
|
addError(String error, where) async {
|
||||||
|
CRUD().post(link: AppLink.addError, payload: {
|
||||||
|
'error': error.toString(), // Example error description
|
||||||
|
'userId': box.read(BoxName.driverID) ??
|
||||||
|
box.read(BoxName.passengerID), // Example user ID
|
||||||
|
'userType': box.read(BoxName.driverID) != null
|
||||||
|
? 'Driver'
|
||||||
|
: 'passenger', // Example user type
|
||||||
|
'phone': box.read(BoxName.phone) ??
|
||||||
|
box.read(BoxName.phoneDriver), // Example phone number
|
||||||
|
|
||||||
|
'device': where
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ import 'package:SEFER/env/env.dart';
|
|||||||
import '../../constant/api_key.dart';
|
import '../../constant/api_key.dart';
|
||||||
|
|
||||||
import '../../print.dart';
|
import '../../print.dart';
|
||||||
|
import '../../views/widgets/elevated_btn.dart';
|
||||||
|
import 'add_error.dart';
|
||||||
import 'upload_image.dart';
|
import 'upload_image.dart';
|
||||||
|
|
||||||
class CRUD {
|
class CRUD {
|
||||||
@@ -28,8 +30,9 @@ class CRUD {
|
|||||||
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
|
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// Log.print('payload: ${payload}');
|
|
||||||
Log.print('response.request: ${response.request}');
|
Log.print('response.request: ${response.request}');
|
||||||
|
Log.print('payload: ${payload}');
|
||||||
// Log.print('response.reasonPhrase: ${response.reasonPhrase}');
|
// Log.print('response.reasonPhrase: ${response.reasonPhrase}');
|
||||||
|
|
||||||
Log.print('response.body: ${response.body}');
|
Log.print('response.body: ${response.body}');
|
||||||
@@ -43,7 +46,6 @@ class CRUD {
|
|||||||
return jsonData['status'];
|
return jsonData['status'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// }
|
|
||||||
Future<dynamic> getTokenParent({
|
Future<dynamic> getTokenParent({
|
||||||
required String link,
|
required String link,
|
||||||
Map<String, dynamic>? payload,
|
Map<String, dynamic>? payload,
|
||||||
@@ -71,6 +73,73 @@ class CRUD {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future sendWhatsAppAuth(String to, String token) async {
|
||||||
|
var res = await CRUD()
|
||||||
|
.get(link: AppLink.getApiKey, payload: {'keyName': 'whatsapp_key'});
|
||||||
|
var accesstoken = jsonDecode(res)['message']['whatsapp_key'];
|
||||||
|
var headers = {
|
||||||
|
'Authorization': 'Bearer $accesstoken',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
|
||||||
|
var url = 'https://graph.facebook.com/v20.0/${Env.whatappID}/messages';
|
||||||
|
var request = http.Request('POST', Uri.parse(url));
|
||||||
|
|
||||||
|
var body = json.encode({
|
||||||
|
"messaging_product": "whatsapp",
|
||||||
|
"to": to,
|
||||||
|
"type": "template",
|
||||||
|
"template": {
|
||||||
|
"name": "sefer1",
|
||||||
|
"language": {"code": "en"},
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"type": "body",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": token,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
request.body = body;
|
||||||
|
request.headers.addAll(headers);
|
||||||
|
|
||||||
|
try {
|
||||||
|
print('Sending request to $url');
|
||||||
|
print('Request headers: $headers');
|
||||||
|
print('Request body: $body');
|
||||||
|
|
||||||
|
http.StreamedResponse response = await request.send();
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
String responseBody = await response.stream.bytesToString();
|
||||||
|
print('Response: $responseBody');
|
||||||
|
|
||||||
|
Get.defaultDialog(
|
||||||
|
title: 'You will receive a code in WhatsApp Messenger'.tr,
|
||||||
|
middleText: 'wait 1 minute to recive message'.tr,
|
||||||
|
confirm: MyElevatedButton(
|
||||||
|
title: 'OK'.tr,
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
String errorBody = await response.stream.bytesToString();
|
||||||
|
print('Error ${response.statusCode}: ${response.reasonPhrase}');
|
||||||
|
print('Error body: $errorBody');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Exception occurred: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic> getAgoraToken({
|
Future<dynamic> getAgoraToken({
|
||||||
required String channelName,
|
required String channelName,
|
||||||
required String uid,
|
required String uid,
|
||||||
@@ -215,36 +284,83 @@ class CRUD {
|
|||||||
} else {}
|
} else {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Future<dynamic> post({
|
||||||
|
// required String link,
|
||||||
|
// Map<String, dynamic>? payload,
|
||||||
|
// }) async {
|
||||||
|
// // String? basicAuthCredentials =
|
||||||
|
// // await storage.read(key: BoxName.basicAuthCredentials);
|
||||||
|
// var url = Uri.parse(
|
||||||
|
// link,
|
||||||
|
// );
|
||||||
|
// var response = await http.post(
|
||||||
|
// url,
|
||||||
|
// body: payload,
|
||||||
|
// headers: {
|
||||||
|
// "Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
// 'Authorization':
|
||||||
|
// 'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// Log.print('payload: ${payload}');
|
||||||
|
// Log.print('response.request: ${response.request}');
|
||||||
|
// Log.print('response.body: ${response.body}');
|
||||||
|
// var jsonData = jsonDecode(response.body);
|
||||||
|
// if (response.statusCode == 200) {
|
||||||
|
// if (jsonData['status'] == 'success') {
|
||||||
|
// return response.body;
|
||||||
|
// } else {
|
||||||
|
// return (jsonData['status']);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// return response.statusCode;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
Future<dynamic> post({
|
Future<dynamic> post({
|
||||||
required String link,
|
required String link,
|
||||||
Map<String, dynamic>? payload,
|
Map<String, dynamic>? payload,
|
||||||
}) async {
|
}) async {
|
||||||
// String? basicAuthCredentials =
|
var url = Uri.parse(link);
|
||||||
// await storage.read(key: BoxName.basicAuthCredentials);
|
try {
|
||||||
var url = Uri.parse(
|
var response = await http.post(
|
||||||
link,
|
url,
|
||||||
);
|
body: payload,
|
||||||
var response = await http.post(
|
headers: {
|
||||||
url,
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
body: payload,
|
'Authorization':
|
||||||
headers: {
|
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
},
|
||||||
'Authorization':
|
);
|
||||||
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
|
|
||||||
},
|
Log.print('Response.request: ${response.request}');
|
||||||
);
|
Log.print('Payload: $payload');
|
||||||
// Log.print('payload: ${payload}');
|
// Log.print('Response.statusCode: ${response.statusCode}');
|
||||||
// Log.print('response.request: ${response.request}');
|
Log.print('Response.body: ${response.body}');
|
||||||
Log.print('response.body: ${response.body}');
|
|
||||||
var jsonData = jsonDecode(response.body);
|
if (response.statusCode == 200) {
|
||||||
if (response.statusCode == 200) {
|
try {
|
||||||
if (jsonData['status'] == 'success') {
|
var jsonData = jsonDecode(response.body);
|
||||||
return response.body;
|
|
||||||
|
if (jsonData['status'] == 'success') {
|
||||||
|
return jsonData;
|
||||||
|
} else {
|
||||||
|
return jsonData['status'];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Log.print('JSON parsing error: $e');
|
||||||
|
addError(e.toString(), 'crud().post');
|
||||||
|
return 'failure'; // Return a recognizable failure string for JSON errors
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return (jsonData['status']);
|
Log.print('Non-200 response code: ${response.statusCode}');
|
||||||
|
addError(
|
||||||
|
'Non-200 response code: ${response.statusCode}', 'crud().post');
|
||||||
|
return 'failure'; // Handle unexpected status codes as failures
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e) {
|
||||||
return response.statusCode;
|
Log.print('HTTP request error: $e');
|
||||||
|
addError('HTTP request error: $e', 'crud().post');
|
||||||
|
return 'failure'; // Handle HTTP request errors as failures
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,6 +509,26 @@ class CRUD {
|
|||||||
return (jsonData['status']);
|
return (jsonData['status']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<dynamic> getHereMap({
|
||||||
|
required String link,
|
||||||
|
}) async {
|
||||||
|
var url = Uri.parse(link);
|
||||||
|
try {
|
||||||
|
var response = await http.get(url);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
// Ensure the response body is decoded as UTF-8
|
||||||
|
var decodedBody = utf8.decode(response.bodyBytes);
|
||||||
|
var data = jsonDecode(decodedBody);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic> update({
|
Future<dynamic> update({
|
||||||
required String endpoint,
|
required String endpoint,
|
||||||
required Map<String, dynamic> data,
|
required Map<String, dynamic> data,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'dart:io';
|
|||||||
import 'package:SEFER/constant/links.dart';
|
import 'package:SEFER/constant/links.dart';
|
||||||
import 'package:SEFER/controller/functions/crud.dart';
|
import 'package:SEFER/controller/functions/crud.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@@ -17,7 +16,7 @@ Future<void> checkForUpdate(BuildContext context) async {
|
|||||||
final version = packageInfo.version;
|
final version = packageInfo.version;
|
||||||
print('currentVersion is : $currentVersion');
|
print('currentVersion is : $currentVersion');
|
||||||
// Fetch the latest version from your server
|
// Fetch the latest version from your server
|
||||||
String latestVersion = await getPackageInfo();
|
String latestVersion = box.read(BoxName.package);
|
||||||
box.write(BoxName.packagInfo, version);
|
box.write(BoxName.packagInfo, version);
|
||||||
|
|
||||||
if (latestVersion.isNotEmpty && latestVersion != currentVersion) {
|
if (latestVersion.isNotEmpty && latestVersion != currentVersion) {
|
||||||
@@ -25,18 +24,22 @@ Future<void> checkForUpdate(BuildContext context) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getPackageInfo() async {
|
checkForBounusInvitation() {
|
||||||
final response = await CRUD().get(link: AppLink.packageInfo, payload: {
|
if (box.read(BoxName.inviteCode) != null) {}
|
||||||
"platform": Platform.isAndroid ? 'android' : 'ios',
|
|
||||||
"appName": AppInformation.appName,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response != 'failure') {
|
|
||||||
return jsonDecode(response)['message'][0]['version'];
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Future<String> getPackageInfo() async {
|
||||||
|
// final response = await CRUD().get(link: AppLink.packageInfo, payload: {
|
||||||
|
// "platform": Platform.isAndroid ? 'android' : 'ios',
|
||||||
|
// "appName": AppInformation.appName,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (response != 'failure') {
|
||||||
|
// return jsonDecode(response)['message'][0]['version'];
|
||||||
|
// }
|
||||||
|
// return '';
|
||||||
|
// }
|
||||||
|
|
||||||
void showUpdateDialog(BuildContext context) {
|
void showUpdateDialog(BuildContext context) {
|
||||||
final String storeUrl = Platform.isAndroid
|
final String storeUrl = Platform.isAndroid
|
||||||
? 'https://play.google.com/store/apps/details?id=com.mobileapp.store.ride'
|
? 'https://play.google.com/store/apps/details?id=com.mobileapp.store.ride'
|
||||||
@@ -65,10 +68,11 @@ void showUpdateDialog(BuildContext context) {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
CupertinoDialogAction(
|
CupertinoDialogAction(
|
||||||
child: Text('Cancel'.tr),
|
child: Text('Cancel'.tr),
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
})
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import 'package:SEFER/views/widgets/elevated_btn.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import '../../print.dart';
|
||||||
import '../auth/register_controller.dart';
|
import '../auth/register_controller.dart';
|
||||||
import 'crud.dart';
|
import 'crud.dart';
|
||||||
|
|
||||||
@@ -29,12 +30,12 @@ class SmsEgyptController extends GetxController {
|
|||||||
Future<dynamic> sendSmsEgypt(String phone, otp) async {
|
Future<dynamic> sendSmsEgypt(String phone, otp) async {
|
||||||
String sender = await getSender();
|
String sender = await getSender();
|
||||||
var body = jsonEncode({
|
var body = jsonEncode({
|
||||||
"username": AppInformation.appName,
|
"username": 'Sefer',
|
||||||
"password": AK.smsPasswordEgypt,
|
"password": AK.smsPasswordEgypt,
|
||||||
"message": "${AppInformation.appName} app code is $otp\ncopy it to app",
|
"message": "${AppInformation.appName} app code is $otp\ncopy it to app",
|
||||||
"language": box.read(BoxName.lang) == 'en' ? "e" : 'r',
|
"language": box.read(BoxName.lang) == 'en' ? "e" : 'r',
|
||||||
"sender": sender, //"Sefer Egy",
|
"sender": sender, //"Sefer Egy",
|
||||||
"receiver": "2$phone"
|
"receiver": phone
|
||||||
});
|
});
|
||||||
|
|
||||||
var res = await http.post(
|
var res = await http.post(
|
||||||
|
|||||||
@@ -1,49 +1,50 @@
|
|||||||
import 'package:SEFER/constant/box_name.dart';
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
import 'package:SEFER/main.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_tts/flutter_tts.dart';
|
import 'package:flutter_tts/flutter_tts.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../main.dart';
|
||||||
|
|
||||||
class TextToSpeechController extends GetxController {
|
class TextToSpeechController extends GetxController {
|
||||||
final flutterTts = FlutterTts();
|
final flutterTts = FlutterTts();
|
||||||
|
|
||||||
// Initialize TTS in initState
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
initTts();
|
initTts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispose of TTS when controller is closed
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
|
flutterTts.stop(); // Stop any ongoing TTS
|
||||||
super.onClose();
|
super.onClose();
|
||||||
flutterTts.completionHandler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to initialize TTS engine
|
// Initialize TTS engine with language check
|
||||||
Future<void> initTts() async {
|
Future<void> initTts() async {
|
||||||
String? lang =
|
try {
|
||||||
WidgetsBinding.instance.platformDispatcher.locale.countryCode;
|
String langCode = box.read(BoxName.lang) ?? 'en-US';
|
||||||
await flutterTts
|
bool isAvailable = await flutterTts.isLanguageAvailable(langCode);
|
||||||
.setLanguage(box.read(BoxName.lang).toString()); //'en-US' Set language
|
|
||||||
// await flutterTts.setLanguage('ar-SA'); //'en-US' Set language
|
// If language is unavailable, default to 'en-US'
|
||||||
// await flutterTts.setLanguage(lang!); //'en-US' Set language
|
if (!isAvailable) {
|
||||||
await flutterTts.setSpeechRate(0.5); // Adjust speech rate
|
langCode = 'en-US';
|
||||||
await flutterTts.setVolume(1.0); // Set volume
|
}
|
||||||
|
|
||||||
|
await flutterTts.setLanguage(langCode);
|
||||||
|
await flutterTts.setSpeechRate(0.5); // Adjust speech rate
|
||||||
|
await flutterTts.setVolume(1.0); // Set volume
|
||||||
|
} catch (error) {
|
||||||
|
Get.snackbar('Error', 'Failed to initialize TTS: $error');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to speak the given text
|
// Function to speak the given text
|
||||||
Future<void> speakText(String text) async {
|
Future<void> speakText(String text) async {
|
||||||
try {
|
try {
|
||||||
await flutterTts.awaitSpeakCompletion(true);
|
await flutterTts.awaitSpeakCompletion(true);
|
||||||
var result = await flutterTts.speak(text);
|
await flutterTts.speak(text);
|
||||||
if (result == 1) {
|
|
||||||
// TTS operation has started
|
|
||||||
// You can perform additional operations here, if needed
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Handle error gracefully, e.g., show a message
|
|
||||||
Get.snackbar('Error', 'Failed to speak text: $error');
|
Get.snackbar('Error', 'Failed to speak text: $error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
91
lib/controller/home/blinking_promo_controller.dart.dart
Normal file
91
lib/controller/home/blinking_promo_controller.dart.dart
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../constant/links.dart';
|
||||||
|
import '../../views/widgets/elevated_btn.dart';
|
||||||
|
import '../functions/crud.dart';
|
||||||
|
|
||||||
|
class BlinkingController extends GetxController {
|
||||||
|
final promoFormKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final promo = TextEditingController();
|
||||||
|
bool promoTaken = false;
|
||||||
|
void applyPromoCodeToPassenger() async {
|
||||||
|
//TAWJIHI
|
||||||
|
if (promoFormKey.currentState!.validate()) {
|
||||||
|
CRUD().get(link: AppLink.getPassengersPromo, payload: {
|
||||||
|
'promo_code': promo.text,
|
||||||
|
}).then((value) {
|
||||||
|
if (value == 'failure') {
|
||||||
|
Get.defaultDialog(
|
||||||
|
title: 'Promo End !'.tr,
|
||||||
|
confirm: MyElevatedButton(
|
||||||
|
title: 'Back',
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
var decode = jsonDecode(value);
|
||||||
|
|
||||||
|
// if (decode["status"] == "success") {
|
||||||
|
// var firstElement = decode["message"][0];
|
||||||
|
// if (double.parse(box.read(BoxName.passengerWalletTotal)) < 0) {
|
||||||
|
// totalPassenger = totalCostPassenger -
|
||||||
|
// (totalCostPassenger * int.parse(firstElement['amount']) / 100);
|
||||||
|
// update();
|
||||||
|
// } else {
|
||||||
|
// totalPassenger = totalCostPassenger -
|
||||||
|
// (totalCostPassenger * int.parse(firstElement['amount']) / 100);
|
||||||
|
// update();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// totalDriver = totalDriver -
|
||||||
|
// (totalDriver * int.parse(firstElement['amount']) / 100);
|
||||||
|
// promoTaken = true;
|
||||||
|
// update();
|
||||||
|
// Get.back();
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reactive variable for blinking (on/off)
|
||||||
|
var isLightOn = false.obs;
|
||||||
|
|
||||||
|
// To animate the border color
|
||||||
|
var borderColor = Colors.black.obs;
|
||||||
|
|
||||||
|
Timer? _blinkingTimer;
|
||||||
|
|
||||||
|
// Method to start blinking for 5 seconds
|
||||||
|
void startBlinking() {
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
_blinkingTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
|
// Toggle light on/off
|
||||||
|
isLightOn.value = !isLightOn.value;
|
||||||
|
borderColor.value = isLightOn.value
|
||||||
|
? Colors.yellow
|
||||||
|
: Colors.black; // Animate border color
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
// Stop blinking after 5 seconds
|
||||||
|
if (count >= 35) {
|
||||||
|
timer.cancel();
|
||||||
|
isLightOn.value = false; // Ensure light turns off
|
||||||
|
borderColor.value = Colors.black; // Reset the border color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
_blinkingTimer?.cancel();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
78
lib/controller/home/contact_us_controller.dart
Normal file
78
lib/controller/home/contact_us_controller.dart
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../constant/colors.dart';
|
||||||
|
import '../functions/launch.dart';
|
||||||
|
|
||||||
|
class ContactUsController extends GetxController {
|
||||||
|
final String phone1 = '+201018805430';
|
||||||
|
final String phone2 = '+201080182934';
|
||||||
|
final TimeOfDay workStartTime = const TimeOfDay(hour: 12, minute: 0);
|
||||||
|
final TimeOfDay workEndTime = const TimeOfDay(hour: 19, minute: 0);
|
||||||
|
|
||||||
|
bool _isWithinWorkTime(TimeOfDay now) {
|
||||||
|
return (now.hour > workStartTime.hour ||
|
||||||
|
(now.hour == workStartTime.hour &&
|
||||||
|
now.minute >= workStartTime.minute)) &&
|
||||||
|
(now.hour < workEndTime.hour ||
|
||||||
|
(now.hour == workEndTime.hour && now.minute <= workEndTime.minute));
|
||||||
|
}
|
||||||
|
|
||||||
|
void showContactDialog(BuildContext context) {
|
||||||
|
TimeOfDay now = TimeOfDay.now();
|
||||||
|
|
||||||
|
showCupertinoModalPopup(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => CupertinoActionSheet(
|
||||||
|
title: Text('Contact Us'.tr),
|
||||||
|
message: Text('Choose a contact option'.tr),
|
||||||
|
actions: <Widget>[
|
||||||
|
if (_isWithinWorkTime(now))
|
||||||
|
CupertinoActionSheetAction(
|
||||||
|
child: Text(phone1),
|
||||||
|
onPressed: () => makePhoneCall(
|
||||||
|
phone1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_isWithinWorkTime(now))
|
||||||
|
CupertinoActionSheetAction(
|
||||||
|
child: Text(phone2),
|
||||||
|
onPressed: () => makePhoneCall(phone2),
|
||||||
|
),
|
||||||
|
if (!_isWithinWorkTime(now))
|
||||||
|
CupertinoActionSheetAction(
|
||||||
|
child: Text(
|
||||||
|
'Work time is from 12:00 - 19:00.\nYou can send a WhatsApp message or email.'
|
||||||
|
.tr),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
CupertinoActionSheetAction(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
FontAwesome.whatsapp,
|
||||||
|
color: AppColor.greenColor,
|
||||||
|
),
|
||||||
|
Text('Send WhatsApp Message'.tr),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () =>
|
||||||
|
launchCommunication('whatsapp', phone1, 'Hello'.tr),
|
||||||
|
),
|
||||||
|
CupertinoActionSheetAction(
|
||||||
|
child: Text('Send Email'.tr),
|
||||||
|
onPressed: () =>
|
||||||
|
launchCommunication('email', 'support@sefer.live', 'Hello'.tr),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
cancelButton: CupertinoActionSheetAction(
|
||||||
|
child: Text('Cancel'.tr),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:SEFER/views/widgets/my_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:SEFER/constant/box_name.dart';
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
import 'package:SEFER/constant/colors.dart';
|
import 'package:SEFER/constant/colors.dart';
|
||||||
import 'package:SEFER/constant/links.dart';
|
import 'package:SEFER/constant/links.dart';
|
||||||
@@ -9,11 +12,38 @@ import 'package:SEFER/constant/style.dart';
|
|||||||
import 'package:SEFER/controller/functions/crud.dart';
|
import 'package:SEFER/controller/functions/crud.dart';
|
||||||
import 'package:SEFER/main.dart';
|
import 'package:SEFER/main.dart';
|
||||||
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
||||||
|
import 'package:http_parser/http_parser.dart';
|
||||||
|
import 'package:mime/mime.dart';
|
||||||
|
|
||||||
|
import '../../../constant/api_key.dart';
|
||||||
|
import '../../../print.dart';
|
||||||
|
|
||||||
class ComplaintController extends GetxController {
|
class ComplaintController extends GetxController {
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
final formKey = GlobalKey<FormState>();
|
final formKey = GlobalKey<FormState>();
|
||||||
final complaintController = TextEditingController();
|
final complaintController = TextEditingController();
|
||||||
|
final suggestionController = TextEditingController();
|
||||||
|
List feedBack = [];
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
getLatestRidesForPassengers();
|
||||||
|
}
|
||||||
|
|
||||||
|
getLatestRidesForPassengers() async {
|
||||||
|
isLoading = true;
|
||||||
|
update();
|
||||||
|
var res = await CRUD().get(link: AppLink.getFeedBack, payload: {
|
||||||
|
'passengerId': box.read(BoxName.passengerID).toString(),
|
||||||
|
});
|
||||||
|
if (res != 'failure') {
|
||||||
|
var d = jsonDecode(res)['message'];
|
||||||
|
feedBack = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading = false;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void addComplaint() async {
|
void addComplaint() async {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
@@ -34,11 +64,175 @@ class ComplaintController extends GetxController {
|
|||||||
title: 'Ok'.tr,
|
title: 'Ok'.tr,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
Get.back();
|
// Get.back();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isUploading = false.obs;
|
||||||
|
var uploadSuccess = false.obs;
|
||||||
|
late String audioLink = '';
|
||||||
|
Future<void> uploadAudioFile(File audioFile) async {
|
||||||
|
try {
|
||||||
|
isUploading.value = true;
|
||||||
|
|
||||||
|
// Prepare the file upload
|
||||||
|
var uri = Uri.parse('${AppLink.seferCairoServer}/upload_audio.php');
|
||||||
|
var request = http.MultipartRequest('POST', uri);
|
||||||
|
|
||||||
|
// Add the file to the request with MIME type
|
||||||
|
var mimeType = lookupMimeType(audioFile.path);
|
||||||
|
request.headers.addAll({
|
||||||
|
'Authorization':
|
||||||
|
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
|
||||||
|
});
|
||||||
|
request.files.add(
|
||||||
|
await http.MultipartFile.fromPath(
|
||||||
|
'audio',
|
||||||
|
audioFile.path,
|
||||||
|
contentType: mimeType != null ? MediaType.parse(mimeType) : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
var response = await request.send();
|
||||||
|
|
||||||
|
// Convert response to string for parsing
|
||||||
|
var responseBody = await http.Response.fromStream(response);
|
||||||
|
|
||||||
|
// After the upload request
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var jsonResponse = jsonDecode(responseBody.body);
|
||||||
|
|
||||||
|
if (jsonResponse['status'] == 'Audio file uploaded successfully.') {
|
||||||
|
uploadSuccess.value = true;
|
||||||
|
audioLink = jsonResponse['link']; // Get the audio link
|
||||||
|
Get.back();
|
||||||
|
Get.snackbar('Success'.tr, 'Audio uploaded successfully.'.tr,
|
||||||
|
backgroundColor: const Color.fromARGB(255, 89, 185, 115));
|
||||||
|
} else {
|
||||||
|
uploadSuccess.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uploadSuccess.value = false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
uploadSuccess.value = false;
|
||||||
|
} finally {
|
||||||
|
isUploading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var customerServiceSolutions;
|
||||||
|
var passengerReport;
|
||||||
|
var driverReport;
|
||||||
|
var isloading = false;
|
||||||
|
Future<void> geminiAudio(payload, String audioLink, String complain) async {
|
||||||
|
String prompt = '''
|
||||||
|
Analyze the following complaint between a passenger and driver in a ride-hailing service. The complaint includes an audio link for reference. Provide two possible solutions for customer service to resolve the issue, and generate a detailed report for both the passenger and the driver.
|
||||||
|
|
||||||
|
Complaint details:
|
||||||
|
- Passenger: $complain
|
||||||
|
- Driver: [Driver's complaint]
|
||||||
|
- Ride Information: {ride details such as start_location, end_location, date, price, status, and rating details}
|
||||||
|
- Audio Link: [$audioLink]
|
||||||
|
|
||||||
|
Output the result in JSON format with the following structure:
|
||||||
|
{
|
||||||
|
"customerServiceSolutions": [
|
||||||
|
"solution1",
|
||||||
|
"solution2"
|
||||||
|
],
|
||||||
|
"passengerReport": {
|
||||||
|
"solution": "Passenger's solution" if passenger right,
|
||||||
|
"complaint": "Passenger's complaint",
|
||||||
|
"rideDetails": {detailed ride info}
|
||||||
|
},
|
||||||
|
"driverReport": {
|
||||||
|
"complaint": "Driver's complaint",
|
||||||
|
"rideDetails": {detailed ride info}
|
||||||
|
}
|
||||||
|
} the response in arabic language with egypt
|
||||||
|
''';
|
||||||
|
|
||||||
|
var requestBody = jsonEncode({
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"parts": [
|
||||||
|
{"text": "$payload $prompt"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"generationConfig": {
|
||||||
|
"temperature": 1,
|
||||||
|
"topK": 64,
|
||||||
|
"topP": 0.95,
|
||||||
|
"maxOutputTokens": 8192,
|
||||||
|
"stopSequences": []
|
||||||
|
},
|
||||||
|
"safetySettings": [
|
||||||
|
{
|
||||||
|
"category": "HARM_CATEGORY_HARASSMENT",
|
||||||
|
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "HARM_CATEGORY_HATE_SPEECH",
|
||||||
|
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
|
||||||
|
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
|
||||||
|
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse(
|
||||||
|
'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro:generateContent?key=${AK.geminiApi}'),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: requestBody,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var responseData = jsonDecode(response.body);
|
||||||
|
var result = responseData['candidates'][0]['content']['parts'][0]['text'];
|
||||||
|
Log.print('result: ${result}');
|
||||||
|
|
||||||
|
// Clean up the result by removing surrounding backticks if they exist
|
||||||
|
result = result.replaceAll(RegExp(r'^```json\s*|\s*```$'), '');
|
||||||
|
|
||||||
|
// Attempt to decode the cleaned result as JSON
|
||||||
|
try {
|
||||||
|
var jsonResult = jsonDecode(result);
|
||||||
|
|
||||||
|
// Access customer service solutions and reports for both passenger and driver
|
||||||
|
customerServiceSolutions = jsonResult['customerServiceSolutions'];
|
||||||
|
passengerReport = jsonResult['passengerReport'];
|
||||||
|
driverReport = jsonResult['driverReport'];
|
||||||
|
update();
|
||||||
|
// Use the data accordingly
|
||||||
|
// For example, log the reports or display them in a UI dialog
|
||||||
|
|
||||||
|
update();
|
||||||
|
} catch (e) {
|
||||||
|
MyDialog().getDialog(
|
||||||
|
'Error'.tr,
|
||||||
|
'Unable to parse the response as JSON. Please check the format and try again.'
|
||||||
|
.tr, () {
|
||||||
|
Get.back();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Get.snackbar(
|
||||||
|
'Error', "Request failed with status: ${response.statusCode}",
|
||||||
|
backgroundColor: AppColor.redColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
309
lib/controller/home/profile/invit_controller.dart
Normal file
309
lib/controller/home/profile/invit_controller.dart
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
|
import 'package:SEFER/constant/colors.dart';
|
||||||
|
import 'package:SEFER/constant/links.dart';
|
||||||
|
import 'package:SEFER/controller/functions/crud.dart';
|
||||||
|
import 'package:SEFER/controller/payment/payment_controller.dart';
|
||||||
|
import 'package:SEFER/views/widgets/mysnakbar.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_contacts/contact.dart';
|
||||||
|
import 'package:flutter_contacts/flutter_contacts.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:share/share.dart';
|
||||||
|
|
||||||
|
import '../../../main.dart';
|
||||||
|
import '../../../print.dart';
|
||||||
|
import '../../../views/widgets/my_dialog.dart';
|
||||||
|
import '../../functions/launch.dart';
|
||||||
|
import '../../notification/notification_captain_controller.dart';
|
||||||
|
|
||||||
|
class InviteController extends GetxController {
|
||||||
|
final TextEditingController invitePhoneController = TextEditingController();
|
||||||
|
List driverInvitationData = [];
|
||||||
|
List driverInvitationDataToPassengers = [];
|
||||||
|
String? couponCode;
|
||||||
|
String? driverCouponCode;
|
||||||
|
|
||||||
|
int selectedTab = 0;
|
||||||
|
PassengerStats passengerStats = PassengerStats();
|
||||||
|
void updateSelectedTab(int index) {
|
||||||
|
selectedTab = index;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> shareCouponCode() async {
|
||||||
|
// TODO: Implement sharing functionality
|
||||||
|
// You can use share_plus package to share the coupon code
|
||||||
|
}
|
||||||
|
Future<void> shareDriverCode() async {
|
||||||
|
if (driverCouponCode != null) {
|
||||||
|
final String shareText = '''
|
||||||
|
Join SEFER as a driver using my referral code!
|
||||||
|
Use code: $driverCouponCode
|
||||||
|
Download the SEFER Driver app now and earn rewards!
|
||||||
|
''';
|
||||||
|
await Share.share(shareText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> sharePassengerCode() async {
|
||||||
|
if (couponCode != null) {
|
||||||
|
final String shareText = '''
|
||||||
|
Get a discount on your first SEFER ride!
|
||||||
|
Use my referral code: $couponCode
|
||||||
|
Download the SEFER app now and enjoy your ride!
|
||||||
|
''';
|
||||||
|
await Share.share(shareText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
// fetchDriverStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchDriverStats() async {
|
||||||
|
try {
|
||||||
|
var response = await CRUD().get(link: AppLink.getInviteDriver, payload: {
|
||||||
|
"driverId": box.read(BoxName.driverID),
|
||||||
|
});
|
||||||
|
if (response != 'failure') {
|
||||||
|
var data = jsonDecode(response);
|
||||||
|
driverInvitationData = data['message'];
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchDriverStatsPassengers() async {
|
||||||
|
try {
|
||||||
|
var response = await CRUD()
|
||||||
|
.get(link: AppLink.getDriverInvitationToPassengers, payload: {
|
||||||
|
"driverId": box.read(BoxName.passengerID),
|
||||||
|
});
|
||||||
|
if (response != 'failure') {
|
||||||
|
var data = jsonDecode(response);
|
||||||
|
driverInvitationDataToPassengers = data['message'];
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectPhone(String phone) {
|
||||||
|
if (box.read(BoxName.countryCode) == 'Egypt') {
|
||||||
|
invitePhoneController.text = phone;
|
||||||
|
update();
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Contact> contacts = <Contact>[];
|
||||||
|
List<Contact> selectedContacts = <Contact>[];
|
||||||
|
RxList<Map<String, dynamic>> contactMaps = <Map<String, dynamic>>[].obs;
|
||||||
|
|
||||||
|
Future<void> pickContacts() async {
|
||||||
|
try {
|
||||||
|
// Request contacts permission
|
||||||
|
if (await FlutterContacts.requestPermission(readonly: true)) {
|
||||||
|
// Fetch all contacts with full properties
|
||||||
|
final List<Contact> allContacts = await FlutterContacts.getContacts(
|
||||||
|
withProperties: true,
|
||||||
|
withThumbnail: false,
|
||||||
|
withPhoto: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if contacts are available
|
||||||
|
if (allContacts.isNotEmpty) {
|
||||||
|
// Store the contacts
|
||||||
|
contacts = allContacts;
|
||||||
|
Log.print('contacts: $contacts');
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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(),
|
||||||
|
};
|
||||||
|
}).toList());
|
||||||
|
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
Get.snackbar('No contacts available'.tr,
|
||||||
|
'Please add contacts to your phone.'.tr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Get.snackbar('Permission denied'.tr,
|
||||||
|
'Contact permission is required to pick contacts'.tr);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Get.snackbar(
|
||||||
|
'Error'.tr, 'An error occurred while picking contacts: $e'.tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSelectPassengerInvitation(int index) async {
|
||||||
|
MyDialog().getDialog(
|
||||||
|
driverInvitationDataToPassengers[index]['countOfInvitDriver'] < 2
|
||||||
|
? '${'When'.tr} ${driverInvitationDataToPassengers[index]['passengerName']} ${"complete, you can claim your gift".tr} '
|
||||||
|
: 'You deserve the gift'.tr,
|
||||||
|
'${driverInvitationDataToPassengers[index]['passengerName']} ${driverInvitationDataToPassengers[index]['countOfInvitDriver']} / 2 ${'Trip'.tr}',
|
||||||
|
() async {
|
||||||
|
if (driverInvitationDataToPassengers[index]['countOfInvitDriver'] < 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<PaymentController>().addPassengersWallet('20');
|
||||||
|
// add for invitor too
|
||||||
|
// await Get.find<CaptainWalletController>().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();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<String> to a comma-separated string
|
||||||
|
});
|
||||||
|
if (res != 'failure') {}
|
||||||
|
} else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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')) {
|
||||||
|
digitsOnly = digitsOnly.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return digitsOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendInviteToPassenger() async {
|
||||||
|
if (invitePhoneController.text.isEmpty ||
|
||||||
|
invitePhoneController.text.length < 11) {
|
||||||
|
mySnackeBarError('Please enter a correct phone'.tr);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try {
|
||||||
|
String phoneNumber = formatPhoneNumber(invitePhoneController.text);
|
||||||
|
|
||||||
|
var response =
|
||||||
|
await CRUD().post(link: AppLink.addInvitationPassenger, payload: {
|
||||||
|
"driverId": box.read(BoxName.passengerID),
|
||||||
|
"inviterPassengerPhone": '+2$phoneNumber'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response != 'failure') {
|
||||||
|
var d = response;
|
||||||
|
Get.snackbar('Success', 'Invite sent successfully'.tr);
|
||||||
|
|
||||||
|
String message = '${'*SEFER 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';
|
||||||
|
|
||||||
|
launchCommunication('whatsapp', '+2$phoneNumber', message);
|
||||||
|
|
||||||
|
invitePhoneController.clear();
|
||||||
|
} else {
|
||||||
|
Get.snackbar('Error'.tr, "Invite code already used".tr,
|
||||||
|
backgroundColor: AppColor.redColor,
|
||||||
|
duration: const Duration(seconds: 4));
|
||||||
|
}
|
||||||
|
// } catch (e) {
|
||||||
|
// Get.snackbar('Error', 'An error occurred'.tr);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PassengerStats {
|
||||||
|
final int totalInvites;
|
||||||
|
final int activeUsers;
|
||||||
|
final double totalEarnings;
|
||||||
|
|
||||||
|
PassengerStats({
|
||||||
|
this.totalInvites = 0,
|
||||||
|
this.activeUsers = 0,
|
||||||
|
this.totalEarnings = 0.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/constant/links.dart';
|
import 'package:SEFER/constant/links.dart';
|
||||||
import 'package:SEFER/constant/style.dart';
|
|
||||||
import 'package:SEFER/controller/functions/crud.dart';
|
import 'package:SEFER/controller/functions/crud.dart';
|
||||||
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
|
||||||
|
import '../../../main.dart';
|
||||||
|
|
||||||
class PromosController extends GetxController {
|
class PromosController extends GetxController {
|
||||||
List<dynamic> promoList = [];
|
List<dynamic> promoList = [];
|
||||||
@@ -17,7 +18,9 @@ class PromosController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future getPromoByToday() async {
|
Future getPromoByToday() async {
|
||||||
var res = await CRUD().get(link: AppLink.getPromoBytody, payload: {});
|
var res = await CRUD().get(link: AppLink.getPromoBytody, payload: {
|
||||||
|
'passengerID': box.read(BoxName.passengerID).toString(),
|
||||||
|
});
|
||||||
if (res.toString() == 'failure') {
|
if (res.toString() == 'failure') {
|
||||||
// Get.defaultDialog(
|
// Get.defaultDialog(
|
||||||
// title: 'No Promo for today .'.tr,
|
// title: 'No Promo for today .'.tr,
|
||||||
|
|||||||
323
lib/controller/home/vip_waitting_page.dart
Normal file
323
lib/controller/home/vip_waitting_page.dart
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
|
import 'package:SEFER/constant/colors.dart';
|
||||||
|
import 'package:SEFER/constant/links.dart';
|
||||||
|
import 'package:SEFER/constant/style.dart';
|
||||||
|
import 'package:SEFER/controller/home/map_passenger_controller.dart';
|
||||||
|
import 'package:SEFER/main.dart';
|
||||||
|
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
||||||
|
import 'package:SEFER/views/widgets/my_scafold.dart';
|
||||||
|
import 'package:SEFER/views/widgets/mycircular.dart';
|
||||||
|
import 'package:SEFER/views/widgets/mysnakbar.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import '../functions/crud.dart';
|
||||||
|
|
||||||
|
class VipOrderController extends GetxController {
|
||||||
|
RxBool isLoading = false.obs;
|
||||||
|
final arguments = Get.arguments;
|
||||||
|
RxList<dynamic> tripData = <dynamic>[].obs;
|
||||||
|
RxBool isButtonVisible = false.obs;
|
||||||
|
RxInt countdown = 60.obs;
|
||||||
|
Timer? _countdownTimer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
fetchOrder();
|
||||||
|
startCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
_countdownTimer?.cancel();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> fetchOrder() async {
|
||||||
|
try {
|
||||||
|
isLoading.value = true;
|
||||||
|
var mapPassengerController = Get.find<MapPassengerController>();
|
||||||
|
|
||||||
|
var res = await CRUD().get(
|
||||||
|
link: AppLink.getMishwari,
|
||||||
|
payload: {
|
||||||
|
// 'driverId': mapPassengerController.driverIdVip.toString(),
|
||||||
|
'driverId': box.read(BoxName.passengerID).toString(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res != 'failure') {
|
||||||
|
var decodedResponse = jsonDecode(res);
|
||||||
|
if (decodedResponse['message'] is List) {
|
||||||
|
tripData.value = decodedResponse['message'];
|
||||||
|
} else {
|
||||||
|
tripData.clear(); // Ensure empty list if no data
|
||||||
|
// mySnackeBarError('No trip data found');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tripData.clear();
|
||||||
|
// mySnackeBarError('Failed to fetch trip data');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
tripData.clear();
|
||||||
|
// mySnackeBarError('An error occurred: $e');
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void startCountdown() {
|
||||||
|
_countdownTimer?.cancel(); // Cancel any existing timer
|
||||||
|
countdown.value = 60;
|
||||||
|
|
||||||
|
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
|
if (countdown.value > 0) {
|
||||||
|
countdown.value--;
|
||||||
|
} else {
|
||||||
|
timer.cancel();
|
||||||
|
isButtonVisible.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendToDriverAgain() {
|
||||||
|
// Reset states
|
||||||
|
isButtonVisible.value = false;
|
||||||
|
fetchOrder(); // Refresh order
|
||||||
|
startCountdown(); // Restart countdown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VipWaittingPage extends StatelessWidget {
|
||||||
|
VipWaittingPage({super.key});
|
||||||
|
final VipOrderController vipOrderController = Get.put(VipOrderController());
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MyScafolld(
|
||||||
|
title: "Waiting VIP".tr,
|
||||||
|
body: [
|
||||||
|
Obx(() {
|
||||||
|
// Loading state
|
||||||
|
if (vipOrderController.isLoading.value) {
|
||||||
|
return const Center(child: MyCircularProgressIndicator());
|
||||||
|
}
|
||||||
|
|
||||||
|
// No data state
|
||||||
|
if (vipOrderController.tripData.isEmpty) {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
'No trip data available'.tr,
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data available
|
||||||
|
var data = vipOrderController.tripData[0];
|
||||||
|
|
||||||
|
// Function to get the localized status string
|
||||||
|
String getLocalizedStatus(String status) {
|
||||||
|
switch (status) {
|
||||||
|
case 'pending':
|
||||||
|
return 'pending'.tr;
|
||||||
|
case 'accepted':
|
||||||
|
return 'accepted'.tr;
|
||||||
|
case 'begin':
|
||||||
|
return 'begin'.tr;
|
||||||
|
case 'rejected':
|
||||||
|
return 'rejected'.tr;
|
||||||
|
case 'cancelled':
|
||||||
|
return 'cancelled'.tr;
|
||||||
|
default:
|
||||||
|
return 'unknown'.tr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to get the appropriate status color
|
||||||
|
Color getStatusColor(String status) {
|
||||||
|
switch (status) {
|
||||||
|
case 'pending':
|
||||||
|
return Colors.yellow;
|
||||||
|
case 'accepted':
|
||||||
|
return Colors.green;
|
||||||
|
case 'begin':
|
||||||
|
return Colors.green;
|
||||||
|
case 'rejected':
|
||||||
|
return Colors.red;
|
||||||
|
case 'cancelled':
|
||||||
|
return Colors.red;
|
||||||
|
default:
|
||||||
|
return Colors.grey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
elevation: 4,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
margin: const EdgeInsets.all(16),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${'Driver Name:'.tr} ${data['name']}",
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${'Car Plate:'.tr} ${data['car_plate']}",
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${'Car Make:'.tr} ${data['make']}",
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${'Car Model:'.tr} ${data['model']}",
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${"Car Color:".tr} ${data['color']}",
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
child: Icon(
|
||||||
|
Fontisto.car,
|
||||||
|
size: 80,
|
||||||
|
color: Color(
|
||||||
|
int.parse(
|
||||||
|
data['color_hex'].replaceFirst('#', '0xff'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
const Divider(),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Container(
|
||||||
|
color: getStatusColor(data['status']),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
"${'Trip Status:'.tr} ${getLocalizedStatus(data['status'])}",
|
||||||
|
style: const TextStyle(fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${'Scheduled Time:'.tr} ${DateFormat('yyyy-MM-dd hh:mm a').format(DateTime.parse(data['timeSelected']))}",
|
||||||
|
style: const TextStyle(fontSize: 16),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
data['status'].toString() != 'begin'
|
||||||
|
? MyElevatedButton(
|
||||||
|
title: "Cancel Trip".tr,
|
||||||
|
kolor: AppColor.redColor,
|
||||||
|
onPressed: () {
|
||||||
|
Get.find<MapPassengerController>().cancelVip(
|
||||||
|
data['token'].toString(),
|
||||||
|
data['id'].toString(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
Obx(() {
|
||||||
|
// If countdown is still running, show countdown
|
||||||
|
if (!vipOrderController.isButtonVisible.value) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
CircularProgressIndicator(
|
||||||
|
value: 1 -
|
||||||
|
(vipOrderController.countdown.value / 60),
|
||||||
|
strokeWidth: 6.0,
|
||||||
|
color: AppColor.greenColor,
|
||||||
|
backgroundColor: AppColor.accentColor,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
"${vipOrderController.countdown.value}s ${'remaining'.tr}",
|
||||||
|
style: const TextStyle(fontSize: 16),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once countdown is complete, show "Send to Driver Again" button
|
||||||
|
return MyElevatedButton(
|
||||||
|
title: "Send to Driver Again".tr,
|
||||||
|
kolor: AppColor.greenColor,
|
||||||
|
onPressed: () {
|
||||||
|
Get.find<MapPassengerController>()
|
||||||
|
.sendToDriverAgain(data['token']);
|
||||||
|
vipOrderController.fetchOrder();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 30,
|
||||||
|
),
|
||||||
|
data['status'].toString() == 'begin'
|
||||||
|
? MyElevatedButton(
|
||||||
|
title: "Click here to begin your trip\n\nGood luck, "
|
||||||
|
.tr +
|
||||||
|
box.read(BoxName.name).toString(),
|
||||||
|
kolor: AppColor.greenColor,
|
||||||
|
onPressed: () {
|
||||||
|
final mapPassengerController =
|
||||||
|
Get.find<MapPassengerController>();
|
||||||
|
mapPassengerController.make = data['make'];
|
||||||
|
mapPassengerController.licensePlate =
|
||||||
|
data['car_plate'];
|
||||||
|
mapPassengerController.model = data['model'];
|
||||||
|
mapPassengerController.driverId = data['driverId'];
|
||||||
|
mapPassengerController.carColor = data['color'];
|
||||||
|
mapPassengerController.driverRate = data['rating'];
|
||||||
|
mapPassengerController.colorHex = data['color_hex'];
|
||||||
|
mapPassengerController.driverPhone = data['phone'];
|
||||||
|
mapPassengerController.driverToken = data['token'];
|
||||||
|
mapPassengerController.driverName =
|
||||||
|
data['name'].toString().split(' ')[0];
|
||||||
|
|
||||||
|
Get.back();
|
||||||
|
|
||||||
|
mapPassengerController.begiVIPTripFromPassenger();
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: const SizedBox()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
isleading: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,72 +20,58 @@ class LocaleController extends GetxController {
|
|||||||
case "ar":
|
case "ar":
|
||||||
locale = const Locale("ar");
|
locale = const Locale("ar");
|
||||||
appTheme = themeArabic;
|
appTheme = themeArabic;
|
||||||
box.write(BoxName.lang, 'ar');
|
|
||||||
break;
|
break;
|
||||||
case "en":
|
case "en":
|
||||||
locale = const Locale("en");
|
locale = const Locale("en");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'en');
|
|
||||||
break;
|
break;
|
||||||
case "tr":
|
case "tr":
|
||||||
locale = const Locale("tr");
|
locale = const Locale("tr");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'tr');
|
|
||||||
break;
|
break;
|
||||||
case "fr":
|
case "fr":
|
||||||
locale = const Locale("fr");
|
locale = const Locale("fr");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'fr');
|
|
||||||
break;
|
break;
|
||||||
case "it":
|
case "it":
|
||||||
locale = const Locale("it");
|
locale = const Locale("it");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'it');
|
|
||||||
break;
|
break;
|
||||||
case "de":
|
case "de":
|
||||||
locale = const Locale("de");
|
locale = const Locale("de");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'de');
|
|
||||||
break;
|
break;
|
||||||
case "el":
|
case "el":
|
||||||
locale = const Locale("el");
|
locale = const Locale("el");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'el');
|
|
||||||
break;
|
break;
|
||||||
case "es":
|
case "es":
|
||||||
locale = const Locale("es");
|
locale = const Locale("es");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'es');
|
|
||||||
break;
|
break;
|
||||||
case "fa":
|
case "fa":
|
||||||
locale = const Locale("fa");
|
locale = const Locale("fa");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeArabic;
|
||||||
box.write(BoxName.lang, 'fa');
|
|
||||||
break;
|
break;
|
||||||
case "zh":
|
case "zh":
|
||||||
locale = const Locale("zh");
|
locale = const Locale("zh");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'zh');
|
|
||||||
break;
|
break;
|
||||||
case "ru":
|
case "ru":
|
||||||
locale = const Locale("ru");
|
locale = const Locale("ru");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'ru');
|
|
||||||
break;
|
break;
|
||||||
case "hi":
|
case "hi":
|
||||||
locale = const Locale("hi");
|
locale = const Locale("hi");
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
box.write(BoxName.lang, 'hi');
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
locale = Locale(Get.deviceLocale!.languageCode);
|
locale = Locale(Get.deviceLocale!.languageCode);
|
||||||
box.write(BoxName.lang, Get.deviceLocale!.languageCode);
|
|
||||||
appTheme = themeEnglish;
|
appTheme = themeEnglish;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
box.write(BoxName.lang, langcode);
|
box.write(BoxName.lang, langcode);
|
||||||
// box.write(BoxName.lang, langcode);
|
|
||||||
Get.changeTheme(appTheme);
|
Get.changeTheme(appTheme);
|
||||||
Get.updateLocale(locale);
|
Get.updateLocale(locale);
|
||||||
restartApp();
|
restartApp();
|
||||||
@@ -94,62 +80,15 @@ class LocaleController extends GetxController {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
String storedLang = box.read(BoxName.lang) ?? "";
|
String? storedLang = box.read(BoxName.lang);
|
||||||
switch (storedLang) {
|
if (storedLang == null) {
|
||||||
case "ar":
|
// Use device language if no language is stored
|
||||||
language = const Locale("ar");
|
storedLang = Get.deviceLocale!.languageCode;
|
||||||
appTheme = themeArabic;
|
box.write(BoxName.lang, storedLang);
|
||||||
break;
|
|
||||||
case "en":
|
|
||||||
language = const Locale("en");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "tr":
|
|
||||||
language = const Locale("tr");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "fr":
|
|
||||||
language = const Locale("fr");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "it":
|
|
||||||
language = const Locale("it");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "de":
|
|
||||||
language = const Locale("de");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "el":
|
|
||||||
language = const Locale("el");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "es":
|
|
||||||
language = const Locale("es");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "fa":
|
|
||||||
language = const Locale("fa");
|
|
||||||
appTheme = themeArabic;
|
|
||||||
break;
|
|
||||||
case "zh":
|
|
||||||
language = const Locale("zh");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "ru":
|
|
||||||
language = const Locale("ru");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
case "hi":
|
|
||||||
language = const Locale("hi");
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
language = Locale(Get.deviceLocale!.languageCode);
|
|
||||||
appTheme = themeEnglish;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeLang(storedLang);
|
||||||
|
|
||||||
super.onInit();
|
super.onInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7574
lib/controller/local/phone_intel/countries.dart
Normal file
7574
lib/controller/local/phone_intel/countries.dart
Normal file
File diff suppressed because it is too large
Load Diff
168
lib/controller/local/phone_intel/country_picker_dialog.dart
Normal file
168
lib/controller/local/phone_intel/country_picker_dialog.dart
Normal 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),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
lib/controller/local/phone_intel/helpers.dart
Normal file
31
lib/controller/local/phone_intel/helpers.dart
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
521
lib/controller/local/phone_intel/intl_phone_field.dart
Normal file
521
lib/controller/local/phone_intel/intl_phone_field.dart
Normal 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,
|
||||||
|
}
|
||||||
79
lib/controller/local/phone_intel/phone_number.dart
Normal file
79
lib/controller/local/phone_intel/phone_number.dart
Normal 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)';
|
||||||
|
}
|
||||||
@@ -4,7 +4,52 @@ class MyTranslation extends Translations {
|
|||||||
@override
|
@override
|
||||||
Map<String, Map<String, String>> get keys => {
|
Map<String, Map<String, String>> get keys => {
|
||||||
"ar": {
|
"ar": {
|
||||||
|
"Home Page": "الصفحة الرئيسية",
|
||||||
|
"To change Language the App": "لتغيير لغة التطبيق",
|
||||||
|
"Learn more about our app and mission":
|
||||||
|
"تعرف على المزيد حول تطبيقنا ورسالتنا",
|
||||||
|
"Promos For Today": "عروض اليوم",
|
||||||
|
'Bonus gift': 'بونص', "Pay": "ادفع",
|
||||||
|
"Get": "احصل على",
|
||||||
|
"Send to Driver Again": "إرسال إلى السائق مرة أخرى",
|
||||||
|
"Driver Name:": "اسم السائق:",
|
||||||
|
'No trip data available': "لا توجد بيانات رحلة متاحة",
|
||||||
|
"Car Plate:": "رقم اللوحة:", "remaining": "متبقي",
|
||||||
|
"Order Cancelled": "تم إلغاء الطلب",
|
||||||
|
'You canceled VIP trip': "ألغيت الرحلة",
|
||||||
|
"Passenger cancelled order": "الراكب قام بإلغاء الطلب",
|
||||||
|
"Your trip is scheduled": "رحلتك مجدولة",
|
||||||
|
"Don't forget your ride!": "لا تنسَ رحلتك!",
|
||||||
|
"Trip updated successfully": "تم تحديث الرحلة بنجاح",
|
||||||
|
"Car Make:": "ماركة السيارة:",
|
||||||
|
"Car Model:": "طراز السيارة:", "Car Color:": "لون السيارة:",
|
||||||
|
"Driver Phone:": "رقم هاتف السائق:",
|
||||||
|
'Pre-booking': 'احجز مسبقًا', "Waiting VIP": "انتظار VIP",
|
||||||
|
"Driver List": "قائمة السائقين", "Confirm Trip": "تأكيد الرحلة",
|
||||||
|
"Select date and time of trip": "حدد تاريخ ووقت الرحلة",
|
||||||
|
"Date and Time Picker": "اختيار التاريخ والوقت",
|
||||||
|
"Trip Status:": "حالة الرحلة:", "pending": "قيد الانتظار",
|
||||||
|
"accepted": "تم القبول",
|
||||||
|
"rejected": "تم الرفض",
|
||||||
|
"Scheduled Time:": "الوقت المحدد:",
|
||||||
|
"No drivers available": "لا يوجد سائقين متاحين",
|
||||||
|
"Please try again in a few moments":
|
||||||
|
"يرجى المحاولة مرة أخرى بعد قليل",
|
||||||
|
"Unknown Driver": "سائق غير معروف",
|
||||||
|
"rides": "الرحلات",
|
||||||
|
"The reason is": "السبب هو",
|
||||||
|
"User does not have a wallet #1652": "المستخدم ليس لديه محفظة ",
|
||||||
|
"Price of trip": "سعر الرحلة",
|
||||||
|
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
|
||||||
|
"بالنسبة لرحلات السرعة والتوصيل، يتم حساب السعر ديناميكياً. بالنسبة لرحلات الراحة، يتم حساب السعر بناءً على الوقت والمسافة",
|
||||||
|
"Phone Wallet Saved Successfully": "تم حفظ المحفظة الهاتفية بنجاح",
|
||||||
|
"Add wallet phone you use": "أضف محفظة الهاتف التي تستخدمها",
|
||||||
"Update Available": "تحديث متوفر",
|
"Update Available": "تحديث متوفر",
|
||||||
|
'Phone number must be exactly 11 digits long':
|
||||||
|
"رقم الهاتف يجب أن يكون بطول 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.":
|
"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":
|
"We use location to get accurate and nearest passengers for you":
|
||||||
@@ -41,14 +86,20 @@ class MyTranslation extends Translations {
|
|||||||
"Pick from map destination": "حدد وجهتك على الخريطة",
|
"Pick from map destination": "حدد وجهتك على الخريطة",
|
||||||
"Pick or Tap to confirm": "حدد أو انقر للتأكيد",
|
"Pick or Tap to confirm": "حدد أو انقر للتأكيد",
|
||||||
"Select Order Type": "حدد نوع الطلب",
|
"Select Order Type": "حدد نوع الطلب",
|
||||||
|
'Accepted your order': "تم قبول طلبك",
|
||||||
"Choose who this order is for": "اختر لمن هذا الطلب",
|
"Choose who this order is for": "اختر لمن هذا الطلب",
|
||||||
|
"Order Accepted": "تم قبول الطلب", "with type": "مع النوع",
|
||||||
|
"accepted your order at price": "قبل طلبك بالسعر",
|
||||||
"I want to order for myself": "أريد أن أطلب لنفسي",
|
"I want to order for myself": "أريد أن أطلب لنفسي",
|
||||||
"I want to order for someone else": "أريد أن أطلب لشخص آخر",
|
"I want to order for someone else": "أريد أن أطلب لشخص آخر",
|
||||||
"Cancel Trip from driver": "إلغاء الرحلة من السائق",
|
"Cancel Trip from driver": "إلغاء الرحلة من السائق",
|
||||||
|
"Order Cancelled": "تم إلغاء الطلب",
|
||||||
|
"you canceled order": "لقد قمت بإلغاء الطلب",
|
||||||
"If you want order to another person": "إذا كنت تريد الطلب لشخص آخر",
|
"If you want order to another person": "إذا كنت تريد الطلب لشخص آخر",
|
||||||
"We will look for a new driver.\nPlease wait.":
|
"Ok I will go now.": "حسنًا، سأذهب الآن.",
|
||||||
"سنبحث عن سائق جديد.\nمن فضلك انتظر.",
|
"Hi, I will go now": "مرحبًا، سأذهب الآن.",
|
||||||
"upgrade price": "رفع السعر",
|
"upgrade price": "رفع السعر",
|
||||||
|
'Please enter a correct phone': 'يرجى إدخال رقم هاتف صحيح',
|
||||||
'airport': 'مطار',
|
'airport': 'مطار',
|
||||||
"Best choice for a comfortable car with a flexible route and stop points. This airport offers visa entry at this price.":
|
"Best choice for a comfortable car with a flexible route and stop points. This airport offers visa entry at this price.":
|
||||||
"أفضل اختيار لسيارة مريحة مع طريق ونقاط توقف مرنة. يقدم هذا المطار تأشيرة دخول بهذا السعر.",
|
"أفضل اختيار لسيارة مريحة مع طريق ونقاط توقف مرنة. يقدم هذا المطار تأشيرة دخول بهذا السعر.",
|
||||||
@@ -224,15 +275,76 @@ iOS [https://getapp.cc/app/6458734951]
|
|||||||
"Capture an Image of Your ID Document front":
|
"Capture an Image of Your ID Document front":
|
||||||
"التقط صورة للواجهة الأمامية لوثيقة هويتك",
|
"التقط صورة للواجهة الأمامية لوثيقة هويتك",
|
||||||
"NationalID": "الرقم القومي",
|
"NationalID": "الرقم القومي",
|
||||||
|
'You can share the SEFER App with your friends and earn rewards for rides they take using your code':
|
||||||
|
'يمكنك مشاركة تطبيق SEFER مع أصدقائك وكسب مكافآت من الرحلات التي يقومون بها باستخدام كودك.',
|
||||||
"FullName": "الاسم الكامل",
|
"FullName": "الاسم الكامل",
|
||||||
|
"No invitation found yet!": "لم يتم العثور على دعوات حتى الآن!",
|
||||||
"InspectionResult": "نتيجة الفحص",
|
"InspectionResult": "نتيجة الفحص",
|
||||||
"Criminal Record": "السجل الجنائي",
|
"Criminal Record": "السجل الجنائي", 'Share App': 'شارك التطبيق',
|
||||||
"The email or phone number is already registered.":
|
"The email or phone number is already registered.":
|
||||||
"البريد الإلكتروني أو رقم الهاتف مسجل بالفعل.",
|
"البريد الإلكتروني أو رقم الهاتف مسجل بالفعل.",
|
||||||
'To become a ride-sharing driver on the Sefer 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 Sefer app. Please note, submitting fraudulent documents is a serious offense and may result in immediate termination and legal consequences.':
|
'To become a ride-sharing driver on the Sefer 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 Sefer app. Please note, submitting fraudulent documents is a serious offense and may result in immediate termination and legal consequences.':
|
||||||
'لِتُصْبِحَ سَائِقَاً لِلرُّكوبِ المُشْتَرَكِ عَلَى تَطْبِيق سَفَر، يَجِبُ عَلَيْكَ تَحْمِيل رُخْصَةِ القِيَادَةِ، وَثِيقَةِ الهُوِيَّةِ، وَوَثِيقَةَ تَسْجِيل السَّيَّارَةِ. سَيَقُومُ نِظَامُ الذَّكَاءِ الاِصْطِنَاعِيِّ لَدَيْنَا بِمُرَاجَعَةِ وَتَحْقِيقِ صِحَّةِ الوَثَائِقِ فِي غُضُونِ ٢-٣ دَقَائِقَ فَقَطْ. إِذَا تَمَّتْ المُوَافَقَةُ عَلَى وَثَائِقِكَ، يُمْكِنُكَ البَدْءُ فِي العَمَلِ كَسَائِقٍ عَلَى تَطْبِيق سَفَر. يُرْجَى مُلَاحَظَةُ، تَقْدِيمُ وَثَائِقَ مُزَورَةٍ يُعَدُّ جَرِيمَةً خَطِيرَةً وَقَدْ يَتَرَتَّبُ عَلَيْهِ اِنهَاءُ الحِسَابِ فَوْرِيَّاً وَعَوَاقِبُ قَانُونِيَّة.',
|
'لِتُصْبِحَ سَائِقَاً لِلرُّكوبِ المُشْتَرَكِ عَلَى تَطْبِيق سَفَر، يَجِبُ عَلَيْكَ تَحْمِيل رُخْصَةِ القِيَادَةِ، وَثِيقَةِ الهُوِيَّةِ، وَوَثِيقَةَ تَسْجِيل السَّيَّارَةِ. سَيَقُومُ نِظَامُ الذَّكَاءِ الاِصْطِنَاعِيِّ لَدَيْنَا بِمُرَاجَعَةِ وَتَحْقِيقِ صِحَّةِ الوَثَائِقِ فِي غُضُونِ ٢-٣ دَقَائِقَ فَقَطْ. إِذَا تَمَّتْ المُوَافَقَةُ عَلَى وَثَائِقِكَ، يُمْكِنُكَ البَدْءُ فِي العَمَلِ كَسَائِقٍ عَلَى تَطْبِيق سَفَر. يُرْجَى مُلَاحَظَةُ، تَقْدِيمُ وَثَائِقَ مُزَورَةٍ يُعَدُّ جَرِيمَةً خَطِيرَةً وَقَدْ يَتَرَتَّبُ عَلَيْهِ اِنهَاءُ الحِسَابِ فَوْرِيَّاً وَعَوَاقِبُ قَانُونِيَّة.',
|
||||||
"Documents check": "فحص الوثائق",
|
"Documents check": "فحص الوثائق",
|
||||||
"Driver's License": "رخصة القيادة",
|
"Driver's License": "رخصة القيادة",
|
||||||
|
|
||||||
|
"for your first registration!": "للتسجيل الأول!",
|
||||||
|
"Get it Now!": "احصل عليه الآن!",
|
||||||
|
"before": "قبل",
|
||||||
|
"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:": "قم بتثبيت تطبيقنا:",
|
||||||
|
"Invite another driver and both get a gift after he completes 100 trips!":
|
||||||
|
"ادع صديقًا ليكون سائقًا واحصلا على هدية بعد إكماله 100 مشوار!",
|
||||||
|
"Share App": "شارك التطبيق",
|
||||||
|
"Invite": "دعوة", "Are you sure?": "هل أنت متأكد؟",
|
||||||
|
"This will delete all recorded files from your device.":
|
||||||
|
"سيؤدي هذا إلى حذف جميع الملفات المسجلة من جهازك.",
|
||||||
|
"Select a file": "اختر ملفاً",
|
||||||
|
"Select a File": "اختر ملفاً", "Delete": "حذف",
|
||||||
|
'attach audio of complain': 'إرفاق صوت للشكوى',
|
||||||
|
"Phone Number Check": "فحص رقم الهاتف",
|
||||||
|
"Drivers received orders": "السائقون استقبلوا الطلبات",
|
||||||
|
'No audio files recorded.': 'لا توجد ملفات صوتية مسجلة.',
|
||||||
|
'This is for delivery or a motorcycle.':
|
||||||
|
"هذا للتوصيل أو للدراجة النارية.",
|
||||||
|
"We will look for a new driver.\nPlease wait.":
|
||||||
|
"سوف نبحث عن سائق جديد.\nيرجى الانتظار",
|
||||||
|
"Sefer Reminder": "تطبيق سفر",
|
||||||
|
"It's time to check the Sefer app!": "حان وقت استخدام تطبيق سفر",
|
||||||
|
"The email or phone number is already registered.":
|
||||||
|
"البريد الإلكتروني أو رقم الهاتف مسجل بالفعل.",
|
||||||
|
"you must insert token code": "يجب إدخال رمز التحقق.",
|
||||||
|
"Something went wrong. Please try again.":
|
||||||
|
"حدث خطأ ما. يرجى المحاولة مرة أخرى.",
|
||||||
|
"This is for delivery or a motorcycle.":
|
||||||
|
"هذا للتوصيل أو للدراجة النارية.",
|
||||||
|
"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": "السعر",
|
||||||
|
"Status": "الحالة",
|
||||||
|
"Choose from contact": "اختر من جهات الاتصال",
|
||||||
|
'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": " يمكنك المطالبة بهديتك",
|
||||||
|
"When": "عندما يكمل",
|
||||||
|
"Enter driver's phone": "أدخل رقم هاتف السائق",
|
||||||
|
"Send Invite": "أرسل الدعوة", "Show Invitations": "عرض الدعوات",
|
||||||
"License Type": "نوع الرخصة",
|
"License Type": "نوع الرخصة",
|
||||||
"National Number": "الرقم الوطني",
|
"National Number": "الرقم الوطني",
|
||||||
"Name (Arabic)": "الاسم بالعربي",
|
"Name (Arabic)": "الاسم بالعربي",
|
||||||
@@ -369,7 +481,7 @@ iOS [https://getapp.cc/app/6458734951]
|
|||||||
"Go to this Target": "الانْتِقَال إِلَى هَذَا الهَدَف",
|
"Go to this Target": "الانْتِقَال إِلَى هَذَا الهَدَف",
|
||||||
"My Profile": "مَلَفِي الشَّخْصِي",
|
"My Profile": "مَلَفِي الشَّخْصِي",
|
||||||
"Sign Out": "تَسْجِيل الخُرُوج",
|
"Sign Out": "تَسْجِيل الخُرُوج",
|
||||||
"Home Page": "الصَّفْحَة الرَّئِيسِيَّة",
|
|
||||||
"Are you want to go to this site":
|
"Are you want to go to this site":
|
||||||
"هَل تَرْغَب فِي الانْتِقَال إِلَى هَذَا المَوْقِع",
|
"هَل تَرْغَب فِي الانْتِقَال إِلَى هَذَا المَوْقِع",
|
||||||
"MyLocation": "مَوْقِعِي",
|
"MyLocation": "مَوْقِعِي",
|
||||||
@@ -446,11 +558,11 @@ iOS [https://getapp.cc/app/6458734951]
|
|||||||
"Bachelor's Degree": "بَكَالُورِيُوس",
|
"Bachelor's Degree": "بَكَالُورِيُوس",
|
||||||
"Master's Degree": "مَاجِسْتِير",
|
"Master's Degree": "مَاجِسْتِير",
|
||||||
"Doctoral Degree": "دُكْتُورَاه",
|
"Doctoral Degree": "دُكْتُورَاه",
|
||||||
"Promos For today": "الْعُرُوض التَّرْوِيجِيَّة لِلْيَوْم",
|
|
||||||
"Copy this Promo to use it in your Ride!":
|
"Copy this Promo to use it in your Ride!":
|
||||||
"انْسَخْ هَذَا الْعَرْض لِاسْتِخْدَامِهِ فِي رِحْلَتِك!",
|
"انْسَخْ هَذَا الْعَرْض لِاسْتِخْدَامِهِ فِي رِحْلَتِك!",
|
||||||
"To change some Settings": "لِتَغْيِير بَعْض الإِعْدَادَات",
|
"To change some Settings": "لِتَغْيِير بَعْض الإِعْدَادَات",
|
||||||
"To change Language the App": "لِتَغْيِير لُغَة التَّطْبِيق",
|
|
||||||
"Order Request Page": "صَفْحَة طَلَب الطَّلَب",
|
"Order Request Page": "صَفْحَة طَلَب الطَّلَب",
|
||||||
"Rouats of Trip": "طُرُق الرِّحْلَة",
|
"Rouats of Trip": "طُرُق الرِّحْلَة",
|
||||||
"Passenger Name is ": "اسْم الرَّاكِب هُوَ ",
|
"Passenger Name is ": "اسْم الرَّاكِب هُوَ ",
|
||||||
@@ -503,6 +615,30 @@ iOS [https://getapp.cc/app/6458734951]
|
|||||||
"Do you want to pay Tips for this Driver":
|
"Do you want to pay Tips for this Driver":
|
||||||
"هَل تُرِيد دَفْع أُكْرَامِيَّة لِهَذَا السَّائِق؟",
|
"هَل تُرِيد دَفْع أُكْرَامِيَّة لِهَذَا السَّائِق؟",
|
||||||
"Tip is ": " مَبْلَغ الأُكْرَامِيَّة هُوَ",
|
"Tip is ": " مَبْلَغ الأُكْرَامِيَّة هُوَ",
|
||||||
|
"Are you sure to delete this location?":
|
||||||
|
"هل أنت متأكد من حذف هذا الموقع؟",
|
||||||
|
'Are you want to wait drivers to accept your order':
|
||||||
|
'هل تريد الانتظار حتى يقبل السائقون طلبك؟',
|
||||||
|
|
||||||
|
"deleted": "تم الحذف",
|
||||||
|
'Trip is begin': "الرحلة قد بدأت",
|
||||||
|
'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.":
|
||||||
|
"الكابتن مسؤول عن المسار",
|
||||||
|
'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':
|
||||||
|
"بدأت الرحلة! لا تتردد في الاتصال بأرقام الطوارئ، مشاركة رحلتك، أو تفعيل التسجيل الصوتي للرحلة",
|
||||||
|
'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 Sefer app':
|
||||||
|
'الرجاء التأكد من جميع أغراضك الشخصية وأنه تم إضافة باقي الأجرة إن وجد إلى محفظتك قبل النزول. شكرا لاختيارك تطبيق سفر',
|
||||||
|
'Don’t forget your personal belongings.': "لا تنسى متعلقاتك الشخصية",
|
||||||
"Tip is": " مَبْلَغ الأُكْرَامِيَّة هُوَ",
|
"Tip is": " مَبْلَغ الأُكْرَامِيَّة هُوَ",
|
||||||
"Camera Access Denied.": "تَمَّ رَفْض الْوُصُول إِلَى الْكَامِيرَا.",
|
"Camera Access Denied.": "تَمَّ رَفْض الْوُصُول إِلَى الْكَامِيرَا.",
|
||||||
"Open Settings": "افْتَحْ الإِعْدَادَات",
|
"Open Settings": "افْتَحْ الإِعْدَادَات",
|
||||||
@@ -596,6 +732,45 @@ iOS [https://getapp.cc/app/6458734951]
|
|||||||
'الرَّجَاء التَّحَرُّك إِلَى السَّيَّارَة الآن',
|
'الرَّجَاء التَّحَرُّك إِلَى السَّيَّارَة الآن',
|
||||||
'You will receive a code in WhatsApp Messenger':
|
'You will receive a code in WhatsApp Messenger':
|
||||||
"سوف تتلقى رمزًا في واتساب ماسنجر",
|
"سوف تتلقى رمزًا في واتساب ماسنجر",
|
||||||
|
'If you need assistance, contact us':
|
||||||
|
"إذا كنت بحاجة إلى المساعدة، تواصل معنا",
|
||||||
|
"Promo Ended": "انتهى العرض",
|
||||||
|
'Enter the promo code and get': 'أدخل رمز الترويج واحصل على',
|
||||||
|
'DISCOUNT': 'خصم',
|
||||||
|
'No wallet record found': 'لم يتم العثور على سجل محفظة',
|
||||||
|
'for': 'لمدة',
|
||||||
|
"SEFER is the safest ride-sharing app that introduces many features for both captains and passengers. We offer the lowest commission rate of just 8%, ensuring you get the best value for your rides. Our app includes insurance for the best captains, regular maintenance of cars with top engineers, and on-road services to ensure a respectful and high-quality experience for all users.":
|
||||||
|
"سفر هو التطبيق الأكثر أمانًا لمشاركة الركوب الذي يقدم العديد من الميزات لكل من السائقين والركاب. نحن نقدم أقل عمولة بنسبة 8% فقط، مما يضمن حصولك على أفضل قيمة لرحلاتك. يتضمن تطبيقنا التأمين لأفضل السائقين، الصيانة المنتظمة للسيارات مع أفضل المهندسين، والخدمات على الطريق لضمان تجربة محترمة وعالية الجودة لجميع المستخدمين.",
|
||||||
|
"You can contact us during working hours from 12:00 - 19:00.":
|
||||||
|
"يمكنك الاتصال بنا خلال ساعات العمل من 12:00 - 7:00.",
|
||||||
|
"Contact Us": "اتصل بنا",
|
||||||
|
'Choose a contact option': 'اختر خيار الاتصال',
|
||||||
|
'Work time is from 12:00 - 19:00.\nYou can send a WhatsApp message or email.':
|
||||||
|
'ساعات العمل من 12:00 - 19:00.\nيمكنك إرسال رسالة عبر واتساب أو بريد إلكتروني.',
|
||||||
|
'Promo code copied to clipboard!': "'تم نسخ رمز العرض إلى الحافظة!'",
|
||||||
|
'Copy Code': 'نسخ الرمز',
|
||||||
|
"Your invite code was successfully applied!":
|
||||||
|
"تم تطبيق رمز الدعوة بنجاح!",
|
||||||
|
"Payment Options": " خيارات الدفع",
|
||||||
|
"wait 1 minute to receive message":
|
||||||
|
"انتظر دقيقة واحدة لاستلام الرسالة",
|
||||||
|
'Promo Copied!': 'تم نسخ العرض!',
|
||||||
|
'You have copied the promo code.': 'لقد قمت بنسخ رمز العرض.',
|
||||||
|
'Valid Until:': 'لمدة:',
|
||||||
|
"Select Payment Amount": " اختر مبلغ الدفع",
|
||||||
|
"The promotion period has ended.": "انتهت فترة العرض.",
|
||||||
|
"Promo Code Accepted": "تم قبول كود العرض",
|
||||||
|
'Tap on the promo code to copy it!': 'اضغط على رمز العرض لنسخه!',
|
||||||
|
"Lowest Price Achieved": "تم الوصول إلى أدنى سعر",
|
||||||
|
"Cannot apply further discounts.":
|
||||||
|
"لا يمكن تطبيق المزيد من الخصومات.",
|
||||||
|
"Promo Already Used": "تم استخدام كود العرض بالفعل",
|
||||||
|
'Invitation Used': "تم استخدام الدعوة",
|
||||||
|
"You have already used this promo code.":
|
||||||
|
"لقد استخدمت هذا الكود بالفعل.",
|
||||||
|
"Insert Your Promo Code": "أدخل كود العرض الخاص بك",
|
||||||
|
"Enter promo code here": "أدخل كود العرض هنا",
|
||||||
|
"Please enter a valid promo code": "يرجى إدخال كود عرض صالح",
|
||||||
'Awfar Car': 'أوفر كار',
|
'Awfar Car': 'أوفر كار',
|
||||||
"Old and affordable, perfect for budget rides.":
|
"Old and affordable, perfect for budget rides.":
|
||||||
"سيارة ميسورة التكلفة، مثالية للرحلات الاقتصادية.",
|
"سيارة ميسورة التكلفة، مثالية للرحلات الاقتصادية.",
|
||||||
@@ -656,7 +831,7 @@ iOS [https://getapp.cc/app/6458734951]
|
|||||||
'Selected Date and Time': "التاريخ والوقت المحددان",
|
'Selected Date and Time': "التاريخ والوقت المحددان",
|
||||||
"Lets check Car license ":
|
"Lets check Car license ":
|
||||||
"دَعْنَا نَتَحَقَّق مِن رُخْصَة السَّيَّارَة ",
|
"دَعْنَا نَتَحَقَّق مِن رُخْصَة السَّيَّارَة ",
|
||||||
'Driver List': 'قائمة السائقين',
|
// 'Driver List': 'قائمة السائقين',
|
||||||
'Car': 'السيارة',
|
'Car': 'السيارة',
|
||||||
'Plate': 'لوحة السيارة',
|
'Plate': 'لوحة السيارة',
|
||||||
'N/A': 'غير متوفر',
|
'N/A': 'غير متوفر',
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:SEFER/views/widgets/my_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/controller/firebase/firbase_messge.dart';
|
import 'package:SEFER/controller/firebase/firbase_messge.dart';
|
||||||
|
|
||||||
import '../../constant/box_name.dart';
|
import '../../constant/box_name.dart';
|
||||||
import '../../constant/links.dart';
|
import '../../constant/links.dart';
|
||||||
import '../../constant/style.dart';
|
|
||||||
import '../../main.dart';
|
import '../../main.dart';
|
||||||
import '../../views/widgets/elevated_btn.dart';
|
|
||||||
import '../functions/crud.dart';
|
import '../functions/crud.dart';
|
||||||
|
|
||||||
class PassengerNotificationController extends GetxController {
|
class PassengerNotificationController extends GetxController {
|
||||||
@@ -21,22 +20,17 @@ class PassengerNotificationController extends GetxController {
|
|||||||
link: AppLink.getNotificationPassenger,
|
link: AppLink.getNotificationPassenger,
|
||||||
payload: {'passenger_id': box.read(BoxName.passengerID)});
|
payload: {'passenger_id': box.read(BoxName.passengerID)});
|
||||||
if (res == "failure") {
|
if (res == "failure") {
|
||||||
Get.defaultDialog(
|
MyDialog().getDialog('There is no notification yet'.tr, '', () {
|
||||||
title: 'There is no notification yet'.tr,
|
Get.back();
|
||||||
titleStyle: AppStyle.title,
|
Get.back();
|
||||||
middleText: '',
|
});
|
||||||
confirm: MyElevatedButton(
|
} else {
|
||||||
title: 'Back',
|
notificationData = jsonDecode(res);
|
||||||
onPressed: () {
|
isloading = false;
|
||||||
Get.back();
|
update();
|
||||||
Get.back();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
notificationData = jsonDecode(res);
|
|
||||||
// sql.insertData(notificationData['message'], TableName.captainNotification);
|
|
||||||
|
|
||||||
isloading = false;
|
// sql.insertData(notificationData['message'], TableName.captainNotification);
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateNotification(String id) async {
|
updateNotification(String id) async {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:SEFER/constant/style.dart';
|
import 'package:SEFER/constant/style.dart';
|
||||||
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
||||||
|
import 'package:SEFER/views/widgets/my_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/constant/box_name.dart';
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
import 'package:SEFER/constant/links.dart';
|
import 'package:SEFER/constant/links.dart';
|
||||||
@@ -23,17 +24,10 @@ class PassengerWalletHistoryController extends GetxController {
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
update();
|
update();
|
||||||
} else {
|
} else {
|
||||||
Get.defaultDialog(
|
MyDialog().getDialog('No wallet record found'.tr, '', () {
|
||||||
barrierDismissible: false,
|
Get.back();
|
||||||
title: 'No wallet record found'.tr,
|
Get.back();
|
||||||
titleStyle: AppStyle.title,
|
});
|
||||||
middleText: '',
|
|
||||||
confirm: MyElevatedButton(
|
|
||||||
title: 'OK'.tr,
|
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
|
||||||
Get.back();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import '../../constant/colors.dart';
|
|||||||
import '../../constant/info.dart';
|
import '../../constant/info.dart';
|
||||||
import '../../constant/links.dart';
|
import '../../constant/links.dart';
|
||||||
import '../../main.dart';
|
import '../../main.dart';
|
||||||
|
import '../../print.dart';
|
||||||
import '../functions/crud.dart';
|
import '../functions/crud.dart';
|
||||||
import '../functions/toast.dart';
|
import '../functions/toast.dart';
|
||||||
import 'paymob/paymob_wallet.dart';
|
import 'paymob/paymob_wallet.dart';
|
||||||
@@ -31,6 +32,7 @@ class PaymentController extends GetxController {
|
|||||||
bool isPromoSheetDialogue = false;
|
bool isPromoSheetDialogue = false;
|
||||||
final formKey = GlobalKey<FormState>();
|
final formKey = GlobalKey<FormState>();
|
||||||
final promo = TextEditingController();
|
final promo = TextEditingController();
|
||||||
|
final walletphoneController = TextEditingController();
|
||||||
double totalPassenger = Get.find<MapPassengerController>().totalPassenger;
|
double totalPassenger = Get.find<MapPassengerController>().totalPassenger;
|
||||||
int? selectedAmount = 0;
|
int? selectedAmount = 0;
|
||||||
List<dynamic> totalPassengerWalletDetails = [];
|
List<dynamic> totalPassengerWalletDetails = [];
|
||||||
@@ -166,7 +168,7 @@ class PaymentController extends GetxController {
|
|||||||
? '1140'
|
? '1140'
|
||||||
: '0');
|
: '0');
|
||||||
|
|
||||||
getPassengerWallet();
|
// getPassengerWallet();
|
||||||
|
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
update();
|
update();
|
||||||
@@ -696,25 +698,31 @@ class PaymentController extends GetxController {
|
|||||||
billingData: PaymobBillingDataWallet(),
|
billingData: PaymobBillingDataWallet(),
|
||||||
onPayment: (PaymobResponseWallet response) {},
|
onPayment: (PaymobResponseWallet response) {},
|
||||||
);
|
);
|
||||||
|
// Log.print('response.message!: ${response!.responseCode!}');
|
||||||
|
// if (response!.success == true && response.responseCode == '200') {
|
||||||
|
|
||||||
if (response!.success == true && response.responseCode == '200') {
|
if (response!.success == true &&
|
||||||
Get.defaultDialog(
|
response!.message.toString() == 'Approved') {
|
||||||
barrierDismissible: false,
|
// Log.print('transactionID wewer: ${response.transactionID}');
|
||||||
title: 'Payment Successful'.tr,
|
Toast.show(context, 'Payment Successful'.tr, AppColor.greenColor);
|
||||||
titleStyle: AppStyle.title,
|
method();
|
||||||
content: Text(
|
// Get.defaultDialog(
|
||||||
'The payment was approved.'.tr,
|
// barrierDismissible: false,
|
||||||
style: AppStyle.title,
|
// title: 'Payment Successful'.tr,
|
||||||
),
|
// titleStyle: AppStyle.title,
|
||||||
confirm: MyElevatedButton(
|
// content: Text(
|
||||||
title: 'OK'.tr,
|
// 'The payment was approved.'.tr,
|
||||||
kolor: AppColor.greenColor,
|
// style: AppStyle.title,
|
||||||
onPressed: () async {
|
// ),
|
||||||
Get.back();
|
// confirm: MyElevatedButton(
|
||||||
method();
|
// title: 'OK'.tr,
|
||||||
},
|
// kolor: AppColor.greenColor,
|
||||||
),
|
// onPressed: () async {
|
||||||
);
|
// Get.back();
|
||||||
|
// method();
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
} else {
|
} else {
|
||||||
Get.defaultDialog(
|
Get.defaultDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
@@ -762,26 +770,29 @@ class PaymentController extends GetxController {
|
|||||||
billingData: PaymobBillingData(),
|
billingData: PaymobBillingData(),
|
||||||
onPayment: (PaymobResponse response) {},
|
onPayment: (PaymobResponse response) {},
|
||||||
);
|
);
|
||||||
|
if (response!.responseCode == '200' && response.success == true) {
|
||||||
if (response!.responseCode == 'APPROVED') {
|
// if (response!.success == true && response.responseCode == '200') {
|
||||||
Get.defaultDialog(
|
// if (response!.responseCode == 'APPROVED') {
|
||||||
barrierDismissible: false,
|
Toast.show(context, 'Payment Successful'.tr, AppColor.greenColor);
|
||||||
title: 'Payment Successful'.tr,
|
method();
|
||||||
titleStyle: AppStyle.title,
|
// Get.defaultDialog(
|
||||||
// backgroundColor: AppColor.greenColor,
|
// barrierDismissible: false,
|
||||||
content: Text(
|
// title: 'Payment Successful'.tr,
|
||||||
'The payment was approved.'.tr,
|
// titleStyle: AppStyle.title,
|
||||||
style: AppStyle.title,
|
// // backgroundColor: AppColor.greenColor,
|
||||||
),
|
// content: Text(
|
||||||
confirm: MyElevatedButton(
|
// 'The payment was approved.'.tr,
|
||||||
kolor: AppColor.greenColor,
|
// style: AppStyle.title,
|
||||||
title: 'OK'.tr,
|
// ),
|
||||||
onPressed: () async {
|
// confirm: MyElevatedButton(
|
||||||
Get.back();
|
// kolor: AppColor.greenColor,
|
||||||
method();
|
// title: 'OK'.tr,
|
||||||
},
|
// onPressed: () async {
|
||||||
),
|
// Get.back();
|
||||||
);
|
// method();
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
} else {
|
} else {
|
||||||
Get.defaultDialog(
|
Get.defaultDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
@@ -801,6 +812,7 @@ class PaymentController extends GetxController {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Get.defaultDialog(
|
Get.defaultDialog(
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class PaymobPaymentWallet {
|
|||||||
}) async {
|
}) async {
|
||||||
final Map<String, dynamic> data = {
|
final Map<String, dynamic> data = {
|
||||||
"source": {
|
"source": {
|
||||||
"identifier": box.read(BoxName.phone).toString(),
|
"identifier": box.read(BoxName.phoneWallet).toString(),
|
||||||
"subtype": "WALLET",
|
"subtype": "WALLET",
|
||||||
},
|
},
|
||||||
"payment_token": paymentToken,
|
"payment_token": paymentToken,
|
||||||
@@ -269,7 +269,7 @@ class PaymobBillingDataWallet {
|
|||||||
"email": box.read(BoxName.email) ?? box.read(BoxName.emailDriver),
|
"email": box.read(BoxName.email) ?? box.read(BoxName.emailDriver),
|
||||||
"first_name": box.read(BoxName.name) ?? box.read(BoxName.nameDriver),
|
"first_name": box.read(BoxName.name) ?? box.read(BoxName.nameDriver),
|
||||||
"last_name": box.read(BoxName.name) ?? box.read(BoxName.nameDriver),
|
"last_name": box.read(BoxName.name) ?? box.read(BoxName.nameDriver),
|
||||||
"phone_number": box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver),
|
"phone_number": box.read(BoxName.phoneWallet),
|
||||||
"apartment": apartment ?? "NA",
|
"apartment": apartment ?? "NA",
|
||||||
"floor": floor ?? "NA",
|
"floor": floor ?? "NA",
|
||||||
"building": building ?? "NA",
|
"building": building ?? "NA",
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:SEFER/constant/colors.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/constant/box_name.dart';
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
@@ -48,40 +50,41 @@ class ProfileController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatField(String columnName, TextInputType type) async {
|
updatField(String columnName, TextInputType type) async {
|
||||||
Get.defaultDialog(
|
Get.dialog(
|
||||||
title: '${'Update'.tr} $columnName',
|
CupertinoAlertDialog(
|
||||||
content: Column(
|
title: Text('${'Update'.tr} $columnName'),
|
||||||
children: [
|
content: Column(
|
||||||
SizedBox(
|
children: [
|
||||||
width: Get.width * .7,
|
const SizedBox(height: 16), // Add spacing between title and input
|
||||||
child: MyTextForm(
|
CupertinoTextField(
|
||||||
controller: txtController,
|
controller: txtController,
|
||||||
label: 'type here'.tr,
|
placeholder: 'type here'.tr,
|
||||||
hint: 'type here',
|
keyboardType: type,
|
||||||
type: type)
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||||
// TextField(
|
decoration: BoxDecoration(
|
||||||
// controller: txtController,
|
border: Border.all(color: CupertinoColors.lightBackgroundGray),
|
||||||
// decoration: const InputDecoration(
|
borderRadius: BorderRadius.circular(8),
|
||||||
// border: OutlineInputBorder(), hintText: 'type here'),
|
|
||||||
// ),
|
|
||||||
|
|
||||||
),
|
),
|
||||||
MyElevatedButton(
|
),
|
||||||
title: 'Update'.tr,
|
const SizedBox(height: 20),
|
||||||
onPressed: () async {
|
CupertinoButton(
|
||||||
Get.back();
|
color: AppColor.blueColor,
|
||||||
await updateColumn({
|
onPressed: () async {
|
||||||
'id': box.read(BoxName.passengerID),
|
Get.back();
|
||||||
columnName: txtController.text,
|
await updateColumn({
|
||||||
});
|
'id': box.read(BoxName.passengerID),
|
||||||
if (columnName == 'first_name') {
|
columnName: txtController.text,
|
||||||
box.write(BoxName.name, txtController.text);
|
});
|
||||||
}
|
if (columnName == 'first_name') {
|
||||||
|
box.write(BoxName.name, txtController.text);
|
||||||
|
}
|
||||||
|
|
||||||
txtController.clear();
|
txtController.clear();
|
||||||
},
|
},
|
||||||
)
|
child: Text('Update'.tr),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,24 +70,39 @@ class RateController extends GetxController {
|
|||||||
'token': token1,
|
'token': token1,
|
||||||
});
|
});
|
||||||
if (res != 'failure') {
|
if (res != 'failure') {
|
||||||
FirebaseMessagesController().sendNotificationToAnyWithoutData(
|
FirebaseMessagesController().sendNotificationToDriverMAP(
|
||||||
'You Have Tips'.tr,
|
'You Have Tips'.tr,
|
||||||
'${'${tip.toString()}\$${' tips\nTotal is'.tr}'} ${tip + (Get.find<MapPassengerController>().totalPassenger)}',
|
'${'${tip.toString()}\$${' tips\nTotal is'.tr}'} ${tip + (Get.find<MapPassengerController>().totalPassenger)}',
|
||||||
Get.find<MapPassengerController>().driverToken.toString(),
|
Get.find<MapPassengerController>().driverToken.toString(),
|
||||||
|
[],
|
||||||
'ding.wav',
|
'ding.wav',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await CRUD().post(link: AppLink.addRateToDriver, payload: {
|
await CRUD().post(
|
||||||
'passenger_id': box.read(BoxName.passengerID).toString(),
|
link: "${AppLink.seferCairoServer}/ride/rate/addRateToDriver.php",
|
||||||
'driver_id': driverId,
|
payload: {
|
||||||
'ride_id': rideId,
|
'passenger_id': box.read(BoxName.passengerID).toString(),
|
||||||
'rating': selectedRateItemId.toString(),
|
'driver_id': driverId.toString(),
|
||||||
'comment': comment.text,
|
'ride_id': rideId.toString(),
|
||||||
}).then((value) {
|
'rating': selectedRateItemId.toString(),
|
||||||
Get.find<MapPassengerController>().restCounter();
|
'comment': comment.text,
|
||||||
Get.offAll(const MapPagePassenger());
|
});
|
||||||
});
|
|
||||||
|
if (AppLink.endPoint != AppLink.seferCairoServer) {
|
||||||
|
CRUD().post(
|
||||||
|
link: "${AppLink.endPoint}/ride/rate/addRateToDriver.php",
|
||||||
|
payload: {
|
||||||
|
'passenger_id': box.read(BoxName.passengerID).toString(),
|
||||||
|
'driver_id': driverId.toString(),
|
||||||
|
'ride_id': rideId.toString(),
|
||||||
|
'rating': selectedRateItemId.toString(),
|
||||||
|
'comment': comment.text,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Get.find<MapPassengerController>().restCounter();
|
||||||
|
Get.offAll(const MapPagePassenger());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:SEFER/controller/payment/paymob/paymob_response.dart';
|
import 'package:SEFER/controller/payment/paymob/paymob_response.dart';
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
@@ -12,6 +13,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||||
import 'constant/api_key.dart';
|
import 'constant/api_key.dart';
|
||||||
import 'constant/info.dart';
|
import 'constant/info.dart';
|
||||||
|
import 'constant/notification.dart';
|
||||||
import 'controller/firebase/firbase_messge.dart';
|
import 'controller/firebase/firbase_messge.dart';
|
||||||
import 'controller/firebase/local_notification.dart';
|
import 'controller/firebase/local_notification.dart';
|
||||||
import 'controller/local/local_controller.dart';
|
import 'controller/local/local_controller.dart';
|
||||||
@@ -40,10 +42,12 @@ void main() async {
|
|||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
WakelockPlus.enable();
|
WakelockPlus.enable();
|
||||||
// await LocationController().startLocationUpdates();
|
// await LocationController().startLocationUpdates();
|
||||||
if (Platform.isAndroid) {
|
// if (Platform.isAndroid) {
|
||||||
await NotificationController().initNotifications();
|
NotificationController notificationController =
|
||||||
}
|
Get.put(NotificationController());
|
||||||
|
|
||||||
|
// await NotificationController().initNotifications();
|
||||||
|
// }
|
||||||
await GetStorage.init();
|
await GetStorage.init();
|
||||||
// Get.put(DriverCallController());
|
// Get.put(DriverCallController());
|
||||||
// await AC().gAK();
|
// await AC().gAK();
|
||||||
@@ -77,20 +81,25 @@ void main() async {
|
|||||||
userTokenExpiration: 200,
|
userTokenExpiration: 200,
|
||||||
iFrameID: 837992,
|
iFrameID: 837992,
|
||||||
);
|
);
|
||||||
|
|
||||||
PaymobPaymentWallet.instance.initialize(
|
PaymobPaymentWallet.instance.initialize(
|
||||||
apiKey: AK
|
apiKey: AK.payMobApikey,
|
||||||
.payMobApikey, // from dashboard Select Settings -> Account Info -> API Key
|
|
||||||
integrationID: int.parse(AK.integrationIdPayMobWallet),
|
integrationID: int.parse(AK.integrationIdPayMobWallet),
|
||||||
userTokenExpiration: 200,
|
userTokenExpiration: 200,
|
||||||
iFrameID: 837992,
|
iFrameID: 837992,
|
||||||
);
|
);
|
||||||
// Get device information
|
await notificationController.initNotifications();
|
||||||
// List<Map<String, dynamic>> deviceDataList =
|
|
||||||
// await DeviceInfoPlus.getDeviceInfo();
|
|
||||||
//
|
|
||||||
// // Print all device data
|
|
||||||
// DeviceInfoPlus.printDeviceInfo();
|
|
||||||
|
|
||||||
|
// Generate a random index to pick a message
|
||||||
|
final random = Random();
|
||||||
|
final randomMessage = messages[random.nextInt(messages.length)];
|
||||||
|
|
||||||
|
// Schedule the notification with the random message
|
||||||
|
notificationController.scheduleNotificationsForSevenDays(
|
||||||
|
randomMessage.split(':')[0],
|
||||||
|
randomMessage.split(':')[1],
|
||||||
|
"tone1",
|
||||||
|
);
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,20 +113,20 @@ class MyApp extends StatelessWidget {
|
|||||||
LocaleController localController = Get.put(LocaleController());
|
LocaleController localController = Get.put(LocaleController());
|
||||||
|
|
||||||
return GetMaterialApp(
|
return GetMaterialApp(
|
||||||
title: AppInformation.appName,
|
title: AppInformation.appName,
|
||||||
translations: MyTranslation(),
|
translations: MyTranslation(),
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
locale: localController.language,
|
locale: localController.language,
|
||||||
theme: localController.appTheme,
|
theme: localController.appTheme,
|
||||||
key: UniqueKey(),
|
key: UniqueKey(),
|
||||||
// routes: {'/':const HomePage()},
|
// routes: {'/':const HomePage()},
|
||||||
home: SplashScreen()
|
// home: LoginCaptin());
|
||||||
// initialRoute: '/',
|
initialRoute: '/',
|
||||||
// getPages: [
|
getPages: [
|
||||||
// GetPage(name: '/', page: () => SplashScreen()),
|
GetPage(name: '/', page: () => SplashScreen()),
|
||||||
// GetPage(name: '/tripmonitor', page: () => const TripMonitor()),
|
GetPage(name: '/tripmonitor', page: () => const TripMonitor()),
|
||||||
// ],
|
],
|
||||||
// home: SplashScreen()
|
// home: SplashScreen()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,18 +37,21 @@ class DbSql {
|
|||||||
latitude REAL,
|
latitude REAL,
|
||||||
longitude REAL,
|
longitude REAL,
|
||||||
name TEXT UNIQUE,
|
name TEXT UNIQUE,
|
||||||
rate TEXT
|
rate TEXT,
|
||||||
|
createdAt TEXT
|
||||||
)
|
)
|
||||||
''');
|
''');
|
||||||
|
await db.execute('DROP TABLE IF EXISTS ${TableName.recentLocations}');
|
||||||
await db.execute('''
|
await db.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS ${TableName.recentLocations}(
|
CREATE TABLE ${TableName.recentLocations}(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
latitude REAL,
|
latitude REAL,
|
||||||
longitude REAL,
|
longitude REAL,
|
||||||
name TEXT ,
|
name TEXT,
|
||||||
rate TEXT
|
rate TEXT,
|
||||||
)
|
createdAt TEXT
|
||||||
''');
|
)
|
||||||
|
''');
|
||||||
await db.execute('''
|
await db.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS ${TableName.driverOrdersRefuse}(
|
CREATE TABLE IF NOT EXISTS ${TableName.driverOrdersRefuse}(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -97,6 +100,34 @@ class DbSql {
|
|||||||
return await db.insert(table, map);
|
return await db.insert(table, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<int> insertMapLocation(Map<String, dynamic> map, String table) async {
|
||||||
|
Database db = await instance.database;
|
||||||
|
|
||||||
|
// Check if the record already exists (based on latitude, longitude, and name)
|
||||||
|
var existing = await db.query(
|
||||||
|
table,
|
||||||
|
where: 'latitude = ? AND longitude = ? AND name = ?',
|
||||||
|
whereArgs: [map['latitude'], map['longitude'], map['name']],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existing.isNotEmpty) {
|
||||||
|
// If record exists, update the createdAt field with the current timestamp
|
||||||
|
var updatedMap = Map<String, dynamic>.from(map);
|
||||||
|
updatedMap['createdAt'] =
|
||||||
|
DateTime.now().toIso8601String(); // Update timestamp
|
||||||
|
return await db.update(
|
||||||
|
table,
|
||||||
|
updatedMap,
|
||||||
|
where: 'id = ?',
|
||||||
|
whereArgs: [existing.first['id']], // Update the existing row
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// If record doesn't exist, insert new record with the current timestamp
|
||||||
|
map['createdAt'] = DateTime.now().toIso8601String();
|
||||||
|
return await db.insert(table, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> updateData(Map<String, dynamic> map, String table, int id) async {
|
Future<int> updateData(Map<String, dynamic> map, String table, int id) async {
|
||||||
Database db = await instance.database;
|
Database db = await instance.database;
|
||||||
|
|
||||||
|
|||||||
276
lib/models/model/painter_copoun.dart
Normal file
276
lib/models/model/painter_copoun.dart
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
|
import 'package:SEFER/main.dart';
|
||||||
|
import 'package:SEFER/splash_screen_page.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class CouponPainter extends CustomPainter {
|
||||||
|
final Color primaryColor;
|
||||||
|
final Color secondaryColor;
|
||||||
|
|
||||||
|
CouponPainter({
|
||||||
|
required this.primaryColor,
|
||||||
|
required this.secondaryColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
final Paint primaryPaint = Paint()
|
||||||
|
..color = primaryColor
|
||||||
|
..style = PaintingStyle.fill; //
|
||||||
|
|
||||||
|
final Paint secondaryPaint = Paint()
|
||||||
|
..color = secondaryColor
|
||||||
|
..style = PaintingStyle.fill;
|
||||||
|
|
||||||
|
final Path path = Path();
|
||||||
|
|
||||||
|
// Draw the main ticket shape
|
||||||
|
path.moveTo(0, size.height * 0.1);
|
||||||
|
path.lineTo(size.width * 0.93, size.height * 0.1);
|
||||||
|
path.arcToPoint(
|
||||||
|
Offset(size.width, size.height * 0.2),
|
||||||
|
radius: const Radius.circular(20),
|
||||||
|
clockwise: false,
|
||||||
|
);
|
||||||
|
path.lineTo(size.width, size.height * 0.8);
|
||||||
|
path.arcToPoint(
|
||||||
|
Offset(size.width * 0.93, size.height * 0.9),
|
||||||
|
radius: const Radius.circular(20),
|
||||||
|
clockwise: false,
|
||||||
|
);
|
||||||
|
path.lineTo(0, size.height * 0.9);
|
||||||
|
path.close();
|
||||||
|
|
||||||
|
canvas.drawPath(path, primaryPaint);
|
||||||
|
|
||||||
|
// Draw decorative circles on the left side
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
canvas.drawCircle(
|
||||||
|
Offset(0, size.height * (0.2 + i * 0.15)),
|
||||||
|
10,
|
||||||
|
secondaryPaint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a wavy pattern on the right side
|
||||||
|
final wavePaint = Paint()
|
||||||
|
..color = secondaryColor.withOpacity(0.3)
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(size.width * 0.8, i * 10.0),
|
||||||
|
Offset(
|
||||||
|
size.width,
|
||||||
|
i * 10.0 + math.sin(i * 0.5) * 10,
|
||||||
|
),
|
||||||
|
wavePaint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PromoBanner extends StatelessWidget {
|
||||||
|
final String promoCode;
|
||||||
|
final String discountPercentage;
|
||||||
|
final String validity;
|
||||||
|
|
||||||
|
const PromoBanner({
|
||||||
|
Key? key,
|
||||||
|
required this.promoCode,
|
||||||
|
required this.discountPercentage,
|
||||||
|
required this.validity,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CustomPaint(
|
||||||
|
painter: CouponPainter(
|
||||||
|
primaryColor: Colors.blue[800]!,
|
||||||
|
secondaryColor: Colors.white,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: 320,
|
||||||
|
height: 240,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Enter the promo code and get'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${'DISCOUNT'.tr} $discountPercentage ${'for'.tr} $validity'
|
||||||
|
.toUpperCase(),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 4,
|
||||||
|
offset: const Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
|
child: Text(
|
||||||
|
promoCode,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.blue[800],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
// Copy promo code to clipboard
|
||||||
|
Clipboard.setData(ClipboardData(text: promoCode));
|
||||||
|
// Show a Snackbar or other feedback to the user
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('Promo code copied to clipboard!'.tr)),
|
||||||
|
);
|
||||||
|
box.write(BoxName.isGiftToken, '1');
|
||||||
|
box.write(BoxName.isFirstTime, '1');
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
foregroundColor: Colors.blue[800], // Customize the color
|
||||||
|
backgroundColor: Colors.white, // Customize the background color
|
||||||
|
),
|
||||||
|
child: Text('Copy Code'.tr),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// import 'package:SEFER/constant/colors.dart';
|
||||||
|
// import 'package:flutter/cupertino.dart';
|
||||||
|
// import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// class CouponPainter extends CustomPainter {
|
||||||
|
// @override
|
||||||
|
// void paint(Canvas canvas, Size size) {
|
||||||
|
// final Paint paint = Paint()
|
||||||
|
// ..color = AppColor.blueColor
|
||||||
|
// ..style = PaintingStyle.fill;
|
||||||
|
|
||||||
|
// final Path path = Path();
|
||||||
|
|
||||||
|
// // Draw the ticket shape (like the image)
|
||||||
|
// path.moveTo(0, 0);
|
||||||
|
// path.lineTo(size.width * 0.7, 0); // top left to top right edge
|
||||||
|
|
||||||
|
// // Draw curve for the cut on the right side (ticket look)
|
||||||
|
// path.arcToPoint(Offset(size.width, size.height * 0.15),
|
||||||
|
// radius: const Radius.circular(15), clockwise: false);
|
||||||
|
// path.lineTo(size.width, size.height * 0.85);
|
||||||
|
// path.arcToPoint(Offset(size.width * 0.7, size.height),
|
||||||
|
// radius: const Radius.circular(15), clockwise: false);
|
||||||
|
// path.lineTo(0, size.height);
|
||||||
|
|
||||||
|
// canvas.drawPath(path, paint);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// bool shouldRepaint(CustomPainter oldDelegate) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class PromoBanner extends StatelessWidget {
|
||||||
|
// final String promoCode;
|
||||||
|
// final String discountPercentage;
|
||||||
|
// final String validity;
|
||||||
|
|
||||||
|
// const PromoBanner({
|
||||||
|
// required this.promoCode,
|
||||||
|
// required this.discountPercentage,
|
||||||
|
// required this.validity,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return CustomPaint(
|
||||||
|
// painter: CouponPainter(),
|
||||||
|
// child: Container(
|
||||||
|
// width: 300, // Fixed width for the promo banner
|
||||||
|
// height: 180, // Set the desired height for your banner
|
||||||
|
// padding: const EdgeInsets.all(16),
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// 'Enter the promo code and get'.toUpperCase(),
|
||||||
|
// style: const TextStyle(
|
||||||
|
// fontSize: 16,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// color: Colors.white,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// '$discountPercentage OFF for $validity'.toUpperCase(),
|
||||||
|
// style: const TextStyle(
|
||||||
|
// fontSize: 18,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// color: Colors.white,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// const SizedBox(height: 10),
|
||||||
|
// Container(
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: Colors.white,
|
||||||
|
// borderRadius: BorderRadius.circular(10),
|
||||||
|
// ),
|
||||||
|
// padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
|
// child: Text(
|
||||||
|
// promoCode,
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 20,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// color: Colors.blue[800],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@@ -40,7 +40,7 @@ class RateDriverFromPassenger extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'${'Total price to '.tr}${Get.find<MapPassengerController>().firstName}',
|
'${'Total price to '.tr}${Get.find<MapPassengerController>().driverName}',
|
||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ import 'package:SEFER/constant/style.dart';
|
|||||||
import 'package:SEFER/main.dart';
|
import 'package:SEFER/main.dart';
|
||||||
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
||||||
import 'package:SEFER/views/widgets/my_scafold.dart';
|
import 'package:SEFER/views/widgets/my_scafold.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
import '../../constant/info.dart';
|
import '../../constant/info.dart';
|
||||||
import '../../controller/auth/apple_signin_controller.dart';
|
import '../../controller/auth/apple_signin_controller.dart';
|
||||||
import '../../controller/auth/google_sign.dart';
|
import '../../controller/auth/google_sign.dart';
|
||||||
import '../../controller/auth/login_controller.dart';
|
import '../../controller/auth/login_controller.dart';
|
||||||
|
import '../home/HomePage/contact_us.dart';
|
||||||
import '../home/profile/passenger_profile_page.dart';
|
import '../home/profile/passenger_profile_page.dart';
|
||||||
import '../widgets/mycircular.dart';
|
import '../widgets/mycircular.dart';
|
||||||
|
|
||||||
@@ -218,7 +220,7 @@ class LoginPage extends StatelessWidget {
|
|||||||
// ),
|
// ),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await GoogleSignInHelper.signInFromLogin();
|
await GoogleSignInHelper().signInFromLogin();
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@@ -303,6 +305,14 @@ class LoginPage extends StatelessWidget {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: Get.height * .1,
|
height: Get.height * .1,
|
||||||
),
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => Get.to(() => ContactUsPage()),
|
||||||
|
child: Text(
|
||||||
|
'If you need assistance, contact us'
|
||||||
|
.tr, // Improved wording
|
||||||
|
style: AppStyle.subtitle,
|
||||||
|
),
|
||||||
|
),
|
||||||
// Text(
|
// Text(
|
||||||
// 'if you dont have account'.tr,
|
// 'if you dont have account'.tr,
|
||||||
// style: AppStyle.subtitle,
|
// style: AppStyle.subtitle,
|
||||||
@@ -447,6 +457,16 @@ class LoginPage extends StatelessWidget {
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
),
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
// Optionally, navigate to app settings for manual permission control
|
||||||
|
openAppSettings();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
"Open Settings".tr,
|
||||||
|
style: const TextStyle(color: AppColor.blueColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
MyElevatedButton(
|
MyElevatedButton(
|
||||||
title: 'Next'.tr,
|
title: 'Next'.tr,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import 'package:SEFER/constant/style.dart';
|
import 'package:SEFER/constant/style.dart';
|
||||||
import 'package:SEFER/controller/auth/register_controller.dart';
|
import 'package:SEFER/controller/auth/register_controller.dart';
|
||||||
import 'package:SEFER/views/widgets/elevated_btn.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_scafold.dart';
|
||||||
import 'package:SEFER/views/widgets/my_textField.dart';
|
import 'package:SEFER/views/widgets/my_textField.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../controller/local/phone_intel/intl_phone_field.dart';
|
||||||
|
import '../../print.dart';
|
||||||
|
import '../widgets/mycircular.dart';
|
||||||
|
// import 'package:intl_phone_field/intl_phone_field.dart';
|
||||||
|
|
||||||
class SmsSignupEgypt extends StatelessWidget {
|
class SmsSignupEgypt extends StatelessWidget {
|
||||||
SmsSignupEgypt({super.key});
|
SmsSignupEgypt({super.key});
|
||||||
|
|
||||||
@@ -13,7 +19,7 @@ class SmsSignupEgypt extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Get.put(RegisterController());
|
Get.put(RegisterController());
|
||||||
return MyScafolld(
|
return MyScafolld(
|
||||||
title: 'Phone Check'.tr,
|
title: "Phone Number Check".tr,
|
||||||
body: [
|
body: [
|
||||||
GetBuilder<RegisterController>(builder: (registerController) {
|
GetBuilder<RegisterController>(builder: (registerController) {
|
||||||
return ListView(
|
return ListView(
|
||||||
@@ -37,62 +43,43 @@ class SmsSignupEgypt extends StatelessWidget {
|
|||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Enter phone number text
|
|
||||||
Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
|
||||||
child: Text(
|
|
||||||
'Enter your phone number'.tr,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Phone number input field with country code dropdown
|
// Phone number input field with country code dropdown
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: !registerController.isSent
|
child: IntlPhoneField(
|
||||||
? Form(
|
decoration: InputDecoration(
|
||||||
key: registerController.formKey3,
|
labelText: 'Phone Number'.tr,
|
||||||
child: Row(
|
border: const OutlineInputBorder(
|
||||||
children: [
|
borderSide: BorderSide(),
|
||||||
// Country Code Dropdown
|
),
|
||||||
DropdownButton<String>(
|
),
|
||||||
value: registerController.selectedCountryCode,
|
initialCountryCode: 'EG',
|
||||||
items: registerController.countryCodes
|
onChanged: (phone) {
|
||||||
.map((String code) {
|
// Properly concatenate country code and number
|
||||||
return DropdownMenuItem<String>(
|
registerController.phoneController.text =
|
||||||
value: code,
|
phone.completeNumber.toString();
|
||||||
child: Text(code),
|
Log.print(' phone.number: ${phone.number}');
|
||||||
);
|
print(
|
||||||
}).toList(),
|
"Formatted phone number: ${registerController.phoneController.text}");
|
||||||
onChanged: (String? newValue) {
|
},
|
||||||
registerController.updateCountryCode(newValue!);
|
validator: (phone) {
|
||||||
},
|
// Check if the phone number is not null and is valid
|
||||||
),
|
if (phone == null || phone.completeNumber.isEmpty) {
|
||||||
// Spacer
|
return 'Please enter your phone number';
|
||||||
const SizedBox(width: 10),
|
}
|
||||||
// Phone Number Input Field
|
|
||||||
Expanded(
|
// Extract the phone number (excluding the country code)
|
||||||
child: MyTextForm(
|
final number = phone.completeNumber.toString();
|
||||||
controller:
|
|
||||||
registerController.phoneController,
|
// Check if the number length is exactly 11 digits
|
||||||
label: 'Enter your phone number'.tr,
|
if (number.length != 13) {
|
||||||
hint: 'Enter your phone number'.tr,
|
return 'Phone number must be exactly 11 digits long';
|
||||||
type: TextInputType.phone),
|
}
|
||||||
),
|
|
||||||
],
|
// If all validations pass, return null
|
||||||
),
|
return null;
|
||||||
)
|
},
|
||||||
: Container(
|
),
|
||||||
decoration: AppStyle.boxDecoration1,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
|
||||||
registerController.phoneController.text,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
@@ -110,14 +97,19 @@ class SmsSignupEgypt extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Submit button
|
// Submit button
|
||||||
MyElevatedButton(
|
registerController.isLoading
|
||||||
onPressed: () async {
|
? const MyCircularProgressIndicator()
|
||||||
!registerController.isSent
|
: Padding(
|
||||||
? await registerController.sendOtpMessage()
|
padding: const EdgeInsets.all(16.0),
|
||||||
: await registerController.verifySMSCode();
|
child: MyElevatedButton(
|
||||||
},
|
onPressed: () async {
|
||||||
title: 'Submit'.tr,
|
!registerController.isSent
|
||||||
),
|
? await registerController.sendOtpMessage()
|
||||||
|
: await registerController.verifySMSCode();
|
||||||
|
},
|
||||||
|
title: 'Submit'.tr,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,101 +1,153 @@
|
|||||||
import 'package:SEFER/constant/box_name.dart';
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
import 'package:SEFER/constant/style.dart';
|
|
||||||
import 'package:SEFER/main.dart';
|
import 'package:SEFER/main.dart';
|
||||||
import 'package:SEFER/views/widgets/my_scafold.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
class AboutPage extends StatelessWidget {
|
class AboutPage extends StatelessWidget {
|
||||||
const AboutPage({super.key});
|
const AboutPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MyScafolld(
|
return CupertinoPageScaffold(
|
||||||
title: 'About Us'.tr,
|
navigationBar: CupertinoNavigationBar(
|
||||||
body: [
|
middle: Text('About Us'.tr),
|
||||||
// Company Logo (consider adding an image asset)
|
),
|
||||||
ListView(
|
child: SafeArea(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
// Company Logo
|
||||||
Center(
|
Center(
|
||||||
child: Image.asset(
|
child: Padding(
|
||||||
'assets/images/logo.png', // Replace with your logo image asset path
|
padding: const EdgeInsets.all(16.0),
|
||||||
height: 100.0,
|
child: Image.asset(
|
||||||
width: 100.0,
|
'assets/images/logo.png', // Replace with your logo image asset path
|
||||||
|
height: 100.0,
|
||||||
|
width: 100.0,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
), // Company Name and Location
|
),
|
||||||
|
|
||||||
|
// Company Name and Location
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'SEFER LLC\n${box.read(BoxName.countryCode).toString().tr}',
|
'SEFER LLC\n${box.read(BoxName.countryCode).toString().tr}',
|
||||||
style: AppStyle.headTitle2,
|
style:
|
||||||
|
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 22.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// About Us Description
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'SEFER 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:'
|
'SEFER 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:'
|
||||||
.tr,
|
.tr,
|
||||||
style: AppStyle.title,
|
style:
|
||||||
|
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 16.0,
|
||||||
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
), // Security Features List
|
|
||||||
const SizedBox(
|
|
||||||
height: 20,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
// Security Features
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.lock, color: Colors.blue),
|
const Icon(CupertinoIcons.lock_fill,
|
||||||
|
color: CupertinoColors.activeBlue),
|
||||||
const SizedBox(width: 8.0),
|
const SizedBox(width: 8.0),
|
||||||
Text(
|
Expanded(
|
||||||
'Most Secure Methods'.tr,
|
child: Text(
|
||||||
style: AppStyle.title,
|
'Most Secure Methods'.tr,
|
||||||
|
style: CupertinoTheme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.textStyle
|
||||||
|
.copyWith(
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8.0),
|
const SizedBox(height: 8.0),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.phone, color: Colors.blue),
|
const Icon(CupertinoIcons.phone_fill,
|
||||||
|
color: CupertinoColors.activeBlue),
|
||||||
const SizedBox(width: 8.0),
|
const SizedBox(width: 8.0),
|
||||||
Text(
|
Expanded(
|
||||||
'In-App VOIP Calls'.tr,
|
child: Text(
|
||||||
style: AppStyle.title,
|
'In-App VOIP Calls'.tr,
|
||||||
|
style: CupertinoTheme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.textStyle
|
||||||
|
.copyWith(
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8.0),
|
const SizedBox(height: 8.0),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.videocam, color: Colors.blue),
|
const Icon(CupertinoIcons.videocam_fill,
|
||||||
|
color: CupertinoColors.activeBlue),
|
||||||
const SizedBox(width: 8.0),
|
const SizedBox(width: 8.0),
|
||||||
Text(
|
Expanded(
|
||||||
'Recorded Trips for Safety'.tr,
|
child: Text(
|
||||||
style: AppStyle.title,
|
'Recorded Trips for Safety'.tr,
|
||||||
|
style: CupertinoTheme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.textStyle
|
||||||
|
.copyWith(
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
), // Affordability Highlight
|
),
|
||||||
|
|
||||||
|
// Affordability Highlight
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'\nWe also prioritize affordability, offering competitive pricing to make your rides accessible.'
|
'\nWe also prioritize affordability, offering competitive pricing to make your rides accessible.'
|
||||||
.tr,
|
.tr,
|
||||||
style: AppStyle.title,
|
style:
|
||||||
|
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 20),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
// About Us Text
|
),
|
||||||
],
|
);
|
||||||
isleading: true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
102
lib/views/home/HomePage/contact_us.dart
Normal file
102
lib/views/home/HomePage/contact_us.dart
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import 'package:SEFER/constant/colors.dart';
|
||||||
|
import 'package:SEFER/constant/style.dart';
|
||||||
|
// ignore: unused_import
|
||||||
|
import 'package:SEFER/controller/functions/launch.dart';
|
||||||
|
import 'package:SEFER/views/widgets/my_scafold.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../controller/functions/tts.dart';
|
||||||
|
import '../../../controller/home/contact_us_controller.dart';
|
||||||
|
|
||||||
|
class ContactUsPage extends StatelessWidget {
|
||||||
|
ContactUsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Get.put(ContactUsController());
|
||||||
|
return GetBuilder<ContactUsController>(builder: (controller) {
|
||||||
|
return MyScafolld(
|
||||||
|
title: "Contact Us".tr,
|
||||||
|
body: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: ListView(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: AppStyle.boxDecoration1,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
child: Image.asset('assets/images/logo.gif')),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
Get.put(TextToSpeechController()).speakText(
|
||||||
|
'SEFER is the safest ride-sharing app that introduces many features for both captains and passengers. We offer the lowest commission rate of just 8%, ensuring you get the best value for your rides. Our app includes insurance for the best captains, regular maintenance of cars with top engineers, and on-road services to ensure a respectful and high-quality experience for all users.'
|
||||||
|
.tr);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.headphones),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'SEFER is the safest ride-sharing app that introduces many features for both captains and passengers. We offer the lowest commission rate of just 8%, ensuring you get the best value for your rides. Our app includes insurance for the best captains, regular maintenance of cars with top engineers, and on-road services to ensure a respectful and high-quality experience for all users.'
|
||||||
|
.tr,
|
||||||
|
style: AppStyle.title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 30,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: AppStyle.boxDecoration1,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
"You can contact us during working hours from 12:00 - 19:00."
|
||||||
|
.tr,
|
||||||
|
style: AppStyle.title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
InkWell(
|
||||||
|
onTap: () => controller.showContactDialog(context),
|
||||||
|
child: const Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.phone,
|
||||||
|
color: AppColor.blueColor,
|
||||||
|
),
|
||||||
|
Icon(
|
||||||
|
FontAwesome.whatsapp,
|
||||||
|
color: AppColor.greenColor,
|
||||||
|
),
|
||||||
|
Icon(
|
||||||
|
Icons.email,
|
||||||
|
color: AppColor.redColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 30,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
isleading: true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
572
lib/views/home/HomePage/share_app_page.dart
Normal file
572
lib/views/home/HomePage/share_app_page.dart
Normal file
@@ -0,0 +1,572 @@
|
|||||||
|
import 'package:SEFER/constant/style.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../constant/box_name.dart';
|
||||||
|
import '../../../constant/colors.dart';
|
||||||
|
import '../../../controller/home/profile/invit_controller.dart';
|
||||||
|
import '../../../main.dart';
|
||||||
|
import '../../../print.dart';
|
||||||
|
|
||||||
|
class ShareAppPage extends StatelessWidget {
|
||||||
|
final InviteController controller = Get.put(InviteController());
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: CupertinoColors.systemBackground,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: CupertinoColors.systemBackground,
|
||||||
|
elevation: 0,
|
||||||
|
title: Text(
|
||||||
|
'Invite'.tr,
|
||||||
|
style: const TextStyle(color: CupertinoColors.label),
|
||||||
|
),
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(Icons.arrow_back_ios, color: AppColor.blueColor),
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: GetBuilder<InviteController>(
|
||||||
|
builder: (controller) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: _buildPassengerTab(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPassengerTab(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: CupertinoColors.systemGrey6,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Share this code with your friends and earn rewards when they use it!"
|
||||||
|
.tr,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CupertinoColors.secondaryLabel,
|
||||||
|
fontSize: 13,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildPhoneInput(),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildActionButtonsPassengers(),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildInvitationsListPassengers(context),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Widget _buildPhoneInput() {
|
||||||
|
// return Container(
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: CupertinoColors.systemGrey6,
|
||||||
|
// borderRadius: BorderRadius.circular(8),
|
||||||
|
// ),
|
||||||
|
// child: Row(
|
||||||
|
// children: [
|
||||||
|
// Expanded(
|
||||||
|
// child: CupertinoTextField.borderless(
|
||||||
|
// controller: controller.invitePhoneController,
|
||||||
|
// placeholder: 'Enter phone'.tr,
|
||||||
|
// padding: const EdgeInsets.all(12),
|
||||||
|
// keyboardType: TextInputType.phone,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// CupertinoButton(
|
||||||
|
// child: const Icon(CupertinoIcons.person_badge_plus,
|
||||||
|
// color: AppColor.blueColor),
|
||||||
|
// onPressed: () async {
|
||||||
|
// await controller.pickContacts();
|
||||||
|
// if (controller.contacts.isNotEmpty) {
|
||||||
|
// if (box.read(BoxName.isSavedPhones) == null) {
|
||||||
|
// controller.savePhoneToServer();
|
||||||
|
// box.write(BoxName.isSavedPhones, true);
|
||||||
|
// }
|
||||||
|
// _showContactsDialog(Get.context!);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
Widget _buildPhoneInput() {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: CupertinoColors.systemGrey6,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CupertinoTextField.borderless(
|
||||||
|
controller: controller.invitePhoneController,
|
||||||
|
placeholder: 'Enter phone'.tr,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
keyboardType: TextInputType.phone,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
CupertinoButton(
|
||||||
|
child: const Icon(CupertinoIcons.person_badge_plus,
|
||||||
|
color: AppColor.blueColor),
|
||||||
|
onPressed: () async {
|
||||||
|
await controller.pickContacts();
|
||||||
|
Log.print('contacts: ${controller.contacts}');
|
||||||
|
if (controller.contacts.isNotEmpty) {
|
||||||
|
_showContactsDialog(Get
|
||||||
|
.context!); // Show contacts dialog after loading contacts
|
||||||
|
} else {
|
||||||
|
Get.snackbar(
|
||||||
|
'No contacts available'.tr,
|
||||||
|
'Please add contacts to your phone.'.tr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildActionButtonsPassengers() {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 16.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 6,
|
||||||
|
offset: const Offset(0, 3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: CupertinoButton(
|
||||||
|
color: AppColor.blueColor,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
onPressed: controller.sendInviteToPassenger,
|
||||||
|
child: Text(
|
||||||
|
'Send Invite'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: CupertinoColors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 6,
|
||||||
|
offset: const Offset(0, 3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: CupertinoButton(
|
||||||
|
color: AppColor.blueColor,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
child: Text(
|
||||||
|
'Show Invitations'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: CupertinoColors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
controller.fetchDriverStatsPassengers();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInvitationsListPassengers(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: Get.height * .4,
|
||||||
|
child: controller.driverInvitationDataToPassengers.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: Text(
|
||||||
|
"No invitation found yet!".tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CupertinoColors.secondaryLabel,
|
||||||
|
fontSize: 17,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: ListView.builder(
|
||||||
|
itemCount: controller.driverInvitationDataToPassengers.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _buildInvitationItemPassengers(context, index);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInvitationItemPassengers(BuildContext context, int index) {
|
||||||
|
// Extracting the data from the sample JSON-like structure
|
||||||
|
var invitation = controller.driverInvitationDataToPassengers[index];
|
||||||
|
|
||||||
|
int countOfInvitDriver =
|
||||||
|
int.tryParse(invitation['countOfInvitDriver']?.toString() ?? '0') ?? 0;
|
||||||
|
double progressValue = (countOfInvitDriver / 10.0).clamp(0.0, 1.0);
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
controller.onSelectPassengerInvitation(index);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: CupertinoColors.systemGrey6,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
invitation['passengerName']
|
||||||
|
.toString(), // Handle null or missing data
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: CupertinoColors.label,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
child: LinearProgressIndicator(
|
||||||
|
value: progressValue,
|
||||||
|
backgroundColor: CupertinoColors.systemGrey4,
|
||||||
|
valueColor:
|
||||||
|
const AlwaysStoppedAnimation<Color>(AppColor.blueColor),
|
||||||
|
minHeight: 6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
'$countOfInvitDriver / 2 ${'Trip'.tr}', // Show trips completed
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: CupertinoColors.secondaryLabel,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPassengerStats(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: CupertinoColors.systemGrey6,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Your Rewards".tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: CupertinoColors.label,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildStatItem(
|
||||||
|
context,
|
||||||
|
"Total Invites".tr,
|
||||||
|
controller.driverInvitationDataToPassengers[0]['countOfInvitDriver']
|
||||||
|
.toString(),
|
||||||
|
),
|
||||||
|
_buildStatItem(
|
||||||
|
context,
|
||||||
|
"Active Users".tr,
|
||||||
|
controller.driverInvitationDataToPassengers[0]['passengerName']
|
||||||
|
.toString(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildStatItem(BuildContext context, String label, String value) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CupertinoColors.label,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColor.blueColor,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showContactsDialog(BuildContext context) {
|
||||||
|
Get.defaultDialog(
|
||||||
|
title: 'Choose from contact'.tr,
|
||||||
|
content: SizedBox(
|
||||||
|
height: 400,
|
||||||
|
width: 400,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Header with cancel and title
|
||||||
|
// Container(
|
||||||
|
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
// decoration: const BoxDecoration(
|
||||||
|
// borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
// color: CupertinoColors.systemGrey6,
|
||||||
|
// ),
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
// children: [
|
||||||
|
// CupertinoButton(
|
||||||
|
// padding: EdgeInsets.zero,
|
||||||
|
// child: Text(
|
||||||
|
// 'Cancel'.tr,
|
||||||
|
// style: const TextStyle(color: CupertinoColors.systemBlue),
|
||||||
|
// ),
|
||||||
|
// onPressed: () => Navigator.pop(context),
|
||||||
|
// ),
|
||||||
|
// Container(
|
||||||
|
// child: Text('Choose from contact'.tr,
|
||||||
|
// style: AppStyle.title)),
|
||||||
|
// const SizedBox(width: 60), // Balance for Cancel button
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
|
||||||
|
// Contact list
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: controller.contactMaps.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final contact = controller.contactMaps[index];
|
||||||
|
return CupertinoButton(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
onPressed: () {
|
||||||
|
controller.selectPhone(contact['phones'].toString());
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16, vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: CupertinoColors.systemBackground,
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: CupertinoColors.separator.withOpacity(0.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// Display contact name and phone number
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
contact['name'],
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CupertinoColors.label,
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
controller.formatPhoneNumber(
|
||||||
|
contact['phones'][0].toString()),
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CupertinoColors.secondaryLabel,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Chevron icon for selection
|
||||||
|
const Icon(
|
||||||
|
CupertinoIcons.chevron_forward,
|
||||||
|
color: CupertinoColors.systemGrey2,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// showCupertinoModalPopup(
|
||||||
|
// context: context,
|
||||||
|
// builder: (BuildContext context) => Container(
|
||||||
|
// height: 400,
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: CupertinoColors.systemBackground,
|
||||||
|
// borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
// boxShadow: [
|
||||||
|
// BoxShadow(
|
||||||
|
// color: CupertinoColors.black.withOpacity(0.2),
|
||||||
|
// offset: const Offset(0, -4),
|
||||||
|
// blurRadius: 10,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// child: Column(
|
||||||
|
// children: [
|
||||||
|
// // Header with cancel and title
|
||||||
|
// Container(
|
||||||
|
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
// decoration: const BoxDecoration(
|
||||||
|
// borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
// color: CupertinoColors.systemGrey6,
|
||||||
|
// ),
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
// children: [
|
||||||
|
// CupertinoButton(
|
||||||
|
// padding: EdgeInsets.zero,
|
||||||
|
// child: Text(
|
||||||
|
// 'Cancel'.tr,
|
||||||
|
// style: const TextStyle(color: CupertinoColors.systemBlue),
|
||||||
|
// ),
|
||||||
|
// onPressed: () => Navigator.pop(context),
|
||||||
|
// ),
|
||||||
|
// Container(
|
||||||
|
// child: Text('Choose from contact'.tr,
|
||||||
|
// style: AppStyle.title)),
|
||||||
|
// const SizedBox(width: 60), // Balance for Cancel button
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
|
||||||
|
// // Contact list
|
||||||
|
// Expanded(
|
||||||
|
// child: ListView.builder(
|
||||||
|
// itemCount: controller.contactMaps.length,
|
||||||
|
// itemBuilder: (context, index) {
|
||||||
|
// final contact = controller.contactMaps[index];
|
||||||
|
// return CupertinoButton(
|
||||||
|
// padding: EdgeInsets.zero,
|
||||||
|
// onPressed: () {
|
||||||
|
// controller.selectPhone(contact['phones'].toString());
|
||||||
|
// },
|
||||||
|
// child: Container(
|
||||||
|
// padding: const EdgeInsets.symmetric(
|
||||||
|
// horizontal: 16, vertical: 12),
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: CupertinoColors.systemBackground,
|
||||||
|
// border: Border(
|
||||||
|
// bottom: BorderSide(
|
||||||
|
// color: CupertinoColors.separator.withOpacity(0.5),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// child: Row(
|
||||||
|
// children: [
|
||||||
|
// // Display contact name and phone number
|
||||||
|
// Expanded(
|
||||||
|
// child: Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// contact['name'],
|
||||||
|
// style: const TextStyle(
|
||||||
|
// color: CupertinoColors.label,
|
||||||
|
// fontSize: 17,
|
||||||
|
// fontWeight: FontWeight.w500,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// controller.formatPhoneNumber(
|
||||||
|
// contact['phones'][0].toString()),
|
||||||
|
// style: const TextStyle(
|
||||||
|
// color: CupertinoColors.secondaryLabel,
|
||||||
|
// fontSize: 15,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// // Chevron icon for selection
|
||||||
|
// const Icon(
|
||||||
|
// CupertinoIcons.chevron_forward,
|
||||||
|
// color: CupertinoColors.systemGrey2,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
import 'package:SEFER/views/widgets/my_scafold.dart';
|
import 'package:SEFER/views/widgets/my_scafold.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:share/share.dart';
|
import 'package:share/share.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
import '../../../constant/colors.dart';
|
|
||||||
import '../../../constant/style.dart';
|
|
||||||
import '../../../controller/functions/audio_record1.dart';
|
import '../../../controller/functions/audio_record1.dart';
|
||||||
import '../../../controller/functions/tts.dart';
|
|
||||||
import '../../widgets/elevated_btn.dart';
|
|
||||||
|
|
||||||
class TripsRecordedPage extends StatelessWidget {
|
class TripsRecordedPage extends StatelessWidget {
|
||||||
const TripsRecordedPage({
|
const TripsRecordedPage({
|
||||||
@@ -21,132 +18,193 @@ class TripsRecordedPage extends StatelessWidget {
|
|||||||
title: 'Trips recorded'.tr,
|
title: 'Trips recorded'.tr,
|
||||||
body: [
|
body: [
|
||||||
GetBuilder<AudioRecorderController>(builder: (audio) {
|
GetBuilder<AudioRecorderController>(builder: (audio) {
|
||||||
return Column(
|
return SingleChildScrollView(
|
||||||
children: [
|
child: Column(
|
||||||
FutureBuilder<List<String>>(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
future: audio.getRecordedFiles(),
|
children: [
|
||||||
builder: (context, snapshot) {
|
FutureBuilder<List<String>>(
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
future: audio.getRecordedFiles(),
|
||||||
return const CircularProgressIndicator();
|
builder: (context, snapshot) {
|
||||||
} else if (snapshot.hasData) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
final recordedFiles = snapshot.data!;
|
return const Center(
|
||||||
return DropdownButton<String>(
|
child: CupertinoActivityIndicator());
|
||||||
value: audio.selectedFilePath,
|
} else if (snapshot.hasData) {
|
||||||
onChanged: (value) {
|
final recordedFiles = snapshot.data!;
|
||||||
audio.selectedFilePath = value;
|
return Padding(
|
||||||
audio.playRecordedFile(value!);
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
audio.update();
|
child: CupertinoButton(
|
||||||
},
|
padding: EdgeInsets.zero,
|
||||||
items: recordedFiles
|
|
||||||
.map((file) => DropdownMenuItem<String>(
|
|
||||||
value: file,
|
|
||||||
child: Text(path.basename(file)),
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Text('Error: ${snapshot.error}');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Slider(
|
|
||||||
value: audio.currentPosition,
|
|
||||||
max: audio.totalDuration,
|
|
||||||
inactiveColor: AppColor.accentColor,
|
|
||||||
label: audio.currentPosition.toString(),
|
|
||||||
onChanged: (value) {
|
|
||||||
audio.currentPosition = value;
|
|
||||||
audio.audioPlayer.seek(Duration(seconds: value.toInt()));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
audio.isPlaying ? Icons.pause : Icons.play_arrow),
|
|
||||||
onPressed: () {
|
|
||||||
if (audio.isPlaying) {
|
|
||||||
audio.pausePlayback();
|
|
||||||
} else {
|
|
||||||
audio.resumePlayback();
|
|
||||||
}
|
|
||||||
audio.update();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.stop),
|
|
||||||
onPressed: () {
|
|
||||||
audio.stopPlayback();
|
|
||||||
audio.update();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.delete),
|
|
||||||
onPressed: () async {
|
|
||||||
Get.defaultDialog(
|
|
||||||
title: 'Are you sure to delete recorded files'.tr,
|
|
||||||
content: Column(
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
Get.find<TextToSpeechController>().speakText(
|
|
||||||
'this will delete all files from your device'
|
|
||||||
.tr);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.headphones),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'this will delete all files from your device'
|
|
||||||
.tr,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
titleStyle: AppStyle.title,
|
|
||||||
confirm: MyElevatedButton(
|
|
||||||
title: 'Delete'.tr,
|
|
||||||
kolor: AppColor.redColor,
|
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await audio.deleteAllRecordedFiles();
|
String? selectedFile =
|
||||||
Get.back();
|
await showCupertinoModalPopup<String>(
|
||||||
Get.back();
|
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}'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// 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();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
|
||||||
Align(
|
// iOS-style playback controls
|
||||||
alignment: Alignment.bottomCenter,
|
Padding(
|
||||||
child: Container(
|
padding: const EdgeInsets.symmetric(
|
||||||
padding: const EdgeInsets.all(16.0),
|
vertical: 16.0, horizontal: 16.0),
|
||||||
color: Colors.grey[200],
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
CupertinoButton(
|
||||||
audio.selectedFilePath != null
|
padding: EdgeInsets.zero,
|
||||||
? '${'Selected file:'.tr} ${path.basename(audio.selectedFilePath!)}'
|
child: Icon(
|
||||||
: 'No file selected'.tr,
|
audio.isPlaying
|
||||||
style: AppStyle.subtitle,
|
? CupertinoIcons.pause
|
||||||
),
|
: CupertinoIcons.play_arrow,
|
||||||
if (audio.selectedFilePath != null)
|
color: CupertinoColors.activeBlue,
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.share),
|
|
||||||
onPressed: () {
|
|
||||||
Share.shareFiles([audio.selectedFilePath!]);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
// 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.shareFiles([audio.selectedFilePath!]);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
})
|
||||||
],
|
],
|
||||||
isleading: true);
|
isleading: true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,11 @@ import 'package:SEFER/controller/home/home_page_controller.dart';
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/constant/colors.dart';
|
|
||||||
import 'package:SEFER/constant/style.dart';
|
|
||||||
import 'package:SEFER/views/lang/languages.dart';
|
import 'package:SEFER/views/lang/languages.dart';
|
||||||
import 'package:SEFER/views/widgets/my_scafold.dart';
|
|
||||||
|
|
||||||
import '../../constant/box_name.dart';
|
|
||||||
import '../../controller/profile/profile_controller.dart';
|
|
||||||
import '../../main.dart';
|
|
||||||
import '../widgets/elevated_btn.dart';
|
|
||||||
import 'HomePage/about_page.dart';
|
import 'HomePage/about_page.dart';
|
||||||
import 'HomePage/frequentlyQuestionsPage.dart';
|
import 'HomePage/frequentlyQuestionsPage.dart';
|
||||||
|
import 'HomePage/share_app_page.dart';
|
||||||
import 'HomePage/trip_record_page.dart';
|
import 'HomePage/trip_record_page.dart';
|
||||||
import 'profile/passenger_profile_page.dart';
|
import 'profile/passenger_profile_page.dart';
|
||||||
|
|
||||||
@@ -22,104 +16,108 @@ class HomePage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Get.put(HomePageController());
|
Get.put(HomePageController());
|
||||||
final List<String> countryOptions = [
|
return CupertinoPageScaffold(
|
||||||
'Jordan',
|
navigationBar: CupertinoNavigationBar(
|
||||||
'USA',
|
middle: Text('Home Page'.tr),
|
||||||
'Egypt',
|
leading: CupertinoButton(
|
||||||
'Turkey',
|
padding: EdgeInsets.zero,
|
||||||
'Saudi Arabia',
|
child: const Icon(CupertinoIcons.back),
|
||||||
'Qatar',
|
onPressed: () {
|
||||||
'Bahrain',
|
Navigator.pop(context);
|
||||||
'Kuwait',
|
},
|
||||||
];
|
),
|
||||||
return MyScafolld(
|
),
|
||||||
isleading: true,
|
child: SafeArea(
|
||||||
title: 'Home Page'.tr,
|
child: ListView(
|
||||||
body: [
|
|
||||||
Column(
|
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
CupertinoListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.to(() => const Language());
|
Get.to(() => const Language());
|
||||||
},
|
},
|
||||||
title: Text(
|
leading: const Icon(CupertinoIcons.globe,
|
||||||
'Language'.tr,
|
color: CupertinoColors.activeBlue),
|
||||||
style: AppStyle.headTitle2,
|
title: Text('Language'.tr),
|
||||||
),
|
subtitle: Text('To change Language the App'.tr),
|
||||||
subtitle: Text(
|
trailing: const CupertinoListTileChevron(),
|
||||||
'To change Language the App'.tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
trailing: const Icon(
|
|
||||||
Icons.arrow_forward_ios,
|
|
||||||
size: 30,
|
|
||||||
color: AppColor.primaryColor,
|
|
||||||
),
|
|
||||||
leading: const Icon(
|
|
||||||
Icons.language_sharp,
|
|
||||||
color: AppColor.primaryColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
changeCountry(countryOptions),
|
CupertinoListTile(
|
||||||
ListTile(
|
onTap: () {
|
||||||
leading: const Icon(Icons.question_answer),
|
Get.to(CupertinoPageScaffold(
|
||||||
title: Text(
|
navigationBar: CupertinoNavigationBar(
|
||||||
'Frequently Questions'.tr,
|
middle: Text('Change Country'.tr),
|
||||||
style: AppStyle.headTitle2,
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
'You can change the Country to get all features'.tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
onTap: () => Get.to(() => const FrequentlyQuestionsPage()),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: const Icon(Icons.vibration),
|
|
||||||
title: GetBuilder<HomePageController>(builder: (controller) {
|
|
||||||
return SwitchListTile(
|
|
||||||
title: Text(
|
|
||||||
'Vibration'.tr,
|
|
||||||
style: AppStyle.headTitle2,
|
|
||||||
),
|
),
|
||||||
value: controller.isVibrate,
|
child: SafeArea(
|
||||||
onChanged: controller.changeVibrateOption,
|
child: CountryPickerFromSetting(),
|
||||||
activeColor: AppColor.primaryColor,
|
),
|
||||||
);
|
));
|
||||||
}),
|
},
|
||||||
subtitle: Text(
|
leading: const Icon(CupertinoIcons.location,
|
||||||
"You can change the vibration feedback for all buttons".tr,
|
color: CupertinoColors.activeBlue),
|
||||||
style: AppStyle.title,
|
title: Text('Change Country'.tr),
|
||||||
),
|
subtitle:
|
||||||
onTap: () => Get.to(() => const FrequentlyQuestionsPage()),
|
Text('You can change the Country to get all features'.tr),
|
||||||
|
trailing: const CupertinoListTileChevron(),
|
||||||
),
|
),
|
||||||
ListTile(
|
CupertinoListTile(
|
||||||
leading: const Icon(Icons.record_voice_over_outlined),
|
onTap: () {
|
||||||
title: Text(
|
Get.to(() => const FrequentlyQuestionsPage());
|
||||||
'Trips recorded'.tr,
|
},
|
||||||
style: AppStyle.headTitle2,
|
leading: const Icon(CupertinoIcons.question,
|
||||||
),
|
color: CupertinoColors.activeBlue),
|
||||||
subtitle: Text(
|
title: Text('Frequently Questions'.tr),
|
||||||
'Here recorded trips audio'.tr,
|
subtitle: Text('Find answers to common questions'.tr),
|
||||||
style: AppStyle.title,
|
trailing: const CupertinoListTileChevron(),
|
||||||
),
|
),
|
||||||
onTap: () async {
|
CupertinoListTile(
|
||||||
Get.to(() => TripsRecordedPage());
|
leading: const Icon(Icons.vibration,
|
||||||
}),
|
color: CupertinoColors.activeBlue),
|
||||||
ListTile(
|
title: Text('Vibration'.tr),
|
||||||
leading: const Icon(Icons.account_balance_outlined),
|
trailing: GetBuilder<HomePageController>(
|
||||||
title: Text(
|
builder: (controller) {
|
||||||
'About Us'.tr,
|
return CupertinoSwitch(
|
||||||
style: AppStyle.headTitle2,
|
value: controller.isVibrate,
|
||||||
|
onChanged: controller.changeVibrateOption,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'You can change the Country to get all features'.tr,
|
'You can change the vibration feedback for all buttons'.tr),
|
||||||
style: AppStyle.title,
|
),
|
||||||
),
|
CupertinoListTile(
|
||||||
onTap: () => Get.to(() => const AboutPage()),
|
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 SEFER App with your friends and earn rewards for rides they take using your code'
|
||||||
|
.tr),
|
||||||
|
trailing: const CupertinoListTileChevron(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import 'map_widget.dart/payment_method.page.dart';
|
|||||||
import 'map_widget.dart/points_page_for_rider.dart';
|
import 'map_widget.dart/points_page_for_rider.dart';
|
||||||
import 'map_widget.dart/ride_from_start_app.dart';
|
import 'map_widget.dart/ride_from_start_app.dart';
|
||||||
import 'map_widget.dart/searching_captain_window.dart';
|
import 'map_widget.dart/searching_captain_window.dart';
|
||||||
|
import 'map_widget.dart/vip_begin.dart';
|
||||||
|
|
||||||
class MapPagePassenger extends StatelessWidget {
|
class MapPagePassenger extends StatelessWidget {
|
||||||
const MapPagePassenger({super.key});
|
const MapPagePassenger({super.key});
|
||||||
@@ -51,6 +52,7 @@ class MapPagePassenger extends StatelessWidget {
|
|||||||
CarDetailsTypeToChoose(),
|
CarDetailsTypeToChoose(),
|
||||||
const HeaderDestination(),
|
const HeaderDestination(),
|
||||||
const BurcMoney(),
|
const BurcMoney(),
|
||||||
|
const PromoCode(),
|
||||||
const ApplyOrderWidget(), const MapMenuWidget(),
|
const ApplyOrderWidget(), const MapMenuWidget(),
|
||||||
// hexagonClipper(),
|
// hexagonClipper(),
|
||||||
const CancelRidePageShow(),
|
const CancelRidePageShow(),
|
||||||
@@ -62,7 +64,9 @@ class MapPagePassenger extends StatelessWidget {
|
|||||||
// const TimerToPassengerFromDriver(),
|
// const TimerToPassengerFromDriver(),
|
||||||
const PassengerRideLocationWidget(),
|
const PassengerRideLocationWidget(),
|
||||||
const RideBeginPassenger(),
|
const RideBeginPassenger(),
|
||||||
|
const VipRideBeginPassenger(),
|
||||||
const RideFromStartApp(),
|
const RideFromStartApp(),
|
||||||
|
|
||||||
cancelRidePage(),
|
cancelRidePage(),
|
||||||
const MenuIconMapPageWidget(),
|
const MenuIconMapPageWidget(),
|
||||||
PointsPageForRider()
|
PointsPageForRider()
|
||||||
@@ -82,7 +86,7 @@ class CancelRidePageShow extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetBuilder<MapPassengerController>(
|
return GetBuilder<MapPassengerController>(
|
||||||
builder: (controller) =>
|
builder: (controller) =>
|
||||||
(controller.data.isNotEmpty && controller.remainingTime > 0)
|
(controller.data.isNotEmpty && controller.statusRide != 'Begin')
|
||||||
// ||
|
// ||
|
||||||
// controller.timeToPassengerFromDriverAfterApplied == 0
|
// controller.timeToPassengerFromDriverAfterApplied == 0
|
||||||
? Positioned(
|
? Positioned(
|
||||||
|
|||||||
@@ -17,6 +17,21 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
Color _parseColor(String colorHex) {
|
||||||
|
if (colorHex.isEmpty) {
|
||||||
|
return Colors.grey; // Fallback for empty color
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the string starts with '0xff' for ARGB format
|
||||||
|
String processedHex = colorHex.replaceFirst('#', '0xff').trim();
|
||||||
|
|
||||||
|
if (!processedHex.startsWith('0xff')) {
|
||||||
|
processedHex = '0xff$processedHex'; // Add '0xff' if missing
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color(int.parse(processedHex));
|
||||||
|
}
|
||||||
|
|
||||||
return GetBuilder<MapPassengerController>(builder: (controller) {
|
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||||
if (controller.statusRide == 'Apply' &&
|
if (controller.statusRide == 'Apply' &&
|
||||||
controller.isSearchingWindow == false) {
|
controller.isSearchingWindow == false) {
|
||||||
@@ -27,12 +42,13 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
right: 0,
|
right: 0,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: AppStyle.boxDecoration,
|
decoration: AppStyle.boxDecoration,
|
||||||
height: Get.height * .35,
|
height: Get.height * .36,
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (box.read(BoxName.carType) == 'Speed' ||
|
if (box.read(BoxName.carType) == 'Speed' ||
|
||||||
|
box.read(BoxName.carType) == 'Awfar Car' ||
|
||||||
box.read(BoxName.carType) == 'Delivery') {
|
box.read(BoxName.carType) == 'Delivery') {
|
||||||
Get.snackbar(
|
Get.snackbar(
|
||||||
'This price is'.tr +
|
'This price is'.tr +
|
||||||
@@ -86,7 +102,7 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
height: Get.height * .3,
|
height: Get.height * .31,
|
||||||
width: Get.width * .9,
|
width: Get.width * .9,
|
||||||
decoration: AppStyle.boxDecoration,
|
decoration: AppStyle.boxDecoration,
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -107,28 +123,43 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
// ColorFiltered(
|
||||||
box.read(BoxName.carType) == 'Comfort'
|
// colorFilter: ColorFilter.mode(
|
||||||
? 'assets/images/blob.png'
|
// _parseColor(controller.colorHex),
|
||||||
: box.read(BoxName.carType) == 'Lady'
|
// BlendMode.srcIn,
|
||||||
? 'assets/images/lady.png' // Assuming there's an image for Lady
|
// ),
|
||||||
: box.read(BoxName.carType) == 'Speed'
|
// child: Image.asset(
|
||||||
? 'assets/images/carspeed.png'
|
// box.read(BoxName.carType) == 'Comfort'
|
||||||
: box.read(BoxName.carType) ==
|
// ? 'assets/images/blob.png'
|
||||||
'Delivery'
|
// : box.read(BoxName.carType) == 'Lady'
|
||||||
? 'assets/images/moto.png'
|
// ? 'assets/images/lady.png' // Assuming there's an image for Lady
|
||||||
: box.read(BoxName.carType) ==
|
// : box.read(BoxName.carType) == 'Speed'
|
||||||
'Mashwari'
|
// ? 'assets/images/carspeed.png'
|
||||||
? 'assets/images/freeRide.png'
|
// : box.read(BoxName.carType) ==
|
||||||
: box.read(BoxName
|
// 'Scooter'
|
||||||
.carType) ==
|
// ? 'assets/images/moto.png'
|
||||||
'Rayeh Gai'
|
// : box.read(BoxName.carType) ==
|
||||||
? 'assets/images/roundtrip.png'
|
// 'Mishwar Vip'
|
||||||
: 'assets/images/carspeed.png', // Default image if none of the above
|
// ? 'assets/images/freeRide.png'
|
||||||
width: 80,
|
// : box.read(BoxName
|
||||||
),
|
// .carType) ==
|
||||||
|
// 'Awfar Car'
|
||||||
|
// ? 'assets/images/balash.png'
|
||||||
|
// : box.read(BoxName
|
||||||
|
// .carType) ==
|
||||||
|
// 'Pink Bike'
|
||||||
|
// ? 'assets/images/pinkBike.png'
|
||||||
|
// : box.read(BoxName
|
||||||
|
// .carType) ==
|
||||||
|
// 'Rayeh Gai'
|
||||||
|
// ? 'assets/images/roundtrip.png'
|
||||||
|
// : 'assets/images/carspeed.png', // Default image if none of the above
|
||||||
|
// width: 80,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
@@ -143,14 +174,31 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
// 'Black',
|
// 'Black',
|
||||||
controller.carColor,
|
controller.carColor.toString(),
|
||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
|
ColorFiltered(
|
||||||
|
colorFilter: ColorFilter.mode(
|
||||||
|
_parseColor(controller.colorHex),
|
||||||
|
BlendMode.srcIn,
|
||||||
|
),
|
||||||
|
child: Image.asset(
|
||||||
|
box.read(BoxName.carType) == 'Scooter' ||
|
||||||
|
box.read(BoxName.carType) ==
|
||||||
|
'Pink Bike'
|
||||||
|
? 'assets/images/moto.png'
|
||||||
|
: 'assets/images/car3.png',
|
||||||
|
width: 80,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
@@ -159,17 +207,57 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
radius: 30,
|
radius: 25,
|
||||||
backgroundImage: NetworkImage(
|
backgroundImage: NetworkImage(
|
||||||
// '',
|
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg',
|
||||||
// ),
|
),
|
||||||
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg'),
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
return Image.network(
|
||||||
|
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
loadingBuilder: (BuildContext context,
|
||||||
|
Widget child,
|
||||||
|
ImageChunkEvent? loadingProgress) {
|
||||||
|
if (loadingProgress == null) {
|
||||||
|
return child; // Image is loaded
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
value: loadingProgress
|
||||||
|
.expectedTotalBytes !=
|
||||||
|
null
|
||||||
|
? loadingProgress
|
||||||
|
.cumulativeBytesLoaded /
|
||||||
|
(loadingProgress
|
||||||
|
.expectedTotalBytes ??
|
||||||
|
1)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorBuilder: (BuildContext context,
|
||||||
|
Object error,
|
||||||
|
StackTrace? stackTrace) {
|
||||||
|
return const Icon(
|
||||||
|
Icons
|
||||||
|
.person, // Icon to show when image fails to load
|
||||||
|
size:
|
||||||
|
25, // Adjust the size as needed
|
||||||
|
color: AppColor
|
||||||
|
.blueColor, // Color for the error icon
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
// 'fadi ahmad',
|
// 'fadi ahmad',
|
||||||
controller.firstName,
|
controller.driverName,
|
||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
@@ -182,7 +270,7 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Get.defaultDialog(
|
Get.defaultDialog(
|
||||||
title: 'Select one message'.tr,
|
title: 'Select one message',
|
||||||
titleStyle: AppStyle.title,
|
titleStyle: AppStyle.title,
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
width: 300,
|
width: 300,
|
||||||
@@ -192,11 +280,13 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
FirebaseMessagesController()
|
FirebaseMessagesController()
|
||||||
.sendNotificationToAnyWithoutData(
|
.sendNotificationToDriverMAP(
|
||||||
'message From passenger',
|
'message From passenger',
|
||||||
'Hello, I\'m at the agreed-upon location'
|
'Hello, I\'m at the agreed-upon location'
|
||||||
.tr,
|
.tr,
|
||||||
controller.driverToken,
|
controller.driverToken
|
||||||
|
.toString(),
|
||||||
|
[],
|
||||||
'ding.wav',
|
'ding.wav',
|
||||||
);
|
);
|
||||||
Get.back();
|
Get.back();
|
||||||
@@ -222,11 +312,12 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
FirebaseMessagesController()
|
FirebaseMessagesController()
|
||||||
.sendNotificationToAnyWithoutData(
|
.sendNotificationToDriverMAP(
|
||||||
'message From passenger'.tr,
|
'message From passenger',
|
||||||
'My location is correct. You can search for me using the navigation app'
|
'My location is correct. You can search for me using the navigation app'
|
||||||
.tr,
|
.tr,
|
||||||
controller.driverToken,
|
controller.driverToken,
|
||||||
|
[],
|
||||||
'ding.wav',
|
'ding.wav',
|
||||||
);
|
);
|
||||||
Get.back();
|
Get.back();
|
||||||
@@ -252,11 +343,12 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
FirebaseMessagesController()
|
FirebaseMessagesController()
|
||||||
.sendNotificationToAnyWithoutData(
|
.sendNotificationToDriverMAP(
|
||||||
'message From passenger',
|
'message From passenger',
|
||||||
'My location is correct. You can search for me using the navigation app'
|
'My location is correct. You can search for me using the navigation app'
|
||||||
.tr,
|
.tr,
|
||||||
controller.driverToken,
|
controller.driverToken,
|
||||||
|
[],
|
||||||
'ding.wav',
|
'ding.wav',
|
||||||
);
|
);
|
||||||
Get.back();
|
Get.back();
|
||||||
@@ -281,11 +373,12 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
FirebaseMessagesController()
|
FirebaseMessagesController()
|
||||||
.sendNotificationToAnyWithoutData(
|
.sendNotificationToDriverMAP(
|
||||||
'message From passenger',
|
'message From passenger',
|
||||||
"How much longer will you be?"
|
"How much longer will you be?"
|
||||||
.tr,
|
.tr,
|
||||||
controller.driverToken,
|
controller.driverToken,
|
||||||
|
[],
|
||||||
'ding.wav',
|
'ding.wav',
|
||||||
);
|
);
|
||||||
Get.back();
|
Get.back();
|
||||||
@@ -335,13 +428,14 @@ class ApplyOrderWidget extends StatelessWidget {
|
|||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
FirebaseMessagesController()
|
FirebaseMessagesController()
|
||||||
.sendNotificationToAnyWithoutData(
|
.sendNotificationToDriverMAP(
|
||||||
'message From passenger',
|
'message From passenger',
|
||||||
controller
|
controller
|
||||||
.messageToDriver
|
.messageToDriver
|
||||||
.text,
|
.text,
|
||||||
controller
|
controller
|
||||||
.driverToken,
|
.driverToken,
|
||||||
|
[],
|
||||||
'ding.wav');
|
'ding.wav');
|
||||||
controller
|
controller
|
||||||
.messageToDriver
|
.messageToDriver
|
||||||
@@ -463,7 +557,7 @@ class TimeDriverToPassenger extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
decoration: AppStyle.boxDecoration,
|
decoration: AppStyle.boxDecoration,
|
||||||
width: Get.width * .7,
|
width: Get.width * .7,
|
||||||
height: 35,
|
height: 15,
|
||||||
// color: AppColor.yellowColor,
|
// color: AppColor.yellowColor,
|
||||||
),
|
),
|
||||||
Stack(
|
Stack(
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import 'package:get/get.dart';
|
|||||||
import 'package:SEFER/constant/colors.dart';
|
import 'package:SEFER/constant/colors.dart';
|
||||||
import 'package:SEFER/constant/style.dart';
|
import 'package:SEFER/constant/style.dart';
|
||||||
import 'package:SEFER/controller/home/map_passenger_controller.dart';
|
import 'package:SEFER/controller/home/map_passenger_controller.dart';
|
||||||
|
|
||||||
import '../../widgets/elevated_btn.dart';
|
import '../../widgets/elevated_btn.dart';
|
||||||
|
|
||||||
GetBuilder<MapPassengerController> cancelRidePage() {
|
GetBuilder<MapPassengerController> cancelRidePage() {
|
||||||
Get.put(MapPassengerController());
|
Get.put(MapPassengerController());
|
||||||
|
|
||||||
final List<String> reasons = [
|
final List<String> reasons = [
|
||||||
"I don't need a ride anymore".tr,
|
"I don't need a ride anymore".tr,
|
||||||
"I was just trying the application".tr,
|
"I was just trying the application".tr,
|
||||||
@@ -16,80 +16,74 @@ GetBuilder<MapPassengerController> cancelRidePage() {
|
|||||||
"I don't have a reason".tr,
|
"I don't have a reason".tr,
|
||||||
"Other".tr,
|
"Other".tr,
|
||||||
];
|
];
|
||||||
|
|
||||||
return GetBuilder<MapPassengerController>(
|
return GetBuilder<MapPassengerController>(
|
||||||
builder: (controller) => controller.isCancelRidePageShown
|
builder: (controller) => controller.isCancelRidePageShown
|
||||||
? Positioned(
|
? Positioned(
|
||||||
left: Get.width * .1,
|
left: 20,
|
||||||
top: Get.width * .2,
|
top: Get.height * 0.15,
|
||||||
right: Get.width * .1,
|
right: 20,
|
||||||
bottom: Get.width * .15,
|
bottom: Get.height * 0.15,
|
||||||
child: Container(
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppColor.secondaryColor,
|
color: Colors.white,
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
const BoxShadow(
|
|
||||||
color: AppColor.accentColor,
|
|
||||||
offset: Offset(2, 2),
|
|
||||||
blurRadius: 5),
|
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: AppColor.accentColor.withOpacity(.4),
|
color: Colors.black.withOpacity(0.2),
|
||||||
offset: const Offset(-2, -2),
|
offset: const Offset(0, 8),
|
||||||
blurRadius: 5)
|
blurRadius: 16,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
height: Get.height * .7,
|
|
||||||
width: Get.width * .7,
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Text(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
'Can we know why you want to cancel Ride ?'.tr,
|
||||||
child: Text(
|
style: AppStyle.title
|
||||||
'Can we know why you want to cancel Ride ?'.tr,
|
.copyWith(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
style: AppStyle.title,
|
textAlign: TextAlign.center,
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(
|
const SizedBox(height: 20),
|
||||||
height: 380,
|
Expanded(
|
||||||
width: 300,
|
child: ListView.separated(
|
||||||
child: ListView.builder(
|
|
||||||
itemCount: reasons.length,
|
itemCount: reasons.length,
|
||||||
|
separatorBuilder: (context, index) => const Divider(),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: InkWell(
|
title: Text(
|
||||||
onTap: () {
|
reasons[index],
|
||||||
controller.selectReason(
|
style: AppStyle.title.copyWith(fontSize: 16),
|
||||||
index,
|
),
|
||||||
reasons[index].toString(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
reasons[index],
|
|
||||||
style: AppStyle.title,
|
|
||||||
)),
|
|
||||||
leading: Radio(
|
leading: Radio(
|
||||||
value: index,
|
value: index,
|
||||||
groupValue: controller.selectedReason,
|
groupValue: controller.selectedReason,
|
||||||
onChanged: (int? value) {
|
onChanged: (int? value) {
|
||||||
controller.selectReason(
|
controller.selectReason(value!, reasons[index]);
|
||||||
value!,
|
|
||||||
reasons[index].toString(),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
activeColor: AppColor.primaryColor,
|
||||||
),
|
),
|
||||||
|
onTap: () {
|
||||||
|
controller.selectReason(index, reasons[index]);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
MyElevatedButton(
|
MyElevatedButton(
|
||||||
title: 'Cancel Ride'.tr,
|
title: 'Cancel Ride'.tr,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (controller.selectedReason == -1) {
|
if (controller.selectedReason == -1) {
|
||||||
Get.snackbar('You Should be select reason.'.tr, '',
|
Get.snackbar(
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
'You Should be select reason.'.tr,
|
||||||
backgroundColor: AppColor.redColor);
|
'',
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
backgroundColor: AppColor.redColor,
|
||||||
|
colorText: Colors.white,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
controller.cancelRide();
|
controller.cancelRide();
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,8 @@ class CashConfirmPageShown extends StatelessWidget {
|
|||||||
? controller.cashConfirmPageShown
|
? controller.cashConfirmPageShown
|
||||||
: 0,
|
: 0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: box.read(BoxName.carType) == 'Lady'
|
color: box.read(BoxName.carType) == 'Lady' ||
|
||||||
|
box.read(BoxName.carType) == 'Pink Bike'
|
||||||
? Colors.pink.shade100
|
? Colors.pink.shade100
|
||||||
: AppColor.secondaryColor,
|
: AppColor.secondaryColor,
|
||||||
borderRadius: BorderRadius.circular(15)),
|
borderRadius: BorderRadius.circular(15)),
|
||||||
@@ -168,7 +169,8 @@ class CashConfirmPageShown extends StatelessWidget {
|
|||||||
paymentController.update();
|
paymentController.update();
|
||||||
controller.changeCashConfirmPageShown();
|
controller.changeCashConfirmPageShown();
|
||||||
controller.isSearchingWindow = true;
|
controller.isSearchingWindow = true;
|
||||||
controller.confirmRideForFirstDriver();
|
controller
|
||||||
|
.confirmRideForAllDriverAvailable();
|
||||||
controller.update();
|
controller.update();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -179,7 +181,7 @@ class CashConfirmPageShown extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
controller.changeCashConfirmPageShown();
|
controller.changeCashConfirmPageShown();
|
||||||
controller.isSearchingWindow = true;
|
controller.isSearchingWindow = true;
|
||||||
controller.confirmRideForFirstDriver();
|
controller.confirmRideForAllDriverAvailable();
|
||||||
controller.update();
|
controller.update();
|
||||||
},
|
},
|
||||||
), // Add a fallback widget if none of the conditions are met
|
), // Add a fallback widget if none of the conditions are met
|
||||||
|
|||||||
@@ -242,109 +242,127 @@ GetBuilder<MapPassengerController> formSearchPlacesDestenation() {
|
|||||||
// )
|
// )
|
||||||
// : const SizedBox(),
|
// : const SizedBox(),
|
||||||
Container(
|
Container(
|
||||||
height: controller.placesDestination.isNotEmpty
|
height: controller.placesDestination.isNotEmpty
|
||||||
? controller.height
|
? controller.height
|
||||||
: 0,
|
: 0,
|
||||||
color: AppColor.secondaryColor,
|
color: AppColor.secondaryColor,
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: controller.placesDestination.length,
|
itemCount: controller.placesDestination.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
var res = controller.placesDestination[index];
|
var res = controller.placesDestination[index];
|
||||||
return InkWell(
|
|
||||||
onTap: () async {
|
|
||||||
controller.changeHeightPlaces();
|
|
||||||
await sql.insertData({
|
|
||||||
'latitude': res['geometry']['location']['lat'],
|
|
||||||
'longitude': res['geometry']['location']['lng'],
|
|
||||||
'name': res['name'].toString(),
|
|
||||||
'rate': res['rating'].toString(),
|
|
||||||
}, TableName.recentLocations);
|
|
||||||
|
|
||||||
controller.changeHeightPlaces();
|
// Extract fields with null safety
|
||||||
|
var title = res['title']?.toString() ?? 'Unknown Place';
|
||||||
|
var position = res['position'];
|
||||||
|
var latitude = position?['lat'];
|
||||||
|
var longitude = position?['lng'];
|
||||||
|
var address =
|
||||||
|
res['address']?['label'] ?? 'Unknown Address';
|
||||||
|
var categories = res['categories'] ?? [];
|
||||||
|
var primaryCategory = categories.isNotEmpty
|
||||||
|
? categories[0]['name']
|
||||||
|
: 'Unknown Category';
|
||||||
|
|
||||||
controller.passengerLocation = controller.newMyLocation;
|
return InkWell(
|
||||||
controller.myDestination = LatLng(
|
onTap: () async {
|
||||||
double.parse(
|
if (latitude != null && longitude != null) {
|
||||||
res['geometry']['location']['lat'].toString()),
|
sql.insertMapLocation({
|
||||||
double.parse(
|
'latitude': latitude,
|
||||||
res['geometry']['location']['lng'].toString()),
|
'longitude': longitude,
|
||||||
);
|
'name': title,
|
||||||
controller.convertHintTextDestinationNewPlaces(index);
|
'rate': 'N/A',
|
||||||
|
'createdAt': DateTime.now().toIso8601String(),
|
||||||
|
// No rating in this structure, adjust as needed
|
||||||
|
}, TableName.recentLocations);
|
||||||
|
|
||||||
controller.placesDestination = [];
|
controller.passengerLocation =
|
||||||
controller.placeDestinationController.clear();
|
controller.newMyLocation;
|
||||||
controller.changeMainBottomMenuMap();
|
controller.myDestination =
|
||||||
controller.passengerStartLocationFromMap = true;
|
LatLng(latitude, longitude);
|
||||||
controller.isPickerShown = true;
|
controller
|
||||||
},
|
.convertHintTextDestinationNewPlaces(index);
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
controller.placesDestination = [];
|
||||||
child: Column(
|
controller.placeDestinationController.clear();
|
||||||
children: [
|
controller.changeMainBottomMenuMap();
|
||||||
Row(
|
controller.passengerStartLocationFromMap = true;
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
controller.isPickerShown = true;
|
||||||
children: [
|
} else {
|
||||||
Column(
|
Toast.show(
|
||||||
children: [
|
context,
|
||||||
Image.network(
|
'Invalid location data',
|
||||||
res['icon'],
|
AppColor.redColor,
|
||||||
width: 20,
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.place,
|
||||||
|
size: 20), // Fallback icon for places
|
||||||
|
IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (latitude != null &&
|
||||||
|
longitude != null) {
|
||||||
|
await sql.insertMapLocation({
|
||||||
|
'latitude': latitude,
|
||||||
|
'longitude': longitude,
|
||||||
|
'name': title,
|
||||||
|
'rate': 'N/A',
|
||||||
|
}, TableName.placesFavorite);
|
||||||
|
Toast.show(
|
||||||
|
context,
|
||||||
|
'$title ${'Saved Successfully'.tr}',
|
||||||
|
AppColor.primaryColor,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Toast.show(
|
||||||
|
context,
|
||||||
|
'Invalid location data',
|
||||||
|
AppColor.redColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.favorite_border),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
address,
|
||||||
|
style: AppStyle.subtitle,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
primaryCategory,
|
||||||
|
style: AppStyle.subtitle,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
IconButton(
|
),
|
||||||
onPressed: () async {
|
],
|
||||||
await sql.insertData({
|
),
|
||||||
'latitude': res['geometry']
|
const Divider(thickness: 1),
|
||||||
['location']['lat'],
|
],
|
||||||
'longitude': res['geometry']
|
),
|
||||||
['location']['lng'],
|
|
||||||
'name': res['name'].toString(),
|
|
||||||
'rate': res['rating'].toString(),
|
|
||||||
}, TableName.placesFavorite);
|
|
||||||
Toast.show(
|
|
||||||
context,
|
|
||||||
'${res['name']} ${'Saved Sucssefully'.tr}',
|
|
||||||
AppColor.primaryColor);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.favorite_border),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
res['name'].toString(),
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
res['vicinity'].toString(),
|
|
||||||
style: AppStyle.subtitle,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'rate',
|
|
||||||
style: AppStyle.subtitle,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
res['rating'].toString(),
|
|
||||||
style: AppStyle.subtitle,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const Divider(
|
|
||||||
thickness: 1,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
},
|
))
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ GetBuilder<MapPassengerController> formSearchPlacesStart() {
|
|||||||
// controller.myLocation =
|
// controller.myLocation =
|
||||||
// controller.newStartPointLocation;
|
// controller.newStartPointLocation;
|
||||||
// }
|
// }
|
||||||
await sql.insertData({
|
await sql.insertMapLocation({
|
||||||
'latitude': res['geometry']['location']['lat'],
|
'latitude': res['geometry']['location']['lat'],
|
||||||
'longitude': res['geometry']['location']['lng'],
|
'longitude': res['geometry']['location']['lng'],
|
||||||
'name': res['name'].toString(),
|
'name': res['name'].toString(),
|
||||||
@@ -130,7 +130,7 @@ GetBuilder<MapPassengerController> formSearchPlacesStart() {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await sql.insertData({
|
await sql.insertMapLocation({
|
||||||
'latitude': res['geometry']
|
'latitude': res['geometry']
|
||||||
['location']['lat'],
|
['location']['lat'],
|
||||||
'longitude': res['geometry']
|
'longitude': res['geometry']
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ GetBuilder<MapPassengerController> formSearchPlaces(int index) {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await sql.insertData({
|
await sql.insertMapLocation({
|
||||||
'latitude': res['geometry']
|
'latitude': res['geometry']
|
||||||
['location']['lat'],
|
['location']['lat'],
|
||||||
'longitude': res['geometry']
|
'longitude': res['geometry']
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ class GoogleMapPassengerWidget extends StatelessWidget {
|
|||||||
// icon: controller.endIcon,
|
// icon: controller.endIcon,
|
||||||
// ),
|
// ),
|
||||||
// },
|
// },
|
||||||
|
polygons: controller.polygons,
|
||||||
polylines: {
|
polylines: {
|
||||||
Polyline(
|
Polyline(
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
@@ -419,7 +419,7 @@ class GoogleMapPassengerWidget extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
|
|
||||||
mapType:
|
mapType:
|
||||||
controller.mapType ? MapType.satellite : MapType.normal,
|
controller.mapType ? MapType.satellite : MapType.terrain,
|
||||||
myLocationButtonEnabled: true,
|
myLocationButtonEnabled: true,
|
||||||
// liteModeEnabled: true, tiltGesturesEnabled: false,
|
// liteModeEnabled: true, tiltGesturesEnabled: false,
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
import 'package:SEFER/constant/api_key.dart';
|
|
||||||
import 'package:SEFER/constant/box_name.dart';
|
|
||||||
import 'package:SEFER/main.dart';
|
|
||||||
import 'package:SEFER/views/auth/sms_verfy_page.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
import '../../../constant/char_map.dart';
|
|
||||||
import '../../../constant/colors.dart';
|
import '../../../constant/colors.dart';
|
||||||
import '../../../constant/credential.dart';
|
|
||||||
import '../../../constant/links.dart';
|
|
||||||
import '../../../controller/firebase/firbase_messge.dart';
|
|
||||||
import '../../../controller/functions/audio_record1.dart';
|
|
||||||
import '../../../controller/functions/crud.dart';
|
|
||||||
import '../../../controller/functions/tts.dart';
|
import '../../../controller/functions/tts.dart';
|
||||||
import '../../../controller/home/map_passenger_controller.dart';
|
import '../../../controller/home/map_passenger_controller.dart';
|
||||||
|
import '../../../controller/home/vip_waitting_page.dart';
|
||||||
|
|
||||||
GetBuilder<MapPassengerController> leftMainMenuIcons() {
|
GetBuilder<MapPassengerController> leftMainMenuIcons() {
|
||||||
final textToSpeechController = Get.put(TextToSpeechController());
|
Get.put(TextToSpeechController());
|
||||||
return GetBuilder<MapPassengerController>(
|
return GetBuilder<MapPassengerController>(
|
||||||
builder: (controller) => Positioned(
|
builder: (controller) => Positioned(
|
||||||
top: Get.height * .008,
|
top: Get.height * .008,
|
||||||
@@ -99,20 +91,10 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
|
|||||||
borderRadius: BorderRadius.circular(15)),
|
borderRadius: BorderRadius.circular(15)),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
FirebaseMessagesController().sendNotificationToAnyWithoutData(
|
Get.to(() => VipWaittingPage());
|
||||||
'Order'.tr,
|
|
||||||
'from: ',
|
|
||||||
// jsonDecode(value)['message'].toString(),
|
|
||||||
'fBJObfCd9kHxnzMsEzeh2R:APA91bEE435Fvg1ixHs2_GPJJzz5CztswczqAi-PJfS6gSzg5U0eHvOi_v2J3imqPeWvkic-Dhhq2Pzrva2LncvS3MofCTJyM8AVScktGUuB6NvgyeK_5er8yDPrp2-2fqUz7VOXflni',
|
|
||||||
'order.wav'
|
|
||||||
|
|
||||||
// polylineCoordinates.toString()
|
|
||||||
);
|
|
||||||
// print(box.read(BoxName.tokenFCM));
|
|
||||||
//
|
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.voice_chat,
|
Octicons.watch, // Replace this with your desired VIP icon
|
||||||
size: 29,
|
size: 29,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -126,54 +108,13 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
|
|||||||
// borderRadius: BorderRadius.circular(15)),
|
// borderRadius: BorderRadius.circular(15)),
|
||||||
// child: IconButton(
|
// child: IconButton(
|
||||||
// onPressed: () async {
|
// onPressed: () async {
|
||||||
// Get.to(SmsSignupEgypt());
|
// controller.statusRide == 'Apply' &&
|
||||||
|
// controller.isSearchingWindow == false;
|
||||||
|
// controller.update();
|
||||||
// },
|
// },
|
||||||
// icon: const Icon(
|
// icon: const Icon(
|
||||||
// Icons.chat,
|
// Octicons
|
||||||
// size: 29,
|
// .telescope, // Replace this with your desired VIP icon
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// 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 {
|
|
||||||
// await CRUD().allMethodForAI(
|
|
||||||
// 'name,fullName,address,idNumber,cardId,dob',
|
|
||||||
// AppLink.uploadEgypt,
|
|
||||||
// 'idFront');
|
|
||||||
|
|
||||||
// await ImageController().choosImage(
|
|
||||||
// 'https://api.sefer.live/sefer/uploadEgypt.php',
|
|
||||||
// 'FrontId');
|
|
||||||
// AC credentials = AC();
|
|
||||||
// String apiKey =
|
|
||||||
// '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';
|
|
||||||
// String convertedStringN = credentials.c(
|
|
||||||
// credentials.c(credentials.c(apiKey, cs), cC), cn);
|
|
||||||
|
|
||||||
// String retrievedStringS = credentials.r(
|
|
||||||
// credentials.r(credentials.r(convertedStringN, cn), cC),
|
|
||||||
// cs);
|
|
||||||
// //
|
|
||||||
// if (retrievedStringS == apiKey) {
|
|
||||||
// print('convertedStringN --- $convertedStringN');
|
|
||||||
// print('retrievedStringS ---$retrievedStringS');
|
|
||||||
// print('same');
|
|
||||||
// }
|
|
||||||
|
|
||||||
// await Get.find<PaymentController>()
|
|
||||||
// .payWithPayMob(context, '1100', 'EGP');
|
|
||||||
// Initiates a payment with a card using the FlutterPaymob instance
|
|
||||||
// },
|
|
||||||
// icon: const Icon(
|
|
||||||
// // Get.put(AudioRecorderController()).isRecording
|
|
||||||
// Icons.start,
|
|
||||||
// size: 29,
|
// size: 29,
|
||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import 'package:SEFER/views/widgets/my_dialog.dart';
|
||||||
import 'package:SEFER/views/widgets/my_textField.dart';
|
import 'package:SEFER/views/widgets/my_textField.dart';
|
||||||
|
import 'package:SEFER/views/widgets/mysnakbar.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -14,6 +16,7 @@ import '../../../constant/colors.dart';
|
|||||||
import '../../../constant/table_names.dart';
|
import '../../../constant/table_names.dart';
|
||||||
import '../../../controller/functions/toast.dart';
|
import '../../../controller/functions/toast.dart';
|
||||||
import '../../../controller/functions/tts.dart';
|
import '../../../controller/functions/tts.dart';
|
||||||
|
import '../../../print.dart';
|
||||||
import 'form_search_start.dart';
|
import 'form_search_start.dart';
|
||||||
|
|
||||||
class MainBottomMenuMap extends StatelessWidget {
|
class MainBottomMenuMap extends StatelessWidget {
|
||||||
@@ -46,24 +49,34 @@ class MainBottomMenuMap extends StatelessWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
width: Get.width * .8,
|
width: Get.width * .8,
|
||||||
height: Get.height * .1,
|
height: Get.height * .1,
|
||||||
decoration: const BoxDecoration(
|
padding: const EdgeInsets.symmetric(
|
||||||
boxShadow: [
|
horizontal: 20, vertical: 10),
|
||||||
BoxShadow(
|
decoration: BoxDecoration(
|
||||||
color: Color.fromARGB(
|
gradient: LinearGradient(
|
||||||
255, 237, 230, 230),
|
colors: [
|
||||||
blurRadius: 5,
|
AppColor.blueColor.withOpacity(0.8),
|
||||||
offset: Offset(2, 4)),
|
AppColor.blueColor.withOpacity(0.6),
|
||||||
BoxShadow(
|
],
|
||||||
color: Color.fromARGB(
|
begin: Alignment.topLeft,
|
||||||
255, 242, 237, 237),
|
end: Alignment.bottomRight,
|
||||||
blurRadius: 5,
|
|
||||||
offset: Offset(-2, -2))
|
|
||||||
],
|
|
||||||
color: AppColor.blueColor,
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.elliptical(15, 30),
|
|
||||||
),
|
),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromARGB(
|
||||||
|
255, 237, 230, 230),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(4, 8),
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromARGB(
|
||||||
|
255, 242, 237, 237),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(-4, -4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
),
|
),
|
||||||
|
|
||||||
// decoration: AppStyle.boxDecoration1,
|
// decoration: AppStyle.boxDecoration1,
|
||||||
child: DefaultTextStyle(
|
child: DefaultTextStyle(
|
||||||
style: AppStyle.title.copyWith(
|
style: AppStyle.title.copyWith(
|
||||||
@@ -338,7 +351,7 @@ class MainBottomMenuMap extends StatelessWidget {
|
|||||||
title: 'Yes'.tr,
|
title: 'Yes'.tr,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Get.back();
|
Get.back();
|
||||||
controller.getLocation();
|
await controller.getLocation();
|
||||||
await controller.getMap(
|
await controller.getMap(
|
||||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||||
'${controller.recentPlaces[index]['latitude']},${controller.recentPlaces[index]['longitude']}',
|
'${controller.recentPlaces[index]['latitude']},${controller.recentPlaces[index]['longitude']}',
|
||||||
@@ -350,6 +363,18 @@ class MainBottomMenuMap extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
MyDialog().getDialog(
|
||||||
|
"Are you sure to delete this location?".tr, '', () {
|
||||||
|
sql.deleteData(TableName.recentLocations,
|
||||||
|
controller.recentPlaces[index]['id']);
|
||||||
|
|
||||||
|
controller.getFavioratePlaces();
|
||||||
|
controller.update();
|
||||||
|
Get.back();
|
||||||
|
mySnackbarSuccess('deleted'.tr);
|
||||||
|
});
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: AppStyle.boxDecoration1,
|
decoration: AppStyle.boxDecoration1,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -606,7 +631,7 @@ class FaviouratePlacesDialog extends StatelessWidget {
|
|||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Get.back();
|
Get.back();
|
||||||
controller.getLocation();
|
await controller.getLocation();
|
||||||
await controller.getMap(
|
await controller.getMap(
|
||||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||||
'${favoritePlaces[index]['latitude']},${favoritePlaces[index]['longitude']}',
|
'${favoritePlaces[index]['latitude']},${favoritePlaces[index]['longitude']}',
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:SEFER/views/home/HomePage/contact_us.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||||
@@ -110,10 +111,10 @@ class MapMenuWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
IconMainPageMap(
|
IconMainPageMap(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.to(() => const TaarifPage());
|
Get.to(() => ContactUsPage());
|
||||||
},
|
},
|
||||||
title: 'Tariff'.tr,
|
title: "Contact Us".tr,
|
||||||
icon: Icons.money,
|
icon: Icons.contact_page,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:SEFER/main.dart';
|
|||||||
import '../../../constant/colors.dart';
|
import '../../../constant/colors.dart';
|
||||||
import '../../../constant/style.dart';
|
import '../../../constant/style.dart';
|
||||||
import '../../../controller/functions/audio_record1.dart';
|
import '../../../controller/functions/audio_record1.dart';
|
||||||
|
import '../../../controller/functions/launch.dart';
|
||||||
import '../../../controller/functions/toast.dart';
|
import '../../../controller/functions/toast.dart';
|
||||||
import '../../../controller/home/map_passenger_controller.dart';
|
import '../../../controller/home/map_passenger_controller.dart';
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ class RideBeginPassenger extends StatelessWidget {
|
|||||||
return Positioned(
|
return Positioned(
|
||||||
left: 10,
|
left: 10,
|
||||||
right: 10,
|
right: 10,
|
||||||
bottom: 4,
|
bottom: 10,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: AppStyle.boxDecoration,
|
decoration: AppStyle.boxDecoration,
|
||||||
height: controller.statusRide == 'Begin' ? Get.height * .33 : 0,
|
height: controller.statusRide == 'Begin' ? Get.height * .33 : 0,
|
||||||
@@ -52,7 +53,7 @@ class RideBeginPassenger extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
decoration: AppStyle.boxDecoration,
|
decoration: AppStyle.boxDecoration,
|
||||||
child: Text(
|
child: Text(
|
||||||
controller.firstName,
|
controller.driverName,
|
||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -248,8 +249,8 @@ class RideBeginPassenger extends StatelessWidget {
|
|||||||
profileController.prfoileData['sosPhone']);
|
profileController.prfoileData['sosPhone']);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
controller
|
makePhoneCall('122');
|
||||||
.sendSMS(box.read(BoxName.sosPhonePassenger));
|
// box.read(BoxName.sosPhonePassenger));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
|
|||||||
@@ -8,6 +8,121 @@ import 'package:SEFER/views/widgets/my_textField.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../constant/links.dart';
|
||||||
|
|
||||||
|
// class SearchingCaptainWindow extends StatelessWidget {
|
||||||
|
// const SearchingCaptainWindow({super.key});
|
||||||
|
|
||||||
|
// Widget _buildDriverAvatars(MapPassengerController controller) {
|
||||||
|
// // If no drivers yet, show loading indicator
|
||||||
|
// if (controller.isSearchingWindow) {
|
||||||
|
// // Check if dataCarsLocationByPassenger or its 'data' is null
|
||||||
|
// if (controller.dataCarsLocationByPassenger == null ||
|
||||||
|
// controller.dataCarsLocationByPassenger['data'] == null ||
|
||||||
|
// controller.dataCarsLocationByPassenger['data'].isEmpty) {
|
||||||
|
// return const SizedBox(
|
||||||
|
// height: 60,
|
||||||
|
// child: Center(
|
||||||
|
// child: CircularProgressIndicator(
|
||||||
|
// valueColor:
|
||||||
|
// AlwaysStoppedAnimation<Color>(AppColor.secondaryColor),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return SizedBox(
|
||||||
|
// height: 60,
|
||||||
|
// child: ListView.builder(
|
||||||
|
// scrollDirection: Axis.horizontal,
|
||||||
|
// itemCount: controller.dataCarsLocationByPassenger['data'].length,
|
||||||
|
// padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
// itemBuilder: (context, index) {
|
||||||
|
// final driver = controller.dataCarsLocationByPassenger['data'][index];
|
||||||
|
// return Padding(
|
||||||
|
// padding: const EdgeInsets.only(right: 8),
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: [
|
||||||
|
// CircleAvatar(
|
||||||
|
// radius: 25,
|
||||||
|
// backgroundColor: AppColor.secondaryColor,
|
||||||
|
// child: ClipOval(
|
||||||
|
// child: Image.network(
|
||||||
|
// '${AppLink.server}/portrate_captain_image/${driver['driver_id']}.jpg',
|
||||||
|
// width: 50,
|
||||||
|
// height: 50,
|
||||||
|
// fit: BoxFit.cover,
|
||||||
|
// errorBuilder: (context, error, stackTrace) {
|
||||||
|
// return const Icon(
|
||||||
|
// Icons.person,
|
||||||
|
// color: Colors.white,
|
||||||
|
// size: 30,
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return GetBuilder<MapPassengerController>(
|
||||||
|
// builder: (mapPassengerController) {
|
||||||
|
// return mapPassengerController.isSearchingWindow
|
||||||
|
// ? Positioned(
|
||||||
|
// bottom: 0,
|
||||||
|
// left: 0,
|
||||||
|
// right: 0,
|
||||||
|
// child: Container(
|
||||||
|
// decoration: AppStyle.boxDecoration1,
|
||||||
|
// height: Get.height *
|
||||||
|
// .3, // Increased height to accommodate avatars
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
// children: [
|
||||||
|
// SizedBox(
|
||||||
|
// width: Get.width * .7,
|
||||||
|
// child: const LinearProgressIndicator(
|
||||||
|
// minHeight: 6,
|
||||||
|
// backgroundColor: AppColor.yellowColor,
|
||||||
|
// color: AppColor.secondaryColor,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// mapPassengerController.driverOrderStatus == 'recive'
|
||||||
|
// ? Text(
|
||||||
|
// "Drivers received orders".tr,
|
||||||
|
// style: AppStyle.title,
|
||||||
|
// )
|
||||||
|
// : Text(
|
||||||
|
// "We are searching for the nearest driver to you"
|
||||||
|
// .tr,
|
||||||
|
// style: AppStyle.title,
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// 'please wait till driver accept your order'.tr,
|
||||||
|
// style: AppStyle.title,
|
||||||
|
// ),
|
||||||
|
// // New: Driver avatars section
|
||||||
|
// _buildDriverAvatars(mapPassengerController),
|
||||||
|
// _buildTimer(mapPassengerController),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// : const SizedBox();
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
class SearchingCaptainWindow extends StatelessWidget {
|
class SearchingCaptainWindow extends StatelessWidget {
|
||||||
const SearchingCaptainWindow({super.key});
|
const SearchingCaptainWindow({super.key});
|
||||||
|
|
||||||
@@ -22,11 +137,13 @@ class SearchingCaptainWindow extends StatelessWidget {
|
|||||||
right: 0,
|
right: 0,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: AppStyle.boxDecoration1,
|
decoration: AppStyle.boxDecoration1,
|
||||||
height: Get.height * .2,
|
height: Get.height * .25,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
// Use Stack for overlapping widgets
|
// Use Stack for overlapping widgets
|
||||||
children: [
|
children: [
|
||||||
// Text elements
|
// Text elements
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: Get.width * .7,
|
width: Get.width * .7,
|
||||||
child: const LinearProgressIndicator(
|
child: const LinearProgressIndicator(
|
||||||
@@ -36,9 +153,13 @@ class SearchingCaptainWindow extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"We are searching for the nearest driver to you".tr,
|
mapPassengerController.driversStatusForSearchWindow,
|
||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
),
|
),
|
||||||
|
// Text(
|
||||||
|
// "We are searching for the nearest driver to you".tr,
|
||||||
|
// style: AppStyle.title,
|
||||||
|
// ),
|
||||||
Text(
|
Text(
|
||||||
'please wait till driver accept your order'.tr,
|
'please wait till driver accept your order'.tr,
|
||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import 'package:SEFER/constant/colors.dart';
|
import 'package:SEFER/constant/colors.dart';
|
||||||
import 'package:SEFER/constant/style.dart';
|
import 'package:SEFER/constant/style.dart';
|
||||||
import 'package:SEFER/controller/home/map_passenger_controller.dart';
|
import 'package:SEFER/controller/home/map_passenger_controller.dart';
|
||||||
import 'package:SEFER/env/env.dart';
|
|
||||||
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
import '../../../constant/api_key.dart';
|
import '../../../constant/api_key.dart';
|
||||||
|
import '../../../constant/links.dart';
|
||||||
import '../../../print.dart';
|
import '../../../print.dart';
|
||||||
|
|
||||||
class CupertinoDriverListWidget extends StatelessWidget {
|
class CupertinoDriverListWidget extends StatelessWidget {
|
||||||
@@ -17,154 +17,214 @@ class CupertinoDriverListWidget extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
middle: Text('Driver List'.tr),
|
middle: Text('Driver List'.tr), // Ensure text is properly localized
|
||||||
),
|
),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: ListView.separated(
|
child: mapPassengerController.driversForMishwari.isEmpty
|
||||||
itemCount: mapPassengerController.driversForMishwari.length,
|
? Center(
|
||||||
separatorBuilder: (context, index) => const Divider(height: 1),
|
child: Text(
|
||||||
itemBuilder: (context, index) {
|
'No drivers available at the moment. Please try again later.'
|
||||||
var driver = mapPassengerController.driversForMishwari[index];
|
.tr,
|
||||||
return Container(
|
style: const TextStyle(
|
||||||
decoration: AppStyle.boxDecoration1,
|
fontSize: 18, // Adjust the size as needed
|
||||||
child: CupertinoListTile(
|
fontWeight: FontWeight.w600,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
color: CupertinoColors.inactiveGray, // Customize color
|
||||||
leading: CircleAvatar(
|
),
|
||||||
radius: 25,
|
textAlign: TextAlign.center, // Center-align the text
|
||||||
backgroundImage: NetworkImage(
|
|
||||||
'${Env.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg',
|
|
||||||
),
|
|
||||||
backgroundColor: CupertinoColors.systemGrey5,
|
|
||||||
),
|
|
||||||
title: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'${driver['NAME'].toString().split(' ')[0]} ${driver['NAME'].toString().split(' ')[1]}',
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
),
|
||||||
Text('${'Age'.tr}: ${driver['age'].toString()}'),
|
)
|
||||||
Row(
|
: ListView.separated(
|
||||||
children: [
|
itemCount: mapPassengerController.driversForMishwari.length,
|
||||||
const Icon(CupertinoIcons.star_fill,
|
separatorBuilder: (context, index) =>
|
||||||
size: 16, color: CupertinoColors.systemYellow),
|
const Divider(height: 1),
|
||||||
const SizedBox(width: 4),
|
itemBuilder: (context, index) {
|
||||||
Text(driver['rating']?.toStringAsFixed(1) ?? 'N/A'.tr),
|
var driver =
|
||||||
const SizedBox(width: 8),
|
mapPassengerController.driversForMishwari[index];
|
||||||
Text('${'Rides'.tr}: ${driver['countRide']}'),
|
return Container(
|
||||||
],
|
decoration: AppStyle.boxDecoration1,
|
||||||
),
|
child: CupertinoListTile(
|
||||||
],
|
padding: const EdgeInsets.symmetric(
|
||||||
),
|
vertical: 4, horizontal: 8),
|
||||||
subtitle: Column(
|
leading: CircleAvatar(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
radius: 25,
|
||||||
children: [
|
backgroundImage: NetworkImage(
|
||||||
Row(
|
'${AppLink.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg',
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
),
|
||||||
children: [
|
child: Builder(
|
||||||
Text(
|
builder: (context) {
|
||||||
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
|
return Image.network(
|
||||||
Text('${'Plate'.tr}: ${driver['car_plate']}'),
|
'${AppLink.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg',
|
||||||
],
|
fit: BoxFit.cover,
|
||||||
),
|
loadingBuilder: (BuildContext context,
|
||||||
Row(
|
Widget child,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
ImageChunkEvent? loadingProgress) {
|
||||||
children: [
|
if (loadingProgress == null) {
|
||||||
Text('${'Education'.tr}: ${driver['education']}'),
|
return child; // Image is loaded
|
||||||
],
|
} else {
|
||||||
),
|
return Center(
|
||||||
Row(
|
child: CircularProgressIndicator(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
value: loadingProgress
|
||||||
children: [
|
.expectedTotalBytes !=
|
||||||
SizedBox(
|
null
|
||||||
// width: Get.width * .3,
|
? loadingProgress
|
||||||
child: Row(
|
.cumulativeBytesLoaded /
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
(loadingProgress
|
||||||
children: [
|
.expectedTotalBytes ??
|
||||||
Text('${'Color'.tr}: ${driver['color']}'),
|
1)
|
||||||
const SizedBox(width: 8),
|
: null,
|
||||||
Container(
|
),
|
||||||
width: 20,
|
);
|
||||||
height: 20,
|
}
|
||||||
decoration: BoxDecoration(
|
},
|
||||||
color: hexToColor(
|
errorBuilder: (BuildContext context,
|
||||||
driver['color_hex'].toString()) ??
|
Object error, StackTrace? stackTrace) {
|
||||||
Colors.amber,
|
return const Icon(
|
||||||
borderRadius: BorderRadius.circular(4),
|
Icons
|
||||||
border: Border.all(),
|
.person, // Icon to show when image fails to load
|
||||||
),
|
size: 25, // Adjust the size as needed
|
||||||
),
|
color: AppColor
|
||||||
],
|
.blueColor, // Color for the error icon
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
title: Row(
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
// Handle driver selection
|
|
||||||
Get.defaultDialog(
|
|
||||||
title: '${'Selected driver'.tr}: ${driver['NAME']}',
|
|
||||||
content: Column(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
|
'${driver['NAME'].toString().split(' ')[0]} ${driver['NAME'].toString().split(' ')[1]}',
|
||||||
Text('${'Plate'.tr}: ${driver['car_plate']}'),
|
style:
|
||||||
|
const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
Text('${'Age'.tr}: ${driver['age'].toString()}'),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
Text('${'Color'.tr}: ${driver['color']}'),
|
const Icon(CupertinoIcons.star_fill,
|
||||||
|
size: 16,
|
||||||
|
color: CupertinoColors.systemYellow),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(driver['rating']?.toStringAsFixed(1) ??
|
||||||
|
'N/A'.tr),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Container(
|
Text('${'Rides'.tr}: ${driver['ride_count']}'),
|
||||||
width: 20,
|
],
|
||||||
height: 20,
|
),
|
||||||
decoration: BoxDecoration(
|
],
|
||||||
color: hexToColor(
|
),
|
||||||
driver['color_hex'].toString()) ??
|
subtitle: Column(
|
||||||
AppColor.bronze,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
borderRadius: BorderRadius.circular(4),
|
children: [
|
||||||
border: Border.all(),
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
|
||||||
|
Text('${'Plate'.tr}: ${driver['car_plate']}'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
// width: Get.width * .3,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('${'Color'.tr}: ${driver['color']}'),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Container(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: driver['color_hex']
|
||||||
|
.toString() ==
|
||||||
|
'null'
|
||||||
|
? Colors.amber
|
||||||
|
: hexToColor(driver['color_hex']
|
||||||
|
.toString()),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(4),
|
||||||
|
border: Border.all(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
onTap: () {
|
||||||
),
|
Log.print(' driver["id"]: ${driver['driver_id']}');
|
||||||
confirm: MyElevatedButton(
|
Get.find<MapPassengerController>().driverIdVip =
|
||||||
title: 'OK'.tr,
|
driver['driver_id'];
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
// Handle driver selection
|
||||||
showDateTimePickerDialog(driver);
|
Get.defaultDialog(
|
||||||
Log.print('driver: ${driver}');
|
title:
|
||||||
}));
|
'${'Selected driver'.tr}: ${driver['NAME']}',
|
||||||
print('${'Selected driver'.tr}: ${driver['NAME']}');
|
content: Column(
|
||||||
// Get.back(); // Close the dialog
|
children: [
|
||||||
},
|
Column(
|
||||||
),
|
mainAxisAlignment:
|
||||||
);
|
MainAxisAlignment.spaceBetween,
|
||||||
},
|
children: [
|
||||||
)),
|
Text(
|
||||||
|
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
|
||||||
|
Text(
|
||||||
|
'${'Plate'.tr}: ${driver['car_plate']}'),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${'Color'.tr}: ${driver['color']}'),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Container(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: driver['color_hex']
|
||||||
|
.toString() ==
|
||||||
|
'null'
|
||||||
|
? Colors.amber
|
||||||
|
: hexToColor(
|
||||||
|
driver['color_hex']
|
||||||
|
.toString()),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(4),
|
||||||
|
border: Border.all(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
confirm: MyElevatedButton(
|
||||||
|
title: 'OK'.tr,
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
showDateTimePickerDialog(driver);
|
||||||
|
}));
|
||||||
|
print('${'Selected driver'.tr}: ${driver['NAME']}');
|
||||||
|
// Get.back(); // Close the dialog
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color hexToColor(String hexColor) {
|
Color hexToColor(String hexColor) {
|
||||||
if (hexColor == null || hexColor.isEmpty || hexColor == 'null') {
|
|
||||||
// Return a default color if the hex color is invalid
|
|
||||||
return Colors.grey;
|
|
||||||
}
|
|
||||||
hexColor = hexColor.replaceAll("#", "");
|
hexColor = hexColor.replaceAll("#", "");
|
||||||
if (hexColor.length == 6) {
|
String colorString = "ff$hexColor";
|
||||||
hexColor = "ff$hexColor";
|
return Color(int.parse(colorString, radix: 16));
|
||||||
} else if (hexColor.length != 8) {
|
|
||||||
// Return a default color if the hex color is not in the valid format
|
|
||||||
return Colors.grey;
|
|
||||||
}
|
|
||||||
return Color(int.parse(hexColor, radix: 16));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void showDriverSelectionDialog(Map<String, dynamic> driver) {
|
void showDriverSelectionDialog(Map<String, dynamic> driver) {
|
||||||
@@ -185,7 +245,9 @@ class CupertinoDriverListWidget extends StatelessWidget {
|
|||||||
width: 20,
|
width: 20,
|
||||||
height: 20,
|
height: 20,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: hexToColor(driver['color_hex'].toString()),
|
color: driver['color_hex'].toString() == 'null'
|
||||||
|
? Colors.amber
|
||||||
|
: hexToColor(driver['color_hex'].toString()),
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
border: Border.all(),
|
border: Border.all(),
|
||||||
),
|
),
|
||||||
@@ -204,28 +266,12 @@ class CupertinoDriverListWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> confirmTripData(
|
|
||||||
Map<String, dynamic> driver, DateTime selectedDateTime) async {
|
|
||||||
try {
|
|
||||||
// Save trip data and set up notifications
|
|
||||||
// Log.print('selectedDateTime: $selectedDateTime');
|
|
||||||
// Log.print('driver: $driver');
|
|
||||||
await mapPassengerController.saveTripData(driver, selectedDateTime);
|
|
||||||
Get.back(); // Close the dialog
|
|
||||||
} catch (e) {
|
|
||||||
// Handle any errors that occur during the save process
|
|
||||||
Log.print('Error saving trip data: $e');
|
|
||||||
Get.snackbar('Error', 'Failed to save trip data');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void showDateTimePickerDialog(Map<String, dynamic> driver) {
|
void showDateTimePickerDialog(Map<String, dynamic> driver) {
|
||||||
Log.print('driver: ${driver}');
|
|
||||||
DateTime selectedDateTime = DateTime.now();
|
DateTime selectedDateTime = DateTime.now();
|
||||||
|
|
||||||
Get.defaultDialog(
|
Get.defaultDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
title: 'select date and time of trip'.tr,
|
title: "Select date and time of trip".tr,
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
// height: 400, // Adjust height as needed
|
// height: 400, // Adjust height as needed
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
@@ -237,10 +283,19 @@ class CupertinoDriverListWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
confirm: MyElevatedButton(
|
confirm: MyElevatedButton(
|
||||||
title: 'Confirm Trip'.tr,
|
title: 'Confirm Trip'.tr,
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
DateTime selectedDateTime =
|
DateTime selectedDateTime =
|
||||||
mapPassengerController.selectedDateTime.value;
|
mapPassengerController.selectedDateTime.value;
|
||||||
confirmTripData(driver, selectedDateTime);
|
// Save trip data and set up notifications
|
||||||
|
Get.back();
|
||||||
|
await mapPassengerController.saveTripData(driver, selectedDateTime);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
cancel: MyElevatedButton(
|
||||||
|
kolor: AppColor.redColor,
|
||||||
|
title: 'Cancel'.tr,
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -253,10 +308,10 @@ class DateTimePickerWidget extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
navigationBar: const CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
transitionBetweenRoutes: false,
|
transitionBetweenRoutes: false,
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
middle: Text('Date and Time Picker'),
|
middle: Text('Date and Time Picker'.tr),
|
||||||
),
|
),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
319
lib/views/home/map_widget.dart/vip_begin.dart
Normal file
319
lib/views/home/map_widget.dart/vip_begin.dart
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
import 'package:SEFER/constant/links.dart';
|
||||||
|
import 'package:SEFER/views/home/profile/complaint_page.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
|
import 'package:SEFER/controller/profile/profile_controller.dart';
|
||||||
|
import 'package:SEFER/main.dart';
|
||||||
|
|
||||||
|
import '../../../constant/colors.dart';
|
||||||
|
import '../../../constant/style.dart';
|
||||||
|
import '../../../controller/functions/audio_record1.dart';
|
||||||
|
import '../../../controller/functions/launch.dart';
|
||||||
|
import '../../../controller/functions/toast.dart';
|
||||||
|
import '../../../controller/home/map_passenger_controller.dart';
|
||||||
|
|
||||||
|
class VipRideBeginPassenger extends StatelessWidget {
|
||||||
|
const VipRideBeginPassenger({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ProfileController profileController = Get.put(ProfileController());
|
||||||
|
AudioRecorderController audioController =
|
||||||
|
Get.put(AudioRecorderController());
|
||||||
|
// Get.put(MapPassengerController());
|
||||||
|
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||||
|
if (controller.statusRideVip == 'Begin' ||
|
||||||
|
!controller.statusRideFromStart) {
|
||||||
|
return Positioned(
|
||||||
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
bottom: 10,
|
||||||
|
child: Container(
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
height: controller.statusRideVip == 'Begin' ? Get.height * .33 : 0,
|
||||||
|
// width: 100,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 30,
|
||||||
|
backgroundImage: NetworkImage(
|
||||||
|
'${AppLink.server}/portrate_captain_image/${controller.driverId}.jpg',
|
||||||
|
),
|
||||||
|
onBackgroundImageError: (_, __) {
|
||||||
|
// Handle error here
|
||||||
|
},
|
||||||
|
backgroundColor: Colors.grey,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.person, // Default icon or placeholder
|
||||||
|
size: 30,
|
||||||
|
color: Colors.white,
|
||||||
|
), // Placeholder background color
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 6, vertical: 2),
|
||||||
|
child: Text(
|
||||||
|
controller.driverName,
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 6, vertical: 2),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
controller.make,
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
controller.model,
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(3),
|
||||||
|
child: Text(
|
||||||
|
'vip',
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${controller.driverRate} 📈',
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// SizedBox(
|
||||||
|
// height: 5,
|
||||||
|
// ),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: Get.width * .15,
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () => Get.to(
|
||||||
|
() => ComplaintPage(),
|
||||||
|
transition: Transition.downToUp,
|
||||||
|
),
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.note_add,
|
||||||
|
color: AppColor.redColor,
|
||||||
|
),
|
||||||
|
tooltip: ' Add Note', // Optional tooltip for clarity
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: Get.width * .15,
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
child: audioController.isRecording == false
|
||||||
|
? IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await audioController.startRecording();
|
||||||
|
Toast.show(context, 'Start Record'.tr,
|
||||||
|
AppColor.greenColor);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.play_circle_fill_outlined,
|
||||||
|
color: AppColor.greenColor,
|
||||||
|
),
|
||||||
|
tooltip:
|
||||||
|
' Add Note', // Optional tooltip for clarity
|
||||||
|
)
|
||||||
|
: IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await audioController.stopRecording();
|
||||||
|
Toast.show(context, 'Record saved'.tr,
|
||||||
|
AppColor.greenColor);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.stop_circle,
|
||||||
|
color: AppColor.greenColor,
|
||||||
|
),
|
||||||
|
tooltip:
|
||||||
|
' Add Note', // Optional tooltip for clarity
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
width: Get.width * .15,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (box.read(BoxName.sosPhonePassenger) == null) {
|
||||||
|
{
|
||||||
|
await profileController.updatField(
|
||||||
|
'sosPhone', TextInputType.phone);
|
||||||
|
box.write(BoxName.sosPhonePassenger,
|
||||||
|
profileController.prfoileData['sosPhone']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
makePhoneCall('122');
|
||||||
|
// box.read(BoxName.sosPhonePassenger));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.sos_rounded,
|
||||||
|
color: AppColor.redColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
width: Get.width * .15,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (box.read(BoxName.sosPhonePassenger) == null ||
|
||||||
|
box.read(BoxName.sosPhonePassenger) == 'sos') {
|
||||||
|
{
|
||||||
|
await profileController.updatField(
|
||||||
|
'sosPhone', TextInputType.phone);
|
||||||
|
box.write(BoxName.sosPhonePassenger,
|
||||||
|
profileController.prfoileData['sosPhone']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String phoneNumber = box
|
||||||
|
.read(BoxName.sosPhonePassenger)
|
||||||
|
.toString();
|
||||||
|
// phoneNumber = phoneNumber.replaceAll('0', '');
|
||||||
|
var phone = box.read(BoxName.countryCode) ==
|
||||||
|
'Egypt'
|
||||||
|
? '+2${box.read(BoxName.sosPhonePassenger)}'
|
||||||
|
: '+962${box.read(BoxName.sosPhonePassenger)}';
|
||||||
|
controller.sendWhatsapp(phone);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
FontAwesome.whatsapp,
|
||||||
|
color: AppColor.greenColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: AppStyle.boxDecoration,
|
||||||
|
width: Get.width * .15,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await controller.getTokenForParent();
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
AntDesign.Safety,
|
||||||
|
color: AppColor.blueColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Stack(
|
||||||
|
children: [
|
||||||
|
// StreamCounter(),
|
||||||
|
LinearProgressIndicator(
|
||||||
|
backgroundColor: AppColor.accentColor,
|
||||||
|
color:
|
||||||
|
// controller.remainingTimeTimerRideBegin < 60
|
||||||
|
// ? AppColor.redColor
|
||||||
|
// :
|
||||||
|
AppColor.greenColor,
|
||||||
|
minHeight: 25,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
value:
|
||||||
|
24 //controller.progressTimerRideBegin.toDouble(),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
controller.stringElapsedTimeRideBeginVip,
|
||||||
|
style: AppStyle.title,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamCounter extends StatelessWidget {
|
||||||
|
const StreamCounter({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
// Build the UI based on the timer value
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Get.put(MapPassengerController());
|
||||||
|
return GetBuilder<MapPassengerController>(builder: (controller) {
|
||||||
|
return StreamBuilder<int>(
|
||||||
|
initialData: 0,
|
||||||
|
stream: controller.timerController.stream,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
// Calculate the remaining time based on the current tick
|
||||||
|
final remainingTime = controller.durationToRide - snapshot.data!;
|
||||||
|
|
||||||
|
// Format the remaining time as a string
|
||||||
|
final formattedRemainingTime =
|
||||||
|
'${(remainingTime / 60).floor()}:${(remainingTime % 60).toString().padLeft(2, '0')}';
|
||||||
|
|
||||||
|
// Return the UI widgets based on the remaining time
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Text(formattedRemainingTime),
|
||||||
|
// ElevatedButton(
|
||||||
|
// onPressed: () {
|
||||||
|
// // Handle button press here
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -6,6 +7,7 @@ import '../../../constant/box_name.dart';
|
|||||||
import '../../../constant/colors.dart';
|
import '../../../constant/colors.dart';
|
||||||
import '../../../constant/info.dart';
|
import '../../../constant/info.dart';
|
||||||
import '../../../constant/style.dart';
|
import '../../../constant/style.dart';
|
||||||
|
import '../../../controller/functions/toast.dart';
|
||||||
import '../../../controller/home/payment/credit_card_controller.dart';
|
import '../../../controller/home/payment/credit_card_controller.dart';
|
||||||
import '../../../controller/payment/payment_controller.dart';
|
import '../../../controller/payment/payment_controller.dart';
|
||||||
import '../../../main.dart';
|
import '../../../main.dart';
|
||||||
@@ -27,27 +29,51 @@ class PassengerWallet extends StatelessWidget {
|
|||||||
GetBuilder<PaymentController>(
|
GetBuilder<PaymentController>(
|
||||||
builder: (controller) => Column(
|
builder: (controller) => Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
const CardSeferWallet(),
|
const CardSeferWallet(),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
padding:
|
||||||
child: Row(
|
const EdgeInsets.symmetric(horizontal: 80, vertical: 10),
|
||||||
children: [
|
child: MyElevatedButton(
|
||||||
MyElevatedButton(
|
kolor: AppColor.blueColor,
|
||||||
kolor: AppColor.blueColor,
|
title: 'Payment History'.tr,
|
||||||
title: 'Payment History'.tr,
|
onPressed: () {
|
||||||
onPressed: () {
|
Get.to(() => const PaymentHistoryPassengerPage(),
|
||||||
Get.to(() => const PaymentHistoryPassengerPage(),
|
transition: Transition.size);
|
||||||
transition: Transition.size);
|
},
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
// Padding(
|
||||||
|
// padding:
|
||||||
|
// const EdgeInsets.symmetric(horizontal: 80, vertical: 10),
|
||||||
|
// child: MyElevatedButton(
|
||||||
|
// kolor: AppColor.yellowColor,
|
||||||
|
// title: 'Bonus gift'.tr,
|
||||||
|
// onPressed: () {
|
||||||
|
// Get.dialog(
|
||||||
|
// AlertDialog(
|
||||||
|
// contentPadding: EdgeInsets
|
||||||
|
// .zero, // Removes the padding around the content
|
||||||
|
// content: SizedBox(
|
||||||
|
// width: 300, // Match the width of PromoBanner
|
||||||
|
// // height: 250, // Match the height of PromoBanner
|
||||||
|
// child: PromoBanner(
|
||||||
|
// promoCode: box.read(BoxName.promo),
|
||||||
|
// discountPercentage: box.read(BoxName.discount),
|
||||||
|
// validity: box.read(BoxName.validity),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// Log.print(
|
||||||
|
// 'box.read(BoxName.isGiftToken).toString(): ${box.read(BoxName.isGiftToken).toString()}');
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -62,11 +88,77 @@ class PassengerWallet extends StatelessWidget {
|
|||||||
bottom: Get.height * .2,
|
bottom: Get.height * .2,
|
||||||
left: Get.width * .2,
|
left: Get.width * .2,
|
||||||
right: Get.width * .2,
|
right: Get.width * .2,
|
||||||
child: MyElevatedButton(
|
child: Column(
|
||||||
title: 'Show Promos to Charge'.tr,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
onPressed: () {
|
children: [
|
||||||
controller.changePromoSheetDialogue();
|
MyElevatedButton(
|
||||||
},
|
title: 'Show Promos to Charge'.tr,
|
||||||
|
onPressed: () {
|
||||||
|
// controller.changePromoSheetDialogue();
|
||||||
|
showPaymentBottomSheet(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
MyElevatedButton(
|
||||||
|
kolor: AppColor.deepPurpleAccent,
|
||||||
|
title: "Add wallet phone you use".tr,
|
||||||
|
onPressed: () {
|
||||||
|
Get.dialog(
|
||||||
|
CupertinoAlertDialog(
|
||||||
|
title: Text('Insert Wallet phone number'.tr),
|
||||||
|
content: Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Form(
|
||||||
|
key: controller.formKey,
|
||||||
|
child: CupertinoTextField(
|
||||||
|
controller:
|
||||||
|
controller.walletphoneController,
|
||||||
|
placeholder:
|
||||||
|
'Insert Wallet phone number'.tr,
|
||||||
|
keyboardType: TextInputType.phone,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 12, horizontal: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
CupertinoDialogAction(
|
||||||
|
child: Text('Cancel'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CupertinoColors
|
||||||
|
.destructiveRed)),
|
||||||
|
onPressed: () {
|
||||||
|
Get.back(); // Dismiss the dialog
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CupertinoDialogAction(
|
||||||
|
child: Text('OK'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
color:
|
||||||
|
CupertinoColors.activeGreen)),
|
||||||
|
onPressed: () async {
|
||||||
|
Get.back(); // Close the dialog
|
||||||
|
box.write(
|
||||||
|
BoxName.phoneWallet,
|
||||||
|
controller
|
||||||
|
.walletphoneController.text);
|
||||||
|
Toast.show(
|
||||||
|
context,
|
||||||
|
'Phone Wallet Saved Successfully'.tr,
|
||||||
|
AppColor.greenColor);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
barrierDismissible:
|
||||||
|
false, // Set to prevent dismissing by tapping outside
|
||||||
|
);
|
||||||
|
})
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
const PassengerWalletDialog(),
|
const PassengerWalletDialog(),
|
||||||
@@ -76,70 +168,71 @@ class PassengerWallet extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CardSeferWallet extends StatelessWidget {
|
class CardSeferWallet extends StatelessWidget {
|
||||||
const CardSeferWallet({
|
const CardSeferWallet({super.key});
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetBuilder<PaymentController>(builder: (paymentController) {
|
return GetBuilder<PaymentController>(
|
||||||
return Row(
|
builder: (paymentController) {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
return Container(
|
||||||
children: [
|
width: Get.width * 0.9,
|
||||||
Container(
|
height: Get.height * 0.25,
|
||||||
width: Get.width * .85,
|
margin: const EdgeInsets.all(16.0),
|
||||||
height: Get.height * .3,
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
color: CupertinoColors.extraLightBackgroundGray,
|
||||||
color: AppColor.twitterColor.withOpacity(.8),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
boxShadow: [
|
||||||
gradient: const LinearGradient(colors: [
|
BoxShadow(
|
||||||
AppColor.redColor,
|
color: Colors.black.withOpacity(0.1),
|
||||||
AppColor.yellowColor,
|
offset: const Offset(0, 10),
|
||||||
AppColor.yellowColor,
|
blurRadius: 20,
|
||||||
]),
|
),
|
||||||
),
|
],
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
// Wallet Title
|
||||||
padding: const EdgeInsets.all(8.0),
|
Text(
|
||||||
child: Row(
|
'${AppInformation.appName} Wallet',
|
||||||
children: [
|
style: AppStyle.headTitle.copyWith(
|
||||||
Text(
|
color: CupertinoColors.label,
|
||||||
'${AppInformation.appName} Wallet',
|
fontSize: 20,
|
||||||
style: AppStyle.headTitle
|
fontWeight: FontWeight.bold,
|
||||||
.copyWith(color: AppColor.writeColor),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// Wallet Balance
|
||||||
children: [
|
Center(
|
||||||
Text(
|
child: Text(
|
||||||
'${box.read(BoxName.passengerWalletTotal)} \$' ??
|
'${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${'LE'.tr}',
|
||||||
'0.0 \$',
|
style: AppStyle.headTitle2.copyWith(
|
||||||
style: AppStyle.headTitle2,
|
color: CupertinoColors.label,
|
||||||
)
|
fontSize: 36,
|
||||||
],
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
box.read(BoxName.name),
|
|
||||||
style: AppStyle.title,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
|
||||||
|
// User Name (Bottom Right)
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.bottomRight,
|
||||||
|
child: Text(
|
||||||
|
box.read(BoxName.name),
|
||||||
|
style: AppStyle.title.copyWith(
|
||||||
|
color: CupertinoColors.secondaryLabel,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
);
|
},
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'package:SEFER/constant/box_name.dart';
|
import 'package:SEFER/constant/style.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:SEFER/constant/box_name.dart';
|
||||||
import 'package:SEFER/constant/colors.dart';
|
import 'package:SEFER/constant/colors.dart';
|
||||||
import 'package:SEFER/constant/style.dart';
|
|
||||||
import 'package:SEFER/controller/functions/toast.dart';
|
import 'package:SEFER/controller/functions/toast.dart';
|
||||||
import 'package:SEFER/controller/payment/payment_controller.dart';
|
import 'package:SEFER/controller/payment/payment_controller.dart';
|
||||||
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
|
||||||
|
|
||||||
import '../../../main.dart';
|
import '../../../main.dart';
|
||||||
|
|
||||||
@@ -18,249 +18,344 @@ class PassengerWalletDialog extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetBuilder<PaymentController>(
|
return GetBuilder<PaymentController>(
|
||||||
builder: (controller) => Positioned(
|
builder: (controller) => Positioned(
|
||||||
top: Get.height * .1,
|
top: Get.height * .1,
|
||||||
right: Get.width * .15,
|
right: Get.width * .15,
|
||||||
left: Get.width * .15,
|
left: Get.width * .15,
|
||||||
bottom: Get.height * .1,
|
bottom: Get.height * .1,
|
||||||
child: controller.isPromoSheetDialogue
|
child: controller.isPromoSheetDialogue
|
||||||
? Container(
|
? CupertinoActionSheet(
|
||||||
decoration: const BoxDecoration(
|
title: Text('Select Payment Amount'.tr),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
actions: [
|
||||||
color: AppColor.secondaryColor,
|
CupertinoActionSheetAction(
|
||||||
boxShadow: [
|
onPressed: () {
|
||||||
BoxShadow(
|
controller.updateSelectedAmount(
|
||||||
color: AppColor.accentColor,
|
box.read(BoxName.countryCode) == 'Egypt' ? 100 : 10,
|
||||||
offset: Offset(-1, -1),
|
);
|
||||||
blurRadius: 0,
|
showPaymentOptions(context, controller);
|
||||||
spreadRadius: 0,
|
},
|
||||||
blurStyle: BlurStyle.normal),
|
child: Text(
|
||||||
BoxShadow(
|
box.read(BoxName.countryCode) == 'Egypt'
|
||||||
color: AppColor.accentColor,
|
? '100 ${'LE'.tr}'
|
||||||
offset: Offset(3, 3),
|
: '10 ${'JOD'.tr}',
|
||||||
blurRadius: 1,
|
),
|
||||||
spreadRadius: 0,
|
),
|
||||||
blurStyle: BlurStyle.normal)
|
CupertinoActionSheetAction(
|
||||||
]),
|
onPressed: () {
|
||||||
child: Padding(
|
controller.updateSelectedAmount(
|
||||||
padding: const EdgeInsets.all(6),
|
box.read(BoxName.countryCode) == 'Egypt' ? 200 : 20,
|
||||||
child: Column(
|
);
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
showPaymentOptions(context, controller);
|
||||||
children: [
|
},
|
||||||
GestureDetector(
|
child: Text(
|
||||||
onTap: () {
|
box.read(BoxName.countryCode) == 'Egypt'
|
||||||
controller.updateSelectedAmount(10);
|
? '200 ${'LE'.tr} = 205 ${'LE'.tr}'
|
||||||
},
|
: '20 ${'JOD'.tr}',
|
||||||
child: Row(
|
),
|
||||||
children: [
|
),
|
||||||
Radio(
|
CupertinoActionSheetAction(
|
||||||
value: box.read(BoxName.countryCode) == 'Egypt'
|
onPressed: () {
|
||||||
? 100
|
controller.updateSelectedAmount(
|
||||||
: 10,
|
box.read(BoxName.countryCode) == 'Egypt' ? 400 : 40,
|
||||||
groupValue: controller.selectedAmount,
|
);
|
||||||
onChanged: (value) {
|
showPaymentOptions(context, controller);
|
||||||
controller.updateSelectedAmount(value as int);
|
},
|
||||||
},
|
child: Text(
|
||||||
),
|
box.read(BoxName.countryCode) == 'Egypt'
|
||||||
Text(
|
? '400 ${'LE'.tr} = 415 ${'LE'.tr}'
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
: '40 ${'JOD'.tr}',
|
||||||
? '100 ${'LE'.tr}'.tr
|
),
|
||||||
: '10 ${'JOD'.tr}'.tr,
|
),
|
||||||
style: AppStyle.title,
|
CupertinoActionSheetAction(
|
||||||
),
|
onPressed: () {
|
||||||
],
|
controller.updateSelectedAmount(
|
||||||
|
box.read(BoxName.countryCode) == 'Egypt' ? 1000 : 50,
|
||||||
|
);
|
||||||
|
showPaymentOptions(context, controller);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
box.read(BoxName.countryCode) == 'Egypt'
|
||||||
|
? '1000 ${'LE'.tr} = 1100 ${'LE'.tr}'
|
||||||
|
: '50 ${'JOD'.tr}',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
cancelButton: CupertinoActionSheetAction(
|
||||||
|
onPressed: () {
|
||||||
|
controller.changePromoSheetDialogue();
|
||||||
|
},
|
||||||
|
child: Text('Cancel'.tr),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// class PassengerWalletDialog extends StatelessWidget {
|
||||||
|
// const PassengerWalletDialog({
|
||||||
|
// super.key,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return GetBuilder<PaymentController>(
|
||||||
|
// builder: (controller) {
|
||||||
|
// return Positioned(
|
||||||
|
// top: Get.height * .1,
|
||||||
|
// right: Get.width * .15,
|
||||||
|
// left: Get.width * .15,
|
||||||
|
// bottom: Get.height * .1,
|
||||||
|
// child: controller.isPromoSheetDialogue
|
||||||
|
// ? Container()
|
||||||
|
// : SizedBox
|
||||||
|
// .shrink(), // If condition is false, return an empty widget
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
void showPaymentBottomSheet(BuildContext context) {
|
||||||
|
final controller = Get.find<PaymentController>();
|
||||||
|
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(15.0)),
|
||||||
|
),
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () async {
|
||||||
|
Get.back();
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Select Payment Amount'.tr,
|
||||||
|
style: AppStyle.headTitle2,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
|
||||||
|
// Payment Options List
|
||||||
|
_buildPaymentOption(
|
||||||
|
context: context,
|
||||||
|
controller: controller,
|
||||||
|
amount: box.read(BoxName.countryCode) == 'Egypt' ? 100 : 10,
|
||||||
|
bonusAmount: 0,
|
||||||
|
currency: box.read(BoxName.countryCode) == 'Egypt'
|
||||||
|
? 'LE'.tr
|
||||||
|
: 'JOD'.tr,
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 8.0),
|
||||||
|
_buildPaymentOption(
|
||||||
|
context: context,
|
||||||
|
controller: controller,
|
||||||
|
amount: box.read(BoxName.countryCode) == 'Egypt' ? 200 : 20,
|
||||||
|
bonusAmount: box.read(BoxName.countryCode) == 'Egypt' ? 5 : 1,
|
||||||
|
currency: box.read(BoxName.countryCode) == 'Egypt'
|
||||||
|
? 'LE'.tr
|
||||||
|
: 'JOD'.tr,
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 8.0),
|
||||||
|
_buildPaymentOption(
|
||||||
|
context: context,
|
||||||
|
controller: controller,
|
||||||
|
amount: box.read(BoxName.countryCode) == 'Egypt' ? 400 : 40,
|
||||||
|
bonusAmount:
|
||||||
|
box.read(BoxName.countryCode) == 'Egypt' ? 15 : 2.5,
|
||||||
|
currency: box.read(BoxName.countryCode) == 'Egypt'
|
||||||
|
? 'LE'.tr
|
||||||
|
: 'JOD'.tr,
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 8.0),
|
||||||
|
_buildPaymentOption(
|
||||||
|
context: context,
|
||||||
|
controller: controller,
|
||||||
|
amount: box.read(BoxName.countryCode) == 'Egypt' ? 1000 : 50,
|
||||||
|
bonusAmount: box.read(BoxName.countryCode) == 'Egypt' ? 100 : 6,
|
||||||
|
currency: box.read(BoxName.countryCode) == 'Egypt'
|
||||||
|
? 'LE'.tr
|
||||||
|
: 'JOD'.tr,
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
child: Text('Cancel'.tr),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPaymentOption({
|
||||||
|
required BuildContext context,
|
||||||
|
required PaymentController controller,
|
||||||
|
required int amount,
|
||||||
|
required double bonusAmount,
|
||||||
|
required String currency,
|
||||||
|
}) {
|
||||||
|
return Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
controller.updateSelectedAmount(amount);
|
||||||
|
Get.back();
|
||||||
|
showPaymentOptions(context, controller);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: Colors.grey[300]!),
|
||||||
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
bonusAmount > 0
|
||||||
|
? '${'Pay'.tr} $amount $currency, ${'Get'.tr} ${amount + bonusAmount} $currency'
|
||||||
|
: '$amount $currency',
|
||||||
|
style: AppStyle.title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void showPaymentOptions(BuildContext context, PaymentController controller) {
|
||||||
|
showCupertinoModalPopup(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => CupertinoActionSheet(
|
||||||
|
title: Text('Payment Options'.tr),
|
||||||
|
actions: [
|
||||||
|
box.read(BoxName.countryCode) == 'Egypt'
|
||||||
|
? CupertinoActionSheetAction(
|
||||||
|
child: Text('💳 Pay with Credit Card'.tr),
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.selectedAmount != 0) {
|
||||||
|
controller.payWithPayMob(
|
||||||
|
context,
|
||||||
|
controller.selectedAmount.toString(),
|
||||||
|
box.read(BoxName.countryCode) == 'Egypt' ? 'EGP' : 'JOD',
|
||||||
|
() async {
|
||||||
|
await controller.addPassengerWallet();
|
||||||
|
controller.changePromoSheetDialogue();
|
||||||
|
await controller.getPassengerWallet();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Toast.show(context, '⚠️ You need to choose an amount!'.tr,
|
||||||
|
AppColor.redColor);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
box.read(BoxName.countryCode) != 'Egypt'
|
||||||
|
? CupertinoActionSheetAction(
|
||||||
|
child: Text('Pay with PayPal'.tr),
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.selectedAmount != 0) {
|
||||||
|
controller.makePaymentPayPal(context);
|
||||||
|
} else {
|
||||||
|
Toast.show(context, 'You will choose one of above!'.tr,
|
||||||
|
AppColor.redColor);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
box.read(BoxName.phoneWallet) != null
|
||||||
|
? CupertinoActionSheetAction(
|
||||||
|
child: Text('💰 Pay with Wallet'.tr),
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.selectedAmount != 0) {
|
||||||
|
controller.isLoading = true;
|
||||||
|
controller.update();
|
||||||
|
controller.payWithPayMobWallet(
|
||||||
|
context,
|
||||||
|
controller.selectedAmount.toString(),
|
||||||
|
box.read(BoxName.countryCode) == 'Egypt' ? 'EGP' : 'JOD',
|
||||||
|
() async {
|
||||||
|
await controller.addPassengerWallet();
|
||||||
|
controller.changePromoSheetDialogue();
|
||||||
|
await controller.getPassengerWallet();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
controller.isLoading = false;
|
||||||
|
controller.update();
|
||||||
|
} else {
|
||||||
|
Toast.show(context, '⚠️ You need to choose an amount!'.tr,
|
||||||
|
AppColor.redColor);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: CupertinoActionSheetAction(
|
||||||
|
child: Text('Add wallet phone you use'.tr),
|
||||||
|
onPressed: () {
|
||||||
|
Get.dialog(
|
||||||
|
CupertinoAlertDialog(
|
||||||
|
title: Text('Insert Wallet phone number'.tr),
|
||||||
|
content: Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
CupertinoTextField(
|
||||||
|
controller: controller.walletphoneController,
|
||||||
|
placeholder: 'Insert Wallet phone number'.tr,
|
||||||
|
keyboardType: TextInputType.phone,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 12,
|
||||||
|
horizontal: 10,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
GestureDetector(
|
),
|
||||||
onTap: () {
|
actions: [
|
||||||
controller.updateSelectedAmount(20);
|
CupertinoDialogAction(
|
||||||
},
|
child: Text('Cancel'.tr,
|
||||||
child: Row(
|
style: const TextStyle(
|
||||||
children: [
|
color: CupertinoColors.destructiveRed)),
|
||||||
Radio(
|
|
||||||
value:
|
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
|
||||||
? 200
|
|
||||||
: 20,
|
|
||||||
groupValue: controller.selectedAmount,
|
|
||||||
onChanged: (value) {
|
|
||||||
controller
|
|
||||||
.updateSelectedAmount(value as int);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
|
||||||
? '200 ${'LE'.tr} '.tr
|
|
||||||
: '20 ${'JOD'.tr}'.tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
controller.updateSelectedAmount(40);
|
|
||||||
},
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Radio(
|
|
||||||
value:
|
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
|
||||||
? 400
|
|
||||||
: 40,
|
|
||||||
groupValue: controller.selectedAmount,
|
|
||||||
onChanged: (value) {
|
|
||||||
controller
|
|
||||||
.updateSelectedAmount(value as int);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
|
||||||
? '400 ${'LE'.tr} '.tr
|
|
||||||
: '40 ${'JOD'.tr}'.tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
controller.updateSelectedAmount(100);
|
|
||||||
},
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Radio(
|
|
||||||
value:
|
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
|
||||||
? 1000
|
|
||||||
: 50,
|
|
||||||
groupValue: controller.selectedAmount,
|
|
||||||
onChanged: (value) {
|
|
||||||
controller
|
|
||||||
.updateSelectedAmount(value as int);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
|
||||||
? '1000 ${'LE'.tr} '.tr
|
|
||||||
: '50 ${'JOD'.tr}'.tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
const Spacer(),
|
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
|
||||||
? const SizedBox()
|
|
||||||
: MyElevatedButton(
|
|
||||||
kolor: AppColor.blueColor,
|
|
||||||
title: '${'Pay with Your'.tr} PayPal',
|
|
||||||
onPressed: () {
|
|
||||||
if (controller.selectedAmount != 0) {
|
|
||||||
controller.makePaymentPayPal(context);
|
|
||||||
} else {
|
|
||||||
Toast.show(
|
|
||||||
context,
|
|
||||||
'You will choose one of above !'.tr,
|
|
||||||
AppColor.redColor);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
box.read(BoxName.countryCode) == 'Egypt'
|
|
||||||
? Column(
|
|
||||||
children: [
|
|
||||||
MyElevatedButton(
|
|
||||||
title: '💳 Pay with Credit Card'.tr,
|
|
||||||
onPressed: () {
|
|
||||||
if (controller.selectedAmount != 0) {
|
|
||||||
controller.payWithPayMob(
|
|
||||||
context,
|
|
||||||
controller.selectedAmount
|
|
||||||
.toString(), // Convert int to double
|
|
||||||
box.read(BoxName.countryCode) ==
|
|
||||||
'Egypt'
|
|
||||||
? 'EGP'
|
|
||||||
: 'JOD',
|
|
||||||
() async {
|
|
||||||
await controller
|
|
||||||
.addPassengerWallet();
|
|
||||||
controller
|
|
||||||
.changePromoSheetDialogue();
|
|
||||||
await controller
|
|
||||||
.getPassengerWallet();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Toast.show(
|
|
||||||
context,
|
|
||||||
'⚠️ You need to choose an amount!'.tr,
|
|
||||||
AppColor.redColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
// Add some spacing between buttons
|
|
||||||
MyElevatedButton(
|
|
||||||
kolor: AppColor.yellowColor,
|
|
||||||
title: '💰 Pay with Wallet'.tr,
|
|
||||||
onPressed: () {
|
|
||||||
if (controller.selectedAmount != 0) {
|
|
||||||
controller.payWithPayMobWallet(
|
|
||||||
context,
|
|
||||||
controller.selectedAmount
|
|
||||||
.toString(), // Convert int to double
|
|
||||||
box.read(BoxName.countryCode) ==
|
|
||||||
'Egypt'
|
|
||||||
? 'EGP'
|
|
||||||
: 'JOD',
|
|
||||||
() async {
|
|
||||||
await controller
|
|
||||||
.addPassengerWallet();
|
|
||||||
controller
|
|
||||||
.changePromoSheetDialogue();
|
|
||||||
await controller
|
|
||||||
.getPassengerWallet();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Toast.show(
|
|
||||||
context,
|
|
||||||
'⚠️ You need to choose an amount!'.tr,
|
|
||||||
AppColor.redColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: MyElevatedButton(
|
|
||||||
title: 'Pay with Credit Card'.tr,
|
|
||||||
onPressed: () {
|
|
||||||
if (controller.selectedAmount != 0) {
|
|
||||||
controller.makePaymentStripe(
|
|
||||||
controller.selectedAmount!
|
|
||||||
.toDouble(), // Convert int to double
|
|
||||||
box.read(BoxName.countryCode) != 'Egypt'
|
|
||||||
? 'usd'
|
|
||||||
: 'jod', () {
|
|
||||||
controller.addPassengerWallet();
|
|
||||||
controller.changePromoSheetDialogue();
|
|
||||||
controller.getPassengerWallet();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Toast.show(
|
|
||||||
context,
|
|
||||||
'You will choose one of above !'.tr,
|
|
||||||
AppColor.redColor);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
MyElevatedButton(
|
|
||||||
title: 'Cancel'.tr,
|
|
||||||
kolor: AppColor.redColor,
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
controller.changePromoSheetDialogue();
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CupertinoDialogAction(
|
||||||
|
child: Text('OK'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CupertinoColors.activeGreen)),
|
||||||
|
onPressed: () async {
|
||||||
|
Get.back();
|
||||||
|
box.write(BoxName.phoneWallet,
|
||||||
|
controller.walletphoneController.text);
|
||||||
|
Toast.show(
|
||||||
|
context,
|
||||||
|
'Phone Wallet Saved Successfully'.tr,
|
||||||
|
AppColor.greenColor);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
))
|
barrierDismissible: false,
|
||||||
: const SizedBox()),
|
);
|
||||||
);
|
},
|
||||||
}
|
),
|
||||||
|
],
|
||||||
|
cancelButton: CupertinoActionSheetAction(
|
||||||
|
child: Text('Cancel'.tr),
|
||||||
|
onPressed: () {
|
||||||
|
// controller.changePromoSheetDialogue();
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/constant/colors.dart';
|
import 'package:SEFER/constant/colors.dart';
|
||||||
@@ -17,7 +18,7 @@ class PaymentHistoryPassengerPage extends StatelessWidget {
|
|||||||
body: [
|
body: [
|
||||||
GetBuilder<PassengerWalletHistoryController>(
|
GetBuilder<PassengerWalletHistoryController>(
|
||||||
builder: (controller) => controller.isLoading
|
builder: (controller) => controller.isLoading
|
||||||
? const MyCircularProgressIndicator()
|
? const MyCircularProgressIndicator() // iOS-style loading indicator
|
||||||
: controller.archive.isEmpty
|
: controller.archive.isEmpty
|
||||||
? Center(
|
? Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -25,37 +26,33 @@ class PaymentHistoryPassengerPage extends StatelessWidget {
|
|||||||
style: AppStyle.title,
|
style: AppStyle.title,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: ListView.builder(
|
: CupertinoListSection.insetGrouped(
|
||||||
itemCount: controller.archive.length,
|
children: List.generate(
|
||||||
itemBuilder: (BuildContext context, int index) {
|
controller.archive.length,
|
||||||
var list = controller.archive[index];
|
(index) {
|
||||||
return Padding(
|
var list = controller.archive[index];
|
||||||
padding: const EdgeInsets.all(4),
|
return CupertinoListTile(
|
||||||
child: Container(
|
backgroundColor: double.parse(list['balance']) < 0
|
||||||
decoration: BoxDecoration(
|
? AppColor.redColor.withOpacity(.2)
|
||||||
color: double.parse(list['balance']) < 0
|
: AppColor.greenColor.withOpacity(.2),
|
||||||
? AppColor.redColor.withOpacity(.4)
|
title: Text(
|
||||||
: AppColor.greenColor.withOpacity(.4)),
|
list['balance'],
|
||||||
child: Padding(
|
style: AppStyle.title.copyWith(
|
||||||
padding: const EdgeInsets.all(8.0),
|
color: CupertinoColors.black,
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
list['balance'],
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
list['created_at'],
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
additionalInfo: Text(
|
||||||
);
|
list['created_at'],
|
||||||
},
|
style: AppStyle.title.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
color: CupertinoColors.systemGrey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8, horizontal: 16),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,64 +1,199 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'dart:convert';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:SEFER/views/widgets/my_scafold.dart';
|
|
||||||
import 'package:SEFER/views/widgets/mycircular.dart';
|
|
||||||
|
|
||||||
import '../../../controller/home/profile/complaint_controller.dart';
|
import 'package:SEFER/constant/colors.dart';
|
||||||
import '../../widgets/elevated_btn.dart';
|
import 'package:SEFER/constant/style.dart';
|
||||||
|
import 'package:SEFER/controller/functions/crud.dart';
|
||||||
|
import 'package:SEFER/controller/home/profile/complaint_controller.dart';
|
||||||
|
import 'package:SEFER/views/widgets/my_dialog.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import '../../../controller/functions/audio_record1.dart';
|
||||||
|
|
||||||
class ComplaintPage extends StatelessWidget {
|
class ComplaintPage extends StatelessWidget {
|
||||||
// Rename class
|
final ComplaintController complaintController =
|
||||||
ComplaintPage({super.key});
|
Get.put(ComplaintController());
|
||||||
ComplaintController complaintController =
|
final AudioRecorderController audioRecorderController =
|
||||||
Get.put(ComplaintController()); // Update controller instance
|
Get.put(AudioRecorderController());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MyScafolld(
|
return GetBuilder<ComplaintController>(builder: (complaintController) {
|
||||||
title: 'Complaint'.tr,
|
return CupertinoPageScaffold(
|
||||||
body: [
|
navigationBar: CupertinoNavigationBar(
|
||||||
Padding(
|
middle: Text('Complaint'.tr, style: AppStyle.title),
|
||||||
padding: const EdgeInsets.all(26),
|
|
||||||
child: Form(
|
|
||||||
key: complaintController.formKey,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
TextFormField(
|
|
||||||
controller: complaintController.complaintController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
hintText: 'Enter your complaint here'.tr,
|
|
||||||
labelText: 'Complaint'.tr, // Update label
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Please enter your complaint.'.tr;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
complaintController.isLoading
|
|
||||||
? const MyCircularProgressIndicator()
|
|
||||||
: MyElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (complaintController.formKey.currentState!
|
|
||||||
.validate()) {
|
|
||||||
complaintController
|
|
||||||
.addComplaint(); // Update method name
|
|
||||||
|
|
||||||
// Clear the complaint form
|
|
||||||
complaintController.formKey.currentState!.reset();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: 'Submit'.tr,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
child: complaintController.isLoading
|
||||||
isleading: true,
|
? const Center(child: CupertinoActivityIndicator())
|
||||||
);
|
: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Form(
|
||||||
|
key: complaintController.formKey,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
// Complaint Text Field
|
||||||
|
CupertinoFormSection(
|
||||||
|
header: Text('Submit Your Complaint'.tr),
|
||||||
|
children: [
|
||||||
|
CupertinoTextField(
|
||||||
|
controller:
|
||||||
|
complaintController.complaintController,
|
||||||
|
placeholder: 'Enter your complaint here'.tr,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 12, horizontal: 16),
|
||||||
|
maxLines: 5,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: CupertinoColors.systemGrey4),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
color: CupertinoColors.white,
|
||||||
|
),
|
||||||
|
style: AppStyle.subtitle,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
|
// FutureBuilder to load recorded audio files
|
||||||
|
FutureBuilder<List<String>>(
|
||||||
|
future: audioRecorderController.getRecordedFiles(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState ==
|
||||||
|
ConnectionState.waiting) {
|
||||||
|
return const Center(
|
||||||
|
child: CupertinoActivityIndicator());
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Text('Error: ${snapshot.error}',
|
||||||
|
style: AppStyle.subtitle);
|
||||||
|
} else if (snapshot.hasData &&
|
||||||
|
snapshot.data!.isEmpty) {
|
||||||
|
return Text('No audio files recorded.'.tr,
|
||||||
|
style: AppStyle.subtitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of recorded audio files
|
||||||
|
return CupertinoFormSection(
|
||||||
|
header: Text('attach audio of complain'.tr),
|
||||||
|
children: snapshot.data!.map((audioFilePath) {
|
||||||
|
final audioFile = File(audioFilePath);
|
||||||
|
return CupertinoListTile(
|
||||||
|
title: Text(audioFilePath.split('/').last,
|
||||||
|
style: AppStyle.title),
|
||||||
|
trailing: const Icon(
|
||||||
|
CupertinoIcons.play_arrow,
|
||||||
|
color: AppColor.accentColor),
|
||||||
|
onTap: () async {
|
||||||
|
MyDialogContent().getDialog(
|
||||||
|
'be sure'.tr,
|
||||||
|
Text('attach correct audio'.tr),
|
||||||
|
() async {
|
||||||
|
await complaintController
|
||||||
|
.uploadAudioFile(audioFile);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
|
// Trip Details Section
|
||||||
|
CupertinoFormSection(
|
||||||
|
header: Text('Trip Details'.tr),
|
||||||
|
children: [
|
||||||
|
CupertinoListTile(
|
||||||
|
title: complaintController.feedBack.isEmpty
|
||||||
|
? Text('No Ride found yet'.tr)
|
||||||
|
: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${'Date'.tr}: ${complaintController.feedBack[0]['date']}',
|
||||||
|
style: AppStyle.title),
|
||||||
|
Text(
|
||||||
|
'${'Price'.tr}: ${complaintController.feedBack[0]['price']}',
|
||||||
|
style: AppStyle.title),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
CupertinoFormSection(
|
||||||
|
header: Text('SEFER answer'.tr),
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 100,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
// Check if passengerReport is not null
|
||||||
|
if (complaintController.passengerReport !=
|
||||||
|
null)
|
||||||
|
// Access the 'solution' key safely
|
||||||
|
Text(
|
||||||
|
complaintController
|
||||||
|
.passengerReport!['solution']
|
||||||
|
?.toString() ??
|
||||||
|
'No solution available',
|
||||||
|
style: AppStyle.title,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
const SizedBox(), // Fallback if passengerReport is null
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
// Submit Button
|
||||||
|
CupertinoButton(
|
||||||
|
color: AppColor.blueColor,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 14, horizontal: 30),
|
||||||
|
onPressed: () async {
|
||||||
|
if (complaintController.formKey.currentState!
|
||||||
|
.validate()) {
|
||||||
|
if (complaintController.audioLink.toString() ==
|
||||||
|
'') {
|
||||||
|
MyDialogContent().getDialog(
|
||||||
|
'title',
|
||||||
|
Text(
|
||||||
|
'the audio file not uploaded yet \nDo you want to upload without audio file'
|
||||||
|
.tr), () async {
|
||||||
|
await complaintController.geminiAudio(
|
||||||
|
jsonEncode(complaintController.feedBack),
|
||||||
|
complaintController.audioLink,
|
||||||
|
complaintController
|
||||||
|
.complaintController.text);
|
||||||
|
complaintController.formKey.currentState!
|
||||||
|
.reset();
|
||||||
|
});
|
||||||
|
Get.back();
|
||||||
|
} else {
|
||||||
|
await complaintController.geminiAudio(
|
||||||
|
jsonEncode(complaintController.feedBack),
|
||||||
|
complaintController.audioLink,
|
||||||
|
complaintController
|
||||||
|
.complaintController.text);
|
||||||
|
complaintController.formKey.currentState!
|
||||||
|
.reset();
|
||||||
|
}
|
||||||
|
complaintController.addComplaint();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text('Submit'.tr, style: AppStyle.title),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -393,92 +393,6 @@ class CountryPicker extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListTile changeCountry(List<String> countryOptions) {
|
|
||||||
return ListTile(
|
|
||||||
leading: const Icon(Icons.location_city_outlined),
|
|
||||||
title: Text(
|
|
||||||
'Change Country'.tr,
|
|
||||||
style: AppStyle.headTitle2,
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
'You can change the Country to get all features'.tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
onTap: () => Get.to(MyScafolld(
|
|
||||||
title: 'Change Country'.tr,
|
|
||||||
// body: [],
|
|
||||||
body: [
|
|
||||||
GetBuilder<ProfileController>(builder: (controller) {
|
|
||||||
return 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.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: () async {
|
|
||||||
// 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();
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
isleading: true)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class CountryPickerFromSetting extends StatelessWidget {
|
class CountryPickerFromSetting extends StatelessWidget {
|
||||||
final ProfileController controller = Get.put(ProfileController());
|
final ProfileController controller = Get.put(ProfileController());
|
||||||
final LoginController loginController = Get.put(LoginController());
|
final LoginController loginController = Get.put(LoginController());
|
||||||
@@ -548,7 +462,8 @@ class CountryPickerFromSetting extends StatelessWidget {
|
|||||||
MyElevatedButton(
|
MyElevatedButton(
|
||||||
title: 'Select Country'.tr, // Use translated text for button
|
title: 'Select Country'.tr, // Use translated text for button
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// No conversion needed
|
loginController.saveCountryCode(controller.selectedCountry
|
||||||
|
.toString()); // No conversion needed
|
||||||
box.write(
|
box.write(
|
||||||
BoxName.countryCode, //
|
BoxName.countryCode, //
|
||||||
controller.selectedCountry); // Already saved in English
|
controller.selectedCountry); // Already saved in English
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'package:animated_text_kit/animated_text_kit.dart';
|
import 'package:animated_text_kit/animated_text_kit.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/controller/home/profile/promos_controller.dart';
|
import 'package:SEFER/controller/home/profile/promos_controller.dart';
|
||||||
import 'package:SEFER/views/widgets/my_scafold.dart';
|
import 'package:SEFER/views/widgets/my_scafold.dart';
|
||||||
@@ -18,160 +20,211 @@ class PromosPassengerPage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Get.put(PromosController());
|
Get.put(PromosController());
|
||||||
return MyScafolld(
|
return MyScafolld(
|
||||||
title: 'Promos For today'.tr,
|
title: "Promos For Today".tr,
|
||||||
isleading: true,
|
isleading: true,
|
||||||
body: [
|
body: [
|
||||||
GetBuilder<PromosController>(
|
GetBuilder<PromosController>(
|
||||||
builder: (orderHistoryController) => orderHistoryController.isLoading
|
builder: (orderHistoryController) => orderHistoryController.isLoading
|
||||||
? const MyCircularProgressIndicator()
|
? const MyCircularProgressIndicator()
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
itemCount: orderHistoryController.promoList.length +
|
itemCount: orderHistoryController
|
||||||
1, // Adding 1 for the ad
|
.promoList.length, // Adding 1 for the ad
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
if (index == 0) {
|
// if (index == 0) {
|
||||||
// Ad at the beginning
|
// // Ad at the beginning
|
||||||
return Padding(
|
// return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
// padding: const EdgeInsets.all(8.0),
|
||||||
child: Container(
|
// child: Container(
|
||||||
height: 120, // Adjust the height of the ad container
|
// height: 120, // Adjust the height of the ad container
|
||||||
decoration: BoxDecoration(
|
// decoration: BoxDecoration(
|
||||||
color:
|
// color:
|
||||||
Colors.grey[200], // Background color for the ad
|
// Colors.grey[200], // Background color for the ad
|
||||||
borderRadius: BorderRadius.circular(10),
|
// borderRadius: BorderRadius.circular(10),
|
||||||
),
|
// ),
|
||||||
child: Center(
|
// child: Center(
|
||||||
child: Container(
|
// child: Container(
|
||||||
decoration: AppStyle.boxDecoration,
|
// decoration: AppStyle.boxDecoration,
|
||||||
height: Get.height * .19,
|
// height: Get.height * .19,
|
||||||
child: ListView(
|
// child: ListView(
|
||||||
scrollDirection: Axis.horizontal,
|
// scrollDirection: Axis.horizontal,
|
||||||
children: [
|
// children: [
|
||||||
PointsCaptain(
|
// PointsCaptain(
|
||||||
kolor: AppColor.greyColor,
|
// kolor: AppColor.greyColor,
|
||||||
pricePoint:
|
// pricePoint:
|
||||||
box.read(BoxName.countryCode) ==
|
// box.read(BoxName.countryCode) ==
|
||||||
'Jordan'
|
// 'Jordan'
|
||||||
? 5
|
// ? 5
|
||||||
: 100,
|
// : 100,
|
||||||
countPoint:
|
// countPoint:
|
||||||
box.read(BoxName.countryCode) ==
|
// box.read(BoxName.countryCode) ==
|
||||||
'Jordan'
|
// 'Jordan'
|
||||||
? '300'
|
// ? '300'
|
||||||
: '100',
|
// : '100',
|
||||||
),
|
// ),
|
||||||
PointsCaptain(
|
// PointsCaptain(
|
||||||
kolor: AppColor.bronze,
|
// kolor: AppColor.bronze,
|
||||||
pricePoint:
|
// pricePoint:
|
||||||
box.read(BoxName.countryCode) ==
|
// box.read(BoxName.countryCode) ==
|
||||||
'Jordan'
|
// 'Jordan'
|
||||||
? 10
|
// ? 10
|
||||||
: 200,
|
// : 200,
|
||||||
countPoint:
|
// countPoint:
|
||||||
box.read(BoxName.countryCode) ==
|
// box.read(BoxName.countryCode) ==
|
||||||
'Jordan'
|
// 'Jordan'
|
||||||
? '1040'
|
// ? '1040'
|
||||||
: '210',
|
// : '210',
|
||||||
),
|
// ),
|
||||||
PointsCaptain(
|
// PointsCaptain(
|
||||||
kolor: AppColor.goldenBronze,
|
// kolor: AppColor.goldenBronze,
|
||||||
pricePoint:
|
// pricePoint:
|
||||||
box.read(BoxName.countryCode) ==
|
// box.read(BoxName.countryCode) ==
|
||||||
'Jordan'
|
// 'Jordan'
|
||||||
? 22
|
// ? 22
|
||||||
: 400,
|
// : 400,
|
||||||
countPoint:
|
// countPoint:
|
||||||
box.read(BoxName.countryCode) ==
|
// box.read(BoxName.countryCode) ==
|
||||||
'Jordan'
|
// 'Jordan'
|
||||||
? '2300'
|
// ? '2300'
|
||||||
: '450',
|
// : '450',
|
||||||
),
|
// ),
|
||||||
PointsCaptain(
|
// PointsCaptain(
|
||||||
kolor: AppColor.gold,
|
// kolor: AppColor.gold,
|
||||||
pricePoint:
|
// pricePoint:
|
||||||
box.read(BoxName.countryCode) ==
|
// box.read(BoxName.countryCode) ==
|
||||||
'Jordan'
|
// 'Jordan'
|
||||||
? 50
|
// ? 50
|
||||||
: 1000,
|
// : 1000,
|
||||||
countPoint:
|
// countPoint:
|
||||||
box.read(BoxName.countryCode) ==
|
// box.read(BoxName.countryCode) ==
|
||||||
'Jordan'
|
// 'Jordan'
|
||||||
? '55000'
|
// ? '55000'
|
||||||
: '1200',
|
// : '1200',
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
)),
|
// )),
|
||||||
),
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// Promo items
|
||||||
|
final rides = orderHistoryController.promoList[index];
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: CupertinoColors.systemGrey6,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color:
|
||||||
|
CupertinoColors.systemGrey.withOpacity(0.5),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
child: Padding(
|
||||||
} else {
|
padding: const EdgeInsets.all(16.0),
|
||||||
// Promo items
|
child: Column(
|
||||||
final rides = orderHistoryController.promoList[index - 1];
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
return Padding(
|
children: [
|
||||||
padding: const EdgeInsets.all(8.0),
|
Row(
|
||||||
child: Container(
|
mainAxisAlignment:
|
||||||
decoration: AppStyle.boxDecoration,
|
MainAxisAlignment.spaceBetween,
|
||||||
child: Padding(
|
children: [
|
||||||
padding: const EdgeInsets.all(8.0),
|
Column(
|
||||||
child: Column(
|
crossAxisAlignment:
|
||||||
children: [
|
CrossAxisAlignment.start,
|
||||||
Row(
|
children: [
|
||||||
mainAxisAlignment:
|
GestureDetector(
|
||||||
MainAxisAlignment.spaceBetween,
|
onTap: () {},
|
||||||
children: [
|
child: AnimatedTextKit(
|
||||||
Column(
|
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
AnimatedTextKit(
|
|
||||||
animatedTexts: [
|
animatedTexts: [
|
||||||
ScaleAnimatedText(
|
ScaleAnimatedText(
|
||||||
rides['promo_code'],
|
rides['promo_code'],
|
||||||
textStyle: AppStyle.title),
|
textStyle:
|
||||||
|
AppStyle.title.copyWith(
|
||||||
|
fontSize:
|
||||||
|
32, // Increased font size for emphasis
|
||||||
|
color:
|
||||||
|
CupertinoColors.activeBlue,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
WavyAnimatedText(
|
WavyAnimatedText(
|
||||||
rides['promo_code'],
|
rides['promo_code'],
|
||||||
textStyle: AppStyle.title),
|
textStyle:
|
||||||
FlickerAnimatedText(
|
AppStyle.title.copyWith(
|
||||||
rides['promo_code'],
|
fontSize:
|
||||||
textStyle: AppStyle.title),
|
32, // Increased font size for emphasis
|
||||||
WavyAnimatedText(
|
color:
|
||||||
rides['promo_code'],
|
CupertinoColors.activeBlue,
|
||||||
textStyle: AppStyle.title),
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
isRepeatingAnimation: true,
|
isRepeatingAnimation: true,
|
||||||
onTap: () {},
|
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
rides['description'],
|
const SizedBox(height: 8),
|
||||||
style: AppStyle.title,
|
// Description Text
|
||||||
|
Text(
|
||||||
|
rides['description'],
|
||||||
|
style: AppStyle.title.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
color: CupertinoColors.systemGrey,
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
// Only displaying end date
|
||||||
|
Text(
|
||||||
|
'${'Valid Until:'.tr} ${rides['validity_end_date']}',
|
||||||
|
style: AppStyle.subtitle.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 20,
|
||||||
|
color: CupertinoColors.systemGrey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// const SizedBox(height: 16),
|
||||||
|
// Copy Promo Text
|
||||||
|
Center(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Clipboard.setData(ClipboardData(
|
||||||
|
text: rides['promo_code']));
|
||||||
|
Get.snackbar(
|
||||||
|
'Promo Copied!'.tr,
|
||||||
|
'You have copied the promo code.'.tr,
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
backgroundColor:
|
||||||
|
CupertinoColors.systemGrey,
|
||||||
|
colorText: CupertinoColors.white,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'Copy Code'.tr,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppStyle.headTitle2.copyWith(
|
||||||
|
color: CupertinoColors.systemBlue,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
Column(
|
),
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
rides['validity_start_date'],
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
rides['validity_end_date'],
|
|
||||||
style: AppStyle.title,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
'Copy this Promo to use it in your Ride!'.tr,
|
],
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: AppStyle.headTitle2
|
|
||||||
.copyWith(color: AppColor.accentColor),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:SEFER/constant/colors.dart';
|
import 'package:SEFER/constant/colors.dart';
|
||||||
import 'package:SEFER/constant/style.dart';
|
import 'package:SEFER/constant/style.dart';
|
||||||
|
|
||||||
import '../../controller/notification/passenger_notification_controller.dart';
|
import '../../controller/notification/passenger_notification_controller.dart';
|
||||||
import '../widgets/elevated_btn.dart';
|
|
||||||
import '../widgets/my_scafold.dart';
|
import '../widgets/my_scafold.dart';
|
||||||
import '../widgets/mycircular.dart';
|
import '../widgets/mycircular.dart';
|
||||||
|
|
||||||
@@ -19,64 +19,82 @@ class NotificationPage extends StatelessWidget {
|
|||||||
title: 'Notifications',
|
title: 'Notifications',
|
||||||
body: [
|
body: [
|
||||||
GetBuilder<PassengerNotificationController>(
|
GetBuilder<PassengerNotificationController>(
|
||||||
builder: (notificationCaptainController) =>
|
builder: (notificationCaptainController) => notificationCaptainController
|
||||||
notificationCaptainController.isloading
|
.isloading
|
||||||
? const MyCircularProgressIndicator()
|
? const MyCircularProgressIndicator() // iOS-style loading indicator
|
||||||
: SafeArea(
|
: SafeArea(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: notificationCaptainController
|
itemCount: notificationCaptainController
|
||||||
.notificationData['message'].length,
|
.notificationData['message'].length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
if (notificationCaptainController
|
if (notificationCaptainController
|
||||||
.notificationData['message'] ==
|
.notificationData['message'] ==
|
||||||
"No notification data found") {
|
"No notification data found") {
|
||||||
Get.defaultDialog();
|
Get.defaultDialog(
|
||||||
}
|
title: 'No Notifications'.tr,
|
||||||
var res = notificationCaptainController
|
content: Text(
|
||||||
.notificationData['message'][index];
|
'No notification data found.'.tr,
|
||||||
return Card(
|
),
|
||||||
elevation: 4,
|
);
|
||||||
color: res['isShown'] == 'true'
|
}
|
||||||
? AppColor.secondaryColor.withOpacity(.5)
|
var res = notificationCaptainController
|
||||||
: AppColor.secondaryColor.withOpacity(.9),
|
.notificationData['message'][index];
|
||||||
child: ListTile(
|
return Padding(
|
||||||
onTap: () {
|
padding: const EdgeInsets.symmetric(
|
||||||
Get.defaultDialog(
|
horizontal: 8, vertical: 4),
|
||||||
title: res['title'],
|
child: CupertinoListTile(
|
||||||
titleStyle: AppStyle.title,
|
backgroundColor: res['isShown'] == 'true'
|
||||||
content: SizedBox(
|
? AppColor.secondaryColor.withOpacity(.2)
|
||||||
width: Get.width * .8,
|
: AppColor.secondaryColor.withOpacity(.8),
|
||||||
// height: Get.height * .4,
|
leading: res['isShown'] == 'true'
|
||||||
child: Text(
|
? const Icon(CupertinoIcons.bell_slash_fill)
|
||||||
res['body'],
|
: const Icon(CupertinoIcons.bell_fill),
|
||||||
style: AppStyle.title,
|
title: Text(
|
||||||
),
|
res['title'],
|
||||||
),
|
style: AppStyle.title.copyWith(
|
||||||
confirm: MyElevatedButton(
|
color: CupertinoColors.black,
|
||||||
title: 'Ok',
|
),
|
||||||
onPressed: () {
|
),
|
||||||
notificationCaptainController
|
subtitle: Text(
|
||||||
.updateNotification(
|
res['body'],
|
||||||
res['id'].toString());
|
style: AppStyle.subtitle.copyWith(
|
||||||
}));
|
color: CupertinoColors.systemGrey,
|
||||||
},
|
),
|
||||||
leading: res['isShown'] == 'true'
|
),
|
||||||
? const Icon(
|
onTap: () {
|
||||||
Icons.notifications_off_outlined)
|
showCupertinoDialog(
|
||||||
: const Icon(Icons.notifications_active),
|
context: context,
|
||||||
title: Text(
|
builder: (BuildContext context) {
|
||||||
res['title'],
|
return CupertinoAlertDialog(
|
||||||
style: AppStyle.title,
|
title: Text(
|
||||||
),
|
res['title'],
|
||||||
subtitle: Text(
|
style: AppStyle.title,
|
||||||
res['body'],
|
),
|
||||||
style: AppStyle.subtitle,
|
content: Text(
|
||||||
),
|
res['body'],
|
||||||
),
|
style: AppStyle.subtitle,
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
CupertinoDialogAction(
|
||||||
|
child: const Text('Ok'),
|
||||||
|
onPressed: () {
|
||||||
|
notificationCaptainController
|
||||||
|
.updateNotification(
|
||||||
|
res['id'].toString());
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
))
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
@@ -11,34 +12,98 @@ import 'elevated_btn.dart';
|
|||||||
class MyDialog extends GetxController {
|
class MyDialog extends GetxController {
|
||||||
void getDialog(String title, String? midTitle, VoidCallback onPressed) {
|
void getDialog(String title, String? midTitle, VoidCallback onPressed) {
|
||||||
final textToSpeechController = Get.put(TextToSpeechController());
|
final textToSpeechController = Get.put(TextToSpeechController());
|
||||||
Get.defaultDialog(
|
|
||||||
title: title,
|
Get.dialog(
|
||||||
titleStyle: AppStyle.title,
|
BackdropFilter(
|
||||||
barrierDismissible: false,
|
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
||||||
middleTextStyle: AppStyle.title,
|
child: CupertinoAlertDialog(
|
||||||
content: Column(
|
title: Text(
|
||||||
children: [
|
title,
|
||||||
IconButton(
|
style: AppStyle.title.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
content: Column(
|
||||||
|
children: [
|
||||||
|
CupertinoButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await textToSpeechController.speakText(title ?? midTitle!);
|
await textToSpeechController.speakText(title ?? midTitle!);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.headphones)),
|
child: const Icon(CupertinoIcons.headphones,
|
||||||
Text(
|
color: AppColor.primaryColor),
|
||||||
midTitle!,
|
),
|
||||||
style: AppStyle.title,
|
Text(
|
||||||
)
|
midTitle!,
|
||||||
|
style: AppStyle.title.copyWith(fontSize: 16),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
CupertinoDialogAction(
|
||||||
|
child: const Text('Cancel',
|
||||||
|
style: TextStyle(color: AppColor.redColor)),
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CupertinoDialogAction(
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Text('OK'.tr,
|
||||||
|
style: const TextStyle(color: AppColor.greenColor)),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
confirm: MyElevatedButton(
|
),
|
||||||
title: 'Ok'.tr,
|
barrierDismissible: false,
|
||||||
onPressed: onPressed,
|
);
|
||||||
kolor: AppColor.greenColor,
|
}
|
||||||
),
|
}
|
||||||
cancel: MyElevatedButton(
|
|
||||||
title: 'Cancel',
|
class MyDialogContent extends GetxController {
|
||||||
kolor: AppColor.redColor,
|
void getDialog(String title, Widget? content, VoidCallback onPressed) {
|
||||||
onPressed: () {
|
final textToSpeechController = Get.put(TextToSpeechController());
|
||||||
Get.back();
|
|
||||||
}));
|
Get.dialog(
|
||||||
|
BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
||||||
|
child: CupertinoAlertDialog(
|
||||||
|
title: Text(
|
||||||
|
title,
|
||||||
|
style: AppStyle.title.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
content: Column(
|
||||||
|
children: [
|
||||||
|
CupertinoButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await textToSpeechController.speakText(title);
|
||||||
|
},
|
||||||
|
child: const Icon(CupertinoIcons.speaker_2,
|
||||||
|
color: AppColor.primaryColor),
|
||||||
|
),
|
||||||
|
content!
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
CupertinoDialogAction(
|
||||||
|
child: const Text('Cancel',
|
||||||
|
style: TextStyle(color: AppColor.redColor)),
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CupertinoDialogAction(
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Text('OK'.tr,
|
||||||
|
style: const TextStyle(color: AppColor.greenColor)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
barrierDismissible: false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class MyTextForm extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
label.tr,
|
label.tr,
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
color: CupertinoColors.label,
|
color: CupertinoColors.label,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ class MyCircularProgressIndicator extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 110,
|
width: 140,
|
||||||
height: 110,
|
height: 140,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
@@ -21,13 +21,11 @@ class MyCircularProgressIndicator extends StatelessWidget {
|
|||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
const Center(child: CircularProgressIndicator()),
|
const Center(child: CircularProgressIndicator()),
|
||||||
Column(
|
Image.asset(
|
||||||
children: [
|
'assets/images/logo.gif',
|
||||||
Align(
|
width: 140,
|
||||||
alignment: Alignment.center,
|
height: 140,
|
||||||
child: Image.asset('assets/images/logo.gif'),
|
fit: BoxFit.contain,
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
69
lib/views/widgets/mysnakbar.dart
Normal file
69
lib/views/widgets/mysnakbar.dart
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../constant/colors.dart';
|
||||||
|
|
||||||
|
SnackbarController mySnackeBarError(String message) {
|
||||||
|
return Get.snackbar(
|
||||||
|
'Error'.tr,
|
||||||
|
message,
|
||||||
|
backgroundColor: AppColor.redColor.withOpacity(0.9),
|
||||||
|
colorText: AppColor.secondaryColor,
|
||||||
|
icon: const Icon(Icons.error, color: AppColor.secondaryColor),
|
||||||
|
shouldIconPulse: true,
|
||||||
|
snackPosition: SnackPosition.TOP,
|
||||||
|
margin: const EdgeInsets.all(10),
|
||||||
|
borderRadius: 10,
|
||||||
|
animationDuration: const Duration(milliseconds: 500),
|
||||||
|
forwardAnimationCurve: Curves.easeOutBack,
|
||||||
|
reverseAnimationCurve: Curves.easeInBack,
|
||||||
|
titleText: Text(
|
||||||
|
'Error'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageText: Text(
|
||||||
|
message,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white.withOpacity(0.9),
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SnackbarController mySnackbarSuccess(String message) {
|
||||||
|
return Get.snackbar(
|
||||||
|
'Success'.tr,
|
||||||
|
message,
|
||||||
|
backgroundColor: AppColor.greenColor
|
||||||
|
.withOpacity(0.9), // Assuming green color for success
|
||||||
|
colorText: AppColor.secondaryColor,
|
||||||
|
icon: const Icon(Icons.check_circle, color: AppColor.secondaryColor),
|
||||||
|
shouldIconPulse: true,
|
||||||
|
snackPosition: SnackPosition.TOP,
|
||||||
|
margin: const EdgeInsets.all(10),
|
||||||
|
borderRadius: 10,
|
||||||
|
animationDuration: const Duration(milliseconds: 500),
|
||||||
|
forwardAnimationCurve: Curves.easeOutBack,
|
||||||
|
reverseAnimationCurve: Curves.easeInBack,
|
||||||
|
titleText: Text(
|
||||||
|
'Success'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
messageText: Text(
|
||||||
|
message,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white.withOpacity(0.9),
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ import sqflite
|
|||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
import video_player_avfoundation
|
import video_player_avfoundation
|
||||||
import wakelock_plus
|
import wakelock_plus
|
||||||
|
import webview_flutter_wkwebview
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
||||||
@@ -51,4 +52,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
|
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
|
||||||
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
|
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
|
||||||
|
FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
|
|
||||||
@NSApplicationMain
|
@main
|
||||||
class AppDelegate: FlutterAppDelegate {
|
class AppDelegate: FlutterAppDelegate {
|
||||||
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||||
return true
|
return true
|
||||||
|
|||||||
127
pubspec.lock
127
pubspec.lock
@@ -5,10 +5,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
|
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "67.0.0"
|
version: "72.0.0"
|
||||||
_flutterfire_internals:
|
_flutterfire_internals:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -17,14 +17,19 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.41"
|
version: "1.3.41"
|
||||||
|
_macros:
|
||||||
|
dependency: transitive
|
||||||
|
description: dart
|
||||||
|
source: sdk
|
||||||
|
version: "0.3.2"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
|
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.4.1"
|
version: "6.7.0"
|
||||||
animated_text_kit:
|
animated_text_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -109,18 +114,18 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7"
|
sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.11"
|
version: "2.4.12"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe
|
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.3.1"
|
version: "7.3.2"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -141,26 +146,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: cached_network_image
|
name: cached_network_image
|
||||||
sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819"
|
sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.0"
|
version: "3.3.1"
|
||||||
cached_network_image_platform_interface:
|
cached_network_image_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: cached_network_image_platform_interface
|
name: cached_network_image_platform_interface
|
||||||
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
|
sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.1"
|
version: "4.0.0"
|
||||||
cached_network_image_web:
|
cached_network_image_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: cached_network_image_web
|
name: cached_network_image_web
|
||||||
sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996"
|
sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.2.0"
|
||||||
calendar_builder:
|
calendar_builder:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -189,10 +194,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: chewie
|
name: chewie
|
||||||
sha256: "8210c6e8702ddae9b3337aad0d539a9ff128cc4a5baaadc0174edbd0f99b0125"
|
sha256: e53da939709efb9aad0f3d72a69a8d05f889168b7a138af60ce78bab5c94b135
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.4"
|
version: "1.8.1"
|
||||||
cli_util:
|
cli_util:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -269,10 +274,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
|
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.6"
|
version: "2.3.7"
|
||||||
dbus:
|
dbus:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -482,10 +487,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_cache_manager
|
name: flutter_cache_manager
|
||||||
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
|
sha256: ceff65d74d907b1b772e22cf04daad60fb472461638977d9fae8b00a63e01e3d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.1"
|
version: "3.3.3"
|
||||||
|
flutter_confetti:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_confetti
|
||||||
|
sha256: "22fc66984c17aea73e3cd300666609c4581176c00c31d4513b1e16758f75cb08"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.4"
|
||||||
|
flutter_contacts:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_contacts
|
||||||
|
sha256: "388d32cd33f16640ee169570128c933b45f3259bddbfae7a100bb49e5ffea9ae"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.9+2"
|
||||||
flutter_font_icons:
|
flutter_font_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -836,10 +857,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_android
|
name: google_maps_flutter_android
|
||||||
sha256: "075f550650a907a85d00d1e48f135e9cc326f1519652eb5f8caafebacabf7727"
|
sha256: bccf64ccbb2ea672dc62a61177b315a340af86b0228564484b023657544a3fd5
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.14.5"
|
version: "2.14.11"
|
||||||
google_maps_flutter_ios:
|
google_maps_flutter_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -852,10 +873,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_maps_flutter_platform_interface
|
name: google_maps_flutter_platform_interface
|
||||||
sha256: "8ba5daee8b5d2230fea17a7903047ce4dc45fb1f0726356a1d8eb541e30c7d05"
|
sha256: a951981c22d790848efb9f114f81794945bc5c06bc566238a419a92f110af6cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.9.1"
|
version: "2.9.5"
|
||||||
google_maps_flutter_web:
|
google_maps_flutter_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -961,7 +982,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "3.2.1"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http_parser
|
name: http_parser
|
||||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||||
@@ -1012,10 +1033,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_android
|
name: image_picker_android
|
||||||
sha256: "8c5abf0dcc24fe6e8e0b4a5c0b51a5cf30cefdf6407a3213dae61edc75a70f56"
|
sha256: a26dc9a03fe042440c1e4be554fb0fceae2bf6d887d7467fc48c688fa4a81889
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.12+12"
|
version: "0.8.12+7"
|
||||||
image_picker_for_web:
|
image_picker_for_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1164,10 +1185,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: local_auth_android
|
name: local_auth_android
|
||||||
sha256: e99c44ca0bce08f26f25e2a2e07d3b443d69986e1c3acf67c1449f7d847e3625
|
sha256: "33fcebe9c3cf1bb0033bc85caed354c1e75ff7f7670918a571bd3152a2b65bf4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.43"
|
version: "1.0.42"
|
||||||
local_auth_darwin:
|
local_auth_darwin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1224,6 +1245,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
macros:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: macros
|
||||||
|
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.2-main.4"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1249,7 +1278,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0"
|
version: "1.15.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
||||||
@@ -1396,10 +1425,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_platform_interface
|
name: permission_handler_platform_interface
|
||||||
sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea
|
sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.2"
|
version: "4.2.1"
|
||||||
permission_handler_windows:
|
permission_handler_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1640,10 +1669,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4"
|
sha256: "7b41b6c3507854a159e24ae90a8e3e9cc01eb26a477c118d6dca065b5f55453e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.4"
|
version: "2.5.4+2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1704,10 +1733,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: synchronized
|
name: synchronized
|
||||||
sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
|
sha256: a824e842b8a054f91a728b783c177c1e4731f6b124f9192468457a8913371255
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0+1"
|
version: "3.2.0"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1725,7 +1754,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.2"
|
version: "0.7.2"
|
||||||
timezone:
|
timezone:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: timezone
|
name: timezone
|
||||||
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
|
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
|
||||||
@@ -1784,10 +1813,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79
|
sha256: "95d8027db36a0e52caf55680f91e33ea6aa12a3ce608c90b06f4e429a21067ac"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.9"
|
version: "6.3.5"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1904,10 +1933,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: video_player_android
|
name: video_player_android
|
||||||
sha256: e343701aa890b74a863fa460f5c0e628127ed06a975d7d9af6b697133fb25bdf
|
sha256: fdc0331ce9f808cc2714014cb8126bd6369943affefd54f8fdab0ea0bb617b7f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.7.1"
|
version: "2.5.2"
|
||||||
video_player_avfoundation:
|
video_player_avfoundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1992,10 +2021,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: webview_flutter
|
name: webview_flutter
|
||||||
sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
|
sha256: ec81f57aa1611f8ebecf1d2259da4ef052281cb5ad624131c93546c79ccc7736
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.0"
|
version: "4.9.0"
|
||||||
webview_flutter_android:
|
webview_flutter_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2016,10 +2045,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_wkwebview
|
name: webview_flutter_wkwebview
|
||||||
sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb"
|
sha256: "1942a12224ab31e9508cf00c0c6347b931b023b8a4f0811e5dec3b06f94f117d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.14.0"
|
version: "3.15.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2032,10 +2061,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32_registry
|
name: win32_registry
|
||||||
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
|
sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.4"
|
version: "1.1.3"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2061,5 +2090,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.4.0 <4.0.0"
|
dart: ">=3.5.0 <4.0.0"
|
||||||
flutter: ">=3.22.0"
|
flutter: ">=3.24.0"
|
||||||
|
|||||||
@@ -61,7 +61,11 @@ dependencies:
|
|||||||
package_info_plus: ^8.0.0
|
package_info_plus: ^8.0.0
|
||||||
uni_links: ^0.5.1
|
uni_links: ^0.5.1
|
||||||
googleapis_auth: ^1.6.0
|
googleapis_auth: ^1.6.0
|
||||||
timezone: ^0.9.4
|
flutter_confetti: ^0.3.0
|
||||||
|
# intl_phone_field: ^3.1.0
|
||||||
|
flutter_contacts: ^1.1.8
|
||||||
|
mime: ^1.0.6
|
||||||
|
http_parser: ^4.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
BIN
ride9-11.zip
Normal file
BIN
ride9-11.zip
Normal file
Binary file not shown.
@@ -1,11 +1,11 @@
|
|||||||
# This file is used to configure the Shorebird updater used by your app.
|
# This file is used to configure the Shorebird updater used by your app.
|
||||||
# Learn more at https://docs.shorebird.dev
|
# Learn more at https://docs.shorebird.dev
|
||||||
# This file should be checked into version control.
|
# This file does not contain any sensitive information and should be checked into version control.
|
||||||
|
|
||||||
# This is the unique identifier assigned to your app.
|
# Your app_id is the unique identifier assigned to your app.
|
||||||
# Your app_id is not a secret and is just used to identify your app
|
# It is used to identify your app when requesting patches from Shorebird's servers.
|
||||||
# when requesting patches from Shorebird's servers.
|
# It is not a secret and can be shared publicly.
|
||||||
app_id: 8a571d7f-dfbf-4a65-be62-17eed08cbd5c
|
app_id: 496cb3ac-c25c-455d-9d2e-5ebbea13ab03
|
||||||
|
|
||||||
# auto_update controls if Shorebird should automatically update in the background on launch.
|
# auto_update controls if Shorebird should automatically update in the background on launch.
|
||||||
# If auto_update: false, you will need to use package:shorebird_code_push to trigger updates.
|
# If auto_update: false, you will need to use package:shorebird_code_push to trigger updates.
|
||||||
|
|||||||
Reference in New Issue
Block a user