new change to use intaleq_map sdk 04-16-4
This commit is contained in:
@@ -107,4 +107,5 @@ class BoxName {
|
||||
static const String recentLocations = 'recentLocations';
|
||||
static const String tripData = 'tripData';
|
||||
static const String parentTripSelected = 'parentTripSelected';
|
||||
static const String styleVersion = 'styleVersion';
|
||||
}
|
||||
|
||||
@@ -91,17 +91,47 @@ class CountryPolygons {
|
||||
];
|
||||
|
||||
// دالة تُرجع رابط API بناءً على اسم الدولة
|
||||
static String getRoutingApiUrl(String countryName) {
|
||||
switch (countryName) {
|
||||
case 'Jordan':
|
||||
return 'https://routec.intaleq.xyz/route-jo';
|
||||
case 'Syria':
|
||||
return 'https://routec.intaleq.xyz/route';
|
||||
case 'Egypt':
|
||||
return 'https://routec.intaleq.xyz/route-eg';
|
||||
default:
|
||||
// الافتراضي في حالة لم يقع الموقع ضمن أي من المضلعات
|
||||
return 'https://routec.intaleq.xyz/route';
|
||||
// static String getRoutingApiUrl(String countryName) {
|
||||
// switch (countryName) {
|
||||
// case 'Jordan':
|
||||
// return 'https://routec.intaleq.xyz/route-jo';
|
||||
// case 'Syria':
|
||||
// return 'https://routec.intaleq.xyz/route';
|
||||
// case 'Egypt':
|
||||
// return 'https://routec.intaleq.xyz/route-eg';
|
||||
// default:
|
||||
// // الافتراضي في حالة لم يقع الموقع ضمن أي من المضلعات
|
||||
// return 'https://routec.intaleq.xyz/route';
|
||||
// }
|
||||
// }
|
||||
|
||||
/// دالة تحدد اسم الدولة (باللغة الإنجليزية للـ API) بناءً على الإحداثيات
|
||||
static String getCountryName(LatLng? point) {
|
||||
if (point == null) return "jordan";
|
||||
|
||||
if (_isPointInPolygon(point, jordanBoundary)) return "jordan";
|
||||
if (_isPointInPolygon(point, syriaBoundary)) return "syria";
|
||||
if (_isPointInPolygon(point, egyptBoundary)) return "egypt";
|
||||
|
||||
return "jordan"; // الافتراضي
|
||||
}
|
||||
|
||||
/// خوارزمية Ray Casting للتحقق من وقوع نقطة داخل مضلع
|
||||
static bool _isPointInPolygon(LatLng p, List<LatLng> polygon) {
|
||||
bool isInside = false;
|
||||
int j = polygon.length - 1;
|
||||
for (int i = 0; i < polygon.length; i++) {
|
||||
if (((polygon[i].latitude > p.latitude) !=
|
||||
(polygon[j].latitude > p.latitude)) &&
|
||||
(p.longitude <
|
||||
(polygon[j].longitude - polygon[i].longitude) *
|
||||
(p.latitude - polygon[i].latitude) /
|
||||
(polygon[j].latitude - polygon[i].latitude) +
|
||||
polygon[i].longitude)) {
|
||||
isInside = !isInside;
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
return isInside;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,6 +663,8 @@ class CRUD {
|
||||
'x-api-key': Env.mapSaasKey,
|
||||
},
|
||||
);
|
||||
Log.print('link -MapSaas: $link');
|
||||
Log.print('response -MapSaas: ${response.body}');
|
||||
if (response.statusCode == 200) {
|
||||
return jsonDecode(response.body);
|
||||
}
|
||||
|
||||
@@ -32,12 +32,14 @@ import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
// import 'package:google_polyline_algorithm/google_polyline_algorithm.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:location/location.dart';
|
||||
import 'package:Intaleq/constant/colors.dart';
|
||||
import 'package:Intaleq/constant/country_polygons.dart';
|
||||
import 'package:Intaleq/constant/links.dart';
|
||||
import 'package:Intaleq/constant/style.dart';
|
||||
import 'package:Intaleq/controller/home/points_for_rider_controller.dart';
|
||||
import 'package:Intaleq/views/home/map_widget.dart/form_serch_multiy_point.dart';
|
||||
import '../../constant/api_key.dart';
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/country_polygons.dart';
|
||||
import '../../constant/info.dart';
|
||||
import '../../constant/links.dart';
|
||||
@@ -3276,7 +3278,9 @@ class MapPassengerController extends GetxController {
|
||||
"step3": placesCoordinate.length > 3 ? placesCoordinate[3] : "",
|
||||
"step4": placesCoordinate.length > 4 ? placesCoordinate[4] : "",
|
||||
};
|
||||
Log.print('payload add_ride: $payload');
|
||||
Log.print(
|
||||
'🏁 Ride Registration Detail: $startNameAddress -> $endNameAddress');
|
||||
Log.print(' 📦 Payload: $payload');
|
||||
|
||||
try {
|
||||
// الاتصال بـ add_ride.php
|
||||
@@ -4859,7 +4863,7 @@ Intaleq Team''';
|
||||
}
|
||||
|
||||
// 4. التخلص من متحكم الخريطة (ممارسة جيدة)
|
||||
mapController?.dispose();
|
||||
mapController = null;
|
||||
|
||||
Log.print("--- Cleanup complete. ---");
|
||||
super.onClose();
|
||||
@@ -5307,27 +5311,44 @@ Intaleq Team''';
|
||||
|
||||
final lat = passengerLocation.latitude;
|
||||
final lng = passengerLocation.longitude;
|
||||
final country = CountryPolygons.getCountryName(passengerLocation);
|
||||
|
||||
try {
|
||||
final url =
|
||||
'${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=45000&country=syria';
|
||||
'${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country';
|
||||
final response = await CRUD().getMapSaas(link: url);
|
||||
|
||||
if (response != null && response['results'] is List) {
|
||||
List list = List.from(response['results']);
|
||||
List results = List.from(response['results']);
|
||||
final List filteredResults = [];
|
||||
final Set<String> seenPlaces = {};
|
||||
|
||||
for (final p in list) {
|
||||
// Normalize fields to match expected format in components
|
||||
p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0;
|
||||
// Ensure latitude/longitude are strings if UI expects them that way,
|
||||
// though modern code usually prefers doubles.
|
||||
// The old code used double.tryParse(p['latitude']?.toString() ?? '0.0')
|
||||
p['latitude'] = p['latitude'].toString();
|
||||
p['longitude'] = p['longitude'].toString();
|
||||
for (final p in results) {
|
||||
final name = p['name_ar'] ?? p['name'] ?? '';
|
||||
final district = p['district'] ?? '';
|
||||
final plat = p['latitude']?.toString() ?? '0';
|
||||
final plng = p['longitude']?.toString() ?? '0';
|
||||
|
||||
final dedupeKey =
|
||||
"${name.trim().toLowerCase()}_${district.trim().toLowerCase()}";
|
||||
|
||||
if (!seenPlaces.contains(dedupeKey)) {
|
||||
seenPlaces.add(dedupeKey);
|
||||
|
||||
p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0;
|
||||
p['latitude'] = plat;
|
||||
p['longitude'] = plng;
|
||||
p['name'] = name;
|
||||
p['address'] = p['full_address'] ??
|
||||
(district.isNotEmpty
|
||||
? "$district، ${p['governorate'] ?? ''}"
|
||||
: (p['governorate'] ?? ''));
|
||||
|
||||
filteredResults.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
placesDestination = list;
|
||||
Log.print('Updated places: $placesDestination');
|
||||
placesDestination = filteredResults;
|
||||
update();
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -5533,23 +5554,26 @@ Intaleq Team''';
|
||||
|
||||
final lat = passengerLocation.latitude;
|
||||
final lng = passengerLocation.longitude;
|
||||
final country = CountryPolygons.getCountryName(passengerLocation);
|
||||
|
||||
try {
|
||||
final url =
|
||||
'${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=200000&country=syria';
|
||||
'${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country';
|
||||
final response = await CRUD().getMapSaas(link: url);
|
||||
|
||||
if (response != null && response['results'] is List) {
|
||||
List list = List.from(response['results']);
|
||||
|
||||
for (final p in list) {
|
||||
p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0;
|
||||
p['latitude'] = p['latitude'].toString();
|
||||
p['longitude'] = p['longitude'].toString();
|
||||
p['name'] = p['name_ar'] ?? p['name'] ?? '';
|
||||
p['address'] = p['full_address'] ??
|
||||
(p['district'] != null
|
||||
? "${p['district']}، ${p['governorate'] ?? ''}"
|
||||
: (p['governorate'] ?? ''));
|
||||
}
|
||||
|
||||
placesStart = list;
|
||||
Log.print('Updated places start: $placesStart');
|
||||
update();
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -5557,34 +5581,37 @@ Intaleq Team''';
|
||||
}
|
||||
}
|
||||
|
||||
Future getPlacesListsWayPoint(int index) async {
|
||||
var languageCode = wayPoint0Controller.text;
|
||||
Future<void> getPlacesListsWayPoint(int index) async {
|
||||
final q = wayPoint0Controller.text.trim();
|
||||
if (q.length < 3) return;
|
||||
|
||||
// Regular expression to check for English alphabet characters
|
||||
final englishRegex = RegExp(r'[a-zA-Z]');
|
||||
|
||||
// Check if text contains English characters
|
||||
if (englishRegex.hasMatch(languageCode)) {
|
||||
languageCode = 'en';
|
||||
} else {
|
||||
languageCode = 'ar';
|
||||
}
|
||||
|
||||
var url =
|
||||
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${wayPoint0Controller.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=250000&language=$languageCode&key=${AK.mapAPIKEY.toString()}';
|
||||
final lat = passengerLocation.latitude;
|
||||
final lng = passengerLocation.longitude;
|
||||
final country = CountryPolygons.getCountryName(passengerLocation);
|
||||
|
||||
try {
|
||||
var response = await CRUD().getGoogleApi(link: url, payload: {});
|
||||
final url =
|
||||
'${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country';
|
||||
final response = await CRUD().getMapSaas(link: url);
|
||||
|
||||
if (response != null && response['results'] != null) {
|
||||
wayPoint0 = response['results'];
|
||||
placeListResponseAll[index] = response['results'];
|
||||
if (response != null && response['results'] is List) {
|
||||
List list = List.from(response['results']);
|
||||
for (final p in list) {
|
||||
p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0;
|
||||
p['latitude'] = p['latitude'].toString();
|
||||
p['longitude'] = p['longitude'].toString();
|
||||
p['name'] = p['name_ar'] ?? p['name'] ?? '';
|
||||
p['address'] = p['full_address'] ??
|
||||
(p['district'] != null
|
||||
? "${p['district']}، ${p['governorate'] ?? ''}"
|
||||
: (p['governorate'] ?? ''));
|
||||
}
|
||||
wayPoint0 = list;
|
||||
placeListResponseAll[index] = list;
|
||||
update();
|
||||
} else {
|
||||
Log.print('Error: Invalid response from Google Places API');
|
||||
}
|
||||
} catch (e) {
|
||||
Log.print('Error fetching places: $e');
|
||||
Log.print('Error fetching places in WayPoint: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6292,7 +6319,7 @@ Intaleq Team''';
|
||||
}
|
||||
|
||||
bool isDrawingRoute = false;
|
||||
showDrawingBottomSheet() {
|
||||
void showDrawingBottomSheet() {
|
||||
final bool isDark = Get.isDarkMode;
|
||||
final Color bgColor = isDark
|
||||
? Colors.black.withOpacity(0.65)
|
||||
@@ -6300,6 +6327,9 @@ Intaleq Team''';
|
||||
final Color textColor = isDark ? Colors.white : Colors.grey.shade800;
|
||||
final Color subtitleColor = isDark ? Colors.white70 : Colors.grey.shade600;
|
||||
|
||||
// Prevent showing multiple bottom sheets if one is already active
|
||||
if (Get.isBottomSheetOpen == true) return;
|
||||
|
||||
Get.bottomSheet(
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
@@ -6324,16 +6354,34 @@ Intaleq Team''';
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Minimal handle
|
||||
Container(
|
||||
width: 40,
|
||||
height: 4,
|
||||
margin: const EdgeInsets.only(bottom: 24),
|
||||
decoration: BoxDecoration(
|
||||
color: isDark ? Colors.white24 : Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
// Minimal handle and Close button Row
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const SizedBox(width: 48), // Balance for the close button
|
||||
Container(
|
||||
width: 40,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: isDark ? Colors.white24 : Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
icon: Icon(Icons.close,
|
||||
color: textColor.withOpacity(0.5), size: 22),
|
||||
onPressed: () {
|
||||
// Force back to close the overlay regardless of GetX state check
|
||||
Get.back();
|
||||
isDrawingRoute = false;
|
||||
isLoading = false;
|
||||
update();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
@@ -6538,26 +6586,10 @@ Intaleq Team''';
|
||||
String pointsString;
|
||||
dynamic routeData;
|
||||
|
||||
if (isSaaSRequest) {
|
||||
// SaaS parsing
|
||||
apiDistanceMeters = (responseData['distance'] as num).toDouble();
|
||||
pointsString = responseData['points'] ?? "";
|
||||
routeData = responseData; // For box storage
|
||||
} else {
|
||||
// OSRM parsing
|
||||
if (responseData['routes'] == null || responseData['routes'].isEmpty) {
|
||||
if (attemptCount < 2) {
|
||||
await _retryProcess(origin, destination, waypoints, attemptCount);
|
||||
return;
|
||||
}
|
||||
_handleFatalError("Route Not Found".tr,
|
||||
"No routes available for this destination.".tr);
|
||||
return;
|
||||
}
|
||||
routeData = responseData['routes'][0];
|
||||
apiDistanceMeters = (routeData['distance'] as num).toDouble();
|
||||
pointsString = routeData['geometry'] ?? "";
|
||||
}
|
||||
// SaaS parsing
|
||||
apiDistanceMeters = (responseData['distance'] as num).toDouble();
|
||||
pointsString = responseData['points'] ?? "";
|
||||
routeData = responseData; // For box storage
|
||||
|
||||
var originCoords = origin.split(',');
|
||||
double startLat = double.parse(originCoords[0]);
|
||||
@@ -6613,21 +6645,14 @@ Intaleq Team''';
|
||||
polylineCoordinates.clear();
|
||||
polylineCoordinates.addAll(decodedPoints);
|
||||
|
||||
// ── 4. العناوين والتحديثات ──────────────────────────────────
|
||||
final LatLng startLoc = polylineCoordinates.first;
|
||||
final LatLng endLoc = polylineCoordinates.last;
|
||||
|
||||
try {
|
||||
final results = await Future.wait([
|
||||
getReverseGeocoding(startLoc),
|
||||
getReverseGeocoding(endLoc),
|
||||
]);
|
||||
startNameAddress = results[0];
|
||||
endNameAddress = results[1];
|
||||
} catch (e) {
|
||||
startNameAddress = 'Start Point'.tr;
|
||||
endNameAddress = 'Destination'.tr;
|
||||
}
|
||||
// ── 4. العناوين والتحديثات ──────────────────────────────────
|
||||
startNameAddress = responseData['startName'] ?? 'Start Point'.tr;
|
||||
endNameAddress = responseData['endName'] ?? 'Destination'.tr;
|
||||
Log.print('📍 ROUTE START: $startNameAddress');
|
||||
Log.print('📍 ROUTE END: $endNameAddress');
|
||||
|
||||
// ── 5. Bounds Calculation (SaaS bbox vs OSRM manual) ──────────
|
||||
if (isSaaSRequest && responseData['bbox'] != null) {
|
||||
@@ -6863,7 +6888,7 @@ Intaleq Team''';
|
||||
// -----------------------------------------------------------------------------------------
|
||||
void _handleFatalError(String title, String message) {
|
||||
// 1. إغلاق شاشة التحميل (Drawing route...)
|
||||
if (isDrawingRoute || (Get.isBottomSheetOpen ?? false)) {
|
||||
if (Get.isBottomSheetOpen == true || Get.isDialogOpen == true) {
|
||||
Get.back();
|
||||
}
|
||||
|
||||
@@ -8041,6 +8066,7 @@ Intaleq Team''';
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
_checkAndRefreshMapStyle(); // Verify style version and clear cache if needed
|
||||
// // --- إضافة جديدة: تهيئة وحدة التحكم في الروابط العميقة ---
|
||||
Get.put(DeepLinkController(), permanent: true);
|
||||
// // ----------------------------------------------------
|
||||
@@ -8189,6 +8215,34 @@ Intaleq Team''';
|
||||
'The price may increase if the route changes.'.tr, 'ding');
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the current version of assets/style.json and purges the map cache if it has changed.
|
||||
Future<void> _checkAndRefreshMapStyle() async {
|
||||
try {
|
||||
final String styleJson = await rootBundle.loadString('assets/style.json');
|
||||
final Map<String, dynamic> decoded = json.decode(styleJson);
|
||||
final String? currentVersion =
|
||||
decoded['metadata'] != null ? decoded['metadata']['version'] : null;
|
||||
|
||||
if (currentVersion == null) return;
|
||||
|
||||
final String lastVersion = box.read(BoxName.styleVersion) ?? "0.0.0";
|
||||
|
||||
if (currentVersion != lastVersion) {
|
||||
Log.print(
|
||||
"♻️ Map Style Version mismatch ($lastVersion -> $currentVersion). Purging offline cache...");
|
||||
await OfflineMapService.instance.clearCache();
|
||||
|
||||
// Final verification check: give native engine time to flush
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
box.write(BoxName.styleVersion, currentVersion);
|
||||
Log.print("✅ Style Version updated to $currentVersion");
|
||||
}
|
||||
} catch (e) {
|
||||
Log.print("⚠️ Style version check failed: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CarLocation {
|
||||
|
||||
@@ -119,7 +119,7 @@ class TripMonitorController extends GetxController {
|
||||
@override
|
||||
void onClose() {
|
||||
timer.cancel();
|
||||
mapController?.dispose();
|
||||
mapController = null;
|
||||
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ class Log {
|
||||
Log._();
|
||||
|
||||
static void print(String value, {StackTrace? stackTrace}) {
|
||||
// developer.log(value, name: 'LOG', stackTrace: stackTrace);
|
||||
developer.log(value, name: 'LOG', stackTrace: stackTrace);
|
||||
}
|
||||
|
||||
static Object? inspect(Object? object) {
|
||||
|
||||
@@ -103,4 +103,19 @@ class OfflineMapService {
|
||||
2;
|
||||
return 12742 * math.asin(math.sqrt(a));
|
||||
}
|
||||
|
||||
/// Clears all offline map regions and tiles from local storage
|
||||
Future<void> clearCache() async {
|
||||
try {
|
||||
Log.print("♻️ Purging MapLibre Offline Cache...");
|
||||
// In maplibre_gl 0.25.0, we use top-level functions instead of an OfflineManager class
|
||||
final List<OfflineRegion> regions = await getListOfRegions();
|
||||
for (var region in regions) {
|
||||
await deleteOfflineRegion(region.id);
|
||||
}
|
||||
Log.print("✅ Map cache cleared successfully. ${regions.length} regions removed.");
|
||||
} catch (e) {
|
||||
Log.print("⚠️ Failed to clear map cache: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user