feat: add device authentication, place gates support, and PiP navigation features

This commit is contained in:
Hamza-Ayed
2026-09-19 12:34:26 +03:00
parent 55830beee8
commit ce896df30a
86 changed files with 3414 additions and 341 deletions
@@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:intaleq_maps/intaleq_maps.dart';
import '../../core/constants/api_constants.dart';
import '../../core/services/device_fingerprint_service.dart';
import '../../core/utils/polyline_decoder.dart';
import '../../core/utils/arabic_search_normalizer.dart';
import '../../core/services/location_service.dart';
@@ -15,6 +16,12 @@ class MapSaasRepository {
MapSaasRepository({http.Client? client}) : client = client ?? http.Client();
Map<String, String> get _baseHeaders => {
'Content-Type': 'application/json',
'x-api-key': DeviceFingerprintService.instance.activeApiKey,
...DeviceFingerprintService.instance.headers,
};
/// Fetch primary and alternative routes from MapSaaS
Future<List<RouteData>> getRoute({
required LatLng origin,
@@ -43,7 +50,7 @@ class MapSaasRepository {
try {
final response = await client.get(
saasUri,
headers: {'x-api-key': ApiConstants.mapSaasKey},
headers: _baseHeaders,
);
print("📥 [MapSaasRepo] Route response HTTP status: ${response.statusCode} (${response.body.length} bytes)");
@@ -165,7 +172,7 @@ class MapSaasRepository {
final uri = Uri.parse(ApiConstants.mapSaasSearch).replace(queryParameters: queryParams);
final response = await client.get(
uri,
headers: {'x-api-key': ApiConstants.mapSaasKey},
headers: _baseHeaders,
);
if (response.statusCode == 200) {
@@ -232,14 +239,12 @@ class MapSaasRepository {
return distM <= ApiConstants.maxSearchRadiusMeters;
}).toList();
// 4. Smart Ranking: exact text match priority + proximity ascending
final bool categorySearch = ArabicSearchNormalizer.isCategoryQuery(query);
// 4. Smart Ranking:
// - For category searches (e.g. مطعم, مخبز, دكان, مسجد, سوبرماركت), PROXIMITY dominates (closest first).
// - For landmark/name searches (e.g. المدينة الطبية, سيتي مول), exact name match takes precedence, then proximity.
filteredPlaces.sort((a, b) {
final matchA = ArabicSearchNormalizer.matches(a.name, normalizedQuery);
final matchB = ArabicSearchNormalizer.matches(b.name, normalizedQuery);
if (matchA && !matchB) return -1;
if (!matchA && matchB) return 1;
final distA = LocationService.instance.calculateDistance(
center,
LatLng(a.latitude, a.longitude),
@@ -248,6 +253,17 @@ class MapSaasRepository {
center,
LatLng(b.latitude, b.longitude),
);
if (categorySearch) {
return distA.compareTo(distB);
}
final matchA = ArabicSearchNormalizer.matches(a.name, normalizedQuery);
final matchB = ArabicSearchNormalizer.matches(b.name, normalizedQuery);
if (matchA && !matchB) return -1;
if (!matchA && matchB) return 1;
return distA.compareTo(distB);
});
@@ -267,7 +283,7 @@ class MapSaasRepository {
final response = await client.post(
uri,
headers: {
'x-api-key': ApiConstants.mapSaasKey,
..._baseHeaders,
'Content-Type': 'application/json',
},
body: jsonEncode({
@@ -308,15 +324,15 @@ class MapSaasRepository {
'driver_id': driverId,
'latitude': latitude,
'longitude': longitude,
'speed': speed,
'heading': heading,
'speed': speed < 0 ? 0.0 : speed,
'heading': heading < 0 ? 0.0 : heading,
'distance': distance,
'elevation': elevation,
};
final response = await client.post(
uri,
headers: {
'x-api-key': ApiConstants.mapSaasKey,
..._baseHeaders,
'Content-Type': 'application/json',
},
body: jsonEncode(payload),