Initial push to my private server

This commit is contained in:
Hamza-Ayed
2025-09-21 15:02:12 +03:00
parent 7e904ae460
commit f08ee61a7e
32 changed files with 1622 additions and 373 deletions

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:math';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
@@ -10,6 +11,7 @@ import 'package:sefer_driver/constant/colors.dart';
// استخدام نفس مسارات الاستيراد التي قدمتها
import '../../../constant/api_key.dart';
import '../../../constant/links.dart';
import '../../../print.dart';
import '../../functions/crud.dart';
import '../../functions/tts.dart';
@@ -525,45 +527,127 @@ class NavigationController extends GetxController {
String _parseInstruction(String html) =>
html.replaceAll(RegExp(r'<[^>]*>'), ' ');
double _haversineKm(double lat1, double lon1, double lat2, double lon2) {
const R = 6371.0; // km
final dLat = (lat2 - lat1) * math.pi / 180.0;
final dLon = (lon2 - lon1) * math.pi / 180.0;
final a = math.sin(dLat / 2) * math.sin(dLat / 2) +
math.cos(lat1 * math.pi / 180.0) *
math.cos(lat2 * math.pi / 180.0) *
math.sin(dLon / 2) *
math.sin(dLon / 2);
final c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
return R * c;
}
/// تحويل نصف قطر بالكيلومتر إلى دلتا درجات عرض
double _kmToLatDelta(double km) => km / 111.0;
/// تحويل نصف قطر بالكيلومتر إلى دلتا درجات طول (تعتمد على خط العرض)
double _kmToLngDelta(double km, double atLat) =>
km / (111.320 * math.cos(atLat * math.pi / 180.0)).abs().clamp(1e-6, 1e9);
/// حساب درجة التطابق النصي (كل كلمة تبدأ بها الاسم = 2 نقاط، يحتويها = 1 نقطة)
double _relevanceScore(String name, String query) {
final n = name.toLowerCase();
final parts =
query.toLowerCase().split(RegExp(r'\s+')).where((p) => p.length >= 2);
double s = 0.0;
for (final p in parts) {
if (n.startsWith(p)) {
s += 2.0;
} else if (n.contains(p)) {
s += 1.0;
}
}
return s;
}
Future<void> getPlaces() async {
if (placeDestinationController.text.trim().isEmpty) {
final q = placeDestinationController.text.trim();
if (q.isEmpty) {
placesDestination = [];
update();
return;
}
if (myLocation == null) {
Get.snackbar('انتظر', 'جاري تحديد موقعك الحالي...');
return;
}
final query = placeDestinationController.text.trim();
final lat = myLocation!.latitude;
final lng = myLocation!.longitude;
const double range = 2.2;
final lat_min = lat - range,
lat_max = lat + range,
lng_min = lng - range,
lng_max = lng + range;
// نصف قطر البحث بالكيلومتر (عدّل حسب رغبتك)
const radiusKm = 200.0;
// حساب الباوند الصحيح (درجات، وليس 2.2 درجة ثابتة)
final latDelta = _kmToLatDelta(radiusKm);
final lngDelta = _kmToLngDelta(radiusKm, lat);
final latMin = lat - latDelta;
final latMax = lat + latDelta;
final lngMin = lng - lngDelta;
final lngMax = lng + lngDelta;
try {
final response = await CRUD().post(
link: AppLink.getPlacesSyria,
payload: {
'query': query,
'lat_min': lat_min.toString(),
'lat_max': lat_max.toString(),
'lng_min': lng_min.toString(),
'lng_max': lng_max.toString(),
'query': q,
'lat_min': latMin.toString(),
'lat_max': latMax.toString(),
'lng_min': lngMin.toString(),
'lng_max': lngMax.toString(),
},
);
if (response != 'failure') {
placesDestination = response['message'] ?? [];
// يدعم شكلي استجابة: إما {"...","message":[...]} أو قائمة مباشرة [...]
List list;
if (response is Map && response['message'] is List) {
list = List.from(response['message'] as List);
} else if (response is List) {
list = List.from(response);
} else {
placesDestination = [];
print('Unexpected response shape');
return;
}
// جهّز الحقول المحتملة للأسماء
String _bestName(Map p) {
return (p['name'] ?? p['name_ar'] ?? p['name_en'] ?? '').toString();
}
// احسب المسافة ودرجة التطابق والنقاط
for (final p in list) {
final plat = double.tryParse(p['latitude']?.toString() ?? '') ?? 0.0;
final plng = double.tryParse(p['longitude']?.toString() ?? '') ?? 0.0;
final d = _haversineKm(lat, lng, plat, plng);
final rel = _relevanceScore(_bestName(p), q);
// معادلة ترتيب ذكية: مسافة أقل + تطابق أعلى = نقاط أعلى
// تضيف +1 لضمان عدم وصول الوزن للصفر عند عدم وجود تطابق
final score = (1.0 / (1.0 + d)) * (1.0 + rel);
p['distanceKm'] = d;
p['relevance'] = rel;
p['score'] = score;
}
// رتّب حسب score تنازليًا، ثم المسافة تصاعديًا كحسم
list.sort((a, b) {
final sa = (a['score'] ?? 0.0) as double;
final sb = (b['score'] ?? 0.0) as double;
final cmp = sb.compareTo(sa);
if (cmp != 0) return cmp;
final da = (a['distanceKm'] ?? 1e9) as double;
final db = (b['distanceKm'] ?? 1e9) as double;
return da.compareTo(db);
});
// خذ أول 1015 للعرض (اختياري)، أو اعرض الكل
placesDestination = list.take(15).toList();
Log.print('placesDestination: $placesDestination');
update();
} catch (e) {
print('Exception in getPlaces: $e');
} finally {
update();
}
}