diff --git a/lib/components/MapKmlElement.dart b/lib/components/MapKmlElement.dart new file mode 100644 index 0000000..0a372c2 --- /dev/null +++ b/lib/components/MapKmlElement.dart @@ -0,0 +1,309 @@ +import 'dart:math'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:google_maps_flutter/google_maps_flutter.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/map_position.dart'; +import 'package:super_liquid_galaxy_controller/screens/map_kml_fullscreen.dart'; +import 'package:super_liquid_galaxy_controller/utils/galaxy_colors.dart'; +import 'package:super_liquid_galaxy_controller/utils/map_movement_controller.dart'; + +class Mapkmlelement extends StatefulWidget { + Mapkmlelement( + {super.key, + required this.position, + required this.mapMovementController, + required this.elementIndex, + required this.handlerCallback(CallbackHandler handler), + required this.submitData}); + + MapPosition position; + MapMovementController mapMovementController; + int elementIndex; + final Function handlerCallback; + Function(KmlElement) submitData; + + @override + State createState() => _MapkmlelementState(); +} + +class _MapkmlelementState extends State { + List points = []; + Set markers = {}; + List polyline = []; + List polygon = []; + + @override + void initState() { + CallbackHandler handler = CallbackHandler(); + handler.callBack = this.resetData; + widget.handlerCallback(handler); + resetData(widget.elementIndex); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Stack(children: [ + GoogleMap( + gestureRecognizers: >{ + new Factory( + () => new EagerGestureRecognizer(), + ), + }, + minMaxZoomPreference: MinMaxZoomPreference.unbounded, + mapToolbarEnabled: true, + tiltGesturesEnabled: true, + zoomControlsEnabled: true, + zoomGesturesEnabled: true, + scrollGesturesEnabled: true, + compassEnabled: false, + markers: markers, + polylines: widget.elementIndex == 1 ? polyline.toSet() : {}, + polygons: widget.elementIndex == 2 ? polygon.toSet() : {}, + mapType: MapType.hybrid, + initialCameraPosition: widget.position.toCameraPosition(), + onMapCreated: widget.mapMovementController.onMapCreated, + ), + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + MaterialButton( + onPressed: () { + widget.submitData(KmlElement( + index: widget.elementIndex, + elementData: getElementData(widget.elementIndex))); + }, + color: Colors.black.withOpacity(0.5), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + side: BorderSide(width: 1.0)), + child: const Row( + children: [ + Icon( + Icons.save_alt_rounded, + color: Colors.white, + ), + SizedBox( + width: 8.0, + ), + Text( + "SUBMIT DATA", + style: TextStyle(color: Colors.white), + ) + ], + ), + ), + const SizedBox( + width: 16.0, + ), + Visibility( + visible: widget.elementIndex != 0, + child: MaterialButton( + onPressed: () { + addPoint(); + }, + color: Colors.black.withOpacity(0.5), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + side: BorderSide(width: 1.0)), + child: const Row( + children: [ + Icon( + Icons.add_location_alt_outlined, + color: Colors.white, + ), + SizedBox( + width: 8.0, + ), + Text( + "ADD POINT", + style: TextStyle(color: Colors.white), + ) + ], + ), + ), + ), + ], + ), + ), + ), + 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, + ), + ), + ), + ) + ]); + } + + void calculateMarkers() { + markers.clear(); + for (final (index, coords) in points.indexed) { + markers.add(Marker( + markerId: MarkerId("marker${index}"), + position: coords, + draggable: true, + onDragEnd: (LatLng location) { + setState(() { + points[index] = LatLng(location.latitude, location.longitude); + calculateMarkers(); + polyline.clear(); + polygon.clear(); + reloadMap(); + }); + })); + } + } + + Polyline calculatePolyLine() { + return Polyline( + polylineId: PolylineId("polyline${Random.secure()}"), + color: GalaxyColors.blue, + points: points, + ); + } + + Polygon calculatePolygon() { + return Polygon( + polygonId: PolygonId("polygon${Random.secure()}"), + fillColor: GalaxyColors.blue, + strokeColor: GalaxyColors.darkBlue, + points: points, + ); + } + + void reloadMap() { + setState(() { + points.add(LatLng(points[points.length - 1].latitude + 1, + points[points.length - 1].longitude + 1)); + calculateMarkers(); + polyline.clear(); + polygon.clear(); + polyline.add(calculatePolyLine()); + polygon.add(calculatePolygon()); + }); + + setState(() { + points.removeLast(); + calculateMarkers(); + polyline.clear(); + polygon.clear(); + polyline.add(calculatePolyLine()); + polygon.add(calculatePolygon()); + }); + } + + void addPoint() { + setState(() { + points.add(LatLng(points[points.length - 1].latitude + 3, + points[points.length - 1].longitude + 2)); + calculateMarkers(); + polyline.clear(); + polygon.clear(); + polyline.add(calculatePolyLine()); + polygon.add(calculatePolygon()); + }); + print(points); + } + + resetData(int idx) { + print("resetData"); + points.clear(); + points.add(widget.position.toLatLng()); + if (idx == 1) { + var p1 = widget.position.toLatLng(); + p1 = LatLng(p1.latitude, p1.longitude + 2); + points.add(p1); + } else if (idx == 2) { + var p1 = widget.position.toLatLng(); + p1 = LatLng(p1.latitude, p1.longitude + 2); + points.add(p1); + var p2 = widget.position.toLatLng(); + p2 = LatLng(p1.latitude + 1, p1.longitude); + points.add(p2); + } + calculateMarkers(); + polyline.clear(); + polygon.clear(); + polyline.add(calculatePolyLine()); + polygon.add(calculatePolygon()); + setState(() { + reloadMap(); + print(points); + }); + } + + getElementData(int elementIndex) { + switch (elementIndex) { + case 0: + { + return Placemark( + coordinate: Coordinates( + latitude: points[0].latitude, longitude: points[0].longitude), + label: "marker", + description: "from map"); + } + case 1: + { + return LineString( + label: "poly-line", + description: "from map", + coordinates: getCoordinateList(points)); + } + case 2: + { + return PolyGon( + label: "poly-gon", + description: "from map", + coordinates: getCoordinateList(points), + color: 'ffffff'); + } + default: + { + return Placemark( + coordinate: Coordinates( + latitude: points[0].latitude, longitude: points[0].longitude), + label: "marker", + description: "from map"); + } + } + } + + List getCoordinateList(List pointsList) { + List list = []; + for (final coords in pointsList) { + list.add( + Coordinates(latitude: coords.latitude, longitude: coords.longitude)); + } + return list; + } +} + +class CallbackHandler { + Function? callBack; +} diff --git a/lib/components/kml_elements/linestring.dart b/lib/components/kml_elements/linestring.dart index 5c301fb..95cdcbe 100644 --- a/lib/components/kml_elements/linestring.dart +++ b/lib/components/kml_elements/linestring.dart @@ -34,6 +34,7 @@ class _LineStringElementState extends State { super.initState(); DataRetrieverHandler handler = DataRetrieverHandler(); handler.dataRetriever = this.retrieveData; + handler.dataSetter = this.setData; widget.handlerCallback(handler); } @@ -208,6 +209,16 @@ class _LineStringElementState extends State { return null; } } + void setData(KmlElement element) { + if (element.index != 1) { + return; + } + LineString ele = element.elementData; + nameController.text=ele.label; + bodyController.text=ele.description; + pointList.clear(); + pointList.addAll(ele.coordinates); + } bool validateData() { if (nameController.text.isEmpty || diff --git a/lib/components/kml_elements/placemark.dart b/lib/components/kml_elements/placemark.dart index ebce682..230b7b5 100644 --- a/lib/components/kml_elements/placemark.dart +++ b/lib/components/kml_elements/placemark.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:super_liquid_galaxy_controller/data_class/kml_element.dart'; -import 'package:super_liquid_galaxy_controller/data_class/coordinate.dart'; import 'package:get/get.dart'; +import 'package:super_liquid_galaxy_controller/data_class/coordinate.dart'; +import 'package:super_liquid_galaxy_controller/data_class/kml_element.dart'; + import '../coordinate_field.dart'; class PlacemarkElement extends StatefulWidget { @@ -15,12 +16,14 @@ class PlacemarkElement extends StatefulWidget { double width; final Function handlerCallback; + @override State createState() => _PlacemarkElementState(); } class DataRetrieverHandler { Function? dataRetriever; + Function? dataSetter; } class _PlacemarkElementState extends State { @@ -34,6 +37,7 @@ class _PlacemarkElementState extends State { super.initState(); DataRetrieverHandler handler = DataRetrieverHandler(); handler.dataRetriever = this.retrieveData; + handler.dataSetter = this.setData; widget.handlerCallback(handler); } @@ -124,7 +128,7 @@ class _PlacemarkElementState extends State { KmlElement? retrieveData() { try { - if(!validateData()) { + if (!validateData()) { return null; } @@ -145,22 +149,33 @@ class _PlacemarkElementState extends State { } } + void setData(KmlElement element) { + if (element.index != 0) { + return; + } + Placemark ele = element.elementData; + coordinateLatController.text = ele.coordinate.latitude.toString(); + coordinateLongController.text = ele.coordinate.longitude.toString(); + labelController.text = ele.label; + descController.text = ele.description; + } + bool validateData() { - if(coordinateLongController.text.isEmpty||coordinateLatController.text.isEmpty||labelController.text.isEmpty||descController.text.isEmpty) - { - if (!Get.isSnackbarOpen) { - Get.showSnackbar(GetSnackBar( - backgroundColor: Colors.red.shade300, - title: "EMPTY FIELDS", - message: - "One or more Fields are empty", - isDismissible: true, - duration: 5.seconds, - )); - } - return false; + if (coordinateLongController.text.isEmpty || + coordinateLatController.text.isEmpty || + labelController.text.isEmpty || + descController.text.isEmpty) { + if (!Get.isSnackbarOpen) { + Get.showSnackbar(GetSnackBar( + backgroundColor: Colors.red.shade300, + title: "EMPTY FIELDS", + message: "One or more Fields are empty", + isDismissible: true, + duration: 5.seconds, + )); } - else { + return false; + } else { return true; } } diff --git a/lib/components/kml_elements/polygon.dart b/lib/components/kml_elements/polygon.dart index bcf8f09..11f0f93 100644 --- a/lib/components/kml_elements/polygon.dart +++ b/lib/components/kml_elements/polygon.dart @@ -30,6 +30,7 @@ class _PolygonElementState extends State { super.initState(); DataRetrieverHandler handler = DataRetrieverHandler(); handler.dataRetriever =this.retrieveData; + handler.dataSetter = this.setData; widget.handlerCallback(handler); } @@ -198,16 +199,26 @@ class _PolygonElementState extends State { } return KmlElement( index: 2, - elementData: Polygon( + elementData: PolyGon( coordinates: pointList, label: nameController.text.toString(), description: bodyController.text.toString(), - color: ''),); + color: 'ffffff'),); } catch (e) { print(e.toString()); return null; } } + void setData(KmlElement element) { + if (element.index != 2) { + return; + } + PolyGon ele = element.elementData; + nameController.text=ele.label; + bodyController.text=ele.description; + pointList.clear(); + pointList.addAll(ele.coordinates); + } bool validateData() { if ( diff --git a/lib/data_class/kml_element.dart b/lib/data_class/kml_element.dart index a2ae039..ce48234 100644 --- a/lib/data_class/kml_element.dart +++ b/lib/data_class/kml_element.dart @@ -33,13 +33,13 @@ class LineString { } -class Polygon { +class PolyGon { String label; String description; List coordinates; String color; - Polygon({ + PolyGon({ required this.label, required this.description, required this.coordinates, diff --git a/lib/data_class/map_position.dart b/lib/data_class/map_position.dart index f01616e..2fadec1 100644 --- a/lib/data_class/map_position.dart +++ b/lib/data_class/map_position.dart @@ -68,4 +68,9 @@ class MapPosition { return LookAt(longitude, latitude, zoom/rigCount, tilt, bearing); } + LatLng toLatLng() + { + return LatLng(latitude, longitude); + } + } diff --git a/lib/main.dart b/lib/main.dart index 1c53238..1244b8b 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/kml_builder.dart'; import 'package:super_liquid_galaxy_controller/screens/maps_controller.dart'; import 'package:super_liquid_galaxy_controller/screens/test.dart'; import 'package:super_liquid_galaxy_controller/utils/api_manager.dart'; @@ -47,7 +48,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, initialRoute: '/', routes: { - '/': (context) => const MapController(), // Root route + '/': (context) => const KmlUploader(), // Root route // Settings route }, theme: ThemeData( diff --git a/lib/screens/kml_builder.dart b/lib/screens/kml_builder.dart index 02028b1..8cbcf5a 100644 --- a/lib/screens/kml_builder.dart +++ b/lib/screens/kml_builder.dart @@ -2,23 +2,22 @@ import 'dart:io'; import 'dart:math'; import 'dart:ui'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_map/flutter_map.dart'; -import 'package:latlong2/latlong.dart'; import 'package:get/get.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'; import 'package:super_liquid_galaxy_controller/components/kml_elements/linestring.dart'; import 'package:super_liquid_galaxy_controller/components/kml_elements/placemark.dart'; import 'package:super_liquid_galaxy_controller/components/kml_elements/polygon.dart'; -import 'package:super_liquid_galaxy_controller/screens/test.dart'; import 'package:super_liquid_galaxy_controller/utils/galaxy_colors.dart'; import 'package:super_liquid_galaxy_controller/utils/kmlgenerator.dart'; import 'package:super_liquid_galaxy_controller/utils/lg_connection.dart'; import '../data_class/kml_element.dart'; +import '../data_class/map_position.dart'; import '../generated/assets.dart'; +import '../utils/map_movement_controller.dart'; class KmlUploader extends StatefulWidget { const KmlUploader({super.key}); @@ -28,9 +27,22 @@ class KmlUploader extends StatefulWidget { } class _KmlUploaderState extends State { + MapPosition position = MapPosition( + latitude: 40.7128, + longitude: -74.0060, + // Example: New York City + zoom: 5, + bearing: 45, + // 45 degrees east of north + tilt: 45, // City level zoom + ); + + late MapMovementController mapMovementController; + late double screenHeight; late double screenWidth; late DataRetrieverHandler dataController; + late CallbackHandler callbackController; late LGConnection sshClient; int elementIndex = 0; @@ -41,10 +53,12 @@ class _KmlUploaderState extends State { ['Polygon', Icons.pentagon_rounded] ]; List kmlList = []; + KmlElement? loadElement; @override void initState() { sshClient = Get.find(); + mapMovementController = Get.find(); super.initState(); } @@ -126,8 +140,9 @@ class _KmlUploaderState extends State { fontWeight: FontWeight.w400, fontSize: 25.0), ), - - Divider(thickness: 1.0,), + Divider( + thickness: 1.0, + ), const SizedBox( width: 20.0, ), @@ -140,7 +155,7 @@ class _KmlUploaderState extends State { mainAxisSize: MainAxisSize.min, children: [ Image( - image: AssetImage(Assets.iconsKml), + image: AssetImage(Assets.iconsKml), fit: BoxFit.scaleDown, ), const Text( @@ -153,40 +168,43 @@ class _KmlUploaderState extends State { ], ), ), - ) - ), + )), Visibility( visible: kmlList.isNotEmpty, child: Expanded( child: Scrollbar( - controller: ScrollController(), - radius: const Radius.circular(20.0), - thickness: 2.0, - child: ListView.builder( - itemCount: kmlList.length, - itemBuilder: - (BuildContext context, int index) { - var element = kmlList[index]; - return Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - kmlElements[element.index][1], - color: Colors.white, - size: 25.0, - ), - const SizedBox( - width: 10.0, - ), - Text( - "${kmlElements[element.index][0]} : ${element.elementData?.label}", - style: const TextStyle(color: Colors.white,fontSize: 20.0,fontWeight: FontWeight.w400), - ) - ], - ); - }), - )), + controller: ScrollController(), + radius: const Radius.circular(20.0), + thickness: 2.0, + child: ListView.builder( + itemCount: kmlList.length, + itemBuilder: + (BuildContext context, int index) { + var element = kmlList[index]; + return Row( + mainAxisAlignment: + MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + kmlElements[element.index][1], + color: Colors.white, + size: 25.0, + ), + const SizedBox( + width: 10.0, + ), + Text( + "${kmlElements[element.index][0]} : ${element.elementData?.label}", + style: const TextStyle( + color: Colors.white, + fontSize: 20.0, + fontWeight: FontWeight.w400), + ) + ], + ); + }), + )), ) ], ), @@ -202,25 +220,19 @@ class _KmlUploaderState extends State { backgroundGradient: const LinearGradient( colors: [Colors.white, Colors.white], ), - child: FlutterMap( - options: const MapOptions( - initialCenter: LatLng(51.509364, -0.128928), - initialZoom: 9.2, - ), - children: [ - TileLayer( - urlTemplate: - 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', - userAgentPackageName: 'com.example.app', - ), - RichAttributionWidget( - attributions: [ - TextSourceAttribution( - 'OpenStreetMap contributors', - onTap: () {}), - ], - ), - ], + child: Mapkmlelement( + position: position, + mapMovementController: mapMovementController, + elementIndex: elementIndex, + handlerCallback: ((handler) { + callbackController = handler; + }), + submitData: (KmlElement data){ + setState(() { + loadElement = data; + dataController.dataSetter!(data); + }); + }, ), ), Row( @@ -237,9 +249,11 @@ class _KmlUploaderState extends State { String filename = generateRandomString(7); await sshClient.connectToLG(); //await sshClient.clearKml(); - File? file = await sshClient.makeFile(filename, KMLGenerator.generateKml('slave_1', kmlList)); + File? file = await sshClient.makeFile(filename, + KMLGenerator.generateKml('slave_1', kmlList)); print("made successfully"); - await sshClient.kmlFileUpload(context, file!, filename); + await sshClient.kmlFileUpload( + context, file!, filename); print("uploaded successfully"); await sshClient.runKml(filename); }, @@ -253,7 +267,7 @@ class _KmlUploaderState extends State { isLeading: true, onTap: () async { await sshClient.clearKml(); - }, + }, backgroundColor: GalaxyColors.blue.withOpacity(0.4), ) ], @@ -286,7 +300,9 @@ class _KmlUploaderState extends State { onSelected: (label) { setState(() { elementIndex = labels.indexOf(label!); + callbackController.callBack!(elementIndex); }); + }, textStyle: TextStyle(color: Colors.white, fontSize: 20.0), @@ -369,7 +385,8 @@ class _KmlUploaderState extends State { String generateRandomString(int len) { var r = Random.secure(); const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz_'; - return List.generate(len, (index) => _chars[r.nextInt(_chars.length)]).join(); + return List.generate(len, (index) => _chars[r.nextInt(_chars.length)]) + .join(); } addElementToList(KmlElement elementData) { diff --git a/lib/screens/map_kml_fullscreen.dart b/lib/screens/map_kml_fullscreen.dart new file mode 100644 index 0000000..f8ff082 --- /dev/null +++ b/lib/screens/map_kml_fullscreen.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:super_liquid_galaxy_controller/components/MapKmlElement.dart'; +import 'package:super_liquid_galaxy_controller/data_class/kml_element.dart'; + +import '../data_class/map_position.dart'; +import '../utils/map_movement_controller.dart'; + +class MapKmlFullscreen extends StatefulWidget { + MapKmlFullscreen( + {super.key, + required this.position, + required this.mapMovementController, + required this.elementIndex, + required this.submitData}); + + MapPosition position; + MapMovementController mapMovementController; + int elementIndex; + Function(KmlElement) submitData; + + @override + State createState() => _MapKmlFullscreenState(); +} + +class _MapKmlFullscreenState extends State { + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + extendBodyBehindAppBar: true, + appBar: AppBar( + backgroundColor: Colors.black.withOpacity(0.4), + leading: BackButton( + onPressed: () { + Get.back(result: KmlElement(index: -1)); + }, + color: Colors.white, + ), + ), + body: Mapkmlelement( + position: widget.position, + mapMovementController: widget.mapMovementController, + elementIndex: widget.elementIndex, + handlerCallback: ((handler) { + }), + submitData: (KmlElement element){ + Get.back(result: element); + }), + )); + } +} diff --git a/lib/utils/kmlgenerator.dart b/lib/utils/kmlgenerator.dart index 512adec..b767398 100644 --- a/lib/utils/kmlgenerator.dart +++ b/lib/utils/kmlgenerator.dart @@ -47,7 +47,7 @@ class KMLGenerator { '''; - static getLinearRing(Polygon placeMark) => ''' + static getLinearRing(PolyGon placeMark) => ''' ${placeMark.label} ${placeMark.description} @@ -84,7 +84,7 @@ class KMLGenerator { } case 2: { - Polygon element = item.elementData; + PolyGon element = item.elementData; visList+=getLinearRing(element); coordsList.addAll(element.coordinates); } diff --git a/lib/utils/map_movement_controller.dart b/lib/utils/map_movement_controller.dart index ff14450..cdd063e 100644 --- a/lib/utils/map_movement_controller.dart +++ b/lib/utils/map_movement_controller.dart @@ -10,13 +10,6 @@ class MapMovementController extends GetxController { var currentMapType = MapType.normal.obs; Timer? _movementTimer; Timer? _zoomTimer; - /*MapPosition _currentPosition = MapPosition( - latitude: 0.0, - longitude: 0.0, - bearing: 0.0, - tilt: 0.0, - zoom: 0.0, - );*/ void onMapCreated(GoogleMapController controller) { _mapController = controller; @@ -37,11 +30,6 @@ class MapMovementController extends GetxController { : MapType.normal; } - /*void _moveCamera(LatLng target) { - _mapController.animateCamera(CameraUpdate.newLatLng(target)); - }*/ - - void _scrollBy(double x, double y) { _mapController.animateCamera(CameraUpdate.scrollBy(x, y)); }