diff --git a/lib/widgets/draggable_containers/draggable_nt4_widget_container.dart b/lib/widgets/draggable_containers/draggable_nt4_widget_container.dart index ba66cc98..6af9419d 100644 --- a/lib/widgets/draggable_containers/draggable_nt4_widget_container.dart +++ b/lib/widgets/draggable_containers/draggable_nt4_widget_container.dart @@ -7,6 +7,7 @@ import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/differential_d import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/field_widget.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/fms_info.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/gyro.dart'; +import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/network_alerts.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/pid_controller.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/power_distribution.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/combo_box_chooser.dart'; @@ -395,6 +396,11 @@ class DraggableNT4WidgetContainer extends DraggableWidgetContainer { key: UniqueKey(), jsonData: jsonData['properties'], ); + case 'Alerts': + return NetworkAlerts.fromJson( + key: UniqueKey(), + jsonData: jsonData['properties'], + ); default: return TextDisplay.fromJson( key: UniqueKey(), diff --git a/lib/widgets/network_tree/tree_row.dart b/lib/widgets/network_tree/tree_row.dart index 915aa234..833ca369 100644 --- a/lib/widgets/network_tree/tree_row.dart +++ b/lib/widgets/network_tree/tree_row.dart @@ -8,6 +8,7 @@ import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/differential_d import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/field_widget.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/fms_info.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/gyro.dart'; +import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/network_alerts.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/pid_controller.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/power_distribution.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/multi-topic/combo_box_chooser.dart'; @@ -170,6 +171,8 @@ class TreeRow { return FMSInfo(key: UniqueKey(), topic: topic); case 'RobotPreferences': return RobotPreferences(key: UniqueKey(), topic: topic); + case 'Alerts': + return NetworkAlerts(key: UniqueKey(), topic: topic); } return null; @@ -214,6 +217,9 @@ class TreeRow { } else if (primary is RobotPreferences) { width = normalGridSize * 2; height = normalGridSize * 3; + } else if (primary is NetworkAlerts) { + width = normalGridSize * 3; + height = normalGridSize * 2; } return WidgetContainer( diff --git a/lib/widgets/nt4_widgets/multi-topic/network_alerts.dart b/lib/widgets/nt4_widgets/multi-topic/network_alerts.dart new file mode 100644 index 00000000..cd7ed1eb --- /dev/null +++ b/lib/widgets/nt4_widgets/multi-topic/network_alerts.dart @@ -0,0 +1,138 @@ +import 'package:dot_cast/dot_cast.dart'; +import 'package:elastic_dashboard/services/globals.dart'; +import 'package:elastic_dashboard/services/nt4_connection.dart'; +import 'package:elastic_dashboard/widgets/nt4_widgets/nt4_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class NetworkAlerts extends StatelessWidget with NT4Widget { + @override + String type = 'Alerts'; + + late String errorsTopicName; + late String warningsTopicName; + late String infosTopicName; + + NetworkAlerts({super.key, required topic, period = Globals.defaultPeriod}) { + super.topic = topic; + super.period = period; + + init(); + } + + NetworkAlerts.fromJson({super.key, required Map jsonData}) { + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; + + init(); + } + + @override + void init() { + super.init(); + + errorsTopicName = '$topic/errors'; + warningsTopicName = '$topic/warnings'; + infosTopicName = '$topic/infos'; + } + + @override + void resetSubscription() { + super.resetSubscription(); + + errorsTopicName = '$topic/errors'; + warningsTopicName = '$topic/warnings'; + infosTopicName = '$topic/infos'; + } + + @override + Widget build(BuildContext context) { + notifier = context.watch(); + + return StreamBuilder( + stream: subscription?.periodicStream(), + builder: (context, snapshot) { + List errorsRaw = nt4Connection + .getLastAnnouncedValue(errorsTopicName) + ?.tryCast>() ?? + []; + + List warningsRaw = nt4Connection + .getLastAnnouncedValue(warningsTopicName) + ?.tryCast>() ?? + []; + + List infosRaw = nt4Connection + .getLastAnnouncedValue(infosTopicName) + ?.tryCast>() ?? + []; + + List errors = errorsRaw.whereType().toList(); + List warnings = warningsRaw.whereType().toList(); + List infos = infosRaw.whereType().toList(); + + return ListView.builder( + itemCount: errors.length + warnings.length + infos.length, + itemBuilder: (context, index) { + String alertType = 'error'; + String alertMessage; + if (index >= errors.length) { + index -= errors.length; + alertType = 'warning'; + } + if (index >= warnings.length && alertType == 'warning') { + index -= warnings.length; + alertType = 'info'; + } + if (index >= infos.length && alertType == 'info') { + alertType = 'none'; + } + + TextStyle? messageStyle = Theme.of(context).textTheme.bodyMedium; + + switch (alertType) { + case 'error': + alertMessage = errors[index]; + return ListTile( + dense: true, + contentPadding: const EdgeInsets.symmetric(horizontal: 8.0), + leading: const Icon( + Icons.cancel, + size: 24, + color: Colors.red, + ), + title: Text(alertMessage, style: messageStyle), + ); + case 'warning': + alertMessage = warnings[index]; + return ListTile( + dense: true, + contentPadding: const EdgeInsets.symmetric(horizontal: 8.0), + leading: const Icon( + Icons.warning, + size: 24, + color: Colors.yellow, + ), + title: Text(alertMessage, style: messageStyle), + ); + case 'info': + alertMessage = infos[index]; + return ListTile( + dense: true, + contentPadding: const EdgeInsets.symmetric(horizontal: 8.0), + leading: const Icon( + Icons.info, + size: 24, + color: Colors.green, + ), + title: Text(alertMessage, style: messageStyle), + ); + default: + return Container(); + } + }, + ); + }, + ); + } +}