2026-04-03-pre map libra
This commit is contained in:
+46
-20
@@ -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"
|
||||||
}
|
}
|
||||||
+24
-5
@@ -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}"
|
||||||
}
|
|
||||||
|
|
||||||
subprojects {
|
|
||||||
project.evaluationDependsOn(':app')
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project.state.executed) {
|
||||||
|
setupAndroid()
|
||||||
|
} else {
|
||||||
|
project.afterEvaluate {
|
||||||
|
setupAndroid()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("clean", Delete) {
|
tasks.register("clean", Delete) {
|
||||||
|
|||||||
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
@@ -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"}
|
||||||
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
@@ -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 {
|
||||||
|
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 {
|
} 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.
|
||||||
@@ -196,11 +348,11 @@ Download the Intaleq app now and enjoy your ride!
|
|||||||
Get.back();
|
Get.back();
|
||||||
} 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 {
|
||||||
@@ -265,21 +417,21 @@ Download the Intaleq app now and enjoy your ride!
|
|||||||
Get.back();
|
Get.back();
|
||||||
} 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; // لعرض الوقت في الواجهة
|
||||||
await getCaptainDurationOnToday();
|
Duration _currentDuration = Duration.zero; // لتخزين الوقت ككائن Duration
|
||||||
|
|
||||||
|
void startPeriodicExecution() async {
|
||||||
|
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 {
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ class PaymobPayout extends GetxController {
|
|||||||
if (isAvailable) {
|
if (isAvailable) {
|
||||||
// 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: {
|
||||||
@@ -116,11 +116,11 @@ class PaymobPayout extends GetxController {
|
|||||||
if (isAvailable) {
|
if (isAvailable) {
|
||||||
// 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",
|
||||||
@@ -187,11 +187,11 @@ class PaymobPayout extends GetxController {
|
|||||||
if (isAvailable) {
|
if (isAvailable) {
|
||||||
// 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 {
|
||||||
@@ -213,11 +213,11 @@ class PaymobPayout extends GetxController {
|
|||||||
if (isAvailable) {
|
if (isAvailable) {
|
||||||
// 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 {
|
||||||
|
|||||||
@@ -438,11 +438,11 @@ class PaymentController extends GetxController {
|
|||||||
if (isAvailable) {
|
if (isAvailable) {
|
||||||
// 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,
|
||||||
@@ -589,11 +589,12 @@ class PaymentController extends GetxController {
|
|||||||
if (isAvailable) {
|
if (isAvailable) {
|
||||||
// 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) {
|
||||||
|
|||||||
@@ -310,12 +310,12 @@ class WalletCaptainRefactored extends StatelessWidget {
|
|||||||
if (isAvailable) {
|
if (isAvailable) {
|
||||||
// Authenticate the user
|
// Authenticate the user
|
||||||
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"))
|
||||||
|
|||||||
+417
-385
File diff suppressed because it is too large
Load Diff
+29
-29
@@ -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