From a1a988ee2d16a4fd861c10be13972c964bbecf5a Mon Sep 17 00:00:00 2001 From: Gold872 Date: Sun, 15 Oct 2023 19:15:41 -0400 Subject: [PATCH] Prevent wrongly typed data from crashing program when loading --- .../multi-topic/camera_stream.dart | 8 ++-- .../multi-topic/combo_box_chooser.dart | 26 ++++------ .../multi-topic/command_scheduler.dart | 48 ++++++------------- .../multi-topic/command_widget.dart | 19 ++++---- .../multi-topic/differential_drive.dart | 11 +++-- .../nt4_widgets/multi-topic/field_widget.dart | 21 ++++---- .../nt4_widgets/multi-topic/fms_info.dart | 20 ++++---- lib/widgets/nt4_widgets/multi-topic/gyro.dart | 10 ++-- .../multi-topic/pid_controller.dart | 27 +++++------ .../multi-topic/power_distribution.dart | 17 +++---- .../multi-topic/robot_preferences.dart | 5 +- .../multi-topic/split_button_chooser.dart | 25 ++++------ .../multi-topic/subsystem_widget.dart | 17 +++---- .../nt4_widgets/single_topic/boolean_box.dart | 15 +++--- .../nt4_widgets/single_topic/graph.dart | 18 +++---- .../nt4_widgets/single_topic/match_time.dart | 7 +-- .../single_topic/multi_color_view.dart | 17 +++---- .../nt4_widgets/single_topic/number_bar.dart | 17 +++---- .../single_topic/number_slider.dart | 13 ++--- .../single_topic/single_color_view.dart | 7 +-- .../single_topic/text_display.dart | 5 +- .../single_topic/toggle_button.dart | 9 ++-- .../single_topic/toggle_switch.dart | 9 ++-- .../single_topic/voltage_view.dart | 17 +++---- pubspec.lock | 8 ++++ pubspec.yaml | 1 + 26 files changed, 198 insertions(+), 199 deletions(-) diff --git a/lib/widgets/nt4_widgets/multi-topic/camera_stream.dart b/lib/widgets/nt4_widgets/multi-topic/camera_stream.dart index 1fa9e985..0abf6a9b 100644 --- a/lib/widgets/nt4_widgets/multi-topic/camera_stream.dart +++ b/lib/widgets/nt4_widgets/multi-topic/camera_stream.dart @@ -1,3 +1,4 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -32,8 +33,8 @@ class CameraStreamWidget extends StatelessWidget with NT4Widget { CameraStreamWidget.fromJson( {super.key, required Map jsonData}) { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -110,7 +111,8 @@ class CameraStreamWidget extends StatelessWidget with NT4Widget { rawStreams = value; - List rawStreamsList = rawStreams as List? ?? []; + List rawStreamsList = + rawStreams?.tryCast>() ?? []; List streams = []; for (Object? stream in rawStreamsList) { diff --git a/lib/widgets/nt4_widgets/multi-topic/combo_box_chooser.dart b/lib/widgets/nt4_widgets/multi-topic/combo_box_chooser.dart index 2089a03e..121990ef 100644 --- a/lib/widgets/nt4_widgets/multi-topic/combo_box_chooser.dart +++ b/lib/widgets/nt4_widgets/multi-topic/combo_box_chooser.dart @@ -1,4 +1,6 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; import 'package:elastic_dashboard/widgets/nt4_widgets/nt4_widget.dart'; @@ -32,8 +34,8 @@ class ComboBoxChooser extends StatelessWidget with NT4Widget { ComboBoxChooser.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? 0.033; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -99,34 +101,26 @@ class ComboBoxChooser extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), builder: (context, snapshot) { List rawOptions = nt4Connection - .getLastAnnouncedValue(optionsTopicName) as List? ?? + .getLastAnnouncedValue(optionsTopicName) + ?.tryCast>() ?? []; - List options = []; - - for (Object? option in rawOptions) { - if (option == null || option is! String) { - continue; - } - - options.add(option); - } + List options = rawOptions.whereType().toList(); String? active = - nt4Connection.getLastAnnouncedValue(activeTopicName) as String?; + tryCast(nt4Connection.getLastAnnouncedValue(activeTopicName)); if (active != null && active == '') { active = null; } String? selected = - nt4Connection.getLastAnnouncedValue(selectedTopicName) as String?; + tryCast(nt4Connection.getLastAnnouncedValue(selectedTopicName)); if (selected != null && selected == '') { selected = null; } String? defaultOption = - nt4Connection.getLastAnnouncedValue(defaultTopicName) as String?; - + tryCast(nt4Connection.getLastAnnouncedValue(defaultTopicName)); if (defaultOption != null && defaultOption == '') { defaultOption = null; } diff --git a/lib/widgets/nt4_widgets/multi-topic/command_scheduler.dart b/lib/widgets/nt4_widgets/multi-topic/command_scheduler.dart index 017c5870..9b09dee4 100644 --- a/lib/widgets/nt4_widgets/multi-topic/command_scheduler.dart +++ b/lib/widgets/nt4_widgets/multi-topic/command_scheduler.dart @@ -1,3 +1,4 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -25,8 +26,8 @@ class CommandSchedulerWidget extends StatelessWidget with NT4Widget { CommandSchedulerWidget.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -53,18 +54,12 @@ class CommandSchedulerWidget extends StatelessWidget with NT4Widget { void cancelCommand(int id) { List currentCancellationsRaw = nt4Connection - .getLastAnnouncedValue(cancelTopicName) as List? ?? + .getLastAnnouncedValue(cancelTopicName) + ?.tryCast>() ?? []; - List currentCancellations = []; - - for (Object? cancelID in currentCancellationsRaw) { - if (cancelID == null || cancelID is! int) { - continue; - } - - currentCancellations.add(cancelID); - } + List currentCancellations = + currentCancellationsRaw.whereType().toList(); currentCancellations.add(id); @@ -86,30 +81,17 @@ class CommandSchedulerWidget extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), builder: (context, snapshot) { List rawNames = nt4Connection - .getLastAnnouncedValue(namesTopicName) as List? ?? - []; - List rawIds = nt4Connection.getLastAnnouncedValue(idsTopicName) - as List? ?? + .getLastAnnouncedValue(namesTopicName) + ?.tryCast>() ?? []; - List names = []; - List ids = []; - - for (Object? name in rawNames) { - if (name == null || name is! String) { - continue; - } - - names.add(name); - } - - for (Object? id in rawIds) { - if (id == null || id is! int) { - continue; - } + List rawIds = nt4Connection + .getLastAnnouncedValue(idsTopicName) + ?.tryCast>() ?? + []; - ids.add(id); - } + List names = rawNames.whereType().toList(); + List ids = rawIds.whereType().toList(); return Column( mainAxisAlignment: MainAxisAlignment.start, diff --git a/lib/widgets/nt4_widgets/multi-topic/command_widget.dart b/lib/widgets/nt4_widgets/multi-topic/command_widget.dart index fe91cc99..81ac79ef 100644 --- a/lib/widgets/nt4_widgets/multi-topic/command_widget.dart +++ b/lib/widgets/nt4_widgets/multi-topic/command_widget.dart @@ -1,3 +1,4 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -22,8 +23,8 @@ class CommandWidget extends StatelessWidget with NT4Widget { } CommandWidget.fromJson({super.key, required Map jsonData}) { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? ''; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -53,12 +54,14 @@ class CommandWidget extends StatelessWidget with NT4Widget { return StreamBuilder( stream: subscription?.periodicStream(), builder: (context, snapshot) { - bool running = - nt4Connection.getLastAnnouncedValue(runningTopicName) as bool? ?? - false; - String name = - nt4Connection.getLastAnnouncedValue(nameTopicName) as String? ?? - 'Unknown'; + bool running = nt4Connection + .getLastAnnouncedValue(runningTopicName) + ?.tryCast() ?? + false; + String name = nt4Connection + .getLastAnnouncedValue(nameTopicName) + ?.tryCast() ?? + 'Unknown'; String buttonText = topic.substring(topic.lastIndexOf('/') + 1); diff --git a/lib/widgets/nt4_widgets/multi-topic/differential_drive.dart b/lib/widgets/nt4_widgets/multi-topic/differential_drive.dart index 559e6b0a..49b5bc1b 100644 --- a/lib/widgets/nt4_widgets/multi-topic/differential_drive.dart +++ b/lib/widgets/nt4_widgets/multi-topic/differential_drive.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -36,8 +37,8 @@ class DifferentialDrive extends StatelessWidget with NT4Widget { DifferentialDrive.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -73,10 +74,12 @@ class DifferentialDrive extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), builder: (context, snapshot) { double leftSpeed = nt4Connection - .getLastAnnouncedValue(leftSpeedTopicName) as double? ?? + .getLastAnnouncedValue(leftSpeedTopicName) + ?.tryCast() ?? 0.0; double rightSpeed = nt4Connection - .getLastAnnouncedValue(rightSpeedTopicName) as double? ?? + .getLastAnnouncedValue(rightSpeedTopicName) + ?.tryCast() ?? 0.0; if (leftSpeed != leftSpeedPreviousValue) { diff --git a/lib/widgets/nt4_widgets/multi-topic/field_widget.dart b/lib/widgets/nt4_widgets/multi-topic/field_widget.dart index 9ea84ae0..f8ee894d 100644 --- a/lib/widgets/nt4_widgets/multi-topic/field_widget.dart +++ b/lib/widgets/nt4_widgets/multi-topic/field_widget.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/field_images.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; @@ -52,16 +53,16 @@ class FieldWidget extends StatelessWidget with NT4Widget { } FieldWidget.fromJson({super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; - fieldGame = jsonData['field_game'] ?? fieldGame; + fieldGame = tryCast(jsonData['field_game']) ?? fieldGame; - robotWidthMeters = jsonData['robot_width'] ?? 0.82; - robotLengthMeters = jsonData['robot_length'] ?? 1.00; + robotWidthMeters = tryCast(jsonData['robot_width']) ?? 0.82; + robotLengthMeters = tryCast(jsonData['robot_length']) ?? 1.00; - showOtherObjects = jsonData['show_other_objects'] ?? true; - showTrajectories = jsonData['show_trajectories'] ?? true; + showOtherObjects = tryCast(jsonData['show_other_objects']) ?? true; + showTrajectories = tryCast(jsonData['show_trajectories']) ?? true; init(); } @@ -332,7 +333,8 @@ class FieldWidget extends StatelessWidget with NT4Widget { } List robotPositionRaw = nt4Connection - .getLastAnnouncedValue(robotTopicName) as List? ?? + .getLastAnnouncedValue(robotTopicName) + ?.tryCast>() ?? []; List? robotPosition = []; @@ -374,7 +376,8 @@ class FieldWidget extends StatelessWidget with NT4Widget { if (showOtherObjects || showTrajectories) { for (String objectTopic in otherObjectTopics) { List? objectPositionRaw = nt4Connection - .getLastAnnouncedValue(objectTopic) as List?; + .getLastAnnouncedValue(objectTopic) + ?.tryCast>(); if (objectPositionRaw == null) { continue; diff --git a/lib/widgets/nt4_widgets/multi-topic/fms_info.dart b/lib/widgets/nt4_widgets/multi-topic/fms_info.dart index e884c0b4..31bd6831 100644 --- a/lib/widgets/nt4_widgets/multi-topic/fms_info.dart +++ b/lib/widgets/nt4_widgets/multi-topic/fms_info.dart @@ -1,3 +1,4 @@ +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'; @@ -32,8 +33,8 @@ class FMSInfo extends StatelessWidget with NT4Widget { } FMSInfo.fromJson({super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? '/FMSInfo'; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -89,18 +90,19 @@ class FMSInfo extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), builder: (context, snapshot) { String eventName = - nt4Connection.getLastAnnouncedValue(eventNameTopic) as String? ?? - ''; + tryCast(nt4Connection.getLastAnnouncedValue(eventNameTopic)) ?? ''; int controlData = - nt4Connection.getLastAnnouncedValue(controlDataTopic) as int? ?? 32; + tryCast(nt4Connection.getLastAnnouncedValue(controlDataTopic)) ?? + 32; bool redAlliance = - nt4Connection.getLastAnnouncedValue(allianceTopic) as bool? ?? true; + tryCast(nt4Connection.getLastAnnouncedValue(allianceTopic)) ?? true; int matchNumber = - nt4Connection.getLastAnnouncedValue(matchNumberTopic) as int? ?? 0; + tryCast(nt4Connection.getLastAnnouncedValue(matchNumberTopic)) ?? 0; int matchType = - nt4Connection.getLastAnnouncedValue(matchTypeTopic) as int? ?? 0; + tryCast(nt4Connection.getLastAnnouncedValue(matchTypeTopic)) ?? 0; int replayNumber = - nt4Connection.getLastAnnouncedValue(replayNumberTopic) as int? ?? 0; + tryCast(nt4Connection.getLastAnnouncedValue(replayNumberTopic)) ?? + 0; String eventNameDisplay = '$eventName${(eventName != '') ? ' ' : ''}'; String matchTypeString = _getMatchTypeString(matchType); diff --git a/lib/widgets/nt4_widgets/multi-topic/gyro.dart b/lib/widgets/nt4_widgets/multi-topic/gyro.dart index cec29777..dcc6b305 100644 --- a/lib/widgets/nt4_widgets/multi-topic/gyro.dart +++ b/lib/widgets/nt4_widgets/multi-topic/gyro.dart @@ -1,3 +1,4 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -34,9 +35,10 @@ class Gyro extends StatelessWidget with NT4Widget { } Gyro.fromJson({super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; - counterClockwisePositive = jsonData['counter_clockwise_positive'] ?? false; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; + counterClockwisePositive = + tryCast(jsonData['counter_clockwise_positive']) ?? false; init(); } @@ -109,7 +111,7 @@ class Gyro extends StatelessWidget with NT4Widget { stream: valueSubscription.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(valueTopic), builder: (context, snapshot) { - double value = (snapshot.data as double?) ?? 0.0; + double value = tryCast(snapshot.data) ?? 0.0; if (counterClockwisePositive) { value *= -1; diff --git a/lib/widgets/nt4_widgets/multi-topic/pid_controller.dart b/lib/widgets/nt4_widgets/multi-topic/pid_controller.dart index c7653072..8c4557a7 100644 --- a/lib/widgets/nt4_widgets/multi-topic/pid_controller.dart +++ b/lib/widgets/nt4_widgets/multi-topic/pid_controller.dart @@ -1,3 +1,4 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -51,13 +52,14 @@ class PIDControllerWidget extends StatelessWidget with NT4Widget { PIDControllerWidget.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; - kpTopicName = jsonData['kp_topic'] ?? '$topic/p'; - kiTopicName = jsonData['ki_topic'] ?? '$topic/i'; - kdTopicName = jsonData['kd_topic'] ?? '$topic/d'; - setpointTopicName = jsonData['setpoint_topic'] ?? '$topic/setpoint'; + kpTopicName = tryCast(jsonData['kp_topic']) ?? '$topic/p'; + kiTopicName = tryCast(jsonData['ki_topic']) ?? '$topic/i'; + kdTopicName = tryCast(jsonData['kd_topic']) ?? '$topic/d'; + setpointTopicName = + tryCast(jsonData['setpoint_topic']) ?? '$topic/setpoint'; init(); } @@ -97,17 +99,14 @@ class PIDControllerWidget extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), builder: (context, snapshot) { double kP = - nt4Connection.getLastAnnouncedValue(kpTopicName) as double? ?? - 0.0; + tryCast(nt4Connection.getLastAnnouncedValue(kpTopicName)) ?? 0.0; double kI = - nt4Connection.getLastAnnouncedValue(kiTopicName) as double? ?? - 0.0; + tryCast(nt4Connection.getLastAnnouncedValue(kiTopicName)) ?? 0.0; double kD = - nt4Connection.getLastAnnouncedValue(kdTopicName) as double? ?? + tryCast(nt4Connection.getLastAnnouncedValue(kdTopicName)) ?? 0.0; + double setpoint = + tryCast(nt4Connection.getLastAnnouncedValue(setpointTopicName)) ?? 0.0; - double setpoint = nt4Connection - .getLastAnnouncedValue(setpointTopicName) as double? ?? - 0.0; // Creates the text editing controllers if they are null kpTextController ??= TextEditingController(text: kP.toString()); diff --git a/lib/widgets/nt4_widgets/multi-topic/power_distribution.dart b/lib/widgets/nt4_widgets/multi-topic/power_distribution.dart index fc5e518d..3ff612f1 100644 --- a/lib/widgets/nt4_widgets/multi-topic/power_distribution.dart +++ b/lib/widgets/nt4_widgets/multi-topic/power_distribution.dart @@ -1,3 +1,4 @@ +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'; @@ -25,8 +26,8 @@ class PowerDistribution extends StatelessWidget with NT4Widget { PowerDistribution.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -61,8 +62,8 @@ class PowerDistribution extends StatelessWidget with NT4Widget { List channels = []; for (int channel = start; channel <= end; channel++) { - double current = nt4Connection - .getLastAnnouncedValue(channelTopics[channel]) as double? ?? + double current = tryCast( + nt4Connection.getLastAnnouncedValue(channelTopics[channel])) ?? 0.0; channels.add( @@ -98,8 +99,8 @@ class PowerDistribution extends StatelessWidget with NT4Widget { List channels = []; for (int channel = start; channel >= end; channel--) { - double current = nt4Connection - .getLastAnnouncedValue(channelTopics[channel]) as double? ?? + double current = tryCast( + nt4Connection.getLastAnnouncedValue(channelTopics[channel])) ?? 0.0; channels.add( @@ -140,9 +141,9 @@ class PowerDistribution extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), builder: (context, snapshot) { double voltage = - nt4Connection.getLastAnnouncedValue(voltageTopic) as double? ?? 0.0; + tryCast(nt4Connection.getLastAnnouncedValue(voltageTopic)) ?? 0.0; double totalCurrent = - nt4Connection.getLastAnnouncedValue(currentTopic) as double? ?? 0.0; + tryCast(nt4Connection.getLastAnnouncedValue(currentTopic)) ?? 0.0; return Column( children: [ diff --git a/lib/widgets/nt4_widgets/multi-topic/robot_preferences.dart b/lib/widgets/nt4_widgets/multi-topic/robot_preferences.dart index 4d1e7b08..19a16eab 100644 --- a/lib/widgets/nt4_widgets/multi-topic/robot_preferences.dart +++ b/lib/widgets/nt4_widgets/multi-topic/robot_preferences.dart @@ -1,3 +1,4 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -28,8 +29,8 @@ class RobotPreferences extends StatelessWidget with NT4Widget { RobotPreferences.fromJson( {super.key, required Map jsonData}) { - topic = jsonData['topic'] ?? '/Preferences'; - period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? '/Preferences'; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } diff --git a/lib/widgets/nt4_widgets/multi-topic/split_button_chooser.dart b/lib/widgets/nt4_widgets/multi-topic/split_button_chooser.dart index 4ee2bef1..c9be7faf 100644 --- a/lib/widgets/nt4_widgets/multi-topic/split_button_chooser.dart +++ b/lib/widgets/nt4_widgets/multi-topic/split_button_chooser.dart @@ -1,3 +1,4 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -31,8 +32,8 @@ class SplitButtonChooser extends StatelessWidget with NT4Widget { SplitButtonChooser.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -78,34 +79,26 @@ class SplitButtonChooser extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), builder: (context, snapshot) { List rawOptions = nt4Connection - .getLastAnnouncedValue(optionsTopicName) as List? ?? + .getLastAnnouncedValue(optionsTopicName) + ?.tryCast>() ?? []; - List options = []; - - for (Object? option in rawOptions) { - if (option == null || option is! String) { - continue; - } - - options.add(option); - } + List options = rawOptions.whereType().toList(); String? active = - nt4Connection.getLastAnnouncedValue(activeTopicName) as String?; + tryCast(nt4Connection.getLastAnnouncedValue(activeTopicName)); if (active != null && active == '') { active = null; } String? selected = - nt4Connection.getLastAnnouncedValue(selectedTopicName) as String?; + tryCast(nt4Connection.getLastAnnouncedValue(selectedTopicName)); if (selected != null && selected == '') { selected = null; } String? defaultOption = - nt4Connection.getLastAnnouncedValue(defaultTopicName) as String?; - + tryCast(nt4Connection.getLastAnnouncedValue(defaultTopicName)); if (defaultOption != null && defaultOption == '') { defaultOption = null; } diff --git a/lib/widgets/nt4_widgets/multi-topic/subsystem_widget.dart b/lib/widgets/nt4_widgets/multi-topic/subsystem_widget.dart index 732cc72a..2024e7bf 100644 --- a/lib/widgets/nt4_widgets/multi-topic/subsystem_widget.dart +++ b/lib/widgets/nt4_widgets/multi-topic/subsystem_widget.dart @@ -1,3 +1,4 @@ +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'; @@ -20,8 +21,8 @@ class SubsystemWidget extends StatelessWidget with NT4Widget { SubsystemWidget.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -49,12 +50,12 @@ class SubsystemWidget extends StatelessWidget with NT4Widget { return StreamBuilder( stream: subscription?.periodicStream(), builder: (context, snapshot) { - String defaultCommand = nt4Connection - .getLastAnnouncedValue(defaultCommandTopic) as String? ?? - 'none'; - String currentCommand = nt4Connection - .getLastAnnouncedValue(currentCommandTopic) as String? ?? - 'none'; + String defaultCommand = + tryCast(nt4Connection.getLastAnnouncedValue(defaultCommandTopic)) ?? + 'none'; + String currentCommand = + tryCast(nt4Connection.getLastAnnouncedValue(currentCommandTopic)) ?? + 'none'; return Column( mainAxisAlignment: MainAxisAlignment.start, diff --git a/lib/widgets/nt4_widgets/single_topic/boolean_box.dart b/lib/widgets/nt4_widgets/single_topic/boolean_box.dart index eb6fb66c..ddbc0c1a 100644 --- a/lib/widgets/nt4_widgets/single_topic/boolean_box.dart +++ b/lib/widgets/nt4_widgets/single_topic/boolean_box.dart @@ -1,3 +1,4 @@ +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/dialog_widgets/dialog_color_picker.dart'; @@ -26,10 +27,12 @@ class BooleanBox extends StatelessWidget with NT4Widget { } BooleanBox.fromJson({super.key, required Map jsonData}) - : trueColor = Color(jsonData['true_color'] ?? Colors.green.value), - falseColor = Color(jsonData['false_color'] ?? Colors.red.value) { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? Globals.defaultPeriod; + : trueColor = + Color(tryCast(jsonData['true_color']) ?? Colors.green.value), + falseColor = + Color(tryCast(jsonData['false_color']) ?? Colors.red.value) { + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -81,9 +84,7 @@ class BooleanBox extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - Object data = snapshot.data ?? false; - - bool value = (data is bool) ? data : false; + bool value = tryCast(snapshot.data) ?? false; return Container( decoration: BoxDecoration( diff --git a/lib/widgets/nt4_widgets/single_topic/graph.dart b/lib/widgets/nt4_widgets/single_topic/graph.dart index 38f41c2e..80f6419e 100644 --- a/lib/widgets/nt4_widgets/single_topic/graph.dart +++ b/lib/widgets/nt4_widgets/single_topic/graph.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/widgets/dialog_widgets/dialog_color_picker.dart'; @@ -37,12 +38,12 @@ class GraphWidget extends StatelessWidget with NT4Widget { } GraphWidget.fromJson({super.key, required Map jsonData}) { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? Globals.defaultPeriod; - timeDisplayed = jsonData['time_displayed'] ?? 5.0; - minValue = jsonData['min_value']; - maxValue = jsonData['max_value']; - mainColor = Color(jsonData['color'] ?? Colors.cyan.value); + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; + timeDisplayed = tryCast(jsonData['time_displayed']) ?? 5.0; + minValue = tryCast(jsonData['min_value']); + maxValue = tryCast(jsonData['max_value']); + mainColor = Color(tryCast(jsonData['color']) ?? Colors.cyan.value); init(); } @@ -221,8 +222,9 @@ class _GraphWidgetGraphState extends State { } subscriptionListener = widget.subscription?.periodicStream().listen((data) { - if (data != null && data is double) { - graphData.add(_GraphPoint(x: fakeXIndex.toDouble(), y: data)); + if (data != null) { + graphData.add( + _GraphPoint(x: fakeXIndex.toDouble(), y: tryCast(data) ?? 0.0)); graphData.removeAt(0); fakeXIndex++; diff --git a/lib/widgets/nt4_widgets/single_topic/match_time.dart b/lib/widgets/nt4_widgets/single_topic/match_time.dart index b310f546..fbe63b96 100644 --- a/lib/widgets/nt4_widgets/single_topic/match_time.dart +++ b/lib/widgets/nt4_widgets/single_topic/match_time.dart @@ -1,3 +1,4 @@ +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'; @@ -16,8 +17,8 @@ class MatchTimeWidget extends StatelessWidget with NT4Widget { MatchTimeWidget.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -40,7 +41,7 @@ class MatchTimeWidget extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - double time = snapshot.data as double? ?? -1.0; + double time = tryCast(snapshot.data) ?? -1.0; return Text('${time.ceil()}', style: Theme.of(context).textTheme.displaySmall!.copyWith( diff --git a/lib/widgets/nt4_widgets/single_topic/multi_color_view.dart b/lib/widgets/nt4_widgets/single_topic/multi_color_view.dart index 7ca2695c..e840cb24 100644 --- a/lib/widgets/nt4_widgets/single_topic/multi_color_view.dart +++ b/lib/widgets/nt4_widgets/single_topic/multi_color_view.dart @@ -1,3 +1,4 @@ +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'; @@ -15,8 +16,8 @@ class MultiColorView extends StatelessWidget with NT4Widget { } MultiColorView.fromJson({super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -27,17 +28,13 @@ class MultiColorView extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - List hexStrings = - (snapshot.data as List?)?.whereType().toList() ?? - []; + List hexStringsRaw = + snapshot.data?.tryCast>() ?? []; + List hexStrings = hexStringsRaw.whereType().toList(); List colors = []; - for (String? hexString in hexStrings) { - if (hexString == null) { - continue; - } - + for (String hexString in hexStrings) { hexString = hexString.toUpperCase().replaceAll('#', ''); if (hexString.length == 6) { diff --git a/lib/widgets/nt4_widgets/single_topic/number_bar.dart b/lib/widgets/nt4_widgets/single_topic/number_bar.dart index 7683079c..a9c32cde 100644 --- a/lib/widgets/nt4_widgets/single_topic/number_bar.dart +++ b/lib/widgets/nt4_widgets/single_topic/number_bar.dart @@ -1,3 +1,4 @@ +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/dialog_widgets/dialog_dropdown_chooser.dart'; @@ -36,14 +37,14 @@ class NumberBar extends StatelessWidget with NT4Widget { } NumberBar.fromJson({super.key, required Map jsonData}) { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; - minValue = jsonData['min_value'] ?? -1.0; - maxValue = jsonData['max_value'] ?? 1.0; - divisions = jsonData['divisions']; - inverted = jsonData['inverted'] ?? false; - orientation = jsonData['orientation'] ?? 'horizontal'; + minValue = tryCast(jsonData['min_value']) ?? -1.0; + maxValue = tryCast(jsonData['max_value']) ?? 1.0; + divisions = tryCast(jsonData['divisions']); + inverted = tryCast(jsonData['inverted']) ?? false; + orientation = tryCast(jsonData['orientation']) ?? 'horizontal'; init(); } @@ -170,7 +171,7 @@ class NumberBar extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - double value = snapshot.data as double? ?? 0.0; + double value = tryCast(snapshot.data) ?? 0.0; double clampedValue = value.clamp(minValue, maxValue); diff --git a/lib/widgets/nt4_widgets/single_topic/number_slider.dart b/lib/widgets/nt4_widgets/single_topic/number_slider.dart index 54f5efd8..a9d1bbdc 100644 --- a/lib/widgets/nt4_widgets/single_topic/number_slider.dart +++ b/lib/widgets/nt4_widgets/single_topic/number_slider.dart @@ -1,3 +1,4 @@ +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/dialog_widgets/dialog_text_input.dart'; @@ -32,11 +33,11 @@ class NumberSlider extends StatelessWidget with NT4Widget { } NumberSlider.fromJson({super.key, required Map jsonData}) - : minValue = jsonData['min_value'] ?? -1.0, - maxValue = jsonData['max_value'] ?? 1.0, - divisions = jsonData['divisions'] { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? Globals.defaultPeriod; + : minValue = tryCast(jsonData['min_value']) ?? -1.0, + maxValue = tryCast(jsonData['max_value']) ?? 1.0, + divisions = tryCast(jsonData['divisions']) ?? 5 { + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -119,7 +120,7 @@ class NumberSlider extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - double value = snapshot.data as double? ?? 0.0; + double value = tryCast(snapshot.data) ?? 0.0; double clampedValue = value.clamp(minValue, maxValue); diff --git a/lib/widgets/nt4_widgets/single_topic/single_color_view.dart b/lib/widgets/nt4_widgets/single_topic/single_color_view.dart index cd346051..ca1db72e 100644 --- a/lib/widgets/nt4_widgets/single_topic/single_color_view.dart +++ b/lib/widgets/nt4_widgets/single_topic/single_color_view.dart @@ -1,3 +1,4 @@ +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'; @@ -17,8 +18,8 @@ class SingleColorView extends StatelessWidget with NT4Widget { SingleColorView.fromJson( {super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -31,7 +32,7 @@ class SingleColorView extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - String hexString = snapshot.data as String? ?? ""; + String hexString = tryCast(snapshot.data) ?? ''; hexString = hexString.toUpperCase().replaceAll('#', ''); diff --git a/lib/widgets/nt4_widgets/single_topic/text_display.dart b/lib/widgets/nt4_widgets/single_topic/text_display.dart index 0b09d8cf..9f06cdee 100644 --- a/lib/widgets/nt4_widgets/single_topic/text_display.dart +++ b/lib/widgets/nt4_widgets/single_topic/text_display.dart @@ -1,3 +1,4 @@ +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/globals.dart'; import 'package:elastic_dashboard/services/nt4.dart'; import 'package:elastic_dashboard/services/nt4_connection.dart'; @@ -21,8 +22,8 @@ class TextDisplay extends StatelessWidget with NT4Widget { } TextDisplay.fromJson({super.key, required Map jsonData}) { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } diff --git a/lib/widgets/nt4_widgets/single_topic/toggle_button.dart b/lib/widgets/nt4_widgets/single_topic/toggle_button.dart index 08a9de2f..fa0e89f3 100644 --- a/lib/widgets/nt4_widgets/single_topic/toggle_button.dart +++ b/lib/widgets/nt4_widgets/single_topic/toggle_button.dart @@ -1,3 +1,4 @@ +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'; @@ -16,8 +17,8 @@ class ToggleButton extends StatelessWidget with NT4Widget { } ToggleButton.fromJson({super.key, required Map jsonData}) { - super.topic = jsonData['topic'] ?? ''; - super.period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -30,9 +31,7 @@ class ToggleButton extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - Object data = snapshot.data ?? false; - - bool value = (data is bool) ? data : false; + bool value = tryCast(snapshot.data) ?? false; String buttonText = topic.substring(topic.lastIndexOf('/') + 1); diff --git a/lib/widgets/nt4_widgets/single_topic/toggle_switch.dart b/lib/widgets/nt4_widgets/single_topic/toggle_switch.dart index df9ac7c8..b52cf191 100644 --- a/lib/widgets/nt4_widgets/single_topic/toggle_switch.dart +++ b/lib/widgets/nt4_widgets/single_topic/toggle_switch.dart @@ -1,3 +1,4 @@ +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'; @@ -16,8 +17,8 @@ class ToggleSwitch extends StatelessWidget with NT4Widget { } ToggleSwitch.fromJson({super.key, required Map jsonData}) { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; init(); } @@ -30,9 +31,7 @@ class ToggleSwitch extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - Object data = snapshot.data ?? false; - - bool value = (data is bool) ? data : false; + bool value = tryCast(snapshot.data) ?? false; return Switch( value: value, diff --git a/lib/widgets/nt4_widgets/single_topic/voltage_view.dart b/lib/widgets/nt4_widgets/single_topic/voltage_view.dart index 1986f4f4..2fbbc1e5 100644 --- a/lib/widgets/nt4_widgets/single_topic/voltage_view.dart +++ b/lib/widgets/nt4_widgets/single_topic/voltage_view.dart @@ -1,3 +1,4 @@ +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/dialog_widgets/dialog_dropdown_chooser.dart'; @@ -36,14 +37,14 @@ class VoltageView extends StatelessWidget with NT4Widget { } VoltageView.fromJson({super.key, required Map jsonData}) { - topic = jsonData['topic'] ?? ''; - period = jsonData['period'] ?? Globals.defaultPeriod; + topic = tryCast(jsonData['topic']) ?? ''; + period = tryCast(jsonData['period']) ?? Globals.defaultPeriod; - minValue = jsonData['min_value'] ?? 4; - maxValue = jsonData['max_value'] ?? 13.0; - divisions = jsonData['divisions']; - inverted = jsonData['inverted'] ?? false; - orientation = jsonData['orientation'] ?? 'horizontal'; + minValue = tryCast(jsonData['min_value']) ?? 4; + maxValue = tryCast(jsonData['max_value']) ?? 13.0; + divisions = tryCast(jsonData['divisions']); + inverted = tryCast(jsonData['inverted']) ?? false; + orientation = tryCast(jsonData['orientation']) ?? 'horizontal'; init(); } @@ -170,7 +171,7 @@ class VoltageView extends StatelessWidget with NT4Widget { stream: subscription?.periodicStream(), initialData: nt4Connection.getLastAnnouncedValue(topic), builder: (context, snapshot) { - double voltage = snapshot.data as double? ?? 0.0; + double voltage = tryCast(snapshot.data) ?? 0.0; double clampedVoltage = voltage.clamp(minValue, maxValue); diff --git a/pubspec.lock b/pubspec.lock index e3c4619f..036d6935 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -249,6 +249,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.8" + dot_cast: + dependency: "direct main" + description: + name: dot_cast + sha256: e653eb81bcd7e11e457792e80bc54ce22ff49b18568d34c479a70c2879584b9c + url: "https://pub.dev" + source: hosted + version: "1.2.0" dropdown_button2: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index b2017d7b..a7aa7b67 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,7 @@ dependencies: animations: ^2.0.7 collection: ^1.17.1 contextmenu: ^3.0.0 + dot_cast: ^1.2.0 dropdown_button2: ^2.3.9 elegant_notification: ^1.11.0 file_selector: ^0.9.3