chore: add build artifacts, map assets, and routing data

This commit is contained in:
Hamza-Ayed
2026-09-19 12:34:24 +03:00
parent aa2b9f131f
commit 43ad2e0ad4
327 changed files with 52421 additions and 1810 deletions
@@ -1,9 +1,9 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:maplibre_gl/maplibre_gl.dart' as mgl;
import 'intaleq_map_controller.dart';
import 'styles.dart';
import 'offline_service.dart';
import 'models/geometry.dart';
import 'models/types.dart';
@@ -59,7 +59,7 @@ class IntaleqMap extends StatefulWidget {
this.scrollGesturesEnabled = true,
this.tiltGesturesEnabled = true,
this.zoomGesturesEnabled = true,
this.autoCache = true,
this.autoCache = false,
this.minMaxZoomPreference = MinMaxZoomPreference.unbounded,
this.cameraTargetBounds = CameraTargetBounds.unbounded,
});
@@ -144,6 +144,7 @@ class _IntaleqMapState extends State<IntaleqMap> {
bool _isCameraMoving = false;
String? _styleString;
bool _isLoadingStyle = true;
bool _isNativeStyleLoaded = false;
@override
void initState() {
@@ -158,10 +159,20 @@ class _IntaleqMapState extends State<IntaleqMap> {
if (url.startsWith('{')) {
_styleString = url;
} else if (url.startsWith('asset://')) {
} else if (url.startsWith('asset://') || url.startsWith('assets/') || (url.endsWith('.json') && !url.startsWith('http'))) {
final assetPath = url.replaceFirst('asset://', '');
_styleString = await rootBundle.loadString(assetPath);
print("🔥 [IntaleqMap] Style loaded from asset string: ${assetPath.split('/').last}");
try {
_styleString = await rootBundle.loadString(assetPath);
print("🔥 [IntaleqMap] Style loaded from asset string: ${assetPath.split('/').last}");
} catch (_) {
try {
_styleString = await rootBundle.loadString('packages/intaleq_maps/$assetPath');
print("🔥 [IntaleqMap] Style loaded from package asset: packages/intaleq_maps/$assetPath");
} catch (e) {
print("❌ [IntaleqMap] Asset load failed: $e");
_styleString = url;
}
}
} else if (url.startsWith('file://')) {
final filePath = url.replaceFirst('file://', '');
final file = File(filePath);
@@ -171,9 +182,49 @@ class _IntaleqMapState extends State<IntaleqMap> {
} else {
_styleString = url;
}
} else if (url.startsWith('http://') || url.startsWith('https://')) {
// If satellite theme requested, use bundled ESRI Satellite hybrid style directly
if (widget.mapType == IntaleqMapType.satellite || url.contains('theme=satellite')) {
try {
_styleString = await rootBundle.loadString('packages/intaleq_maps/assets/style-satellite.json');
print("🛰️ [IntaleqMap] Loaded bundled ESRI Satellite hybrid style successfully");
return;
} catch (_) {
try {
_styleString = await rootBundle.loadString('assets/style-satellite.json');
print("🛰️ [IntaleqMap] Loaded local ESRI Satellite hybrid style successfully");
return;
} catch (_) {}
}
}
try {
final res = await http.get(Uri.parse(url)).timeout(const Duration(seconds: 4));
if (res.statusCode == 200 && res.body.trim().startsWith('{')) {
_styleString = res.body;
print("🔥 [IntaleqMap] Pre-fetched remote style JSON (${res.body.length} bytes)");
} else {
_styleString = url;
}
} catch (netErr) {
print("⚠️ [IntaleqMap] Direct HTTP fetch failed ($netErr), attempting bundled fallback");
try {
final fallback = (widget.mapType == IntaleqMapType.satellite || url.contains('theme=satellite'))
? 'packages/intaleq_maps/assets/style-satellite.json'
: 'packages/intaleq_maps/assets/style.json';
_styleString = await rootBundle.loadString(fallback);
print("🔥 [IntaleqMap] Loaded bundled offline fallback style successfully: $fallback");
} catch (_) {
_styleString = url;
}
}
} else {
_styleString = url;
print("🔥 [IntaleqMap] Using remote style URL: $url");
// Fallback: try rootBundle first
try {
_styleString = await rootBundle.loadString(url);
print("🔥 [IntaleqMap] Style loaded from rootBundle fallback: $url");
} catch (_) {
_styleString = url;
}
}
} catch (e) {
print("❌ [IntaleqMap] Failed to load style: $e");
@@ -191,11 +242,12 @@ class _IntaleqMapState extends State<IntaleqMap> {
if (oldWidget.mapType != widget.mapType ||
oldWidget.styleUrl != widget.styleUrl) {
_isNativeStyleLoaded = false;
_loadStyle();
}
final ctrl = _controller;
if (ctrl == null) return;
if (ctrl == null || !_isNativeStyleLoaded) return;
// Reconcile each overlay set when widget rebuilds.
ctrl.diffMarkers(oldWidget.markers, widget.markers);
@@ -206,17 +258,17 @@ class _IntaleqMapState extends State<IntaleqMap> {
String get _resolvedStyleUrl {
if (widget.styleUrl != null) return widget.styleUrl!;
// Point to live sovereign server style by default (Google + OSM modern hybrid style)
// Default to local assets for instant loading and 100% offline support (as in Siro Rider)
return switch (widget.mapType) {
IntaleqMapType.normal => IntaleqStyles.light(widget.apiKey),
IntaleqMapType.light => IntaleqStyles.light(widget.apiKey),
IntaleqMapType.satellite => IntaleqStyles.satellite(widget.apiKey),
IntaleqMapType.normal => 'asset://packages/intaleq_maps/assets/style_dark.json',
IntaleqMapType.light => 'asset://packages/intaleq_maps/assets/style.json',
IntaleqMapType.satellite => 'asset://packages/intaleq_maps/assets/style-satellite.json',
IntaleqMapType.none => 'about:blank',
};
}
Future<void> _onMapCreated(mgl.MapLibreMapController rawCtrl) async {
// Wire up tap routing before handing the controller to the caller.
print("🗺️ [IntaleqMapWidget] _onMapCreated: Native MapLibre controller attached.");
rawCtrl.onSymbolTapped.add(_onSymbolTapped);
rawCtrl.onLineTapped.add(_onLineTapped);
@@ -225,6 +277,7 @@ class _IntaleqMapState extends State<IntaleqMap> {
apiKey: widget.apiKey,
);
_controller = ctrl;
print("🗺️ [IntaleqMapWidget] Invoking widget.onMapCreated callback...");
widget.onMapCreated?.call(ctrl);
}
@@ -234,18 +287,22 @@ class _IntaleqMapState extends State<IntaleqMap> {
void _onLineTapped(mgl.Line line) => _controller?.onLineTapped(line);
Future<void> _onStyleLoaded() async {
print("🎨 [IntaleqMapWidget] _onStyleLoaded: MapLibre native style finished loading.");
_isNativeStyleLoaded = true;
final ctrl = _controller;
if (ctrl == null) return;
if (ctrl == null) {
print("⚠️ [IntaleqMapWidget] _onStyleLoaded: _controller is null!");
return;
}
await ctrl.onStyleLoaded();
print("🎨 [IntaleqMapWidget] Invoking widget.onStyleLoaded callback...");
final callbackResult = widget.onStyleLoaded?.call();
if (callbackResult is Future) {
await callbackResult;
}
// Re-render everything from the current declarative sets.
// This ensures overlays persist across style changes (Dark/Light mode)
// and during certain zoom/camera events that trigger style reloads.
print("📌 [IntaleqMapWidget] Re-rendering overlays: markers=${widget.markers.length}, polylines=${widget.polylines.length}, circles=${widget.circles.length}, polygons=${widget.polygons.length}");
for (final m in widget.markers) await ctrl.addMarker(m);
for (final p in widget.polylines) await ctrl.addPolyline(p);
for (final c in widget.circles) await ctrl.addCircle(c);
@@ -253,6 +310,12 @@ class _IntaleqMapState extends State<IntaleqMap> {
// Apply defaults AFTER markers have initialized the symbol layer
await ctrl.applyMarkerVisibilityDefaults();
// Safely refresh to enable native location layer after style is ready on iOS
if (widget.myLocationEnabled && mounted) {
print("📍 [IntaleqMapWidget] Enabling native location layer after style is loaded.");
setState(() {});
}
}
@override
@@ -261,7 +324,9 @@ class _IntaleqMapState extends State<IntaleqMap> {
return const Center(child: CircularProgressIndicator());
}
return mgl.MaplibreMap(
final bool canEnableLocation = _isNativeStyleLoaded && widget.myLocationEnabled;
return mgl.MapLibreMap(
styleString: _styleString!,
initialCameraPosition: widget.initialCameraPosition.toMapLibre(),
onMapCreated: _onMapCreated,
@@ -288,8 +353,8 @@ class _IntaleqMapState extends State<IntaleqMap> {
widget.onCameraIdle?.call();
},
onCameraTrackingChanged: null,
myLocationEnabled: widget.myLocationEnabled,
myLocationRenderMode: widget.myLocationEnabled
myLocationEnabled: canEnableLocation,
myLocationRenderMode: canEnableLocation
? mgl.MyLocationRenderMode.normal
: mgl.MyLocationRenderMode.normal,
myLocationTrackingMode: mgl.MyLocationTrackingMode.none,