diff --git a/lib/components/MapKmlElement.dart b/lib/components/MapKmlElement.dart index d3f81a6..62288be 100644 --- a/lib/components/MapKmlElement.dart +++ b/lib/components/MapKmlElement.dart @@ -19,13 +19,15 @@ class Mapkmlelement extends StatefulWidget { required this.mapMovementController, required this.elementIndex, required this.handlerCallback(CallbackHandler handler), - required this.submitData}); + required this.submitData, + this.hideFullScreen}); MapPosition position; MapMovementController mapMovementController; int elementIndex; final Function handlerCallback; Function(KmlElement) submitData; + bool? hideFullScreen; @override State createState() => _MapkmlelementState(); @@ -136,24 +138,27 @@ class _MapkmlelementState extends State { ), ), ), - Align( - alignment: Alignment.topRight, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: IconButton( - onPressed: () async { - print("runs"); - var kmlElement = await Get.to(() => MapKmlFullscreen( - position: widget.position, - mapMovementController: widget.mapMovementController, - elementIndex: widget.elementIndex, - submitData: widget.submitData)); - widget.submitData(kmlElement); - }, - icon: const Icon( - Icons.fullscreen_rounded, - color: Colors.white, - size: 50.0, + Visibility( + visible: !(widget.hideFullScreen ?? false), + child: Align( + alignment: Alignment.topRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: IconButton( + onPressed: () async { + print("runs"); + var kmlElement = await Get.to(() => MapKmlFullscreen( + position: widget.position, + mapMovementController: widget.mapMovementController, + elementIndex: widget.elementIndex, + submitData: widget.submitData)); + widget.submitData(kmlElement); + }, + icon: const Icon( + Icons.fullscreen_rounded, + color: Colors.white, + size: 50.0, + ), ), ), ), diff --git a/lib/components/location_selector.dart b/lib/components/location_selector.dart index 582f68d..aca6a81 100644 --- a/lib/components/location_selector.dart +++ b/lib/components/location_selector.dart @@ -9,16 +9,18 @@ import 'package:super_liquid_galaxy_controller/data_class/country_data.dart'; import 'package:super_liquid_galaxy_controller/screens/location_picker.dart'; import 'package:super_liquid_galaxy_controller/utils/galaxy_colors.dart'; import 'package:geocoding/geocoding.dart'; +import 'package:super_liquid_galaxy_controller/utils/tour_controller.dart'; import '../generated/assets.dart'; class LocationSelector extends StatefulWidget { LocationSelector( - {super.key, this.height, this.width, this.iconSize, this.searchSize, required this.submitData}); + {super.key, this.height, this.width, this.iconSize, this.searchSize, required this.submitData,required this.tourController}); double? height; double? width; double? iconSize; double? searchSize; + TourController tourController; Function(Coordinates,String) submitData; @override @@ -29,7 +31,6 @@ class _LocationSelectorState extends State { late List jsonList; late List dataList; late String label; - late String selectedCountry; late String selectedState; @@ -39,6 +40,7 @@ class _LocationSelectorState extends State { selectedCountry = "India"; selectedState = "West Bengal"; label = "$selectedCountry \n$selectedState"; + widget.tourController.setSearchAround(Coordinates(latitude: 22.9867569, longitude: 87.854975), label); initializeJsonList(); super.initState(); } @@ -286,14 +288,16 @@ class _LocationSelectorState extends State { const SizedBox( width: 16.0, ), - Text( - label, - style: const TextStyle( - color: Colors.white, - fontSize: 30.0, - fontWeight: FontWeight.w700, - ), - ), + Obx((){ + return Text( + widget.tourController.label.value, + style: const TextStyle( + color: Colors.white, + fontSize: 30.0, + fontWeight: FontWeight.w700, + ), + ); + }) ], )), ), diff --git a/lib/components/navisland.dart b/lib/components/navisland.dart index 6ff93dd..ab2d69d 100644 --- a/lib/components/navisland.dart +++ b/lib/components/navisland.dart @@ -174,8 +174,8 @@ class NavIsland extends StatelessWidget { color: Colors.transparent, child: InkWell( onTap: () async { - LatLng start = LatLng(1, 5); - LatLng end = LatLng(7, 11); + LatLng start = LatLng(7, 11); + LatLng end = LatLng(1, 5); double dashLength = 10000.0; // Length of each dash in meters diff --git a/lib/data_class/coordinate.dart b/lib/data_class/coordinate.dart index 9ae1ef0..b3bde54 100644 --- a/lib/data_class/coordinate.dart +++ b/lib/data_class/coordinate.dart @@ -1,4 +1,5 @@ import 'package:latlong2/latlong.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart' as mp; class Coordinates { late double latitude; @@ -13,6 +14,14 @@ class Coordinates { longitude = point.longitude; } + Coordinates.fromLatLngMap(mp.LatLng point) { + latitude = point.latitude; + longitude = point.longitude; + + longitude += 360.0; + longitude %= 360.0; + } + // Override toString for better debugging output @override String toString() { diff --git a/lib/data_class/geo_reversecode_response.dart b/lib/data_class/geo_reversecode_response.dart index 436e8d1..cd42864 100644 --- a/lib/data_class/geo_reversecode_response.dart +++ b/lib/data_class/geo_reversecode_response.dart @@ -91,8 +91,8 @@ class Results { this.datasource = json["datasource"] == null ? null : Datasource.fromJson(json["datasource"]); this.country = json["country"]; this.countryCode = json["country_code"]; - this.lon = json["lon"]; - this.lat = json["lat"]; + this.lon = json["lon"]?.toDouble(); + this.lat = json["lat"]?.toDouble(); this.distance = json["distance"]?.toDouble(); this.resultType = json["result_type"]; this.formatted = json["formatted"]; diff --git a/lib/data_class/place_details_response.dart b/lib/data_class/place_details_response.dart new file mode 100644 index 0000000..99aea50 --- /dev/null +++ b/lib/data_class/place_details_response.dart @@ -0,0 +1,417 @@ +import 'coordinate.dart'; + +class PlaceDetailsResponse { + String? type; + List? features; + + PlaceDetailsResponse({this.type, this.features}); + + PlaceDetailsResponse.fromJson(Map json) { + if (json["type"] is String) this.type = json["type"]; + if (json["features"] is List) + this.features = json["features"] == null + ? null + : (json["features"] as List) + .map((e) => Features.fromJson(e)) + .toList(); + } + + Map toJson() { + final Map data = new Map(); + data["type"] = this.type; + if (this.features != null) + data["features"] = this.features?.map((e) => e.toJson()).toList(); + return data; + } + + @override + String toString() { + return 'PlaceDetailsResponse{type: $type, features: $features}'; + } +} + +class Features { + String? type; + Properties? properties; + Geometry? geometry; + + Features({this.type, this.properties, this.geometry}); + + Features.fromJson(Map json) { + if (json["type"] is String) this.type = json["type"]; + if (json["properties"] is Map) + this.properties = json["properties"] == null + ? null + : Properties.fromJson(json["properties"]); + if (json["geometry"] is Map) + this.geometry = + json["geometry"] == null ? null : Geometry.fromJson(json["geometry"]); + } + + Map toJson() { + final Map data = new Map(); + data["type"] = this.type; + if (this.properties != null) data["properties"] = this.properties?.toJson(); + if (this.geometry != null) data["geometry"] = this.geometry?.toJson(); + return data; + } + + @override + String toString() { + return 'Features{type: $type, properties: $properties, geometry: $geometry}'; + } +} + +class Geometry { + String? type; + List? coordinates; + List>? polygonList; + List>>? multiPolygonList; + Geometry({this.type, this.coordinates}); + + Geometry.fromJson(Map json) { + if (json["type"] is String) this.type = json["type"]; + print(type); + if (json["coordinates"] is List) { + this.coordinates = json["coordinates"] == null + ? null + : List.from(json["coordinates"]); + + if (coordinates != null && coordinates!.isNotEmpty) { + + + if (type?.compareTo("Polygon")==0) { + polygonList = []; + for (List polygon in coordinates!) { + List coordinateList = []; + for (List item in polygon) { + //print(item); + coordinateList + .add(Coordinates(latitude: double.parse(item[1].toString()), + longitude: double.parse(item[0].toString()))); + } + polygonList?.add(coordinateList); + } + } + else + { + if(type?.compareTo("MultiPolygon")==0) + { + multiPolygonList =[]; + for(List multipolygon in coordinates!) { + List> list = []; + for (List polygon in multipolygon) { + List coordinateList = []; + for (List item in polygon) { + //print(item); + coordinateList + .add(Coordinates( + latitude: double.parse(item[1].toString()), + longitude: double.parse(item[0].toString()))); + } + list.add(coordinateList); + } + multiPolygonList?.add(list); + } + } + } + } + } + } + Map toJson() { + final Map data = new Map(); + data["type"] = this.type; + if (this.coordinates != null) data["coordinates"] = this.coordinates; + return data; + } + + @override + String toString() { + return 'Geometry{type: $type, coordinates: $coordinates}'; + } +} + +class Properties { + String? featureType; + List? categories; + Datasource? datasource; + String? state; + String? country; + String? countryCode; + String? formatted; + String? addressLine1; + String? addressLine2; + double? lat; + double? lon; + String? name; + Timezone? timezone; + String? placeId; + + Properties( + {this.featureType, + this.categories, + this.datasource, + this.state, + this.country, + this.countryCode, + this.formatted, + this.addressLine1, + this.addressLine2, + this.lat, + this.lon, + this.name, + this.timezone, + this.placeId}); + + Properties.fromJson(Map json) { + if (json["feature_type"] is String) this.featureType = json["feature_type"]; + if (json["categories"] is List) + this.categories = json["categories"] == null + ? null + : List.from(json["categories"]); + if (json["datasource"] is Map) + this.datasource = json["datasource"] == null + ? null + : Datasource.fromJson(json["datasource"]); + if (json["state"] is String) this.state = json["state"]; + if (json["country"] is String) this.country = json["country"]; + if (json["country_code"] is String) this.countryCode = json["country_code"]; + if (json["formatted"] is String) this.formatted = json["formatted"]; + if (json["address_line1"] is String) + this.addressLine1 = json["address_line1"]; + if (json["address_line2"] is String) + this.addressLine2 = json["address_line2"]; + if (json["lat"] is double) this.lat = json["lat"]; + if (json["lon"] is double) this.lon = json["lon"]; + if (json["name"] is String) this.name = json["name"]; + if (json["timezone"] is Map) + this.timezone = + json["timezone"] == null ? null : Timezone.fromJson(json["timezone"]); + if (json["place_id"] is String) this.placeId = json["place_id"]; + } + + Map toJson() { + final Map data = new Map(); + data["feature_type"] = this.featureType; + if (this.categories != null) data["categories"] = this.categories; + if (this.datasource != null) data["datasource"] = this.datasource?.toJson(); + data["state"] = this.state; + data["country"] = this.country; + data["country_code"] = this.countryCode; + data["formatted"] = this.formatted; + data["address_line1"] = this.addressLine1; + data["address_line2"] = this.addressLine2; + data["lat"] = this.lat; + data["lon"] = this.lon; + data["name"] = this.name; + if (this.timezone != null) data["timezone"] = this.timezone?.toJson(); + data["place_id"] = this.placeId; + return data; + } + + @override + String toString() { + return 'Properties{featureType: $featureType, categories: $categories, datasource: $datasource, state: $state, country: $country, countryCode: $countryCode, formatted: $formatted, addressLine1: $addressLine1, addressLine2: $addressLine2, lat: $lat, lon: $lon, name: $name, timezone: $timezone, placeId: $placeId}'; + } +} + +class Timezone { + String? name; + String? offsetStd; + int? offsetStdSeconds; + String? offsetDst; + int? offsetDstSeconds; + + Timezone( + {this.name, + this.offsetStd, + this.offsetStdSeconds, + this.offsetDst, + this.offsetDstSeconds}); + + Timezone.fromJson(Map json) { + if (json["name"] is String) this.name = json["name"]; + if (json["offset_STD"] is String) this.offsetStd = json["offset_STD"]; + if (json["offset_STD_seconds"] is int) + this.offsetStdSeconds = json["offset_STD_seconds"]; + if (json["offset_DST"] is String) this.offsetDst = json["offset_DST"]; + if (json["offset_DST_seconds"] is int) + this.offsetDstSeconds = json["offset_DST_seconds"]; + } + + Map toJson() { + final Map data = new Map(); + data["name"] = this.name; + data["offset_STD"] = this.offsetStd; + data["offset_STD_seconds"] = this.offsetStdSeconds; + data["offset_DST"] = this.offsetDst; + data["offset_DST_seconds"] = this.offsetDstSeconds; + return data; + } + + @override + String toString() { + return 'Timezone{name: $name, offsetStd: $offsetStd, offsetStdSeconds: $offsetStdSeconds, offsetDst: $offsetDst, offsetDstSeconds: $offsetDstSeconds}'; + } +} + +class Datasource { + String? sourcename; + String? attribution; + String? license; + String? url; + Raw? raw; + + Datasource( + {this.sourcename, this.attribution, this.license, this.url, this.raw}); + + Datasource.fromJson(Map json) { + if (json["sourcename"] is String) this.sourcename = json["sourcename"]; + if (json["attribution"] is String) this.attribution = json["attribution"]; + if (json["license"] is String) this.license = json["license"]; + if (json["url"] is String) this.url = json["url"]; + if (json["raw"] is Map) + this.raw = json["raw"] == null ? null : Raw.fromJson(json["raw"]); + } + + Map toJson() { + final Map data = new Map(); + data["sourcename"] = this.sourcename; + data["attribution"] = this.attribution; + data["license"] = this.license; + data["url"] = this.url; + if (this.raw != null) data["raw"] = this.raw?.toJson(); + return data; + } + + @override + String toString() { + return 'Datasource{sourcename: $sourcename, attribution: $attribution, license: $license, url: $url, raw: $raw}'; + } +} + +class Raw { + String? ref; + String? name; + String? type; + int? osmId; + String? nameel; + String? namees; + String? namehe; + String? nameja; + String? nameru; + String? nameuk; + String? namezh; + String? boundary; + String? osmType; + String? timezone; + String? wikidata; + String? iso31662; + String? wikipedia; + String? placeRef; + String? shortName; + int? adminLevel; + String? countryCode; + String? linkedPlace; + String? isIncountry; + String? officialName; + String? placeNameeo; + String? placeNameabbreviation; + + Raw( + {this.ref, + this.name, + this.type, + this.osmId, + this.nameel, + this.namees, + this.namehe, + this.nameja, + this.nameru, + this.nameuk, + this.namezh, + this.boundary, + this.osmType, + this.timezone, + this.wikidata, + this.iso31662, + this.wikipedia, + this.placeRef, + this.shortName, + this.adminLevel, + this.countryCode, + this.linkedPlace, + this.isIncountry, + this.officialName, + this.placeNameeo, + this.placeNameabbreviation}); + + Raw.fromJson(Map json) { + if (json["ref"] is String) this.ref = json["ref"]; + if (json["name"] is String) this.name = json["name"]; + if (json["type"] is String) this.type = json["type"]; + if (json["osm_id"] is int) this.osmId = json["osm_id"]; + if (json["name:el"] is String) this.nameel = json["name:el"]; + if (json["name:es"] is String) this.namees = json["name:es"]; + if (json["name:he"] is String) this.namehe = json["name:he"]; + if (json["name:ja"] is String) this.nameja = json["name:ja"]; + if (json["name:ru"] is String) this.nameru = json["name:ru"]; + if (json["name:uk"] is String) this.nameuk = json["name:uk"]; + if (json["name:zh"] is String) this.namezh = json["name:zh"]; + if (json["boundary"] is String) this.boundary = json["boundary"]; + if (json["osm_type"] is String) this.osmType = json["osm_type"]; + if (json["timezone"] is String) this.timezone = json["timezone"]; + if (json["wikidata"] is String) this.wikidata = json["wikidata"]; + if (json["ISO3166-2"] is String) this.iso31662 = json["ISO3166-2"]; + if (json["wikipedia"] is String) this.wikipedia = json["wikipedia"]; + if (json["_place_ref"] is String) this.placeRef = json["_place_ref"]; + if (json["short_name"] is String) this.shortName = json["short_name"]; + if (json["admin_level"] is int) this.adminLevel = json["admin_level"]; + if (json["country_code"] is String) this.countryCode = json["country_code"]; + if (json["linked_place"] is String) this.linkedPlace = json["linked_place"]; + if (json["is_in:country"] is String) + this.isIncountry = json["is_in:country"]; + if (json["official_name"] is String) + this.officialName = json["official_name"]; + if (json["_place_name:eo"] is String) + this.placeNameeo = json["_place_name:eo"]; + if (json["_place_name:abbreviation"] is String) + this.placeNameabbreviation = json["_place_name:abbreviation"]; + } + + Map toJson() { + final Map data = new Map(); + data["ref"] = this.ref; + data["name"] = this.name; + data["type"] = this.type; + data["osm_id"] = this.osmId; + data["name:el"] = this.nameel; + data["name:es"] = this.namees; + data["name:he"] = this.namehe; + data["name:ja"] = this.nameja; + data["name:ru"] = this.nameru; + data["name:uk"] = this.nameuk; + data["name:zh"] = this.namezh; + data["boundary"] = this.boundary; + data["osm_type"] = this.osmType; + data["timezone"] = this.timezone; + data["wikidata"] = this.wikidata; + data["ISO3166-2"] = this.iso31662; + data["wikipedia"] = this.wikipedia; + data["_place_ref"] = this.placeRef; + data["short_name"] = this.shortName; + data["admin_level"] = this.adminLevel; + data["country_code"] = this.countryCode; + data["linked_place"] = this.linkedPlace; + data["is_in:country"] = this.isIncountry; + data["official_name"] = this.officialName; + data["_place_name:eo"] = this.placeNameeo; + data["_place_name:abbreviation"] = this.placeNameabbreviation; + return data; + } + + @override + String toString() { + return 'Raw{ref: $ref, name: $name, type: $type, osmId: $osmId, nameel: $nameel, namees: $namees, namehe: $namehe, nameja: $nameja, nameru: $nameru, nameuk: $nameuk, namezh: $namezh, boundary: $boundary, osmType: $osmType, timezone: $timezone, wikidata: $wikidata, iso31662: $iso31662, wikipedia: $wikipedia, placeRef: $placeRef, shortName: $shortName, adminLevel: $adminLevel, countryCode: $countryCode, linkedPlace: $linkedPlace, isIncountry: $isIncountry, officialName: $officialName, placeNameeo: $placeNameeo, placeNameabbreviation: $placeNameabbreviation}'; + } +} diff --git a/lib/data_class/place_response.dart b/lib/data_class/place_response.dart new file mode 100644 index 0000000..182f5ce --- /dev/null +++ b/lib/data_class/place_response.dart @@ -0,0 +1,379 @@ +import 'coordinate.dart'; + +class PlaceResponse { + String? type; + List? features; + + PlaceResponse({this.type, this.features}); + + PlaceResponse.fromJson(Map json) { + if(json["type"] is String) + this.type = json["type"]; + if(json["features"] is List) + this.features = json["features"] == null ? null : (json["features"] as List).map((e)=>Features.fromJson(e)).toList(); + } + + Map toJson() { + final Map data = new Map(); + data["type"] = this.type; + if(this.features != null) + data["features"] = this.features?.map((e)=>e.toJson()).toList(); + return data; + } + + @override + String toString() { + return 'PlaceResponse{type: $type, features: $features}'; + } +} + +class Features { + String? type; + Properties? properties; + Geometry? geometry; + + Features({this.type, this.properties, this.geometry}); + + Features.fromJson(Map json) { + if(json["type"] is String) + this.type = json["type"]; + if(json["properties"] is Map) + this.properties = json["properties"] == null ? null : Properties.fromJson(json["properties"]); + if(json["geometry"] is Map) + this.geometry = json["geometry"] == null ? null : Geometry.fromJson(json["geometry"]); + } + + Map toJson() { + final Map data = new Map(); + data["type"] = this.type; + if(this.properties != null) + data["properties"] = this.properties?.toJson(); + if(this.geometry != null) + data["geometry"] = this.geometry?.toJson(); + return data; + } + + @override + String toString() { + return 'Features{type: $type, properties: $properties, geometry: $geometry}'; + } +} + +class Geometry { + String? type; + List? coordinates; + Coordinates? point; + + + Geometry({this.type, this.coordinates}); + + Geometry.fromJson(Map json) { + if(json["type"] is String) + this.type = json["type"]; + if(json["coordinates"] is List) + this.coordinates = json["coordinates"] == null ? null : List.from(json["coordinates"]); + if(coordinates!= null && coordinates!.isNotEmpty) + { + point = Coordinates(latitude: double.parse(coordinates![1].toString()) , longitude:double.parse(coordinates![0].toString()) ); + } + } + + Map toJson() { + final Map data = new Map(); + data["type"] = this.type; + if(this.coordinates != null) + data["coordinates"] = this.coordinates; + return data; + } + + @override + String toString() { + return 'Geometry{type: $type, coordinates: $coordinates}'; + } +} + +class Properties { + String? name; + String? country; + String? countryCode; + String? state; + String? county; + String? city; + double? lon; + double? lat; + String? stateCode; + String? formatted; + String? addressLine1; + String? addressLine2; + List? categories; + List? details; + Datasource? datasource; + String? website; + String? operator; + RefOther? refOther; + Contact? contact; + WikiAndMedia? wikiAndMedia; + Historic? historic; + Heritage? heritage; + String? placeId; + + Properties({this.name, this.country, this.countryCode, this.state, this.county, this.city, this.lon, this.lat, this.stateCode, this.formatted, this.addressLine1, this.addressLine2, this.categories, this.details, this.datasource, this.website, this.operator, this.refOther, this.contact, this.wikiAndMedia, this.historic, this.heritage, this.placeId}); + + Properties.fromJson(Map json) { + if(json["name"] is String) + this.name = json["name"]; + if(json["country"] is String) + this.country = json["country"]; + if(json["country_code"] is String) + this.countryCode = json["country_code"]; + if(json["state"] is String) + this.state = json["state"]; + if(json["county"] is String) + this.county = json["county"]; + if(json["city"] is String) + this.city = json["city"]; + if(json["lon"] is double) + this.lon = json["lon"]; + if(json["lat"] is double) + this.lat = json["lat"]; + if(json["state_code"] is String) + this.stateCode = json["state_code"]; + if(json["formatted"] is String) + this.formatted = json["formatted"]; + if(json["address_line1"] is String) + this.addressLine1 = json["address_line1"]; + if(json["address_line2"] is String) + this.addressLine2 = json["address_line2"]; + if(json["categories"] is List) + this.categories = json["categories"] == null ? null : List.from(json["categories"]); + if(json["details"] is List) + this.details = json["details"] == null ? null : List.from(json["details"]); + if(json["datasource"] is Map) + this.datasource = json["datasource"] == null ? null : Datasource.fromJson(json["datasource"]); + if(json["website"] is String) + this.website = json["website"]; + if(json["operator"] is String) + this.operator = json["operator"]; + if(json["ref_other"] is Map) + this.refOther = json["ref_other"] == null ? null : RefOther.fromJson(json["ref_other"]); + if(json["contact"] is Map) + this.contact = json["contact"] == null ? null : Contact.fromJson(json["contact"]); + if(json["wiki_and_media"] is Map) + this.wikiAndMedia = json["wiki_and_media"] == null ? null : WikiAndMedia.fromJson(json["wiki_and_media"]); + if(json["historic"] is Map) + this.historic = json["historic"] == null ? null : Historic.fromJson(json["historic"]); + if(json["heritage"] is Map) + this.heritage = json["heritage"] == null ? null : Heritage.fromJson(json["heritage"]); + if(json["place_id"] is String) + this.placeId = json["place_id"]; + } + + Map toJson() { + final Map data = new Map(); + data["name"] = this.name; + data["country"] = this.country; + data["country_code"] = this.countryCode; + data["state"] = this.state; + data["county"] = this.county; + data["city"] = this.city; + data["lon"] = this.lon; + data["lat"] = this.lat; + data["state_code"] = this.stateCode; + data["formatted"] = this.formatted; + data["address_line1"] = this.addressLine1; + data["address_line2"] = this.addressLine2; + if(this.categories != null) + data["categories"] = this.categories; + if(this.details != null) + data["details"] = this.details; + if(this.datasource != null) + data["datasource"] = this.datasource?.toJson(); + data["website"] = this.website; + data["operator"] = this.operator; + if(this.refOther != null) + data["ref_other"] = this.refOther?.toJson(); + if(this.contact != null) + data["contact"] = this.contact?.toJson(); + if(this.wikiAndMedia != null) + data["wiki_and_media"] = this.wikiAndMedia?.toJson(); + if(this.historic != null) + data["historic"] = this.historic?.toJson(); + if(this.heritage != null) + data["heritage"] = this.heritage?.toJson(); + data["place_id"] = this.placeId; + return data; + } + + @override + String toString() { + return 'Properties{name: $name, country: $country, countryCode: $countryCode, state: $state, county: $county, city: $city, lon: $lon, lat: $lat, stateCode: $stateCode, formatted: $formatted, addressLine1: $addressLine1, addressLine2: $addressLine2, categories: $categories, details: $details, datasource: $datasource, website: $website, operator: $operator, refOther: $refOther, contact: $contact, wikiAndMedia: $wikiAndMedia, historic: $historic, heritage: $heritage, placeId: $placeId}'; + } +} + +class Heritage { + int? level; + String? operator; + int? ref; + + Heritage({this.level, this.operator, this.ref}); + + Heritage.fromJson(Map json) { + if(json["level"] is int) + this.level = json["level"]; + if(json["operator"] is String) + this.operator = json["operator"]; + if(json["ref"] is int) + this.ref = json["ref"]; + } + + Map toJson() { + final Map data = new Map(); + data["level"] = this.level; + data["operator"] = this.operator; + data["ref"] = this.ref; + return data; + } + + @override + String toString() { + return 'Heritage{level: $level, operator: $operator, ref: $ref}'; + } +} + +class Historic { + int? wikidata; + String? operator; + int? ref; + + Historic({this.wikidata, this.operator, this.ref}); + + Historic.fromJson(Map json) { + if(json["wikidata"] is int) + this.wikidata = json["wikidata"]; + if(json["operator"] is String) + this.operator = json["operator"]; + if(json["ref"] is int) + this.ref = json["ref"]; + } + + Map toJson() { + final Map data = new Map(); + data["wikidata"] = this.wikidata; + data["operator"] = this.operator; + data["ref"] = this.ref; + return data; + } + + @override + String toString() { + return 'Historic{wikidata: $wikidata, operator: $operator, ref: $ref}'; + } +} + +class WikiAndMedia { + String? image; + + WikiAndMedia({this.image}); + + WikiAndMedia.fromJson(Map json) { + if(json["image"] is String) + this.image = json["image"]; + } + + Map toJson() { + final Map data = new Map(); + data["image"] = this.image; + return data; + } + + @override + String toString() { + return 'WikiAndMedia{image: $image}'; + } +} + +class Contact { + String? phone; + String? website; + + Contact({this.phone, this.website}); + + Contact.fromJson(Map json) { + if(json["phone"] is String) + this.phone = json["phone"]; + if(json["website"] is String) + this.website = json["website"]; + } + + Map toJson() { + final Map data = new Map(); + data["phone"] = this.phone; + data["website"] = this.website; + return data; + } + + @override + String toString() { + return 'Contact{phone: $phone, website: $website}'; + } +} + +class RefOther { + String? ref; + String? operator; + + RefOther({this.ref, this.operator}); + + RefOther.fromJson(Map json) { + if(json["ref"] is String) + this.ref = json["ref"]; + if(json["operator"] is String) + this.operator = json["operator"]; + } + + Map toJson() { + final Map data = new Map(); + data["ref"] = this.ref; + data["operator"] = this.operator; + return data; + } + + @override + String toString() { + return 'RefOther{ref: $ref, operator: $operator}'; + } +} + +class Datasource { + String? sourcename; + String? attribution; + String? license; + String? url; + + Datasource({this.sourcename, this.attribution, this.license, this.url}); + + Datasource.fromJson(Map json) { + if(json["sourcename"] is String) + this.sourcename = json["sourcename"]; + if(json["attribution"] is String) + this.attribution = json["attribution"]; + if(json["license"] is String) + this.license = json["license"]; + if(json["url"] is String) + this.url = json["url"]; + } + + Map toJson() { + final Map data = new Map(); + data["sourcename"] = this.sourcename; + data["attribution"] = this.attribution; + data["license"] = this.license; + data["url"] = this.url; + return data; + } + + @override + String toString() { + return 'Datasource{sourcename: $sourcename, attribution: $attribution, license: $license, url: $url}'; + } +} diff --git a/lib/main.dart b/lib/main.dart index 2c98a82..615f9d4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; import 'package:super_liquid_galaxy_controller/screens/dashboard.dart'; +import 'package:super_liquid_galaxy_controller/screens/maps_controller.dart'; import 'package:super_liquid_galaxy_controller/screens/splashscreen.dart'; import 'package:super_liquid_galaxy_controller/utils/api_manager.dart'; import 'package:super_liquid_galaxy_controller/utils/lg_connection.dart'; @@ -41,7 +42,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, initialRoute: '/', routes: { - '/': (context) => const DashBoard(), // Root route + '/': (context) => const SplashScreen(), // Root route // Settings route }, theme: ThemeData( diff --git a/lib/screens/dashboard.dart b/lib/screens/dashboard.dart index 3d04ca6..40de834 100644 --- a/lib/screens/dashboard.dart +++ b/lib/screens/dashboard.dart @@ -88,9 +88,14 @@ class _DashBoardState extends State { height: screenHeight * 0.1, ), SizedBox(width: 20), - Image( - image: AssetImage(Assets.assetsLogotxt), - height: screenHeight * 0.05, + Container( + width: screenWidth * 0.4, + height: screenHeight * 0.1, + child: FittedBox( + fit: BoxFit.contain, + child: Text("SUPER LIQUID GALAXY CONTROLLER",style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 30.0),), + + ), ), ], ), diff --git a/lib/screens/kml_builder.dart b/lib/screens/kml_builder.dart index 3a00913..befc903 100644 --- a/lib/screens/kml_builder.dart +++ b/lib/screens/kml_builder.dart @@ -4,6 +4,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:device_info_plus/device_info_plus.dart'; import 'package:super_liquid_galaxy_controller/components/MapKmlElement.dart'; import 'package:super_liquid_galaxy_controller/components/galaxy_button.dart'; import 'package:super_liquid_galaxy_controller/components/glassbox.dart'; @@ -258,7 +259,7 @@ class _KmlUploaderState extends State { //String kml = KMLGenerator.generateCustomKml('slave_1', kmlList); print("made successfully"); await sshClient.kmlFileUpload( - context, file!, filename); + file!, filename); print("uploaded successfully"); await sshClient.runKml(filename); @@ -275,7 +276,7 @@ class _KmlUploaderState extends State { onTap: () async { //await sshClient.clearKml(); String kml = KMLGenerator.generateCustomKml('slave_1', kmlList); - saveStringToExternalStorageWithProgress(kml, 'custom_kml', 'kml', (progress){ + saveStringToExternalStorageWithProgress(kml, 'custom_kml_ID_${generateRandomString(7)}', 'kml', (progress){ print(progress); }); }, @@ -467,10 +468,23 @@ class _KmlUploaderState extends State { } } } + Future saveStringToExternalStorageWithProgress( String content, String filename, String extension, Function(double) onProgress) async { // Request storage permissions - if (await Permission.manageExternalStorage.request().isGranted) { + String response = await getAndroidVersion(); + bool isAbove13 = false; + if(response.compareTo('')==0) + { + print('Failed to fetch android version'); + } + else + { + if(int.tryParse(response)!>=13) { + isAbove13 = true; + } + } + if ( isAbove13 || await Permission.storage.request().isGranted) { // Get the external storage directory Directory? directory = await getExternalStorageDirectory(); if (directory != null) { @@ -504,6 +518,18 @@ class _KmlUploaderState extends State { } + Future getAndroidVersion() async { + if (Platform.isAndroid) { + DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; + return androidInfo.version.release; + } + else + { + return "unsupported"; + } + } + void showSuccessSnackbar(String message) { if (!Get.isSnackbarOpen) { Get.showSnackbar(GetSnackBar( diff --git a/lib/screens/map_kml_fullscreen.dart b/lib/screens/map_kml_fullscreen.dart index f8ff082..d352d61 100644 --- a/lib/screens/map_kml_fullscreen.dart +++ b/lib/screens/map_kml_fullscreen.dart @@ -42,11 +42,13 @@ class _MapKmlFullscreenState extends State { position: widget.position, mapMovementController: widget.mapMovementController, elementIndex: widget.elementIndex, + hideFullScreen: true, handlerCallback: ((handler) { }), submitData: (KmlElement element){ Get.back(result: element); }), + )); } } diff --git a/lib/screens/maps_controller.dart b/lib/screens/maps_controller.dart index 5ebc295..ed17080 100644 --- a/lib/screens/maps_controller.dart +++ b/lib/screens/maps_controller.dart @@ -1,21 +1,20 @@ import 'dart:async'; import 'dart:math'; +import 'package:avatar_glow/avatar_glow.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:avatar_glow/avatar_glow.dart'; import 'package:super_liquid_galaxy_controller/components/autocomplete_locationfield.dart'; import 'package:super_liquid_galaxy_controller/components/tray_button.dart'; -import 'package:super_liquid_galaxy_controller/data_class/place_suggestion_response.dart'; import 'package:super_liquid_galaxy_controller/data_class/coordinate.dart'; import 'package:super_liquid_galaxy_controller/data_class/map_position.dart'; +import 'package:super_liquid_galaxy_controller/data_class/place_suggestion_response.dart'; import 'package:super_liquid_galaxy_controller/generated/assets.dart'; import 'package:super_liquid_galaxy_controller/utils/autocomplete_controller.dart'; -import 'package:super_liquid_galaxy_controller/utils/galaxy_colors.dart'; import 'package:super_liquid_galaxy_controller/utils/lg_connection.dart'; import 'package:super_liquid_galaxy_controller/utils/map_movement_controller.dart'; import 'package:super_liquid_galaxy_controller/utils/speech_controller.dart'; @@ -29,7 +28,7 @@ class MapController extends StatefulWidget { class MapControllerState extends State { //final Completer _controller = - // Completer(); + // Completer(); AutocompleteController textController = AutocompleteController(); bool locationSet = false; @@ -100,16 +99,19 @@ class MapControllerState extends State { padding: const EdgeInsets.all(8.0), child: Padding( padding: const EdgeInsets.all(8.0), - child: AutoCompleteLocationField( - hintText: "Enter Location to search here", - labelText: "", - iconData: Icons.search_rounded, - textInputType: TextInputType.text, - isPassword: false, - fillColor: Colors.white, - textColor: Colors.black, - autocompleteController: textController, - seekTo: goToSearchFeature, + child: Container( + color: Colors.green.withOpacity(0.2), + child: AutoCompleteLocationField( + hintText: "Enter Location to search here", + labelText: "", + iconData: Icons.search_rounded, + textInputType: TextInputType.text, + isPassword: false, + fillColor: Colors.white, + textColor: Colors.black, + autocompleteController: textController, + seekTo: goToSearchFeature, + ), ), )), ), @@ -125,18 +127,19 @@ class MapControllerState extends State { children: [ Container( decoration: BoxDecoration( - color: Colors.grey.withOpacity(1.0), + color: Colors.grey.shade800, borderRadius: BorderRadius.circular(20.0), - backgroundBlendMode: BlendMode.screen), + backgroundBlendMode: BlendMode.modulate), child: Column( mainAxisSize: MainAxisSize.min, children: [ TrayButton( icon: Assets.iconsMic, - color: voiceCommandActive ?Colors.green:Colors.grey.shade700, + color: + voiceCommandActive ? Colors.green : Colors.grey, text: "VOICE \n COMMANDS", iconSize: screenHeight * 0.07, - action: (){ + action: () { setState(() { voiceCommandActive = !voiceCommandActive; }); @@ -150,119 +153,240 @@ class MapControllerState extends State { : Colors.red, text: "SYNC TO \n LG", iconSize: screenHeight * 0.07, - action: (){ + action: () { bootLGClient(); }, ); }), TrayButton( icon: Assets.iconsNearbypoi, - color: Colors.black, + color: Colors.grey, text: "NEARBY \n POIs", iconSize: screenHeight * 0.07, ), ], - ) - ), + )), ], ), ), ), - Padding( + /*Padding( padding: const EdgeInsets.all(16.0), child: Visibility( visible: voiceCommandActive, child: Align( - alignment: Alignment.bottomLeft, - child: Obx((){ - print('mapTest: command word ui ${speechController.commandWord.value}'); - return Row( - children: [ - AvatarGlow( - glowColor: Colors.white, - glowShape: BoxShape.circle, - animate: speechController.isListening.value, - curve: Curves.fastOutSlowIn, + alignment: Alignment.bottomCenter, + child: Obx((){ + //print('mapTest: command word ui ${speechController.commandWord.value}'); + return Container( + width: screenWidth*0.4, + height: screenHeight*0.125, + decoration: BoxDecoration( + color: Colors.grey.shade800, + borderRadius: BorderRadius.circular(20.0), + backgroundBlendMode: BlendMode.modulate), + child: FittedBox( + fit: BoxFit.contain, child: Material( - elevation: 8.0, - shape: CircleBorder(), - color: Colors.transparent, - child: InkWell( - borderRadius: BorderRadius.circular(20.0), - onTapUp: (TapUpDetails tapdetails) { - print('up: ${tapdetails.kind}'); - speechController.stopListening(); - }, - onTapDown: (TapDownDetails details) { - print('down: ${details.kind}'); - speechController.startListening(); - }, - onTapCancel: () { - print('cancel'); - speechController.stopListening(); - }, - child: Padding( - padding: EdgeInsets.all(12.0), - child: CircleAvatar( - backgroundColor: Colors.white, - backgroundImage: AssetImage(Assets.iconsMic), - radius: screenHeight *0.05, - ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + child: AvatarGlow( + glowColor: Colors.white, + glowShape: BoxShape.circle, + animate: speechController.isListening.value, + curve: Curves.fastOutSlowIn, + child: Material( + elevation: 8.0, + shape: CircleBorder(), + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.circular(20.0), + onTapUp: (TapUpDetails tapdetails) { + print('up: ${tapdetails.kind}'); + speechController.stopListening(); + }, + onTapDown: (TapDownDetails details) { + print('down: ${details.kind}'); + speechController.startListening(); + }, + onTapCancel: () { + print('cancel'); + speechController.stopListening(); + }, + child: Padding( + padding: EdgeInsets.all(6.0), + child: CircleAvatar( + backgroundColor: Colors.grey.shade700, + radius: screenHeight * 0.05, + child: ImageIcon( + AssetImage(Assets.iconsMic), + color: Colors.white, + size: screenHeight * 0.07, + ), + ), + ), + ), + ), + ), + ), + + const SizedBox(width: 20.0,), + + Flexible( + child: Container( + color: Colors.green, + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Material( + color: Colors.transparent, + child: Center( + child: Text( + speechController.commandWord.value, + style: const TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.bold, + color: Colors.white + ), + ), + ), + ), + Material( + color: Colors.transparent, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center(child: Text(speechController.wordsString.value,style: const TextStyle(color: Colors.grey,fontSize: 12.0),),), + ), + ) + ], + ), + ), + ) + ], ), ), ), ), + ); + } - SizedBox(width: screenWidth*0.07,), + ) + ), + ), + )*/ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Material( - color: Colors.transparent, - child: Container( - height: screenHeight*0.06, - width: screenWidth*0.2, - decoration: const BoxDecoration( - color: Colors.grey, - borderRadius: BorderRadius.vertical(top: Radius.circular(20.0)), - backgroundBlendMode: BlendMode.screen), - child: Center( - child: Text( - speechController.commandWord.value, - style: const TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.bold + Visibility( + visible: voiceCommandActive, + child: Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Container( + height: screenHeight * 0.125, + width: screenWidth * 0.35, + decoration: BoxDecoration( + color: Colors.grey.shade800, + borderRadius: BorderRadius.circular(20.0), + backgroundBlendMode: BlendMode.modulate), + child: Material( + color: Colors.transparent, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Obx(() { + return Row( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + child: FittedBox( + fit: BoxFit.contain, + child: AvatarGlow( + glowColor: Colors.white, + glowShape: BoxShape.circle, + animate: speechController.isListening.value, + curve: Curves.fastOutSlowIn, + child: Material( + elevation: 8.0, + shape: CircleBorder(), + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.circular(20.0), + onTapUp: (TapUpDetails tapdetails) { + print('up: ${tapdetails.kind}'); + speechController.stopListening(); + }, + onTapDown: (TapDownDetails details) { + print('down: ${details.kind}'); + speechController.startListening(); + }, + onTapCancel: () { + print('cancel'); + speechController.stopListening(); + }, + child: Padding( + padding: EdgeInsets.all(6.0), + child: CircleAvatar( + backgroundColor: Colors.grey.shade800, + radius: screenHeight * 0.05, + child: ImageIcon( + const AssetImage(Assets.iconsMic), + color: Colors.white, + size: screenHeight * 0.07, + ), + ), + ), + ), ), ), + )), + Expanded( + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Container( + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + flex: 7, + child: Container( + child: FittedBox( + fit: BoxFit.contain, + child: Text( + speechController.commandWord.value, + style: const TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ), + ), + ), + Expanded( + flex: 3, + child: Container( + child: FittedBox( + fit: BoxFit.contain, + child: Text( + speechController.wordsString.value.isEmpty?"Word Queue Empty. Try Saying something!":speechController.wordsString.value, + style: const TextStyle( + color: Colors.grey, fontSize: 12.0), + ), + ), + ), + ) + ], + )), + ), ), - ), - ), - Container( - color: Colors.grey, - width: screenWidth*0.2, - height: 2.0, - ), - Container( - width: screenWidth*0.2, - decoration: const BoxDecoration( - color: Colors.grey, - backgroundBlendMode: BlendMode.screen), - child: Material( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center(child: Text(speechController.wordsString.value,style: const TextStyle(color: Colors.black,fontSize: 12.0),),), - ), - ), - ) - ], - ) - ], - ); - } - - ) + ], + ); + })), + ), + ), ), ), ) @@ -368,19 +492,16 @@ class MapControllerState extends State { ], ), ); - } - else - { - if (!Get.isSnackbarOpen) { - Get.showSnackbar(GetSnackBar( - backgroundColor: Colors.green.shade300, - title: "CONNECTED!", - message: "Your Maps controller is now connected to the LG rig.", - isDismissible: true, - duration: 5.seconds, - )); - - } + } else { + if (!Get.isSnackbarOpen) { + Get.showSnackbar(GetSnackBar( + backgroundColor: Colors.green.shade300, + title: "CONNECTED!", + message: "Your Maps controller is now connected to the LG rig.", + isDismissible: true, + duration: 5.seconds, + )); } + } } } diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index aebec61..11d970f 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -124,50 +124,66 @@ class _SettingsState extends State { tabs: [ Tab( height: screenHeight * 0.1, - child: Padding( - padding: EdgeInsets.symmetric(vertical: 15.0), - child: Row(mainAxisSize: MainAxisSize.min, children: const [ - ImageIcon(AssetImage(Assets.iconsConnection), size: 60.0), - SizedBox( - width: 10.0, + child: Container( + //color: Colors.green.withOpacity(0.3), + child: FittedBox( + fit: BoxFit.contain, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 15.0), + child: Row(mainAxisSize: MainAxisSize.min, children: const [ + ImageIcon(AssetImage(Assets.iconsConnection), size: 60.0), + SizedBox( + width: 10.0, + ), + Text( + "Connection ", + style: TextStyle(fontSize: 30.0), + ), + ]), ), - Text( - "Connection ", - style: TextStyle(fontSize: 30.0), - ), - ]), + ), ), ), Tab( height: screenHeight * 0.1, - child: Padding( - padding: EdgeInsets.symmetric(vertical: 15.0), - child: Row(mainAxisSize: MainAxisSize.min, children: const [ - ImageIcon(AssetImage(Assets.iconsSsh), size: 60.0), - SizedBox( - width: 10.0, - ), - Text( - "SSH Commands ", - style: TextStyle(fontSize: 30.0), + child: Container( + child: FittedBox( + fit: BoxFit.contain, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 15.0), + child: Row(mainAxisSize: MainAxisSize.min, children: const [ + ImageIcon(AssetImage(Assets.iconsSsh), size: 60.0), + SizedBox( + width: 10.0, + ), + Text( + "SSH Commands ", + style: TextStyle(fontSize: 30.0), + ), + ]), ), - ]), + ), ), ), Tab( height: screenHeight * 0.1, - child: Padding( - padding: EdgeInsets.symmetric(vertical: 15.0), - child: Row(mainAxisSize: MainAxisSize.min, children: const [ - ImageIcon(AssetImage(Assets.iconsKey), size: 60.0), - SizedBox( - width: 10.0, - ), - Text( - "API Keys ", - style: TextStyle(fontSize: 30.0), + child: Container( + child: FittedBox( + fit: BoxFit.contain, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 15.0), + child: Row(mainAxisSize: MainAxisSize.min, children: const [ + ImageIcon(AssetImage(Assets.iconsKey), size: 60.0), + SizedBox( + width: 10.0, + ), + Text( + "API Keys ", + style: TextStyle(fontSize: 30.0), + ), + ]), ), - ]), + ), ), ), ], diff --git a/lib/screens/tour_builder.dart b/lib/screens/tour_builder.dart index 958e994..1979892 100644 --- a/lib/screens/tour_builder.dart +++ b/lib/screens/tour_builder.dart @@ -183,6 +183,7 @@ class _TourBuilderState extends State { width: screenWidth * 0.25, iconSize: screenHeight * 0.1, searchSize: screenWidth * 0.85, + tourController: tourController, submitData: (Coordinates point, String label) { setSearchAround(point,label); }, @@ -196,7 +197,35 @@ class _TourBuilderState extends State { child: Container( height: screenHeight * 0.448, width: screenWidth * 0.93, - child: GridView.builder( + child: Obx( + (){ + return ListView.builder(itemBuilder: (_,int index){ + return Container( + height: screenHeight*0.13, + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + color: Colors.green, + ), + ), + Expanded( + child: Container( + color: Colors.blue, + ), + ) + ], + ), + ); + }, + itemCount: (tourController.placeList.length%2==0)?tourController.placeList.length~/2:((tourController.placeList.length~/2)+1), + ); + } + ) + + + /*GridView.builder( itemCount: 12, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( @@ -217,7 +246,7 @@ class _TourBuilderState extends State { height: screenHeight*0.15, ), )); - }), + })*/, ), ) ], diff --git a/lib/utils/api_manager.dart b/lib/utils/api_manager.dart index 219390a..ceda938 100644 --- a/lib/utils/api_manager.dart +++ b/lib/utils/api_manager.dart @@ -5,6 +5,12 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:super_liquid_galaxy_controller/data_class/api_error.dart'; import 'package:super_liquid_galaxy_controller/data_class/coordinate.dart'; import 'package:super_liquid_galaxy_controller/data_class/geo_reversecode_response.dart'; +import 'package:super_liquid_galaxy_controller/data_class/place_details_response.dart'; +import 'package:super_liquid_galaxy_controller/data_class/place_response.dart'; +import 'package:super_liquid_galaxy_controller/screens/test.dart'; +import 'package:super_liquid_galaxy_controller/utils/kmlgenerator.dart'; + +import '../data_class/kml_element.dart'; class ApiManager extends getx.GetxController { late String _placesApiKey; @@ -21,6 +27,9 @@ class ApiManager extends getx.GetxController { static const placesEndPoint = "/places"; static const geocodeEndPoint = "/geocode/search"; static const reverseGeoCodeEndPoint = "/geocode/reverse"; + static const boundariesPartOfEndPoint = "/boundaries/part-of"; + static const boundariesConsistsOfEndPoint = "/boundaries/consists-of"; + static const placeDetailsEndPoint = "/place-details"; /*ApiManager._privateConstructor() { print("instance created"); @@ -78,6 +87,20 @@ class ApiManager extends getx.GetxController { return response; } + Future getPlaces(String id, String categories) async { + await _connectApi(2); + var response = await _apiClient.get(placesEndPoint, queryParameters: { + 'filter': 'place:$id', + 'apiKey': _placesApiKey.trim(), + 'categories': categories, + 'limit': '500' + }); + if (response.statusCode != 200) { + handleError(response); + } + return response; + } + Future getReverseGeoCodeResponse( Coordinates point, String searchLevel) async { await _connectApi(1); @@ -103,6 +126,52 @@ class ApiManager extends getx.GetxController { return response; } + Future getBoundariesPartOf(String id) async { + await _connectApi(1); + //print("hasType: $hasType"); + var response = + await _apiClient.get(boundariesPartOfEndPoint, queryParameters: { + 'id': id, + 'apiKey': _placesApiKey.trim(), + 'geometry': 'geometry_1000', + 'sublevel': '1' + }); + if (response.statusCode != 200) { + handleError(response); + } + return response; + } + + Future getPlaceDetails(String id) async { + await _connectApi(2); + //print("hasType: $hasType"); + var response = await _apiClient.get(placeDetailsEndPoint, queryParameters: { + 'id': id, + 'apiKey': _placesApiKey.trim(), + 'features': 'details.full_geometry' + }); + if (response.statusCode != 200) { + handleError(response); + } + return response; + } + + Future getBoundariesConsistsOf(String id) async { + await _connectApi(1); + //print("hasType: $hasType"); + var response = + await _apiClient.get(boundariesConsistsOfEndPoint, queryParameters: { + 'id': id, + 'apiKey': _placesApiKey.trim(), + 'geometry': 'geometry_1000', + 'sublevel': '1' + }); + if (response.statusCode != 200) { + handleError(response); + } + return response; + } + void handleError(Response response) { var errorResponse = ApiErrorResponse.fromJson(response.data); print('error : ${response.statusMessage}'); @@ -136,7 +205,8 @@ class ApiManager extends getx.GetxController { } } - Future tryResponseFromPoint(Coordinates searchAroundCoords, bool isCountry) async { + Future tryGeoCodeResponseFromPoint( + Coordinates searchAroundCoords, bool isCountry) async { Response response = await getReverseGeoCodeResponse( searchAroundCoords, isCountry ? 'country' : 'state'); if (response.statusCode != 200) { @@ -146,11 +216,9 @@ class ApiManager extends getx.GetxController { if (responseObj.results != null && responseObj.results!.isNotEmpty) { return responseObj.results![0].placeId!; - } - else - { - Response response2 = await getReverseGeoCodeResponse( - searchAroundCoords, 'none'); + } else { + Response response2 = + await getReverseGeoCodeResponse(searchAroundCoords, 'none'); var responseObj2 = GeoReverseCodeResponse.fromJson(response2.data); print(responseObj2); if (response2.statusCode != 200) { @@ -158,11 +226,85 @@ class ApiManager extends getx.GetxController { } if (responseObj2.results != null && responseObj2.results!.isNotEmpty) { return responseObj2.results![0].placeId!; + } else { + return ''; } - else - { - return ''; + } + } + + Future<({String kml,PlaceDetailsResponse? obj})> tryBoundaryResponseForID( + String id, Coordinates searchAroundCoords) async { + Response response = await getPlaceDetails(id); + if (response.statusCode != 200) { + return (kml:'',obj: null); + } + + var responseObj = PlaceDetailsResponse.fromJson(response.data); + print(responseObj); + print(responseObj.features?[0].geometry?.polygonList); + print(responseObj.features?[0].geometry?.multiPolygonList); + + Response places = await getPlaces(id, 'tourism'); + if (places.statusCode != 200) { + return (kml:'',obj: null); + } + + var placeObj = PlaceResponse.fromJson(places.data); + print(placeObj); + if (responseObj.features != null && + responseObj.features!.isNotEmpty && + responseObj.features![0].geometry != null) { + String kml = + KMLGenerator.generateBoundaries(responseObj.features![0].geometry!); + /*var list = placeObj.features; + List coordinates = []; + for (final feature in list!) { + try { + coordinates.add(Placemark( + coordinate: feature.geometry!.point!, + label: feature.properties!.name!.replaceAll('&', 'and'), + description: feature.properties!.addressLine2!.replaceAll('&', 'and'))); + } catch (e) { + print(e); + print(feature); } + }*/ + //kml += KMLGenerator.addPlaces(coordinates); + //getx.Get.to(() => TestScreen(kml: KMLGenerator.generateKml('69', kml))); + return (kml:kml,obj:responseObj); } + return (kml:'',obj: null); } + + Future<({String kml,PlaceResponse? obj,List places})> tryPlaceResponseForID( + String id, Coordinates searchAroundCoords) async { + Response places = await getPlaces(id, 'tourism'); + if (places.statusCode != 200) { + return (kml:'',obj: null,places:[]); + } + var placeObj = PlaceResponse.fromJson(places.data); + //print(placeObj); + if (placeObj.features!=null && placeObj.features!.isNotEmpty) { + var list = placeObj.features; + List coordinates = []; + for (final feature in list!) { + try { + var name = (feature.properties!.name != null)?feature.properties!.name!.replaceAll('&', 'and'):feature.properties!.addressLine1!; + coordinates.add(Placemark( + coordinate: feature.geometry!.point!, + label: name, + description: feature.properties!.addressLine2!.replaceAll('&', 'and'))); + } catch (e) { + print(e); + print(feature); + } + } + String kml = KMLGenerator.addPlaces(coordinates); + //getx.Get.to(() => TestScreen(kml: KMLGenerator.generateKml('69', kml))); + return (kml:kml,obj:placeObj,places: coordinates); + } + return (kml:'',obj: null,places:[]); + } + + } diff --git a/lib/utils/geo_utils.dart b/lib/utils/geo_utils.dart index 24ab916..3fcbedf 100644 --- a/lib/utils/geo_utils.dart +++ b/lib/utils/geo_utils.dart @@ -1,7 +1,7 @@ import 'dart:math'; - +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:latlong2/latlong.dart' as ll; import '../data_class/coordinate.dart'; - class GeoUtils { // Convert latitude and longitude to Cartesian coordinates static List _toCartesian(double lat, double lon) { @@ -87,5 +87,140 @@ class GeoUtils { '''; } + + static LatLngBounds getBoundingBox(List coordinatesList) { + if (coordinatesList.isEmpty) { + throw ArgumentError("The coordinates list cannot be empty."); + } + + double minLat = double.infinity; + double minLng = double.infinity; + double maxLat = -double.infinity; + double maxLng = -double.infinity; + + for (var coord in coordinatesList) { + if (coord.latitude < minLat) minLat = coord.latitude; + if (coord.longitude < minLng) minLng = coord.longitude; + if (coord.latitude > maxLat) maxLat = coord.latitude; + if (coord.longitude > maxLng) maxLng = coord.longitude; + } + + /*maxLng +=360; + maxLng %=360; + minLng +=360; + minLng %=360;*/ + + print(minLng); + print(maxLng); + LatLng southwest = LatLng(minLat, minLng); + LatLng northeast = LatLng(maxLat, maxLng); + + print(LatLngBounds(southwest: southwest,northeast: northeast)); + return LatLngBounds(southwest: southwest,northeast: northeast); + } + + static List splitLatLngBounds(LatLngBounds bounds, double maxDistance) { + final distance = ll.Distance(); + + final LatLng southWest = bounds.southwest; + final LatLng northEast = bounds.northeast; + + // Normalize longitudes to the range [-180, 180] + double swLng = southWest.longitude; + double neLng = northEast.longitude; + + if (swLng > neLng) { + neLng += 360; // Handle wrap-around + } + + // Calculate the distance between the southwest and northeast corners + double totalLatDistance = distance.as( + ll.LengthUnit.Meter, + ll.LatLng(southWest.latitude, southWest.longitude), + ll.LatLng(northEast.latitude, southWest.longitude), + ); + + double totalLngDistance = distance.as( + ll.LengthUnit.Meter, + ll.LatLng(southWest.latitude, swLng), + ll.LatLng(southWest.latitude, neLng), + ); + + // Check if the bounds are already within the maxDistance + if (totalLatDistance <= maxDistance && totalLngDistance <= maxDistance) { + return [bounds]; + } + + // Number of divisions along latitude and longitude + int latDivisions = (totalLatDistance / maxDistance).ceil(); + int lngDivisions = (totalLngDistance / maxDistance).ceil(); + + // Calculate the latitude and longitude step size + double latStep = (northEast.latitude - southWest.latitude) / latDivisions; + double lngStep = (neLng - swLng) / lngDivisions; + + List boundsList = []; + + for (int i = 0; i < latDivisions; i++) { + for (int j = 0; j < lngDivisions; j++) { + LatLng sw = LatLng( + southWest.latitude + i * latStep, + (swLng + j * lngStep) % 360, + ); + LatLng ne = LatLng( + sw.latitude + latStep, + (sw.longitude + lngStep) % 360, + ); + + // Adjust if the northeast point exceeds the original bounds + if (ne.latitude > northEast.latitude) { + ne = LatLng(northEast.latitude, ne.longitude); + } + if (ne.longitude > northEast.longitude) { + ne = LatLng(ne.latitude, northEast.longitude % 360); + } + + boundsList.add(LatLngBounds(southwest: sw, northeast: ne)); + } + } + return boundsList; + } + + /*static double calculateCoverage(LatLngBounds bounds, List polygon) { + var bboxPolygon = turf.bboxPolygon([ + bounds.southwest.longitude, + bounds.southwest.latitude, + bounds.northeast.longitude, + bounds.northeast.latitude, + ]); + + var polygonFeature = turf.Polygon([polygon.map((e) => [e.longitude, e.latitude]).toList()]); + + var intersection = turf.intersect(bboxPolygon, polygonFeature); + if (intersection == null) { + return 0.0; + } + + var bboxArea = turf.area(bboxPolygon); + var intersectionArea = turf.area(intersection); + + return intersectionArea / bboxArea; + }*/ + + static List getLatLngBoundsPolygon(LatLngBounds bounds) { + LatLng southwest = bounds.southwest; + LatLng northeast = bounds.northeast; + LatLng northwest = LatLng(northeast.latitude, southwest.longitude); + LatLng southeast = LatLng(southwest.latitude, northeast.longitude); + + return [ + Coordinates.fromLatLngMap(southwest), + Coordinates.fromLatLngMap(northwest), + Coordinates.fromLatLngMap(northeast), + Coordinates.fromLatLngMap(southeast), + ]; + } + + } diff --git a/lib/utils/kmlgenerator.dart b/lib/utils/kmlgenerator.dart index 2da7705..a78220b 100644 --- a/lib/utils/kmlgenerator.dart +++ b/lib/utils/kmlgenerator.dart @@ -1,9 +1,12 @@ import 'dart:math' as Math; import 'dart:math'; +import 'package:google_maps_flutter/google_maps_flutter.dart' as mp; import 'package:latlong2/latlong.dart'; import 'package:super_liquid_galaxy_controller/data_class/coordinate.dart'; import 'package:super_liquid_galaxy_controller/data_class/kml_element.dart'; +import 'package:super_liquid_galaxy_controller/data_class/place_details_response.dart'; +import 'package:super_liquid_galaxy_controller/data_class/place_response.dart' as pr; import 'package:super_liquid_galaxy_controller/utils/geo_utils.dart'; class KMLGenerator { @@ -96,8 +99,8 @@ class KMLGenerator { } } - var lookAt = ''; - lookAt += GeoUtils.calculateLookAt(coordsList, 45); + // var lookAt = ''; + // lookAt += GeoUtils.calculateLookAt(coordsList, 45); return ''' @@ -156,6 +159,15 @@ class KMLGenerator { a1ffaa00 +