diff --git a/lib/src/models/view/map.dart b/lib/src/models/view/map.dart index bf38b8e39..1a5211745 100644 --- a/lib/src/models/view/map.dart +++ b/lib/src/models/view/map.dart @@ -119,9 +119,11 @@ class AutonomyModel with ChangeNotifier { markCell(result, obstacle, AutonomyCell.obstacle); } if (isPlayingBadApple) return result; - for (final path in data.path) { - markCell(result, path, AutonomyCell.path); - } + for (final path in data.path) { + if (!data.obstacles.contains(path)) { + markCell(result, path, AutonomyCell.path); + } + } for (final marker in markers) { markCell(result, marker, AutonomyCell.marker); } diff --git a/lib/src/pages/map.dart b/lib/src/pages/map.dart index 91f2110f0..bfd29585b 100644 --- a/lib/src/pages/map.dart +++ b/lib/src/pages/map.dart @@ -1,4 +1,5 @@ import "dart:math"; +import "package:burt_network/generated.dart"; import "package:flutter/material.dart"; import "package:rover_dashboard/models.dart"; @@ -30,8 +31,9 @@ class MapPage extends ReactiveWidget { ), actions: [ TextButton( - child: const Text("Cancel"), - onPressed: () => Navigator.of(context).pop()), + child: const Text("Cancel"), + onPressed: () => Navigator.of(context).pop(), + ), ElevatedButton( onPressed: model.markerBuilder.isValid ? () { @@ -49,40 +51,75 @@ class MapPage extends ReactiveWidget { /// The index of this view. final int index; + /// Builder for autonomy commands + final AutonomyCommandBuilder commandBuilder = AutonomyCommandBuilder(); + /// A const constructor. - const MapPage({required this.index}); + MapPage({required this.index}); @override AutonomyModel createModel() => AutonomyModel(); /// Creates a widget to display the cell data for the provided [cell] Widget createCell(AutonomyModel model, MapCellData cell) => Expanded( - child: GestureDetector( - onTap: () { - if (cell.cellType == AutonomyCell.marker) { - model.removeMarker(cell.coordinates); - } else if (cell.cellType == AutonomyCell.empty) { - model.placeMarker(cell.coordinates); + child: DragTarget( + onAcceptWithDetails: (details) { + switch (details.data) { + case AutonomyCell.destination: + { + commandBuilder.gps.latDecimal.value = cell.coordinates.latitude; + commandBuilder.gps.longDecimal.value = cell.coordinates.longitude; + + commandBuilder.submit(); + break; + } + case AutonomyCell.obstacle: + { + final obstacleData = AutonomyData(obstacles: [cell.coordinates]); + models.sockets.autonomy.sendMessage(obstacleData); + break; + } + case AutonomyCell.marker: + { + if (cell.cellType == AutonomyCell.marker) { + model.removeMarker(cell.coordinates); + } else if (cell.cellType == AutonomyCell.empty) { + model.placeMarker(cell.coordinates); + } + break; + } + // ignore: no_default_cases + default: + break; } }, - child: Container( - width: 24, - decoration: BoxDecoration( - color: getColor(cell.cellType), - border: Border.all(), - ), - child: cell.cellType != AutonomyCell.rover - ? null - : Container( - color: Colors.blue, - width: double.infinity, - height: double.infinity, - margin: const EdgeInsets.all(4), - child: Transform.rotate( - angle: -model.roverHeading * pi / 180, - child: const Icon(Icons.arrow_upward, size: 24), + builder: (context, candidates, rejects) => GestureDetector( + onTap: () { + if (cell.cellType == AutonomyCell.marker) { + model.removeMarker(cell.coordinates); + } else if (cell.cellType == AutonomyCell.empty) { + model.placeMarker(cell.coordinates); + } + }, + child: Container( + width: 24, + decoration: BoxDecoration( + color: getColor(cell.cellType), + border: Border.all(), + ), + child: cell.cellType != AutonomyCell.rover + ? null + : Container( + color: Colors.blue, + width: double.infinity, + height: double.infinity, + margin: const EdgeInsets.all(4), + child: Transform.rotate( + angle: -model.roverHeading * pi / 180, + child: const Icon(Icons.arrow_upward, size: 24), + ), ), - ), + ), ), ), ); @@ -170,7 +207,7 @@ class MapPage extends ReactiveWidget { ], ), // const SizedBox(height: 4), - AutonomyCommandEditor(model), + AutonomyCommandEditor(commandBuilder, model), // const SizedBox(height: 12), ], ), @@ -202,19 +239,39 @@ class MapLegend extends StatelessWidget { Text("Rover", style: context.textTheme.titleMedium), ], ), - Column( - children: [ - Container(width: 24, height: 24, color: Colors.green), - const SizedBox(height: 2), - Text("Destination", style: context.textTheme.titleMedium), - ], + Draggable( + data: AutonomyCell.destination, + dragAnchorStrategy: (draggable, context, position) => + const Offset(12, 12), + feedback: Container( + width: 24, + height: 24, + color: Colors.green.withOpacity(0.50), + ), + child: Column( + children: [ + Container(width: 24, height: 24, color: Colors.green), + const SizedBox(height: 2), + Text("Destination", style: context.textTheme.titleMedium), + ], + ), ), - Column( - children: [ - Container(width: 24, height: 24, color: Colors.black), - const SizedBox(height: 2), - Text("Obstacle", style: context.textTheme.titleMedium), - ], + Draggable( + data: AutonomyCell.obstacle, + dragAnchorStrategy: (draggable, context, position) => + const Offset(12, 12), + feedback: Container( + width: 24, + height: 24, + color: Colors.black.withOpacity(0.50), + ), + child: Column( + children: [ + Container(width: 24, height: 24, color: Colors.black), + const SizedBox(height: 2), + Text("Obstacle", style: context.textTheme.titleMedium), + ], + ), ), Column( children: [ @@ -223,12 +280,22 @@ class MapLegend extends StatelessWidget { Text("Path", style: context.textTheme.titleMedium), ], ), - Column( - children: [ - Container(width: 24, height: 24, color: Colors.red), - const SizedBox(height: 2), - Text("Marker", style: context.textTheme.titleMedium), - ], + Draggable( + data: AutonomyCell.marker, + dragAnchorStrategy: (draggable, context, position) => + const Offset(12, 12), + feedback: Container( + width: 24, + height: 24, + color: Colors.red.withOpacity(0.50), + ), + child: Column( + children: [ + Container(width: 24, height: 24, color: Colors.red), + const SizedBox(height: 2), + Text("Marker", style: context.textTheme.titleMedium), + ], + ), ), ], ); diff --git a/lib/src/widgets/atomic/autonomy_command.dart b/lib/src/widgets/atomic/autonomy_command.dart index cadbe81e1..f4c2ee2a8 100644 --- a/lib/src/widgets/atomic/autonomy_command.dart +++ b/lib/src/widgets/atomic/autonomy_command.dart @@ -5,14 +5,11 @@ import "package:rover_dashboard/models.dart"; import "package:rover_dashboard/widgets.dart"; /// A widget to edit an [AutonomyCommand]. -class AutonomyCommandEditor extends ReactiveWidget { +class AutonomyCommandEditor extends ReusableReactiveWidget { /// The autonomy view model. final AutonomyModel dataModel; /// A const constructor. - const AutonomyCommandEditor(this.dataModel); - - @override - AutonomyCommandBuilder createModel() => AutonomyCommandBuilder(); + const AutonomyCommandEditor(super.model, this.dataModel); /// Opens a dialog to prompt the user to create an [AutonomyCommand] and sends it to the rover. void createTask(BuildContext context, AutonomyCommandBuilder command) => showDialog(