refactor: upgrade API endpoints to v3 and refactor navigation and response handling across controllers
This commit is contained in:
@@ -6,7 +6,7 @@ class AppLink {
|
|||||||
static String paymentServer = 'https://walletintaleq.intaleq.xyz/v2/main';
|
static String paymentServer = 'https://walletintaleq.intaleq.xyz/v2/main';
|
||||||
|
|
||||||
///https://api.intaleq.xyz/intaleq/ride/location
|
///https://api.intaleq.xyz/intaleq/ride/location
|
||||||
static String location = 'https://api.intaleq.xyz/intaleq_v1/ride/location';
|
static String location = 'https://api.intaleq.xyz/intaleq_v3/ride/location';
|
||||||
|
|
||||||
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
|
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
|
||||||
/// https://routesy.intaleq.xyz for syria
|
/// https://routesy.intaleq.xyz for syria
|
||||||
@@ -26,7 +26,7 @@ class AppLink {
|
|||||||
'https://location.intaleq.xyz/intaleq/ride/location';
|
'https://location.intaleq.xyz/intaleq/ride/location';
|
||||||
|
|
||||||
///https://api.intaleq.xyz/intaleq
|
///https://api.intaleq.xyz/intaleq
|
||||||
static final String endPoint = 'https://api.intaleq.xyz/intaleq_v1';
|
static final String endPoint = 'https://api.intaleq.xyz/intaleq_v3';
|
||||||
|
|
||||||
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
|
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
|
||||||
/// https://rides.intaleq.xyz/intaleq
|
/// https://rides.intaleq.xyz/intaleq
|
||||||
@@ -34,7 +34,7 @@ class AppLink {
|
|||||||
|
|
||||||
///https://api.intaleq.xyz/intaleq
|
///https://api.intaleq.xyz/intaleq
|
||||||
/// main api link for all api calls except rides and location
|
/// main api link for all api calls except rides and location
|
||||||
static final String server = 'https://api.intaleq.xyz/intaleq_v1';
|
static final String server = 'https://api.intaleq.xyz/intaleq_v3';
|
||||||
|
|
||||||
///https://rides.intaleq.xyz
|
///https://rides.intaleq.xyz
|
||||||
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
|
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
@@ -21,14 +22,12 @@ import 'package:Intaleq/views/home/map_page_passenger.dart';
|
|||||||
|
|
||||||
import 'package:location/location.dart';
|
import 'package:location/location.dart';
|
||||||
|
|
||||||
|
import '../../env/env.dart';
|
||||||
|
|
||||||
import '../../print.dart';
|
import '../../print.dart';
|
||||||
import '../../views/auth/otp_token_page.dart';
|
import '../../views/auth/otp_token_page.dart';
|
||||||
import '../functions/encrypt_decrypt.dart';
|
import '../functions/encrypt_decrypt.dart';
|
||||||
import '../functions/package_info.dart';
|
import '../functions/package_info.dart';
|
||||||
|
|
||||||
|
|
||||||
class LoginController extends GetxController {
|
class LoginController extends GetxController {
|
||||||
final formKey = GlobalKey<FormState>();
|
final formKey = GlobalKey<FormState>();
|
||||||
final formKeyAdmin = GlobalKey<FormState>();
|
final formKeyAdmin = GlobalKey<FormState>();
|
||||||
@@ -48,35 +47,12 @@ class LoginController extends GetxController {
|
|||||||
var dev = '';
|
var dev = '';
|
||||||
@override
|
@override
|
||||||
void onInit() async {
|
void onInit() async {
|
||||||
await getJWT();
|
|
||||||
// Log.print('box.read(BoxName.isTest): ${box.read(BoxName.isTest)}');
|
// Log.print('box.read(BoxName.isTest): ${box.read(BoxName.isTest)}');
|
||||||
box.write(BoxName.countryCode, 'Syria');
|
box.write(BoxName.countryCode, 'Syria');
|
||||||
FirebaseMessagesController().getToken();
|
FirebaseMessagesController().getToken();
|
||||||
super.onInit();
|
super.onInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAppTester() async {
|
|
||||||
// var res = await CRUD().get(
|
|
||||||
// link: AppLink.getTesterApp,
|
|
||||||
// payload: {'appPlatform': AppInformation.appName});
|
|
||||||
// if (res != 'failure') {
|
|
||||||
// var d = jsonDecode(res);
|
|
||||||
|
|
||||||
// isTest = int.parse(d['message'][0]['isTest'].toString());
|
|
||||||
// box.write(BoxName.isTest, isTest);
|
|
||||||
// update();
|
|
||||||
// } else {
|
|
||||||
// box.write(BoxName.isTest, '1');
|
|
||||||
// update();
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// updateAppTester(String appPlatform) async {
|
|
||||||
// await CRUD().post(
|
|
||||||
// link: AppLink.updateTesterApp, payload: {'appPlatform': appPlatform});
|
|
||||||
// }
|
|
||||||
|
|
||||||
void saveAgreementTerms() {
|
void saveAgreementTerms() {
|
||||||
box.write(BoxName.agreeTerms, 'agreed');
|
box.write(BoxName.agreeTerms, 'agreed');
|
||||||
update();
|
update();
|
||||||
@@ -87,7 +63,6 @@ class LoginController extends GetxController {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════
|
||||||
// LoginController — دوال إدارة الـ JWT
|
// LoginController — دوال إدارة الـ JWT
|
||||||
// ───────────────────────────────────────────────────────────────
|
// ───────────────────────────────────────────────────────────────
|
||||||
@@ -104,70 +79,134 @@ class LoginController extends GetxController {
|
|||||||
// • firstTimeLoadKey == false ← مستخدم موجود → loginJwtRider
|
// • firstTimeLoadKey == false ← مستخدم موجود → loginJwtRider
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
Future<void> getJWT() async {
|
Future<void> getJWT() async {
|
||||||
dev = Platform.isAndroid ? 'android' : 'ios';
|
// إذا كان التوكن الحالي لا يزال صالحاً، لا داعي لطلب واحد جديد
|
||||||
|
if (isTokenValid()) {
|
||||||
|
Log.print("JWT is still valid. Skipping request.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// تأكد إن البصمة محدّثة قبل أي طلب
|
try {
|
||||||
await DeviceHelper.getDeviceFingerprint();
|
dev = Platform.isAndroid ? 'android' : 'ios';
|
||||||
final String fp = box.read(BoxName.deviceFpEncrypted) ?? '';
|
|
||||||
|
|
||||||
if (box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
|
// تأكد إن البصمة محدّثة قبل أي طلب
|
||||||
// ── أول تسجيل ─────────────────────────────────────────
|
await DeviceHelper.getDeviceFingerprint();
|
||||||
// نرسل البصمة المشفرة مع باقي البيانات
|
final String fp = box.read(BoxName.deviceFpEncrypted) ?? '';
|
||||||
// السيرفر سيعمل hash لها ويخزنها في JWT payload
|
|
||||||
var payload = {
|
|
||||||
'id': box.read(BoxName.passengerID) ?? AK.newId,
|
|
||||||
'password': AK.passnpassenger,
|
|
||||||
'aud': '${AK.allowed}$dev',
|
|
||||||
'fingerPrint': fp,
|
|
||||||
};
|
|
||||||
|
|
||||||
var response = await http.post(
|
if (box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
|
||||||
Uri.parse(AppLink.loginFirstTime),
|
// ── أول تسجيل ─────────────────────────────────────────
|
||||||
body: payload,
|
// نرسل البصمة المشفرة مع باقي البيانات
|
||||||
);
|
// السيرفر سيعمل hash لها ويخزنها في JWT payload
|
||||||
Log.print('AppLink.loginFirstTime: ${AppLink.loginFirstTime}');
|
var payload = {
|
||||||
|
'id': box.read(BoxName.passengerID) ?? AK.newId,
|
||||||
|
'password': AK.passnpassenger,
|
||||||
|
'aud': '${AK.allowed}$dev',
|
||||||
|
'fingerPrint': fp,
|
||||||
|
};
|
||||||
|
|
||||||
Log.print('payload: $payload');
|
var response = await http.post(
|
||||||
Log.print('response: $response');
|
Uri.parse(AppLink.loginFirstTime),
|
||||||
|
body: payload,
|
||||||
|
);
|
||||||
|
Log.print('AppLink.loginFirstTime: ${AppLink.loginFirstTime}');
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
Log.print('payload: $payload');
|
||||||
final decoded = jsonDecode(response.body);
|
Log.print('response: $response');
|
||||||
final String jwt = decoded['jwt'];
|
|
||||||
|
|
||||||
// نشفر الـ JWT بالتشفير الثلاثي قبل التخزين في GetStorage
|
if (response.statusCode == 200) {
|
||||||
box.write(BoxName.jwt, c(jwt));
|
final decoded = jsonDecode(response.body);
|
||||||
|
final String? jwt =
|
||||||
|
decoded['data'] != null ? decoded['data']['jwt'] : (decoded['message'] != null ? decoded['message']['jwt'] : decoded['jwt']);
|
||||||
|
|
||||||
|
if (jwt != null) {
|
||||||
|
// نشفر الـ JWT بالتشفير الثلاثي قبل التخزين في GetStorage
|
||||||
|
box.write(BoxName.jwt, c(jwt));
|
||||||
|
}
|
||||||
|
|
||||||
|
await EncryptionHelper.initialize();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ── مستخدم موجود: تجديد التوكن ────────────────────────
|
||||||
await EncryptionHelper.initialize();
|
await EncryptionHelper.initialize();
|
||||||
|
|
||||||
|
var payload = {
|
||||||
|
'id': box.read(BoxName.passengerID),
|
||||||
|
'fingerPrint': fp,
|
||||||
|
'aud': '${AK.allowed}$dev',
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await http.post(
|
||||||
|
Uri.parse(AppLink.loginJwtRider),
|
||||||
|
body: payload,
|
||||||
|
);
|
||||||
|
Log.print('AppLink.loginJwtRider: ${AppLink.loginJwtRider}');
|
||||||
|
|
||||||
|
Log.print('payload: $payload');
|
||||||
|
Log.print('response: ${response.body}');
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final decoded = jsonDecode(response.body);
|
||||||
|
final String? jwt =
|
||||||
|
decoded['data'] != null ? decoded['data']['jwt'] : (decoded['message'] != null ? decoded['message']['jwt'] : decoded['jwt']);
|
||||||
|
|
||||||
|
if (jwt != null) {
|
||||||
|
box.write(BoxName.jwt, c(jwt));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e) {
|
||||||
// ── مستخدم موجود: تجديد التوكن ────────────────────────
|
Log.print('Error in getJWT: $e');
|
||||||
await EncryptionHelper.initialize();
|
|
||||||
|
|
||||||
var payload = {
|
|
||||||
'id': box.read(BoxName.passengerID),
|
|
||||||
'fingerPrint': fp,
|
|
||||||
'aud': '${AK.allowed}$dev',
|
|
||||||
};
|
|
||||||
|
|
||||||
var response = await http.post(
|
|
||||||
Uri.parse(AppLink.loginJwtRider),
|
|
||||||
body: payload,
|
|
||||||
);
|
|
||||||
Log.print('AppLink.loginJwtRider: ${AppLink.loginJwtRider}');
|
|
||||||
|
|
||||||
Log.print('payload: $payload');
|
|
||||||
Log.print('response: ${response.body}');
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
final decoded = jsonDecode(response.body);
|
|
||||||
final String jwt = decoded['jwt'];
|
|
||||||
|
|
||||||
box.write(BoxName.jwt, c(jwt));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
// getJwtWallet: الحصول على توكن لسيرفر المدفوعات
|
// التحقق من صلاحية التوكن يدوياً (بدون مكاتب خارجية)
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
bool isTokenValid() {
|
||||||
|
try {
|
||||||
|
final String? encryptedJwt = box.read(BoxName.jwt);
|
||||||
|
if (encryptedJwt == null || encryptedJwt.isEmpty) {
|
||||||
|
Log.print("isTokenValid: No token found in storage.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. فك تشفير التوكن المخزن
|
||||||
|
final String jwtFull = r(encryptedJwt).toString();
|
||||||
|
final String jwt = jwtFull.split(Env.addd)[0];
|
||||||
|
|
||||||
|
final parts = jwt.split('.');
|
||||||
|
if (parts.length != 3) {
|
||||||
|
Log.print("isTokenValid: Invalid JWT format (parts: ${parts.length})");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. فك Base64 للجزء الأوسط (Payload)
|
||||||
|
String payloadPart = parts[1];
|
||||||
|
while (payloadPart.length % 4 != 0) {
|
||||||
|
payloadPart += '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
final String decodedPayload = utf8.decode(base64Url.decode(payloadPart));
|
||||||
|
final Map<String, dynamic> payload = jsonDecode(decodedPayload);
|
||||||
|
|
||||||
|
if (!payload.containsKey('exp')) {
|
||||||
|
Log.print("isTokenValid: No 'exp' claim in token.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int exp = payload['exp'];
|
||||||
|
final int now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||||
|
|
||||||
|
Log.print("isTokenValid: Now=$now, Exp=$exp, Diff=${exp - now}s");
|
||||||
|
|
||||||
|
// اعتبار التوكن منتهي قبل دقيقة للأمان
|
||||||
|
final bool valid = exp > (now + 60);
|
||||||
|
Log.print("isTokenValid: Result=$valid");
|
||||||
|
return valid;
|
||||||
|
} catch (e) {
|
||||||
|
Log.print("isTokenValid Error: $e");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
// الفرق عن getJWT:
|
// الفرق عن getJWT:
|
||||||
// • يستخدم endpoint مختلف (loginWallet)
|
// • يستخدم endpoint مختلف (loginWallet)
|
||||||
@@ -197,11 +236,15 @@ class LoginController extends GetxController {
|
|||||||
Log.print('response wallet: ${response.body}');
|
Log.print('response wallet: ${response.body}');
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final decoded = jsonDecode(response.body);
|
final decoded = jsonDecode(response.body);
|
||||||
final String jwt = decoded['jwt'];
|
final String? jwt =
|
||||||
final String hmac = decoded['hmac'];
|
decoded['data'] != null ? decoded['data']['jwt'] : decoded['jwt'];
|
||||||
|
final String? hmac =
|
||||||
|
decoded['data'] != null ? decoded['data']['hmac'] : decoded['hmac'];
|
||||||
|
|
||||||
// نخزن الـ hmac للاستخدام في X-HMAC-Auth header
|
if (hmac != null) {
|
||||||
box.write(BoxName.hmac, hmac);
|
// نخزن الـ hmac للاستخدام في X-HMAC-Auth header
|
||||||
|
box.write(BoxName.hmac, hmac);
|
||||||
|
}
|
||||||
|
|
||||||
// wallet JWT يُرجَع مباشرة دون تشفير ثلاثي
|
// wallet JWT يُرجَع مباشرة دون تشفير ثلاثي
|
||||||
return jwt;
|
return jwt;
|
||||||
@@ -213,8 +256,8 @@ class LoginController extends GetxController {
|
|||||||
Future<void> loginUsingCredentials(String passengerID, String email) async {
|
Future<void> loginUsingCredentials(String passengerID, String email) async {
|
||||||
isloading = true;
|
isloading = true;
|
||||||
update();
|
update();
|
||||||
await getJWT();
|
// await getJWT();
|
||||||
|
Log.print("LoginController.loginUsingCredentials: ");
|
||||||
try {
|
try {
|
||||||
// 1) استعلام تسجيل الدخول
|
// 1) استعلام تسجيل الدخول
|
||||||
final res = await CRUD().get(
|
final res = await CRUD().get(
|
||||||
@@ -227,16 +270,16 @@ class LoginController extends GetxController {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (res == 'Failure') {
|
// 2) فك JSON مرة واحدة والتحقق من النجاح
|
||||||
|
final decoded = jsonDecode(res);
|
||||||
|
if (decoded is! Map || decoded.isEmpty) return;
|
||||||
|
|
||||||
|
if (decoded['status'] == 'failure' || decoded['status'] == 'Failure') {
|
||||||
Get.snackbar("User does not exist.".tr, '',
|
Get.snackbar("User does not exist.".tr, '',
|
||||||
backgroundColor: Colors.red);
|
backgroundColor: Colors.red);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) فك JSON مرة واحدة
|
|
||||||
final decoded = jsonDecode(res);
|
|
||||||
if (decoded is! Map || decoded.isEmpty) return;
|
|
||||||
|
|
||||||
final status = (decoded['status'] ?? '').toString();
|
final status = (decoded['status'] ?? '').toString();
|
||||||
final data = (decoded['data'] as List?)?.firstOrNull as Map? ?? {};
|
final data = (decoded['data'] as List?)?.firstOrNull as Map? ?? {};
|
||||||
if (status != 'success' || data['verified'].toString() != '1') {
|
if (status != 'success' || data['verified'].toString() != '1') {
|
||||||
@@ -263,47 +306,62 @@ class LoginController extends GetxController {
|
|||||||
// مهم: تأكد من passengerID في الـ box
|
// مهم: تأكد من passengerID في الـ box
|
||||||
box.write(BoxName.passengerID, passengerID);
|
box.write(BoxName.passengerID, passengerID);
|
||||||
|
|
||||||
// 4) تنفيذ العمليات بالتوازي: getTokens + fingerprint محلي
|
// 4) فحص ما إذا كان التوكن موجوداً في رد الـ Login المدمج (V3 Optimization)
|
||||||
final results = await Future.wait([
|
String? serverFCM;
|
||||||
CRUD().get(
|
String? serverFP;
|
||||||
link: AppLink.getTokens, payload: {'passengerID': passengerID}),
|
|
||||||
DeviceHelper.getDeviceFingerprint(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
final tokenResp = results[0];
|
var userData = decoded['data'] is List
|
||||||
final localFP = (results[1] ?? '').toString();
|
? (decoded['data'] as List).firstOrNull
|
||||||
|
: decoded['data'];
|
||||||
|
if (userData is Map && userData['fcm_token'] != null) {
|
||||||
|
serverFCM = userData['fcm_token'].toString();
|
||||||
|
serverFP = userData['fcm_fingerprint']?.toString() ?? '';
|
||||||
|
Log.print(
|
||||||
|
"✅ FCM Token found in Login response. Skipping separate getTokens call.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// إذا لم يكن موجوداً (توافقية قديمة)، نقوم بطلبه
|
||||||
|
String? tokenResp;
|
||||||
|
if (serverFCM == null) {
|
||||||
|
tokenResp = await CRUD().get(
|
||||||
|
link: AppLink.getTokens, payload: {'passengerID': passengerID});
|
||||||
|
}
|
||||||
|
|
||||||
|
final localFP = (await DeviceHelper.getDeviceFingerprint()).toString();
|
||||||
await storage.write(key: BoxName.fingerPrint, value: localFP);
|
await storage.write(key: BoxName.fingerPrint, value: localFP);
|
||||||
await box.write(BoxName.firstTimeLoadKey, 'false');
|
await box.write(BoxName.firstTimeLoadKey, 'false');
|
||||||
|
|
||||||
// ── 5. المقارنة: FCM token + fingerprint ──────────────────────
|
// ── 5. المقارنة: FCM token + fingerprint ──────────────────────
|
||||||
if (email != '962798583052@intaleqapp.com' && tokenResp != 'failure') {
|
if (email != '962798583052@intaleqapp.com') {
|
||||||
final tokenJson = jsonDecode(tokenResp);
|
if (serverFCM == null &&
|
||||||
final serverData = tokenJson['message'] as Map?; // null = أول تسجيل
|
tokenResp != null &&
|
||||||
|
tokenResp != 'failure' &&
|
||||||
if (serverData != null) {
|
tokenResp != 'error') {
|
||||||
final serverFCM = serverData['token']?.toString() ?? '';
|
final tokenJson = jsonDecode(tokenResp);
|
||||||
final serverFP = serverData['fingerPrint']?.toString() ?? '';
|
final serverData = tokenJson['data'] ?? tokenJson['message'];
|
||||||
|
if (serverData is Map) {
|
||||||
|
serverFCM = serverData['token']?.toString() ?? '';
|
||||||
|
serverFP = serverData['fingerPrint']?.toString() ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverFCM != null && serverFCM.isNotEmpty) {
|
||||||
final localFCM = (box.read(BoxName.tokenFCM) ?? '').toString();
|
final localFCM = (box.read(BoxName.tokenFCM) ?? '').toString();
|
||||||
|
|
||||||
// ── اختلاف أي منهما = جهاز مختلف أو تثبيت جديد ─────────
|
// ── اختلاف أي منهما = جهاز مختلف أو تثبيت جديد ─────────
|
||||||
final fcmChanged = serverFCM.isNotEmpty && serverFCM != localFCM;
|
final fcmChanged = serverFCM != localFCM;
|
||||||
final fpChanged = serverFP.isNotEmpty && serverFP != localFP;
|
final fpChanged =
|
||||||
|
serverFP != null && serverFP.isNotEmpty && serverFP != localFP;
|
||||||
|
|
||||||
if (fcmChanged || fpChanged) {
|
if (fcmChanged || fpChanged) {
|
||||||
// final goVerify = await _confirmDeviceChangeDialog();
|
|
||||||
// if (goVerify == true) {
|
|
||||||
mySnackbarInfo('Device Change Detected'.tr);
|
mySnackbarInfo('Device Change Detected'.tr);
|
||||||
//
|
|
||||||
await Get.to(() => OtpVerificationPage(
|
await Get.to(() => OtpVerificationPage(
|
||||||
phone: data['phone'].toString(),
|
phone: data['phone'].toString(),
|
||||||
deviceToken: localFP,
|
deviceToken: localFP,
|
||||||
token: tokenResp,
|
token: tokenResp ?? '',
|
||||||
ptoken: serverFCM, // نمرر FCM القديم للـ OTP controller
|
ptoken: serverFCM ?? '', // نمرر FCM القديم للـ OTP controller
|
||||||
));
|
));
|
||||||
return; // لا تكمل — الـ OTP controller يتولى الانتقال
|
return;
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ class CRUD {
|
|||||||
box.read(BoxName.driverID) != null ? 'Driver' : 'Passenger';
|
box.read(BoxName.driverID) != null ? 'Driver' : 'Passenger';
|
||||||
final phone = box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver);
|
final phone = box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver);
|
||||||
|
|
||||||
|
// طباعة الخطأ في الكونسول للمطور للمتابعة الفورية
|
||||||
|
Log.print("🚨 [ADD_ERROR] Where: $where | Error: $error | Details: $details");
|
||||||
|
|
||||||
// Fire-and-forget call to prevent infinite loops if the logger itself fails.
|
// Fire-and-forget call to prevent infinite loops if the logger itself fails.
|
||||||
CRUD().post(
|
CRUD().post(
|
||||||
link: AppLink.addError,
|
link: AppLink.addError,
|
||||||
@@ -203,23 +206,35 @@ class CRUD {
|
|||||||
Log.print('payload: $payload');
|
Log.print('payload: $payload');
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
var jsonData = jsonDecode(response.body);
|
return response.body;
|
||||||
if (jsonData['status'] == 'success') {
|
|
||||||
return response.body;
|
|
||||||
}
|
|
||||||
return jsonData['status'];
|
|
||||||
} else if (response.statusCode == 401) {
|
} else if (response.statusCode == 401) {
|
||||||
var jsonData = jsonDecode(response.body);
|
var jsonData = jsonDecode(response.body);
|
||||||
if (jsonData['error'] == 'Token expired') {
|
if (jsonData['error'] == 'Token expired') {
|
||||||
|
print("CRUD.get: Token expired, refreshing and retrying once...");
|
||||||
await Get.put(LoginController()).getJWT();
|
await Get.put(LoginController()).getJWT();
|
||||||
return 'token_expired';
|
|
||||||
|
// إعادة المحاولة مرة واحدة فقط بتوكن جديد
|
||||||
|
var retryResponse = await http.post(
|
||||||
|
url,
|
||||||
|
body: payload,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
'Authorization': 'Bearer ${r(box.read(BoxName.jwt)).toString().split(Env.addd)[0]}',
|
||||||
|
'X-Device-FP': _getFpHeader(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (retryResponse.statusCode == 200) {
|
||||||
|
return retryResponse.body;
|
||||||
|
}
|
||||||
|
return jsonEncode({'status': 'failure', 'message': 'token_expired_retry_failed'});
|
||||||
} else {
|
} else {
|
||||||
return 'failure';
|
return jsonEncode({'status': 'failure', 'message': '401_unauthorized'});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
addError('Non-200 response code: ${response.statusCode}',
|
addError('Non-200 response code: ${response.statusCode}',
|
||||||
'crud().get - Other', url.toString());
|
'crud().get - Other', url.toString());
|
||||||
return 'failure';
|
return jsonEncode({'status': 'failure', 'message': 'server_error_${response.statusCode}'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:Intaleq/services/offline_map_service.dart';
|
import 'package:Intaleq/services/offline_map_service.dart';
|
||||||
import 'package:Intaleq/services/emergency_signal_service.dart';
|
import 'package:Intaleq/services/emergency_signal_service.dart';
|
||||||
|
import 'package:Intaleq/views/widgets/mycircular.dart';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math' show Random, atan2, cos, max, min, pi, pow, sin, sqrt;
|
import 'dart:math' show Random, atan2, cos, max, min, pi, pow, sin, sqrt;
|
||||||
@@ -1517,17 +1518,17 @@ class MapPassengerController extends GetxController {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RideState.searching:
|
case RideState.searching:
|
||||||
// effectivePollingInterval = 5;
|
// 1. التحقق من حالة الطلب (هل قبله أحد؟) عبر البولينج فقط إذا كان السوكيت غير متصل
|
||||||
|
if (!isSocketConnected) {
|
||||||
// 1. التحقق من حالة الطلب (هل قبله أحد؟)
|
try {
|
||||||
try {
|
String statusFromServer = await getRideStatus(rideId);
|
||||||
String statusFromServer = await getRideStatus(rideId);
|
if (statusFromServer == 'Apply' || statusFromServer == 'Applied') {
|
||||||
if (statusFromServer == 'Apply' || statusFromServer == 'Applied') {
|
await processRideAcceptance(source: "Polling");
|
||||||
await processRideAcceptance(source: "Polling");
|
break;
|
||||||
break;
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Log.print('Error polling getRideStatus: $e');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
Log.print('Error polling getRideStatus: $e');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
@@ -1587,18 +1588,21 @@ class MapPassengerController extends GetxController {
|
|||||||
rideAppliedFromDriver(true);
|
rideAppliedFromDriver(true);
|
||||||
_isDriverAppliedLogicExecuted = true;
|
_isDriverAppliedLogicExecuted = true;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
String statusFromServer = await getRideStatus(rideId);
|
if (!isSocketConnected) {
|
||||||
if (statusFromServer == 'Arrived') {
|
try {
|
||||||
currentRideState.value = RideState.driverArrived;
|
String statusFromServer = await getRideStatus(rideId);
|
||||||
break;
|
if (statusFromServer == 'Arrived') {
|
||||||
} else if (statusFromServer == 'Begin' ||
|
currentRideState.value = RideState.driverArrived;
|
||||||
statusFromServer == 'inProgress') {
|
break;
|
||||||
processRideBegin();
|
} else if (statusFromServer == 'Begin' ||
|
||||||
break;
|
statusFromServer == 'inProgress') {
|
||||||
|
processRideBegin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Log.print('Error polling for Arrived/Begin status: $e');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
Log.print('Error polling for Arrived/Begin status: $e');
|
|
||||||
}
|
}
|
||||||
getDriverCarsLocationToPassengerAfterApplied();
|
getDriverCarsLocationToPassengerAfterApplied();
|
||||||
break;
|
break;
|
||||||
@@ -1615,31 +1619,33 @@ class MapPassengerController extends GetxController {
|
|||||||
case RideState.inProgress:
|
case RideState.inProgress:
|
||||||
// effectivePollingInterval = 6;
|
// effectivePollingInterval = 6;
|
||||||
|
|
||||||
try {
|
if (!isSocketConnected) {
|
||||||
String statusFromServer = await getRideStatus(rideId);
|
try {
|
||||||
|
String statusFromServer = await getRideStatus(rideId);
|
||||||
|
|
||||||
// !!! هنا التغيير الجذري !!!
|
// !!! هنا التغيير الجذري !!!
|
||||||
if (statusFromServer == 'Finished' ||
|
if (statusFromServer == 'Finished' ||
|
||||||
statusFromServer == 'finished') {
|
statusFromServer == 'finished') {
|
||||||
Log.print(
|
Log.print(
|
||||||
'🏁 DETECTED FINISHED: Killing processes and forcing Review.');
|
'🏁 DETECTED FINISHED: Killing processes and forcing Review.');
|
||||||
|
|
||||||
// 1. قتل العمليات فوراً
|
// 1. قتل العمليات فوراً
|
||||||
stopAllTimers();
|
stopAllTimers();
|
||||||
|
|
||||||
// 2. تغيير الحالة الداخلية لمنع أي كود آخر من العمل
|
// 2. تغيير الحالة الداخلية لمنع أي كود آخر من العمل
|
||||||
currentRideState.value = RideState.preCheckReview;
|
currentRideState.value = RideState.preCheckReview;
|
||||||
|
|
||||||
// 3. تنظيف الواجهة
|
// 3. تنظيف الواجهة
|
||||||
tripFinishedFromDriver();
|
tripFinishedFromDriver();
|
||||||
|
|
||||||
// 4. استدعاء شاشة التقييم فوراً
|
// 4. استدعاء شاشة التقييم فوراً
|
||||||
_checkLastRideForReview();
|
_checkLastRideForReview();
|
||||||
|
|
||||||
return; // خروج نهائي من الدالة لمنع أي كود بالأسفل من التنفيذ
|
return; // خروج نهائي من الدالة لمنع أي كود بالأسفل من التنفيذ
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Log.print('Error polling status: $e');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
Log.print('Error polling status: $e');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// بقية كود التتبع العادي (لن يتم الوصول إليه إذا انتهت الرحلة)
|
// بقية كود التتبع العادي (لن يتم الوصول إليه إذا انتهت الرحلة)
|
||||||
@@ -2906,8 +2912,17 @@ class MapPassengerController extends GetxController {
|
|||||||
isStartAppHasRide = false;
|
isStartAppHasRide = false;
|
||||||
Log.print(
|
Log.print(
|
||||||
"No rides found for the given passenger ID within the last hour.");
|
"No rides found for the given passenger ID within the last hour.");
|
||||||
|
} else {
|
||||||
|
var decoded = jsonDecode(res);
|
||||||
|
if (decoded['status'] == 'failure') {
|
||||||
|
rideStatusFromStartApp = {
|
||||||
|
'data': {'status': 'NoRide', 'needsReview': false}
|
||||||
|
};
|
||||||
|
isStartAppHasRide = false;
|
||||||
|
} else {
|
||||||
|
rideStatusFromStartApp = decoded;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rideStatusFromStartApp = jsonDecode(res);
|
|
||||||
if (rideStatusFromStartApp['data']['status'] == 'Begin' ||
|
if (rideStatusFromStartApp['data']['status'] == 'Begin' ||
|
||||||
rideStatusFromStartApp['data']['status'] == 'Apply' ||
|
rideStatusFromStartApp['data']['status'] == 'Apply' ||
|
||||||
rideStatusFromStartApp['data']['status'] == 'Applied') {
|
rideStatusFromStartApp['data']['status'] == 'Applied') {
|
||||||
@@ -6020,35 +6035,58 @@ Intaleq Team''';
|
|||||||
Log.print(
|
Log.print(
|
||||||
'🔔 showDrawingBottomSheet called. isDrawingRoute: $isDrawingRoute');
|
'🔔 showDrawingBottomSheet called. isDrawingRoute: $isDrawingRoute');
|
||||||
|
|
||||||
// استخدام addPostFrameCallback لضمان ظهور الإشعار بعد انتهاء بناء الإطار
|
final context = Get.context;
|
||||||
|
if (context == null) return;
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Get.rawSnackbar(
|
// إغلاق أي سناك بار مفتوح حالياً لتجنب التكرار
|
||||||
titleText: Text(
|
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||||
'Drawing route on map...'.tr,
|
|
||||||
style: const TextStyle(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
color: Colors.white,
|
SnackBar(
|
||||||
fontWeight: FontWeight.bold,
|
content: Row(
|
||||||
fontSize: 14,
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
child: MyCircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Drawing route on map...'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
'Please wait while we prepare your trip.'.tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white70,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
backgroundColor: AppColor.primaryColor.withOpacity(0.95),
|
||||||
messageText: Text(
|
duration: const Duration(seconds: 3),
|
||||||
'Please wait while we prepare your trip.'.tr,
|
behavior: SnackBarBehavior.floating,
|
||||||
style: const TextStyle(
|
margin: const EdgeInsets.fromLTRB(16, 0, 16, 110),
|
||||||
color: Colors.white70,
|
shape: RoundedRectangleBorder(
|
||||||
fontSize: 12,
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
|
elevation: 8,
|
||||||
),
|
),
|
||||||
showProgressIndicator: true,
|
|
||||||
progressIndicatorBackgroundColor: Colors.white24,
|
|
||||||
progressIndicatorValueColor:
|
|
||||||
const AlwaysStoppedAnimation<Color>(Colors.white),
|
|
||||||
snackPosition: SnackPosition.BOTTOM,
|
|
||||||
backgroundColor: AppColor.primaryColor.withOpacity(0.9),
|
|
||||||
duration: const Duration(seconds: 3),
|
|
||||||
margin: const EdgeInsets.fromLTRB(16, 0, 16, 110),
|
|
||||||
borderRadius: 16,
|
|
||||||
icon: const Icon(Icons.map_outlined, color: Colors.white),
|
|
||||||
isDismissible: true,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -7484,16 +7522,22 @@ Intaleq Team''';
|
|||||||
);
|
);
|
||||||
if (res != 'failure') {
|
if (res != 'failure') {
|
||||||
var json = jsonDecode(res);
|
var json = jsonDecode(res);
|
||||||
kazan = double.parse(json['message'][0]['kazan']);
|
// التحقق الديناميكي من 'data' أو 'message'
|
||||||
naturePrice = double.parse(json['message'][0]['naturePrice']);
|
var dataList = json['data'] ?? json['message'];
|
||||||
heavyPrice = double.parse(json['message'][0]['heavyPrice']);
|
|
||||||
latePrice = double.parse(json['message'][0]['latePrice']);
|
if (dataList != null && dataList is List && dataList.isNotEmpty) {
|
||||||
comfortPrice = double.parse(json['message'][0]['comfortPrice']);
|
var firstRow = dataList[0];
|
||||||
speedPrice = double.parse(json['message'][0]['speedPrice']);
|
kazan = double.parse(firstRow['kazan'].toString());
|
||||||
deliveryPrice = double.parse(json['message'][0]['deliveryPrice']);
|
naturePrice = double.parse(firstRow['naturePrice'].toString());
|
||||||
mashwariPrice = double.parse(json['message'][0]['freePrice']);
|
heavyPrice = double.parse(firstRow['heavyPrice'].toString());
|
||||||
familyPrice = double.parse(json['message'][0]['familyPrice']);
|
latePrice = double.parse(firstRow['latePrice'].toString());
|
||||||
fuelPrice = double.parse(json['message'][0]['fuelPrice']);
|
comfortPrice = double.parse(firstRow['comfortPrice'].toString());
|
||||||
|
speedPrice = double.parse(firstRow['speedPrice'].toString());
|
||||||
|
deliveryPrice = double.parse(firstRow['deliveryPrice'].toString());
|
||||||
|
mashwariPrice = double.parse(firstRow['freePrice'].toString());
|
||||||
|
familyPrice = double.parse(firstRow['familyPrice'].toString());
|
||||||
|
fuelPrice = double.parse(firstRow['fuelPrice'].toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7502,7 +7546,8 @@ Intaleq Team''';
|
|||||||
link: AppLink.getPassengerRate,
|
link: AppLink.getPassengerRate,
|
||||||
payload: {'passenger_id': box.read(BoxName.passengerID)});
|
payload: {'passenger_id': box.read(BoxName.passengerID)});
|
||||||
if (res != 'failure') {
|
if (res != 'failure') {
|
||||||
var message = jsonDecode(res)['message'];
|
var json = jsonDecode(res);
|
||||||
|
var message = json['data'] ?? json['message'];
|
||||||
if (message['rating'] == null) {
|
if (message['rating'] == null) {
|
||||||
passengerRate = 5.0; // Default rating
|
passengerRate = 5.0; // Default rating
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -230,8 +230,16 @@ ${'Download the Intaleq app now and enjoy your ride!'.tr}
|
|||||||
Get.snackbar('Success'.tr, 'Invite sent successfully'.tr,
|
Get.snackbar('Success'.tr, 'Invite sent successfully'.tr,
|
||||||
backgroundColor: Colors.green, colorText: Colors.white);
|
backgroundColor: Colors.green, colorText: Colors.white);
|
||||||
|
|
||||||
String expirationTime = d['message']['expirationTime'].toString();
|
// التحقق الديناميكي من مكان البيانات (V1 vs V3)
|
||||||
String inviteCode = d['message']['inviteCode'].toString();
|
var payload = d['data'] ?? d['message'];
|
||||||
|
|
||||||
|
// إذا كان الـ message نصاً وليس خريطة (Map)، نأخذ البيانات من المستوى الأعلى
|
||||||
|
if (payload is String) {
|
||||||
|
payload = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
String expirationTime = (payload['expirationTime'] ?? '').toString();
|
||||||
|
String inviteCode = (payload['inviteCode'] ?? '').toString();
|
||||||
|
|
||||||
// New and improved WhatsApp message for better user engagement.
|
// New and improved WhatsApp message for better user engagement.
|
||||||
String message =
|
String message =
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class OrderHistoryController extends GetxController {
|
|||||||
update();
|
update();
|
||||||
} else {
|
} else {
|
||||||
var jsonDecoded = jsonDecode(res);
|
var jsonDecoded = jsonDecode(res);
|
||||||
|
var rawData = jsonDecoded['data'] ?? jsonDecoded['message'];
|
||||||
orderHistoryListPassenger = jsonDecoded['data'];
|
orderHistoryListPassenger = rawData is List ? rawData : [];
|
||||||
isloading = false;
|
isloading = false;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ class SplashScreenController extends GetxController
|
|||||||
await _getPackageInfo();
|
await _getPackageInfo();
|
||||||
SecureStorage().saveData('iss', 'mobile-app:');
|
SecureStorage().saveData('iss', 'mobile-app:');
|
||||||
|
|
||||||
|
// ── [OPTIMIZATION] جلب التوكن عند بداية تشغيل التطبيق ────────────────
|
||||||
|
Log.print("SplashScreen: Initializing JWT...");
|
||||||
|
await Get.find<LoginController>().getJWT();
|
||||||
|
|
||||||
if (box.read(BoxName.onBoarding) == null) {
|
if (box.read(BoxName.onBoarding) == null) {
|
||||||
Get.off(() => OnBoardingPage());
|
Get.off(() => OnBoardingPage());
|
||||||
} else if (box.read(BoxName.email) != null &&
|
} else if (box.read(BoxName.email) != null &&
|
||||||
|
|||||||
@@ -20,13 +20,26 @@ class PassengerNotificationController extends GetxController {
|
|||||||
var res = await CRUD().get(
|
var res = await CRUD().get(
|
||||||
link: AppLink.getNotificationPassenger,
|
link: AppLink.getNotificationPassenger,
|
||||||
payload: {'passenger_id': box.read(BoxName.passengerID)});
|
payload: {'passenger_id': box.read(BoxName.passengerID)});
|
||||||
if (res == "failure") {
|
if (res == "failure" || res == "error") {
|
||||||
MyDialog().getDialog('There is no notification yet'.tr, '', () {
|
MyDialog().getDialog('There is no notification yet'.tr, '', () {
|
||||||
Get.back();
|
Get.back();
|
||||||
Get.back();
|
Get.back();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
notificationData = jsonDecode(res);
|
final decoded = jsonDecode(res);
|
||||||
|
// التحقق من وجود البيانات في 'data' أو 'message'
|
||||||
|
var rawData = decoded['data'] ?? decoded['message'];
|
||||||
|
|
||||||
|
if (decoded['status'] == 'error' || decoded['status'] == 'failure' || rawData == "No notification data found") {
|
||||||
|
notificationData = {'status': 'success', 'message': []}; // قائمة فارغة لمنع الخطأ في UI
|
||||||
|
} else {
|
||||||
|
// التأكد أننا نخزن قائمة
|
||||||
|
notificationData = {
|
||||||
|
'status': 'success',
|
||||||
|
'message': rawData is List ? rawData : [rawData]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
isloading = false;
|
isloading = false;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -638,7 +638,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () => Get.back(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
foregroundColor: Colors.grey,
|
foregroundColor: Colors.grey,
|
||||||
),
|
),
|
||||||
@@ -653,7 +653,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
|||||||
if (controller.promoFormKey.currentState!
|
if (controller.promoFormKey.currentState!
|
||||||
.validate()) {
|
.validate()) {
|
||||||
controller.applyPromoCodeToPassenger(context);
|
controller.applyPromoCodeToPassenger(context);
|
||||||
Get.back();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -779,7 +779,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () => Get.back(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
@@ -799,7 +799,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
|||||||
kolor: AppColor.greenColor,
|
kolor: AppColor.greenColor,
|
||||||
title: 'Select This Ride'.tr,
|
title: 'Select This Ride'.tr,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back();
|
Navigator.of(context).pop();
|
||||||
_handleCarSelection(
|
_handleCarSelection(
|
||||||
context, mapPassengerController, carType);
|
context, mapPassengerController, carType);
|
||||||
},
|
},
|
||||||
@@ -886,7 +886,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
|||||||
mapPassengerController.totalPassenger =
|
mapPassengerController.totalPassenger =
|
||||||
_getOriginalPrice(carType, mapPassengerController);
|
_getOriginalPrice(carType, mapPassengerController);
|
||||||
if (carType.carType == 'Mishwar Vip') {
|
if (carType.carType == 'Mishwar Vip') {
|
||||||
Get.back();
|
Navigator.of(context).pop();
|
||||||
mapPassengerController.mishwariOption();
|
mapPassengerController.mishwariOption();
|
||||||
} else if (carType.carType == 'Lady') {
|
} else if (carType.carType == 'Lady') {
|
||||||
if (box.read(BoxName.gender).toString() != '') {
|
if (box.read(BoxName.gender).toString() != '') {
|
||||||
@@ -905,17 +905,17 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
|||||||
title: "Select betweeen types".tr,
|
title: "Select betweeen types".tr,
|
||||||
content:
|
content:
|
||||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||||
_buildRayehGaiOption(mapPassengerController, 'Awfar Car',
|
_buildRayehGaiOption(context, mapPassengerController, 'Awfar Car',
|
||||||
mapPassengerController.totalPassengerRayehGaiBalash),
|
mapPassengerController.totalPassengerRayehGaiBalash),
|
||||||
_buildRayehGaiOption(mapPassengerController, 'Fixed Price',
|
_buildRayehGaiOption(context, mapPassengerController, 'Fixed Price',
|
||||||
mapPassengerController.totalPassengerRayehGai),
|
mapPassengerController.totalPassengerRayehGai),
|
||||||
_buildRayehGaiOption(mapPassengerController, 'Comfort',
|
_buildRayehGaiOption(context, mapPassengerController, 'Comfort',
|
||||||
mapPassengerController.totalPassengerRayehGaiComfort)
|
mapPassengerController.totalPassengerRayehGaiComfort)
|
||||||
]),
|
]),
|
||||||
cancel: MyElevatedButton(
|
cancel: MyElevatedButton(
|
||||||
kolor: AppColor.redColor,
|
kolor: AppColor.redColor,
|
||||||
title: 'Cancel'.tr,
|
title: 'Cancel'.tr,
|
||||||
onPressed: () => Get.back()),
|
onPressed: () => Navigator.of(context).pop()),
|
||||||
confirm: MyElevatedButton(
|
confirm: MyElevatedButton(
|
||||||
kolor: AppColor.greenColor,
|
kolor: AppColor.greenColor,
|
||||||
title: 'Next'.tr,
|
title: 'Next'.tr,
|
||||||
@@ -951,11 +951,14 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRayehGaiOption(MapPassengerController mapPassengerController,
|
Widget _buildRayehGaiOption(
|
||||||
String carTypeName, double price) {
|
BuildContext context,
|
||||||
|
MapPassengerController mapPassengerController,
|
||||||
|
String carTypeName,
|
||||||
|
double price) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.back();
|
Navigator.of(context).pop();
|
||||||
mapPassengerController.totalPassenger = price;
|
mapPassengerController.totalPassenger = price;
|
||||||
mapPassengerController.isBottomSheetShown = false;
|
mapPassengerController.isBottomSheetShown = false;
|
||||||
mapPassengerController.update();
|
mapPassengerController.update();
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class NotificationPage extends StatelessWidget {
|
|||||||
Get.put(PassengerNotificationController());
|
Get.put(PassengerNotificationController());
|
||||||
return MyScafolld(
|
return MyScafolld(
|
||||||
isleading: true,
|
isleading: true,
|
||||||
title: 'Notifications',
|
title: 'Notifications'.tr,
|
||||||
body: [
|
body: [
|
||||||
GetBuilder<PassengerNotificationController>(
|
GetBuilder<PassengerNotificationController>(
|
||||||
builder: (notificationCaptainController) => notificationCaptainController
|
builder: (notificationCaptainController) => notificationCaptainController
|
||||||
|
|||||||
Reference in New Issue
Block a user