Files
tripz-llc/apps/driver/lib/controller/auth/captin/login_captin_controller.dart
T
HamzaandClaude Opus 4.8 6234e66471 feat: Gemini AI (doc OCR + face match) + role-assignment endpoints
- GeminiService (integrations/gemini, @Global): extractDocument (OCR fields) + faceMatch; graceful if no GEMINI_API_KEY
- documents: face-match now real via Gemini; POST /admin/documents/:id/ocr extracts fields for CS auto-fill
- roles: PATCH /admin/users/:id/role (admin) + POST /platform/users/role (bootstrap via x-platform-secret)
- config: gemini + platform.secret; .env.example entries

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:01:26 +03:00

788 lines
30 KiB
Dart
Executable File

import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'dart:math';
import 'package:http/http.dart' as http;
import 'package:permission_handler/permission_handler.dart';
import 'package:sefer_driver/views/auth/captin/egypt_card_a_i.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:get/get.dart';
import 'package:sefer_driver/constant/box_name.dart';
import 'package:sefer_driver/constant/links.dart';
import 'package:sefer_driver/controller/functions/crud.dart';
import 'package:sefer_driver/main.dart';
import 'package:sefer_driver/views/home/Captin/home_captain/home_captin.dart';
import 'package:location/location.dart';
import '../../../constant/api_key.dart';
import '../../../print.dart';
import '../../../views/auth/captin/otp_page.dart';
import '../../../views/auth/captin/otp_token_page.dart';
import '../../../views/auth/syria/pending_driver_page.dart';
import '../../firebase/local_notification.dart';
import '../../firebase/notification_service.dart';
import '../../functions/encrypt_decrypt.dart';
import '../../functions/package_info.dart';
import '../../functions/security_checks.dart';
class LoginDriverController extends GetxController {
final formKey = GlobalKey<FormState>();
TextEditingController emailController = TextEditingController();
TextEditingController phoneController = TextEditingController();
TextEditingController passwordController = TextEditingController();
TextEditingController passwordController2 = TextEditingController();
bool isAgreeTerms = false;
bool isGoogleDashOpen = false;
bool isGoogleLogin = false;
bool isloading = false;
late int isTest = 1;
final FlutterSecureStorage _storage = const FlutterSecureStorage();
final location = Location();
void changeAgreeTerm() {
isAgreeTerms = !isAgreeTerms;
update();
}
bool isPasswordHidden = true;
void togglePasswordVisibility() {
isPasswordHidden = !isPasswordHidden;
update([
'passwordVisibility'
]); // Use a unique ID to only update the password field
}
void changeGoogleDashOpen() {
isGoogleDashOpen = !isGoogleDashOpen;
update();
}
@override
void onInit() async {
box.write(BoxName.countryCode, 'Egypt');
// box.write(BoxName.driverID, '34feffd3fa72d6bee56b');
// await getAppTester();
getJWT();
super.onInit();
}
// getAppTester() async {
// var res = await CRUD().get(
// link: AppLink.getTesterApp,
// payload: {'appPlatform': AppInformation.appName});
// // Log.print('res: ${res}');
// if (res != 'failure') {
// var d = jsonDecode(res);
// isTest = d['message'][0]['isTest'];
// // Log.print('isTest: ${isTest}');
// box.write(BoxName.isTest, isTest);
// // Log.print('isTest: ${box.read(BoxName.isTest)}');
// update();
// } else {
// isTest = 0;
// box.write(BoxName.isTest, isTest);
// update();
// return false;
// }
// }
updateAppTester(String appPlatform) async {
await CRUD().post(
link: AppLink.updateTesterApp, payload: {'appPlatform': appPlatform});
}
isPhoneVerified() async {
// 1. أولاً نتأكد هل يوجد رقم هاتف محفوظ محلياً (تجاوز الـ OTP)
String? savedPhone = box.read(BoxName.phoneDriver);
Log.print('savedPhone: ${savedPhone}');
if (savedPhone == null || savedPhone.isEmpty) {
// لا يوجد رقم محفوظ، نعيد المستخدم لصفحة إدخال الرقم
Get.offAll(() => PhoneNumberScreen());
return;
}
var res = await CRUD().post(
link: AppLink.isPhoneVerified, payload: {'phone_number': savedPhone});
Log.print('isPhoneVerified Res: $res');
if (res != 'failure') {
// الحالة 1: السائق موجود ومفعل -> نذهب للصفحة التالية
Get.offAll(() => EgyptCardAI());
} else {
// الحالة 2: الرد فشل (السائق غير موجود في الداتا بيز)
if (savedPhone != null && savedPhone.isNotEmpty) {
// بما أن الرقم محفوظ، فهذا مستخدم جديد أكمل التحقق
// نوجهه لصفحة التسجيل/البطاقة بدلاً من العودة للبداية
Log.print('New User Detected, redirecting to Registration...');
Get.offAll(() => EgyptCardAI());
} else {
// لا يوجد رقم محفوظ ولا مستخدم في السيرفر -> عودة للبداية
Get.offAll(() => PhoneNumberScreen());
}
}
}
// isPhoneVerified() async {
// var res = await CRUD().post(
// link: AppLink.isPhoneVerified,
// payload: {'phone_number': box.read(BoxName.phoneDriver)});
// Log.print('isPhoneVerified: ${res}');
// if (res != 'failure') {
// // Get.offAll(() => SyrianCardAI());
// Get.offAll(() => EgyptCardAI());
// // isloading = false;
// // update();
// } else {
// Get.offAll(() => PhoneNumberScreen());
// }
// }
void saveAgreementTerms() {
box.write(BoxName.agreeTerms, 'agreed');
update();
}
void saveCountryCode(String countryCode) {
box.write(BoxName.countryCode, countryCode);
update();
}
var dev = '';
getJwtWallet() async {
if (box.read(BoxName.security_check).toString() != 'passed') {
Log.print('Security check failed');
return;
}
Log.print('Security check passed');
String fingerPrint = await DeviceHelper.getDeviceFingerprint();
// Log.print('fingerPrint: ${fingerPrint}');
dev = Platform.isAndroid ? 'android' : 'ios';
var payload = {
'id': box.read(BoxName.driverID),
'password': AK.passnpassenger,
'aud': '${AK.allowedWallet}$dev',
'fingerPrint': fingerPrint
};
var response1 = await http.post(
Uri.parse(AppLink.loginJwtWalletDriver),
body: payload,
);
// Log.print('response.request: ${response1.request}');
// Log.print('response.JwtWallet: ${response1.body}');
// print(payload);
// Log.print('payment["jwt"]: ${jsonDecode(response1.body)['jwt']}');
await box.write(BoxName.hmac, jsonDecode(response1.body)['hmac']);
return jsonDecode(response1.body)['jwt'].toString();
}
String shortHash(String password) {
var bytes = utf8.encode(password);
var digest = sha256.convert(bytes);
return base64UrlEncode(digest.bytes);
}
getJWT() async {
dev = Platform.isAndroid ? 'android' : 'ios';
Log.print(
'box.read(BoxName.firstTimeLoadKey): ${box.read(BoxName.firstTimeLoadKey)}');
if (box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
var payload = {
'id': box.read(BoxName.driverID) ?? AK.newId,
'password': AK.passnpassenger,
'aud': '${AK.allowed}$dev',
};
// Log.print('payload: ${payload}');
var response0 = await http.post(
Uri.parse(AppLink.loginFirstTimeDriver),
body: payload,
);
// Log.print('response0: ${response0.body}');
Log.print('request: ${response0.request}');
if (response0.statusCode == 200) {
final decodedResponse1 = jsonDecode(response0.body);
// Log.print('decodedResponse1: ${decodedResponse1}');
final jwt = decodedResponse1['jwt'];
box.write(BoxName.jwt, c(jwt));
// ✅ بعد التأكد أن كل المفاتيح موجودة
await EncryptionHelper.initialize();
// await AppInitializer().getKey();
} else {}
} else {
await EncryptionHelper.initialize();
var payload = {
'id': box.read(BoxName.driverID),
'password': box.read(BoxName.emailDriver),
'aud': '${AK.allowed}$dev',
};
// print(payload);
var response1 = await http.post(
Uri.parse(AppLink.loginJwtDriver),
body: payload,
);
// print(response1.request);
// print(response1.body);
if (response1.statusCode == 200) {
final decodedResponse1 = jsonDecode(response1.body);
// Log.print('decodedResponse1: ${decodedResponse1}');
final jwt = decodedResponse1['jwt'];
await box.write(BoxName.jwt, c(jwt));
// await AppInitializer().getKey();
}
}
}
Future<void> getLocationPermission() async {
var status = await Permission.locationAlways.status;
if (!status.isGranted) {
await Permission.locationAlways.request();
}
update();
}
String generateUniqueIdFromEmail(String email) {
// Step 1: Extract the local part of the email
String localPart = email.split('@')[0];
// Step 2: Replace invalid characters (if any)
String cleanLocalPart = localPart.replaceAll(RegExp(r'[^a-zA-Z0-9]'), '');
// Step 3: Ensure it does not exceed 24 characters
if (cleanLocalPart.length > 24) {
cleanLocalPart = cleanLocalPart.substring(0, 24);
}
// Step 4: Generate a random suffix if needed
String suffix = generateRandomSuffix(24 - cleanLocalPart.length);
return cleanLocalPart + suffix;
}
String generateRandomSuffix(int length) {
const String chars =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
Random random = Random();
return List.generate(length, (index) => chars[random.nextInt(chars.length)])
.join('');
}
bool isInviteDriverFound = false;
Future updateInvitationCodeFromRegister() async {
var res = await CRUD().post(
link: AppLink.updateDriverInvitationDirectly,
payload: {
"inviterDriverPhone": box.read(BoxName.phoneDriver).toString(),
},
);
Log.print('invite: ${res}');
box.write(BoxName.isInstall, '1');
// ✅ تصحيح 1: التحقق من أن الرد ليس 'failure' وأنه Map قبل القراءة
if (res != 'failure' && res is Map && res['status'] == 'success') {
isInviteDriverFound = true;
update();
NotificationController().showNotification(
"Code approved".tr, "Code approved".tr, 'tone2', '');
// ✅ تصحيح 2: استخراج التوكن حسب هيكل PHP الجديد (مفتاح 'data')
String? targetToken;
// الهيكل الجديد: {status: success, data: {token: ...}}
if (res['data'] != null && res['data']['token'] != null) {
targetToken = res['data']['token'].toString();
}
// دعم الهيكل القديم للاحتياط: {status: success, message: [{token: ...}]}
else if (res['message'] is List && res['message'].isNotEmpty) {
targetToken = res['message'][0]['token'].toString();
}
if (targetToken != null) {
NotificationService.sendNotification(
target: targetToken,
title: 'You have received a gift token!'.tr,
body: 'for '.tr + box.read(BoxName.phoneDriver).toString(),
isTopic: false,
tone: 'tone2',
driverList: [],
category: 'You have received a gift token!',
);
}
} else {
// فشل التحديث (الكود غير موجود أو خطأ سيرفر)
// لا تفعل شيئاً أو اعرض رسالة خطأ صامتة
}
}
loginWithGoogleCredential(String driverID, String email) async {
isloading = true;
update();
try {
// 1. تجهيز البيانات الإضافية للأمان
String platformName = Platform.isIOS ? 'ios' : 'android';
String storedPhone = box.read(BoxName.phoneDriver)?.toString() ?? '';
// 2. إرسال الطلب الموحد (Login + Token + PackageInfo)
var res = await CRUD().get(link: AppLink.loginFromGoogleCaptin, payload: {
'id': driverID,
'email': email, // ضروري للمطابقة الأمنية في السيرفر
'phone': storedPhone, // اختياري، لزيادة الموثوقية
'platform': platformName // لجلب معلومات التحديث المناسبة للجهاز
});
Log.print('loginWithGoogleCredential Response: $res');
if (res == 'failure') {
// فشل الدخول (البيانات غير موجودة أو غير مطابقة)
// نحاول التحقق من حالة الهاتف لتوجيهه للتسجيل إذا كان جديداً
await isPhoneVerified();
isloading = false;
update();
return false;
} else {
var jsonResponse = jsonDecode(res);
if (jsonResponse['status'] == 'success') {
// ---------------------------------------------------------
// A. معالجة بيانات السائق الأساسية
// ---------------------------------------------------------
var d = jsonResponse['data'][0];
if (d['is_verified'].toString() == '1') {
// حفظ البيانات في التخزين المحلي
box.write(BoxName.emailDriver, d['email']);
box.write(BoxName.firstTimeLoadKey, 'false');
box.write(BoxName.driverID, d['id']);
box.write(BoxName.isTest, '1'); // أو حسب القيمة القادمة
box.write(BoxName.gender, d['gender']);
box.write(BoxName.phoneVerified, d['is_verified'].toString());
box.write(BoxName.phoneDriver, d['phone']);
box.write(BoxName.is_claimed, d['is_claimed']);
if (box.read(BoxName.isInstall).toString() == 'null' ||
box.read(BoxName.isInstall).toString() == '') {
box.write(BoxName.isInstall, d['isInstall']);
}
Log.print(
'isInstall for update invitation: ${box.read(BoxName.isInstall)}');
// box.write(BoxName.isInstall, d['isInstall']);
box.write(BoxName.nameArabic,
d['name_arabic']); // تأكد أن هذا الحقل موجود في الرد أو عدله
box.write(BoxName.bankCodeDriver, d['bankCode']);
box.write(BoxName.accountBankNumberDriver, d['accountBank']);
box.write(
BoxName.nameDriver, '${d['first_name']} ${d['last_name']}');
int categoryId =
int.tryParse(d['vehicle_category_id']?.toString() ?? '0') ?? 0;
// معالجة سنة السيارة بشكل آمن لتجنب الكراش
int carYear = int.tryParse(d['year']?.toString() ?? '0') ?? 0;
box.write(BoxName.carYear, carYear);
// منطق تحديد نوع السيارة
String gender = d['gender']?.toString() ?? '';
if (categoryId == 2) {
// 2 = دراجة / سكوتر (حسب قاعدة البيانات)
if (gender == 'Male') {
box.write(BoxName.carTypeOfDriver, 'Scooter');
} else {
box.write(BoxName.carTypeOfDriver, 'Pink Bike');
}
} else if (categoryId == 3) {
// 3 = فان (إذا كان لديكم فئة فان)
box.write(BoxName.carTypeOfDriver, 'Van');
} else if (carYear > 2017) {
if (gender != 'Male') {
box.write(BoxName.carTypeOfDriver, 'Lady');
} else {
box.write(BoxName.carTypeOfDriver, 'Comfort');
}
} else if (carYear > 2002 && carYear <= 2017) {
box.write(BoxName.carTypeOfDriver, 'Speed');
} else if (carYear <= 2002 && carYear > 0) {
box.write(BoxName.carTypeOfDriver, 'Awfar Car');
}
// ---------------------------------------------------------
// B. معالجة التحديثات (Package Info) من نفس الرد
// ---------------------------------------------------------
// if (jsonResponse['package_info'] != null &&
// (jsonResponse['package_info'] as List).isNotEmpty) {
// var pkg = jsonResponse['package_info'][0];
// // استدعاء دالة فحص التحديث (تأكد من وجودها أو مرر البيانات لها)
// // checkUpdateFromData(pkg);
// checkForUpdate(Get.context!);
// }
// ---------------------------------------------------------
// C. معالجة كود الدعوة
// ---------------------------------------------------------
if (box.read(BoxName.isInstall) == null ||
box.read(BoxName.isInstall).toString() == '0') {
updateInvitationCodeFromRegister();
}
// ---------------------------------------------------------
// D. التحقق الأمني (Device Fingerprint & Token)
// ---------------------------------------------------------
if (d['status'].toString() != 'yet') {
// استخراج التوكن من الرد المجمع (دون طلب جديد)
List? tokenList = jsonResponse['driver_token'];
// توليد بصمة الجهاز الحالية
String currentFingerPrint =
await DeviceHelper.getDeviceFingerprint();
await storage.write(
key: BoxName.fingerPrint, value: currentFingerPrint);
if (tokenList != null && tokenList.isNotEmpty) {
var tokenData = tokenList[0];
String serverToken = tokenData['token'].toString();
String serverFingerPrint = tokenData['fingerPrint'].toString();
String localToken =
box.read(BoxName.tokenDriver)?.toString() ?? "";
// التحقق من تطابق التوكن والبصمة
if (serverToken != localToken ||
serverFingerPrint != currentFingerPrint) {
isloading = false;
update();
await Get.defaultDialog(
barrierDismissible: false,
title: 'Device Change Detected'.tr,
middleText: 'Please verify your identity'.tr,
textConfirm: 'Verify'.tr,
confirmTextColor: Colors.white,
onConfirm: () {
Get.back(); // إغلاق الديالوج
// الانتقال لصفحة التحقق مع تمرير البيانات اللازمة
Get.to(() => OtpVerificationPage(
phone: d['phone'].toString(),
deviceToken: currentFingerPrint,
// نمرر التوكن القادم من السيرفر ليستعمل في التحقق لاحقاً
token: jsonEncode(
{'status': 'success', 'data': tokenList}),
ptoken: serverToken,
));
},
);
return true; // إيقاف التنفيذ هنا (بانتظار التحقق)
}
}
// إذا كل شيء سليم، الدخول للرئيسية
Get.offAll(() => HomeCaptain());
} else {
// الحالة "yet" تعني أن السائق لم يكمل رفع الوثائق
Get.offAll(() => DriverVerificationScreen());
}
isloading = false;
update();
return true;
} else {
// الحساب موجود لكن رقم الهاتف غير مفعل
Get.offAll(() => PhoneNumberScreen());
isloading = false;
update();
return false;
}
} else {
// الرد من السيرفر ليس success (رغم أنه ليس failure في الاتصال)
Get.offAll(() => PhoneNumberScreen());
isloading = false;
update();
return false;
}
}
} catch (e) {
Log.print("Login Critical Error: $e");
isloading = false;
update();
return false;
}
}
logintest(String driverID, email) async {
isloading = true;
update();
// await SecurityHelper.performSecurityChecks();
// Log.print('(BoxName.emailDriver): ${box.read(BoxName.emailDriver)}');
var res = await CRUD()
.get(link: AppLink.loginUsingCredentialsWithoutGoogle, payload: {
'email': email ?? 'yet',
'id': driverID,
});
// print('res is $res');
// if (res == 'failure') {
// await isPhoneVerified();
// // Get.snackbar('Failure', '', backgroundColor: Colors.red);
// } else
// {
var jsonDecoeded = jsonDecode(res);
var d = jsonDecoeded['data'][0];
if (jsonDecoeded.isNotEmpty) {
if (jsonDecoeded['status'] == 'success')
// &&
// d['is_verified'].toString() == '1')
{
box.write(BoxName.emailDriver, d['email']);
box.write(BoxName.firstTimeLoadKey, 'false');
box.write(BoxName.driverID, (d['id']));
box.write(BoxName.isTest, '1');
box.write(BoxName.gender, (d['gender']));
box.write(BoxName.phoneVerified, d['is_verified'].toString());
box.write(BoxName.phoneDriver, (d['phone']));
box.write(BoxName.is_claimed, d['is_claimed']);
box.write(BoxName.isInstall, d['isInstall']);
// box.write(
// BoxName.isGiftToken, d['isGiftToken']);
box.write(BoxName.nameArabic, (d['name_arabic']));
box.write(BoxName.carYear, d['year']);
box.write(BoxName.bankCodeDriver, (d['bankCode']));
box.write(BoxName.accountBankNumberDriver, (d['accountBank']));
box.write(
BoxName.nameDriver,
'${(d['first_name'])}'
' ${(d['last_name'])}');
if (((d['model']).toString().contains('دراجه') ||
d['make'].toString().contains('دراجه '))) {
if ((d['gender']).toString() == 'Male') {
box.write(BoxName.carTypeOfDriver, 'Scooter');
} else {
box.write(BoxName.carTypeOfDriver, 'Pink Bike');
}
} else if (int.parse(d['year'].toString()) > 2017) {
if (d['gender'].toString() != 'Male') {
box.write(BoxName.carTypeOfDriver, 'Lady');
} else {
box.write(BoxName.carTypeOfDriver, 'Comfort');
}
} else if (int.parse(d['year'].toString()) > 2002 &&
int.parse(d['year'].toString()) < 2017) {
box.write(BoxName.carTypeOfDriver, 'Speed');
} else if (int.parse(d['year'].toString()) < 2002) {
box.write(BoxName.carTypeOfDriver, 'Awfar Car');
}
// updateAppTester(AppInformation.appName);
// var token = await CRUD().get(
// link: AppLink.getDriverToken,
// payload: {'captain_id': (box.read(BoxName.driverID)).toString()});
// String fingerPrint = await DeviceHelper.getDeviceFingerprint();
// await storage.write(
// key: BoxName.fingerPrint, value: fingerPrint.toString());
Get.off(() => HomeCaptain());
// } else {
// Get.offAll(() => PhoneNumberScreen());
// isloading = false;
// update();
// }
// }
// else {
// mySnackbarSuccess('');
// isloading = false;
// update();
}
}
}
loginUsingCredentialsWithoutGoogle(
String password, String email, String phone) async {
isloading = true;
// تحديد نوع العملية (ليس جوجل)
isGoogleLogin = false;
update();
try {
String platformName = Platform.isIOS ? 'ios' : 'android';
// 1. إرسال الطلب (إضافة Platform)
var res = await CRUD()
.get(link: AppLink.loginUsingCredentialsWithoutGoogle, payload: {
'email': email,
'password': password,
'phone': phone, // <-- يجب إضافة هذا السطر
'platform': platformName
});
// حفظ الإيميل لمحاولات الدخول اللاحقة
box.write(BoxName.emailDriver, email);
if (res == 'failure') {
// في حال الفشل (كلمة مرور خطأ أو مستخدم غير موجود)
// نقوم بفحص حالة الهاتف إذا كان مسجلاً من قبل لتوجيهه
await isPhoneVerified();
isloading = false;
update();
return false;
} else {
var jsonResponse = jsonDecode(res);
if (jsonResponse['status'] == 'success' &&
jsonResponse['data'].isNotEmpty) {
var d = jsonResponse['data'][0];
// 2. التحقق من تفعيل الهاتف
if (d['is_verified'].toString() == '1') {
// --- A. حفظ البيانات الأساسية ---
box.write(BoxName.emailDriver, d['email']);
box.write(BoxName.firstTimeLoadKey, 'false');
box.write(BoxName.driverID, d['id']);
box.write(BoxName.isTest, '1');
box.write(BoxName.gender, d['gender']);
box.write(BoxName.phoneVerified, d['is_verified'].toString());
box.write(BoxName.phoneDriver, d['phone']);
box.write(BoxName.is_claimed, d['is_claimed']);
box.write(BoxName.isInstall, d['isInstall']);
box.write(BoxName.nameArabic, d['name_arabic']);
box.write(BoxName.bankCodeDriver, d['bankCode']);
box.write(BoxName.accountBankNumberDriver, d['accountBank']);
box.write(
BoxName.nameDriver, '${d['first_name']} ${d['last_name']}');
// --- B. منطق نوع السيارة ---
int categoryId =
int.tryParse(d['vehicle_category_id']?.toString() ?? '0') ?? 0;
int carYear = int.tryParse(d['year']?.toString() ?? '0') ?? 0;
box.write(BoxName.carYear, carYear);
String gender = d['gender']?.toString() ?? '';
if (categoryId == 2) {
if (gender == 'Male') {
box.write(BoxName.carTypeOfDriver, 'Scooter');
} else {
box.write(BoxName.carTypeOfDriver, 'Pink Bike');
}
} else if (categoryId == 3) {
box.write(BoxName.carTypeOfDriver, 'Van');
} else if (carYear > 2017) {
if (gender != 'Male') {
box.write(BoxName.carTypeOfDriver, 'Lady');
} else {
box.write(BoxName.carTypeOfDriver, 'Comfort');
}
} else if (carYear > 2002 && carYear <= 2017) {
box.write(BoxName.carTypeOfDriver, 'Speed');
} else if (carYear <= 2002 && carYear > 0) {
box.write(BoxName.carTypeOfDriver, 'Awfar Car');
}
// --- C. كود الدعوة ---
if (box.read(BoxName.isInstall) == null ||
box.read(BoxName.isInstall).toString() == '0') {
updateInvitationCodeFromRegister();
}
// --- D. التحقق الأمني (Device Fingerprint) ---
if (d['status'].toString() != 'yet') {
// الـ PHP المعدل يعيد driver_token داخل object السائق
List? tokenList = d['driver_token'];
String currentFingerPrint =
await DeviceHelper.getDeviceFingerprint();
await storage.write(
key: BoxName.fingerPrint, value: currentFingerPrint);
if (tokenList != null && tokenList.isNotEmpty) {
// نأخذ أحدث توكن (أو الأول في القائمة)
var tokenData = tokenList[0];
String serverToken = tokenData['token'].toString();
String serverFingerPrint = tokenData['fingerPrint'].toString();
String localToken =
box.read(BoxName.tokenDriver)?.toString() ?? "";
// إذا اختلف التوكن أو البصمة => جهاز جديد
if (serverToken != localToken ||
serverFingerPrint != currentFingerPrint) {
isloading = false;
update();
await Get.defaultDialog(
barrierDismissible: false,
title: 'Device Change Detected'.tr,
middleText: 'Please verify your identity'.tr,
textConfirm: 'Verify'.tr,
confirmTextColor: Colors.white,
onConfirm: () {
Get.back();
Get.to(() => OtpVerificationPage(
phone: d['phone'].toString(),
deviceToken: currentFingerPrint,
// تمرير قائمة التوكنات لاستخدامها في التحقق
token: jsonEncode(
{'status': 'success', 'data': tokenList}),
ptoken: serverToken,
));
},
);
return true;
}
}
// الدخول للرئيسية
Get.offAll(() => HomeCaptain());
} else {
// لم يكمل الوثائق
Get.offAll(() => DriverVerificationScreen());
}
isloading = false;
update();
return true;
} else {
// الحساب موجود لكن غير مفعل
Get.offAll(() => PhoneNumberScreen());
isloading = false;
update();
return false;
}
} else {
// استجابة غير متوقعة أو data فارغة
Get.snackbar("Error".tr, "Login Failed".tr);
isloading = false;
update();
return false;
}
}
} catch (e) {
Log.print("Login Credentials Error: $e");
isloading = false;
update();
return false;
}
}
void loginByBoxData() async {
Get.to(() => HomeCaptain());
await CRUD().post(link: AppLink.addTokensDriver, payload: {
'token': box.read(BoxName.tokenDriver).toString(),
'captain_id': box.read(BoxName.driverID).toString()
});
}
}