2026-04-03-pre map libra
This commit is contained in:
@@ -20,39 +20,57 @@ android {
|
|||||||
compileSdk = 36
|
compileSdk = 36
|
||||||
ndkVersion "29.0.14033849"
|
ndkVersion "29.0.14033849"
|
||||||
|
|
||||||
externalNativeBuild {
|
|
||||||
cmake {
|
|
||||||
path "src/main/cpp/CMakeLists.txt"
|
|
||||||
// Using a common, stable version. Your CMakeLists.txt requests 3.10.2,
|
|
||||||
// but your old gradle file had 3.22.1 and 3.31.5. Let's use a stable one.
|
|
||||||
version "3.22.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
coreLibraryDesugaringEnabled true
|
coreLibraryDesugaringEnabled true
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_1_8
|
jvmTarget = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path "src/main/cpp/CMakeLists.txt"
|
||||||
|
version "3.22.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// تمت الإضافة: توجيه مسار المكتبات الأصلية لمطابقة تطبيق الراكب
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
jniLibs.srcDirs = ['src/main/jniLibs']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merged the two defaultConfig sections into one. This is the correct way.
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.intaleq_driver"
|
applicationId = "com.intaleq_driver"
|
||||||
minSdkVersion = flutter.minSdkVersion
|
minSdkVersion = flutter.minSdkVersion
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 59
|
versionCode = 61
|
||||||
versionName = '1.1.59' // I've used the higher version name
|
versionName = '1.1.61'
|
||||||
multiDexEnabled = true
|
multiDexEnabled = true
|
||||||
|
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters "armeabi-v7a", "arm64-v8a" // Keep these!
|
abiFilters "armeabi-v7a", "arm64-v8a"
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestPlaceholders += [mapsApiKey: keystoreProperties['mapsApiKey'] ?: ""]
|
manifestPlaceholders += [mapsApiKey: keystoreProperties['mapsApiKey'] ?: ""]
|
||||||
|
|
||||||
|
// تمت الإضافة: تمرير تعليمات 16 KB لمترجم C++
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// تمت الإضافة: منع ضغط المكتبات لتتوافق مع متطلبات نظام التشغيل
|
||||||
|
packaging {
|
||||||
|
jniLibs {
|
||||||
|
useLegacyPackaging = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@@ -80,9 +98,17 @@ flutter {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
// تمت الترقية لتطابق تطبيق الراكب
|
||||||
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||||
|
|
||||||
|
// تمت الترقية لتطابق تطبيق الراكب (لتجنب ملفات 4KB القديمة)
|
||||||
|
implementation "com.stripe:stripe-android:21.4.2"
|
||||||
|
implementation 'com.stripe:paymentsheet:21.4.2'
|
||||||
|
|
||||||
implementation 'com.scottyab:rootbeer-lib:0.1.0'
|
implementation 'com.scottyab:rootbeer-lib:0.1.0'
|
||||||
implementation 'com.stripe:paymentsheet:20.52.2'
|
|
||||||
implementation "androidx.concurrent:concurrent-futures:1.2.0" // Added this from your first file, it was missing
|
// تمت الترقية لتطابق تطبيق الراكب
|
||||||
implementation 'com.google.android.gms:play-services-safetynet:18.0.1'
|
implementation 'com.google.android.gms:play-services-safetynet:18.1.0'
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
|
|
||||||
|
implementation "androidx.concurrent:concurrent-futures:1.2.0"
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '2.1.0'
|
ext.kotlin_version = '2.3.10'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
classpath 'com.android.tools.build:gradle:8.13.2'
|
||||||
classpath 'com.google.gms:google-services:4.3.15'
|
classpath 'com.google.gms:google-services:4.3.15'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
@@ -22,10 +22,29 @@ rootProject.buildDir = '../build'
|
|||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
|
project.evaluationDependsOn(':app')
|
||||||
|
|
||||||
|
def setupAndroid = {
|
||||||
|
if (project.plugins.hasPlugin('com.android.library') || project.plugins.hasPlugin('com.android.application')) {
|
||||||
|
project.android {
|
||||||
|
if (namespace == null || namespace == "") {
|
||||||
|
namespace = project.group
|
||||||
|
}
|
||||||
|
compileSdk 36
|
||||||
|
defaultConfig {
|
||||||
|
targetSdk 36
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
if (project.state.executed) {
|
||||||
project.evaluationDependsOn(':app')
|
setupAndroid()
|
||||||
|
} else {
|
||||||
|
project.afterEvaluate {
|
||||||
|
setupAndroid()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("clean", Delete) {
|
tasks.register("clean", Delete) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
{"buildConfigurations":[{"baseConfigurationFileReference":"bfdfe7dc352907fc980b868725387e98713093b836ed941f0ae441b0f84ea767","buildSettings":{"ASSETCATALOG_COMPILER_APPICON_NAME":"AppIcon","ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME":"AccentColor","CLANG_ENABLE_OBJC_WEAK":"NO","ENABLE_USER_SCRIPT_SANDBOXING":"NO","EXCLUDED_ARCHS[sdk=iphonesimulator*]":"arm64","IPHONEOS_DEPLOYMENT_TARGET":"14.0","LD_RUNPATH_SEARCH_PATHS":"$(inherited) @executable_path/Frameworks","ONLY_ACTIVE_ARCH":"NO","SDKROOT":"iphoneos","TARGETED_DEVICE_FAMILY":"1,2"},"guid":"bfdfe7dc352907fc980b868725387e980bc977b873df9b0e01b3c822e5c77429","name":"Debug"},{"baseConfigurationFileReference":"bfdfe7dc352907fc980b868725387e982a75f557648c19374fbba760cc62794a","buildSettings":{"ASSETCATALOG_COMPILER_APPICON_NAME":"AppIcon","ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME":"AccentColor","CLANG_ENABLE_OBJC_WEAK":"NO","ENABLE_USER_SCRIPT_SANDBOXING":"NO","EXCLUDED_ARCHS[sdk=iphonesimulator*]":"arm64","IPHONEOS_DEPLOYMENT_TARGET":"14.0","LD_RUNPATH_SEARCH_PATHS":"$(inherited) @executable_path/Frameworks","SDKROOT":"iphoneos","TARGETED_DEVICE_FAMILY":"1,2","VALIDATE_PRODUCT":"YES"},"guid":"bfdfe7dc352907fc980b868725387e98b75274b69084014a6a5ac37ea7a9d4bc","name":"Profile"},{"baseConfigurationFileReference":"bfdfe7dc352907fc980b868725387e982a75f557648c19374fbba760cc62794a","buildSettings":{"ASSETCATALOG_COMPILER_APPICON_NAME":"AppIcon","ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME":"AccentColor","CLANG_ENABLE_OBJC_WEAK":"NO","ENABLE_USER_SCRIPT_SANDBOXING":"NO","EXCLUDED_ARCHS[sdk=iphonesimulator*]":"arm64","IPHONEOS_DEPLOYMENT_TARGET":"14.0","LD_RUNPATH_SEARCH_PATHS":"$(inherited) @executable_path/Frameworks","SDKROOT":"iphoneos","TARGETED_DEVICE_FAMILY":"1,2","VALIDATE_PRODUCT":"YES"},"guid":"bfdfe7dc352907fc980b868725387e988b8e6347e534cb57e9bb1b22dc47b716","name":"Release"}],"buildPhases":[],"buildRules":[],"dependencies":[],"guid":"bfdfe7dc352907fc980b868725387e989da425bb6d6d5d8dbb95e4afffb82217","name":"Flutter","provisioningSourceData":[{"bundleIdentifierFromInfoPlist":"","configurationName":"Debug","provisioningStyle":0},{"bundleIdentifierFromInfoPlist":"","configurationName":"Profile","provisioningStyle":0},{"bundleIdentifierFromInfoPlist":"","configurationName":"Release","provisioningStyle":0}],"type":"aggregate"}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
{"guid":"dc4b70c03e8043e50e38f2068887b1d4","name":"Pods","path":"/Users/hamzaaleghwairyeen/development/App/intaleq_driver/ios/Pods/Pods.xcodeproj/project.xcworkspace","projects":["PROJECT@v11_mod=8a8e73429c1ecbff8f5eafafe69e0e09_hash=bfdfe7dc352907fc980b868725387e98plugins=1OJSG6M1FOV3XYQCBH7Z29RZ0FPR9XDE1"]}
|
||||||
File diff suppressed because one or more lines are too long
@@ -16,9 +16,9 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version '8.11.0' apply false
|
id "com.android.application" version '8.13.2' apply false
|
||||||
id "com.google.gms.google-services" version "4.3.10" apply false
|
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||||
id "org.jetbrains.kotlin.android" version "2.1.0" apply false // Updated version
|
id "org.jetbrains.kotlin.android" version "2.3.10" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
include ":app"
|
include ":app"
|
||||||
@@ -23,7 +23,7 @@ apply plugin: 'com.android.library'
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'com.dsaved.bubblehead.bubble'
|
namespace 'com.dsaved.bubblehead.bubble'
|
||||||
compileSdkVersion 33
|
compileSdkVersion 36
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_contacts/contact.dart';
|
import 'package:flutter_contacts/contact.dart';
|
||||||
@@ -124,24 +125,175 @@ Download the Intaleq app now and enjoy your ride!
|
|||||||
/// **MODIFIED**: This function now opens the phone's native contact picker.
|
/// **MODIFIED**: This function now opens the phone's native contact picker.
|
||||||
Future<void> pickContactFromNativeApp() async {
|
Future<void> pickContactFromNativeApp() async {
|
||||||
try {
|
try {
|
||||||
|
log('=== START: FETCHING ALL CONTACTS FOR BOTTOM SHEET ===',
|
||||||
|
name: 'ContactPicker');
|
||||||
|
|
||||||
if (await FlutterContacts.requestPermission(readonly: true)) {
|
if (await FlutterContacts.requestPermission(readonly: true)) {
|
||||||
// 1. Open the native contacts app to select a single contact.
|
// عرض شاشة تحميل بسيطة ريثما يتم جلب الأسماء
|
||||||
final Contact? contact = await FlutterContacts.openExternalPick();
|
Get.dialog(const Center(child: CircularProgressIndicator()),
|
||||||
|
barrierDismissible: false);
|
||||||
|
|
||||||
// 2. If a contact is selected and has a phone number...
|
log('Permission granted. Calling FlutterContacts.getContacts()...',
|
||||||
if (contact != null && contact.phones.isNotEmpty) {
|
name: 'ContactPicker');
|
||||||
String selectedPhone = contact.phones.first.number;
|
|
||||||
|
|
||||||
// 3. Format the number and update the text field.
|
// جلب جميع جهات الاتصال إجبارياً من الصفر مع خصائصها
|
||||||
invitePhoneController.text = _formatSyrianPhoneNumber(selectedPhone);
|
List<Contact> allContacts =
|
||||||
update();
|
await FlutterContacts.getContacts(withProperties: true);
|
||||||
}
|
|
||||||
|
log('Total Contacts Fetched from Device: ${allContacts.length}',
|
||||||
|
name: 'ContactPicker');
|
||||||
|
|
||||||
|
// فصل الأسماء لمعرفة الخلل
|
||||||
|
List<Contact> validContacts = [];
|
||||||
|
List<Contact> invalidContacts = [];
|
||||||
|
|
||||||
|
for (var c in allContacts) {
|
||||||
|
if (c.phones.isNotEmpty) {
|
||||||
|
validContacts.add(c);
|
||||||
} else {
|
} else {
|
||||||
|
invalidContacts.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log('Contacts WITH phone numbers: ${validContacts.length}',
|
||||||
|
name: 'ContactPicker');
|
||||||
|
log('Contacts WITHOUT phone numbers: ${invalidContacts.length}',
|
||||||
|
name: 'ContactPicker');
|
||||||
|
|
||||||
|
// طباعة أول 20 اسم صالح
|
||||||
|
log('--- Sample of VALID Contacts ---', name: 'ContactPicker');
|
||||||
|
for (int i = 0; i < validContacts.length && i < 20; i++) {
|
||||||
|
log('[$i] Name: ${validContacts[i].displayName}, Phone: ${validContacts[i].phones.first.number}',
|
||||||
|
name: 'ContactPicker');
|
||||||
|
}
|
||||||
|
|
||||||
|
// طباعة أول 20 اسم غير صالح (بدون أرقام) لفحص المشكلة
|
||||||
|
log('--- Sample of INVALID Contacts (No Phone) ---',
|
||||||
|
name: 'ContactPicker');
|
||||||
|
for (int i = 0; i < invalidContacts.length && i < 20; i++) {
|
||||||
|
log('[$i] Name: ${invalidContacts[i].displayName}',
|
||||||
|
name: 'ContactPicker');
|
||||||
|
}
|
||||||
|
|
||||||
|
Get.back(); // إغلاق شاشة التحميل
|
||||||
|
|
||||||
|
if (validContacts.isEmpty) {
|
||||||
|
mySnackeBarError('No contacts with phone numbers found'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// متغيرات للبحث داخل القائمة المنسدلة
|
||||||
|
RxList<Contact> filteredContacts = validContacts.obs;
|
||||||
|
TextEditingController searchController = TextEditingController();
|
||||||
|
|
||||||
|
// دالة لتنظيف النصوص من أي رموز معطوبة
|
||||||
|
String sanitizeText(String input) {
|
||||||
|
if (input.isEmpty) return '';
|
||||||
|
return input
|
||||||
|
.replaceAll(
|
||||||
|
RegExp(r'[^\x00-\x7F\u0600-\u06FF\u08A0-\u08FF\p{L}\p{N}\s]'),
|
||||||
|
'')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// فتح دليل هاتف مخصص داخل التطبيق
|
||||||
|
Get.bottomSheet(
|
||||||
|
Container(
|
||||||
|
height: Get.height * 0.85,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(Get.context!).scaffoldBackgroundColor,
|
||||||
|
borderRadius:
|
||||||
|
const BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 10, bottom: 10),
|
||||||
|
width: 50,
|
||||||
|
height: 5,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[400],
|
||||||
|
borderRadius: BorderRadius.circular(10)),
|
||||||
|
),
|
||||||
|
Text("Select a Contact".tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: TextField(
|
||||||
|
controller: searchController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Search name or number...".tr,
|
||||||
|
prefixIcon: const Icon(Icons.search),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10)),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 0),
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
filteredContacts.value = validContacts.where((c) {
|
||||||
|
final nameMatch = c.displayName
|
||||||
|
.toLowerCase()
|
||||||
|
.contains(value.toLowerCase());
|
||||||
|
final phoneMatch =
|
||||||
|
c.phones.first.number.contains(value);
|
||||||
|
return nameMatch || phoneMatch;
|
||||||
|
}).toList();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Obx(() => ListView.builder(
|
||||||
|
itemCount: filteredContacts.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
Contact c = filteredContacts[index];
|
||||||
|
var firstPhone = c.phones.first;
|
||||||
|
|
||||||
|
String selectedPhone =
|
||||||
|
firstPhone.normalizedNumber.isNotEmpty
|
||||||
|
? firstPhone.normalizedNumber
|
||||||
|
: firstPhone.number;
|
||||||
|
|
||||||
|
String safeName = sanitizeText(c.displayName);
|
||||||
|
if (safeName.isEmpty) safeName = 'Unknown'.tr;
|
||||||
|
|
||||||
|
String safePhone = sanitizeText(selectedPhone);
|
||||||
|
String initial = safeName.isNotEmpty
|
||||||
|
? safeName[0].toUpperCase()
|
||||||
|
: '?';
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
leading: CircleAvatar(
|
||||||
|
backgroundColor:
|
||||||
|
Colors.blueAccent.withOpacity(0.1),
|
||||||
|
child: Text(initial,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.blueAccent)),
|
||||||
|
),
|
||||||
|
title: Text(safeName),
|
||||||
|
subtitle: Text(safePhone,
|
||||||
|
textDirection: TextDirection.ltr),
|
||||||
|
onTap: () {
|
||||||
|
selectPhone(selectedPhone);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isScrollControlled: true,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log('Permission DENIED', name: 'ContactPicker');
|
||||||
mySnackeBarError('Contact permission is required to pick contacts'.tr);
|
mySnackeBarError('Contact permission is required to pick contacts'.tr);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
mySnackeBarError('An error occurred while picking contacts: $e'.tr);
|
if (Get.isDialogOpen ?? false) Get.back();
|
||||||
|
log('CRITICAL ERROR: $e', name: 'ContactPicker');
|
||||||
|
mySnackeBarError('An error occurred while loading contacts: $e'.tr);
|
||||||
}
|
}
|
||||||
|
log('=== END: FETCHING CONTACTS ===', name: 'ContactPicker');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// **FIX**: Added the missing 'selectPhone' method.
|
/// **FIX**: Added the missing 'selectPhone' method.
|
||||||
@@ -197,10 +349,10 @@ Download the Intaleq app now and enjoy your ride!
|
|||||||
} else if (isAvailable) {
|
} else if (isAvailable) {
|
||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||||
options: const AuthenticationOptions(
|
// options: const AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
if ((driverInvitationData[index]['isGiftToken']).toString() ==
|
if ((driverInvitationData[index]['isGiftToken']).toString() ==
|
||||||
'0') {
|
'0') {
|
||||||
@@ -210,23 +362,23 @@ Download the Intaleq app now and enjoy your ride!
|
|||||||
payload: {'id': (driverInvitationData[index]['id'])});
|
payload: {'id': (driverInvitationData[index]['id'])});
|
||||||
await Get.find<CaptainWalletController>().addDriverPayment(
|
await Get.find<CaptainWalletController>().addDriverPayment(
|
||||||
'paymentMethod',
|
'paymentMethod',
|
||||||
('50000'),
|
('500'),
|
||||||
'',
|
'',
|
||||||
);
|
);
|
||||||
await Get.find<CaptainWalletController>()
|
await Get.find<CaptainWalletController>()
|
||||||
.addDriverWalletToInvitor(
|
.addDriverWalletToInvitor(
|
||||||
'paymentMethod',
|
'paymentMethod',
|
||||||
(driverInvitationData[index]['driverInviterId']),
|
(driverInvitationData[index]['driverInviterId']),
|
||||||
('50000'),
|
('500'),
|
||||||
);
|
);
|
||||||
NotificationCaptainController().addNotificationCaptain(
|
NotificationCaptainController().addNotificationCaptain(
|
||||||
driverInvitationData[index]['driverInviterId'].toString(),
|
driverInvitationData[index]['driverInviterId'].toString(),
|
||||||
"You have got a gift for invitation".tr,
|
"You have got a gift for invitation".tr,
|
||||||
'${"You have 50000".tr} ${'SYP'.tr}',
|
'${"You have 500".tr} ${'SYP'.tr}',
|
||||||
false);
|
false);
|
||||||
NotificationController().showNotification(
|
NotificationController().showNotification(
|
||||||
"You have got a gift for invitation".tr,
|
"You have got a gift for invitation".tr,
|
||||||
'${"You have 50000".tr} ${'SYP'.tr}',
|
'${"You have 500".tr} ${'SYP'.tr}',
|
||||||
'tone1',
|
'tone1',
|
||||||
'');
|
'');
|
||||||
} else {
|
} else {
|
||||||
@@ -266,20 +418,20 @@ Download the Intaleq app now and enjoy your ride!
|
|||||||
} else if (isAvailable) {
|
} else if (isAvailable) {
|
||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||||
options: const AuthenticationOptions(
|
// options: const AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
if (driverInvitationDataToPassengers[index]['isGiftToken']
|
if (driverInvitationDataToPassengers[index]['isGiftToken']
|
||||||
.toString() ==
|
.toString() ==
|
||||||
'0') {
|
'0') {
|
||||||
Get.back();
|
Get.back();
|
||||||
await Get.find<CaptainWalletController>()
|
await Get.find<CaptainWalletController>()
|
||||||
.addDriverWallet('paymentMethod', '20000', '20000');
|
.addDriverWallet('paymentMethod', '200', '200');
|
||||||
await Get.find<CaptainWalletController>()
|
await Get.find<CaptainWalletController>()
|
||||||
.addDriverWalletToInvitor('paymentMethod',
|
.addDriverWalletToInvitor('paymentMethod',
|
||||||
driverInvitationData[index]['driverInviterId'], '20000');
|
driverInvitationData[index]['driverInviterId'], '200');
|
||||||
await CRUD().post(
|
await CRUD().post(
|
||||||
link: AppLink.updatePassengerGift,
|
link: AppLink.updatePassengerGift,
|
||||||
payload: {'id': driverInvitationDataToPassengers[index]['id']},
|
payload: {'id': driverInvitationDataToPassengers[index]['id']},
|
||||||
@@ -288,7 +440,7 @@ Download the Intaleq app now and enjoy your ride!
|
|||||||
driverInvitationDataToPassengers[index]['passengerInviterId']
|
driverInvitationDataToPassengers[index]['passengerInviterId']
|
||||||
.toString(),
|
.toString(),
|
||||||
"You have got a gift for invitation".tr,
|
"You have got a gift for invitation".tr,
|
||||||
'${"You have 20000".tr} ${'SYP'.tr}',
|
'${"You have 200".tr} ${'SYP'.tr}',
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -13,19 +13,20 @@ import '../functions/add_error.dart';
|
|||||||
import '../functions/encrypt_decrypt.dart';
|
import '../functions/encrypt_decrypt.dart';
|
||||||
|
|
||||||
class GoogleSignInHelper {
|
class GoogleSignInHelper {
|
||||||
static final GoogleSignIn _googleSignIn = GoogleSignIn(
|
static final GoogleSignIn _googleSignIn = GoogleSignIn.instance;
|
||||||
scopes: [
|
|
||||||
'email',
|
// متغير ثابت لحفظ حالة المستخدم محلياً كبديل لخاصية currentUser المحذوفة
|
||||||
'profile',
|
static GoogleSignInAccount? _cachedUser;
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Method to handle Google Sign-In
|
|
||||||
static Future<GoogleSignInAccount?> signIn() async {
|
static Future<GoogleSignInAccount?> signIn() async {
|
||||||
try {
|
try {
|
||||||
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
|
final GoogleSignInAccount? googleUser =
|
||||||
|
await _googleSignIn.authenticate();
|
||||||
|
|
||||||
if (googleUser != null) {
|
if (googleUser != null) {
|
||||||
|
_cachedUser = googleUser; // حفظ الجلسة في الكاش المحلي
|
||||||
await _handleSignUp(googleUser);
|
await _handleSignUp(googleUser);
|
||||||
|
|
||||||
if (box.read(BoxName.countryCode) == 'Egypt') {
|
if (box.read(BoxName.countryCode) == 'Egypt') {
|
||||||
Get.to(() => SmsSignupEgypt());
|
Get.to(() => SmsSignupEgypt());
|
||||||
} else if (box.read(BoxName.countryCode) == 'Jordan') {
|
} else if (box.read(BoxName.countryCode) == 'Jordan') {
|
||||||
@@ -40,32 +41,23 @@ class GoogleSignInHelper {
|
|||||||
|
|
||||||
Future<GoogleSignInAccount?> signInFromLogin() async {
|
Future<GoogleSignInAccount?> signInFromLogin() async {
|
||||||
try {
|
try {
|
||||||
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
|
final GoogleSignInAccount? googleUser =
|
||||||
|
await _googleSignIn.authenticate();
|
||||||
|
|
||||||
if (googleUser != null) {
|
if (googleUser != null) {
|
||||||
// Handle sign-up and store user information
|
_cachedUser = googleUser; // حفظ الجلسة في الكاش المحلي
|
||||||
await _handleSignUp(googleUser);
|
await _handleSignUp(googleUser);
|
||||||
|
|
||||||
// Retrieve driverID and emailDriver with added validation
|
|
||||||
final driverID =
|
final driverID =
|
||||||
(box.read(BoxName.driverID)!.toString()) ?? 'Unknown ID';
|
(box.read(BoxName.driverID)?.toString()) ?? 'Unknown ID';
|
||||||
final emailDriver =
|
final emailDriver =
|
||||||
(box.read(BoxName.emailDriver)!.toString()) ?? 'Unknown Email';
|
(box.read(BoxName.emailDriver)?.toString()) ?? 'Unknown Email';
|
||||||
|
|
||||||
// Debug print statements
|
|
||||||
print('Driver ID: $driverID');
|
print('Driver ID: $driverID');
|
||||||
print('Driver Email: $emailDriver');
|
print('Driver Email: $emailDriver');
|
||||||
|
|
||||||
// Check if driverID is a valid numeric string
|
|
||||||
// if (driverID != 'Unknown ID' && int.tryParse(driverID) != null) {
|
|
||||||
await Get.find<LoginDriverController>()
|
await Get.find<LoginDriverController>()
|
||||||
.loginWithGoogleCredential(driverID, emailDriver);
|
.loginWithGoogleCredential(driverID, emailDriver);
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// print('Invalid driverID format: $driverID');
|
|
||||||
// Get.snackbar('Login Error', 'Invalid driver ID format.',
|
|
||||||
// backgroundColor: AppColor.redColor);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return googleUser;
|
return googleUser;
|
||||||
@@ -78,204 +70,29 @@ class GoogleSignInHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> _handleSignUp(GoogleSignInAccount user) async {
|
static Future<void> _handleSignUp(GoogleSignInAccount user) async {
|
||||||
// Store driver information
|
box.write(BoxName.driverID, (user.id) ?? 'Unknown ID');
|
||||||
box.write(BoxName.driverID,
|
|
||||||
(user.id) ?? 'Unknown ID'); // Ensure there's a fallback value
|
|
||||||
box.write(BoxName.emailDriver, (user.email) ?? 'Unknown Email');
|
box.write(BoxName.emailDriver, (user.email) ?? 'Unknown Email');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to handle Google Sign-Out
|
|
||||||
static Future<void> signOut() async {
|
static Future<void> signOut() async {
|
||||||
try {
|
try {
|
||||||
await _googleSignIn.signOut();
|
await _googleSignIn.signOut();
|
||||||
|
} catch (error) {
|
||||||
|
// التعامل مع الخطأ بصمت إذا كانت جلسة جوجل فارغة مسبقاً
|
||||||
|
} finally {
|
||||||
|
_cachedUser = null; // مسح الكاش المحلي بشكل إلزامي
|
||||||
await _handleSignOut();
|
await _handleSignOut();
|
||||||
} catch (error) {}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> _handleSignOut() async {
|
static Future<void> _handleSignOut() async {
|
||||||
// Clear stored driver information
|
|
||||||
box.erase();
|
box.erase();
|
||||||
storage.deleteAll();
|
storage.deleteAll();
|
||||||
Get.offAll(OnBoardingPage());
|
Get.offAll(OnBoardingPage());
|
||||||
// Perform any additional sign-out tasks or API calls here
|
|
||||||
// For example, you can notify your server about the user sign-out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to get the current signed-in user
|
// استخدام الكاش المحلي بدلاً من استدعاء المكتبة
|
||||||
static GoogleSignInAccount? getCurrentUser() {
|
static GoogleSignInAccount? getCurrentUser() {
|
||||||
return _googleSignIn.currentUser;
|
return _cachedUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// import 'dart:async';
|
|
||||||
// import 'dart:async';
|
|
||||||
// import 'dart:convert';
|
|
||||||
// import 'package:flutter/material.dart';
|
|
||||||
// import 'package:get/get.dart';
|
|
||||||
// import 'package:http/http.dart' as http;
|
|
||||||
// import 'package:sefer_driver/constant/box_name.dart';
|
|
||||||
// import 'package:sefer_driver/controller/auth/captin/login_captin_controller.dart';
|
|
||||||
// import 'package:sefer_driver/main.dart';
|
|
||||||
// import 'package:sefer_driver/views/auth/captin/ai_page.dart';
|
|
||||||
// import 'package:sefer_driver/views/auth/captin/cards/sms_signup.dart';
|
|
||||||
// import 'package:sefer_driver/views/home/on_boarding_page.dart';
|
|
||||||
// import 'package:sefer_driver/views/widgets/error_snakbar.dart';
|
|
||||||
// import 'package:url_launcher/url_launcher.dart';
|
|
||||||
|
|
||||||
// import '../functions/add_error.dart';
|
|
||||||
|
|
||||||
// /// Helper class to manage Google Sign-In via an external browser and polling.
|
|
||||||
// class GoogleSignInHelper {
|
|
||||||
// // URLs for your server endpoints
|
|
||||||
// static const String _startLoginUrl =
|
|
||||||
// 'https://api.tripz-egypt.com/tripz/auth/google_auth/login.php';
|
|
||||||
// static const String _checkStatusUrl =
|
|
||||||
// 'https://api.tripz-egypt.com/tripz/auth/google_auth/check_status.php';
|
|
||||||
|
|
||||||
// static Future<void> _initiateSignIn(
|
|
||||||
// Function(Map<String, dynamic> userData) onSignInSuccess) async {
|
|
||||||
// try {
|
|
||||||
// // Show a loading dialog to the user
|
|
||||||
// Get.dialog(
|
|
||||||
// const Center(
|
|
||||||
// child: Material(
|
|
||||||
// color: Colors.transparent,
|
|
||||||
// child: Column(
|
|
||||||
// mainAxisSize: MainAxisSize.min,
|
|
||||||
// children: [
|
|
||||||
// CircularProgressIndicator(),
|
|
||||||
// SizedBox(height: 16),
|
|
||||||
// Text(
|
|
||||||
// "Waiting for browser sign-in...",
|
|
||||||
// style: TextStyle(color: Colors.white, fontSize: 16),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// barrierDismissible: false,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // 1. Get the auth URL and login token from the server
|
|
||||||
// final startResponse = await http.get(Uri.parse(_startLoginUrl));
|
|
||||||
// if (startResponse.statusCode != 200) {
|
|
||||||
// throw Exception('Failed to start login process.');
|
|
||||||
// }
|
|
||||||
|
|
||||||
// final startData = jsonDecode(startResponse.body);
|
|
||||||
// final String authUrl = startData['authUrl'];
|
|
||||||
// final String loginToken = startData['loginToken'];
|
|
||||||
|
|
||||||
// // 2. Launch the URL in an external browser
|
|
||||||
// if (!await launchUrl(Uri.parse(authUrl),
|
|
||||||
// mode: LaunchMode.externalApplication)) {
|
|
||||||
// throw Exception('Could not launch browser.');
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 3. Start polling the server for status
|
|
||||||
// await _startPolling(loginToken, onSignInSuccess);
|
|
||||||
// } catch (e) {
|
|
||||||
// addError(e.toString(), '_initiateSignIn');
|
|
||||||
// mySnackeBarError('Sign-in failed: ${e.toString()}');
|
|
||||||
// // Close the loading dialog on error
|
|
||||||
// if (Get.isDialogOpen ?? false) {
|
|
||||||
// Get.back();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static Future<void> _startPolling(String loginToken,
|
|
||||||
// Function(Map<String, dynamic> userData) onSignInSuccess) async {
|
|
||||||
// Timer? poller;
|
|
||||||
// const int maxAttempts = 30; // Poll for 60 seconds (30 attempts * 2s)
|
|
||||||
// int attempts = 0;
|
|
||||||
|
|
||||||
// poller = Timer.periodic(const Duration(seconds: 2), (timer) async {
|
|
||||||
// if (attempts >= maxAttempts) {
|
|
||||||
// timer.cancel();
|
|
||||||
// if (Get.isDialogOpen ?? false) Get.back();
|
|
||||||
// mySnackeBarError('Sign-in timed out. Please try again.');
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// attempts++;
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// final statusResponse = await http.post(
|
|
||||||
// Uri.parse(_checkStatusUrl),
|
|
||||||
// headers: {'Content-Type': 'application/json'},
|
|
||||||
// body: jsonEncode({'loginToken': loginToken}),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (statusResponse.statusCode == 200) {
|
|
||||||
// final statusData = jsonDecode(statusResponse.body);
|
|
||||||
// if (statusData['status'] == 'success') {
|
|
||||||
// timer.cancel();
|
|
||||||
// if (Get.isDialogOpen ?? false) Get.back();
|
|
||||||
// // Success!
|
|
||||||
// onSignInSuccess(statusData['userData']);
|
|
||||||
// }
|
|
||||||
// // If status is 'pending', do nothing and wait for the next poll.
|
|
||||||
// }
|
|
||||||
// } catch (e) {
|
|
||||||
// // Handle polling errors silently or log them
|
|
||||||
// debugPrint("Polling error: $e");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Triggers the sign-in process for a new user.
|
|
||||||
// static Future<void> signIn() async {
|
|
||||||
// await _initiateSignIn((userData) async {
|
|
||||||
// debugPrint('Sign-in success data: $userData');
|
|
||||||
// await _handleSignUp(userData);
|
|
||||||
// if (box.read(BoxName.countryCode) == 'Egypt') {
|
|
||||||
// Get.offAll(() => SmsSignupEgypt());
|
|
||||||
// } else if (box.read(BoxName.countryCode) == 'Jordan') {
|
|
||||||
// Get.offAll(() => AiPage());
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Triggers the sign-in process for an existing user.
|
|
||||||
// static Future<void> signInFromLogin() async {
|
|
||||||
// await _initiateSignIn((userData) async {
|
|
||||||
// debugPrint('Sign-in from login success data: $userData');
|
|
||||||
// await _handleSignUp(userData);
|
|
||||||
|
|
||||||
// final driverID = userData['id']?.toString() ?? 'Unknown ID';
|
|
||||||
// final emailDriver = userData['email']?.toString() ?? 'Unknown Email';
|
|
||||||
|
|
||||||
// debugPrint('Driver ID from server: $driverID');
|
|
||||||
// debugPrint('Driver Email from server: $emailDriver');
|
|
||||||
|
|
||||||
// await Get.find<LoginDriverController>()
|
|
||||||
// .loginWithGoogleCredential(driverID, emailDriver);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Stores user information received from the server.
|
|
||||||
// static Future<void> _handleSignUp(Map<String, dynamic> userData) async {
|
|
||||||
// box.write(BoxName.driverID, userData['id'] ?? 'Unknown ID');
|
|
||||||
// box.write(BoxName.emailDriver, userData['email'] ?? 'Unknown Email');
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Clears local data.
|
|
||||||
// static Future<void> signOut() async {
|
|
||||||
// box.remove(BoxName.driverID);
|
|
||||||
// box.remove(BoxName.emailDriver);
|
|
||||||
// box.remove(BoxName.lang);
|
|
||||||
// box.remove(BoxName.nameDriver);
|
|
||||||
// box.remove(BoxName.passengerID);
|
|
||||||
// box.remove(BoxName.phoneDriver);
|
|
||||||
// box.remove(BoxName.tokenFCM);
|
|
||||||
// box.remove(BoxName.tokens);
|
|
||||||
// box.remove(BoxName.carPlate);
|
|
||||||
// box.remove(BoxName.lastNameDriver);
|
|
||||||
// box.remove(BoxName.agreeTerms);
|
|
||||||
// box.remove(BoxName.tokenDriver);
|
|
||||||
// box.remove(BoxName.countryCode);
|
|
||||||
// box.remove(BoxName.accountIdStripeConnect);
|
|
||||||
// box.remove(BoxName.phoneVerified);
|
|
||||||
// Get.offAll(() => OnBoardingPage());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ class NotificationController extends GetxController {
|
|||||||
print('✅ Notifications initialized with Action Buttons Support');
|
print('✅ Notifications initialized with Action Buttons Support');
|
||||||
|
|
||||||
await _flutterLocalNotificationsPlugin.initialize(
|
await _flutterLocalNotificationsPlugin.initialize(
|
||||||
initializationSettings,
|
|
||||||
onDidReceiveNotificationResponse: onDidReceiveNotificationResponse,
|
onDidReceiveNotificationResponse: onDidReceiveNotificationResponse,
|
||||||
onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
|
onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
|
||||||
|
settings: initializationSettings,
|
||||||
);
|
);
|
||||||
|
|
||||||
// إنشاء قناة الأندرويد ذات الأهمية القصوى
|
// إنشاء قناة الأندرويد ذات الأهمية القصوى
|
||||||
@@ -183,10 +183,10 @@ class NotificationController extends GetxController {
|
|||||||
|
|
||||||
// عرض الإشعار
|
// عرض الإشعار
|
||||||
await _flutterLocalNotificationsPlugin.show(
|
await _flutterLocalNotificationsPlugin.show(
|
||||||
1001, // ID ثابت لاستبدال الإشعار القديم
|
id: 1001, // ID ثابت لاستبدال الإشعار القديم
|
||||||
title,
|
title: title,
|
||||||
"$price - مسافة $formattedBigText", // نص مختصر يظهر في البار العلوي
|
body: "$price - مسافة $formattedBigText", // نص مختصر يظهر في البار العلوي
|
||||||
details,
|
notificationDetails: details,
|
||||||
payload: jsonEncode({
|
payload: jsonEncode({
|
||||||
'type': 'Order',
|
'type': 'Order',
|
||||||
'data': myListString,
|
'data': myListString,
|
||||||
@@ -215,7 +215,7 @@ class NotificationController extends GetxController {
|
|||||||
|
|
||||||
// أ) زر القبول
|
// أ) زر القبول
|
||||||
if (response.actionId == 'ACCEPT_ORDER') {
|
if (response.actionId == 'ACCEPT_ORDER') {
|
||||||
await _flutterLocalNotificationsPlugin.cancel(1001); // حذف الإشعار
|
await _flutterLocalNotificationsPlugin.cancel(id: 1001); // حذف الإشعار
|
||||||
_processAcceptOrder(listData);
|
_processAcceptOrder(listData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ class NotificationController extends GetxController {
|
|||||||
|
|
||||||
// ج) زر الرفض
|
// ج) زر الرفض
|
||||||
else if (response.actionId == 'REJECT_ORDER') {
|
else if (response.actionId == 'REJECT_ORDER') {
|
||||||
await _flutterLocalNotificationsPlugin.cancel(1001); // حذف الإشعار
|
await _flutterLocalNotificationsPlugin.cancel(id: 1001); // حذف الإشعار
|
||||||
_processRejectOrder(listData);
|
_processRejectOrder(listData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,7 +428,11 @@ class NotificationController extends GetxController {
|
|||||||
NotificationDetails details =
|
NotificationDetails details =
|
||||||
NotificationDetails(android: android, iOS: ios);
|
NotificationDetails(android: android, iOS: ios);
|
||||||
|
|
||||||
await _flutterLocalNotificationsPlugin.show(0, title, message, details,
|
await _flutterLocalNotificationsPlugin.show(
|
||||||
|
id: 0,
|
||||||
|
title: title,
|
||||||
|
body: message,
|
||||||
|
notificationDetails: details,
|
||||||
payload: jsonEncode({'title': title, 'data': payLoad}));
|
payload: jsonEncode({'title': title, 'data': payLoad}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +494,7 @@ class NotificationController extends GetxController {
|
|||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
Future<void> cancelOrderNotification() async {
|
Future<void> cancelOrderNotification() async {
|
||||||
// 1001 هو نفس الآيدي الذي استخدمناه عند عرض الإشعار
|
// 1001 هو نفس الآيدي الذي استخدمناه عند عرض الإشعار
|
||||||
await _flutterLocalNotificationsPlugin.cancel(1001);
|
await _flutterLocalNotificationsPlugin.cancel(id: 1001);
|
||||||
print("🗑️ Order Notification Cancelled (Taken by another driver)");
|
print("🗑️ Order Notification Cancelled (Taken by another driver)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,14 +526,12 @@ class NotificationController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _flutterLocalNotificationsPlugin.zonedSchedule(
|
await _flutterLocalNotificationsPlugin.zonedSchedule(
|
||||||
notificationId,
|
id: notificationId,
|
||||||
title,
|
title: title,
|
||||||
message,
|
body: message,
|
||||||
scheduledDate,
|
scheduledDate: scheduledDate,
|
||||||
details,
|
notificationDetails: details,
|
||||||
androidScheduleMode: AndroidScheduleMode.exact,
|
androidScheduleMode: AndroidScheduleMode.exact, // أو exactAllowWhileIdle
|
||||||
uiLocalNotificationDateInterpretation:
|
|
||||||
UILocalNotificationDateInterpretation.absoluteTime,
|
|
||||||
matchDateTimeComponents: null,
|
matchDateTimeComponents: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ Future<bool> onStart(ServiceInstance service) async {
|
|||||||
print("✅ Background Service: Socket Connected!");
|
print("✅ Background Service: Socket Connected!");
|
||||||
if (service is AndroidServiceInstance) {
|
if (service is AndroidServiceInstance) {
|
||||||
flutterLocalNotificationsPlugin.show(
|
flutterLocalNotificationsPlugin.show(
|
||||||
notificationId,
|
id: notificationId,
|
||||||
'أنت متصل الآن',
|
title: 'أنت متصل الآن',
|
||||||
'بانتظار الطلبات...',
|
body: 'بانتظار الطلبات...',
|
||||||
const NotificationDetails(
|
notificationDetails: const NotificationDetails(
|
||||||
android: AndroidNotificationDetails(
|
android: AndroidNotificationDetails(
|
||||||
notificationChannelId,
|
notificationChannelId,
|
||||||
'خدمة السائق',
|
'خدمة السائق',
|
||||||
@@ -107,10 +107,10 @@ Future<bool> onStart(ServiceInstance service) async {
|
|||||||
if (service is AndroidServiceInstance) {
|
if (service is AndroidServiceInstance) {
|
||||||
if (await service.isForegroundService()) {
|
if (await service.isForegroundService()) {
|
||||||
flutterLocalNotificationsPlugin.show(
|
flutterLocalNotificationsPlugin.show(
|
||||||
notificationId,
|
id: notificationId,
|
||||||
'خدمة السائق نشطة',
|
title: 'خدمة السائق نشطة',
|
||||||
'بانتظار الطلبات...',
|
body: 'بانتظار الطلبات...',
|
||||||
const NotificationDetails(
|
notificationDetails: const NotificationDetails(
|
||||||
android: AndroidNotificationDetails(
|
android: AndroidNotificationDetails(
|
||||||
notificationChannelId,
|
notificationChannelId,
|
||||||
'خدمة السائق',
|
'خدمة السائق',
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:jwt_decoder/jwt_decoder.dart';
|
import 'package:jwt_decoder/jwt_decoder.dart';
|
||||||
import 'package:path/path.dart';
|
|
||||||
import 'package:sefer_driver/controller/functions/encrypt_decrypt.dart';
|
import 'package:sefer_driver/controller/functions/encrypt_decrypt.dart';
|
||||||
import 'package:sefer_driver/controller/functions/network/net_guard.dart';
|
import 'package:sefer_driver/controller/functions/network/net_guard.dart';
|
||||||
import 'package:secure_string_operations/secure_string_operations.dart';
|
|
||||||
import 'package:sefer_driver/constant/box_name.dart';
|
import 'package:sefer_driver/constant/box_name.dart';
|
||||||
import 'package:sefer_driver/constant/links.dart';
|
import 'package:sefer_driver/constant/links.dart';
|
||||||
import 'package:sefer_driver/controller/auth/captin/login_captin_controller.dart';
|
import 'package:sefer_driver/controller/auth/captin/login_captin_controller.dart';
|
||||||
@@ -16,8 +14,6 @@ import 'package:sefer_driver/env/env.dart';
|
|||||||
import 'package:sefer_driver/print.dart';
|
import 'package:sefer_driver/print.dart';
|
||||||
|
|
||||||
import '../../constant/api_key.dart';
|
import '../../constant/api_key.dart';
|
||||||
import '../../constant/char_map.dart';
|
|
||||||
import '../../constant/info.dart';
|
|
||||||
import '../../views/widgets/error_snakbar.dart';
|
import '../../views/widgets/error_snakbar.dart';
|
||||||
import 'gemeni.dart';
|
import 'gemeni.dart';
|
||||||
import 'upload_image.dart';
|
import 'upload_image.dart';
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class DeviceController {
|
|||||||
final deviceInfo = DeviceInfo(
|
final deviceInfo = DeviceInfo(
|
||||||
manufacturer: androidInfo.manufacturer,
|
manufacturer: androidInfo.manufacturer,
|
||||||
model: androidInfo.model,
|
model: androidInfo.model,
|
||||||
deviceId: androidInfo.serialNumber,
|
deviceId: androidInfo.id,
|
||||||
osVersion: androidInfo.version.release,
|
osVersion: androidInfo.version.release,
|
||||||
platform: 'Android',
|
platform: 'Android',
|
||||||
deviceName: androidInfo.device,
|
deviceName: androidInfo.device,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import 'package:trip_overlay_plugin/trip_overlay_plugin.dart';
|
|||||||
import '../../constant/box_name.dart';
|
import '../../constant/box_name.dart';
|
||||||
import '../../constant/links.dart';
|
import '../../constant/links.dart';
|
||||||
import '../../main.dart';
|
import '../../main.dart';
|
||||||
|
import '../../print.dart';
|
||||||
import '../home/captin/home_captain_controller.dart';
|
import '../home/captin/home_captain_controller.dart';
|
||||||
import '../home/captin/map_driver_controller.dart';
|
import '../home/captin/map_driver_controller.dart';
|
||||||
import '../home/payment/captain_wallet_controller.dart';
|
import '../home/payment/captain_wallet_controller.dart';
|
||||||
@@ -74,7 +75,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
@override
|
@override
|
||||||
Future<void> onInit() async {
|
Future<void> onInit() async {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
print('🚀 LocationController Starting...');
|
Log.print('🚀 LocationController Starting...');
|
||||||
|
|
||||||
// 1. Register Lifecycle Observer
|
// 1. Register Lifecycle Observer
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
@@ -83,7 +84,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
// مراقب الحالة (Status Watcher)
|
// مراقب الحالة (Status Watcher)
|
||||||
box.listenKey(BoxName.statusDriverLocation, (value) {
|
box.listenKey(BoxName.statusDriverLocation, (value) {
|
||||||
if (value == 'blocked') {
|
if (value == 'blocked') {
|
||||||
print("⛔ Driver is Blocked: Force Stopping Location Updates.");
|
Log.print("⛔ Driver is Blocked: Force Stopping Location Updates.");
|
||||||
stopLocationUpdates();
|
stopLocationUpdates();
|
||||||
if (socket != null && socket!.connected) {
|
if (socket != null && socket!.connected) {
|
||||||
socket!.emit('update_location', {
|
socket!.emit('update_location', {
|
||||||
@@ -113,7 +114,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
await startLocationUpdates();
|
await startLocationUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
print('✅ LocationController Initialized.');
|
Log.print('✅ LocationController Initialized.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -133,7 +134,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
if (state == AppLifecycleState.resumed) {
|
if (state == AppLifecycleState.resumed) {
|
||||||
print("📱 Lifecycle: App is in FOREGROUND");
|
Log.print("📱 Lifecycle: App is in FOREGROUND");
|
||||||
box.write(BoxName.isAppInForeground, true);
|
box.write(BoxName.isAppInForeground, true);
|
||||||
|
|
||||||
// إيقاف خدمة الخلفية لأننا في الواجهة الآن
|
// إيقاف خدمة الخلفية لأننا في الواجهة الآن
|
||||||
@@ -141,7 +142,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
// التأكد من أن السوكيت متصل، وإذا لا، نعيد الاتصال فوراً
|
// التأكد من أن السوكيت متصل، وإذا لا، نعيد الاتصال فوراً
|
||||||
if (socket == null || !socket!.connected) {
|
if (socket == null || !socket!.connected) {
|
||||||
print("🔄 Socket disconnected in background. Reconnecting now...");
|
Log.print("🔄 Socket disconnected in background. Reconnecting now...");
|
||||||
initSocket();
|
initSocket();
|
||||||
} else {
|
} else {
|
||||||
// إذا كان متصلاً، ننعش المستمعين فقط للتأكد
|
// إذا كان متصلاً، ننعش المستمعين فقط للتأكد
|
||||||
@@ -149,7 +150,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
} else if (state == AppLifecycleState.paused ||
|
} else if (state == AppLifecycleState.paused ||
|
||||||
state == AppLifecycleState.detached) {
|
state == AppLifecycleState.detached) {
|
||||||
print("📱 Lifecycle: App is in BACKGROUND");
|
Log.print("📱 Lifecycle: App is in BACKGROUND");
|
||||||
box.write(BoxName.isAppInForeground, false);
|
box.write(BoxName.isAppInForeground, false);
|
||||||
|
|
||||||
// تشغيل خدمة الخلفية لضمان بقاء التطبيق حياً
|
// تشغيل خدمة الخلفية لضمان بقاء التطبيق حياً
|
||||||
@@ -186,14 +187,15 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 1. إذا كان السوكيت موجوداً، فقط تأكد من اتصاله
|
// 1. إذا كان السوكيت موجوداً، فقط تأكد من اتصاله
|
||||||
if (socket != null) {
|
if (socket != null) {
|
||||||
if (!socket!.connected) {
|
if (!socket!.connected) {
|
||||||
print("🟡 Socket exists but disconnected. Reconnecting...");
|
Log.print("🟡 Socket exists but disconnected. Reconnecting...");
|
||||||
socket!.connect();
|
socket!.connect();
|
||||||
}
|
}
|
||||||
_setupSocketListeners(); // تحديث المستمعين
|
_setupSocketListeners(); // تحديث المستمعين
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
print("🟡 [LocationController] Creating NEW Socket for Driver: $driverId");
|
Log.print(
|
||||||
|
"🟡 [LocationController] Creating NEW Socket for Driver: $driverId");
|
||||||
|
|
||||||
// 2. إنشاء الاتصال
|
// 2. إنشاء الاتصال
|
||||||
socket = IO.io(
|
socket = IO.io(
|
||||||
@@ -222,20 +224,27 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
socket!.off('ride_cancelled');
|
socket!.off('ride_cancelled');
|
||||||
|
|
||||||
socket!.onConnect((_) {
|
socket!.onConnect((_) {
|
||||||
print('✅ Socket Connected! ID: ${socket?.id}');
|
Log.print('✅ Socket Connected! ID: ${socket?.id}');
|
||||||
isSocketConnected = true;
|
isSocketConnected = true;
|
||||||
_startHeartbeat();
|
_startHeartbeat();
|
||||||
});
|
});
|
||||||
|
|
||||||
socket!.onDisconnect((_) {
|
socket!.onDisconnect((_) {
|
||||||
print('❌ Socket Disconnected');
|
Log.print('❌ Socket Disconnected');
|
||||||
isSocketConnected = false;
|
isSocketConnected = false;
|
||||||
_stopHeartbeat();
|
_stopHeartbeat();
|
||||||
});
|
});
|
||||||
|
socket!.onConnectError((err) {
|
||||||
|
Log.print('❌ Socket Connect Error: $err');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket!.onError((err) {
|
||||||
|
Log.print('❌ Socket General Error: $err');
|
||||||
|
});
|
||||||
|
|
||||||
// 🔥 الاستماع للطلبات الجديدة
|
// 🔥 الاستماع للطلبات الجديدة
|
||||||
socket!.on('new_ride_request', (data) {
|
socket!.on('new_ride_request', (data) {
|
||||||
print("🔔 Socket: New Ride Request Arrived!");
|
Log.print("🔔 Socket: New Ride Request Arrived!");
|
||||||
|
|
||||||
// نستخدم Future.microtask لضمان عدم حظر الـ UI Thread
|
// نستخدم Future.microtask لضمان عدم حظر الـ UI Thread
|
||||||
Future.microtask(() {
|
Future.microtask(() {
|
||||||
@@ -259,7 +268,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
handleIncomingOrder(convertedMap, "Socket");
|
handleIncomingOrder(convertedMap, "Socket");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("❌ Error processing socket data: $e");
|
Log.print("❌ Error processing socket data: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -267,7 +276,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
// 🔥 الاستماع للإلغاء
|
// 🔥 الاستماع للإلغاء
|
||||||
socket!.on('cancel_ride', (data) {
|
socket!.on('cancel_ride', (data) {
|
||||||
print("🚫 Socket: Ride Cancelled Event Received");
|
Log.print("🚫 Socket: Ride Cancelled Event Received");
|
||||||
String reason = data['reason'] ?? 'No reason provided';
|
String reason = data['reason'] ?? 'No reason provided';
|
||||||
if (Get.isRegistered<MapDriverController>()) {
|
if (Get.isRegistered<MapDriverController>()) {
|
||||||
Get.find<MapDriverController>()
|
Get.find<MapDriverController>()
|
||||||
@@ -280,13 +289,13 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
Future<void> handleIncomingOrder(
|
Future<void> handleIncomingOrder(
|
||||||
Map<String, dynamic> rideData, String source) async {
|
Map<String, dynamic> rideData, String source) async {
|
||||||
print("📦 Socket Order Received from ($source)");
|
Log.print("📦 Socket Order Received from ($source)");
|
||||||
|
|
||||||
// 🔴 1. التحقق من حالة التطبيق قبل أي شيء 🔴
|
// 🔴 1. التحقق من حالة التطبيق قبل أي شيء 🔴
|
||||||
bool isAppInForeground = box.read(BoxName.isAppInForeground) ?? false;
|
bool isAppInForeground = box.read(BoxName.isAppInForeground) ?? false;
|
||||||
|
|
||||||
if (!isAppInForeground) {
|
if (!isAppInForeground) {
|
||||||
print(
|
Log.print(
|
||||||
"🛑 التطبيق في الخلفية. السوكيت سيتجاهل التوجيه ويترك المهمة للـ Overlay.");
|
"🛑 التطبيق في الخلفية. السوكيت سيتجاهل التوجيه ويترك المهمة للـ Overlay.");
|
||||||
return; // 👈 هذا السطر يمنع السوكيت من إكمال العمل وفتح الصفحة
|
return; // 👈 هذا السطر يمنع السوكيت من إكمال العمل وفتح الصفحة
|
||||||
}
|
}
|
||||||
@@ -294,7 +303,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
try {
|
try {
|
||||||
// 2. التحقق من صحة البيانات
|
// 2. التحقق من صحة البيانات
|
||||||
if (rideData.isEmpty || !rideData.containsKey('16')) {
|
if (rideData.isEmpty || !rideData.containsKey('16')) {
|
||||||
print("❌ Socket Error: Invalid Ride Data.");
|
Log.print("❌ Socket Error: Invalid Ride Data.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,25 +320,26 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 4. إغلاق النافذة (إن وجدت بالخطأ) والتنقل
|
// 4. إغلاق النافذة (إن وجدت بالخطأ) والتنقل
|
||||||
try {
|
try {
|
||||||
if (await TripOverlayPlugin.isOverlayActive()) {
|
if (await TripOverlayPlugin.isOverlayActive()) {
|
||||||
print("📲 Closing Overlay because App took control via Socket");
|
Log.print("📲 Closing Overlay because App took control via Socket");
|
||||||
await TripOverlayPlugin.hideOverlay();
|
await TripOverlayPlugin.hideOverlay();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Overlay check error: $e");
|
Log.print("Overlay check error: $e");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Get.currentRoute != '/OrderRequestPage') {
|
if (Get.currentRoute != '/OrderRequestPage') {
|
||||||
print("🚀 Socket: Navigating to OrderRequestPage...");
|
Log.print("🚀 Socket: Navigating to OrderRequestPage...");
|
||||||
Get.toNamed('/OrderRequestPage', arguments: {
|
Get.toNamed('/OrderRequestPage', arguments: {
|
||||||
'myListString': jsonEncode(driverList),
|
'myListString': jsonEncode(driverList),
|
||||||
'DriverList': driverList,
|
'DriverList': driverList,
|
||||||
'body': 'New Trip Request via Socket ⚡'
|
'body': 'New Trip Request via Socket ⚡'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
print("⚠️ User is already on OrderRequestPage. Skipping navigation.");
|
Log.print(
|
||||||
|
"⚠️ User is already on OrderRequestPage. Skipping navigation.");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("❌ Socket Navigation Error: $e");
|
Log.print("❌ Socket Navigation Error: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,8 +384,8 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug print to verify
|
// DebugLog.print to verify
|
||||||
// print('🚀 Emitting Location: $payload');
|
//Log.print('🚀 Emitting Location: $payload');
|
||||||
|
|
||||||
if (socket != null && socket!.connected) {
|
if (socket != null && socket!.connected) {
|
||||||
socket!.emit('update_location', payload);
|
socket!.emit('update_location', payload);
|
||||||
@@ -437,11 +447,11 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
update();
|
update();
|
||||||
emitLocationToSocket(pos, heading, speed);
|
emitLocationToSocket(pos, heading, speed);
|
||||||
await _saveBehaviorIfMoved(pos, now, currentSpeed: speed);
|
await _saveBehaviorIfMoved(pos, now, currentSpeed: speed);
|
||||||
}, onError: (e) => print('❌ Location Stream Error: $e'));
|
}, onError: (e) => Log.print('❌ Location Stream Error: $e'));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> stopLocationUpdates() async {
|
Future<void> stopLocationUpdates() async {
|
||||||
print("🛑 Stopping Location Updates...");
|
Log.print("🛑 Stopping Location Updates...");
|
||||||
|
|
||||||
_locSub?.cancel();
|
_locSub?.cancel();
|
||||||
_locSub = null;
|
_locSub = null;
|
||||||
@@ -525,7 +535,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
payload: {'driver_id': driverId, 'batch_data': jsonEncode(batch)},
|
payload: {'driver_id': driverId, 'batch_data': jsonEncode(batch)},
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('❌ Failed to upload batch: $e');
|
Log.print('❌ Failed to upload batch: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,7 +569,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
}, TableName.behavior);
|
}, TableName.behavior);
|
||||||
_lastSqlLoc = pos;
|
_lastSqlLoc = pos;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('SQLite Error: $e');
|
Log.print('SQLite Error: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,7 +604,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
interval: 1000,
|
interval: 1000,
|
||||||
distanceFilter: 10);
|
distanceFilter: 10);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Warning: $e");
|
Log.print("Warning: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -633,7 +643,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
return await location.getLocation();
|
return await location.getLocation();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('❌ FAILED to get single location: $e');
|
Log.print('❌ FAILED to get single location: $e');
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class NetGuard {
|
|||||||
// اختباري خفيف عبر TCP (80/443) — 400ms timeout
|
// اختباري خفيف عبر TCP (80/443) — 400ms timeout
|
||||||
final port = mustReach.scheme == 'http' ? 80 : 443;
|
final port = mustReach.scheme == 'http' ? 80 : 443;
|
||||||
final socket = await Socket.connect(host, port,
|
final socket = await Socket.connect(host, port,
|
||||||
timeout: const Duration(milliseconds: 400));
|
timeout: const Duration(seconds: 1));
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -433,14 +433,58 @@ class HomeCaptainController extends GetxController {
|
|||||||
return totalDuration;
|
return totalDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void startPeriodicExecution() {
|
Timer? _localDurationTimer;
|
||||||
Timer.periodic(const Duration(seconds: 30), (timer) async {
|
RxString totalDurationDisplay = "00:00:00".obs; // لعرض الوقت في الواجهة
|
||||||
|
Duration _currentDuration = Duration.zero; // لتخزين الوقت ككائن Duration
|
||||||
|
|
||||||
|
void startPeriodicExecution() async {
|
||||||
await getCaptainDurationOnToday();
|
await getCaptainDurationOnToday();
|
||||||
|
String? initialDurationStr = totalDurationToday;
|
||||||
|
|
||||||
|
if (initialDurationStr != null) {
|
||||||
|
// تحويل النص (01:20:30) إلى كائن Duration
|
||||||
|
List<String> parts = initialDurationStr.split(':');
|
||||||
|
_currentDuration = Duration(
|
||||||
|
hours: int.parse(parts[0]),
|
||||||
|
minutes: int.parse(parts[1]),
|
||||||
|
seconds: int.parse(parts[2]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// بدء العداد المحلي
|
||||||
|
_startLocalClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer.periodic(const Duration(seconds: 30), (timer) async {
|
||||||
|
// await getCaptainDurationOnToday();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startLocalClock() {
|
||||||
|
_localDurationTimer?.cancel();
|
||||||
|
_localDurationTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
|
// زيادة ثانية واحدة محلياً
|
||||||
|
_currentDuration += const Duration(seconds: 1);
|
||||||
|
|
||||||
|
// تحديث النص المعروض في الواجهة (Formatting)
|
||||||
|
totalDurationDisplay.value = _formatDuration(_currentDuration);
|
||||||
|
|
||||||
|
// اختيارياً: كل 5 دقائق فقط، قم بتحديث القيمة من السيرفر للتأكد من المزامنة
|
||||||
|
if (timer.tick % 300 == 0) {
|
||||||
|
getCaptainDurationOnToday();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _formatDuration(Duration duration) {
|
||||||
|
String twoDigits(int n) => n.toString().padLeft(2, "0");
|
||||||
|
String hours = twoDigits(duration.inHours);
|
||||||
|
String minutes = twoDigits(duration.inMinutes.remainder(60));
|
||||||
|
String seconds = twoDigits(duration.inSeconds.remainder(60));
|
||||||
|
return "$hours:$minutes:$seconds";
|
||||||
|
}
|
||||||
|
|
||||||
void stopTimer() {
|
void stopTimer() {
|
||||||
timer?.cancel();
|
_localDurationTimer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
getlocation() async {
|
getlocation() async {
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ class PaymobPayout extends GetxController {
|
|||||||
// Authenticate the user
|
// Authenticate the user
|
||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||||
options: AuthenticationOptions(
|
// options: AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
// var dec = await CRUD()
|
// var dec = await CRUD()
|
||||||
// .postWallet(link: AppLink.paymobPayoutDriverWallet, payload: {
|
// .postWallet(link: AppLink.paymobPayoutDriverWallet, payload: {
|
||||||
@@ -117,10 +117,10 @@ class PaymobPayout extends GetxController {
|
|||||||
// Authenticate the user
|
// Authenticate the user
|
||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||||
options: AuthenticationOptions(
|
// options: AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
var body = {
|
var body = {
|
||||||
"issuer": "bank_card",
|
"issuer": "bank_card",
|
||||||
@@ -188,10 +188,10 @@ class PaymobPayout extends GetxController {
|
|||||||
// Authenticate the user
|
// Authenticate the user
|
||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||||
options: AuthenticationOptions(
|
// options: AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
await payToDriverWallet(amount, issuer, msisdn);
|
await payToDriverWallet(amount, issuer, msisdn);
|
||||||
} else {
|
} else {
|
||||||
@@ -214,10 +214,10 @@ class PaymobPayout extends GetxController {
|
|||||||
// Authenticate the user
|
// Authenticate the user
|
||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||||
options: AuthenticationOptions(
|
// options: AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
await payToDriverBankAccount(amount, bankCardNumber, bankCode);
|
await payToDriverBankAccount(amount, bankCardNumber, bankCode);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -439,10 +439,10 @@ class PaymentController extends GetxController {
|
|||||||
// Authenticate the user
|
// Authenticate the user
|
||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||||
options: AuthenticationOptions(
|
// options: AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
final PaymobResponse? response = await PaymobPayment.instance.pay(
|
final PaymobResponse? response = await PaymobPayment.instance.pay(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -590,10 +590,11 @@ class PaymentController extends GetxController {
|
|||||||
// Authenticate the user
|
// Authenticate the user
|
||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
localizedReason: 'Use Touch ID or Face ID to confirm payment',
|
||||||
options: AuthenticationOptions(
|
// options: AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
// )
|
||||||
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
final PaymobResponseWallet? response =
|
final PaymobResponseWallet? response =
|
||||||
await PaymobPaymentWallet.instance.pay(
|
await PaymobPaymentWallet.instance.pay(
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ class _PayoutScreenState extends State<PayoutScreen> {
|
|||||||
// 1. طلب المصادقة البيومترية
|
// 1. طلب المصادقة البيومترية
|
||||||
bool didAuthenticate = await _localAuth.authenticate(
|
bool didAuthenticate = await _localAuth.authenticate(
|
||||||
localizedReason: 'استخدم بصمة الإصبع لتأكيد عملية السحب',
|
localizedReason: 'استخدم بصمة الإصبع لتأكيد عملية السحب',
|
||||||
options: const AuthenticationOptions(
|
// options: const AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
),
|
// ),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (didAuthenticate && mounted) {
|
if (didAuthenticate && mounted) {
|
||||||
|
|||||||
@@ -312,10 +312,10 @@ class WalletCaptainRefactored extends StatelessWidget {
|
|||||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||||
localizedReason:
|
localizedReason:
|
||||||
'Use Touch ID or Face ID to confirm payment'.tr,
|
'Use Touch ID or Face ID to confirm payment'.tr,
|
||||||
options: const AuthenticationOptions(
|
// options: const AuthenticationOptions(
|
||||||
biometricOnly: true,
|
biometricOnly: true,
|
||||||
sensitiveTransaction: true,
|
sensitiveTransaction: true,
|
||||||
));
|
);
|
||||||
if (didAuthenticate) {
|
if (didAuthenticate) {
|
||||||
if (double.parse(controller.amountFromBudgetController.text) <
|
if (double.parse(controller.amountFromBudgetController.text) <
|
||||||
double.parse(controller.totalAmountVisa)) {
|
double.parse(controller.totalAmountVisa)) {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import flutter_app_group_directory
|
|||||||
import flutter_image_compress_macos
|
import flutter_image_compress_macos
|
||||||
import flutter_inappwebview_macos
|
import flutter_inappwebview_macos
|
||||||
import flutter_local_notifications
|
import flutter_local_notifications
|
||||||
import flutter_secure_storage_macos
|
import flutter_secure_storage_darwin
|
||||||
import flutter_tts
|
import flutter_tts
|
||||||
import geolocator_apple
|
import geolocator_apple
|
||||||
import google_sign_in_ios
|
import google_sign_in_ios
|
||||||
@@ -26,8 +26,7 @@ import local_auth_darwin
|
|||||||
import location
|
import location
|
||||||
import objectbox_flutter_libs
|
import objectbox_flutter_libs
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import record_macos
|
||||||
import record_darwin
|
|
||||||
import share_plus
|
import share_plus
|
||||||
import sign_in_with_apple
|
import sign_in_with_apple
|
||||||
import sqflite_darwin
|
import sqflite_darwin
|
||||||
@@ -49,7 +48,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
|
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
|
||||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
|
||||||
FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin"))
|
FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin"))
|
||||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||||
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
|
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
|
||||||
@@ -58,8 +57,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
|
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
|
||||||
ObjectboxFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "ObjectboxFlutterLibsPlugin"))
|
ObjectboxFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "ObjectboxFlutterLibsPlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
|
||||||
RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin"))
|
|
||||||
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
||||||
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
|
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
|
|||||||
802
pubspec.lock
802
pubspec.lock
File diff suppressed because it is too large
Load Diff
58
pubspec.yaml
58
pubspec.yaml
@@ -20,14 +20,14 @@ dependencies:
|
|||||||
path: ./trip_overlay_plugin
|
path: ./trip_overlay_plugin
|
||||||
# flutter_overlay_window: ^0.4.4
|
# flutter_overlay_window: ^0.4.4
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
firebase_messaging: ^15.0.3
|
firebase_messaging: ^16.1.3
|
||||||
firebase_core: ^3.2.0
|
firebase_core: ^4.6.0
|
||||||
flutter_local_notifications: ^18.0.1
|
flutter_local_notifications: ^21.0.0
|
||||||
google_maps_flutter: ^2.10.1
|
google_maps_flutter: ^2.10.1
|
||||||
sqflite: ^2.3.0
|
sqflite: ^2.3.0
|
||||||
path: ^1.8.3
|
path: ^1.8.3
|
||||||
# lottie: ^2.5.0
|
# lottie: ^2.5.0
|
||||||
intl: ^0.19.0
|
intl: ^0.20.2
|
||||||
google_fonts: ^8.0.2
|
google_fonts: ^8.0.2
|
||||||
http: ^1.2.2
|
http: ^1.2.2
|
||||||
get: ^4.6.5
|
get: ^4.6.5
|
||||||
@@ -37,8 +37,8 @@ dependencies:
|
|||||||
google_polyline_algorithm: ^3.1.0
|
google_polyline_algorithm: ^3.1.0
|
||||||
# custom_searchable_dropdown: ^2.1.1
|
# custom_searchable_dropdown: ^2.1.1
|
||||||
animated_text_kit: ^4.2.2
|
animated_text_kit: ^4.2.2
|
||||||
flutter_secure_storage: ^9.0.0
|
flutter_secure_storage: ^10.0.0
|
||||||
geolocator: ^13.0.2
|
geolocator: ^14.0.2
|
||||||
flutter_paypal: ^0.2.0
|
flutter_paypal: ^0.2.0
|
||||||
flutter_launcher_icons: ^0.14.2 #to be remove
|
flutter_launcher_icons: ^0.14.2 #to be remove
|
||||||
# crypto: ^3.0.3
|
# crypto: ^3.0.3
|
||||||
@@ -46,21 +46,21 @@ dependencies:
|
|||||||
flutter_rating_bar: ^4.0.1
|
flutter_rating_bar: ^4.0.1
|
||||||
flutter_font_icons: ^2.2.5
|
flutter_font_icons: ^2.2.5
|
||||||
image_picker: ^1.0.4
|
image_picker: ^1.0.4
|
||||||
flutter_stripe: ^11.3.0
|
flutter_stripe: ^12.4.0
|
||||||
camera: ^0.11.0+1 #to be remove
|
camera: ^0.12.0+1 #to be remove
|
||||||
flutter_widget_from_html: ^0.15.1
|
flutter_widget_from_html: ^0.17.1
|
||||||
local_auth: ^2.1.7
|
local_auth: ^3.0.1
|
||||||
image: ^4.1.3 #to be remove
|
image: ^4.1.3 #to be remove
|
||||||
image_cropper: ^8.1.0
|
image_cropper: ^12.1.1
|
||||||
envied: ^1.0.0
|
envied: ^1.0.0
|
||||||
# cached_network_image: ^3.3.0 #to be remove
|
# cached_network_image: ^3.3.0 #to be remove
|
||||||
calendar_builder: ^0.0.6
|
calendar_builder: ^0.0.6
|
||||||
fl_chart: ^0.70.0
|
fl_chart: ^1.2.0
|
||||||
# agora_rtc_engine: ^6.2.6
|
# agora_rtc_engine: ^6.2.6
|
||||||
flutter_tts: ^4.0.2
|
flutter_tts: ^4.0.2
|
||||||
permission_handler: ^11.3.0
|
permission_handler: ^12.0.1
|
||||||
# google_generative_ai: ^0.0.1-dev
|
# google_generative_ai: ^0.0.1-dev
|
||||||
vibration: ^2.0.1
|
vibration: ^3.1.8
|
||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
# background_location: ^0.13.0
|
# background_location: ^0.13.0
|
||||||
# background_location:
|
# background_location:
|
||||||
@@ -72,29 +72,29 @@ dependencies:
|
|||||||
# git:
|
# git:
|
||||||
# url: https://github.com/Hamza-Ayed/flutter_overlay_apps.git
|
# url: https://github.com/Hamza-Ayed/flutter_overlay_apps.git
|
||||||
# ref: main
|
# ref: main
|
||||||
record: ^5.0.5
|
record: ^6.2.0
|
||||||
dio: ^5.4.3+1
|
dio: ^5.4.3+1
|
||||||
webview_flutter: ^4.9.0
|
webview_flutter: ^4.9.0
|
||||||
just_audio: ^0.9.37
|
just_audio: ^0.10.5
|
||||||
share_plus: ^7.2.1
|
share_plus: ^12.0.2
|
||||||
google_sign_in: ^6.2.1
|
google_sign_in: ^7.2.0
|
||||||
# google_mlkit_text_recognition: ^0.14.0
|
# google_mlkit_text_recognition: ^0.14.0
|
||||||
sign_in_with_apple: ^6.1.0
|
sign_in_with_apple: ^7.0.1
|
||||||
firebase_auth: ^5.1.2
|
firebase_auth: ^6.3.0
|
||||||
package_info_plus: ^8.0.0
|
package_info_plus: ^9.0.1
|
||||||
flutter_image_compress: ^2.3.0
|
flutter_image_compress: ^2.3.0
|
||||||
flutter_contacts: ^1.1.8
|
flutter_contacts: ^1.1.8
|
||||||
flutter_overlay_window: ^0.4.4
|
flutter_overlay_window: ^0.5.0
|
||||||
googleapis_auth: ^1.6.0
|
googleapis_auth: ^2.0.0
|
||||||
video_player: ^2.9.2
|
video_player: ^2.9.2
|
||||||
youtube_player_flutter: ^9.0.4
|
youtube_player_flutter: ^9.0.4
|
||||||
flutter_confetti: ^0.3.0
|
flutter_confetti: ^0.5.1
|
||||||
slide_to_act: ^2.0.2
|
slide_to_act: ^2.0.2
|
||||||
live_activities: ^2.3.0
|
live_activities: ^2.3.0
|
||||||
quick_actions: ^1.1.0
|
quick_actions: ^1.1.0
|
||||||
jwt_decoder: ^2.0.1
|
jwt_decoder: ^2.0.1
|
||||||
jailbreak_root_detection: ^1.1.5
|
jailbreak_root_detection: ^1.1.5
|
||||||
device_info_plus: ^11.3.0
|
device_info_plus: ^12.4.0
|
||||||
flutter_web_browser: ^0.17.3
|
flutter_web_browser: ^0.17.3
|
||||||
# flutter_isolate: ^2.1.0
|
# flutter_isolate: ^2.1.0
|
||||||
# lingo_hunter: ^1.0.3
|
# lingo_hunter: ^1.0.3
|
||||||
@@ -102,14 +102,14 @@ dependencies:
|
|||||||
flutter_svg: ^2.2.0
|
flutter_svg: ^2.2.0
|
||||||
lottie: ^3.3.1
|
lottie: ^3.3.1
|
||||||
flutter_staggered_animations: ^1.1.1
|
flutter_staggered_animations: ^1.1.1
|
||||||
battery_plus: ^6.2.2
|
battery_plus: ^7.0.0
|
||||||
internet_connection_checker: ^3.0.1
|
internet_connection_checker: ^3.0.1
|
||||||
connectivity_plus: ^6.1.5
|
connectivity_plus: ^6.1.5
|
||||||
# pip_view: ^0.9.7
|
# pip_view: ^0.9.7
|
||||||
flutter_map: ^6.1.0 # (استخدم أحدث إصدار دائماً)
|
flutter_map: ^8.2.2 # (استخدم أحدث إصدار دائماً)
|
||||||
|
|
||||||
# مكتبة التخزين لتحميل الخرائط أوفلاين
|
# مكتبة التخزين لتحميل الخرائط أوفلاين
|
||||||
flutter_map_tile_caching: ^9.0.0 # (استخدم أحدث إصدار)
|
flutter_map_tile_caching: ^10.1.1 # (استخدم أحدث إصدار)
|
||||||
latlong2: ^0.9.1
|
latlong2: ^0.9.1
|
||||||
socket_io_client: ^1.0.2
|
socket_io_client: ^1.0.2
|
||||||
flutter_background_service: ^5.1.0
|
flutter_background_service: ^5.1.0
|
||||||
@@ -120,7 +120,7 @@ dev_dependencies:
|
|||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
flutter_lints: ^5.0.0
|
flutter_lints: ^6.0.0
|
||||||
envied_generator: ^1.0.0
|
envied_generator: ^1.0.0
|
||||||
build_runner: ^2.4.6
|
build_runner: ^2.4.6
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,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