Files
intaleq/siro_driver/lib/services/offline_map_service.dart
T
Hamza-AyedandClaude Opus 5 92dc6b3641 chore: استيراد أولي من سيرو (ecfe7568) — بلا أي تعديل
نسخة كاملة من مستودع سيرو عند ecfe7568 لتكون أساس تطبيق «انطلق».
نُسخ المتعقَّب في git فقط (12,509 ملفاً / 302 م.ب) بـ git archive، لا
`cp -r` — فاستُثنيت تلقائياً مخلفات البناء (build · node_modules ·
.dart_tool · .gradle · Pods ≈ 10.7 غ.ب) وكل ما يستثنيه .gitignore.

هذا الكوميت **بلا أي تعديل عمداً** حتى يكون كل ما يليه فرقاً مقروءاً
مقابل سيرو الأصلي. سيرو نفسه لم يُمسّ.

⚠️ لا يبني بعد: `.env` و`lib/env/env.g.dart` غير متعقَّبين في سيرو (وهذا
صحيح — أسرار لكل مستأجر). كل تطبيق فلاتر هنا يحتاج .env خاصاً بانطلق ثم
توليد env.g.dart عبر build_runner. لا تُنسخ أسرار سيرو.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 05:10:29 +03:00

120 lines
3.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:io';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'dart:math' as math;
import '../main.dart';
import '../print.dart';
class OfflineMapService {
static final OfflineMapService instance = OfflineMapService._();
OfflineMapService._();
final _offlineRegionName = "UserRegion";
bool _isDownloading = false;
LatLng? _lastDownloadedCenter;
/// Calculate bounding box for a given center and radius in km
LatLngBounds _calculateBounds(LatLng center, double radiusKm) {
const double earthRadius = 6371.0;
// Latitude degrees per km
double latDelta = (radiusKm / earthRadius) * (180 / math.pi);
// Longitude degrees per km at given latitude
double lngDelta = (radiusKm / earthRadius) *
(180 / math.pi) /
math.cos(center.latitude * math.pi / 180);
return LatLngBounds(
southwest:
LatLng(center.latitude - latDelta, center.longitude - lngDelta),
northeast:
LatLng(center.latitude + latDelta, center.longitude + lngDelta),
);
}
/// Downloads a specified radius around a coordinate
Future<void> downloadRegion(LatLng center,
{double radiusKm = 10.0,
double minZoom = 6.0,
double maxZoom = 15.0}) async {
if (_isDownloading) return;
// Avoid re-downloading if the user hasn't moved significantly (e.g. > 5km)
if (_lastDownloadedCenter != null) {
double distance = _calculateDistance(center, _lastDownloadedCenter!);
if (distance < 5.0) return; // skip if close to previously downloaded
}
_isDownloading = true;
try {
final bounds = _calculateBounds(center, radiusKm);
// Select style based on current theme
final String styleStr =
Get.isDarkMode ? "assets/style_dark.json" : "assets/style.json";
// iOS native crash guard: MLNTilePyramidOfflineRegion does not support relative asset URLs.
// We skip native offline registration on iOS if using local assets to ensure stability.
if (Platform.isIOS && !styleStr.startsWith('http')) {
Log.print(
"ℹ️ Skipping native offline registration on iOS for asset-based style to prevent crash.");
return;
}
final regionDefinition = OfflineRegionDefinition(
bounds: bounds,
mapStyleUrl: styleStr,
minZoom: minZoom,
maxZoom: maxZoom,
);
// We'll update the last downloaded center immediately
_lastDownloadedCenter = center;
// MapLibre standard API for offline downloads
await downloadOfflineRegion(regionDefinition, metadata: {
'name': '$_offlineRegionName-${center.latitude}-${center.longitude}',
'downloadDate': DateTime.now().toIso8601String(),
});
// Reassurance log for the user
Log.print("📍 Map Ready: Service is utilizing local tile cache.");
Log.print(
"✅ Offline Map Cached for Region: $center (radius: ${radiusKm}km, style: $styleStr)");
} catch (e) {
Log.print("⚠️ Offline Map Download Failed: $e");
} finally {
_isDownloading = false;
}
}
/// Helper to calculate distance in km
double _calculateDistance(LatLng p1, LatLng p2) {
var p = 0.017453292519943295;
var c = math.cos;
var a = 0.5 -
c((p2.latitude - p1.latitude) * p) / 2 +
c(p1.latitude * p) *
c(p2.latitude * p) *
(1 - c((p2.longitude - p1.longitude) * p)) /
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...");
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");
}
}
}