improvements

main_production_asset_tracking
Sikander Saleem 2 weeks ago
parent c93afad736
commit d0af447a09

@ -632,7 +632,7 @@ class URLs {
// Asset Tracking APIs // Asset Tracking APIs
static get getAssetsFromPenguin => "$_baseUrl/PenguinIN/GetAssetsFromPenguin"; static get getAssetsFromPenguin => "$_baseUrl/PenguinIN/GetAssetsFromPenguin";
static get getPenguinZones => "$_baseUrl/PenguinIN/zone/";
static get getPenguinSites => "$_baseUrl/PenguinIN/sites/"; static get getPenguinSites => "$_baseUrl/PenguinIN/sites/";
static get getPenguinDepartments => "$_baseUrl/PenguinIN/departments"; static get getPenguinDepartments => "$_baseUrl/PenguinIN/departments";
static get getPenguinBuildings => "$_baseUrl/PenguinIN/buildings"; static get getPenguinBuildings => "$_baseUrl/PenguinIN/buildings";

@ -3,10 +3,12 @@ import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/modules/asset_tracking/models/coordinates_model.dart';
import 'models/asset_tracking_model.dart'; import 'models/asset_tracking_model.dart';
import 'models/floor_map_model.dart'; import 'models/floor_map_model.dart';
import 'models/penguin_site_model.dart'; import 'models/penguin_site_model.dart';
import 'models/zone_data_model.dart';
class AssetTrackingProvider extends ChangeNotifier { class AssetTrackingProvider extends ChangeNotifier {
bool isLoading = false; bool isLoading = false;
@ -17,6 +19,9 @@ class AssetTrackingProvider extends ChangeNotifier {
List<AssetTrackingModel> assetsList = []; List<AssetTrackingModel> assetsList = [];
List<AssetTrackingModel> assetsOnTheFloorList = []; List<AssetTrackingModel> assetsOnTheFloorList = [];
List<ZoneModel> zonesList = [];
ZoneModel? selectedZone;
List<PenguinSiteModel> sitesList = []; List<PenguinSiteModel> sitesList = [];
PenguinSiteModel? selectedSite; PenguinSiteModel? selectedSite;
@ -25,8 +30,24 @@ class AssetTrackingProvider extends ChangeNotifier {
List<PenguinSiteModel> floorList = []; List<PenguinSiteModel> floorList = [];
PenguinSiteModel? selectedFloor; PenguinSiteModel? selectedFloor;
List<Coordinates> coordinates = [];
void calculateCoordinates() {
coordinates.clear();
coordinates.addAll(selectedBuilding!.coordinates!.map((e) => Coordinates(latitude: e.latitude, longitude: e.longitude)).toList());
notify();
}
// List<ZoneModel> getFilteredZones() {
// if (zonesList.isEmpty || selectedSite == null || selectedBuilding == null) {
// return [];
// } else {
// return zonesList.where((zone) => zone.siteId == selectedSite!.id).toList();
// }
// }
String get getExpansionHeader => String get getExpansionHeader =>
(selectedBuilding == null || selectedBuilding == null || selectedFloor == null) ? "Search Floor Map" : "${selectedSite!.label} > ${selectedBuilding!.label} > ${selectedFloor!.label}"; (selectedBuilding == null || selectedBuilding == null) ? "Search Floor Map" : "${selectedSite!.label} > ${selectedBuilding!.label} > ${selectedFloor?.label ?? "Select Floor"}";
reset() { reset() {
isLoading = false; isLoading = false;
@ -86,14 +107,53 @@ class AssetTrackingProvider extends ChangeNotifier {
} }
} }
Future getBuildingMapFromPenguin() async {
if (zonesList.isNotEmpty) {
await Future.delayed(const Duration(milliseconds: 250));
// return;
}
try {
final response = await ApiManager.instance.get(URLs.getPenguinBuildings + "");
if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body);
List list = jsonData["data"];
zonesList.addAll(list.map((item) => ZoneModel.fromJson(item)).toList());
notify();
}
} catch (error) {
print("getZoneFromPenguin:Error:$error");
}
}
Future getZoneFromPenguin() async {
if (zonesList.isNotEmpty) {
await Future.delayed(const Duration(milliseconds: 250));
return;
}
try {
final response = await ApiManager.instance.get(URLs.getPenguinZones);
if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body);
List list = jsonData["data"];
zonesList.addAll(list.map((item) => ZoneModel.fromJson(item)).toList());
notify();
}
} catch (error) {
print("getZoneFromPenguin:Error:$error");
}
}
Future getAssetsFromPenguinByFloor() async { Future getAssetsFromPenguinByFloor() async {
try { try {
assetsOnTheFloorList.clear(); assetsOnTheFloorList.clear();
final response = await ApiManager.instance.post(URLs.getAssetsFromPenguin, body: { Map<String, dynamic> body = {
"campusId": selectedSite!.id, "campusId": selectedSite!.id,
"venueIds": [selectedBuilding!.id], "venueIds": [selectedBuilding!.id]
"floorIds": [selectedFloor!.id] };
}); if (selectedFloor != null) {
body["floorIds"] = [selectedFloor!.id];
}
final response = await ApiManager.instance.post(URLs.getAssetsFromPenguin, body: body);
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body); final Map<String, dynamic> jsonData = json.decode(response.body);
List list = jsonData["data"]; List list = jsonData["data"];

@ -5,11 +5,15 @@ import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_geojson2/flutter_map_geojson2.dart'; import 'package:flutter_map_geojson2/flutter_map_geojson2.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/helper/utils.dart';
import 'package:test_sa/modules/asset_tracking/models/coordinates_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart'; import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
@ -21,6 +25,7 @@ import 'asset_tracking_provider.dart';
import 'models/asset_tracking_model.dart'; import 'models/asset_tracking_model.dart';
import 'models/floor_map_model.dart'; import 'models/floor_map_model.dart';
import 'models/penguin_site_model.dart'; import 'models/penguin_site_model.dart';
import 'models/zone_data_model.dart';
class MapTrackingPage extends StatefulWidget { class MapTrackingPage extends StatefulWidget {
final AssetTrackingModel? assetTrackingData; final AssetTrackingModel? assetTrackingData;
@ -62,6 +67,12 @@ class _MapTrackingPageState extends State<MapTrackingPage> {
}); });
} }
@override
void dispose() {
_polygonHitNotifier.dispose();
super.dispose();
}
void getPenguinSites() async { void getPenguinSites() async {
Utils.showLoading(context); Utils.showLoading(context);
await assetTrackingProvider.getPenguinSites(); await assetTrackingProvider.getPenguinSites();
@ -166,18 +177,43 @@ class _MapTrackingPageState extends State<MapTrackingPage> {
final minChildSize = 0.25; final minChildSize = 0.25;
final maxChildSize = 1.0; final maxChildSize = 1.0;
// final LayerHitNotifier<Map<String, dynamic>> _polygonHitNotifier = ValueNotifier(null);
final LayerHitNotifier<Object> _polygonHitNotifier = ValueNotifier(null);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget mapWidget = FlutterMap( Widget mapWidget = FlutterMap(
mapController: mapController, mapController: mapController,
options: MapOptions(initialCenter: _fallbackCenter, initialZoom: 16.0), options: const MapOptions(initialCenter: _fallbackCenter, initialZoom: 16.0),
children: [ children: [
TileLayer( TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.hmg.atoms', userAgentPackageName: 'com.hmg.atoms',
), ),
if (_geojson != null) ...[ if (_geojson != null) ...[
GeoJsonLayer.memory(_geojson!, styleDefaults: GeoJsonStyleDefaults.leaflet), GestureDetector(
onTap: () {
// final hitResult = _polygonHitNotifier.value;
//
// if (hitResult == null || hitResult.hitValues.isEmpty) return;
// print("hitResult:$hitResult");
// final hitValue = hitResult.hitValues.first;
//
// // Narrow safely instead of assuming the type.
// if (hitValue is Map<String, dynamic>) {
// print(hitValue);
// } else {
// // ignore: avoid_print
// print('Unexpected hit value type: ${hitValue.runtimeType} -> $hitValue');
// }
},
child: GeoJsonLayer.memory(
_geojson!,
hitNotifier: _polygonHitNotifier,
styleDefaults: GeoJsonStyleDefaults.leaflet,
),
),
// if (!inAppView || ) // if (!inAppView || )
if (markers.isNotEmpty) MarkerLayer(markers: markers), if (markers.isNotEmpty) MarkerLayer(markers: markers),
if (inAppView) if (inAppView)
@ -245,6 +281,27 @@ class _MapTrackingPageState extends State<MapTrackingPage> {
}), }),
), ),
], ],
if (inAppView)
Selector<AssetTrackingProvider, List<Coordinates>>(
selector: (_, assetTPro) => assetTPro.coordinates,
builder: (_, coordinates, __) {
if (coordinates.isEmpty) return const SizedBox();
List<LatLng> list = [
for (var coordinate in (coordinates)) LatLng(coordinate.latitude!, coordinate.longitude!),
];
List<Polygon> zonesPolygons = [
Polygon(
label: assetTrackingProvider.selectedBuilding?.label ?? "",
labelStyle: AppTextStyles.bodyText2.copyWith(color: AppColor.textColor(context)),
points: list,
color: AppColor.red30.withOpacity(0.3),
borderColor: AppColor.red30,
borderStrokeWidth: 2.0,
),
];
return PolygonLayer(polygons: zonesPolygons);
}),
Positioned( Positioned(
top: 70, top: 70,
right: 8, right: 8,
@ -357,12 +414,31 @@ class _MapTrackingPageState extends State<MapTrackingPage> {
onSelect: (value) { onSelect: (value) {
if (value != null) { if (value != null) {
assetProvider.selectedFloor = value; assetProvider.selectedFloor = value;
expansibleController.collapse();
getFloorMap(value.id!);
assetTrackingProvider.getAssetsFromPenguinByFloor();
} }
}, },
), ),
8.height,
Align(
alignment: AlignmentGeometry.centerRight,
child: AppTextButton(
label: "View",
disableButton: assetProvider.selectedSite == null || assetProvider.selectedBuilding == null,
onPressed: () {
expansibleController.collapse();
assetTrackingProvider.coordinates.clear();
assetTrackingProvider.assetsOnTheFloorList.clear();
assetTrackingProvider.notify();
assetTrackingProvider.getAssetsFromPenguinByFloor();
if (assetProvider.selectedFloor != null) {
getFloorMap(assetProvider.selectedFloor!.id!);
assetTrackingProvider.getZoneFromPenguin();
} else {
assetTrackingProvider.calculateCoordinates();
}
},
),
),
16.height, 16.height,
], ],
); );

