Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create waypoint queue widget #25

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
171 changes: 171 additions & 0 deletions flutter_app/lib/widgets/waypoint_queue_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
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;

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<WaypointQueue> {
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, _latitude, _longitude, _altitude);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a , after _altitude

setState(() {
_widgetKey.currentState?.reassemble();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reassemble only runs on debug not builds, you might want to test the widget without this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without this, the widget does not update the table when a waypoint is added. what other method could I use to refresh the table so that it repopulates everything in the queue?

});
}

/// Sends a command to send a waypoint, bypassing the queue.
void _queueWaypointWithoutQueue() {
_getWaypointsFromInput();
widget.queueWaypoints.sendWaypointWithoutQueue(
widget.systemId, widget.componentId, _latitude, _longitude, _altitude);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a , after _altitude

}

/// Sends the first waypoint in the queue to the drone.
void _sendNextWaypointInQueue() {
widget.queueWaypoints.sendNextWaypointInQueue();
setState(() {
_widgetKey.currentState?.reassemble();
});
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've confirmed this with Aaron, you can send all the waypoints at once and mavlink will just kinda figure it out. The best way to do this is to create a method in the queueWaypoints class to handle this, lmk if you want to try doing that or if I should do that for you.

@override
Widget build(BuildContext context) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to center the elements

return Column(
BalajiLeninrajan marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporarily wrap this in a SizedBox with a fixed height and width for testing and showcase. It will be merged this way but we'll change it when integrating widget together (which is pretty far down the line)

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>[
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,
),
),
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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try putting the last two ElevatedButtons in an OverflowBar widget with a set spacing attr

onPressed: _queueWaypoint,
child: const Text('Add Waypoint to Queue')),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add , between ))

const SizedBox(height: 16),
ElevatedButton(
onPressed: _queueWaypointWithoutQueue,
child: const Text('Send Waypoint Immediately')),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add , between ))

],
);
}
}