Initial commit for driver_tripz
This commit is contained in:
@@ -358,7 +358,10 @@ class LoginDriverController extends GetxController {
|
||||
' (jsonDecode(token): ${(jsonDecode(token)['data'][0]['token']).toString()}');
|
||||
if ((jsonDecode(token)['data'][0]['token']) !=
|
||||
(box.read(BoxName.tokenDriver))) {
|
||||
Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP(
|
||||
final fcm = Get.isRegistered<FirebaseMessagesController>()
|
||||
? Get.find<FirebaseMessagesController>()
|
||||
: Get.put(FirebaseMessagesController());
|
||||
fcm.sendNotificationToDriverMAP(
|
||||
'token change',
|
||||
'change device'.tr,
|
||||
(jsonDecode(token)['data'][0]['token']).toString(),
|
||||
@@ -367,6 +370,7 @@ class LoginDriverController extends GetxController {
|
||||
await Get.defaultDialog(
|
||||
title: 'you will use this device?'.tr,
|
||||
middleText: '',
|
||||
barrierDismissible: false,
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Ok'.tr,
|
||||
onPressed: () async {
|
||||
|
||||
@@ -14,9 +14,57 @@ import '../../constant/char_map.dart';
|
||||
import '../../constant/info.dart';
|
||||
import '../../print.dart';
|
||||
import 'gemeni.dart';
|
||||
import 'network/net_guard.dart';
|
||||
import 'upload_image.dart';
|
||||
|
||||
class CRUD {
|
||||
final NetGuard _netGuard = NetGuard();
|
||||
final _client = http.Client();
|
||||
|
||||
/// Stores the signature of the last logged error to prevent duplicates.
|
||||
static String _lastErrorSignature = '';
|
||||
|
||||
/// Stores the timestamp of the last logged error.
|
||||
static DateTime _lastErrorTimestamp =
|
||||
DateTime(2000); // Initialize with an old date
|
||||
/// The minimum time that must pass before logging the same error again.
|
||||
static const Duration _errorLogDebounceDuration = Duration(minutes: 1);
|
||||
|
||||
static Future<void> addError(
|
||||
String error, String details, String where) async {
|
||||
try {
|
||||
final currentErrorSignature = '$where-$error';
|
||||
final now = DateTime.now();
|
||||
|
||||
if (currentErrorSignature == _lastErrorSignature &&
|
||||
now.difference(_lastErrorTimestamp) < _errorLogDebounceDuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
_lastErrorSignature = currentErrorSignature;
|
||||
_lastErrorTimestamp = now;
|
||||
|
||||
final userId =
|
||||
box.read(BoxName.driverID) ?? box.read(BoxName.passengerID);
|
||||
final userType =
|
||||
box.read(BoxName.driverID) != null ? 'Driver' : 'Passenger';
|
||||
final phone = box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver);
|
||||
|
||||
// Fire-and-forget call to prevent infinite loops if the logger itself fails.
|
||||
CRUD().post(
|
||||
link: AppLink.addError,
|
||||
payload: {
|
||||
'error': error.toString(),
|
||||
'userId': userId.toString(),
|
||||
'userType': userType,
|
||||
'phone': phone.toString(),
|
||||
'device': where,
|
||||
'details': details,
|
||||
},
|
||||
);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
Future<dynamic> get({
|
||||
required String link,
|
||||
Map<String, dynamic>? payload,
|
||||
@@ -43,9 +91,9 @@ class CRUD {
|
||||
'Bearer ${X.r(X.r(X.r(box.read(BoxName.jwt), cn), cC), cs).toString().split(AppInformation.addd)[0]}'
|
||||
},
|
||||
);
|
||||
// print(response.request);
|
||||
// Log.print('response.body: ${response.body}');
|
||||
// print(payload);
|
||||
print(response.request);
|
||||
Log.print('response.body: ${response.body}');
|
||||
print(payload);
|
||||
if (response.statusCode == 200) {
|
||||
var jsonData = jsonDecode(response.body);
|
||||
if (jsonData['status'] == 'success') {
|
||||
@@ -94,9 +142,9 @@ class CRUD {
|
||||
'X-HMAC-Auth': hmac.toString(),
|
||||
},
|
||||
);
|
||||
// Log.print('response.request: ${response.request}');
|
||||
// Log.print('response.body: ${response.body}');
|
||||
// print(payload);
|
||||
Log.print('response.request: ${response.request}');
|
||||
Log.print('response.body: ${response.body}');
|
||||
print(payload);
|
||||
if (response.statusCode == 200) {
|
||||
var jsonData = jsonDecode(response.body);
|
||||
if (jsonData['status'] == 'success') {
|
||||
@@ -145,9 +193,9 @@ class CRUD {
|
||||
'X-HMAC-Auth': hmac.toString(),
|
||||
},
|
||||
);
|
||||
// Log.print('response.request:${response.request}');
|
||||
// Log.print('response.body: ${response.body}');
|
||||
// Log.print('payload:$payload');
|
||||
Log.print('response.request:${response.request}');
|
||||
Log.print('response.body: ${response.body}');
|
||||
Log.print('payload:$payload');
|
||||
if (response.statusCode == 200) {
|
||||
try {
|
||||
var jsonData = jsonDecode(response.body);
|
||||
@@ -203,9 +251,9 @@ class CRUD {
|
||||
// 'Authorization': 'Bearer ${box.read(BoxName.jwt)}'
|
||||
},
|
||||
);
|
||||
// print(response.request);
|
||||
// Log.print('response.body: ${response.body}');
|
||||
// print(payload);
|
||||
print(response.request);
|
||||
Log.print('response.body: ${response.body}');
|
||||
print(payload);
|
||||
if (response.statusCode == 200) {
|
||||
try {
|
||||
var jsonData = jsonDecode(response.body);
|
||||
|
||||
48
lib/controller/functions/network/connection_check.dart
Normal file
48
lib/controller/functions/network/connection_check.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'net_guard.dart';
|
||||
|
||||
typedef BodyEncoder = Future<http.Response> Function();
|
||||
|
||||
class HttpRetry {
|
||||
/// ريتراي لـ network/transient errors فقط.
|
||||
static Future<http.Response> sendWithRetry(
|
||||
BodyEncoder send, {
|
||||
int maxRetries = 3,
|
||||
Duration baseDelay = const Duration(milliseconds: 400),
|
||||
Duration timeout = const Duration(seconds: 12),
|
||||
}) async {
|
||||
// ✅ Pre-flight check for internet connection
|
||||
if (!await NetGuard().hasInternet()) {
|
||||
// Immediately throw a specific exception if there's no internet.
|
||||
// This avoids pointless retries.
|
||||
throw const SocketException("No internet connection");
|
||||
}
|
||||
int attempt = 0;
|
||||
while (true) {
|
||||
attempt++;
|
||||
try {
|
||||
final res = await send().timeout(timeout);
|
||||
return res;
|
||||
} on TimeoutException catch (_) {
|
||||
if (attempt >= maxRetries) rethrow;
|
||||
} on SocketException catch (_) {
|
||||
if (attempt >= maxRetries) rethrow;
|
||||
} on HandshakeException catch (_) {
|
||||
if (attempt >= maxRetries) rethrow;
|
||||
} on http.ClientException catch (e) {
|
||||
// مثال: Connection reset by peer
|
||||
final msg = e.message.toLowerCase();
|
||||
final transient = msg.contains('connection reset') ||
|
||||
msg.contains('broken pipe') ||
|
||||
msg.contains('timed out');
|
||||
if (!transient || attempt >= maxRetries) rethrow;
|
||||
}
|
||||
// backoff: 0.4s, 0.8s, 1.6s
|
||||
final delay = baseDelay * (1 << (attempt - 1));
|
||||
await Future.delayed(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
lib/controller/functions/network/net_guard.dart
Normal file
48
lib/controller/functions/network/net_guard.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:internet_connection_checker/internet_connection_checker.dart';
|
||||
|
||||
class NetGuard {
|
||||
static final NetGuard _i = NetGuard._();
|
||||
NetGuard._();
|
||||
factory NetGuard() => _i;
|
||||
|
||||
bool _notified = false;
|
||||
|
||||
/// فحص: (أ) فيه شبكة؟ (ب) فيه انترنت؟ (ج) السيرفر نفسه reachable؟
|
||||
Future<bool> hasInternet({Uri? mustReach}) async {
|
||||
final connectivity = await Connectivity().checkConnectivity();
|
||||
if (connectivity == ConnectivityResult.none) return false;
|
||||
|
||||
final hasNet =
|
||||
await InternetConnectionChecker.createInstance().hasConnection;
|
||||
if (!hasNet) return false;
|
||||
|
||||
if (mustReach != null) {
|
||||
try {
|
||||
final host = mustReach.host;
|
||||
final result = await InternetAddress.lookup(host);
|
||||
if (result.isEmpty || result.first.rawAddress.isEmpty) return false;
|
||||
|
||||
// اختباري خفيف عبر TCP (80/443) — 400ms timeout
|
||||
final port = mustReach.scheme == 'http' ? 80 : 443;
|
||||
final socket = await Socket.connect(host, port,
|
||||
timeout: const Duration(milliseconds: 400));
|
||||
socket.destroy();
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// إظهار إشعار مرة واحدة ثم إسكات التكرارات
|
||||
void notifyOnce(void Function(String title, String msg) show) {
|
||||
if (_notified) return;
|
||||
_notified = true;
|
||||
show('لا يوجد اتصال بالإنترنت', 'تحقق من الشبكة ثم حاول مجددًا.');
|
||||
// إعادة السماح بعد 15 ثانية
|
||||
Future.delayed(const Duration(seconds: 15), () => _notified = false);
|
||||
}
|
||||
}
|
||||
@@ -245,7 +245,7 @@ class HomeCaptainController extends GetxController {
|
||||
// isLoading = true;
|
||||
update();
|
||||
|
||||
var res = await CRUD().get(
|
||||
var res = await CRUD().getWallet(
|
||||
link: AppLink.getDriverPaymentPoints,
|
||||
payload: {'driverID': box.read(BoxName.driverID).toString()},
|
||||
);
|
||||
@@ -331,20 +331,6 @@ class HomeCaptainController extends GetxController {
|
||||
'fingerPrint': (fingerPrint).toString()
|
||||
});
|
||||
|
||||
// CRUD().post(
|
||||
// link: "${AppLink.seferAlexandriaServer}/ride/firebase/addDriver.php",
|
||||
// payload: {
|
||||
// 'token': box.read(BoxName.tokenDriver),
|
||||
// 'captain_id': box.read(BoxName.driverID).toString(),
|
||||
// 'fingerPrint': (fingerPrint).toString()
|
||||
// });
|
||||
// CRUD().post(
|
||||
// link: "${AppLink.seferGizaServer}/ride/firebase/addDriver.php",
|
||||
// payload: {
|
||||
// 'token': box.read(BoxName.tokenDriver),
|
||||
// 'captain_id': box.read(BoxName.driverID).toString(),
|
||||
// 'fingerPrint': (fingerPrint).toString()
|
||||
// });
|
||||
await CRUD().postWallet(
|
||||
link: "${AppLink.seferPaymentServer}/ride/firebase/addDriver.php",
|
||||
payload: {
|
||||
@@ -357,7 +343,7 @@ class HomeCaptainController extends GetxController {
|
||||
}
|
||||
|
||||
getPaymentToday() async {
|
||||
var res = await CRUD().get(
|
||||
var res = await CRUD().getWallet(
|
||||
link: AppLink.getDriverPaymentToday,
|
||||
payload: {'driverID': box.read(BoxName.driverID).toString()});
|
||||
if (res != 'failure') {
|
||||
@@ -420,7 +406,7 @@ class HomeCaptainController extends GetxController {
|
||||
}
|
||||
|
||||
getAllPayment() async {
|
||||
var res = await CRUD().get(
|
||||
var res = await CRUD().getWallet(
|
||||
link: AppLink.getAllPaymentFromRide,
|
||||
payload: {'driverID': box.read(BoxName.driverID).toString()});
|
||||
data = jsonDecode(res);
|
||||
|
||||
@@ -572,7 +572,64 @@ Raih Gai: For same-day return trips longer than 50km.
|
||||
"car_plate": "لوحة السيارة",
|
||||
"car_model": "طراز السيارة:",
|
||||
"education": "التعليم",
|
||||
"gender": "الجنس",
|
||||
"gender": "الجنس", "Driver Wallet": "محفظة السائق",
|
||||
"Fetching Wallet Data...": "جاري جلب بيانات المحفظة...",
|
||||
"Charge your Account": "اشحن حسابك",
|
||||
"Total Points": "إجمالي النقاط",
|
||||
"Info": "معلومات",
|
||||
"The 300 points equal 300 L.E for you \nSo go and gain your money":
|
||||
"٣٠٠ نقطة تساوي ٣٠٠ جنيه لك\nاذهب واحصل على أموالك",
|
||||
"OK": "حسناً",
|
||||
"Total Budget from trips is": "إجمالي الميزانية من الرحلات هو",
|
||||
"Total Amount:": "المبلغ الإجمالي:",
|
||||
"L.E": "جنيه",
|
||||
"This amount for all trip I get from Passengers":
|
||||
"هذا المبلغ هو مجموع كل الرحلات التي حصلت عليها من الركاب",
|
||||
"Total Budget from trips by\nCredit card is ":
|
||||
"إجمالي الميزانية من الرحلات عبر\nالبطاقة الائتمانية هو",
|
||||
"This amount for all trip I get from Passengers and Collected For me in":
|
||||
"هذا المبلغ هو مجموع الرحلات من الركاب وتم جمعه لي في",
|
||||
"Wallet": "المحفظة",
|
||||
"You can buy points from your budget":
|
||||
"يمكنك شراء النقاط من ميزانيتك",
|
||||
"Transfer budget": "تحويل الميزانية",
|
||||
"Daily Promos": "العروض اليومية",
|
||||
"Morning Promo": "عرض الصباح",
|
||||
"this is count of your all trips in the morning promo today from 7:00am-10:00am":
|
||||
"هذا عدد رحلاتك في عرض الصباح اليوم من 7 صباحاً إلى 10 صباحاً",
|
||||
"Afternoon Promo": "عرض بعد الظهر",
|
||||
"this is count of your all trips in the Afternoon promo today from 3:00pm-6:00 pm":
|
||||
"هذا عدد رحلاتك في عرض بعد الظهر اليوم من 3 مساءً إلى 6 مساءً",
|
||||
"You can purchase a budget to enable online access through the options listed below.":
|
||||
"يمكنك شراء ميزانية لتفعيل الوصول عبر الإنترنت من خلال الخيارات أدناه.",
|
||||
"Payment History": "سجل المدفوعات",
|
||||
"Weekly Budget": "الميزانية الأسبوعية",
|
||||
"Pay from my budget": "الدفع من ميزانيتي",
|
||||
"You have in account": "لديك في الحساب",
|
||||
"Confirm & Pay": "تأكيد ودفع",
|
||||
"Use Touch ID or Face ID to confirm payment":
|
||||
"استخدم البصمة أو بصمة الوجه لتأكيد الدفع",
|
||||
"Your Budget less than needed": "ميزانيتك أقل من المطلوب",
|
||||
'Weekly Payments': 'المدفوعات الأسبوعية',
|
||||
"Fetching Weekly Data...": "جاري جلب البيانات الأسبوعية...",
|
||||
'Transaction Details': 'تفاصيل المعاملة',
|
||||
'Total Weekly Earnings': 'إجمالي الأرباح الأسبوعية',
|
||||
'No Transactions Yet': 'لا توجد معاملات حتى الآن',
|
||||
'Your weekly payment history will appear here.':
|
||||
'سيظهر سجل مدفوعاتك الأسبوعي هنا.',
|
||||
"Loading History...": "جاري تحميل السجل...",
|
||||
'Credit': 'دفع',
|
||||
'Debit': 'خصم',
|
||||
"Use Touch ID or Face ID to confirm transfer":
|
||||
"استخدم البصمة أو بصمة الوجه لتأكيد التحويل",
|
||||
"You don't have enough money in your Tripz wallet":
|
||||
"لا تملك رصيداً كافياً في محفظة Tripz الخاصة بك",
|
||||
"Insert Account Bank": "إدخال حساب البنك",
|
||||
"Insert Card Bank Details to Receive Your Visa Money Weekly":
|
||||
"أدخل تفاصيل بطاقة البنك لاستلام أموالك عبر الفيزا أسبوعياً",
|
||||
"Insert card number": "أدخل رقم البطاقة",
|
||||
"Ok": "موافق",
|
||||
"bank account added succesfly": "تمت إضافة الحساب البنكي بنجاح",
|
||||
"birthdate": "تاريخ ميلاد",
|
||||
"Approve Driver Documents": "الموافقة على مستندات الشريك السائق",
|
||||
"Total Budget is": "الميزانية الإجمالية",
|
||||
|
||||
Reference in New Issue
Block a user