From 2d6e17c4a0e11486e7abfdd885582febb2297030 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 1 Oct 2026 14:26:09 +0300 Subject: [PATCH] improvement --- .../asset_tracking_provider.dart | 27 ++++---- .../asset_tracking/map_tracking_page.dart | 64 ++++++++++++++++++- .../models/coordinates_model.dart | 8 +-- 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/lib/modules/asset_tracking/asset_tracking_provider.dart b/lib/modules/asset_tracking/asset_tracking_provider.dart index 40eb9952..7bf475e7 100644 --- a/lib/modules/asset_tracking/asset_tracking_provider.dart +++ b/lib/modules/asset_tracking/asset_tracking_provider.dart @@ -136,23 +136,20 @@ class AssetTrackingProvider extends ChangeNotifier { } Future getZoneFromPenguin() async { - if (zonesList.isNotEmpty) { - await Future.delayed(const Duration(milliseconds: 250)); - calculateCoordinates(); - return; - } - try { - final response = await ApiManager.instance.get(URLs.getPenguinZones); - if (response.statusCode >= 200 && response.statusCode < 300) { - final Map jsonData = json.decode(response.body); - List list = jsonData["data"]; - zonesList.addAll(list.map((item) => ZoneModel.fromJson(item)).toList()); - calculateCoordinates(); - // notify(); + if (zonesList.isEmpty) { + try { + final response = await ApiManager.instance.get(URLs.getPenguinZones); + if (response.statusCode >= 200 && response.statusCode < 300) { + final Map jsonData = json.decode(response.body); + List list = jsonData["data"] ?? []; + zonesList.addAll(list.map((item) => ZoneModel.fromJson(item)).toList()); + } + } catch (error) { + print("getZoneFromPenguin:Error:$error"); } - } catch (error) { - print("getZoneFromPenguin:Error:$error"); } + // Building outline comes from the selected building, so always compute it. + calculateCoordinates(); } Future getAssetsFromPenguinByFloor() async { diff --git a/lib/modules/asset_tracking/map_tracking_page.dart b/lib/modules/asset_tracking/map_tracking_page.dart index f62221a4..d3690be8 100644 --- a/lib/modules/asset_tracking/map_tracking_page.dart +++ b/lib/modules/asset_tracking/map_tracking_page.dart @@ -117,6 +117,57 @@ class _MapTrackingPageState extends State { }); } + /// "View" button: loads the floor map (if a floor is selected) or the building outline. + Future _onViewPressed(AssetTrackingProvider provider) async { + expansibleController.collapse(); + provider.coordinates = []; + provider.assetsOnTheFloorList = []; + provider.notify(); + + provider.getAssetsFromPenguinByFloor(); + + if (provider.selectedFloor != null) { + getFloorMap(provider.selectedFloor!.id!); + provider.getZoneFromPenguin(); + return; + } + + // Building only: remove any previously displayed floor map so the building outline is visible. + setState(() { + _geojson = null; + floorMapModel = null; + _selectedZoneProperties = null; + markers = []; + _lastFittedCoordinatesKey = null; // force re-fit even if the same building is viewed again + }); + + Utils.showLoading(context); + await provider.getZoneFromPenguin(); + if (!mounted) return; + Utils.hideLoading(context); + // Camera fit happens in the building-outline Selector once the polygon is rendered. + } + + /// Signature of the last building outline the camera was fitted to. + String? _lastFittedCoordinatesKey; + + /// Zooms/pans the map so all [points] are visible. Runs after the current frame so the + /// map has its final size, and schedules a frame so the callback is guaranteed to fire. + void _fitCameraToPoints(List points) { + if (points.isEmpty) return; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + if (points.length == 1) { + mapController.move(points.first, 18); + return; + } + mapController.fitCamera( + CameraFit.bounds(bounds: LatLngBounds.fromPoints(points), padding: const EdgeInsets.all(48), maxZoom: 20), + ); + }); + WidgetsBinding.instance.scheduleFrame(); + } + void _onFloorMapLoaded(FloorMapModel? loadedFloorMap) { floorMapModel = loadedFloorMap; _selectedZoneProperties = null; @@ -409,13 +460,22 @@ class _MapTrackingPageState extends State { ], if (inAppView && _geojson == null) Selector>( - selector: (_, assetTPro) => assetTPro.coordinates, + selector: (_, assetTPro) => List.of(assetTPro.coordinates), builder: (_, coordinates, __) { if (coordinates.isEmpty) return const SizedBox(); List list = [ - for (var coordinate in (coordinates)) LatLng(coordinate.latitude!, coordinate.longitude!), + for (var coordinate in (coordinates)) + if (coordinate.latitude != null && coordinate.longitude != null) LatLng(coordinate.latitude!, coordinate.longitude!), ]; + if (list.isEmpty) return const SizedBox(); + + // Fit the camera to the building outline once per new outline. + final key = "${assetTrackingProvider.selectedBuilding?.id}|${list.length}|${list.first}|${list.last}"; + if (key != _lastFittedCoordinatesKey) { + _lastFittedCoordinatesKey = key; + _fitCameraToPoints(list); + } List zonesPolygons = [ Polygon( label: assetTrackingProvider.selectedBuilding?.label ?? "", diff --git a/lib/modules/asset_tracking/models/coordinates_model.dart b/lib/modules/asset_tracking/models/coordinates_model.dart index 051b2899..c05a211d 100644 --- a/lib/modules/asset_tracking/models/coordinates_model.dart +++ b/lib/modules/asset_tracking/models/coordinates_model.dart @@ -8,10 +8,10 @@ class Coordinates { Coordinates({this.x, this.y, this.longitude, this.latitude, this.orderIndex}); Coordinates.fromJson(Map json) { - x = json['x']; - y = json['y']; - longitude = json['longitude']; - latitude = json['latitude']; + x = (json['x'] as num?)?.toDouble(); + y = (json['y'] as num?)?.toDouble(); + longitude = (json['longitude'] as num?)?.toDouble(); + latitude = (json['latitude'] as num?)?.toDouble(); orderIndex = json['orderIndex']; }