asset tracking list view & map view added.
parent
2f3bb5ba7d
commit
2a560abcb3
@ -0,0 +1,80 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:test_sa/controllers/api_routes/api_manager.dart';
|
||||
import 'package:test_sa/controllers/api_routes/urls.dart';
|
||||
|
||||
import 'models/asset_tracking_model.dart';
|
||||
import 'models/floor_map_model.dart';
|
||||
|
||||
class AssetTrackingProvider extends ChangeNotifier {
|
||||
bool isLoading = false;
|
||||
bool isNextPageLoading = false;
|
||||
final pageItemNumber = 12;
|
||||
int pageNo = 1;
|
||||
|
||||
List<AssetTrackingModel> assetsList = [];
|
||||
|
||||
reset() {
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<int> getAssetsFromPenguin({bool loadMore = false}) async {
|
||||
if (isLoading || isNextPageLoading) return -2;
|
||||
if (loadMore) {
|
||||
isNextPageLoading = true;
|
||||
pageNo += 1;
|
||||
} else {
|
||||
isLoading = true;
|
||||
pageNo = 1; // reset pagination
|
||||
}
|
||||
notifyListeners();
|
||||
try {
|
||||
final payload = {"pageSize": pageItemNumber, "pageNumber": pageNo};
|
||||
final response = await ApiManager.instance.post(URLs.getAssetsFromPenguin, body: payload);
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||
final Map<String, dynamic> jsonData = json.decode(response.body);
|
||||
List list = jsonData["data"];
|
||||
assetsList.addAll(list.map((item) => AssetTrackingModel.fromJson(item)).toList());
|
||||
if (jsonData["totalRows"] <= assetsList.length) {
|
||||
// nextPage = true;
|
||||
}
|
||||
print("assetsList:${assetsList.length}");
|
||||
// if (loadMore) {
|
||||
// assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []);
|
||||
// assetInventoryResponse?.totalRows = newResponse.totalRows;
|
||||
// } else {
|
||||
// assetInventoryResponse = newResponse;
|
||||
// }
|
||||
// nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0);
|
||||
} else {
|
||||
// nextPage = false;
|
||||
}
|
||||
isLoading = false;
|
||||
isNextPageLoading = false;
|
||||
notifyListeners();
|
||||
return response.statusCode;
|
||||
} catch (error) {
|
||||
isLoading = false;
|
||||
isNextPageLoading = false;
|
||||
// stateCode = -1;
|
||||
// nextPage = false;
|
||||
notifyListeners();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Future<FloorMapModel?> getFloorMap(int floorId) async {
|
||||
FloorMapModel? floorMapModel;
|
||||
// try {
|
||||
final response = await ApiManager.instance.get(URLs.getFloorMap + "$floorId/maps");
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||
floorMapModel = FloorMapModel.fromJson(json.decode(response.body)["data"]);
|
||||
}
|
||||
return floorMapModel;
|
||||
// } catch (error) {
|
||||
// return floorMapModel;
|
||||
// }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map_geojson2/flutter_map_geojson2.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:test_sa/helper/utils.dart';
|
||||
import 'package:test_sa/new_views/app_style/app_color.dart';
|
||||
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
|
||||
|
||||
import 'asset_tracking_provider.dart';
|
||||
import 'models/asset_tracking_model.dart';
|
||||
import 'models/floor_map_model.dart';
|
||||
|
||||
class MapTrackingPage extends StatefulWidget {
|
||||
final AssetTrackingModel? assetTrackingData;
|
||||
final bool inAppView;
|
||||
|
||||
MapTrackingPage({Key? key, this.inAppView = false, this.assetTrackingData}) : super(key: key);
|
||||
|
||||
@override
|
||||
_MapTrackingPageState createState() {
|
||||
return _MapTrackingPageState();
|
||||
}
|
||||
}
|
||||
|
||||
class _MapTrackingPageState extends State<MapTrackingPage> {
|
||||
final MapController mapController = MapController();
|
||||
late AssetTrackingProvider assetTrackingProvider;
|
||||
|
||||
FloorMapModel? floorMapModel;
|
||||
Map<String, dynamic>? _geojson;
|
||||
List<Marker> markers = [];
|
||||
LatLngBounds? _computedBounds;
|
||||
|
||||
// Fallback shown only until the real floor plan bounds are computed.
|
||||
static const LatLng _fallbackCenter = LatLng(24.81200245073082, 46.624273601310186);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
assetTrackingProvider = Provider.of<AssetTrackingProvider>(context, listen: false);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (widget.assetTrackingData != null) {
|
||||
print('widget.assetTrackingData!.location!.floor!.id!: ${widget.assetTrackingData!.toJson()}');
|
||||
Utils.showLoading(context);
|
||||
assetTrackingProvider.getFloorMap(widget.assetTrackingData!.location!.floor!.id!).then((floorMap) {
|
||||
Utils.hideLoading(context);
|
||||
_onFloorMapLoaded(floorMap);
|
||||
}).catchError((error) {
|
||||
print('Failed to load floor map: $error');
|
||||
Utils.hideLoading(context);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _onFloorMapLoaded(FloorMapModel? loadedFloorMap) {
|
||||
floorMapModel = loadedFloorMap;
|
||||
|
||||
if (floorMapModel?.geojsonData == null) {
|
||||
setState(() {});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final decoded = floorMapModel!.geojsonData!;
|
||||
final bounds = _computeBoundsFromGeoJson(decoded);
|
||||
|
||||
setState(() {
|
||||
_geojson = decoded;
|
||||
_computedBounds = bounds;
|
||||
markers = [
|
||||
Marker(
|
||||
point: LatLng(widget.assetTrackingData!.location!.latitude!, widget.assetTrackingData!.location!.longitude!),
|
||||
child: const Icon(Icons.location_pin, color: AppColor.red30),
|
||||
),
|
||||
];
|
||||
});
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
mapController.fitCamera(
|
||||
CameraFit.bounds(bounds: bounds, padding: const EdgeInsets.all(24)),
|
||||
);
|
||||
});
|
||||
} catch (e) {
|
||||
print('Failed to parse/compute bounds for floor geojson: $e');
|
||||
setState(() {}); // still show the map with whatever we have
|
||||
}
|
||||
}
|
||||
|
||||
LatLngBounds _computeBoundsFromGeoJson(Map<String, dynamic> geojson) {
|
||||
final features = (geojson['features'] as List<dynamic>? ?? []);
|
||||
|
||||
double? minLng, minLat, maxLng, maxLat;
|
||||
|
||||
void visit(dynamic node) {
|
||||
if (node is List && node.isNotEmpty && node.first is num) {
|
||||
final lng = (node[0] as num).toDouble();
|
||||
final lat = (node[1] as num).toDouble();
|
||||
minLng = (minLng == null || lng < minLng!) ? lng : minLng;
|
||||
maxLng = (maxLng == null || lng > maxLng!) ? lng : maxLng;
|
||||
minLat = (minLat == null || lat < minLat!) ? lat : minLat;
|
||||
maxLat = (maxLat == null || lat > maxLat!) ? lat : maxLat;
|
||||
} else if (node is List) {
|
||||
for (final child in node) {
|
||||
visit(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final feature in features) {
|
||||
final geometry = feature['geometry'] as Map<String, dynamic>?;
|
||||
final coordinates = geometry?['coordinates'];
|
||||
if (coordinates == null) continue;
|
||||
visit(coordinates);
|
||||
}
|
||||
|
||||
if (minLng == null || minLat == null || maxLng == null || maxLat == null) {
|
||||
throw StateError('No coordinates found in floor geojson — cannot compute bounds.');
|
||||
}
|
||||
|
||||
return LatLngBounds(
|
||||
LatLng(minLat!, minLng!),
|
||||
LatLng(maxLat!, maxLng!),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget mapWidget = FlutterMap(
|
||||
mapController: mapController,
|
||||
options: MapOptions(initialCenter: _fallbackCenter, initialZoom: 16.0),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
userAgentPackageName: 'com.hmg.atoms',
|
||||
),
|
||||
if (_geojson != null) ...[
|
||||
GeoJsonLayer.memory(
|
||||
_geojson!,
|
||||
styleDefaults: GeoJsonStyleDefaults.leaflet,
|
||||
),
|
||||
MarkerLayer(markers: markers),
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
return widget.inAppView
|
||||
? mapWidget
|
||||
: Scaffold(
|
||||
appBar: const DefaultAppBar(title: "Live Asset Tracking"),
|
||||
body: Stack(
|
||||
children: [mapWidget],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,218 @@
|
||||
class AssetTrackingModel {
|
||||
int? id;
|
||||
String? label;
|
||||
String? serialNumber;
|
||||
int? group;
|
||||
Type? type;
|
||||
Type? department;
|
||||
Type? status;
|
||||
Location? location;
|
||||
Tag? tag;
|
||||
Alerts? alerts;
|
||||
|
||||
AssetTrackingModel({this.id, this.label, this.serialNumber, this.group, this.type, this.department, this.status, this.location, this.tag, this.alerts});
|
||||
|
||||
AssetTrackingModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
label = json['label'];
|
||||
serialNumber = json['serialNumber'];
|
||||
group = json['group'];
|
||||
type = json['type'] != null ? new Type.fromJson(json['type']) : null;
|
||||
department = json['department'] != null ? new Type.fromJson(json['department']) : null;
|
||||
status = json['status'] != null ? new Type.fromJson(json['status']) : null;
|
||||
location = json['location'] != null ? new Location.fromJson(json['location']) : null;
|
||||
tag = json['tag'] != null ? new Tag.fromJson(json['tag']) : null;
|
||||
alerts = json['alerts'] != null ? new Alerts.fromJson(json['alerts']) : null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['id'] = this.id;
|
||||
data['label'] = this.label;
|
||||
data['serialNumber'] = this.serialNumber;
|
||||
data['group'] = this.group;
|
||||
if (this.type != null) {
|
||||
data['type'] = this.type!.toJson();
|
||||
}
|
||||
if (this.department != null) {
|
||||
data['department'] = this.department!.toJson();
|
||||
}
|
||||
if (this.status != null) {
|
||||
data['status'] = this.status!.toJson();
|
||||
}
|
||||
if (this.location != null) {
|
||||
data['location'] = this.location!.toJson();
|
||||
}
|
||||
if (this.tag != null) {
|
||||
data['tag'] = this.tag!.toJson();
|
||||
}
|
||||
if (this.alerts != null) {
|
||||
data['alerts'] = this.alerts!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Type {
|
||||
int? id;
|
||||
String? name;
|
||||
|
||||
Type({this.id, this.name});
|
||||
|
||||
Type.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 {
|
||||
bool? isLive;
|
||||
String? lastSeen;
|
||||
Type? venue;
|
||||
Floor? floor;
|
||||
Zone? zone;
|
||||
double? longitude;
|
||||
double? latitude;
|
||||
double? x;
|
||||
double? y;
|
||||
|
||||
Location({this.isLive, this.lastSeen, this.venue, this.floor, this.zone, this.longitude, this.latitude, this.x, this.y});
|
||||
|
||||
Location.fromJson(Map<String, dynamic> json) {
|
||||
isLive = json['isLive'];
|
||||
lastSeen = json['lastSeen'];
|
||||
venue = json['venue'] != null ? new Type.fromJson(json['venue']) : null;
|
||||
floor = json['floor'] != null ? new Floor.fromJson(json['floor']) : null;
|
||||
zone = json['zone'] != null ? new Zone.fromJson(json['zone']) : null;
|
||||
longitude = json['longitude'];
|
||||
latitude = json['latitude'];
|
||||
x = json['x'];
|
||||
y = json['y'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['isLive'] = this.isLive;
|
||||
data['lastSeen'] = this.lastSeen;
|
||||
if (this.venue != null) {
|
||||
data['venue'] = this.venue!.toJson();
|
||||
}
|
||||
if (this.floor != null) {
|
||||
data['floor'] = this.floor!.toJson();
|
||||
}
|
||||
if (this.zone != null) {
|
||||
data['zone'] = this.zone!.toJson();
|
||||
}
|
||||
data['longitude'] = this.longitude;
|
||||
data['latitude'] = this.latitude;
|
||||
data['x'] = this.x;
|
||||
data['y'] = this.y;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Floor {
|
||||
int? id;
|
||||
String? name;
|
||||
String? label;
|
||||
|
||||
Floor({this.id, this.name, this.label});
|
||||
|
||||
Floor.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;
|
||||
}
|
||||
}
|
||||
|
||||
class Zone {
|
||||
int? id;
|
||||
String? name;
|
||||
Type? zoneType;
|
||||
|
||||
Zone({this.id, this.name, this.zoneType});
|
||||
|
||||
Zone.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
zoneType = json['zoneType'] != null ? new Type.fromJson(json['zoneType']) : null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['id'] = this.id;
|
||||
data['name'] = this.name;
|
||||
if (this.zoneType != null) {
|
||||
data['zoneType'] = this.zoneType!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Tag {
|
||||
int? id;
|
||||
String? macAddress;
|
||||
int? batteryPercentage;
|
||||
|
||||
Tag({this.id, this.macAddress, this.batteryPercentage});
|
||||
|
||||
Tag.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
macAddress = json['macAddress'];
|
||||
batteryPercentage = json['batteryPercentage'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['id'] = this.id;
|
||||
data['macAddress'] = this.macAddress;
|
||||
data['batteryPercentage'] = this.batteryPercentage;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Alerts {
|
||||
int? count;
|
||||
String? lastCreationDate;
|
||||
String? mostSevereCreationDate;
|
||||
String? mostSevereTriggerType;
|
||||
String? mostSeverity;
|
||||
String? mostSevereRuleName;
|
||||
|
||||
Alerts({this.count, this.lastCreationDate, this.mostSevereCreationDate, this.mostSevereTriggerType, this.mostSeverity, this.mostSevereRuleName});
|
||||
|
||||
Alerts.fromJson(Map<String, dynamic> json) {
|
||||
count = json['count'];
|
||||
lastCreationDate = json['lastCreationDate'];
|
||||
mostSevereCreationDate = json['mostSevereCreationDate'];
|
||||
mostSevereTriggerType = json['mostSevereTriggerType'];
|
||||
mostSeverity = json['mostSeverity'];
|
||||
mostSevereRuleName = json['mostSevereRuleName'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['count'] = this.count;
|
||||
data['lastCreationDate'] = this.lastCreationDate;
|
||||
data['mostSevereCreationDate'] = this.mostSevereCreationDate;
|
||||
data['mostSevereTriggerType'] = this.mostSevereTriggerType;
|
||||
data['mostSeverity'] = this.mostSeverity;
|
||||
data['mostSevereRuleName'] = this.mostSevereRuleName;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
class FloorMapModel {
|
||||
int? id;
|
||||
String? mapUrl;
|
||||
String? geojsonUrl;
|
||||
String? mapBase64;
|
||||
Map<String, dynamic>? geojsonData;
|
||||
|
||||
FloorMapModel({this.id, this.mapUrl, this.geojsonUrl, this.mapBase64, this.geojsonData});
|
||||
|
||||
FloorMapModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
mapUrl = json['mapUrl'];
|
||||
geojsonUrl = json['geojsonUrl'];
|
||||
mapBase64 = json['mapBase64'];
|
||||
geojsonData = json['geojsonData'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['id'] = this.id;
|
||||
data['mapUrl'] = this.mapUrl;
|
||||
data['geojsonUrl'] = this.geojsonUrl;
|
||||
data['mapBase64'] = this.mapBase64;
|
||||
if (this.geojsonData != null) {
|
||||
// data['geojsonData'] = this.geojsonData!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// class GeojsonData {
|
||||
// String? type;
|
||||
// List<Features>? features;
|
||||
//
|
||||
// GeojsonData({this.type, this.features});
|
||||
//
|
||||
// GeojsonData.fromJson(Map<String, dynamic> json) {
|
||||
// type = json['type'];
|
||||
// if (json['features'] != null) {
|
||||
// features = <Features>[];
|
||||
// json['features'].forEach((v) { features!.add(new Features.fromJson(v)); });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['type'] = this.type;
|
||||
// if (this.features != null) {
|
||||
// data['features'] = this.features!.map((v) => v.toJson()).toList();
|
||||
// }
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
|
||||
// class Features {
|
||||
// String? type;
|
||||
// Properties? properties;
|
||||
// Geometry? geometry;
|
||||
//
|
||||
// Features({this.type, this.properties, this.geometry});
|
||||
//
|
||||
// Features.fromJson(Map<String, dynamic> json) {
|
||||
// type = json['type'];
|
||||
// properties = json['properties'] != null ? new Properties.fromJson(json['properties']) : null;
|
||||
// geometry = json['geometry'] != null ? new Geometry.fromJson(json['geometry']) : null;
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['type'] = this.type;
|
||||
// if (this.properties != null) {
|
||||
// data['properties'] = this.properties!.toJson();
|
||||
// }
|
||||
// if (this.geometry != null) {
|
||||
// data['geometry'] = this.geometry!.toJson();
|
||||
// }
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// class Properties {
|
||||
// int? ff;
|
||||
// int? id;
|
||||
// String? fill;
|
||||
// int? fillOpacity;
|
||||
// String? stroke;
|
||||
// int? strokeOpacity;
|
||||
// int? strokeWidth;
|
||||
//
|
||||
// Properties({this.ff, this.id, this.fill, this.fillOpacity, this.stroke, this.strokeOpacity, this.strokeWidth});
|
||||
//
|
||||
// Properties.fromJson(Map<String, dynamic> json) {
|
||||
// ff = json['ff'];
|
||||
// id = json['id'];
|
||||
// fill = json['fill'];
|
||||
// fillOpacity = json['fillOpacity'];
|
||||
// stroke = json['stroke'];
|
||||
// strokeOpacity = json['strokeOpacity'];
|
||||
// strokeWidth = json['strokeWidth'];
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['ff'] = this.ff;
|
||||
// data['id'] = this.id;
|
||||
// data['fill'] = this.fill;
|
||||
// data['fillOpacity'] = this.fillOpacity;
|
||||
// data['stroke'] = this.stroke;
|
||||
// data['strokeOpacity'] = this.strokeOpacity;
|
||||
// data['strokeWidth'] = this.strokeWidth;
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
|
||||
// class Geometry {
|
||||
// String? type;
|
||||
// List<List>? coordinates;
|
||||
//
|
||||
// Geometry({this.type, this.coordinates});
|
||||
//
|
||||
// Geometry.fromJson(Map<String, dynamic> json) {
|
||||
// type = json['type'];
|
||||
// if (json['coordinates'] != null) {
|
||||
// coordinates = <List>[];
|
||||
// json['coordinates'].forEach((v) { coordinates!.add(new List.fromJson(v)); });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['type'] = this.type;
|
||||
// if (this.coordinates != null) {
|
||||
// data['coordinates'] = this.coordinates!.map((v) => v.toJson()).toList();
|
||||
// }
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// class Coordinates {
|
||||
//
|
||||
//
|
||||
// Coordinates({});
|
||||
//
|
||||
// Coordinates.fromJson(Map<String, dynamic> json) {
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
Loading…
Reference in New Issue