@ -0,0 +1,27 @@
class Coordinates {
double? x;
double? y;
double? longitude;
double? latitude;
int? orderIndex;
Coordinates({this.x, this.y, this.longitude, this.latitude, this.orderIndex});
Coordinates.fromJson(Map<String, dynamic> json) {
x = json['x'];
y = json['y'];
longitude = json['longitude'];
latitude = json['latitude'];
orderIndex = json['orderIndex'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['x'] = this.x;
data['y'] = this.y;
data['longitude'] = this.longitude;
data['latitude'] = this.latitude;
data['orderIndex'] = this.orderIndex;
return data;
}
}

@ -1,11 +1,14 @@
import 'package:test_sa/models/base.dart'; import 'package:test_sa/models/base.dart';
import 'coordinates_model.dart';
class PenguinSiteModel extends Base { class PenguinSiteModel extends Base {
int? id; int? id;
String? label; String? label;
List<Coordinates>? coordinates;
bool? isMapped; bool? isMapped;
PenguinSiteModel({this.id, this.label}) : super(identifier: id?.toString(), name: label); PenguinSiteModel({this.id, this.label, this.coordinates}) : super(identifier: id?.toString(), name: label);
PenguinSiteModel.fromJson(Map<String, dynamic> json) { PenguinSiteModel.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
@ -13,6 +16,15 @@ class PenguinSiteModel extends Base {
label = json['label']; label = json['label'];
name = json['label']; name = json['label'];
isMapped = json['isMapped']; isMapped = json['isMapped'];
if (json['coordinates'] != null) {
coordinates = <Coordinates>[];
json['coordinates'].forEach((v) {
coordinates!.add(new Coordinates.fromJson(v));
});
}
if (this.coordinates != null) {
json['coordinates'] = this.coordinates!.map((v) => v.toJson()).toList();
}
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {

@ -0,0 +1,86 @@
import 'coordinates_model.dart';
class ZoneModel {
int? id;
String? referenceId;
String? name;
ZoneType? zoneType;
Location? location;
List<Coordinates>? coordinates;
ZoneModel({this.id, this.referenceId, this.name, this.zoneType, this.location, this.coordinates});
ZoneModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
referenceId = json['referenceId'];
name = json['name'];
zoneType = json['zoneType'] != null ? new ZoneType.fromJson(json['zoneType']) : null;
location = json['location'] != null ? new Location.fromJson(json['location']) : null;
if (json['coordinates'] != null) {
coordinates = <Coordinates>[];
json['coordinates'].forEach((v) {
coordinates!.add(new Coordinates.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['referenceId'] = this.referenceId;
data['name'] = this.name;
if (this.zoneType != null) {
data['zoneType'] = this.zoneType!.toJson();
}
if (this.location != null) {
data['location'] = this.location!.toJson();
}
if (this.coordinates != null) {
data['coordinates'] = this.coordinates!.map((v) => v.toJson()).toList();
}
return data;
}
}
class ZoneType {
int? id;
String? name;
ZoneType({this.id, this.name});
ZoneType.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}
class Location {
int? id;
String? name;
String? label;
Location({this.id, this.name, this.label});
Location.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
label = json['label'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['label'] = this.label;
return data;
}
}

@ -78,3 +78,58 @@ class AppFilledButton extends StatelessWidget {
).onPress(disableButton ? null : (loading ? null : onPressed)); ).onPress(disableButton ? null : (loading ? null : onPressed));
} }
} }
class AppTextButton extends StatelessWidget {
final VoidCallback? onPressed;
final String label;
final bool maxWidth, loading;
final double? fontSize;
final double? height;
final bool showIcon;
final String? iconString;
final Color? buttonColor;
final bool showBorder;
final double radius;
final bool disableButton;
const AppTextButton(
{this.onPressed,
required this.label,
this.maxWidth = false,
this.showIcon = false,
this.iconString,
this.fontSize,
this.height,
this.loading = false,
this.showBorder = false,
this.disableButton = false,
this.buttonColor,
this.radius = 35,
Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
height: height,
width: label.length * 15,
alignment: Alignment.center,
decoration: BoxDecoration(
color: disableButton ? AppColor.disableFieldBackground(context) : buttonColor ?? AppColor.primary10,
borderRadius: BorderRadius.circular(radius),
),
child: Row(
spacing: 8,
mainAxisSize: MainAxisSize.min,
children: [
if (showIcon && iconString != null) iconString!.toSvgAsset(height: 20, width: 20, color: AppColor.icon2Color(context)),
Text(
label,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.textStyleColor(context)),
),
],
),
).onPress(disableButton ? null : onPressed);
}
}

Loading…
Cancel
Save