From 1d2484cecb055a84d9b0ff77b06f237d52d08b34 Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Sun, 14 Jul 2024 17:38:39 -0400 Subject: [PATCH 01/11] create waypoint queue widget --- .../lib/widgets/waypoint_queue_widget.dart | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 flutter_app/lib/widgets/waypoint_queue_widget.dart diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart new file mode 100644 index 0000000..1477f8c --- /dev/null +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:imacs/modules/queue_waypoints.dart' + +/// Widget to queue waypoints of a drone using MAVLink communication. +/// +/// [DESCRIPTION] +class WaypointQueue extends StatefulWidget { + /// @brief Constructs a WaypointQueue widget. + /// + /// @param queueWaypoints + /// QueueWaypoints class instance + /// + /// @param systemId + /// system ID for command constructor + /// + /// @param componentId + /// component ID for command constructor + /// + final QueueWaypoints queueWaypoints; + final int systemId; + final int componentId; + + const WaypointQueue({ + Key? key, + required this.systemId, + required this.componentId, + required this.queueWaypoints, + }) : super(key: key); + + @override + WaypointQueueState createState() => WaypointQueueState(); +} + +/// State for the QueueWaypoints widget. +class WaypointQueueState extends State { + late double _latitude; + late double _longitude; + late double _altitude; + + /// Sends a command to queue a waypoint. + void _queueWaypoint() { + widget.queueWaypoints.queueWaypoint( + widget.systemId, + widget.componentId, + _latitude, + _longitude, + _altitude + ); + } + + /// Sends a command to send a waypoint, bypassing the queue. + void _queueWaypointWithoutQueue() { + widget.queueWaypoints.sendWaypointWithoutQueue( + widget.systemId, + widget.componentId, + _latitude, + _longitude, + _altitude + ); + } + + void _sendNextWaypointInQueue() { + /// remove first row of queue + /// update row numbers + } + + @override + Widget build(BuildContext context) { + /// could map a list to a table, table updates to the list + return Column(children: [ + + ElevatedButton( + onPressed: _queueWaypoint, + child: const Text('Add Waypoint to Queue') + ), + ElevatedButton( + onPressed: _queueWaypointWithoutQueue, + child: const Text('Send Waypoint Immediately') + ), + ],); + } +} \ No newline at end of file From 220c200e863e319837ab4097c0fef6ebd467c068 Mon Sep 17 00:00:00 2001 From: Mutt Shum Date: Sun, 14 Jul 2024 19:55:42 -0400 Subject: [PATCH 02/11] added data table to display queued waypoints --- .../lib/widgets/waypoint_queue_widget.dart | 78 +++++++++++++++---- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart index 1477f8c..aa1f225 100644 --- a/flutter_app/lib/widgets/waypoint_queue_widget.dart +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:imacs/modules/queue_waypoints.dart' +import 'package:imacs/modules/queue_waypoints.dart'; /// Widget to queue waypoints of a drone using MAVLink communication. /// @@ -33,12 +33,28 @@ class WaypointQueue extends StatefulWidget { /// State for the QueueWaypoints widget. class WaypointQueueState extends State { + final GlobalKey _widgetKey = GlobalKey(); // GlobalKey for the widget + final TextEditingController _latitudeInput = TextEditingController(); + final TextEditingController _longitudeInput = TextEditingController(); + final TextEditingController _altitudeInput = TextEditingController(); + late double _latitude; late double _longitude; late double _altitude; + /// Gets the waypoints from the TextFields + void _getWaypointsFromInput() { + try { + _latitude = double.parse(_latitudeInput.text); + _longitude = double.parse(_longitudeInput.text); + _altitude = double.parse(_altitudeInput.text); + } catch (e) { + print('Enter valid numbers.'); + } + } /// Sends a command to queue a waypoint. void _queueWaypoint() { + _getWaypointsFromInput(); widget.queueWaypoints.queueWaypoint( widget.systemId, widget.componentId, @@ -46,10 +62,14 @@ class WaypointQueueState extends State { _longitude, _altitude ); + setState(() { + _widgetKey.currentState?.reassemble(); + }); } /// Sends a command to send a waypoint, bypassing the queue. void _queueWaypointWithoutQueue() { + _getWaypointsFromInput(); widget.queueWaypoints.sendWaypointWithoutQueue( widget.systemId, widget.componentId, @@ -60,23 +80,55 @@ class WaypointQueueState extends State { } void _sendNextWaypointInQueue() { - /// remove first row of queue + /// send waypoint /// update row numbers } @override Widget build(BuildContext context) { /// could map a list to a table, table updates to the list - return Column(children: [ - - ElevatedButton( - onPressed: _queueWaypoint, - child: const Text('Add Waypoint to Queue') - ), - ElevatedButton( - onPressed: _queueWaypointWithoutQueue, - child: const Text('Send Waypoint Immediately') - ), - ],); + return Column( + children: [ + DataTable( + columns: const [ + DataColumn(label: Text('Latitude')), + DataColumn(label: Text('Longitude')), + DataColumn(label: Text('Altitude')), + ], + rows: widget.queueWaypoints.waypointQueue.map( + ((element) => DataRow( + cells: [ + DataCell(Text(element.x.toString())), + DataCell(Text(element.y.toString())), + DataCell(Text(element.z.toString())), + ], + )), + ).toList(), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: TextField(controller: _latitudeInput), + ), + Expanded( + child: TextField(controller: _longitudeInput), + ), + Expanded( + child: TextField(controller: _altitudeInput), + ), + ], + ), + ElevatedButton( + onPressed: _queueWaypoint, + child: const Text('Add Waypoint to Queue') + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _queueWaypointWithoutQueue, + child: const Text('Send Waypoint Immediately') + ), + ], + ); } } \ No newline at end of file From a514f549c4cc1f5517f97b40e1c896631b60c9b3 Mon Sep 17 00:00:00 2001 From: Mutt Shum Date: Sun, 14 Jul 2024 23:14:41 -0400 Subject: [PATCH 03/11] implemented send waypoint button --- .../lib/widgets/waypoint_queue_widget.dart | 77 +++++++++++++++---- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart index aa1f225..4912980 100644 --- a/flutter_app/lib/widgets/waypoint_queue_widget.dart +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -52,6 +52,7 @@ class WaypointQueueState extends State { print('Enter valid numbers.'); } } + /// Sends a command to queue a waypoint. void _queueWaypoint() { _getWaypointsFromInput(); @@ -79,16 +80,22 @@ class WaypointQueueState extends State { ); } + /// Sends the first waypoint in the queue to the drone. void _sendNextWaypointInQueue() { - /// send waypoint - /// update row numbers + widget.queueWaypoints.sendNextWaypointInQueue(); + setState(() { + _widgetKey.currentState?.reassemble(); + }); } @override Widget build(BuildContext context) { - /// could map a list to a table, table updates to the list return Column( children: [ + const Text( + 'Waypoint Queue', + style: TextStyle(fontWeight: FontWeight.bold), + ), DataTable( columns: const [ DataColumn(label: Text('Latitude')), @@ -105,20 +112,58 @@ class WaypointQueueState extends State { )), ).toList(), ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: TextField(controller: _latitudeInput), - ), - Expanded( - child: TextField(controller: _longitudeInput), - ), - Expanded( - child: TextField(controller: _altitudeInput), - ), - ], + const SizedBox(height: 16), + ElevatedButton( + onPressed: _sendNextWaypointInQueue, + child: const Text('Send Next Waypoint in Queue to Drone') + ), + const SizedBox(height: 16), + const Text( + 'Enter a Waypoint Below', + style: TextStyle(fontWeight: FontWeight.bold), ), + Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Latitude', + ), + controller: _latitudeInput, + ), + ), + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Longitude', + ), + controller: _longitudeInput, + ), + ), + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Altitude', + ), + controller: _altitudeInput, + ), + ), + ], + ), + ), + const SizedBox(height: 16), ElevatedButton( onPressed: _queueWaypoint, child: const Text('Add Waypoint to Queue') From f89f1c5042d293ba70ea97bb76e2eb678c949202 Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Sun, 14 Jul 2024 23:30:31 -0400 Subject: [PATCH 04/11] added widget description --- flutter_app/lib/widgets/waypoint_queue_widget.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart index 4912980..65f188b 100644 --- a/flutter_app/lib/widgets/waypoint_queue_widget.dart +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -3,7 +3,10 @@ import 'package:imacs/modules/queue_waypoints.dart'; /// Widget to queue waypoints of a drone using MAVLink communication. /// -/// [DESCRIPTION] +/// This widget displays a table that contains a queue of waypoints to be +/// sent to the drone. It provides functionality to add a waypoint to the +/// queue as well as bypass the queue and send a waypoint to the drone +/// immediately. class WaypointQueue extends StatefulWidget { /// @brief Constructs a WaypointQueue widget. /// From 5487aa31939b25531e59a47eb13119458a15f382 Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Sun, 14 Jul 2024 23:37:13 -0400 Subject: [PATCH 05/11] formatting --- .../lib/widgets/waypoint_queue_widget.dart | 69 ++++++++----------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart index 65f188b..9e1f808 100644 --- a/flutter_app/lib/widgets/waypoint_queue_widget.dart +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -2,23 +2,23 @@ import 'package:flutter/material.dart'; import 'package:imacs/modules/queue_waypoints.dart'; /// Widget to queue waypoints of a drone using MAVLink communication. -/// +/// /// This widget displays a table that contains a queue of waypoints to be /// sent to the drone. It provides functionality to add a waypoint to the /// queue as well as bypass the queue and send a waypoint to the drone /// immediately. class WaypointQueue extends StatefulWidget { /// @brief Constructs a WaypointQueue widget. - /// + /// /// @param queueWaypoints /// QueueWaypoints class instance - /// + /// /// @param systemId /// system ID for command constructor - /// + /// /// @param componentId /// component ID for command constructor - /// + /// final QueueWaypoints queueWaypoints; final int systemId; final int componentId; @@ -44,7 +44,7 @@ class WaypointQueueState extends State { late double _latitude; late double _longitude; late double _altitude; - + /// Gets the waypoints from the TextFields void _getWaypointsFromInput() { try { @@ -60,12 +60,7 @@ class WaypointQueueState extends State { void _queueWaypoint() { _getWaypointsFromInput(); widget.queueWaypoints.queueWaypoint( - widget.systemId, - widget.componentId, - _latitude, - _longitude, - _altitude - ); + widget.systemId, widget.componentId, _latitude, _longitude, _altitude); setState(() { _widgetKey.currentState?.reassemble(); }); @@ -75,12 +70,7 @@ class WaypointQueueState extends State { void _queueWaypointWithoutQueue() { _getWaypointsFromInput(); widget.queueWaypoints.sendWaypointWithoutQueue( - widget.systemId, - widget.componentId, - _latitude, - _longitude, - _altitude - ); + widget.systemId, widget.componentId, _latitude, _longitude, _altitude); } /// Sends the first waypoint in the queue to the drone. @@ -90,13 +80,13 @@ class WaypointQueueState extends State { _widgetKey.currentState?.reassemble(); }); } - + @override Widget build(BuildContext context) { return Column( children: [ const Text( - 'Waypoint Queue', + 'Waypoint Queue', style: TextStyle(fontWeight: FontWeight.bold), ), DataTable( @@ -105,24 +95,25 @@ class WaypointQueueState extends State { DataColumn(label: Text('Longitude')), DataColumn(label: Text('Altitude')), ], - rows: widget.queueWaypoints.waypointQueue.map( - ((element) => DataRow( - cells: [ - DataCell(Text(element.x.toString())), - DataCell(Text(element.y.toString())), - DataCell(Text(element.z.toString())), - ], - )), - ).toList(), + rows: widget.queueWaypoints.waypointQueue + .map( + ((element) => DataRow( + cells: [ + DataCell(Text(element.x.toString())), + DataCell(Text(element.y.toString())), + DataCell(Text(element.z.toString())), + ], + )), + ) + .toList(), ), const SizedBox(height: 16), ElevatedButton( - onPressed: _sendNextWaypointInQueue, - child: const Text('Send Next Waypoint in Queue to Drone') - ), + onPressed: _sendNextWaypointInQueue, + child: const Text('Send Next Waypoint in Queue to Drone')), const SizedBox(height: 16), const Text( - 'Enter a Waypoint Below', + 'Enter a Waypoint Below', style: TextStyle(fontWeight: FontWeight.bold), ), Padding( @@ -168,15 +159,13 @@ class WaypointQueueState extends State { ), const SizedBox(height: 16), ElevatedButton( - onPressed: _queueWaypoint, - child: const Text('Add Waypoint to Queue') - ), + onPressed: _queueWaypoint, + child: const Text('Add Waypoint to Queue')), const SizedBox(height: 16), ElevatedButton( - onPressed: _queueWaypointWithoutQueue, - child: const Text('Send Waypoint Immediately') - ), + onPressed: _queueWaypointWithoutQueue, + child: const Text('Send Waypoint Immediately')), ], ); } -} \ No newline at end of file +} From 403fb2154b0fd5e512bd1144090a8986d0b5127a Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Thu, 18 Jul 2024 21:42:19 -0400 Subject: [PATCH 06/11] switch column to ListView, nest buttons in OverflowBar --- .../lib/widgets/waypoint_queue_widget.dart | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart index 9e1f808..860f3bc 100644 --- a/flutter_app/lib/widgets/waypoint_queue_widget.dart +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -60,7 +60,12 @@ class WaypointQueueState extends State { void _queueWaypoint() { _getWaypointsFromInput(); widget.queueWaypoints.queueWaypoint( - widget.systemId, widget.componentId, _latitude, _longitude, _altitude); + widget.systemId, + widget.componentId, + _latitude, + _longitude, + _altitude, + ); setState(() { _widgetKey.currentState?.reassemble(); }); @@ -70,7 +75,12 @@ class WaypointQueueState extends State { void _queueWaypointWithoutQueue() { _getWaypointsFromInput(); widget.queueWaypoints.sendWaypointWithoutQueue( - widget.systemId, widget.componentId, _latitude, _longitude, _altitude); + widget.systemId, + widget.componentId, + _latitude, + _longitude, + _altitude, + ); } /// Sends the first waypoint in the queue to the drone. @@ -83,7 +93,7 @@ class WaypointQueueState extends State { @override Widget build(BuildContext context) { - return Column( + return ListView( children: [ const Text( 'Waypoint Queue', @@ -158,13 +168,17 @@ class WaypointQueueState extends State { ), ), const SizedBox(height: 16), - ElevatedButton( + OverflowBar(spacing: 10, children: [ + ElevatedButton( onPressed: _queueWaypoint, - child: const Text('Add Waypoint to Queue')), - const SizedBox(height: 16), - ElevatedButton( + child: const Text('Add Waypoint to Queue'), + ), + const SizedBox(height: 16), + ElevatedButton( onPressed: _queueWaypointWithoutQueue, - child: const Text('Send Waypoint Immediately')), + child: const Text('Send Waypoint Immediately'), + ), + ]), ], ); } From 9b2d055a32ec68b2a0b8c2c340d7a07fa49f2e2c Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Thu, 18 Jul 2024 21:52:48 -0400 Subject: [PATCH 07/11] nested listview in an expanded --- .../lib/widgets/waypoint_queue_widget.dart | 160 +++++++++--------- 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart index 860f3bc..5139d39 100644 --- a/flutter_app/lib/widgets/waypoint_queue_widget.dart +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -93,93 +93,95 @@ class WaypointQueueState extends State { @override Widget build(BuildContext context) { - return ListView( - children: [ - const Text( - 'Waypoint Queue', - style: TextStyle(fontWeight: FontWeight.bold), - ), - DataTable( - columns: const [ - DataColumn(label: Text('Latitude')), - DataColumn(label: Text('Longitude')), - DataColumn(label: Text('Altitude')), - ], - rows: widget.queueWaypoints.waypointQueue - .map( - ((element) => DataRow( - cells: [ - DataCell(Text(element.x.toString())), - DataCell(Text(element.y.toString())), - DataCell(Text(element.z.toString())), - ], - )), - ) - .toList(), - ), - const SizedBox(height: 16), - ElevatedButton( - onPressed: _sendNextWaypointInQueue, - child: const Text('Send Next Waypoint in Queue to Drone')), - const SizedBox(height: 16), - const Text( - 'Enter a Waypoint Below', - style: TextStyle(fontWeight: FontWeight.bold), - ), - Padding( - padding: const EdgeInsets.all(10.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 120, - height: 40, - child: TextField( - decoration: const InputDecoration( - border: OutlineInputBorder(), - hintText: 'Latitude', + return Expanded( + child: ListView( + children: [ + const Text( + 'Waypoint Queue', + style: TextStyle(fontWeight: FontWeight.bold), + ), + DataTable( + columns: const [ + DataColumn(label: Text('Latitude')), + DataColumn(label: Text('Longitude')), + DataColumn(label: Text('Altitude')), + ], + rows: widget.queueWaypoints.waypointQueue + .map( + ((element) => DataRow( + cells: [ + DataCell(Text(element.x.toString())), + DataCell(Text(element.y.toString())), + DataCell(Text(element.z.toString())), + ], + )), + ) + .toList(), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _sendNextWaypointInQueue, + child: const Text('Send Next Waypoint in Queue to Drone')), + const SizedBox(height: 16), + const Text( + 'Enter a Waypoint Below', + style: TextStyle(fontWeight: FontWeight.bold), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Latitude', + ), + controller: _latitudeInput, ), - controller: _latitudeInput, ), - ), - SizedBox( - width: 120, - height: 40, - child: TextField( - decoration: const InputDecoration( - border: OutlineInputBorder(), - hintText: 'Longitude', + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Longitude', + ), + controller: _longitudeInput, ), - controller: _longitudeInput, ), - ), - SizedBox( - width: 120, - height: 40, - child: TextField( - decoration: const InputDecoration( - border: OutlineInputBorder(), - hintText: 'Altitude', + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Altitude', + ), + controller: _altitudeInput, ), - controller: _altitudeInput, ), - ), - ], - ), - ), - const SizedBox(height: 16), - OverflowBar(spacing: 10, children: [ - ElevatedButton( - onPressed: _queueWaypoint, - child: const Text('Add Waypoint to Queue'), + ], + ), ), const SizedBox(height: 16), - ElevatedButton( - onPressed: _queueWaypointWithoutQueue, - child: const Text('Send Waypoint Immediately'), - ), - ]), - ], + OverflowBar(spacing: 10, children: [ + ElevatedButton( + onPressed: _queueWaypoint, + child: const Text('Add Waypoint to Queue'), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _queueWaypointWithoutQueue, + child: const Text('Send Waypoint Immediately'), + ), + ]), + ], + ), ); } } From 1b41b08f37fe99b9321097bec201fbb8e4af7bc9 Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Fri, 19 Jul 2024 12:23:30 -0400 Subject: [PATCH 08/11] used empty set state function to refresh table --- flutter_app/lib/widgets/waypoint_queue_widget.dart | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart index 5139d39..aaf638e 100644 --- a/flutter_app/lib/widgets/waypoint_queue_widget.dart +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -36,7 +36,6 @@ class WaypointQueue extends StatefulWidget { /// State for the QueueWaypoints widget. class WaypointQueueState extends State { - final GlobalKey _widgetKey = GlobalKey(); // GlobalKey for the widget final TextEditingController _latitudeInput = TextEditingController(); final TextEditingController _longitudeInput = TextEditingController(); final TextEditingController _altitudeInput = TextEditingController(); @@ -66,9 +65,7 @@ class WaypointQueueState extends State { _longitude, _altitude, ); - setState(() { - _widgetKey.currentState?.reassemble(); - }); + setState(() {}); } /// Sends a command to send a waypoint, bypassing the queue. @@ -86,9 +83,7 @@ class WaypointQueueState extends State { /// Sends the first waypoint in the queue to the drone. void _sendNextWaypointInQueue() { widget.queueWaypoints.sendNextWaypointInQueue(); - setState(() { - _widgetKey.currentState?.reassemble(); - }); + setState(() {}); } @override From 6330ce4ba651a54fc1606f8e0417181f5aded2a5 Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Fri, 19 Jul 2024 14:24:40 -0400 Subject: [PATCH 09/11] created waypoint queue widget test --- .../widget/waypoint_queue_widget_test.dart | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 flutter_app/test/widget/waypoint_queue_widget_test.dart diff --git a/flutter_app/test/widget/waypoint_queue_widget_test.dart b/flutter_app/test/widget/waypoint_queue_widget_test.dart new file mode 100644 index 0000000..1672dfe --- /dev/null +++ b/flutter_app/test/widget/waypoint_queue_widget_test.dart @@ -0,0 +1,178 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:imacs/modules/mavlink_communication.dart'; +import 'package:imacs/modules/queue_waypoints.dart'; +import 'package:imacs/widgets/waypoint_queue_widget.dart'; + +void main() { + group('WaypointQueue widget', () { + testWidgets( + 'WaypointQueueWidget displays a table, text input fields, and 3 buttons', + (WidgetTester tester) async { + final mavlinkCommunication = MavlinkCommunication( + MavlinkCommunicationType.tcp, '127.0.0.1', 14550); + final queueWaypoints = QueueWaypoints(comm: mavlinkCommunication); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: WaypointQueue( + queueWaypoints: queueWaypoints, + systemId: 0, + componentId: 0, + ), + ), + )); + + expect(find.byType(ElevatedButton), findsNWidgets(3)); + expect(find.byType(DataTable), findsOneWidget); + expect(find.byType(TextField), findsNWidgets(3)); + }); + testWidgets( + 'WaypointQueue sends a waypoint to the drone without queueing it', + (WidgetTester tester) async { + final mavlinkCommunication = MavlinkCommunication( + MavlinkCommunicationType.tcp, '127.0.0.1', 14550); + final queueWaypoints = QueueWaypoints(comm: mavlinkCommunication); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: WaypointQueue( + queueWaypoints: queueWaypoints, + systemId: 0, + componentId: 0, + ), + ), + )); + + /// Enter a waypoint in the text fields + await tester.enterText( + find.ancestor( + of: find.text('Latitude'), + matching: find.byType(TextField), + ), + '10.01'); + await tester.enterText( + find.ancestor( + of: find.text('Longitude'), + matching: find.byType(TextField), + ), + '-20.02'); + await tester.enterText( + find.ancestor( + of: find.text('Altitude'), + matching: find.byType(TextField), + ), + '30.03'); + + expect(find.text('10.01'), findsOneWidget); + expect(find.text('-20.02'), findsOneWidget); + expect(find.text('30.03'), findsOneWidget); + + await tester.tap( + find.widgetWithText(ElevatedButton, 'Send Waypoint Immediately')); + await tester.pump(); + + expect(queueWaypoints.waypointQueue.length, 0); + expect(find.text('10.01'), findsOneWidget); + expect(find.text('-20.02'), findsOneWidget); + expect(find.text('30.03'), findsOneWidget); + }); + + testWidgets('WaypointQueue adds waypoint to queue on button press', + (WidgetTester tester) async { + final mavlinkCommunication = MavlinkCommunication( + MavlinkCommunicationType.tcp, '127.0.0.1', 14550); + final queueWaypoints = QueueWaypoints(comm: mavlinkCommunication); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: WaypointQueue( + queueWaypoints: queueWaypoints, + systemId: 0, + componentId: 0, + ), + ), + )); + + /// Enter a waypoint in the text fields + await tester.enterText( + find.ancestor( + of: find.text('Latitude'), + matching: find.byType(TextField), + ), + '10.01'); + await tester.enterText( + find.ancestor( + of: find.text('Longitude'), + matching: find.byType(TextField), + ), + '-20.02'); + await tester.enterText( + find.ancestor( + of: find.text('Altitude'), + matching: find.byType(TextField), + ), + '30.03'); + + expect(find.text('10.01'), findsOneWidget); + expect(find.text('-20.02'), findsOneWidget); + expect(find.text('30.03'), findsOneWidget); + + await tester + .tap(find.widgetWithText(ElevatedButton, 'Add Waypoint to Queue')); + await tester.pump(); + + expect( + find.ancestor( + of: find.text('10.01'), matching: find.byType(DataCell)), + findsOneWidget); + expect( + find.ancestor( + of: find.text('-20.02'), matching: find.byType(DataCell)), + findsOneWidget); + expect( + find.ancestor( + of: find.text('30.03'), matching: find.byType(DataCell)), + findsOneWidget); + expect(queueWaypoints.waypointQueue.length, 1); + expect(queueWaypoints.waypointQueue[0].x, 10.01); + expect(queueWaypoints.waypointQueue[0].y, -20.02); + expect(queueWaypoints.waypointQueue[0].z, 30.03); + }); + testWidgets('WaypointQueue sends first waypoint in queue to drone', + (WidgetTester tester) async { + final mavlinkCommunication = MavlinkCommunication( + MavlinkCommunicationType.tcp, '127.0.0.1', 14550); + final queueWaypoints = QueueWaypoints(comm: mavlinkCommunication); + + queueWaypoints.queueWaypoint(1, 1, 10.01, -20.02, 30.03); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: WaypointQueue( + queueWaypoints: queueWaypoints, + systemId: 0, + componentId: 0, + ), + ), + )); + + expect(queueWaypoints.waypointQueue.length, 1); + expect(find.text('10.01'), findsOneWidget); + expect(find.text('-20.02'), findsOneWidget); + expect(find.text('30.03'), findsOneWidget); + expect(queueWaypoints.waypointQueue[0].x, 10.01); + expect(queueWaypoints.waypointQueue[0].y, -20.02); + expect(queueWaypoints.waypointQueue[0].z, 30.03); + + await tester.tap(find.widgetWithText( + ElevatedButton, 'Send Next Waypoint in Queue to Drone')); + await tester.pump(); + + expect(queueWaypoints.waypointQueue.length, 0); + expect(find.text('10.01'), findsNothing); + expect(find.text('-20.02'), findsNothing); + expect(find.text('30.03'), findsNothing); + }); + }); +} From fd73cfca6fcf626b33b2eaf9293892a6ca9e8c1c Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Fri, 19 Jul 2024 15:07:32 -0400 Subject: [PATCH 10/11] fixed bugs --- .../lib/widgets/waypoint_queue_widget.dart | 172 +++++++++--------- .../widget/waypoint_queue_widget_test.dart | 21 +-- 2 files changed, 94 insertions(+), 99 deletions(-) diff --git a/flutter_app/lib/widgets/waypoint_queue_widget.dart b/flutter_app/lib/widgets/waypoint_queue_widget.dart index aaf638e..6cc189e 100644 --- a/flutter_app/lib/widgets/waypoint_queue_widget.dart +++ b/flutter_app/lib/widgets/waypoint_queue_widget.dart @@ -88,95 +88,99 @@ class WaypointQueueState extends State { @override Widget build(BuildContext context) { - return Expanded( - child: ListView( - children: [ - const Text( - 'Waypoint Queue', - style: TextStyle(fontWeight: FontWeight.bold), - ), - DataTable( - columns: const [ - DataColumn(label: Text('Latitude')), - DataColumn(label: Text('Longitude')), - DataColumn(label: Text('Altitude')), - ], - rows: widget.queueWaypoints.waypointQueue - .map( - ((element) => DataRow( - cells: [ - DataCell(Text(element.x.toString())), - DataCell(Text(element.y.toString())), - DataCell(Text(element.z.toString())), - ], - )), - ) - .toList(), - ), - const SizedBox(height: 16), - ElevatedButton( - onPressed: _sendNextWaypointInQueue, - child: const Text('Send Next Waypoint in Queue to Drone')), - const SizedBox(height: 16), - const Text( - 'Enter a Waypoint Below', - style: TextStyle(fontWeight: FontWeight.bold), - ), - Padding( - padding: const EdgeInsets.all(10.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 120, - height: 40, - child: TextField( - decoration: const InputDecoration( - border: OutlineInputBorder(), - hintText: 'Latitude', + return Column( + children: [ + const Text( + 'Waypoint Queue', + style: TextStyle(fontWeight: FontWeight.bold), + ), + Expanded( + child: ListView( + children: [ + DataTable( + columns: const [ + DataColumn(label: Text('Latitude')), + DataColumn(label: Text('Longitude')), + DataColumn(label: Text('Altitude')), + ], + rows: widget.queueWaypoints.waypointQueue + .map( + ((element) => DataRow( + cells: [ + DataCell(Text(element.x.toString())), + DataCell(Text(element.y.toString())), + DataCell(Text(element.z.toString())), + ], + )), + ) + .toList(), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _sendNextWaypointInQueue, + child: const Text('Send Next Waypoint in Queue to Drone')), + const SizedBox(height: 16), + const Text( + 'Enter a Waypoint Below', + style: TextStyle(fontWeight: FontWeight.bold), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Latitude', + ), + controller: _latitudeInput, + ), ), - controller: _latitudeInput, - ), - ), - SizedBox( - width: 120, - height: 40, - child: TextField( - decoration: const InputDecoration( - border: OutlineInputBorder(), - hintText: 'Longitude', + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Longitude', + ), + controller: _longitudeInput, + ), ), - controller: _longitudeInput, - ), - ), - SizedBox( - width: 120, - height: 40, - child: TextField( - decoration: const InputDecoration( - border: OutlineInputBorder(), - hintText: 'Altitude', + SizedBox( + width: 120, + height: 40, + child: TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Altitude', + ), + controller: _altitudeInput, + ), ), - controller: _altitudeInput, - ), + ], + ), + ), + const SizedBox(height: 16), + OverflowBar(spacing: 10, children: [ + ElevatedButton( + onPressed: _queueWaypoint, + child: const Text('Add Waypoint to Queue'), ), - ], - ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _queueWaypointWithoutQueue, + child: const Text('Send Waypoint Immediately'), + ), + ]), + ], ), - const SizedBox(height: 16), - OverflowBar(spacing: 10, children: [ - ElevatedButton( - onPressed: _queueWaypoint, - child: const Text('Add Waypoint to Queue'), - ), - const SizedBox(height: 16), - ElevatedButton( - onPressed: _queueWaypointWithoutQueue, - child: const Text('Send Waypoint Immediately'), - ), - ]), - ], - ), + ), + ], ); } } diff --git a/flutter_app/test/widget/waypoint_queue_widget_test.dart b/flutter_app/test/widget/waypoint_queue_widget_test.dart index 1672dfe..1c946eb 100644 --- a/flutter_app/test/widget/waypoint_queue_widget_test.dart +++ b/flutter_app/test/widget/waypoint_queue_widget_test.dart @@ -122,18 +122,9 @@ void main() { .tap(find.widgetWithText(ElevatedButton, 'Add Waypoint to Queue')); await tester.pump(); - expect( - find.ancestor( - of: find.text('10.01'), matching: find.byType(DataCell)), - findsOneWidget); - expect( - find.ancestor( - of: find.text('-20.02'), matching: find.byType(DataCell)), - findsOneWidget); - expect( - find.ancestor( - of: find.text('30.03'), matching: find.byType(DataCell)), - findsOneWidget); + expect(find.text('10.01'), findsNWidgets(2)); + expect(find.text('-20.02'), findsNWidgets(2)); + expect(find.text('30.03'), findsNWidgets(2)); expect(queueWaypoints.waypointQueue.length, 1); expect(queueWaypoints.waypointQueue[0].x, 10.01); expect(queueWaypoints.waypointQueue[0].y, -20.02); @@ -145,7 +136,7 @@ void main() { MavlinkCommunicationType.tcp, '127.0.0.1', 14550); final queueWaypoints = QueueWaypoints(comm: mavlinkCommunication); - queueWaypoints.queueWaypoint(1, 1, 10.01, -20.02, 30.03); + queueWaypoints.queueWaypoint(0, 0, 10.01, -20.02, 30.03); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -167,12 +158,12 @@ void main() { await tester.tap(find.widgetWithText( ElevatedButton, 'Send Next Waypoint in Queue to Drone')); - await tester.pump(); + await tester.pump(const Duration(milliseconds: 10000)); - expect(queueWaypoints.waypointQueue.length, 0); expect(find.text('10.01'), findsNothing); expect(find.text('-20.02'), findsNothing); expect(find.text('30.03'), findsNothing); + expect(queueWaypoints.waypointQueue.length, 0); }); }); } From 5a8cee95ceee26b15b136da5c1edf8cb548fb3c5 Mon Sep 17 00:00:00 2001 From: Andrew Shum Date: Sat, 20 Jul 2024 17:19:38 -0400 Subject: [PATCH 11/11] widget test changes --- flutter_app/test/widget/waypoint_queue_widget_test.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flutter_app/test/widget/waypoint_queue_widget_test.dart b/flutter_app/test/widget/waypoint_queue_widget_test.dart index 1c946eb..3292cff 100644 --- a/flutter_app/test/widget/waypoint_queue_widget_test.dart +++ b/flutter_app/test/widget/waypoint_queue_widget_test.dart @@ -134,6 +134,7 @@ void main() { (WidgetTester tester) async { final mavlinkCommunication = MavlinkCommunication( MavlinkCommunicationType.tcp, '127.0.0.1', 14550); + await mavlinkCommunication.tcpSocketInitializationFlag.future; final queueWaypoints = QueueWaypoints(comm: mavlinkCommunication); queueWaypoints.queueWaypoint(0, 0, 10.01, -20.02, 30.03); @@ -158,7 +159,7 @@ void main() { await tester.tap(find.widgetWithText( ElevatedButton, 'Send Next Waypoint in Queue to Drone')); - await tester.pump(const Duration(milliseconds: 10000)); + await tester.pumpAndSettle(); expect(find.text('10.01'), findsNothing); expect(find.text('-20.02'), findsNothing);