Update: 2026-06-12 22:40:40
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:siro_rider/constant/box_name.dart';
|
||||
import 'package:siro_rider/constant/country_polygons.dart';
|
||||
import 'package:siro_rider/main.dart';
|
||||
import '../../print.dart';
|
||||
|
||||
class CountryLogic {
|
||||
/// Formats the phone number based on the country's dialing rules.
|
||||
@@ -88,7 +92,77 @@ class CountryLogic {
|
||||
return formatPhone(cleanPhone, 'Jordan');
|
||||
}
|
||||
|
||||
final country = box.read(BoxName.countryCode) ?? 'Syria';
|
||||
final country = box.read(BoxName.countryCode) ?? 'Jordan';
|
||||
return formatPhone(cleanPhone, country);
|
||||
}
|
||||
|
||||
/// التحقق مما إذا كانت نقطة داخل مضلع (Ray Casting Algorithm)
|
||||
static bool _isPointInPolygon(LatLng point, List<LatLng> polygon) {
|
||||
int intersections = 0;
|
||||
for (int i = 0; i < polygon.length; i++) {
|
||||
final v1 = polygon[i];
|
||||
final v2 = polygon[(i + 1) % polygon.length];
|
||||
if ((v1.latitude <= point.latitude && v2.latitude > point.latitude) ||
|
||||
(v2.latitude <= point.latitude && v1.latitude > point.latitude)) {
|
||||
final t = (point.latitude - v1.latitude) / (v2.latitude - v1.latitude);
|
||||
if (point.longitude <
|
||||
v1.longitude + t * (v2.longitude - v1.longitude)) {
|
||||
intersections++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return intersections % 2 != 0;
|
||||
}
|
||||
|
||||
/// كشف الدولة تلقائياً عبر الموقع الجغرافي باستخدام مضلعات CountryPolygons
|
||||
static Future<String?> detectByLocation() async {
|
||||
try {
|
||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!serviceEnabled) return null;
|
||||
|
||||
LocationPermission permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.denied) return null;
|
||||
}
|
||||
if (permission == LocationPermission.deniedForever) return null;
|
||||
|
||||
final pos = await Geolocator.getCurrentPosition(
|
||||
desiredAccuracy: LocationAccuracy.low,
|
||||
timeLimit: const Duration(seconds: 8),
|
||||
);
|
||||
final point = LatLng(pos.latitude, pos.longitude);
|
||||
|
||||
if (_isPointInPolygon(point, CountryPolygons.jordanBoundary)) {
|
||||
return 'Jordan';
|
||||
}
|
||||
if (_isPointInPolygon(point, CountryPolygons.syriaBoundary)) {
|
||||
return 'Syria';
|
||||
}
|
||||
if (_isPointInPolygon(point, CountryPolygons.egyptBoundary)) {
|
||||
return 'Egypt';
|
||||
}
|
||||
} catch (e) {
|
||||
Log.print('[CountryLogic] detectByLocation error: $e');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// تهيئة الدولة عند بدء التطبيق
|
||||
static Future<void> initializeCountry() async {
|
||||
final existing = box.read(BoxName.countryCode);
|
||||
if (existing != null && existing.toString().isNotEmpty) {
|
||||
Log.print('[CountryLogic] الدولة موجودة مسبقاً: $existing');
|
||||
return;
|
||||
}
|
||||
Log.print('[CountryLogic] كشف الدولة عبر الموقع...');
|
||||
final country = await detectByLocation();
|
||||
if (country != null) {
|
||||
box.write(BoxName.countryCode, country);
|
||||
Log.print('[CountryLogic] تم الكشف: $country');
|
||||
} else {
|
||||
box.write(BoxName.countryCode, 'Jordan');
|
||||
Log.print('[CountryLogic] افتراضي: Jordan');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,14 +75,39 @@ class CRUD {
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// دالة مساعدة خاصة: يجيب البصمة المشفرة من GetStorage
|
||||
// هي نفس القيمة المرسلة في login وعُملها hash في JWT payload
|
||||
// السيرفر يعمل: sha256(X-Device-FP + FP_PEPPER) == JWT.fingerPrint
|
||||
// دالة مساعدة خاصة: تجيب البصمة المشفرة من GetStorage
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
String _getFpHeader() {
|
||||
return box.read(BoxName.deviceFpEncrypted)?.toString() ?? '';
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// دالة مساعدة خاصة: تقرأ JWT من FlutterSecureStorage (آمن)
|
||||
// بدلاً من GetStorage (غير مشفر)
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
Future<String> _getJwt() async {
|
||||
try {
|
||||
final String? encryptedJwt = await storage.read(key: BoxName.jwt);
|
||||
if (encryptedJwt == null || encryptedJwt.isEmpty) {
|
||||
// Fallback إلى GetStorage للتوافقية
|
||||
final String? fallback = box.read(BoxName.jwt);
|
||||
if (fallback != null) {
|
||||
return r(fallback).toString().split(Env.addd)[0];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
return r(encryptedJwt).toString().split(Env.addd)[0];
|
||||
} catch (e) {
|
||||
Log.print('Error reading JWT from SecureStorage: $e');
|
||||
// Fallback
|
||||
final String? fallback = box.read(BoxName.jwt);
|
||||
if (fallback != null) {
|
||||
return r(fallback).toString().split(Env.addd)[0];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/// Centralized private method to handle all API requests.
|
||||
/// Includes retry logic, network checking, and standardized error handling.
|
||||
Future<dynamic> _makeRequest({
|
||||
@@ -169,7 +194,7 @@ class CRUD {
|
||||
required String link,
|
||||
Map<String, dynamic>? payload,
|
||||
}) async {
|
||||
String token = r(box.read(BoxName.jwt)).toString().split(Env.addd)[0];
|
||||
final token = await _getJwt();
|
||||
|
||||
final headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
@@ -193,14 +218,14 @@ class CRUD {
|
||||
required String link,
|
||||
Map<String, dynamic>? payload,
|
||||
}) async {
|
||||
final token = await _getJwt();
|
||||
var url = Uri.parse(link);
|
||||
var response = 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]}',
|
||||
'Authorization': 'Bearer $token',
|
||||
'X-Device-FP': _getFpHeader(), // ← إثبات الجهاز
|
||||
},
|
||||
);
|
||||
@@ -548,7 +573,6 @@ class CRUD {
|
||||
return response.statusCode;
|
||||
}
|
||||
|
||||
|
||||
Future<dynamic> postPayMob({
|
||||
required String link,
|
||||
Map<String, dynamic>? payload,
|
||||
|
||||
@@ -4,12 +4,9 @@ import 'package:siro_rider/constant/box_name.dart';
|
||||
import 'package:siro_rider/constant/info.dart';
|
||||
import 'package:siro_rider/controller/auth/login_controller.dart';
|
||||
import 'package:jwt_decoder/jwt_decoder.dart';
|
||||
import 'package:secure_string_operations/secure_string_operations.dart';
|
||||
|
||||
import '../../constant/char_map.dart';
|
||||
import '../../constant/links.dart';
|
||||
import '../../main.dart';
|
||||
import '../../print.dart';
|
||||
import 'crud.dart';
|
||||
import 'encrypt_decrypt.dart';
|
||||
|
||||
@@ -24,23 +21,25 @@ class SecureStorage {
|
||||
}
|
||||
}
|
||||
|
||||
const List<String> keysToFetch = [
|
||||
'serverPHP',
|
||||
// 'seferAlexandriaServer',
|
||||
// 'seferPaymentServer',
|
||||
// 'seferCairoServer',
|
||||
// 'seferGizaServer',
|
||||
];
|
||||
|
||||
class AppInitializer {
|
||||
List<Map<String, dynamic>> links = [];
|
||||
|
||||
/// تقرأ JWT من FlutterSecureStorage أولاً، مع fallback إلى GetStorage
|
||||
Future<String?> _readJwt() async {
|
||||
try {
|
||||
final secureJwt = await storage.read(key: 'jwt');
|
||||
if (secureJwt != null && secureJwt.isNotEmpty) return secureJwt;
|
||||
} catch (_) {}
|
||||
return box.read(BoxName.jwt);
|
||||
}
|
||||
|
||||
Future<void> initializeApp() async {
|
||||
if (box.read(BoxName.jwt) == null) {
|
||||
final jwt = await _readJwt();
|
||||
if (jwt == null) {
|
||||
await LoginController().getJWT();
|
||||
} else {
|
||||
bool isTokenExpired = JwtDecoder.isExpired(
|
||||
r(box.read(BoxName.jwt)).toString().split(AppInformation.addd)[0]);
|
||||
bool isTokenExpired =
|
||||
JwtDecoder.isExpired(r(jwt).toString().split(AppInformation.addd)[0]);
|
||||
|
||||
if (isTokenExpired) {
|
||||
await LoginController().getJWT();
|
||||
|
||||
Reference in New Issue
Block a user