Initial commit for service
This commit is contained in:
@@ -28,7 +28,7 @@ if (keystorePropertiesFile.exists()) {
|
|||||||
android {
|
android {
|
||||||
namespace = "com.service_intaleq"
|
namespace = "com.service_intaleq"
|
||||||
compileSdk = 36
|
compileSdk = 36
|
||||||
ndkVersion = "27.0.12077973"
|
// ndkVersion = "27.0.12077973"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.service_intaleq"
|
applicationId = "com.service_intaleq"
|
||||||
@@ -39,7 +39,7 @@ android {
|
|||||||
multiDexEnabled = true
|
multiDexEnabled = true
|
||||||
|
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
abiFilters += listOf("armeabi-v7a", "arm64-v8a")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +67,7 @@ android {
|
|||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
isCoreLibraryDesugaringEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
@@ -76,7 +77,7 @@ android {
|
|||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
path = file("src/main/cpp/CMakeLists.txt")
|
path = file("src/main/cpp/CMakeLists.txt")
|
||||||
version = "3.31.5"
|
version = "3.22.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,97 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- ===== Permissions ===== -->
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
<!-- التخزين القديم (مقيَّد حسب الإصدارات) -->
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
android:maxSdkVersion="32" />
|
android:maxSdkVersion="32" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
android:maxSdkVersion="28" />
|
android:maxSdkVersion="28" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<!-- الإذن الحديث للصور على 33+ -->
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||||
|
<!-- (اختياري) تنبيهات 13+ -->
|
||||||
|
<!-- <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> -->
|
||||||
|
|
||||||
|
<!-- ===== Visibility Queries (Android 11+) =====
|
||||||
|
تمكين اكتشاف التطبيقات/الأنشطة التي تتعامل مع السكيمز:
|
||||||
|
whatsapp://, http/https, tel, sms, mailto -->
|
||||||
|
<queries>
|
||||||
|
<!-- WhatsApp -->
|
||||||
|
<package android:name="com.whatsapp" />
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="whatsapp" />
|
||||||
|
</intent>
|
||||||
|
|
||||||
|
<!-- متصفحات (http/https) -->
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="http" />
|
||||||
|
</intent>
|
||||||
|
|
||||||
|
<!-- هاتف / SMS / بريد -->
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.DIAL" />
|
||||||
|
<data android:scheme="tel" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.SENDTO" />
|
||||||
|
<data android:scheme="smsto" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.SENDTO" />
|
||||||
|
<data android:scheme="mailto" />
|
||||||
|
</intent>
|
||||||
|
|
||||||
|
<!-- تستخدمه إضافات Flutter للنصوص -->
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
|
|
||||||
|
<!-- ===== Application ===== -->
|
||||||
<application
|
<application
|
||||||
android:label="service"
|
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
android:label="service"
|
||||||
android:icon="@mipmap/launcher_icon">
|
android:icon="@mipmap/launcher_icon">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize"
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode">
|
||||||
the Android process has started. This theme is visible to the user
|
|
||||||
while the Flutter UI initializes. After that, this theme continues
|
<!-- Theme أثناء الإقلاع -->
|
||||||
to determine the Window background behind the Flutter UI. -->
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
android:resource="@style/NormalTheme"
|
android:resource="@style/NormalTheme" />
|
||||||
/>
|
|
||||||
|
<!-- نقطة دخول التطبيق -->
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<!-- Don't delete the meta-data below.
|
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
<!-- مطلوب لتسجيل البلَغنز -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
</application>
|
</application>
|
||||||
<!-- Required to query activities that can process text, see:
|
|
||||||
https://developer.android.com/training/package-visibility and
|
|
||||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
|
||||||
|
|
||||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
|
||||||
<data android:mimeType="text/plain" />
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
# platform :ios, '12.0'
|
platform :ios, '15.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|||||||
297
ios/Podfile.lock
Normal file
297
ios/Podfile.lock
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
PODS:
|
||||||
|
- AppAuth (2.0.0):
|
||||||
|
- AppAuth/Core (= 2.0.0)
|
||||||
|
- AppAuth/ExternalUserAgent (= 2.0.0)
|
||||||
|
- AppAuth/Core (2.0.0)
|
||||||
|
- AppAuth/ExternalUserAgent (2.0.0):
|
||||||
|
- AppAuth/Core
|
||||||
|
- AppCheckCore (11.2.0):
|
||||||
|
- GoogleUtilities/Environment (~> 8.0)
|
||||||
|
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||||
|
- PromisesObjC (~> 2.4)
|
||||||
|
- device_info_plus (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- Firebase/Auth (12.0.0):
|
||||||
|
- Firebase/CoreOnly
|
||||||
|
- FirebaseAuth (~> 12.0.0)
|
||||||
|
- Firebase/CoreOnly (12.0.0):
|
||||||
|
- FirebaseCore (~> 12.0.0)
|
||||||
|
- Firebase/Messaging (12.0.0):
|
||||||
|
- Firebase/CoreOnly
|
||||||
|
- FirebaseMessaging (~> 12.0.0)
|
||||||
|
- firebase_auth (6.0.0):
|
||||||
|
- Firebase/Auth (= 12.0.0)
|
||||||
|
- firebase_core
|
||||||
|
- Flutter
|
||||||
|
- firebase_core (4.0.0):
|
||||||
|
- Firebase/CoreOnly (= 12.0.0)
|
||||||
|
- Flutter
|
||||||
|
- firebase_messaging (16.0.0):
|
||||||
|
- Firebase/Messaging (= 12.0.0)
|
||||||
|
- firebase_core
|
||||||
|
- Flutter
|
||||||
|
- FirebaseAppCheckInterop (12.0.0)
|
||||||
|
- FirebaseAuth (12.0.0):
|
||||||
|
- FirebaseAppCheckInterop (~> 12.0.0)
|
||||||
|
- FirebaseAuthInterop (~> 12.0.0)
|
||||||
|
- FirebaseCore (~> 12.0.0)
|
||||||
|
- FirebaseCoreExtension (~> 12.0.0)
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
|
- GTMSessionFetcher/Core (< 6.0, >= 3.4)
|
||||||
|
- RecaptchaInterop (~> 101.0)
|
||||||
|
- FirebaseAuthInterop (12.0.0)
|
||||||
|
- FirebaseCore (12.0.0):
|
||||||
|
- FirebaseCoreInternal (~> 12.0.0)
|
||||||
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
|
- GoogleUtilities/Logger (~> 8.1)
|
||||||
|
- FirebaseCoreExtension (12.0.0):
|
||||||
|
- FirebaseCore (~> 12.0.0)
|
||||||
|
- FirebaseCoreInternal (12.0.0):
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
|
- FirebaseInstallations (12.0.0):
|
||||||
|
- FirebaseCore (~> 12.0.0)
|
||||||
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
|
- PromisesObjC (~> 2.4)
|
||||||
|
- FirebaseMessaging (12.0.0):
|
||||||
|
- FirebaseCore (~> 12.0.0)
|
||||||
|
- FirebaseInstallations (~> 12.0.0)
|
||||||
|
- GoogleDataTransport (~> 10.1)
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
|
- GoogleUtilities/Reachability (~> 8.1)
|
||||||
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
|
- Flutter (1.0.0)
|
||||||
|
- flutter_image_compress_common (1.0.0):
|
||||||
|
- Flutter
|
||||||
|
- Mantle
|
||||||
|
- SDWebImage
|
||||||
|
- SDWebImageWebPCoder
|
||||||
|
- flutter_local_notifications (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- flutter_secure_storage (6.0.0):
|
||||||
|
- Flutter
|
||||||
|
- google_sign_in_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- GoogleSignIn (~> 9.0)
|
||||||
|
- GTMSessionFetcher (>= 3.4.0)
|
||||||
|
- GoogleDataTransport (10.1.0):
|
||||||
|
- nanopb (~> 3.30910.0)
|
||||||
|
- PromisesObjC (~> 2.4)
|
||||||
|
- GoogleSignIn (9.0.0):
|
||||||
|
- AppAuth (~> 2.0)
|
||||||
|
- AppCheckCore (~> 11.0)
|
||||||
|
- GTMAppAuth (~> 5.0)
|
||||||
|
- GTMSessionFetcher/Core (~> 3.3)
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (8.1.0):
|
||||||
|
- GoogleUtilities/Environment
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- GoogleUtilities/Network
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Environment (8.1.0):
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Logger (8.1.0):
|
||||||
|
- GoogleUtilities/Environment
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Network (8.1.0):
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- "GoogleUtilities/NSData+zlib"
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Reachability
|
||||||
|
- "GoogleUtilities/NSData+zlib (8.1.0)":
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/Privacy (8.1.0)
|
||||||
|
- GoogleUtilities/Reachability (8.1.0):
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GoogleUtilities/UserDefaults (8.1.0):
|
||||||
|
- GoogleUtilities/Logger
|
||||||
|
- GoogleUtilities/Privacy
|
||||||
|
- GTMAppAuth (5.0.0):
|
||||||
|
- AppAuth/Core (~> 2.0)
|
||||||
|
- GTMSessionFetcher/Core (< 4.0, >= 3.3)
|
||||||
|
- GTMSessionFetcher (3.5.0):
|
||||||
|
- GTMSessionFetcher/Full (= 3.5.0)
|
||||||
|
- GTMSessionFetcher/Core (3.5.0)
|
||||||
|
- GTMSessionFetcher/Full (3.5.0):
|
||||||
|
- GTMSessionFetcher/Core
|
||||||
|
- image_cropper (0.0.4):
|
||||||
|
- Flutter
|
||||||
|
- TOCropViewController (~> 2.7.4)
|
||||||
|
- image_picker_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- libwebp (1.5.0):
|
||||||
|
- libwebp/demux (= 1.5.0)
|
||||||
|
- libwebp/mux (= 1.5.0)
|
||||||
|
- libwebp/sharpyuv (= 1.5.0)
|
||||||
|
- libwebp/webp (= 1.5.0)
|
||||||
|
- libwebp/demux (1.5.0):
|
||||||
|
- libwebp/webp
|
||||||
|
- libwebp/mux (1.5.0):
|
||||||
|
- libwebp/demux
|
||||||
|
- libwebp/sharpyuv (1.5.0)
|
||||||
|
- libwebp/webp (1.5.0):
|
||||||
|
- libwebp/sharpyuv
|
||||||
|
- Mantle (2.2.0):
|
||||||
|
- Mantle/extobjc (= 2.2.0)
|
||||||
|
- Mantle/extobjc (2.2.0)
|
||||||
|
- nanopb (3.30910.0):
|
||||||
|
- nanopb/decode (= 3.30910.0)
|
||||||
|
- nanopb/encode (= 3.30910.0)
|
||||||
|
- nanopb/decode (3.30910.0)
|
||||||
|
- nanopb/encode (3.30910.0)
|
||||||
|
- path_provider_foundation (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- permission_handler_apple (9.3.0):
|
||||||
|
- Flutter
|
||||||
|
- PromisesObjC (2.4.0)
|
||||||
|
- RecaptchaInterop (101.0.0)
|
||||||
|
- SDWebImage (5.21.2):
|
||||||
|
- SDWebImage/Core (= 5.21.2)
|
||||||
|
- SDWebImage/Core (5.21.2)
|
||||||
|
- SDWebImageWebPCoder (0.14.6):
|
||||||
|
- libwebp (~> 1.0)
|
||||||
|
- SDWebImage/Core (~> 5.17)
|
||||||
|
- share_plus (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- sqflite_darwin (0.0.4):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- TOCropViewController (2.7.4)
|
||||||
|
- url_launcher_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- vibration (3.0.0):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
|
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
|
||||||
|
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||||
|
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||||
|
- Flutter (from `Flutter`)
|
||||||
|
- flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`)
|
||||||
|
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||||
|
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||||
|
- google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`)
|
||||||
|
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
|
||||||
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
|
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
- vibration (from `.symlinks/plugins/vibration/ios`)
|
||||||
|
|
||||||
|
SPEC REPOS:
|
||||||
|
trunk:
|
||||||
|
- AppAuth
|
||||||
|
- AppCheckCore
|
||||||
|
- Firebase
|
||||||
|
- FirebaseAppCheckInterop
|
||||||
|
- FirebaseAuth
|
||||||
|
- FirebaseAuthInterop
|
||||||
|
- FirebaseCore
|
||||||
|
- FirebaseCoreExtension
|
||||||
|
- FirebaseCoreInternal
|
||||||
|
- FirebaseInstallations
|
||||||
|
- FirebaseMessaging
|
||||||
|
- GoogleDataTransport
|
||||||
|
- GoogleSignIn
|
||||||
|
- GoogleUtilities
|
||||||
|
- GTMAppAuth
|
||||||
|
- GTMSessionFetcher
|
||||||
|
- libwebp
|
||||||
|
- Mantle
|
||||||
|
- nanopb
|
||||||
|
- PromisesObjC
|
||||||
|
- RecaptchaInterop
|
||||||
|
- SDWebImage
|
||||||
|
- SDWebImageWebPCoder
|
||||||
|
- TOCropViewController
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
device_info_plus:
|
||||||
|
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||||
|
firebase_auth:
|
||||||
|
:path: ".symlinks/plugins/firebase_auth/ios"
|
||||||
|
firebase_core:
|
||||||
|
:path: ".symlinks/plugins/firebase_core/ios"
|
||||||
|
firebase_messaging:
|
||||||
|
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||||
|
Flutter:
|
||||||
|
:path: Flutter
|
||||||
|
flutter_image_compress_common:
|
||||||
|
:path: ".symlinks/plugins/flutter_image_compress_common/ios"
|
||||||
|
flutter_local_notifications:
|
||||||
|
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||||
|
flutter_secure_storage:
|
||||||
|
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||||
|
google_sign_in_ios:
|
||||||
|
:path: ".symlinks/plugins/google_sign_in_ios/darwin"
|
||||||
|
image_cropper:
|
||||||
|
:path: ".symlinks/plugins/image_cropper/ios"
|
||||||
|
image_picker_ios:
|
||||||
|
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||||
|
path_provider_foundation:
|
||||||
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
|
permission_handler_apple:
|
||||||
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
|
share_plus:
|
||||||
|
:path: ".symlinks/plugins/share_plus/ios"
|
||||||
|
sqflite_darwin:
|
||||||
|
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||||
|
url_launcher_ios:
|
||||||
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
|
vibration:
|
||||||
|
:path: ".symlinks/plugins/vibration/ios"
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
AppAuth: 1c1a8afa7e12f2ec3a294d9882dfa5ab7d3cb063
|
||||||
|
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
|
||||||
|
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||||
|
Firebase: 800d487043c0557d9faed71477a38d9aafb08a41
|
||||||
|
firebase_auth: 5a5603bbe7fc673f88b7c652bf9c41d6c742b545
|
||||||
|
firebase_core: 633e1851ffe1b9ab875f6467a4f574c79cef02e4
|
||||||
|
firebase_messaging: d17feef781edc84ebefe62624fb384358ad96361
|
||||||
|
FirebaseAppCheckInterop: c848d06a04030c9858ef0ae555b82035dbe470d0
|
||||||
|
FirebaseAuth: 654e4de84787c45d7265599a651038e854ccb439
|
||||||
|
FirebaseAuthInterop: 002da671896af5e8879ae117dc604ed240b86e80
|
||||||
|
FirebaseCore: 055f4ab117d5964158c833f3d5e7ec6d91648d4a
|
||||||
|
FirebaseCoreExtension: 639afb3de6abd611952be78a794c54a47fa0f361
|
||||||
|
FirebaseCoreInternal: dedc28e569a4be85f38f3d6af1070a2e12018d55
|
||||||
|
FirebaseInstallations: d4c7c958f99c8860d7fcece786314ae790e2f988
|
||||||
|
FirebaseMessaging: af49f8d7c0a3d2a017d9302c80946f45a7777dde
|
||||||
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
|
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
||||||
|
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
||||||
|
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
|
||||||
|
google_sign_in_ios: 205742c688aea0e64db9da03c33121694a365109
|
||||||
|
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||||
|
GoogleSignIn: c7f09cfbc85a1abf69187be091997c317cc33b77
|
||||||
|
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||||
|
GTMAppAuth: 217a876b249c3c585a54fd6f73e6b58c4f5c4238
|
||||||
|
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
|
||||||
|
image_cropper: c4326ea50132b1e1564499e5d32a84f01fb03537
|
||||||
|
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
||||||
|
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
||||||
|
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
||||||
|
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||||
|
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||||
|
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||||
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
|
RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba
|
||||||
|
SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a
|
||||||
|
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
|
||||||
|
share_plus: de6030e33b4e106470e09322d87cf2a4258d2d1d
|
||||||
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
|
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
|
||||||
|
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||||
|
vibration: 69774ad57825b11c951ee4c46155f455d7a592ce
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: 53a6aebc29ccee84c41f92f409fc20cd4ca011f1
|
||||||
|
|
||||||
|
COCOAPODS: 1.16.2
|
||||||
@@ -14,7 +14,9 @@
|
|||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
AF0AF264D72AAB5C072EBF63 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D353C14D406BEA76DDC4CEDD /* Pods_Runner.framework */; };
|
||||||
ED1F6F4084CE38C57593745C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F533C517F5928BDCFDC9295F /* GoogleService-Info.plist */; };
|
ED1F6F4084CE38C57593745C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F533C517F5928BDCFDC9295F /* GoogleService-Info.plist */; };
|
||||||
|
F6E92F32EE05FDB601BF08FD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A63E609133A89EEF042220B /* Pods_RunnerTests.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -43,6 +45,8 @@
|
|||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
1A63E609133A89EEF042220B /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
28D4768B792FCD16018172CA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
@@ -56,6 +60,12 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
A16DB7C708FA3D7E4D68FD93 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
B8A00C457D5850C21DE865E2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
BF0866B0BBB709298D77AE01 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
D34871C8E2C1B2113E855908 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
D353C14D406BEA76DDC4CEDD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
EEAEE25FE2EFA1AE050FF002 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
F533C517F5928BDCFDC9295F /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
F533C517F5928BDCFDC9295F /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@@ -64,6 +74,15 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
AF0AF264D72AAB5C072EBF63 /* Pods_Runner.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
DF4E3F6FDE887838D39DB349 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
F6E92F32EE05FDB601BF08FD /* Pods_RunnerTests.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -78,6 +97,29 @@
|
|||||||
path = RunnerTests;
|
path = RunnerTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
3AF11E78240F2F4936A829ED /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D353C14D406BEA76DDC4CEDD /* Pods_Runner.framework */,
|
||||||
|
1A63E609133A89EEF042220B /* Pods_RunnerTests.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
92F26F512BB0C437BB6F8B84 /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
28D4768B792FCD16018172CA /* Pods-Runner.debug.xcconfig */,
|
||||||
|
D34871C8E2C1B2113E855908 /* Pods-Runner.release.xcconfig */,
|
||||||
|
B8A00C457D5850C21DE865E2 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
A16DB7C708FA3D7E4D68FD93 /* Pods-RunnerTests.debug.xcconfig */,
|
||||||
|
BF0866B0BBB709298D77AE01 /* Pods-RunnerTests.release.xcconfig */,
|
||||||
|
EEAEE25FE2EFA1AE050FF002 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -97,6 +139,8 @@
|
|||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
F533C517F5928BDCFDC9295F /* GoogleService-Info.plist */,
|
F533C517F5928BDCFDC9295F /* GoogleService-Info.plist */,
|
||||||
|
92F26F512BB0C437BB6F8B84 /* Pods */,
|
||||||
|
3AF11E78240F2F4936A829ED /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -131,8 +175,10 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
84654B32CEBA94A3AB98B1F1 /* [CP] Check Pods Manifest.lock */,
|
||||||
331C807D294A63A400263BE5 /* Sources */,
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
331C807F294A63A400263BE5 /* Resources */,
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
|
DF4E3F6FDE887838D39DB349 /* Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -148,12 +194,15 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
A2F48F17CEBC9FC6CBB4FD8B /* [CP] Check Pods Manifest.lock */,
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
5D3AD08720B484D33EA3F7F2 /* [CP] Embed Pods Frameworks */,
|
||||||
|
639726CC45A829220CA89AB2 /* [CP] Copy Pods Resources */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -242,6 +291,62 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
};
|
};
|
||||||
|
5D3AD08720B484D33EA3F7F2 /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
639726CC45A829220CA89AB2 /* [CP] Copy Pods Resources */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Copy Pods Resources";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
84654B32CEBA94A3AB98B1F1 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
@@ -257,6 +362,28 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
|
A2F48F17CEBC9FC6CBB4FD8B /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@@ -383,6 +510,7 @@
|
|||||||
};
|
};
|
||||||
331C8088294A63A400263BE5 /* Debug */ = {
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = A16DB7C708FA3D7E4D68FD93 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@@ -400,6 +528,7 @@
|
|||||||
};
|
};
|
||||||
331C8089294A63A400263BE5 /* Release */ = {
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = BF0866B0BBB709298D77AE01 /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@@ -415,6 +544,7 @@
|
|||||||
};
|
};
|
||||||
331C808A294A63A400263BE5 /* Profile */ = {
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = EEAEE25FE2EFA1AE050FF002 /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
|||||||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@@ -4,4 +4,7 @@
|
|||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ class BoxName {
|
|||||||
static const String jwt = "jwt";
|
static const String jwt = "jwt";
|
||||||
static const String fingerPrint = "fingerPrint";
|
static const String fingerPrint = "fingerPrint";
|
||||||
static const String payMobApikey = "payMobApikey";
|
static const String payMobApikey = "payMobApikey";
|
||||||
|
static const String employeename = "employeename";
|
||||||
static const String refreshToken = "refreshToken";
|
static const String refreshToken = "refreshToken";
|
||||||
static const String tokenParent = "tokenParent";
|
static const String tokenParent = "tokenParent";
|
||||||
static const String lang = "lang";
|
static const String lang = "lang";
|
||||||
|
|||||||
@@ -9,12 +9,20 @@ class AppLink {
|
|||||||
static final String seferAlexandriaServer = Env.seferAlexandriaServer;
|
static final String seferAlexandriaServer = Env.seferAlexandriaServer;
|
||||||
static final String seferCairoServer = Env.seferCairoServer;
|
static final String seferCairoServer = Env.seferCairoServer;
|
||||||
static final String seferGizaServer = Env.seferGizaServer;
|
static final String seferGizaServer = Env.seferGizaServer;
|
||||||
|
static String paymentServer = 'https://walletintaleq.intaleq.xyz/v1/main';
|
||||||
|
static String location = 'https://api.intaleq.xyz/intaleq/ride/location';
|
||||||
|
static String locationServer =
|
||||||
|
'https://location.intaleq.xyz/intaleq/ride/location';
|
||||||
|
static String seferPaymentServer0 = box.read('seferPaymentServer');
|
||||||
|
|
||||||
|
static final String endPoint = 'https://api.intaleq.xyz/intaleq';
|
||||||
|
static final String rideServer = 'https://rides.intaleq.xyz/intaleq';
|
||||||
// static final String server = Env.serverPHP;
|
// static final String server = Env.serverPHP;
|
||||||
static String getBestDriver = "$server/Admin/driver/getBestDriver.php";
|
static String getBestDriver = "$server/Admin/driver/getBestDriver.php";
|
||||||
static final String server = 'https://intaleq.xyz/intaleq';
|
static final String server = 'https://api.intaleq.xyz/intaleq';
|
||||||
static final String jwtService = '$server/jwtService.php';
|
static final String jwtService = '$server/jwtService.php';
|
||||||
|
|
||||||
static final String endPoint = box.read(BoxName.serverChosen);
|
// static final String endPoint = box.read(BoxName.serverChosen);
|
||||||
// static final String server = Env.seferCairoServer;
|
// static final String server = Env.seferCairoServer;
|
||||||
// static const String server = "https://sefer.click/sefer/sefer";
|
// static const String server = "https://sefer.click/sefer/sefer";
|
||||||
static String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
|
static String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
|
||||||
@@ -46,16 +54,26 @@ class AppLink {
|
|||||||
static String getAccount = "$authCaptin/getAccount.php";
|
static String getAccount = "$authCaptin/getAccount.php";
|
||||||
static String test = "$server/test.php";
|
static String test = "$server/test.php";
|
||||||
static String serviceApp = "$server/serviceapp";
|
static String serviceApp = "$server/serviceapp";
|
||||||
static String getPassengersByPhone =
|
static String getPassengersByPhone = "$serviceApp/getPassengersByPhone.php";
|
||||||
"$server/serviceApp/getPassengersByPhone.php";
|
|
||||||
static String getDriverByPhone = "$serviceApp/getDriverByPhone.php";
|
static String getDriverByPhone = "$serviceApp/getDriverByPhone.php";
|
||||||
|
static String getDriverByNational = "$serviceApp/getDriverByNational.php";
|
||||||
|
static String updateDriver = "$serviceApp/updateDriver.php";
|
||||||
|
static String updateDriverToActive = "$serviceApp/updateDriverToActive.php";
|
||||||
static String getNewDriverRegister = "$serviceApp/getNewDriverRegister.php";
|
static String getNewDriverRegister = "$serviceApp/getNewDriverRegister.php";
|
||||||
|
static String getDriversPhoneNotComplete =
|
||||||
|
"$serviceApp/getDriversPhoneNotComplete.php";
|
||||||
static String addWelcomeDriverNote = "$serviceApp/addWelcomeDriverNote.php";
|
static String addWelcomeDriverNote = "$serviceApp/addWelcomeDriverNote.php";
|
||||||
static String getDriverNotCompleteRegistration =
|
static String getDriverNotCompleteRegistration =
|
||||||
"$serviceApp/getDriverNotCompleteRegistration.php";
|
"$serviceApp/getDriverNotCompleteRegistration.php";
|
||||||
|
static String deleteDriverNotCompleteRegistration =
|
||||||
|
"$serviceApp/deleteDriverNotCompleteRegistration.php";
|
||||||
|
static String getDriversWaitingActive =
|
||||||
|
"$serviceApp/getDriversWaitingActive.php";
|
||||||
static String getPassengersNotCompleteRegistration =
|
static String getPassengersNotCompleteRegistration =
|
||||||
"$serviceApp/getPassengersNotCompleteRegistration.php";
|
"$serviceApp/getPassengersNotCompleteRegistration.php";
|
||||||
static String addNotesDriver = "$serviceApp/addNotesDriver.php";
|
static String addNotesDriver = "$serviceApp/addNotesDriver.php";
|
||||||
|
static String getDriverDetailsForActivate =
|
||||||
|
"$serviceApp/getDriverDetailsForActivate.php";
|
||||||
static String getCarPlateNotEdit = "$serviceApp/getCarPlateNotEdit.php";
|
static String getCarPlateNotEdit = "$serviceApp/getCarPlateNotEdit.php";
|
||||||
static String getdriverWithoutCar = "$serviceApp/getdriverWithoutCar.php";
|
static String getdriverWithoutCar = "$serviceApp/getdriverWithoutCar.php";
|
||||||
static String getBestDriverGiza =
|
static String getBestDriverGiza =
|
||||||
|
|||||||
105
lib/controller/firbase_messge.dart
Normal file
105
lib/controller/firbase_messge.dart
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:service/controller/local_notification.dart';
|
||||||
|
import '../../constant/box_name.dart';
|
||||||
|
import '../../main.dart';
|
||||||
|
import '../../print.dart';
|
||||||
|
|
||||||
|
class FirebaseMessagesController extends GetxController {
|
||||||
|
final fcmToken = FirebaseMessaging.instance;
|
||||||
|
|
||||||
|
List<String> tokens = [];
|
||||||
|
List dataTokens = [];
|
||||||
|
late String driverID;
|
||||||
|
late String driverToken;
|
||||||
|
NotificationSettings? notificationSettings;
|
||||||
|
|
||||||
|
Future<void> getNotificationSettings() async {
|
||||||
|
// Get the current notification settings
|
||||||
|
NotificationSettings? notificationSettings =
|
||||||
|
await FirebaseMessaging.instance.getNotificationSettings();
|
||||||
|
'Notification authorization status: ${notificationSettings.authorizationStatus}';
|
||||||
|
|
||||||
|
// Call the update function if needed
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> requestFirebaseMessagingPermission() async {
|
||||||
|
FirebaseMessaging messaging = FirebaseMessaging.instance;
|
||||||
|
|
||||||
|
// Check if the platform is Android
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
// Request permission for Android
|
||||||
|
await messaging.requestPermission();
|
||||||
|
} else if (Platform.isIOS) {
|
||||||
|
// Request permission for iOS
|
||||||
|
NotificationSettings settings = await messaging.requestPermission(
|
||||||
|
alert: true,
|
||||||
|
announcement: true,
|
||||||
|
badge: true,
|
||||||
|
carPlay: true,
|
||||||
|
criticalAlert: true,
|
||||||
|
provisional: false,
|
||||||
|
sound: true,
|
||||||
|
);
|
||||||
|
messaging.setForegroundNotificationPresentationOptions(
|
||||||
|
alert: true, badge: true, sound: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationController notificationController =
|
||||||
|
// Get.isRegistered<NotificationController>()
|
||||||
|
// ? Get.find<NotificationController>()
|
||||||
|
// : Get.put(NotificationController());
|
||||||
|
|
||||||
|
Future getToken() async {
|
||||||
|
fcmToken.getToken().then((token) {
|
||||||
|
// Log.print('fcmToken: ${token}');
|
||||||
|
box.write(BoxName.tokenFCM, (token.toString()));
|
||||||
|
});
|
||||||
|
// 🔹 الاشتراك في topic
|
||||||
|
await fcmToken.subscribeToTopic("service"); // أو "users" حسب نوع المستخدم
|
||||||
|
print("Subscribed to 'service' topic ✅");
|
||||||
|
|
||||||
|
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||||
|
// If the app is in the background or terminated, show a system tray message
|
||||||
|
RemoteNotification? notification = message.notification;
|
||||||
|
AndroidNotification? android = notification?.android;
|
||||||
|
// if (notification != null && android != null) {
|
||||||
|
if (message.data.isNotEmpty && message.notification != null) {
|
||||||
|
fireBaseTitles(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
FirebaseMessaging.onBackgroundMessage((RemoteMessage message) async {
|
||||||
|
// Handle background message
|
||||||
|
if (message.data.isNotEmpty && message.notification != null) {
|
||||||
|
fireBaseTitles(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
||||||
|
if (message.data.isNotEmpty && message.notification != null) {
|
||||||
|
fireBaseTitles(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> fireBaseTitles(RemoteMessage message) async {
|
||||||
|
// [!! تعديل !!]
|
||||||
|
// اقرأ "النوع" من حمولة البيانات، وليس من العنوان
|
||||||
|
String category = message.data['category'] ?? '';
|
||||||
|
|
||||||
|
// اقرأ العنوان (للعرض)
|
||||||
|
String title = message.notification?.title ?? '';
|
||||||
|
String body = message.notification?.body ?? '';
|
||||||
|
|
||||||
|
if (category == 'new_service_request') {
|
||||||
|
// <-- مثال: كان 'Order'.tr
|
||||||
|
Log.print('message: ${message}');
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
NotificationController().showNotification(title, body, 'Order');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,35 +17,25 @@ import 'initilize.dart';
|
|||||||
|
|
||||||
class CRUD {
|
class CRUD {
|
||||||
var dev;
|
var dev;
|
||||||
getJWT() async {
|
getJWT(String pass, email) async {
|
||||||
var dev = Platform.isAndroid ? 'android' : 'ios';
|
var dev = Platform.isAndroid ? 'android' : 'ios';
|
||||||
var payload = {
|
var payload = {
|
||||||
'password': AK.passnpassenger,
|
'password': box.read(BoxName.password) ?? pass,
|
||||||
// 'email': box.read(BoxName.email),
|
'email': box.read(BoxName.email) ?? email,
|
||||||
'aud': '${AK.allowed}$dev',
|
'aud': '${AK.allowed}$dev',
|
||||||
};
|
};
|
||||||
// if (box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
|
|
||||||
var response0 = await http.post(
|
var response0 = await http.post(
|
||||||
Uri.parse(AppLink.jwtService),
|
Uri.parse(AppLink.jwtService),
|
||||||
body: payload,
|
body: payload,
|
||||||
);
|
);
|
||||||
print(response0.body);
|
|
||||||
print(response0.request);
|
|
||||||
if (response0.statusCode == 200) {
|
if (response0.statusCode == 200) {
|
||||||
final decodedResponse1 = jsonDecode(response0.body);
|
final decodedResponse1 = jsonDecode(response0.body);
|
||||||
|
|
||||||
final jwt = decodedResponse1['jwt'];
|
final jwt = decodedResponse1['jwt'];
|
||||||
|
Log.print('jwt: ${jwt}');
|
||||||
box.write(BoxName.jwt, X.c(X.c(X.c(jwt, cn), cC), cs));
|
box.write(BoxName.jwt, X.c(X.c(X.c(jwt, cn), cC), cs));
|
||||||
|
}
|
||||||
// await AppInitializer().getAIKey(Service.keyOfApp);
|
|
||||||
// await AppInitializer().getAIKey(Service.initializationVector);
|
|
||||||
// await Future.delayed(Duration.zero);
|
|
||||||
await EncryptionHelper.initialize();
|
|
||||||
|
|
||||||
// await AppInitializer().getAIKey(Service.FCM_PRIVATE_KEY);
|
|
||||||
box.write(BoxName.firstTimeLoadKey, 'false');
|
|
||||||
// await AppInitializer().getKey();
|
|
||||||
} else {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> get({
|
Future<dynamic> get({
|
||||||
@@ -61,7 +51,7 @@ class CRUD {
|
|||||||
.split(AppInformation.addd)[0]);
|
.split(AppInformation.addd)[0]);
|
||||||
|
|
||||||
if (isTokenExpired) {
|
if (isTokenExpired) {
|
||||||
await getJWT();
|
await getJWT(box.read(BoxName.password), box.read(BoxName.email));
|
||||||
}
|
}
|
||||||
var response = await http.post(
|
var response = await http.post(
|
||||||
url,
|
url,
|
||||||
@@ -72,10 +62,13 @@ class CRUD {
|
|||||||
'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
|
'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
print(response.request);
|
Log.print('esponse.body: ${response.body}');
|
||||||
Log.print('response.body: ${response.body}');
|
Log.print('esponse.req: ${response.request}');
|
||||||
print(payload); // if (response.statusCode == 200) {
|
Log.print('payload: ${payload}');
|
||||||
|
|
||||||
var jsonData = jsonDecode(response.body);
|
var jsonData = jsonDecode(response.body);
|
||||||
|
|
||||||
|
Log.print('jsonData: ${jsonData}');
|
||||||
if (jsonData['status'] == 'success') {
|
if (jsonData['status'] == 'success') {
|
||||||
return response.body;
|
return response.body;
|
||||||
}
|
}
|
||||||
@@ -179,7 +172,7 @@ class CRUD {
|
|||||||
.split(AppInformation.addd)[0]);
|
.split(AppInformation.addd)[0]);
|
||||||
|
|
||||||
if (isTokenExpired) {
|
if (isTokenExpired) {
|
||||||
await getJWT();
|
await getJWT(box.read(BoxName.password), box.read(BoxName.email));
|
||||||
}
|
}
|
||||||
var response = await http.post(
|
var response = await http.post(
|
||||||
url,
|
url,
|
||||||
@@ -190,10 +183,10 @@ class CRUD {
|
|||||||
'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
|
'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
print(response.request);
|
Log.print('req: ${response.request}');
|
||||||
Log.print('response.body: ${response.body}');
|
Log.print('res: ${response.body}');
|
||||||
print(payload);
|
|
||||||
var jsonData = jsonDecode(response.body);
|
var jsonData = jsonDecode(response.body);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
if (jsonData['status'] == 'success') {
|
if (jsonData['status'] == 'success') {
|
||||||
return response.body;
|
return response.body;
|
||||||
|
|||||||
@@ -15,19 +15,19 @@ import '../../print.dart';
|
|||||||
class AppInitializer {
|
class AppInitializer {
|
||||||
List<Map<String, dynamic>> links = [];
|
List<Map<String, dynamic>> links = [];
|
||||||
|
|
||||||
Future<void> initializeApp() async {
|
// Future<void> initializeApp() async {
|
||||||
if (box.read(BoxName.jwt) == null) {
|
// if (box.read(BoxName.jwt) == null) {
|
||||||
await CRUD().getJWT();
|
// await CRUD().getJWT();
|
||||||
} else {
|
// } else {
|
||||||
bool isTokenExpired = JwtDecoder.isExpired(X
|
// bool isTokenExpired = JwtDecoder.isExpired(X
|
||||||
.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs)
|
// .r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs)
|
||||||
.toString()
|
// .toString()
|
||||||
.split(AppInformation.addd)[0]);
|
// .split(AppInformation.addd)[0]);
|
||||||
if (isTokenExpired) {
|
// if (isTokenExpired) {
|
||||||
await CRUD().getJWT();
|
// await CRUD().getJWT();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
getAIKey(String key1) async {
|
getAIKey(String key1) async {
|
||||||
if (box.read(BoxName.firstTimeLoadKey) == null) {
|
if (box.read(BoxName.firstTimeLoadKey) == null) {
|
||||||
@@ -35,7 +35,6 @@ class AppInitializer {
|
|||||||
await CRUD().get(link: Env.getapiKey, payload: {"keyName": key1});
|
await CRUD().get(link: Env.getapiKey, payload: {"keyName": key1});
|
||||||
if (res != 'failure') {
|
if (res != 'failure') {
|
||||||
var d = jsonDecode(res)['message'];
|
var d = jsonDecode(res)['message'];
|
||||||
Log.print('d: ${d}');
|
|
||||||
await storage.write(key: key1, value: d[key1].toString());
|
await storage.write(key: key1, value: d[key1].toString());
|
||||||
await Future.delayed(Duration.zero);
|
await Future.delayed(Duration.zero);
|
||||||
} else {}
|
} else {}
|
||||||
|
|||||||
@@ -46,9 +46,14 @@ class MyTranslation extends Translations {
|
|||||||
"Dark Red": "نبيتي",
|
"Dark Red": "نبيتي",
|
||||||
"Sky Blue": "أزرق سماوي",
|
"Sky Blue": "أزرق سماوي",
|
||||||
"Mocha": "موكا",
|
"Mocha": "موكا",
|
||||||
|
'Drivers Activity': "نشاط السائقين",
|
||||||
|
'Drivers phones not register': "هواتف السائقين غير مسجلة",
|
||||||
|
'Register new driver': "تسجيل سائق جديد",
|
||||||
"Champagne": "شامبان",
|
"Champagne": "شامبان",
|
||||||
|
'Drivers waitting Register': "السائقون في انتظار التسجيل",
|
||||||
"Bronze": "برونزي",
|
"Bronze": "برونزي",
|
||||||
"Maroon": "ماروني",
|
"Maroon": "ماروني",
|
||||||
|
'Drivers Want Register': "السائقون يريدون التسجيل",
|
||||||
"Capture an Image of Your Criminal Record":
|
"Capture an Image of Your Criminal Record":
|
||||||
"التقط صورة لسجلك الجنائي",
|
"التقط صورة لسجلك الجنائي",
|
||||||
"IssueDate": "تاريخ الإصدار",
|
"IssueDate": "تاريخ الإصدار",
|
||||||
|
|||||||
331
lib/controller/local_notification.dart
Normal file
331
lib/controller/local_notification.dart
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
|
|
||||||
|
import '../../main.dart';
|
||||||
|
|
||||||
|
class NotificationController extends GetxController {
|
||||||
|
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
|
||||||
|
FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
initNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializes the local notifications plugin
|
||||||
|
Future<void> initNotifications() async {
|
||||||
|
const AndroidInitializationSettings android =
|
||||||
|
AndroidInitializationSettings('@mipmap/launcher_icon');
|
||||||
|
DarwinInitializationSettings ios = DarwinInitializationSettings(
|
||||||
|
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);
|
||||||
|
|
||||||
|
tz.initializeTimeZones();
|
||||||
|
print('Notifications initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Displays a notification with the given title and message
|
||||||
|
void showNotification(String title, String message, String tone) async {
|
||||||
|
final AndroidNotificationDetails android = AndroidNotificationDetails(
|
||||||
|
'high_importance_channel',
|
||||||
|
'High Importance Notifications',
|
||||||
|
importance: Importance.max,
|
||||||
|
priority: Priority.high,
|
||||||
|
showWhen: false,
|
||||||
|
sound: RawResourceAndroidNotificationSound(tone),
|
||||||
|
);
|
||||||
|
|
||||||
|
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);
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
void scheduleNotificationsForTimeSelected(
|
||||||
|
String title, String message, String tone, DateTime timeSelected) 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 10 and 30 minutes before the timeSelected
|
||||||
|
await _scheduleNotificationForTimeVIP(
|
||||||
|
timeSelected.subtract(const Duration(minutes: 10)), // 10 minutes before
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
details,
|
||||||
|
1, // Unique ID for 10-minute before notification
|
||||||
|
);
|
||||||
|
|
||||||
|
await _scheduleNotificationForTimeVIP(
|
||||||
|
timeSelected.subtract(const Duration(minutes: 30)), // 30 minutes before
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
details,
|
||||||
|
2, // Unique ID for 30-minute before notification
|
||||||
|
);
|
||||||
|
|
||||||
|
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.absoluteTime,
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,10 +5,15 @@ import 'package:get/get.dart';
|
|||||||
import 'package:service/constant/links.dart';
|
import 'package:service/constant/links.dart';
|
||||||
import 'package:service/controller/functions/crud.dart';
|
import 'package:service/controller/functions/crud.dart';
|
||||||
|
|
||||||
|
import '../constant/box_name.dart';
|
||||||
|
import '../main.dart';
|
||||||
|
import '../print.dart';
|
||||||
import '../views/home/main.dart';
|
import '../views/home/main.dart';
|
||||||
|
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
|
||||||
|
import 'functions/initilize.dart';
|
||||||
|
|
||||||
class LoginController extends GetxController {
|
class LoginController extends GetxController {
|
||||||
var email = TextEditingController();
|
var email = TextEditingController();
|
||||||
var password = TextEditingController();
|
var password = TextEditingController();
|
||||||
@@ -21,28 +26,59 @@ class LoginController extends GetxController {
|
|||||||
String? storedEmail = await storage.read(key: 'email');
|
String? storedEmail = await storage.read(key: 'email');
|
||||||
String? storedPassword = await storage.read(key: 'password');
|
String? storedPassword = await storage.read(key: 'password');
|
||||||
|
|
||||||
|
await CRUD()
|
||||||
|
.getJWT(storedPassword ?? password.text, storedEmail ?? email.text);
|
||||||
|
|
||||||
if (storedEmail != null) {
|
if (storedEmail != null) {
|
||||||
Get.off(() => Main());
|
var payload = {
|
||||||
|
"email": storedEmail,
|
||||||
|
"password": storedPassword,
|
||||||
|
};
|
||||||
|
Log.print('payload: ${payload}');
|
||||||
|
var res = await CRUD().get(link: AppLink.login, payload: payload);
|
||||||
|
Log.print('res: ${res}');
|
||||||
|
|
||||||
|
// if (res != 'failure') {
|
||||||
|
var d = jsonDecode(res);
|
||||||
|
Log.print('d: ${d}');
|
||||||
|
if (d['message'] == "Login successful") {
|
||||||
|
// Save data securely in FlutterSecureStorage
|
||||||
|
|
||||||
|
await box.write(BoxName.employeename, d['data']['first_name']);
|
||||||
|
Get.off(() => Main());
|
||||||
|
// }
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
var res = await CRUD().get(link: AppLink.login, payload: {
|
var payload = {
|
||||||
"email": storedEmail ?? email.text,
|
"email": storedEmail ?? email.text,
|
||||||
"password": storedPassword ?? password.text,
|
"password": storedPassword ?? password.text,
|
||||||
});
|
};
|
||||||
|
Log.print('payload: ${payload}');
|
||||||
|
var res = await CRUD().get(link: AppLink.login, payload: payload);
|
||||||
|
Log.print('res: ${res}');
|
||||||
|
|
||||||
if (res != 'failure') {
|
// if (res != 'failure') {
|
||||||
var d = jsonDecode(res);
|
var d = jsonDecode(res);
|
||||||
if (d['message'] == "Login successful") {
|
Log.print('d: ${d}');
|
||||||
// Save data securely in FlutterSecureStorage
|
if (d['message'] == "Login successful") {
|
||||||
await storage.write(key: 'email', value: d['data']['email']);
|
// Save data securely in FlutterSecureStorage
|
||||||
await storage.write(key: 'name', value: d['data']['first_name']);
|
await storage.write(key: 'email', value: d['data']['email']);
|
||||||
await storage.write(key: 'driverID', value: d['data']['id']);
|
await storage.write(key: 'name', value: d['data']['first_name']);
|
||||||
await storage.write(key: 'password', value: password.text);
|
await storage.write(key: 'driverID', value: d['data']['id']);
|
||||||
|
await storage.write(key: 'password', value: password.text);
|
||||||
|
await box.write(BoxName.employeename, d['data']['first_name']);
|
||||||
|
|
||||||
Get.off(() => Main());
|
Get.off(() => Main());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
login();
|
||||||
|
super.onInit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -71,6 +72,27 @@ class MainController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateDriverField(String key, dynamic value) async {
|
||||||
|
// Update locally
|
||||||
|
driverData['message'][0][key] = value;
|
||||||
|
Log.print('driverData: ${driverData['message'][0]['driverID']}');
|
||||||
|
update();
|
||||||
|
|
||||||
|
var res = await CRUD().post(link: AppLink.updateDriver, payload: {
|
||||||
|
'driverID': driverData['message'][0]['driverID'].toString(),
|
||||||
|
key: value.toString(),
|
||||||
|
});
|
||||||
|
if (res == 'failure') {
|
||||||
|
Get.snackbar('Error', 'Failed to update driver data',
|
||||||
|
backgroundColor: AppColor.redColor);
|
||||||
|
} else {
|
||||||
|
Get.snackbar('Success', 'Driver data updated successfully',
|
||||||
|
backgroundColor: AppColor.greenColor);
|
||||||
|
}
|
||||||
|
// Optionally fetch driver again
|
||||||
|
// await getDriverData();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> makePhoneCall(String phoneNumber) async {
|
Future<void> makePhoneCall(String phoneNumber) async {
|
||||||
final Uri launchUri = Uri(
|
final Uri launchUri = Uri(
|
||||||
scheme: 'tel',
|
scheme: 'tel',
|
||||||
@@ -79,25 +101,29 @@ class MainController extends GetxController {
|
|||||||
await launchUrl(launchUri);
|
await launchUrl(launchUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
void launchCommunication(
|
Future<void> launchCommunication(
|
||||||
String method, String contactInfo, String message) async {
|
String method, String contactInfo, String message) async {
|
||||||
String url;
|
// رقّم فقط (بدون + أو مسافات)
|
||||||
|
final phone = contactInfo.replaceAll(RegExp(r'[^0-9]'), '');
|
||||||
|
final encodedMsg = Uri.encodeComponent(message);
|
||||||
|
|
||||||
|
Uri? uri;
|
||||||
|
|
||||||
if (Platform.isIOS) {
|
if (Platform.isIOS) {
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'phone':
|
case 'phone':
|
||||||
url = 'tel:$contactInfo';
|
uri = Uri.parse('tel:$phone');
|
||||||
break;
|
break;
|
||||||
case 'sms':
|
case 'sms':
|
||||||
url = 'sms:$contactInfo?body=${Uri.encodeComponent(message)}';
|
uri = Uri.parse('sms:$phone?body=$encodedMsg');
|
||||||
break;
|
break;
|
||||||
case 'whatsapp':
|
case 'whatsapp':
|
||||||
url =
|
uri = Uri.parse(
|
||||||
'https://api.whatsapp.com/send?phone=$contactInfo&text=${Uri.encodeComponent(message)}';
|
'https://api.whatsapp.com/send?phone=$phone&text=$encodedMsg');
|
||||||
break;
|
break;
|
||||||
case 'email':
|
case 'email':
|
||||||
url =
|
uri =
|
||||||
'mailto:$contactInfo?subject=Subject&body=${Uri.encodeComponent(message)}';
|
Uri.parse('mailto:$contactInfo?subject=Subject&body=$encodedMsg');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@@ -105,27 +131,32 @@ class MainController extends GetxController {
|
|||||||
} else if (Platform.isAndroid) {
|
} else if (Platform.isAndroid) {
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'phone':
|
case 'phone':
|
||||||
url = 'tel:$contactInfo';
|
uri = Uri.parse('tel:$phone');
|
||||||
break;
|
break;
|
||||||
case 'sms':
|
case 'sms':
|
||||||
url = 'sms:$contactInfo?body=${Uri.encodeComponent(message)}';
|
uri = Uri.parse('sms:$phone?body=$encodedMsg');
|
||||||
break;
|
break;
|
||||||
case 'whatsapp':
|
case 'whatsapp':
|
||||||
// Check if WhatsApp is installed
|
{
|
||||||
final bool whatsappInstalled =
|
final waDeepLink =
|
||||||
await canLaunchUrl(Uri.parse('whatsapp://'));
|
Uri.parse('whatsapp://send?phone=$phone&text=$encodedMsg');
|
||||||
if (whatsappInstalled) {
|
if (await canLaunchUrl(waDeepLink)) {
|
||||||
url =
|
await launchUrl(waDeepLink, mode: LaunchMode.externalApplication);
|
||||||
'whatsapp://send?phone=$contactInfo&text=${Uri.encodeComponent(message)}';
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Provide an alternative action, such as opening the WhatsApp Web API
|
final webUri = Uri.parse(
|
||||||
url =
|
'https://api.whatsapp.com/send?phone=$phone&text=$encodedMsg');
|
||||||
'https://api.whatsapp.com/send?phone=$contactInfo&text=${Uri.encodeComponent(message)}';
|
if (await canLaunchUrl(webUri)) {
|
||||||
|
await launchUrl(webUri, mode: LaunchMode.externalApplication);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// لو ما في متصفح أساسًا
|
||||||
|
throw 'No handler for WhatsApp links';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 'email':
|
case 'email':
|
||||||
url =
|
uri =
|
||||||
'mailto:$contactInfo?subject=Subject&body=${Uri.encodeComponent(message)}';
|
Uri.parse('mailto:$contactInfo?subject=Subject&body=$encodedMsg');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@@ -134,9 +165,14 @@ class MainController extends GetxController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await canLaunchUrl(Uri.parse(url))) {
|
if (uri != null) {
|
||||||
await launchUrl(Uri.parse(url));
|
final ok = await canLaunchUrl(uri);
|
||||||
} else {}
|
if (ok) {
|
||||||
|
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||||
|
} else {
|
||||||
|
// ممكن تضيف Snackbar/Toast هنا
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List driverNotCompleteRegistration = [];
|
List driverNotCompleteRegistration = [];
|
||||||
@@ -153,6 +189,48 @@ class MainController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteDriverNotCompleteRegistration(String phone) async {
|
||||||
|
var res = await CRUD()
|
||||||
|
.get(link: AppLink.deleteDriverNotCompleteRegistration, payload: {
|
||||||
|
'phone': phone,
|
||||||
|
});
|
||||||
|
if (res != 'failure') {
|
||||||
|
Get.snackbar(res, '', backgroundColor: AppColor.greenColor);
|
||||||
|
// await getDriverWantCompleteRegistration();
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
Get.snackbar(res, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List driverWantCompleteRegistration = [];
|
||||||
|
getDriverWantCompleteRegistration() async {
|
||||||
|
var res =
|
||||||
|
await CRUD().get(link: AppLink.getDriversWaitingActive, payload: {});
|
||||||
|
if (res != 'failure') {
|
||||||
|
var d = jsonDecode(res)['message'];
|
||||||
|
driverWantCompleteRegistration = d;
|
||||||
|
filteredDrivers = driverWantCompleteRegistration;
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
Get.snackbar(res, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List driversPhoneNotComplete = [];
|
||||||
|
getDriversPhoneNotComplete() async {
|
||||||
|
var res =
|
||||||
|
await CRUD().get(link: AppLink.getDriversPhoneNotComplete, payload: {});
|
||||||
|
if (res != 'failure') {
|
||||||
|
var d = jsonDecode(res)['message'];
|
||||||
|
driverWantCompleteRegistration = d;
|
||||||
|
filteredDrivers = driverWantCompleteRegistration;
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
Get.snackbar(res, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List newDriverRegister = [];
|
List newDriverRegister = [];
|
||||||
getNewDriverRegister() async {
|
getNewDriverRegister() async {
|
||||||
var res = await CRUD().get(link: AppLink.getNewDriverRegister, payload: {});
|
var res = await CRUD().get(link: AppLink.getNewDriverRegister, payload: {});
|
||||||
@@ -364,6 +442,7 @@ class MainController extends GetxController {
|
|||||||
payload: {"phone": phone, "editor": editor, "note": note});
|
payload: {"phone": phone, "editor": editor, "note": note});
|
||||||
if (res != 'failure') {
|
if (res != 'failure') {
|
||||||
Get.snackbar(res, '', backgroundColor: AppColor.greenColor);
|
Get.snackbar(res, '', backgroundColor: AppColor.greenColor);
|
||||||
|
getDriversPhoneNotComplete();
|
||||||
notesController.clear();
|
notesController.clear();
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar(res, '', backgroundColor: AppColor.redColor);
|
Get.snackbar(res, '', backgroundColor: AppColor.redColor);
|
||||||
@@ -387,6 +466,22 @@ class MainController extends GetxController {
|
|||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
await getDriverByPhone();
|
await getDriverByPhone();
|
||||||
Get.back();
|
Get.back();
|
||||||
|
if (driverData.isEmpty) {
|
||||||
|
Get.snackbar('Error', 'Driver not found', backgroundColor: Colors.red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Get.to(() => DriverPage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchDriverByNational() async {
|
||||||
|
if (formKey.currentState!.validate()) {
|
||||||
|
await getDriverByNational();
|
||||||
|
Get.back();
|
||||||
|
if (driverData.isEmpty) {
|
||||||
|
Get.snackbar('Error', 'Driver not found', backgroundColor: Colors.red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Get.to(() => DriverPage());
|
Get.to(() => DriverPage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -394,7 +489,7 @@ class MainController extends GetxController {
|
|||||||
getPassengersByPhone() async {
|
getPassengersByPhone() async {
|
||||||
var res = await CRUD().get(
|
var res = await CRUD().get(
|
||||||
link: AppLink.getPassengersByPhone,
|
link: AppLink.getPassengersByPhone,
|
||||||
payload: {"phone": '+2${passengerPhoneController.text}'});
|
payload: {"phone": passengerPhoneController.text});
|
||||||
|
|
||||||
if (res != 'failure') {
|
if (res != 'failure') {
|
||||||
var d = jsonDecode(res);
|
var d = jsonDecode(res);
|
||||||
@@ -406,12 +501,28 @@ class MainController extends GetxController {
|
|||||||
getDriverByPhone() async {
|
getDriverByPhone() async {
|
||||||
var res = await CRUD().get(
|
var res = await CRUD().get(
|
||||||
link: AppLink.getDriverByPhone,
|
link: AppLink.getDriverByPhone,
|
||||||
payload: {"phone": '+2${driverPhoneController.text}'});
|
payload: {"phone": driverPhoneController.text});
|
||||||
|
|
||||||
if (res != 'failure') {
|
if (res != 'failure') {
|
||||||
var d = jsonDecode(res);
|
var d = jsonDecode(res);
|
||||||
driverData = d;
|
driverData = d;
|
||||||
update();
|
update();
|
||||||
|
} else {
|
||||||
|
Get.snackbar('Error', 'Driver not found', backgroundColor: Colors.red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDriverByNational() async {
|
||||||
|
var res = await CRUD().get(
|
||||||
|
link: AppLink.getDriverByNational,
|
||||||
|
payload: {"national_number": driverPhoneController.text});
|
||||||
|
|
||||||
|
if (res != 'failure') {
|
||||||
|
var d = jsonDecode(res);
|
||||||
|
driverData = d;
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
Get.snackbar('Error', 'Driver not found', backgroundColor: Colors.red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class AddCarForm extends StatelessWidget {
|
|||||||
AppLink.uploadEgypt, carData['id'], 'car_front');
|
AppLink.uploadEgypt, carData['id'], 'car_front');
|
||||||
},
|
},
|
||||||
child: Image.network(
|
child: Image.network(
|
||||||
'https://sefer.click/sefer/card_image/car_front-${carData['id']}.jpg',
|
'${AppLink.server}/card_image/car_front-${carData['id']}.jpg',
|
||||||
height: 200,
|
height: 200,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
@@ -100,7 +100,7 @@ class AddCarForm extends StatelessWidget {
|
|||||||
StackTrace? stackTrace) {
|
StackTrace? stackTrace) {
|
||||||
// If the image fails to load, use the _copy version
|
// If the image fails to load, use the _copy version
|
||||||
return Image.network(
|
return Image.network(
|
||||||
'https://sefer.click/sefer/card_image/car_front-${carData['id']}_copy.jpg',
|
'${AppLink.server}/card_image/car_front-${carData['id']}_copy.jpg',
|
||||||
height: 200,
|
height: 200,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
@@ -114,7 +114,7 @@ class AddCarForm extends StatelessWidget {
|
|||||||
AppLink.uploadEgypt, carData['id'], 'car_back');
|
AppLink.uploadEgypt, carData['id'], 'car_back');
|
||||||
},
|
},
|
||||||
child: Image.network(
|
child: Image.network(
|
||||||
'https://sefer.click/sefer/card_image/car_back-${carData['id']}.jpg',
|
'${AppLink.server}/card_image/car_back-${carData['id']}.jpg',
|
||||||
height: 200,
|
height: 200,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
@@ -122,7 +122,7 @@ class AddCarForm extends StatelessWidget {
|
|||||||
StackTrace? stackTrace) {
|
StackTrace? stackTrace) {
|
||||||
// If the image fails to load, use the _copy version
|
// If the image fails to load, use the _copy version
|
||||||
return Image.network(
|
return Image.network(
|
||||||
'https://sefer.click/sefer/card_image/car_back-${carData['id']}_copy.jpg',
|
'${AppLink.server}/card_image/car_back-${carData['id']}_copy.jpg',
|
||||||
height: 200,
|
height: 200,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
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:service/views/widgets/my_scafold.dart';
|
|
||||||
|
|
||||||
import '../main_controller.dart';
|
import '../main_controller.dart';
|
||||||
|
|
||||||
class DriverPage extends StatelessWidget {
|
class DriverPage extends StatelessWidget {
|
||||||
DriverPage({super.key});
|
DriverPage({super.key});
|
||||||
MainController mainController = MainController();
|
|
||||||
|
final MainController mainController = Get.find<MainController>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: GetBuilder<MainController>(builder: (mainController) {
|
body: GetBuilder<MainController>(builder: (mainController) {
|
||||||
Map data = mainController.driverData['message'][0];
|
Map data = mainController.driverData['message'][0];
|
||||||
|
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
middle: Text('${data['first_name']} ${data['last_name']}'),
|
middle: Text('${data['first_name']} ${data['last_name']}'),
|
||||||
@@ -21,16 +23,11 @@ class DriverPage extends StatelessWidget {
|
|||||||
child: CupertinoScrollbar(
|
child: CupertinoScrollbar(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
_buildDriverInfoSection(
|
_buildDriverInfoSection(data),
|
||||||
mainController.driverData['message'][0]),
|
_buildStatisticsSection(data),
|
||||||
_buildStatisticsSection(
|
_buildCarInfoSection(data),
|
||||||
mainController.driverData['message'][0]),
|
_buildLicenseInfoSection(data),
|
||||||
_buildCarInfoSection(mainController.driverData['message'][0]),
|
_buildBankInfoSection(data),
|
||||||
_buildLicenseInfoSection(
|
|
||||||
mainController.driverData['message'][0]),
|
|
||||||
_buildBankInfoSection(
|
|
||||||
mainController.driverData['message'][0]),
|
|
||||||
// buildCarInfo(mainController.driverData['message'][0]),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -40,32 +37,83 @@ class DriverPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDriverInfoSection(Map<String, dynamic> data) {
|
// ============================================================
|
||||||
|
// REUSABLE EDIT ROW
|
||||||
|
// ============================================================
|
||||||
|
Widget _buildEditableRow(String label, String key, Map data) {
|
||||||
|
return CupertinoListTile(
|
||||||
|
title: Text(label),
|
||||||
|
trailing: Text(
|
||||||
|
data[key].toString(),
|
||||||
|
style: const TextStyle(color: CupertinoColors.systemGrey),
|
||||||
|
),
|
||||||
|
onTap: () => _openEditSheet(label, key, data[key]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openEditSheet(String label, String key, dynamic value) {
|
||||||
|
final TextEditingController controller =
|
||||||
|
TextEditingController(text: value.toString());
|
||||||
|
|
||||||
|
Get.bottomSheet(
|
||||||
|
CupertinoPageScaffold(
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
middle: Text("Edit $label"),
|
||||||
|
trailing: GestureDetector(
|
||||||
|
child: const Text(
|
||||||
|
"Save",
|
||||||
|
style: TextStyle(color: CupertinoColors.activeBlue),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
mainController.updateDriverField(key, controller.text);
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: CupertinoTextField(
|
||||||
|
controller: controller,
|
||||||
|
autofocus: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// SECTIONS
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
Widget _buildDriverInfoSection(Map data) {
|
||||||
return CupertinoListSection.insetGrouped(
|
return CupertinoListSection.insetGrouped(
|
||||||
header: Text('Driver Information'.tr),
|
header: Text('Driver Information'.tr),
|
||||||
children: [
|
children: [
|
||||||
_buildInfoRow('Name'.tr, data['name_arabic'].toString()),
|
_buildEditableRow('Name Arabic'.tr, 'name_arabic', data),
|
||||||
_buildInfoRow('Name (English)'.tr, data['name_english'].toString()),
|
// _buildEditableRow('Name English'.tr, 'name_english', data),
|
||||||
_buildInfoRow('Phone'.tr, data['phone'].toString()),
|
_buildEditableRow('Phone'.tr, 'phone', data),
|
||||||
_buildInfoRow('Email'.tr, data['email'].toString()),
|
_buildEditableRow('Email'.tr, 'email', data),
|
||||||
_buildInfoRow('Gender'.tr, data['gender'].toString()),
|
_buildEditableRow('Gender'.tr, 'gender', data),
|
||||||
_buildInfoRow('Birthdate'.tr, data['birthdate'].toString()),
|
_buildEditableRow('Birthdate'.tr, 'birthdate', data),
|
||||||
_buildInfoRow('National Number'.tr, data['national_number'].toString()),
|
_buildEditableRow('National Number'.tr, 'national_number', data),
|
||||||
_buildInfoRow('Religion'.tr, data['religion'].toString()),
|
// _buildEditableRow('Religion'.tr, 'religion', data),
|
||||||
_buildInfoRow('Occupation'.tr, data['occupation'].toString()),
|
// _buildEditableRow('Occupation'.tr, 'occupation', data),
|
||||||
_buildInfoRow('Education'.tr, data['education'].toString()),
|
// _buildEditableRow('Education'.tr, 'education', data),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStatisticsSection(Map<String, dynamic> data) {
|
Widget _buildStatisticsSection(Map data) {
|
||||||
return CupertinoListSection.insetGrouped(
|
return CupertinoListSection.insetGrouped(
|
||||||
header: Text('Driver Statistics'.tr),
|
header: Text('Driver Statistics'.tr),
|
||||||
children: [
|
children: [
|
||||||
_buildInfoRow('Total Rides'.tr, data['countRide'].toString()),
|
_buildInfoRow('Total Rides'.tr, data['countRide'].toString()),
|
||||||
_buildInfoRow('Average Rating'.tr, data['rating'].toString()),
|
_buildInfoRow('Average Rating'.tr, data['rating'].toString()),
|
||||||
_buildInfoRow('Total Payments'.tr, '\$${data['totalPayment']}'),
|
_buildInfoRow('Total Payments'.tr, data['totalPayment'].toString()),
|
||||||
_buildInfoRow('Wallet Balance'.tr, '\$${data['totalDriverWallet']}'),
|
_buildInfoRow(
|
||||||
|
'Wallet Balance'.tr, data['totalDriverWallet'].toString()),
|
||||||
_buildInfoRow('Complaints'.tr, data['countComplaint'].toString()),
|
_buildInfoRow('Complaints'.tr, data['countComplaint'].toString()),
|
||||||
_buildInfoRow('Scam Reports'.tr, data['countScam'].toString()),
|
_buildInfoRow('Scam Reports'.tr, data['countScam'].toString()),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
@@ -76,53 +124,55 @@ class DriverPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCarInfoSection(Map<String, dynamic> data) {
|
// Read-only row widget
|
||||||
return CupertinoListSection.insetGrouped(
|
|
||||||
header: Text('Vehicle Information'.tr),
|
|
||||||
children: [
|
|
||||||
_buildInfoRow('VIN'.tr, data['vin'].toString()),
|
|
||||||
_buildInfoRow('Plate Number'.tr, data['car_plate'].toString()),
|
|
||||||
_buildInfoRow('Make'.tr, data['make'].toString()),
|
|
||||||
_buildInfoRow('Model'.tr, data['model'].toString()),
|
|
||||||
_buildInfoRow('Year'.tr, data['year'].toString()),
|
|
||||||
_buildInfoRow('Color'.tr, data['color'].toString()),
|
|
||||||
_buildInfoRow('Fuel Type'.tr, data['fuel'].toString()),
|
|
||||||
_buildInfoRow('Displacement'.tr, data['displacement'].toString()),
|
|
||||||
_buildInfoRow(
|
|
||||||
'Registration Date'.tr, data['registration_date'].toString()),
|
|
||||||
_buildInfoRow('Expiration Date'.tr, data['expiration_date'].toString()),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildLicenseInfoSection(Map<String, dynamic> data) {
|
|
||||||
return CupertinoListSection.insetGrouped(
|
|
||||||
header: Text('License Information'.tr),
|
|
||||||
children: [
|
|
||||||
_buildInfoRow('License Type'.tr, data['license_type'].toString()),
|
|
||||||
_buildInfoRow('Card ID'.tr, data['card_id'].toString()),
|
|
||||||
_buildInfoRow('Issue Date'.tr, data['issue_date'].toString()),
|
|
||||||
_buildInfoRow('Expiry Date'.tr, data['expiry_date'].toString()),
|
|
||||||
_buildInfoRow('Categories'.tr, data['license_categories'].toString()),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildBankInfoSection(Map<String, dynamic> data) {
|
|
||||||
return CupertinoListSection.insetGrouped(
|
|
||||||
header: Text('Bank Information'.tr),
|
|
||||||
children: [
|
|
||||||
_buildInfoRow('Account Number'.tr, data['accountBank'].toString()),
|
|
||||||
_buildInfoRow('Bank Code'.tr, data['bankCode'].toString()),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildInfoRow(String label, String value) {
|
Widget _buildInfoRow(String label, String value) {
|
||||||
return CupertinoListTile(
|
return CupertinoListTile(
|
||||||
title: Text(label),
|
title: Text(label),
|
||||||
trailing: Text(value,
|
trailing: Text(
|
||||||
style: const TextStyle(color: CupertinoColors.systemGrey)),
|
value,
|
||||||
|
style: const TextStyle(color: CupertinoColors.systemGrey),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCarInfoSection(Map data) {
|
||||||
|
return CupertinoListSection.insetGrouped(
|
||||||
|
header: Text('Vehicle Information'.tr),
|
||||||
|
children: [
|
||||||
|
// _buildEditableRow('VIN'.tr, 'vin', data),
|
||||||
|
_buildEditableRow('Plate Number'.tr, 'car_plate', data),
|
||||||
|
_buildEditableRow('Make'.tr, 'make', data),
|
||||||
|
_buildEditableRow('Model'.tr, 'model', data),
|
||||||
|
_buildEditableRow('Year'.tr, 'year', data),
|
||||||
|
_buildEditableRow('Color'.tr, 'color', data),
|
||||||
|
_buildEditableRow('Fuel Type'.tr, 'fuel', data),
|
||||||
|
// _buildEditableRow('Displacement'.tr, 'displacement', data),
|
||||||
|
_buildEditableRow('Registration Date'.tr, 'registration_date', data),
|
||||||
|
_buildEditableRow('Expiration Date'.tr, 'expiration_date', data),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildLicenseInfoSection(Map data) {
|
||||||
|
return CupertinoListSection.insetGrouped(
|
||||||
|
header: Text('License Information'.tr),
|
||||||
|
children: [
|
||||||
|
_buildEditableRow('License Type'.tr, 'license_type', data),
|
||||||
|
_buildEditableRow('Card ID'.tr, 'card_id', data),
|
||||||
|
_buildEditableRow('Issue Date'.tr, 'issue_date', data),
|
||||||
|
_buildEditableRow('Expiry Date'.tr, 'expiry_date', data),
|
||||||
|
_buildEditableRow('Categories'.tr, 'license_categories', data),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBankInfoSection(Map data) {
|
||||||
|
return CupertinoListSection.insetGrouped(
|
||||||
|
header: Text('Bank Information'.tr),
|
||||||
|
children: [
|
||||||
|
_buildEditableRow('Account Number'.tr, 'accountBank', data),
|
||||||
|
_buildEditableRow('Bank Code'.tr, 'bankCode', data),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,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:service/constant/colors.dart';
|
import 'package:service/constant/colors.dart';
|
||||||
import 'package:service/controller/functions/encrypt_decrypt.dart';
|
|
||||||
import 'package:service/controller/mainController/main_controller.dart';
|
import 'package:service/controller/mainController/main_controller.dart';
|
||||||
import 'package:service/views/widgets/my_scafold.dart';
|
import 'package:service/views/widgets/my_scafold.dart';
|
||||||
|
import 'package:service/main.dart';
|
||||||
|
import 'package:service/constant/box_name.dart';
|
||||||
|
|
||||||
import 'registration_captain_page.dart';
|
import 'registration_captain_page.dart';
|
||||||
|
|
||||||
@@ -14,201 +15,204 @@ class DriversCantRegister extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Get.put(MainController());
|
Get.put(MainController());
|
||||||
|
|
||||||
|
// Unified action button (WhatsApp - Edit - etc)
|
||||||
|
Widget buildActionButton({
|
||||||
|
required IconData icon,
|
||||||
|
required Color color,
|
||||||
|
required VoidCallback onPressed,
|
||||||
|
}) {
|
||||||
|
return CupertinoButton(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Icon(icon, color: color, size: 28),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return MyScaffold(
|
return MyScaffold(
|
||||||
title: 'Drivers Cant Register'.tr,
|
title: 'Drivers Want Register'.tr,
|
||||||
isleading: true,
|
isleading: true,
|
||||||
body: [
|
body: [
|
||||||
GetBuilder<MainController>(builder: (mainController) {
|
GetBuilder<MainController>(builder: (mainController) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
|
// Search
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
|
||||||
child: CupertinoSearchTextField(
|
child: CupertinoSearchTextField(
|
||||||
keyboardType: TextInputType.phone,
|
keyboardType: TextInputType.phone,
|
||||||
onChanged: (value) => mainController.searchDrivers(value),
|
onChanged: (value) => mainController.searchDrivers(value),
|
||||||
placeholder: 'Search by phone number'.tr,
|
placeholder: 'Search by phone number'.tr,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// List
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: mainController.filteredDrivers.isEmpty
|
||||||
itemCount: mainController.filteredDrivers.length,
|
? Center(
|
||||||
itemBuilder: (context, index) {
|
child: Text(
|
||||||
final driver = mainController.filteredDrivers[index];
|
'No drivers found'.tr,
|
||||||
return Padding(
|
style:
|
||||||
padding: const EdgeInsets.all(8.0),
|
TextStyle(color: Colors.grey[600], fontSize: 16),
|
||||||
child: Container(
|
),
|
||||||
color: driver['note'] == null
|
)
|
||||||
? AppColor.greenColor
|
: ListView.builder(
|
||||||
: AppColor.greyColor,
|
itemCount: mainController.filteredDrivers.length,
|
||||||
child: CupertinoFormSection(
|
itemBuilder: (context, index) {
|
||||||
header: Text(
|
final driver = mainController.filteredDrivers[index];
|
||||||
'Driver ID: ${driver['driverId']}',
|
|
||||||
),
|
final notesController =
|
||||||
children: [
|
TextEditingController(text: driver['note'] ?? '');
|
||||||
InkWell(
|
|
||||||
onTap: () => mainController
|
return Card(
|
||||||
.makePhoneCall(driver['phone_number']),
|
margin: const EdgeInsets.symmetric(
|
||||||
child: Container(
|
horizontal: 12.0, vertical: 8.0),
|
||||||
height: 40,
|
elevation: 3,
|
||||||
color: driver['note'] != null
|
clipBehavior: Clip.antiAlias,
|
||||||
? AppColor.greenColor
|
shape: RoundedRectangleBorder(
|
||||||
: AppColor.greyColor,
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: Row(
|
side: BorderSide(
|
||||||
mainAxisAlignment:
|
color: driver['note'] != null
|
||||||
MainAxisAlignment.spaceAround,
|
? AppColor.secondaryColor
|
||||||
|
: Colors.transparent,
|
||||||
|
width: 2.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.fromLTRB(16, 12, 16, 12),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Header
|
||||||
|
Text(
|
||||||
|
'Driver Phone: ${driver['first_name'] ?? ''} ${driver['last_name'] ?? ''}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Divider(height: 20),
|
||||||
|
|
||||||
|
// Phone Row
|
||||||
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text((driver['phone_number'])),
|
const Icon(
|
||||||
IconButton(
|
CupertinoIcons.phone_fill,
|
||||||
|
color: AppColor.primaryColor,
|
||||||
|
size: 22,
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
|
||||||
|
Expanded(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
mainController.makePhoneCall(
|
||||||
|
driver['phone_number']);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
driver['phone_number'] ?? 'N/A',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 17,
|
||||||
|
letterSpacing: 1.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// WhatsApp button
|
||||||
|
buildActionButton(
|
||||||
|
icon: Icons.send,
|
||||||
|
color: const Color(0xFF25D366),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
String message = "مرحباً،\n\n"
|
String message = "مرحباً،\n\n"
|
||||||
"نلاحظ أنك لم تكمل عملية التسجيل في خدمة Tripz درايفر. نود تذكيرك بأن إكمال التسجيل يتيح لك فرصة الانضمام إلى فريق Tripz والاستفادة من خدماتنا المتنوعة.\n\n"
|
"يظهر لدينا في نظام تطبيق *انطلق* أنك لم تكمل عملية التسجيل بعد.\n"
|
||||||
"إذا كنت بحاجة إلى أي مساعدة أو لديك أي استفسارات، لا تتردد في الاتصال بنا. نحن هنا لمساعدتك.\n\n"
|
"ندعوك لإكمال التسجيل للاستفادة من مزايا التطبيق والبدء بالعمل معنا.\n\n"
|
||||||
"للاتصال بنا، يرجى الاتصال على الرقم التالي: +20 101 880 5430\n\n"
|
"إذا احتجت لأي مساعدة، تواصل معنا على خدمة العملاء:\n"
|
||||||
"مع تحيات فريق Tripz.";
|
"+963 952 475 742\n\n"
|
||||||
|
"+963 952 475 740\n\n"
|
||||||
|
"فريق انطلق يتمنى لك يوماً سعيداً.";
|
||||||
|
|
||||||
mainController.launchCommunication(
|
mainController.launchCommunication(
|
||||||
'whatsapp',
|
'whatsapp',
|
||||||
'${driver['phone_number']}',
|
driver['phone_number'],
|
||||||
message);
|
message,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
|
||||||
Icons.send_time_extension_sharp,
|
|
||||||
color: AppColor.secondaryColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
IconButton(
|
|
||||||
|
// Edit button → go to registration form
|
||||||
|
buildActionButton(
|
||||||
|
icon: CupertinoIcons
|
||||||
|
.pencil_ellipsis_rectangle,
|
||||||
|
color: AppColor.gold,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.to(() => RegisterCaptain(),
|
Get.to(
|
||||||
arguments: {
|
() => RegisterCaptain(),
|
||||||
"phone_number":
|
arguments: {
|
||||||
driver['phone_number']
|
"phone": driver['phone_number'],
|
||||||
.toString(),
|
"driverId": driver['driverId'],
|
||||||
'driverId': driver['driverId']
|
},
|
||||||
.toString(),
|
);
|
||||||
'email':
|
},
|
||||||
driver['email'].toString(),
|
),
|
||||||
});
|
buildActionButton(
|
||||||
|
icon: CupertinoIcons
|
||||||
|
.pencil_ellipsis_rectangle,
|
||||||
|
color: AppColor.redColor,
|
||||||
|
onPressed: () {
|
||||||
|
mainController
|
||||||
|
.deleteDriverNotCompleteRegistration(
|
||||||
|
driver['phone_number']);
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
|
||||||
Icons.save,
|
|
||||||
color: AppColor.gold,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
|
||||||
// CupertinoFormRow(
|
|
||||||
// prefix: Text('Phone Number'.tr),
|
|
||||||
// child: CupertinoTextFormFieldRow(
|
|
||||||
// initialValue: driver['phone_number'],
|
|
||||||
// readOnly: true,
|
|
||||||
// placeholder: 'Phone Number'.tr,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
),
|
),
|
||||||
),
|
|
||||||
CupertinoFormRow(
|
|
||||||
prefix: Text('Created At'.tr),
|
|
||||||
child: CupertinoTextFormFieldRow(
|
|
||||||
initialValue: driver['created_at'],
|
|
||||||
readOnly: true,
|
|
||||||
placeholder: 'Created At',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CupertinoFormRow(
|
|
||||||
prefix: Text('Status'.tr),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
showCupertinoModalPopup<void>(
|
|
||||||
context: Get.context!,
|
|
||||||
builder: (BuildContext context) =>
|
|
||||||
Container(
|
|
||||||
height: 216,
|
|
||||||
padding: const EdgeInsets.only(top: 6.0),
|
|
||||||
margin: EdgeInsets.only(
|
|
||||||
bottom: MediaQuery.of(context)
|
|
||||||
.viewInsets
|
|
||||||
.bottom,
|
|
||||||
),
|
|
||||||
color: CupertinoColors.systemBackground
|
|
||||||
.resolveFrom(context),
|
|
||||||
child: SafeArea(
|
|
||||||
top: false,
|
|
||||||
child: CupertinoPicker(
|
|
||||||
magnification: 1.22,
|
|
||||||
squeeze: 1.2,
|
|
||||||
useMagnifier: true,
|
|
||||||
itemExtent: 32.0,
|
|
||||||
scrollController:
|
|
||||||
FixedExtentScrollController(
|
|
||||||
initialItem: mainController
|
|
||||||
.selectedStatus
|
|
||||||
.indexOf(mainController
|
|
||||||
.selectedStatus),
|
|
||||||
),
|
|
||||||
onSelectedItemChanged:
|
|
||||||
(int selectedItem) {
|
|
||||||
mainController.setSelectedStatus(
|
|
||||||
mainController
|
|
||||||
.statusOptions[selectedItem]
|
|
||||||
.tr);
|
|
||||||
},
|
|
||||||
children: List<Widget>.generate(
|
|
||||||
mainController.statusOptions
|
|
||||||
.length, (int index) {
|
|
||||||
return Center(
|
|
||||||
child: Text(mainController
|
|
||||||
.statusOptions[index].tr),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: CupertinoFormRow(
|
|
||||||
child: Text(
|
|
||||||
mainController.selectedStatus.tr,
|
|
||||||
style: TextStyle(
|
|
||||||
color: CupertinoColors.label
|
|
||||||
.resolveFrom(Get.context!)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CupertinoFormRow(
|
|
||||||
prefix: Text('Notes'.tr),
|
|
||||||
child: CupertinoTextFormFieldRow(
|
|
||||||
cursorColor: AppColor.blueColor,
|
|
||||||
controller: mainController.notesController,
|
|
||||||
placeholder:
|
|
||||||
driver['note'] ?? "Additional comments".tr,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CupertinoButton(
|
|
||||||
child: Text('Save Notes'.tr),
|
|
||||||
onPressed: () {
|
|
||||||
// Save the notes for the driver
|
|
||||||
String notes =
|
|
||||||
mainController.notesController.text == ''
|
|
||||||
? mainController.selectedStatus
|
|
||||||
.toString()
|
|
||||||
: mainController.notesController.text;
|
|
||||||
|
|
||||||
mainController
|
const SizedBox(height: 16),
|
||||||
.saveNoteForDriverNotCompleteRegistration(
|
|
||||||
driver['phone_number'],
|
// Notes box
|
||||||
'girls name',
|
CupertinoTextField(
|
||||||
notes);
|
controller: notesController,
|
||||||
print(
|
placeholder: "Additional comments".tr,
|
||||||
'Notes for driver ${driver['id']}: $notes');
|
padding: const EdgeInsets.all(12),
|
||||||
},
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey.shade100,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Save button
|
||||||
|
Align(
|
||||||
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
|
child: CupertinoButton(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20),
|
||||||
|
color: AppColor.secondaryColor,
|
||||||
|
onPressed: () {
|
||||||
|
mainController
|
||||||
|
.saveNoteForDriverNotCompleteRegistration(
|
||||||
|
driver['phone_number'],
|
||||||
|
box.read(BoxName.employeename) ??
|
||||||
|
'none',
|
||||||
|
notesController.text,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text('Save Notes'.tr),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
485
lib/controller/mainController/pages/new_driver.dart
Normal file
485
lib/controller/mainController/pages/new_driver.dart
Normal file
@@ -0,0 +1,485 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:service/constant/colors.dart';
|
||||||
|
// Importa tu nuevo controlador de servicio
|
||||||
|
import 'package:service/controller/mainController/ragister_service_controller.dart';
|
||||||
|
import 'package:service/views/widgets/elevated_btn.dart';
|
||||||
|
import 'package:service/views/widgets/my_scafold.dart';
|
||||||
|
|
||||||
|
// El import del antiguo controlador ya no es necesario
|
||||||
|
// import '../registration_captain_controller.dart';
|
||||||
|
|
||||||
|
class RegisterCaptain extends StatelessWidget {
|
||||||
|
const RegisterCaptain({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// Instancia el NUEVO controlador
|
||||||
|
final controller = Get.put(RegisterCaptainServiceController());
|
||||||
|
|
||||||
|
return MyScaffold(
|
||||||
|
title: 'Syrian Documents Check'.tr,
|
||||||
|
isleading: true,
|
||||||
|
body: [
|
||||||
|
Obx(() {
|
||||||
|
if (controller.isLoading.value) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
|
child: StepIndicator(
|
||||||
|
currentStep: controller.currentPageIndex.value,
|
||||||
|
totalSteps: 4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: PageView(
|
||||||
|
controller: controller.pageController,
|
||||||
|
onPageChanged: (index) {
|
||||||
|
controller.currentPageIndex.value = index;
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
// <-- PÁGINAS REACTIVADAS CON EL NUEVO CONTROLADOR -->
|
||||||
|
_buildSyrianDriverLicenseFront(context, controller),
|
||||||
|
_buildSyrianDriverLicenseBack(context, controller),
|
||||||
|
_buildSyrianCarLicenseFront(context, controller),
|
||||||
|
_buildSyrianCarLicenseBack(controller),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_buildNavigationControls(controller),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Este método ya estaba usando el controlador correcto
|
||||||
|
Widget _buildNavigationControls(RegisterCaptainServiceController controller) {
|
||||||
|
bool isLastPage = controller.currentPageIndex.value == 3;
|
||||||
|
bool isFirstPage = controller.currentPageIndex.value == 0;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
if (!isFirstPage)
|
||||||
|
MyElevatedButton(
|
||||||
|
title: 'Back'.tr,
|
||||||
|
onPressed: controller.previousPage,
|
||||||
|
kolor: Colors.grey,
|
||||||
|
),
|
||||||
|
if (isFirstPage) const Spacer(),
|
||||||
|
MyElevatedButton(
|
||||||
|
title: isLastPage ? 'Save and Activate'.tr : 'Next'.tr,
|
||||||
|
onPressed: isLastPage
|
||||||
|
? controller.updateAndActivateSyrianDriver
|
||||||
|
: controller.nextPage,
|
||||||
|
kolor: isLastPage ? AppColor.greenColor : AppColor.primaryColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTextField({
|
||||||
|
required String label,
|
||||||
|
required TextEditingController controller,
|
||||||
|
IconData? icon,
|
||||||
|
TextInputType keyboardType = TextInputType.text,
|
||||||
|
VoidCallback? onTap,
|
||||||
|
String? hintText,
|
||||||
|
}) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: controller,
|
||||||
|
keyboardType: keyboardType,
|
||||||
|
readOnly: onTap != null,
|
||||||
|
onTap: onTap,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: label.tr,
|
||||||
|
hintText: hintText,
|
||||||
|
prefixIcon:
|
||||||
|
icon != null ? Icon(icon, color: AppColor.secondaryColor) : null,
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
borderSide:
|
||||||
|
const BorderSide(color: AppColor.secondaryColor, width: 2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPageContent({
|
||||||
|
required RxString imageUrl,
|
||||||
|
required List<Widget> formFields,
|
||||||
|
}) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
// ClipRRect(
|
||||||
|
// borderRadius: BorderRadius.circular(12),
|
||||||
|
// child: Image.network(
|
||||||
|
// imageUrl.value,
|
||||||
|
// fit: BoxFit.fitWidth,
|
||||||
|
// errorBuilder: (context, error, stackTrace) {
|
||||||
|
// return Container(
|
||||||
|
// height: 200,
|
||||||
|
// color: Colors.grey[200],
|
||||||
|
// child: Center(
|
||||||
|
// child: Text(
|
||||||
|
// 'Image not available'.tr,
|
||||||
|
// style: const TextStyle(color: Colors.grey),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// const SizedBox(height: 20),
|
||||||
|
const Divider(),
|
||||||
|
...formFields,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <-- MODIFICADO: Usa RegisterCaptainServiceController -->
|
||||||
|
Widget _buildColorDropdown(RegisterCaptainServiceController controller) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: Obx(
|
||||||
|
() => DropdownButtonFormField<String>(
|
||||||
|
value: controller.colorHex.value.isEmpty
|
||||||
|
? null
|
||||||
|
: controller.colorHex.value,
|
||||||
|
isExpanded: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Car Color'.tr,
|
||||||
|
prefixIcon: Icon(Icons.color_lens, color: AppColor.secondaryColor),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// <-- MODIFICADO: Usa la referencia estática del nuevo controlador -->
|
||||||
|
items: RegisterCaptainServiceController.kCarColorOptions.map((opt) {
|
||||||
|
final hex = opt['hex']!;
|
||||||
|
final key = opt['key']!;
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: hex,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 18,
|
||||||
|
height: 18,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: controller.hexToColor(hex),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(color: Colors.black12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(child: Text(key.tr)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (hex) {
|
||||||
|
if (hex != null) {
|
||||||
|
controller.updateColorSelection(hex);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <-- MODIFICADO: Usa RegisterCaptainServiceController -->
|
||||||
|
Widget _buildGenderDropdown(RegisterCaptainServiceController controller) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: Obx(
|
||||||
|
() => DropdownButtonFormField<String>(
|
||||||
|
value: controller.selectedGender.value.isEmpty
|
||||||
|
? null
|
||||||
|
: controller.selectedGender.value,
|
||||||
|
isExpanded: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Gender'.tr,
|
||||||
|
prefixIcon: Icon(Icons.wc, color: AppColor.secondaryColor),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
items: ['Male', 'Female'].map((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value.tr),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
if (newValue != null) {
|
||||||
|
controller.selectedGender.value = newValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <-- MODIFICADO: Usa RegisterCaptainServiceController -->
|
||||||
|
Widget _buildFuelDropdown(RegisterCaptainServiceController controller) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: Obx(
|
||||||
|
() => DropdownButtonFormField<String>(
|
||||||
|
// <-- MODIFICADO: Usa la referencia estática del nuevo controlador -->
|
||||||
|
value: RegisterCaptainServiceController.kFuelOptions
|
||||||
|
.contains(controller.selectedFuel.value)
|
||||||
|
? controller.selectedFuel.value
|
||||||
|
: null,
|
||||||
|
isExpanded: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Fuel Type'.tr,
|
||||||
|
prefixIcon:
|
||||||
|
Icon(Icons.local_gas_station, color: AppColor.secondaryColor),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// <-- MODIFICADO: Usa la referencia estática del nuevo controlador -->
|
||||||
|
items:
|
||||||
|
RegisterCaptainServiceController.kFuelOptions.map((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value.tr),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
if (newValue != null) {
|
||||||
|
controller.selectedFuel.value = newValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PAGE 1: Driver License Front ---
|
||||||
|
// <-- MODIFICADO: Usa RegisterCaptainServiceController -->
|
||||||
|
Widget _buildSyrianDriverLicenseFront(
|
||||||
|
BuildContext context, RegisterCaptainServiceController controller) {
|
||||||
|
return _buildPageContent(
|
||||||
|
imageUrl: controller.docUrls['driver_license_front']!,
|
||||||
|
formFields: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'First Name',
|
||||||
|
controller: controller.firstNameController,
|
||||||
|
keyboardType: TextInputType.name),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'Last Name',
|
||||||
|
controller: controller.lastNameController,
|
||||||
|
keyboardType: TextInputType.name),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
_buildTextField(
|
||||||
|
label: 'Phone Number',
|
||||||
|
controller: controller.phoneController,
|
||||||
|
hintText: 'e.g., 963992952235',
|
||||||
|
icon: Icons.phone,
|
||||||
|
keyboardType: TextInputType.phone,
|
||||||
|
),
|
||||||
|
_buildTextField(
|
||||||
|
label: 'Place of Registration',
|
||||||
|
controller: controller.siteController,
|
||||||
|
icon: Icons.location_city),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'National Number',
|
||||||
|
controller: controller.nationalNumberController,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
icon: Icons.fingerprint),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(child: _buildGenderDropdown(controller)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
_buildTextField(
|
||||||
|
label: 'Birthdate',
|
||||||
|
controller: controller.birthdateController,
|
||||||
|
icon: Icons.cake,
|
||||||
|
onTap: () =>
|
||||||
|
controller.selectDate(context, controller.birthdateController)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PAGE 2: Driver License Back ---
|
||||||
|
// <-- MODIFICADO: Usa RegisterCaptainServiceController -->
|
||||||
|
Widget _buildSyrianDriverLicenseBack(
|
||||||
|
BuildContext context, RegisterCaptainServiceController controller) {
|
||||||
|
return _buildPageContent(
|
||||||
|
imageUrl: controller.docUrls['driver_license_back']!,
|
||||||
|
formFields: [
|
||||||
|
_buildTextField(
|
||||||
|
label: 'License Category',
|
||||||
|
controller: controller.licenseCategoriesController),
|
||||||
|
_buildTextField(
|
||||||
|
label: 'Expiry Date',
|
||||||
|
controller: controller.expiryDateController,
|
||||||
|
icon: Icons.event_busy,
|
||||||
|
onTap: () => controller.selectDate(
|
||||||
|
context, controller.expiryDateController)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PAGE 3: Car License Front ---
|
||||||
|
// <-- MODIFICADO: Usa RegisterCaptainServiceController -->
|
||||||
|
Widget _buildSyrianCarLicenseFront(
|
||||||
|
BuildContext context, RegisterCaptainServiceController controller) {
|
||||||
|
return _buildPageContent(
|
||||||
|
imageUrl: controller.docUrls['car_license_front']!,
|
||||||
|
formFields: [
|
||||||
|
_buildTextField(
|
||||||
|
label: 'Owner Name',
|
||||||
|
controller: controller.ownerController,
|
||||||
|
keyboardType: TextInputType.name,
|
||||||
|
icon: Icons.person_search),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: _buildColorDropdown(controller)),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'Car Plate',
|
||||||
|
controller: controller.carPlateController,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// _buildTextField(
|
||||||
|
// label: 'VIN',
|
||||||
|
// controller: controller.vinController,
|
||||||
|
// icon: Icons.confirmation_number),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'License Issue Date',
|
||||||
|
controller: controller.licenseIssueDateController,
|
||||||
|
onTap: () => controller.selectDate(
|
||||||
|
context, controller.licenseIssueDateController))),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'License Expiry Date',
|
||||||
|
controller: controller.carLicenseExpiryDateController,
|
||||||
|
onTap: () => controller.selectDate(
|
||||||
|
context, controller.carLicenseExpiryDateController))),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PAGE 4: Car License Back ---
|
||||||
|
// <-- MODIFICADO: Usa RegisterCaptainServiceController -->
|
||||||
|
Widget _buildSyrianCarLicenseBack(
|
||||||
|
RegisterCaptainServiceController controller) {
|
||||||
|
return _buildPageContent(
|
||||||
|
imageUrl: controller.docUrls['car_license_back']!,
|
||||||
|
formFields: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'Make',
|
||||||
|
controller: controller.makeController,
|
||||||
|
)),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'Model',
|
||||||
|
controller: controller.modelController,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildTextField(
|
||||||
|
label: 'Year',
|
||||||
|
controller: controller.yearController,
|
||||||
|
keyboardType: TextInputType.number)),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(child: _buildFuelDropdown(controller)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StepIndicator extends StatelessWidget {
|
||||||
|
final int currentStep;
|
||||||
|
final int totalSteps;
|
||||||
|
|
||||||
|
const StepIndicator({
|
||||||
|
super.key,
|
||||||
|
required this.currentStep,
|
||||||
|
required this.totalSteps,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${'Step'.tr} ${currentStep + 1} ${'of'.tr} $totalSteps',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black54),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: List.generate(totalSteps, (index) {
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
width: 30,
|
||||||
|
height: 8,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: index <= currentStep
|
||||||
|
? AppColor.primaryColor
|
||||||
|
: Colors.grey.shade300,
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,12 +28,12 @@ class PassengersCantRegister extends StatelessWidget {
|
|||||||
header: Text('Passenger ID: ${passenger['id']}'),
|
header: Text('Passenger ID: ${passenger['id']}'),
|
||||||
children: [
|
children: [
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () => mainController
|
onTap: () =>
|
||||||
.makePhoneCall(passenger['phone_number']),
|
mainController.makePhoneCall(passenger['phone']),
|
||||||
child: CupertinoFormRow(
|
child: CupertinoFormRow(
|
||||||
prefix: Text('Phone Number'.tr),
|
prefix: Text(' phone'.tr),
|
||||||
child: CupertinoTextFormFieldRow(
|
child: CupertinoTextFormFieldRow(
|
||||||
initialValue: ((passenger['phone_number'])),
|
initialValue: ((passenger['phone'])),
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
placeholder: 'Phone Number'.tr,
|
placeholder: 'Phone Number'.tr,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -9,92 +9,109 @@ class PassengersPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetBuilder<MainController>(builder: (mainController) {
|
return GetBuilder<MainController>(
|
||||||
Map data = mainController.passengerData['message'][0];
|
builder: (mainController) {
|
||||||
return MyScaffold(
|
final data = _extractPassengerData(mainController);
|
||||||
title: (data['first_name']?.toString() ?? '') +
|
|
||||||
' ' +
|
return MyScaffold(
|
||||||
(data['last_name']?.toString() ?? ''),
|
title: data != null
|
||||||
isleading: true,
|
? '${data['first_name'] ?? ''} ${data['last_name'] ?? ''}'
|
||||||
body: [
|
: 'Passenger Not Found'.tr,
|
||||||
ListView(
|
isleading: true,
|
||||||
children: [
|
body: [
|
||||||
_buildPersonalInfoCard(data),
|
if (data != null)
|
||||||
_buildLatestRideCard(data),
|
ListView(
|
||||||
_buildWalletInfoCard(data),
|
children: [
|
||||||
],
|
_buildPersonalInfoCard(data),
|
||||||
),
|
_buildLatestRideCard(data),
|
||||||
],
|
_buildWalletInfoCard(data),
|
||||||
);
|
],
|
||||||
});
|
)
|
||||||
|
else
|
||||||
|
const Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(24.0),
|
||||||
|
child: Text(
|
||||||
|
'No passenger data available.',
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper method to extract the passenger data safely.
|
||||||
|
Map? _extractPassengerData(MainController controller) {
|
||||||
|
final passengerData = controller.passengerData;
|
||||||
|
if (passengerData == null ||
|
||||||
|
passengerData['message'] == null ||
|
||||||
|
passengerData['message'].isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return passengerData['message'][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPersonalInfoCard(Map data) {
|
Widget _buildPersonalInfoCard(Map data) {
|
||||||
return Card(
|
return _buildCard(
|
||||||
margin: const EdgeInsets.all(16),
|
title: 'Personal Information'.tr,
|
||||||
child: Padding(
|
children: [
|
||||||
padding: const EdgeInsets.all(16),
|
_buildInfoRow('Phone'.tr, data['phone']),
|
||||||
child: Column(
|
_buildInfoRow('Email'.tr, data['email']),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
_buildInfoRow('Gender'.tr, data['gender']),
|
||||||
children: [
|
_buildInfoRow('Birthdate'.tr, data['birthdate']),
|
||||||
Text('Personal Information'.tr,
|
// _buildInfoRow('Education'.tr, data['education']),
|
||||||
style:
|
_buildInfoRow('Employment'.tr, data['employmentType']),
|
||||||
const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
_buildInfoRow('Marital Status'.tr, data['maritalStatus']),
|
||||||
const SizedBox(height: 16),
|
],
|
||||||
_buildInfoRow('Phone'.tr, data['phone']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow('Email'.tr, data['email']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow('Gender'.tr, data['gender']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow(
|
|
||||||
'Birthdate'.tr, data['birthdate']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow(
|
|
||||||
'Education'.tr, data['education']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow(
|
|
||||||
'Employment'.tr, data['employmentType']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow('Marital Status'.tr,
|
|
||||||
data['maritalStatus']?.toString() ?? 'N/A'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLatestRideCard(Map data) {
|
Widget _buildLatestRideCard(Map data) {
|
||||||
return Card(
|
return _buildCard(
|
||||||
margin: const EdgeInsets.all(16),
|
title: 'Latest Ride'.tr,
|
||||||
child: Padding(
|
children: [
|
||||||
padding: const EdgeInsets.all(16),
|
_buildInfoRow('Ride ID'.tr, data['ride_id']),
|
||||||
child: Column(
|
_buildInfoRow('Date'.tr, data['ride_date']),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
_buildInfoRow('Start Time'.tr, data['ride_time']),
|
||||||
children: [
|
_buildInfoRow('End Time'.tr, data['ride_endtime']),
|
||||||
Text('Latest Ride'.tr,
|
_buildInfoRow(
|
||||||
style:
|
'Price'.tr, data['price'] != null ? '\$${data['price']}' : null),
|
||||||
const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
_buildInfoRow('Status'.tr, data['ride_status']),
|
||||||
const SizedBox(height: 16),
|
_buildInfoRow('Payment Method'.tr, data['ride_payment_method']),
|
||||||
_buildInfoRow('Ride ID'.tr, data['ride_id']?.toString() ?? 'N/A'),
|
_buildInfoRow('Car Type'.tr, data['car_type']),
|
||||||
_buildInfoRow('Date'.tr, data['ride_date']?.toString() ?? 'N/A'),
|
_buildInfoRow(
|
||||||
_buildInfoRow(
|
'Distance'.tr,
|
||||||
'Start Time'.tr, data['ride_time']?.toString() ?? 'N/A'),
|
data['distance'] != null
|
||||||
_buildInfoRow(
|
? '${(data['distance'] as num).toStringAsFixed(2)} km'
|
||||||
'End Time'.tr, data['ride_endtime']?.toString() ?? 'N/A'),
|
: null),
|
||||||
_buildInfoRow(
|
],
|
||||||
'Price'.tr, '\$${data['price']?.toString() ?? 'N/A'}'),
|
|
||||||
_buildInfoRow(
|
|
||||||
'Status'.tr, data['ride_status']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow('Payment Method'.tr,
|
|
||||||
data['ride_payment_method']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow('Car Type'.tr, data['car_type']?.toString() ?? 'N/A'),
|
|
||||||
_buildInfoRow(
|
|
||||||
'Distance'.tr,
|
|
||||||
data['distance'] != null
|
|
||||||
? '${data['distance'].toStringAsFixed(2)} km'
|
|
||||||
: 'N/A'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildWalletInfoCard(Map data) {
|
Widget _buildWalletInfoCard(Map data) {
|
||||||
|
return _buildCard(
|
||||||
|
title: 'Wallet Information'.tr,
|
||||||
|
children: [
|
||||||
|
_buildInfoRow(
|
||||||
|
'Wallet Balance'.tr,
|
||||||
|
data['passenger_wallet_balance'] != null
|
||||||
|
? '\$${data['passenger_wallet_balance']}'
|
||||||
|
: null),
|
||||||
|
_buildInfoRow(
|
||||||
|
'Last Payment Amount'.tr,
|
||||||
|
data['passenger_payment_amount'] != null
|
||||||
|
? '\$${data['passenger_payment_amount']}'
|
||||||
|
: null),
|
||||||
|
_buildInfoRow(
|
||||||
|
'Last Payment Method'.tr, data['passenger_payment_method']),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCard({required String title, required List<Widget> children}) {
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.all(16),
|
margin: const EdgeInsets.all(16),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -102,30 +119,26 @@ class PassengersPage extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('Wallet Information'.tr,
|
Text(title,
|
||||||
style:
|
style:
|
||||||
const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildInfoRow('Wallet Balance'.tr,
|
...children,
|
||||||
'\$${data['passenger_wallet_balance']?.toString() ?? 'N/A'}'),
|
|
||||||
_buildInfoRow('Last Payment Amount'.tr,
|
|
||||||
'\$${data['passenger_payment_amount']?.toString() ?? 'N/A'}'),
|
|
||||||
_buildInfoRow('Last Payment Method'.tr,
|
|
||||||
data['passenger_payment_method']?.toString() ?? 'N/A'),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildInfoRow(String label, String value) {
|
Widget _buildInfoRow(String label, dynamic value) {
|
||||||
|
final displayValue = value?.toString() ?? 'N/A';
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||||
Text(value),
|
Flexible(child: Text(displayValue, overflow: TextOverflow.ellipsis)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
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:service/constant/colors.dart';
|
import 'package:service/constant/colors.dart';
|
||||||
import 'package:service/constant/style.dart';
|
import 'package:service/constant/style.dart';
|
||||||
@@ -12,21 +13,35 @@ class WelcomeCall extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Get.put(MainController());
|
final controller = Get.put(MainController());
|
||||||
|
|
||||||
return MyScaffold(
|
return MyScaffold(
|
||||||
title: 'Welcome Drivers'.tr,
|
title: 'Welcome Drivers'.tr,
|
||||||
isleading: true,
|
isleading: true,
|
||||||
body: [
|
body: [
|
||||||
GetBuilder<MainController>(builder: (mainController) {
|
GetBuilder<MainController>(builder: (mainController) {
|
||||||
return Expanded(
|
final drivers = mainController.newDriverRegister;
|
||||||
child: CupertinoScrollbar(
|
|
||||||
child: ListView.builder(
|
if (drivers.isEmpty) {
|
||||||
itemCount: mainController.newDriverRegister.length,
|
return const Padding(
|
||||||
itemBuilder: (context, index) {
|
padding: EdgeInsets.all(32.0),
|
||||||
final driver = mainController.newDriverRegister[index];
|
child: Center(
|
||||||
return DriverCard(driver: driver);
|
child: Text(
|
||||||
},
|
'No new drivers found.',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CupertinoScrollbar(
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: const EdgeInsets.only(bottom: 20),
|
||||||
|
itemCount: drivers.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final driver = drivers[index];
|
||||||
|
return DriverCard(driver: driver);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
@@ -39,9 +54,22 @@ class DriverCard extends StatelessWidget {
|
|||||||
final Map<String, dynamic> driver;
|
final Map<String, dynamic> driver;
|
||||||
|
|
||||||
const DriverCard({super.key, required this.driver});
|
const DriverCard({super.key, required this.driver});
|
||||||
|
Widget buildActionButton({
|
||||||
|
required IconData icon,
|
||||||
|
required Color color,
|
||||||
|
required VoidCallback onPressed,
|
||||||
|
}) {
|
||||||
|
return CupertinoButton(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Icon(icon, color: color, size: 28),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final controller = Get.find<MainController>();
|
||||||
|
|
||||||
return CupertinoCard(
|
return CupertinoCard(
|
||||||
margin: const EdgeInsets.all(16.0),
|
margin: const EdgeInsets.all(16.0),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -49,38 +77,37 @@ class DriverCard extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
// حالة التلوين حسب isCall
|
||||||
Container(
|
Container(
|
||||||
decoration: AppStyle.boxDecoration1.copyWith(
|
decoration: AppStyle.boxDecoration1.copyWith(
|
||||||
color: driver['isCall'].toString() == '1'
|
color: driver['isCall'].toString() == '1'
|
||||||
? AppColor.greenColor
|
? AppColor.greenColor
|
||||||
: AppColor.accentColor),
|
: AppColor.accentColor,
|
||||||
child: Padding(
|
),
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 2),
|
child: Text(
|
||||||
child: Text(
|
'Driver Information'.tr,
|
||||||
'Driver Information'.tr,
|
style: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
|
||||||
style: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 12),
|
||||||
InfoText('Name'.tr, driver['name_arabic'].toString()),
|
|
||||||
InfoText('Phone'.tr, driver['phone'].toString()),
|
|
||||||
InfoText('Email'.tr, driver['email'].toString()),
|
|
||||||
InfoText('License Type'.tr, driver['license_type'].toString()),
|
|
||||||
InfoText(
|
InfoText(
|
||||||
'License Categories'.tr, driver['license_categories'] ?? ''),
|
'Name'.tr, driver['first_name'] + ' ' + driver['last_name']),
|
||||||
InfoText(
|
InfoText('Phone'.tr, driver['phone']),
|
||||||
'National Number'.tr, driver['national_number'].toString()),
|
InfoText('Email'.tr, driver['email']),
|
||||||
InfoText('Occupation'.tr, driver['occupation'].toString()),
|
InfoText('License Type'.tr, driver['license_type']),
|
||||||
const SizedBox(height: 16),
|
InfoText('License Categories'.tr, driver['license_categories']),
|
||||||
Text(
|
InfoText('National Number'.tr, driver['national_number']),
|
||||||
'Notes:'.tr,
|
InfoText('Occupation'.tr, driver['occupation']),
|
||||||
style: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
|
const SizedBox(height: 12),
|
||||||
),
|
|
||||||
|
Text('Notes:'.tr,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.navTitleTextStyle),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
CupertinoTextField(
|
CupertinoTextField(
|
||||||
controller: Get.find<MainController>().notesController,
|
controller: controller.notesController,
|
||||||
placeholder: driver['notes'] ?? 'Enter notes here...'.tr,
|
placeholder: driver['notes'] ?? 'Enter notes here...'.tr,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
@@ -89,25 +116,55 @@ class DriverCard extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Expanded(
|
||||||
width: Get.width * .4,
|
child: MyElevatedButton(
|
||||||
child: MyElevatedButton(
|
title: 'Call Driver'.tr,
|
||||||
title: 'Call Driver'.tr,
|
onPressed: () {
|
||||||
onPressed: () {
|
controller.makePhoneCall(driver['phone'].toString());
|
||||||
Get.find<MainController>()
|
},
|
||||||
.makePhoneCall(driver['phone'].toString());
|
),
|
||||||
})),
|
),
|
||||||
CupertinoButton(
|
const SizedBox(width: 16),
|
||||||
onPressed: () async {
|
Expanded(
|
||||||
await Get.find<MainController>().addWelcomeCall(
|
child: CupertinoButton(
|
||||||
driver['id'].toString(),
|
onPressed: () async {
|
||||||
);
|
await controller.addWelcomeCall(driver['id'].toString());
|
||||||
},
|
},
|
||||||
child: Text('Save Changes'.tr),
|
child: Text('Save Changes'.tr),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CupertinoButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final phone = driver['phone'];
|
||||||
|
|
||||||
|
if (phone == null || phone.toString().isEmpty) {
|
||||||
|
Get.snackbar("خطأ", "لا يوجد رقم هاتف لهذا السائق");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String message = "مرحباً،\n\n"
|
||||||
|
"يعطيك العافية أستاذ. نرحب بك في شركة *انطلق* للنقل الذكي.\n"
|
||||||
|
"نود تعريفك بالتطبيق ومميزاته لتتمكن من الاستفادة الكاملة وبدء العمل معنا بسهولة.\n\n"
|
||||||
|
"لأي استفسار أو مساعدة، يمكنك التواصل معنا على الأرقام التالية:\n\n"
|
||||||
|
"+963 952 475 742\n"
|
||||||
|
"+963 952 475 740\n"
|
||||||
|
"+963 952 475 734\n\n"
|
||||||
|
"فريق انطلق يتمنى لك تجربة موفقة ويوم سعيد.";
|
||||||
|
|
||||||
|
Get.find<MainController>().launchCommunication(
|
||||||
|
'whatsapp',
|
||||||
|
phone,
|
||||||
|
message,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text('send'.tr),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -120,16 +177,17 @@ class DriverCard extends StatelessWidget {
|
|||||||
|
|
||||||
class InfoText extends StatelessWidget {
|
class InfoText extends StatelessWidget {
|
||||||
final String label;
|
final String label;
|
||||||
final String value;
|
final dynamic value;
|
||||||
|
|
||||||
const InfoText(this.label, this.value, {super.key});
|
const InfoText(this.label, this.value, {super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final display = value?.toString() ?? 'N/A';
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 4.0),
|
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'$label: $value',
|
'$label: $display',
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle,
|
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
352
lib/controller/mainController/ragister_service_controller.dart
Normal file
352
lib/controller/mainController/ragister_service_controller.dart
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:service/constant/box_name.dart';
|
||||||
|
import 'package:service/constant/links.dart';
|
||||||
|
import 'package:service/controller/functions/crud.dart';
|
||||||
|
import 'package:service/main.dart';
|
||||||
|
import 'package:service/print.dart';
|
||||||
|
import 'package:service/views/widgets/my_dialog.dart';
|
||||||
|
|
||||||
|
import 'pages/registration_captain_page.dart';
|
||||||
|
|
||||||
|
class RegisterCaptainServiceController extends GetxController {
|
||||||
|
// --- UI State Management ---
|
||||||
|
var isLoading = true.obs;
|
||||||
|
late PageController pageController;
|
||||||
|
var currentPageIndex = 0.obs;
|
||||||
|
var driverId = ''.obs;
|
||||||
|
var phone = ''.obs;
|
||||||
|
var serverData = <String, dynamic>{}.obs;
|
||||||
|
// En tu archivo registration_captain_controller.dart
|
||||||
|
final phoneController = TextEditingController();
|
||||||
|
// --- Dynamic Document Image URLs ---
|
||||||
|
final Map<String, RxString> docUrls = {
|
||||||
|
'driver_license_front': ''.obs,
|
||||||
|
'driver_license_back': ''.obs,
|
||||||
|
'car_license_front': ''.obs,
|
||||||
|
'car_license_back': ''.obs,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Text Field Controllers ---
|
||||||
|
late TextEditingController firstNameController;
|
||||||
|
late TextEditingController lastNameController;
|
||||||
|
late TextEditingController siteController;
|
||||||
|
late TextEditingController nationalNumberController;
|
||||||
|
late TextEditingController birthdateController;
|
||||||
|
late TextEditingController licenseCategoriesController;
|
||||||
|
late TextEditingController expiryDateController;
|
||||||
|
late TextEditingController ownerController;
|
||||||
|
late TextEditingController colorController;
|
||||||
|
late TextEditingController carPlateController;
|
||||||
|
late TextEditingController vinController;
|
||||||
|
late TextEditingController licenseIssueDateController;
|
||||||
|
late TextEditingController carLicenseExpiryDateController;
|
||||||
|
late TextEditingController makeController;
|
||||||
|
late TextEditingController modelController;
|
||||||
|
late TextEditingController yearController;
|
||||||
|
|
||||||
|
// --- Reactive State for Dropdowns ---
|
||||||
|
var selectedGender = ''.obs;
|
||||||
|
var colorHex = ''.obs;
|
||||||
|
var selectedFuel = ''.obs;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
pageController = PageController();
|
||||||
|
|
||||||
|
// final arguments = Get.arguments;
|
||||||
|
// driverId.value = arguments?['driverId']; // Fallback for testing
|
||||||
|
// phone.value = arguments?['phone']; // Fallback for testing
|
||||||
|
|
||||||
|
_initializeTextControllers();
|
||||||
|
_initializeDocUrls();
|
||||||
|
fetchDataFromServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initializeDocUrls() {
|
||||||
|
const baseUrl =
|
||||||
|
"https://syria.intaleq.xyz/intaleq/auth/syria/driversDocs/syria.intaleq.xyz-";
|
||||||
|
docUrls['driver_license_front']!.value =
|
||||||
|
"$baseUrl${driverId.value}-driver_license_front.jpg";
|
||||||
|
docUrls['driver_license_back']!.value =
|
||||||
|
"$baseUrl${driverId.value}-driver_license_back.jpg";
|
||||||
|
docUrls['car_license_front']!.value =
|
||||||
|
"$baseUrl${driverId.value}-car_license_front.jpg";
|
||||||
|
docUrls['car_license_back']!.value =
|
||||||
|
"$baseUrl${driverId.value}-car_license_back.jpg";
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initializeTextControllers() {
|
||||||
|
firstNameController = TextEditingController();
|
||||||
|
lastNameController = TextEditingController();
|
||||||
|
siteController = TextEditingController();
|
||||||
|
nationalNumberController = TextEditingController();
|
||||||
|
birthdateController = TextEditingController();
|
||||||
|
licenseCategoriesController = TextEditingController();
|
||||||
|
expiryDateController = TextEditingController();
|
||||||
|
ownerController = TextEditingController();
|
||||||
|
colorController = TextEditingController();
|
||||||
|
carPlateController = TextEditingController();
|
||||||
|
vinController = TextEditingController();
|
||||||
|
licenseIssueDateController = TextEditingController();
|
||||||
|
carLicenseExpiryDateController = TextEditingController();
|
||||||
|
makeController = TextEditingController();
|
||||||
|
modelController = TextEditingController();
|
||||||
|
yearController = TextEditingController();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> fetchDataFromServer() async {
|
||||||
|
isLoading.value = true;
|
||||||
|
try {
|
||||||
|
var responseString = await CRUD().post(
|
||||||
|
link: AppLink.getDriverDetailsForActivate,
|
||||||
|
payload: {'driverId': driverId.value});
|
||||||
|
|
||||||
|
if (responseString != 'failure') {
|
||||||
|
var decodedResponse = jsonDecode(responseString);
|
||||||
|
if (decodedResponse['status'] == 'success' &&
|
||||||
|
(decodedResponse['message'] as List).isNotEmpty) {
|
||||||
|
var rawData = decodedResponse['message'][0] as Map<String, dynamic>;
|
||||||
|
// Sanitize data: ensure all values are strings to prevent type errors
|
||||||
|
serverData.value = rawData
|
||||||
|
.map((key, value) => MapEntry(key, value?.toString() ?? ''));
|
||||||
|
_populateControllersWithServerData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Get.snackbar('Error', 'An unexpected error occurred: $e');
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _populateControllersWithServerData() {
|
||||||
|
firstNameController.text = serverData['first_name'] ?? '';
|
||||||
|
lastNameController.text = serverData['last_name'] ?? '';
|
||||||
|
siteController.text = serverData['site'] ?? '';
|
||||||
|
nationalNumberController.text = serverData['national_number'] ?? '';
|
||||||
|
birthdateController.text = serverData['birthdate'] ?? '';
|
||||||
|
selectedGender.value = serverData['gender'] ?? '';
|
||||||
|
licenseCategoriesController.text = serverData['license_categories'] ?? '';
|
||||||
|
expiryDateController.text = serverData['expiry_date'] ?? '';
|
||||||
|
ownerController.text = serverData['owner'] ?? '';
|
||||||
|
|
||||||
|
final serverColorName = serverData['color'] ?? '';
|
||||||
|
final colorOption = kCarColorOptions.firstWhere(
|
||||||
|
(opt) => opt['key'] == serverColorName,
|
||||||
|
orElse: () => {'key': serverColorName, 'hex': '#000000'}); // Fallback
|
||||||
|
colorController.text = colorOption['key']!;
|
||||||
|
colorHex.value = colorOption['hex']!;
|
||||||
|
|
||||||
|
carPlateController.text = serverData['car_plate'] ?? '';
|
||||||
|
vinController.text = serverData['vin'] ?? '';
|
||||||
|
licenseIssueDateController.text = serverData['issue_date'] ?? '';
|
||||||
|
carLicenseExpiryDateController.text = serverData['expiration_date'] ?? '';
|
||||||
|
makeController.text = serverData['make'] ?? '';
|
||||||
|
modelController.text = serverData['model'] ?? '';
|
||||||
|
selectedFuel.value = serverData['fuel'] ?? '';
|
||||||
|
yearController.text = serverData['year'] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> selectDate(
|
||||||
|
BuildContext context, TextEditingController controller) async {
|
||||||
|
DateTime initialDate = DateTime.now();
|
||||||
|
try {
|
||||||
|
if (controller.text.isNotEmpty)
|
||||||
|
initialDate = DateFormat('yyyy-MM-dd').parse(controller.text);
|
||||||
|
} catch (e) {/* Use default if parsing fails */}
|
||||||
|
|
||||||
|
DateTime? pickedDate = initialDate;
|
||||||
|
await showCupertinoModalPopup<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => Container(
|
||||||
|
height: 280,
|
||||||
|
color: CupertinoColors.systemBackground.resolveFrom(context),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 200,
|
||||||
|
child: CupertinoDatePicker(
|
||||||
|
initialDateTime: initialDate,
|
||||||
|
minimumDate: DateTime(1950),
|
||||||
|
maximumDate: DateTime(2050),
|
||||||
|
mode: CupertinoDatePickerMode.date,
|
||||||
|
onDateTimeChanged: (DateTime newDate) {
|
||||||
|
pickedDate = newDate;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
CupertinoButton(
|
||||||
|
child: Text('Done'.tr),
|
||||||
|
onPressed: () {
|
||||||
|
if (pickedDate != null)
|
||||||
|
controller.text =
|
||||||
|
DateFormat('yyyy-MM-dd').format(pickedDate!);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nextPage() {
|
||||||
|
if (currentPageIndex.value < 3)
|
||||||
|
pageController.nextPage(
|
||||||
|
duration: const Duration(milliseconds: 400), curve: Curves.easeInOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
void previousPage() {
|
||||||
|
if (currentPageIndex.value > 0)
|
||||||
|
pageController.previousPage(
|
||||||
|
duration: const Duration(milliseconds: 400), curve: Curves.easeInOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateAndActivateSyrianDriver() {
|
||||||
|
isLoading.value = true;
|
||||||
|
var bytes = utf8.encode(phoneController.text);
|
||||||
|
|
||||||
|
// 2. Genera el hash MD5 completo
|
||||||
|
var digest = md5.convert(bytes);
|
||||||
|
|
||||||
|
// 3. Convierte el hash a un string (tendrá 32 caracteres)
|
||||||
|
String fullMd5Hash = digest.toString();
|
||||||
|
|
||||||
|
// 4. Trunca el string a los primeros 20 caracteres
|
||||||
|
driverId.value = fullMd5Hash.substring(0, 20);
|
||||||
|
Map<String, dynamic> dataToSend = {
|
||||||
|
// Driver fields from all pages
|
||||||
|
'id': driverId.value,
|
||||||
|
'phone': phoneController.text,
|
||||||
|
'first_name': firstNameController.text,
|
||||||
|
'last_name': lastNameController.text,
|
||||||
|
'site': siteController.text,
|
||||||
|
'national_number': nationalNumberController.text,
|
||||||
|
'gender': selectedGender.value,
|
||||||
|
'birthdate': birthdateController.text,
|
||||||
|
'license_categories': licenseCategoriesController.text,
|
||||||
|
'expiry_date': expiryDateController.text,
|
||||||
|
'license_issue_date': licenseIssueDateController.text,
|
||||||
|
'password': md5.convert(utf8.encode('123456')).toString(),
|
||||||
|
'status': 'actives',
|
||||||
|
// Car fields from all pages
|
||||||
|
'owner': ownerController.text,
|
||||||
|
'color': colorController.text,
|
||||||
|
'color_hex': colorHex.value,
|
||||||
|
'car_plate': carPlateController.text,
|
||||||
|
'maritalStatus': box.read(BoxName.employeename) ?? 'unknown',
|
||||||
|
// 'vin': vinController.text,
|
||||||
|
'expiration_date': carLicenseExpiryDateController.text,
|
||||||
|
'make': makeController.text,
|
||||||
|
'model': modelController.text,
|
||||||
|
'fuel': selectedFuel.value,
|
||||||
|
'year': yearController.text,
|
||||||
|
};
|
||||||
|
|
||||||
|
print("--- Submitting Data to Server ---");
|
||||||
|
print(dataToSend);
|
||||||
|
|
||||||
|
CRUD()
|
||||||
|
.post(
|
||||||
|
link:
|
||||||
|
'${AppLink.server}/serviceapp/registerDriverAndCarService.php',
|
||||||
|
payload: dataToSend)
|
||||||
|
.then((response) {
|
||||||
|
isLoading.value = false;
|
||||||
|
var decodedResponse = (response);
|
||||||
|
Log.print('decodedResponse: ${decodedResponse}');
|
||||||
|
if (decodedResponse != 'failure') {
|
||||||
|
MyDialog().getDialog('Success'.tr, '',
|
||||||
|
Text('Driver has been activated successfully!'.tr), () {
|
||||||
|
Get.back();
|
||||||
|
Get.back();
|
||||||
|
// fetchDataFromServer();
|
||||||
|
Get.back();
|
||||||
|
// Get.off(() => RegisterCaptain());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Get.snackbar(
|
||||||
|
'Error'.tr,
|
||||||
|
'Failed to update driver: ${decodedResponse['message']}'.tr,
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}).catchError((error) {
|
||||||
|
isLoading.value = false;
|
||||||
|
Get.snackbar(
|
||||||
|
'Error'.tr,
|
||||||
|
'An error occurred: $error'.tr,
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static const List<Map<String, String>> kCarColorOptions = [
|
||||||
|
{'key': 'white', 'hex': '#FFFFFF'},
|
||||||
|
{'key': 'black', 'hex': '#000000'},
|
||||||
|
{'key': 'silver', 'hex': '#C0C0C0'},
|
||||||
|
{'key': 'gray', 'hex': '#808080'},
|
||||||
|
{'key': 'gunmetal', 'hex': '#2A3439'},
|
||||||
|
{'key': 'red', 'hex': '#C62828'},
|
||||||
|
{'key': 'blue', 'hex': '#1565C0'},
|
||||||
|
{'key': 'navy', 'hex': '#0D47A1'},
|
||||||
|
{'key': 'green', 'hex': '#2E7D32'},
|
||||||
|
{'key': 'darkGreen', 'hex': '#1B5E20'},
|
||||||
|
{'key': 'beige', 'hex': '#D7CCC8'},
|
||||||
|
{'key': 'brown', 'hex': '#5D4037'},
|
||||||
|
{'key': 'maroon', 'hex': '#800000'},
|
||||||
|
{'key': 'burgundy', 'hex': '#800020'},
|
||||||
|
{'key': 'yellow', 'hex': '#F9A825'},
|
||||||
|
{'key': 'orange', 'hex': '#EF6C00'},
|
||||||
|
{'key': 'gold', 'hex': '#D4AF37'},
|
||||||
|
{'key': 'bronze', 'hex': '#CD7F32'},
|
||||||
|
{'key': 'champagne', 'hex': '#EFE1C6'},
|
||||||
|
{'key': 'purple', 'hex': '#6A1B9A'},
|
||||||
|
];
|
||||||
|
|
||||||
|
static const List<String> kFuelOptions = [
|
||||||
|
'بنزين',
|
||||||
|
'ديزل',
|
||||||
|
'هايبرد',
|
||||||
|
'كهربائي'
|
||||||
|
];
|
||||||
|
|
||||||
|
Color hexToColor(String code) =>
|
||||||
|
Color(int.parse(code.substring(1, 7), radix: 16) + 0xFF000000);
|
||||||
|
|
||||||
|
void updateColorSelection(String hex) {
|
||||||
|
colorHex.value = hex;
|
||||||
|
colorController.text =
|
||||||
|
kCarColorOptions.firstWhere((o) => o['hex'] == hex)['key']!;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
pageController.dispose();
|
||||||
|
firstNameController.dispose();
|
||||||
|
lastNameController.dispose();
|
||||||
|
siteController.dispose();
|
||||||
|
nationalNumberController.dispose();
|
||||||
|
birthdateController.dispose();
|
||||||
|
licenseCategoriesController.dispose();
|
||||||
|
expiryDateController.dispose();
|
||||||
|
ownerController.dispose();
|
||||||
|
colorController.dispose();
|
||||||
|
carPlateController.dispose();
|
||||||
|
vinController.dispose();
|
||||||
|
licenseIssueDateController.dispose();
|
||||||
|
carLicenseExpiryDateController.dispose();
|
||||||
|
makeController.dispose();
|
||||||
|
modelController.dispose();
|
||||||
|
yearController.dispose();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
|||||||
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:service/main.dart';
|
||||||
import 'package:service/views/widgets/my_textField.dart';
|
import 'package:service/views/widgets/my_textField.dart';
|
||||||
import 'controller/login_controller.dart';
|
import 'controller/login_controller.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:get_storage/get_storage.dart';
|
import 'package:get_storage/get_storage.dart';
|
||||||
|
import 'package:service/controller/firbase_messge.dart';
|
||||||
|
import 'package:service/firebase_options.dart';
|
||||||
|
|
||||||
import 'controller/functions/encrypt_decrypt.dart';
|
import 'controller/functions/encrypt_decrypt.dart';
|
||||||
import 'controller/functions/initilize.dart';
|
import 'controller/functions/initilize.dart';
|
||||||
@@ -14,31 +17,15 @@ const storage = FlutterSecureStorage();
|
|||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
// if (Platform.isAndroid || Platform.isIOS) {
|
|
||||||
// await Firebase.initializeApp(
|
|
||||||
// options: DefaultFirebaseOptions.currentPlatform,
|
|
||||||
// );
|
|
||||||
// await FirebaseMessagesController().requestFirebaseMessagingPermission();
|
|
||||||
|
|
||||||
// // FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
|
|
||||||
|
|
||||||
// List<Future> initializationTasks = [
|
|
||||||
// FirebaseMessagesController().getNotificationSettings(),
|
|
||||||
// FirebaseMessagesController().getToken(),
|
|
||||||
// ];
|
|
||||||
// // cameras = await availableCameras();
|
|
||||||
// await Future.wait(initializationTasks);
|
|
||||||
// SystemChrome.setPreferredOrientations([
|
|
||||||
// DeviceOrientation.portraitUp,
|
|
||||||
// DeviceOrientation.portraitDown,
|
|
||||||
// ]);
|
|
||||||
// }
|
|
||||||
final AppInitializer initializer = AppInitializer();
|
|
||||||
|
|
||||||
await initializer.initializeApp();
|
|
||||||
await Future.delayed(Duration.zero);
|
|
||||||
await EncryptionHelper.initialize();
|
await EncryptionHelper.initialize();
|
||||||
|
if (Firebase.apps.isEmpty) {
|
||||||
|
await Firebase.initializeApp(
|
||||||
|
options: DefaultFirebaseOptions.currentPlatform);
|
||||||
|
} else {
|
||||||
|
Firebase.app();
|
||||||
|
}
|
||||||
|
Get.put(FirebaseMessagesController()).getToken();
|
||||||
runApp(MyApp());
|
runApp(MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +36,7 @@ class MyApp extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetMaterialApp(
|
return GetMaterialApp(
|
||||||
title: 'Sefer Service'.tr,
|
title: 'Inatleq Service'.tr,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
translations: MyTranslation(),
|
translations: MyTranslation(),
|
||||||
locale: localController.language,
|
locale: localController.language,
|
||||||
|
|||||||
@@ -12,465 +12,485 @@ import 'package:service/views/widgets/elevated_btn.dart';
|
|||||||
import 'package:service/views/widgets/my_dialog.dart';
|
import 'package:service/views/widgets/my_dialog.dart';
|
||||||
import 'package:service/views/widgets/my_textField.dart';
|
import 'package:service/views/widgets/my_textField.dart';
|
||||||
|
|
||||||
|
import '../../constant/box_name.dart';
|
||||||
import '../../constant/style.dart';
|
import '../../constant/style.dart';
|
||||||
import '../../controller/mainController/pages/add_car.dart';
|
import '../../controller/mainController/pages/add_car.dart';
|
||||||
import '../../controller/mainController/pages/contact_page.dart';
|
|
||||||
import '../../controller/mainController/pages/drivers_cant_register.dart';
|
import '../../controller/mainController/pages/drivers_cant_register.dart';
|
||||||
|
import '../../controller/mainController/pages/new_driver.dart';
|
||||||
import '../../controller/mainController/pages/welcome_call.dart';
|
import '../../controller/mainController/pages/welcome_call.dart';
|
||||||
|
import '../../main.dart';
|
||||||
|
import '../../print.dart';
|
||||||
import '../widgets/my_scafold.dart';
|
import '../widgets/my_scafold.dart';
|
||||||
|
|
||||||
|
// --- Service Item Model ---
|
||||||
|
// A helper class to structure the data for each service card.
|
||||||
|
// This makes the code cleaner and easier to manage.
|
||||||
|
class ServiceItem {
|
||||||
|
final String title;
|
||||||
|
final IconData icon;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
ServiceItem({required this.title, required this.icon, required this.onTap});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Main Screen Widget (Redesigned) ---
|
||||||
class Main extends StatelessWidget {
|
class Main extends StatelessWidget {
|
||||||
Main({super.key});
|
Main({super.key});
|
||||||
MainController mainController = Get.put(MainController());
|
|
||||||
|
final MainController mainController = Get.put(MainController());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MyScaffold(title: 'Sefer Service'.tr, isleading: false, body: [
|
// --- List of Services ---
|
||||||
ListView(
|
// All services are defined here in a list. This makes it easy to add, remove, or reorder them.
|
||||||
children: [
|
// The original onTap logic is preserved exactly as it was.
|
||||||
InkWell(
|
final List<ServiceItem> services = [
|
||||||
onTap: () {
|
ServiceItem(
|
||||||
MyDialog().getDialog(
|
title: 'passenger details by phone'.tr,
|
||||||
'insert passenger phone'.tr,
|
icon: Icons.person_search_rounded,
|
||||||
'midTitle',
|
onTap: () {
|
||||||
Column(
|
MyDialog().getDialog(
|
||||||
children: [
|
'insert passenger phone'.tr,
|
||||||
Form(
|
'midTitle',
|
||||||
key: mainController.formKey,
|
Column(children: [
|
||||||
child: MyTextForm(
|
Form(
|
||||||
controller: mainController.passengerPhoneController,
|
key: mainController.formKey,
|
||||||
label: 'insert passenger phone'.tr,
|
child: MyTextForm(
|
||||||
hint: 'insert passenger phone'.tr,
|
controller: mainController.passengerPhoneController,
|
||||||
type: TextInputType.phone,
|
label: 'insert passenger phone'.tr,
|
||||||
)),
|
hint: 'insert passenger phone'.tr,
|
||||||
],
|
type: TextInputType.phone,
|
||||||
),
|
|
||||||
() {
|
|
||||||
mainController.searchPassengerByPhone();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
decoration: AppStyle.boxDecoration,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
|
||||||
'passenger details by phone'.tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
]),
|
||||||
),
|
() => mainController.searchPassengerByPhone(),
|
||||||
const SizedBox(
|
);
|
||||||
height: 20,
|
},
|
||||||
),
|
),
|
||||||
InkWell(
|
ServiceItem(
|
||||||
onTap: () {
|
title: 'Driver details by phone'.tr,
|
||||||
MyDialog().getDialog(
|
icon: Icons.support_agent_rounded,
|
||||||
'insert Driver phone'.tr,
|
onTap: () {
|
||||||
'midTitle',
|
MyDialog().getDialog(
|
||||||
Column(
|
'insert Driver phone'.tr,
|
||||||
children: [
|
'midTitle',
|
||||||
Form(
|
Column(children: [
|
||||||
key: mainController.formKey,
|
Form(
|
||||||
child: MyTextForm(
|
key: mainController.formKey,
|
||||||
controller: mainController.driverPhoneController,
|
child: MyTextForm(
|
||||||
label: 'insert Driver phone'.tr,
|
controller: mainController.driverPhoneController,
|
||||||
hint: 'insert Driver phone'.tr,
|
label: 'insert Driver phone'.tr,
|
||||||
type: TextInputType.phone,
|
hint: 'insert Driver phone'.tr,
|
||||||
)),
|
type: TextInputType.phone,
|
||||||
],
|
|
||||||
),
|
|
||||||
() {
|
|
||||||
mainController.searchDriverByPhone();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
decoration: AppStyle.boxDecoration,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
|
||||||
'Driver details by phone'.tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
]),
|
||||||
),
|
() => mainController.searchDriverByPhone(),
|
||||||
const SizedBox(
|
);
|
||||||
height: 20,
|
},
|
||||||
),
|
),
|
||||||
InkWell(
|
ServiceItem(
|
||||||
onTap: () async {
|
title: 'Driver details by national number'.tr,
|
||||||
await mainController.getDriverNotCompleteRegistration();
|
icon: Icons.support_agent_rounded,
|
||||||
Get.to(() => DriversCantRegister());
|
onTap: () {
|
||||||
},
|
MyDialog().getDialog(
|
||||||
child: Container(
|
'insert Driver national'.tr,
|
||||||
decoration: AppStyle.boxDecoration,
|
'midTitle',
|
||||||
child: Padding(
|
Column(children: [
|
||||||
padding: const EdgeInsets.all(8.0),
|
Form(
|
||||||
child: Text(
|
key: mainController.formKey,
|
||||||
'Drivers Cant Register'.tr,
|
child: MyTextForm(
|
||||||
style: AppStyle.title,
|
controller: mainController.driverPhoneController,
|
||||||
textAlign: TextAlign.center,
|
label: 'insert Driver national'.tr,
|
||||||
|
hint: 'insert Driver national'.tr,
|
||||||
|
type: TextInputType.number,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
]),
|
||||||
|
() => mainController.searchDriverByNational(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: 'Drivers waitting Register'.tr,
|
||||||
|
icon: Icons.pending_actions_rounded,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getDriverWantCompleteRegistration();
|
||||||
|
Get.to(() => DriversCantRegister());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: 'Register new driver'.tr,
|
||||||
|
icon: Icons.person,
|
||||||
|
onTap: () {
|
||||||
|
// await mainController.getDriverWantCompleteRegistration();
|
||||||
|
Get.to(() => RegisterCaptain());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: 'Drivers Cant Register'.tr,
|
||||||
|
icon: Icons.car_crash,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getDriverNotCompleteRegistration();
|
||||||
|
Get.to(() => DriversCantRegister());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: 'Drivers phones not register'.tr,
|
||||||
|
icon: Icons.person,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getDriversPhoneNotComplete();
|
||||||
|
Get.to(() => DriversCantRegister());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: 'Drivers Activity'.tr,
|
||||||
|
icon: Icons.person,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getDriversPhoneNotComplete();
|
||||||
|
Get.to(() => DriversCantRegister());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: 'Passengers Cant Register'.tr,
|
||||||
|
icon: Icons.group_off_rounded,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getPassengerNotCompleteRegistration();
|
||||||
|
Get.to(() => PassengersCantRegister());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: 'Add car'.tr,
|
||||||
|
icon: Icons.add_circle_outline_rounded,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getdriverWithoutCar();
|
||||||
|
if (mainController.driverWithoutCar.isNotEmpty) {
|
||||||
|
Get.to(() => const AddCar());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: 'Edit car plate'.tr,
|
||||||
|
icon: Icons.edit_note_rounded,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getCarPlateNotEdit();
|
||||||
|
if (mainController.carPlateNotEdit.isNotEmpty) {
|
||||||
|
Get.to(() => const EditCarPlate());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: "View complaint".tr,
|
||||||
|
icon: Icons.report_problem_rounded,
|
||||||
|
onTap: () {
|
||||||
|
Get.to(() => const Complaint());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: "Welcome call".tr,
|
||||||
|
icon: Icons.ring_volume_rounded,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getNewDriverRegister();
|
||||||
|
Get.to(() => const WelcomeCall());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: "best driver".tr,
|
||||||
|
icon: Icons.emoji_events_rounded,
|
||||||
|
onTap: () async {
|
||||||
|
await mainController.getNewDriverRegister();
|
||||||
|
Get.to(() => DriverTheBest());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ServiceItem(
|
||||||
|
title: "Add Driver Who Wants to Work".tr,
|
||||||
|
icon: Icons.person_add_alt_1_rounded,
|
||||||
|
onTap: () {
|
||||||
|
Get.defaultDialog(
|
||||||
|
barrierDismissible: false,
|
||||||
|
title: "Add Driver Who Wants to Work".tr,
|
||||||
|
content: SizedBox(
|
||||||
|
width: Get.width * .7,
|
||||||
|
height: 300,
|
||||||
|
child: Form(
|
||||||
|
key: mainController.formKey,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.driverNameController,
|
||||||
|
label: 'Insert Name of Driver'.tr,
|
||||||
|
hint: 'Insert Name of Driver'.tr,
|
||||||
|
type: TextInputType.name),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.nationalIdController,
|
||||||
|
label: 'Insert national ID of Driver'.tr,
|
||||||
|
hint: 'Insert national ID of Driver'.tr,
|
||||||
|
type: TextInputType.number),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.phoneController,
|
||||||
|
label: 'Insert phone of Driver'.tr,
|
||||||
|
hint: 'Insert phone of Driver'.tr,
|
||||||
|
type: TextInputType.phone),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.licenseTypeController,
|
||||||
|
label: 'Insert license type of Driver'.tr,
|
||||||
|
hint: 'Insert license type of Driver'.tr,
|
||||||
|
type: TextInputType.name),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.siteDriverController,
|
||||||
|
label: 'Insert site of Driver'.tr,
|
||||||
|
hint: 'Insert site of Driver'.tr,
|
||||||
|
type: TextInputType.name),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.birthDateController,
|
||||||
|
label: 'Insert birth_date of Driver'.tr,
|
||||||
|
hint: 'Insert license type of Driver'.tr,
|
||||||
|
type: TextInputType.number),
|
||||||
|
],
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
),
|
confirm: MyElevatedButton(
|
||||||
const SizedBox(
|
title: 'Add'.tr,
|
||||||
height: 20,
|
onPressed: () async {
|
||||||
),
|
// if (mainController.formKey.currentState!.validate()) {
|
||||||
InkWell(
|
var res = await CRUD()
|
||||||
onTap: () async {
|
.post(link: AppLink.addDriverWantWork, payload: {
|
||||||
await mainController.getPassengerNotCompleteRegistration();
|
"driver_name": mainController.driverNameController.text,
|
||||||
Get.to(() => PassengersCantRegister());
|
"national_id": mainController.nationalIdController.text,
|
||||||
},
|
"birth_date": mainController.birthDateController.text,
|
||||||
child: Container(
|
"site": mainController.siteDriverController.text,
|
||||||
decoration: AppStyle.boxDecoration,
|
"license_type": mainController.licenseTypeController.text,
|
||||||
child: Padding(
|
"phone": mainController.phoneController.text,
|
||||||
padding: const EdgeInsets.all(8.0),
|
});
|
||||||
child: Text(
|
if (res != 'failure') {
|
||||||
'Passengers Cant Register'.tr,
|
Get.back();
|
||||||
style: AppStyle.title,
|
mainController.driverNameController.clear();
|
||||||
textAlign: TextAlign.center,
|
mainController.nationalIdController.clear();
|
||||||
),
|
mainController.birthDateController.clear();
|
||||||
),
|
mainController.licenseTypeController.clear();
|
||||||
|
mainController.siteDriverController.clear();
|
||||||
|
mainController.phoneController.clear();
|
||||||
|
Get.snackbar('done', '',
|
||||||
|
backgroundColor: AppColor.greenColor);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
kolor: AppColor.greenColor,
|
||||||
),
|
),
|
||||||
),
|
cancel: MyElevatedButton(
|
||||||
const SizedBox(
|
title: 'Cancel'.tr,
|
||||||
height: 20,
|
kolor: AppColor.redColor,
|
||||||
),
|
onPressed: () {
|
||||||
InkWell(
|
Get.back();
|
||||||
onTap: () async {
|
}),
|
||||||
await mainController.getdriverWithoutCar();
|
);
|
||||||
if (mainController.driverWithoutCar.isNotEmpty) {
|
},
|
||||||
Get.to(() => const AddCar());
|
),
|
||||||
}
|
ServiceItem(
|
||||||
},
|
title: "Add Car Who Wants to Work".tr,
|
||||||
child: Container(
|
icon: Icons.directions_car_filled_rounded,
|
||||||
decoration: AppStyle.boxDecoration,
|
onTap: () {
|
||||||
child: Padding(
|
Get.defaultDialog(
|
||||||
padding: const EdgeInsets.all(8.0),
|
barrierDismissible: false,
|
||||||
child: Text(
|
title: "Add Car Who Wants to Work".tr,
|
||||||
'Add car'.tr,
|
content: SizedBox(
|
||||||
style: AppStyle.title,
|
width: Get.width * .7,
|
||||||
textAlign: TextAlign.center,
|
height: 300,
|
||||||
),
|
child: Form(
|
||||||
),
|
key: mainController.formKey,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.carOwnerWorkController,
|
||||||
|
label: 'Insert Name of Owner'.tr,
|
||||||
|
hint: 'Insert Name of Owner'.tr,
|
||||||
|
type: TextInputType.name),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.carNumberController,
|
||||||
|
label: 'Insert car_number of Driver'.tr,
|
||||||
|
hint: 'Insert car_number of Driver'.tr,
|
||||||
|
type: TextInputType.name),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.phoneCarController,
|
||||||
|
label: 'Insert phone of Owner'.tr,
|
||||||
|
hint: 'Insert phone of Owner'.tr,
|
||||||
|
type: TextInputType.phone),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.manufactureYearController,
|
||||||
|
label: 'Insert year of Car'.tr,
|
||||||
|
hint: 'Insert year of Car'.tr,
|
||||||
|
type: TextInputType.number),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.carModelController,
|
||||||
|
label: 'Insert car_model of Driver'.tr,
|
||||||
|
hint: 'Insert car_model of Driver'.tr,
|
||||||
|
type: TextInputType.name),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.siteCarController,
|
||||||
|
label: 'Insert site of Owner'.tr,
|
||||||
|
hint: 'Insert site of Owner'.tr,
|
||||||
|
type: TextInputType.name),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.carTypeController,
|
||||||
|
label: 'Insert car_type of Driver'.tr,
|
||||||
|
hint: 'Insert car_type of Driver'.tr,
|
||||||
|
type: TextInputType.name),
|
||||||
|
MyTextForm(
|
||||||
|
controller: mainController.registrationDateController,
|
||||||
|
label: 'Insert registration_date of Car'.tr,
|
||||||
|
hint: 'Insert registration_date of Car'.tr,
|
||||||
|
type: TextInputType.datetime),
|
||||||
|
],
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
),
|
confirm: MyElevatedButton(
|
||||||
InkWell(
|
title: 'Add'.tr,
|
||||||
onTap: () async {
|
onPressed: () async {
|
||||||
await mainController.getCarPlateNotEdit();
|
// if (mainController.formKey.currentState!.validate()) {
|
||||||
if (mainController.carPlateNotEdit.isNotEmpty) {
|
var res =
|
||||||
Get.to(() => const EditCarPlate());
|
await CRUD().post(link: AppLink.addCarWantWork, payload: {
|
||||||
}
|
"owner_name": mainController.carOwnerWorkController.text,
|
||||||
},
|
"car_number": mainController.carNumberController.text,
|
||||||
child: Container(
|
"manufacture_year":
|
||||||
decoration: AppStyle.boxDecoration,
|
mainController.manufactureYearController.text,
|
||||||
child: Padding(
|
"car_model": mainController.carModelController.text,
|
||||||
padding: const EdgeInsets.all(8.0),
|
"car_type": mainController.carTypeController.text,
|
||||||
child: Text(
|
"site": mainController.siteCarController.text,
|
||||||
'Edit car plate'.tr,
|
"registration_date":
|
||||||
style: AppStyle.title,
|
mainController.registrationDateController.text,
|
||||||
textAlign: TextAlign.center,
|
"phone": mainController.phoneCarController.text,
|
||||||
),
|
});
|
||||||
),
|
Log.print('res: ${res}');
|
||||||
|
if (res != 'failure') {
|
||||||
|
Get.back();
|
||||||
|
mainController.ownerController.clear();
|
||||||
|
mainController.carNumberController.clear();
|
||||||
|
mainController.manufactureYearController.clear();
|
||||||
|
mainController.carModelController.clear();
|
||||||
|
mainController.siteCarController.clear();
|
||||||
|
mainController.carTypeController.clear();
|
||||||
|
mainController.registrationDateController.clear();
|
||||||
|
mainController.phoneController.clear();
|
||||||
|
Get.snackbar('done', '',
|
||||||
|
backgroundColor: AppColor.greenColor);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
kolor: AppColor.greenColor,
|
||||||
),
|
),
|
||||||
|
cancel: MyElevatedButton(
|
||||||
|
title: 'Cancel'.tr,
|
||||||
|
kolor: AppColor.redColor,
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
// --- Building the UI ---
|
||||||
|
return MyScaffold(
|
||||||
|
title: 'Intaleq Service'.tr,
|
||||||
|
isleading: false,
|
||||||
|
action: MyElevatedButton(
|
||||||
|
title: 'Logout'.tr,
|
||||||
|
onPressed: () async {
|
||||||
|
// box.write(BoxName.employeename, 'masa');
|
||||||
|
print(box.read(BoxName.employeename).toString());
|
||||||
|
},
|
||||||
|
kolor: AppColor.redColor,
|
||||||
|
),
|
||||||
|
// The body now uses a GridView for a better layout.
|
||||||
|
// You can replace the color with your main theme color.
|
||||||
|
// backgroundColor: const Color(0xFFF5F7FA),
|
||||||
|
body: [
|
||||||
|
GridView.builder(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
itemCount: services.length,
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 2, // Two columns
|
||||||
|
crossAxisSpacing: 16.0, // Horizontal space between cards
|
||||||
|
mainAxisSpacing: 16.0, // Vertical space between cards
|
||||||
|
childAspectRatio: 1.1, // Adjust card shape (width/height ratio)
|
||||||
),
|
),
|
||||||
const SizedBox(
|
itemBuilder: (context, index) {
|
||||||
height: 20,
|
final service = services[index];
|
||||||
),
|
return ServiceCard(
|
||||||
InkWell(
|
title: service.title,
|
||||||
onTap: () async {
|
icon: service.icon,
|
||||||
// await mainController.getCarPlateNotEdit();
|
onTap: service.onTap,
|
||||||
// if (mainController.carPlateNotEdit.isNotEmpty) {
|
);
|
||||||
Get.to(() => const Complaint());
|
},
|
||||||
// }
|
),
|
||||||
},
|
],
|
||||||
child: Container(
|
);
|
||||||
decoration: AppStyle.boxDecoration,
|
}
|
||||||
child: Padding(
|
}
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
// --- Service Card Widget ---
|
||||||
"View complaint".tr,
|
// A reusable widget for displaying each service.
|
||||||
style: AppStyle.title,
|
class ServiceCard extends StatelessWidget {
|
||||||
textAlign: TextAlign.center,
|
final String title;
|
||||||
),
|
final IconData icon;
|
||||||
),
|
final VoidCallback onTap;
|
||||||
),
|
|
||||||
),
|
const ServiceCard({
|
||||||
const SizedBox(
|
super.key,
|
||||||
height: 20,
|
required this.title,
|
||||||
),
|
required this.icon,
|
||||||
InkWell(
|
required this.onTap,
|
||||||
onTap: () async {
|
});
|
||||||
await mainController.getNewDriverRegister();
|
|
||||||
// if (mainController.carPlateNotEdit.isNotEmpty) {
|
@override
|
||||||
Get.to(() => const WelcomeCall());
|
Widget build(BuildContext context) {
|
||||||
// }
|
return InkWell(
|
||||||
},
|
onTap: onTap,
|
||||||
child: Container(
|
borderRadius: BorderRadius.circular(16.0),
|
||||||
decoration: AppStyle.boxDecoration,
|
child: Container(
|
||||||
child: Padding(
|
decoration: BoxDecoration(
|
||||||
padding: const EdgeInsets.all(8.0),
|
color: Colors.white,
|
||||||
child: Text(
|
borderRadius: BorderRadius.circular(16.0),
|
||||||
"Welcome call".tr,
|
boxShadow: [
|
||||||
style: AppStyle.title,
|
BoxShadow(
|
||||||
textAlign: TextAlign.center,
|
color: Colors.grey.withOpacity(0.15),
|
||||||
),
|
spreadRadius: 2,
|
||||||
),
|
blurRadius: 8,
|
||||||
),
|
offset: const Offset(0, 4), // changes position of shadow
|
||||||
),
|
),
|
||||||
const SizedBox(
|
],
|
||||||
height: 20,
|
),
|
||||||
),
|
child: Column(
|
||||||
InkWell(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
onTap: () async {
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
await mainController.getNewDriverRegister();
|
children: [
|
||||||
// if (mainController.carPlateNotEdit.isNotEmpty) {
|
// Icon
|
||||||
Get.to(() => DriverTheBest());
|
Icon(
|
||||||
// }
|
icon,
|
||||||
},
|
size: 48.0,
|
||||||
child: Container(
|
// You can replace this color with your AppStyle color
|
||||||
decoration: AppStyle.boxDecoration,
|
color: Theme.of(context).primaryColor,
|
||||||
child: Padding(
|
),
|
||||||
padding: const EdgeInsets.all(8.0),
|
const SizedBox(height: 12),
|
||||||
child: Text(
|
// Title
|
||||||
"best driver".tr,
|
Padding(
|
||||||
style: AppStyle.title,
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
textAlign: TextAlign.center,
|
child: Text(
|
||||||
),
|
title,
|
||||||
),
|
textAlign: TextAlign.center,
|
||||||
),
|
style: const TextStyle(
|
||||||
),
|
fontWeight: FontWeight.w600,
|
||||||
const SizedBox(
|
fontSize: 14,
|
||||||
height: 20,
|
// You can replace this color with your AppStyle color
|
||||||
),
|
color: Color(0xFF4A4A4A),
|
||||||
InkWell(
|
),
|
||||||
onTap: () async {
|
maxLines: 2,
|
||||||
Get.defaultDialog(
|
overflow: TextOverflow.ellipsis,
|
||||||
barrierDismissible: false,
|
),
|
||||||
title: "Add Driver Who Wants to Work".tr,
|
),
|
||||||
content: SizedBox(
|
],
|
||||||
width: Get.width * .7,
|
),
|
||||||
height: 300,
|
),
|
||||||
child: Form(
|
);
|
||||||
key: mainController.formKey,
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.driverNameController,
|
|
||||||
label: 'Insert Name of Driver'.tr,
|
|
||||||
hint: 'Insert Name of Driver'.tr,
|
|
||||||
type: TextInputType.name),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.nationalIdController,
|
|
||||||
label: 'Insert national ID of Driver'.tr,
|
|
||||||
hint: 'Insert national ID of Driver'.tr,
|
|
||||||
type: TextInputType.number),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.phoneController,
|
|
||||||
label: 'Insert phone of Driver'.tr,
|
|
||||||
hint: 'Insert phone of Driver'.tr,
|
|
||||||
type: TextInputType.phone),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.licenseTypeController,
|
|
||||||
label: 'Insert license type of Driver'.tr,
|
|
||||||
hint: 'Insert license type of Driver'.tr,
|
|
||||||
type: TextInputType.name),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.siteDriverController,
|
|
||||||
label: 'Insert site of Driver'.tr,
|
|
||||||
hint: 'Insert site of Driver'.tr,
|
|
||||||
type: TextInputType.name),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.birthDateController,
|
|
||||||
label: 'Insert birth_date of Driver'.tr,
|
|
||||||
hint: 'Insert license type of Driver'.tr,
|
|
||||||
type: TextInputType.number),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
confirm: MyElevatedButton(
|
|
||||||
title: 'Add'.tr,
|
|
||||||
onPressed: () async {
|
|
||||||
if (mainController.formKey.currentState!.validate()) {
|
|
||||||
var res = await CRUD()
|
|
||||||
.post(link: AppLink.addDriverWantWork, payload: {
|
|
||||||
"driver_name": mainController.driverNameController.text,
|
|
||||||
"national_id": mainController.nationalIdController.text,
|
|
||||||
"birth_date": mainController.birthDateController.text,
|
|
||||||
"site": mainController.siteDriverController.text,
|
|
||||||
"license_type":
|
|
||||||
mainController.licenseTypeController.text,
|
|
||||||
"phone": mainController.phoneController.text,
|
|
||||||
});
|
|
||||||
if (res != 'failure') {
|
|
||||||
Get.back();
|
|
||||||
mainController.driverNameController.clear();
|
|
||||||
mainController.nationalIdController.clear();
|
|
||||||
mainController.birthDateController.clear();
|
|
||||||
mainController.licenseTypeController.clear();
|
|
||||||
mainController.siteDriverController.clear();
|
|
||||||
mainController.phoneController.clear();
|
|
||||||
Get.snackbar('done', '',
|
|
||||||
backgroundColor: AppColor.greenColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
kolor: AppColor.greenColor,
|
|
||||||
),
|
|
||||||
cancel: MyElevatedButton(
|
|
||||||
title: 'Cancel'.tr,
|
|
||||||
kolor: AppColor.redColor,
|
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
decoration: AppStyle.boxDecoration,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
|
||||||
"Add Driver Who Wants to Work".tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 20,
|
|
||||||
),
|
|
||||||
InkWell(
|
|
||||||
onTap: () async {
|
|
||||||
Get.defaultDialog(
|
|
||||||
barrierDismissible: false,
|
|
||||||
title: "Add Car Who Wants to Work".tr,
|
|
||||||
content: SizedBox(
|
|
||||||
width: Get.width * .7,
|
|
||||||
height: 300,
|
|
||||||
child: Form(
|
|
||||||
key: mainController.formKey,
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.carOwnerWorkController,
|
|
||||||
label: 'Insert Name of Owner'.tr,
|
|
||||||
hint: 'Insert Name of Owner'.tr,
|
|
||||||
type: TextInputType.name),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.carNumberController,
|
|
||||||
label: 'Insert car_number of Driver'.tr,
|
|
||||||
hint: 'Insert car_number of Driver'.tr,
|
|
||||||
type: TextInputType.name),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.phoneCarController,
|
|
||||||
label: 'Insert phone of Owner'.tr,
|
|
||||||
hint: 'Insert phone of Owner'.tr,
|
|
||||||
type: TextInputType.phone),
|
|
||||||
MyTextForm(
|
|
||||||
controller:
|
|
||||||
mainController.manufactureYearController,
|
|
||||||
label: 'Insert year of Car'.tr,
|
|
||||||
hint: 'Insert year of Car'.tr,
|
|
||||||
type: TextInputType.number),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.carModelController,
|
|
||||||
label: 'Insert car_model of Driver'.tr,
|
|
||||||
hint: 'Insert car_model of Driver'.tr,
|
|
||||||
type: TextInputType.name),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.siteCarController,
|
|
||||||
label: 'Insert site of Owner'.tr,
|
|
||||||
hint: 'Insert site of Owner'.tr,
|
|
||||||
type: TextInputType.name),
|
|
||||||
MyTextForm(
|
|
||||||
controller: mainController.carTypeController,
|
|
||||||
label: 'Insert car_type of Driver'.tr,
|
|
||||||
hint: 'Insert car_type of Driver'.tr,
|
|
||||||
type: TextInputType.name),
|
|
||||||
MyTextForm(
|
|
||||||
controller:
|
|
||||||
mainController.registrationDateController,
|
|
||||||
label: 'Insert registration_date of Car'.tr,
|
|
||||||
hint: 'Insert registration_date of Car'.tr,
|
|
||||||
type: TextInputType.datetime),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
confirm: MyElevatedButton(
|
|
||||||
title: 'Add'.tr,
|
|
||||||
onPressed: () async {
|
|
||||||
if (mainController.formKey.currentState!.validate()) {
|
|
||||||
var res = await CRUD()
|
|
||||||
.post(link: AppLink.addCarWantWork, payload: {
|
|
||||||
"owner_name":
|
|
||||||
mainController.carOwnerWorkController.text,
|
|
||||||
"car_number": mainController.carNumberController.text,
|
|
||||||
"manufacture_year":
|
|
||||||
mainController.manufactureYearController.text,
|
|
||||||
"car_model": mainController.carModelController.text,
|
|
||||||
"car_type": mainController.carTypeController.text,
|
|
||||||
"site": mainController.siteCarController.text,
|
|
||||||
"registration_date":
|
|
||||||
mainController.registrationDateController.text,
|
|
||||||
"phone": mainController.phoneCarController.text,
|
|
||||||
});
|
|
||||||
if (res != 'failure') {
|
|
||||||
Get.back();
|
|
||||||
mainController.ownerController.clear();
|
|
||||||
mainController.carNumberController.clear();
|
|
||||||
mainController.manufactureYearController.clear();
|
|
||||||
mainController.carModelController.clear();
|
|
||||||
mainController.siteCarController.clear();
|
|
||||||
mainController.carTypeController.clear();
|
|
||||||
mainController.registrationDateController.clear();
|
|
||||||
mainController.phoneController.clear();
|
|
||||||
Get.snackbar('done', '',
|
|
||||||
backgroundColor: AppColor.greenColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
kolor: AppColor.greenColor,
|
|
||||||
),
|
|
||||||
cancel: MyElevatedButton(
|
|
||||||
title: 'Cancel'.tr,
|
|
||||||
kolor: AppColor.redColor,
|
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
decoration: AppStyle.boxDecoration,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
|
||||||
"Add Car Who Wants to Work".tr,
|
|
||||||
style: AppStyle.title,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 20,
|
|
||||||
),
|
|
||||||
// GestureDetector(
|
|
||||||
// onTap: () {
|
|
||||||
// Get.to(() => const ContactPage());
|
|
||||||
// },
|
|
||||||
// child: Container(
|
|
||||||
// decoration: AppStyle.boxDecoration,
|
|
||||||
// child: const Center(child: Text('contact')),
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
],
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ class MyScaffold extends StatelessWidget {
|
|||||||
actions: [action],
|
actions: [action],
|
||||||
title: Text(
|
title: Text(
|
||||||
title,
|
title,
|
||||||
style: AppStyle.title.copyWith(fontSize: 30),
|
style: AppStyle.title
|
||||||
|
.copyWith(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: SafeArea(child: Stack(children: body)));
|
body: SafeArea(child: Stack(children: body)));
|
||||||
|
|||||||
@@ -55,11 +55,7 @@ class MyTextForm extends StatelessWidget {
|
|||||||
return 'Please enter a valid email.'.tr;
|
return 'Please enter a valid email.'.tr;
|
||||||
}
|
}
|
||||||
} else if (type == TextInputType.phone) {
|
} else if (type == TextInputType.phone) {
|
||||||
if (box.read(BoxName.countryCode) == 'Egypt') {
|
if (value.length > 14) {
|
||||||
if (value.length != 11) {
|
|
||||||
return 'Please enter a valid phone number.'.tr;
|
|
||||||
}
|
|
||||||
} else if (value.length != 11) {
|
|
||||||
//for this you will return to 10 but now for service egypt
|
//for this you will return to 10 but now for service egypt
|
||||||
return 'Please enter a valid phone number.'.tr;
|
return 'Please enter a valid phone number.'.tr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import firebase_auth
|
|||||||
import firebase_core
|
import firebase_core
|
||||||
import firebase_messaging
|
import firebase_messaging
|
||||||
import flutter_image_compress_macos
|
import flutter_image_compress_macos
|
||||||
|
import flutter_local_notifications
|
||||||
import flutter_secure_storage_macos
|
import flutter_secure_storage_macos
|
||||||
import google_sign_in_ios
|
import google_sign_in_ios
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
@@ -25,6 +26,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||||
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
|
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
|
||||||
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
|
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
|
||||||
|
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
|
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
|||||||
48
pubspec.lock
48
pubspec.lock
@@ -217,6 +217,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.11"
|
||||||
device_info_plus:
|
device_info_plus:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -470,6 +478,38 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.0"
|
version: "6.0.0"
|
||||||
|
flutter_local_notifications:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications
|
||||||
|
sha256: "19ffb0a8bb7407875555e5e98d7343a633bb73707bae6c6a5f37c90014077875"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "19.5.0"
|
||||||
|
flutter_local_notifications_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications_linux
|
||||||
|
sha256: e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.0"
|
||||||
|
flutter_local_notifications_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications_platform_interface
|
||||||
|
sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.1.0"
|
||||||
|
flutter_local_notifications_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications_windows
|
||||||
|
sha256: "8d658f0d367c48bd420e7cf2d26655e2d1130147bca1eea917e576ca76668aaf"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1212,6 +1252,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.4"
|
version: "0.7.4"
|
||||||
|
timezone:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timezone
|
||||||
|
sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ dependencies:
|
|||||||
jwt_decoder: ^2.0.1
|
jwt_decoder: ^2.0.1
|
||||||
encrypt: ^5.0.3
|
encrypt: ^5.0.3
|
||||||
share_plus: ^7.2.1
|
share_plus: ^7.2.1
|
||||||
|
flutter_local_notifications: ^19.5.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -105,7 +106,7 @@ flutter_launcher_icons:
|
|||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
assets:
|
assets:
|
||||||
- assets/images
|
- assets/images/
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
flutter_local_notifications_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|||||||
Reference in New Issue
Block a user