From fcf6f27f028ed03782cdf84efb5a202f02545da7 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:18:53 -0400 Subject: [PATCH 01/14] add alerts --- elasticlib/Elastic.java | 0 lib/pages/dashboard_page.dart | 75 +++++++++++++++++++++++++++++------ lib/services/nt4_client.dart | 2 +- pubspec.lock | 4 +- pubspec.yaml | 2 +- 5 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 elasticlib/Elastic.java diff --git a/elasticlib/Elastic.java b/elasticlib/Elastic.java new file mode 100644 index 00000000..e69de29b diff --git a/lib/pages/dashboard_page.dart b/lib/pages/dashboard_page.dart index 618d1114..5491a80f 100644 --- a/lib/pages/dashboard_page.dart +++ b/lib/pages/dashboard_page.dart @@ -1,6 +1,8 @@ import 'dart:convert'; import 'dart:io'; +import 'package:elastic_dashboard/services/nt4_client.dart'; +import 'package:elegant_notification/resources/stacked_options.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; @@ -9,6 +11,7 @@ import 'package:collection/collection.dart'; import 'package:dot_cast/dot_cast.dart'; import 'package:elegant_notification/elegant_notification.dart'; import 'package:file_selector/file_selector.dart'; +import 'package:logger/logger.dart'; import 'package:popover/popover.dart'; import 'package:screen_retriever/screen_retriever.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -206,6 +209,61 @@ class _DashboardPageState extends State with WindowListener { }); Future(() => _checkForUpdates(notifyIfLatest: false, notifyIfError: false)); + + var notifications = ntConnection.subscribe("notifications"); + + //dont display a notification when we first connect + bool notificationFirstRun = true; + notifications.listen((p0, p1) { + List data = p0.toString().replaceAll("[", "").replaceAll("]", "").split(","); + if(notificationFirstRun) { + notificationFirstRun = false; + return; + } + Icon icon; + if(data[0] == "INFO") { + icon = const Icon(Icons.info); + } + else if(data[0] == "WARNING") { + icon = const Icon(Icons.warning_amber, color: Colors.orange,); + } + else if(data[0] == "ERROR") { + icon = const Icon(Icons.error, color: Colors.red,); + } + else { + icon = const Icon(Icons.question_mark); + } + + String title = data[1]; + String description = data[2]; + setState(() { + ColorScheme colorScheme = Theme.of(context).colorScheme; + TextTheme textTheme = Theme.of(context).textTheme; + ElegantNotification notification = ElegantNotification( + autoDismiss: true, + showProgressIndicator: true, + background: colorScheme.surface, + width: 350, + position: Alignment.bottomRight, + title: Text( + title, + style: textTheme.bodyMedium!.copyWith( + fontWeight: FontWeight.bold, + ), + ), + icon: icon, + description: Text(description), + stackedOptions: StackedOptions( + key: 'notification', + type: StackedType.above, + itemOffset: const Offset(0, 20), + ), + ); + if (mounted) { + notification.show(context); + } + }); + }); } @override @@ -271,7 +329,6 @@ class _DashboardPageState extends State with WindowListener { background: colorScheme.surface, progressIndicatorBackground: colorScheme.surface, progressIndicatorColor: const Color(0xff01CB67), - enableShadow: false, width: 150, position: Alignment.bottomRight, toastDuration: const Duration(seconds: 3, milliseconds: 500), @@ -291,7 +348,6 @@ class _DashboardPageState extends State with WindowListener { background: colorScheme.surface, progressIndicatorBackground: colorScheme.surface, progressIndicatorColor: const Color(0xffFE355C), - enableShadow: false, width: 150, position: Alignment.bottomRight, toastDuration: const Duration(seconds: 3, milliseconds: 500), @@ -337,9 +393,7 @@ class _DashboardPageState extends State with WindowListener { background: colorScheme.surface, progressIndicatorBackground: colorScheme.surface, progressIndicatorColor: const Color(0xffFE355C), - enableShadow: false, width: 350, - height: 100, position: Alignment.bottomRight, toastDuration: const Duration(seconds: 3, milliseconds: 500), icon: const Icon(Icons.error, color: Color(0xffFE355C)), @@ -365,9 +419,7 @@ class _DashboardPageState extends State with WindowListener { autoDismiss: false, showProgressIndicator: false, background: colorScheme.surface, - enableShadow: false, - width: 150, - height: 100, + width: 350, position: Alignment.bottomRight, title: Text( 'Version ${updateResponse.latestVersion!} Available', @@ -384,7 +436,7 @@ class _DashboardPageState extends State with WindowListener { fontWeight: FontWeight.bold, ), ), - onActionPressed: () async { + onNotificationPressed: () async { Uri url = Uri.parse(Settings.releasesLink); if (await canLaunchUrl(url)) { @@ -401,9 +453,8 @@ class _DashboardPageState extends State with WindowListener { background: colorScheme.surface, progressIndicatorBackground: colorScheme.surface, progressIndicatorColor: const Color(0xff01CB67), - enableShadow: false, - width: 150, - height: 100, + width: 350, + position: Alignment.bottomRight, toastDuration: const Duration(seconds: 3, milliseconds: 500), icon: const Icon(Icons.check_circle, color: Color(0xff01CB67)), @@ -613,7 +664,6 @@ class _DashboardPageState extends State with WindowListener { background: colorScheme.surface, progressIndicatorBackground: colorScheme.surface, progressIndicatorColor: const Color(0xffFE355C), - enableShadow: false, width: 350, height: 100 + (lines - 1) * 10, position: Alignment.bottomRight, @@ -640,7 +690,6 @@ class _DashboardPageState extends State with WindowListener { background: colorScheme.surface, progressIndicatorBackground: colorScheme.surface, progressIndicatorColor: Colors.yellow, - enableShadow: false, width: 350, height: 100 + (lines - 1) * 10, position: Alignment.bottomRight, diff --git a/lib/services/nt4_client.dart b/lib/services/nt4_client.dart index 65fa5874..dbefd0f9 100644 --- a/lib/services/nt4_client.dart +++ b/lib/services/nt4_client.dart @@ -326,7 +326,7 @@ class NT4Client { NT4Subscription newSub = NT4Subscription( topic: topic, uid: getNewSubUID(), - options: NT4SubscriptionOptions(periodicRateSeconds: period), + options: NT4SubscriptionOptions(periodicRateSeconds: period, all: true), ); if (_subscribedTopics.contains(newSub)) { diff --git a/pubspec.lock b/pubspec.lock index ea3a624f..61bb595c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -253,10 +253,10 @@ packages: dependency: "direct main" description: name: elegant_notification - sha256: "94cf7377a939b101183a3093fea409c26c332511ba8d2da445ef8b251d460dc9" + sha256: f6ad40163a06ac5c41fe698d39c4e45b5d6c1617d6cd17062e11e1ecd39b3a97 url: "https://pub.dev" source: hosted - version: "1.14.0" + version: "2.2.0" equatable: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 600a9bce..65b96118 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: decimal: ^2.3.3 dot_cast: ^1.2.0 dropdown_button2: ^2.3.9 - elegant_notification: ^1.11.0 + elegant_notification: ^2.2.0 file_selector: ^1.0.1 flex_seed_scheme: ^2.0.0 flutter: From d891f58806e9a64c87428ffcf8bd0957ff7c6b54 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:23:06 -0400 Subject: [PATCH 02/14] add elasticlib --- elasticlib/Elastic.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/elasticlib/Elastic.java b/elasticlib/Elastic.java index e69de29b..22873f00 100644 --- a/elasticlib/Elastic.java +++ b/elasticlib/Elastic.java @@ -0,0 +1,24 @@ +package frc.robot; + +import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.networktables.PubSubOption; +import edu.wpi.first.networktables.PubSubOptions; +import edu.wpi.first.networktables.StringArrayEntry; +import edu.wpi.first.networktables.StringArrayPublisher; +import edu.wpi.first.networktables.StringArrayTopic; + +public final class Elastic { + private static final StringArrayTopic topic = NetworkTableInstance.getDefault().getStringArrayTopic("notifications"); + private static final StringArrayPublisher publisher = topic.publish(PubSubOption.sendAll(true)); + + public static void sendAlert(AlertLevel level, String title, String description) { + + publisher.set(new String[] {level.toString(), title, description}); + System.out.println("sent alert"); + } + public enum AlertLevel { + INFO, + WARNING, + ERROR + } +} From 32daba8c0bcf1f9a44140c071d06c64a360951bf Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:30:27 -0400 Subject: [PATCH 03/14] change spacing --- lib/pages/dashboard_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/dashboard_page.dart b/lib/pages/dashboard_page.dart index 5491a80f..ae479dd5 100644 --- a/lib/pages/dashboard_page.dart +++ b/lib/pages/dashboard_page.dart @@ -256,7 +256,7 @@ class _DashboardPageState extends State with WindowListener { stackedOptions: StackedOptions( key: 'notification', type: StackedType.above, - itemOffset: const Offset(0, 20), + itemOffset: const Offset(0, 5), ), ); if (mounted) { From 63c84da7e4df8f1711e80e1116aeb8dc06157c58 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:34:00 -0400 Subject: [PATCH 04/14] remove test prntln --- elasticlib/Elastic.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/elasticlib/Elastic.java b/elasticlib/Elastic.java index 22873f00..6e5d11da 100644 --- a/elasticlib/Elastic.java +++ b/elasticlib/Elastic.java @@ -12,9 +12,7 @@ public final class Elastic { private static final StringArrayPublisher publisher = topic.publish(PubSubOption.sendAll(true)); public static void sendAlert(AlertLevel level, String title, String description) { - publisher.set(new String[] {level.toString(), title, description}); - System.out.println("sent alert"); } public enum AlertLevel { INFO, From ce2b7d939080a581d6536acab96116b954a9af92 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Thu, 20 Jun 2024 19:49:26 -0400 Subject: [PATCH 05/14] move alerts to own service && nt topic name change --- elasticlib/Elastic.java | 10 ++--- lib/pages/dashboard_page.dart | 62 ++--------------------------- lib/services/robot_alerts.dart | 72 ++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 63 deletions(-) create mode 100644 lib/services/robot_alerts.dart diff --git a/elasticlib/Elastic.java b/elasticlib/Elastic.java index 6e5d11da..503f3f2f 100644 --- a/elasticlib/Elastic.java +++ b/elasticlib/Elastic.java @@ -2,21 +2,21 @@ import edu.wpi.first.networktables.NetworkTableInstance; import edu.wpi.first.networktables.PubSubOption; -import edu.wpi.first.networktables.PubSubOptions; -import edu.wpi.first.networktables.StringArrayEntry; import edu.wpi.first.networktables.StringArrayPublisher; import edu.wpi.first.networktables.StringArrayTopic; public final class Elastic { - private static final StringArrayTopic topic = NetworkTableInstance.getDefault().getStringArrayTopic("notifications"); + private static final StringArrayTopic topic = NetworkTableInstance.getDefault() + .getStringArrayTopic("elastic/robotalerts"); private static final StringArrayPublisher publisher = topic.publish(PubSubOption.sendAll(true)); public static void sendAlert(AlertLevel level, String title, String description) { - publisher.set(new String[] {level.toString(), title, description}); + publisher.set(new String[] { level.toString(), title, description }); } + public enum AlertLevel { INFO, WARNING, ERROR } -} +} \ No newline at end of file diff --git a/lib/pages/dashboard_page.dart b/lib/pages/dashboard_page.dart index ae479dd5..1c936be8 100644 --- a/lib/pages/dashboard_page.dart +++ b/lib/pages/dashboard_page.dart @@ -1,8 +1,7 @@ import 'dart:convert'; import 'dart:io'; -import 'package:elastic_dashboard/services/nt4_client.dart'; -import 'package:elegant_notification/resources/stacked_options.dart'; +import 'package:elastic_dashboard/services/robot_alerts.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; @@ -11,7 +10,6 @@ import 'package:collection/collection.dart'; import 'package:dot_cast/dot_cast.dart'; import 'package:elegant_notification/elegant_notification.dart'; import 'package:file_selector/file_selector.dart'; -import 'package:logger/logger.dart'; import 'package:popover/popover.dart'; import 'package:screen_retriever/screen_retriever.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -55,6 +53,7 @@ class DashboardPage extends StatefulWidget { class _DashboardPageState extends State with WindowListener { late final SharedPreferences _preferences; late final UpdateChecker _updateChecker; + late final RobotAlerts _robotAlerts; final List _grids = []; @@ -210,60 +209,8 @@ class _DashboardPageState extends State with WindowListener { Future(() => _checkForUpdates(notifyIfLatest: false, notifyIfError: false)); - var notifications = ntConnection.subscribe("notifications"); - - //dont display a notification when we first connect - bool notificationFirstRun = true; - notifications.listen((p0, p1) { - List data = p0.toString().replaceAll("[", "").replaceAll("]", "").split(","); - if(notificationFirstRun) { - notificationFirstRun = false; - return; - } - Icon icon; - if(data[0] == "INFO") { - icon = const Icon(Icons.info); - } - else if(data[0] == "WARNING") { - icon = const Icon(Icons.warning_amber, color: Colors.orange,); - } - else if(data[0] == "ERROR") { - icon = const Icon(Icons.error, color: Colors.red,); - } - else { - icon = const Icon(Icons.question_mark); - } - - String title = data[1]; - String description = data[2]; - setState(() { - ColorScheme colorScheme = Theme.of(context).colorScheme; - TextTheme textTheme = Theme.of(context).textTheme; - ElegantNotification notification = ElegantNotification( - autoDismiss: true, - showProgressIndicator: true, - background: colorScheme.surface, - width: 350, - position: Alignment.bottomRight, - title: Text( - title, - style: textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.bold, - ), - ), - icon: icon, - description: Text(description), - stackedOptions: StackedOptions( - key: 'notification', - type: StackedType.above, - itemOffset: const Offset(0, 5), - ), - ); - if (mounted) { - notification.show(context); - } - }); - }); + _robotAlerts = RobotAlerts(); + _robotAlerts.listen(ntConnection, context); } @override @@ -454,7 +401,6 @@ class _DashboardPageState extends State with WindowListener { progressIndicatorBackground: colorScheme.surface, progressIndicatorColor: const Color(0xff01CB67), width: 350, - position: Alignment.bottomRight, toastDuration: const Duration(seconds: 3, milliseconds: 500), icon: const Icon(Icons.check_circle, color: Color(0xff01CB67)), diff --git a/lib/services/robot_alerts.dart b/lib/services/robot_alerts.dart new file mode 100644 index 00000000..66677d83 --- /dev/null +++ b/lib/services/robot_alerts.dart @@ -0,0 +1,72 @@ +import 'package:elastic_dashboard/services/nt_connection.dart'; +import 'package:elegant_notification/elegant_notification.dart'; +import 'package:elegant_notification/resources/stacked_options.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class RobotAlerts { + bool _alertFirstRun = true; + + void listen(NTConnection nt, BuildContext context) { + var notifications = ntConnection.subscribe("elastic/robotalerts"); + notifications.listen((alertData, alertTimestamp) { + _onAlert(alertData!, alertTimestamp, context); + }); + } + + void _onAlert(Object alertData, int timestamp, BuildContext context) { + //prevent showing a notification when we connect to NT + if (_alertFirstRun) { + _alertFirstRun = false; + return; + } + List data = + alertData.toString().replaceAll("[", "").replaceAll("]", "").split(","); + Icon icon; + if (data[0] == "INFO") { + icon = const Icon(Icons.info); + } else if (data[0] == "WARNING") { + icon = const Icon( + Icons.warning_amber, + color: Colors.orange, + ); + } else if (data[0] == "ERROR") { + icon = const Icon( + Icons.error, + color: Colors.red, + ); + } else { + icon = const Icon(Icons.question_mark); + } + + String title = data[1]; + String description = data[2]; + _buildNotification(title, description, icon, context).show(context); + } + + ElegantNotification _buildNotification( + String title, String description, Icon icon, BuildContext context) { + ColorScheme colorScheme = Theme.of(context).colorScheme; + TextTheme textTheme = Theme.of(context).textTheme; + return ElegantNotification( + autoDismiss: true, + showProgressIndicator: true, + background: colorScheme.surface, + width: 350, + position: Alignment.bottomRight, + title: Text( + title, + style: textTheme.bodyMedium!.copyWith( + fontWeight: FontWeight.bold, + ), + ), + icon: icon, + description: Text(description), + stackedOptions: StackedOptions( + key: 'robotalert', + type: StackedType.above, + itemOffset: const Offset(0, 5), + ), + ); + } +} From 69ebb267d104abfcb6215a63e2c31261d70f1074 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:19:24 -0400 Subject: [PATCH 06/14] use json for alerts --- elasticlib/Elastic.java | 47 ++++++++++++++++++++++++++++------ lib/services/robot_alerts.dart | 20 ++++++++------- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/elasticlib/Elastic.java b/elasticlib/Elastic.java index 503f3f2f..2c1806a5 100644 --- a/elasticlib/Elastic.java +++ b/elasticlib/Elastic.java @@ -1,22 +1,53 @@ package frc.robot; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + import edu.wpi.first.networktables.NetworkTableInstance; import edu.wpi.first.networktables.PubSubOption; import edu.wpi.first.networktables.StringArrayPublisher; import edu.wpi.first.networktables.StringArrayTopic; +import edu.wpi.first.networktables.StringPublisher; +import edu.wpi.first.networktables.StringTopic; public final class Elastic { - private static final StringArrayTopic topic = NetworkTableInstance.getDefault() - .getStringArrayTopic("elastic/robotalerts"); - private static final StringArrayPublisher publisher = topic.publish(PubSubOption.sendAll(true)); + private static final StringTopic topic = NetworkTableInstance.getDefault().getStringTopic("elastic/robotalerts"); + private static final StringPublisher publisher = topic.publish(PubSubOption.sendAll(true)); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static void sendAlert(RobotAlert alert) { + try { + publisher.set(objectMapper.writeValueAsString(alert)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + + static class RobotAlert { + private final AlertLevel level; + private final String title; + private final String description; + + public RobotAlert(AlertLevel level, String title, String description) { + this.level = level; + this.title = title; + this.description = description; + } + + public AlertLevel getLevel() { + return level; + } + + public String getTitle() { + return title; + } - public static void sendAlert(AlertLevel level, String title, String description) { - publisher.set(new String[] { level.toString(), title, description }); + public String getDescription() { + return description; + } } public enum AlertLevel { - INFO, - WARNING, - ERROR + INFO, WARNING, ERROR } } \ No newline at end of file diff --git a/lib/services/robot_alerts.dart b/lib/services/robot_alerts.dart index 66677d83..908ef5ab 100644 --- a/lib/services/robot_alerts.dart +++ b/lib/services/robot_alerts.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:elastic_dashboard/services/nt_connection.dart'; import 'package:elegant_notification/elegant_notification.dart'; import 'package:elegant_notification/resources/stacked_options.dart'; @@ -20,17 +22,19 @@ class RobotAlerts { _alertFirstRun = false; return; } - List data = - alertData.toString().replaceAll("[", "").replaceAll("]", "").split(","); + + + Map data = jsonDecode(alertData.toString()); Icon icon; - if (data[0] == "INFO") { + + if (data["level"] == "INFO") { icon = const Icon(Icons.info); - } else if (data[0] == "WARNING") { + } else if (data["level"] == "WARNING") { icon = const Icon( Icons.warning_amber, color: Colors.orange, ); - } else if (data[0] == "ERROR") { + } else if (data["level"] == "ERROR") { icon = const Icon( Icons.error, color: Colors.red, @@ -39,9 +43,7 @@ class RobotAlerts { icon = const Icon(Icons.question_mark); } - String title = data[1]; - String description = data[2]; - _buildNotification(title, description, icon, context).show(context); + _buildNotification(data["title"], data["description"], icon, context).show(context); } ElegantNotification _buildNotification( @@ -69,4 +71,4 @@ class RobotAlerts { ), ); } -} +} \ No newline at end of file From 945c1462610922bb8eaba5c2daf665897a9bd18a Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:23:58 -0400 Subject: [PATCH 07/14] use json for alerts --- lib/services/robot_alerts.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/services/robot_alerts.dart b/lib/services/robot_alerts.dart index 908ef5ab..8242d000 100644 --- a/lib/services/robot_alerts.dart +++ b/lib/services/robot_alerts.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:elastic_dashboard/services/nt_connection.dart'; import 'package:elegant_notification/elegant_notification.dart'; import 'package:elegant_notification/resources/stacked_options.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class RobotAlerts { @@ -23,7 +22,6 @@ class RobotAlerts { return; } - Map data = jsonDecode(alertData.toString()); Icon icon; @@ -43,7 +41,8 @@ class RobotAlerts { icon = const Icon(Icons.question_mark); } - _buildNotification(data["title"], data["description"], icon, context).show(context); + _buildNotification(data["title"], data["description"], icon, context) + .show(context); } ElegantNotification _buildNotification( @@ -71,4 +70,4 @@ class RobotAlerts { ), ); } -} \ No newline at end of file +} From 46660611c3a282720dba77ff3e1b323df1e57ed8 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:30:23 -0400 Subject: [PATCH 08/14] rename "robotalerts" to "elastic notifications" etc. addresses name conflicts with wpilibs stuff in 2025 --- elasticlib/Elastic.java | 28 +++++++++--------- lib/pages/dashboard_page.dart | 29 +++++++++---------- ...dart => robot_notifications_listener.dart} | 6 ++-- 3 files changed, 32 insertions(+), 31 deletions(-) rename lib/services/{robot_alerts.dart => robot_notifications_listener.dart} (93%) diff --git a/elasticlib/Elastic.java b/elasticlib/Elastic.java index 2c1806a5..3ff4c845 100644 --- a/elasticlib/Elastic.java +++ b/elasticlib/Elastic.java @@ -5,17 +5,16 @@ import edu.wpi.first.networktables.NetworkTableInstance; import edu.wpi.first.networktables.PubSubOption; -import edu.wpi.first.networktables.StringArrayPublisher; -import edu.wpi.first.networktables.StringArrayTopic; import edu.wpi.first.networktables.StringPublisher; import edu.wpi.first.networktables.StringTopic; public final class Elastic { - private static final StringTopic topic = NetworkTableInstance.getDefault().getStringTopic("elastic/robotalerts"); + private static final StringTopic topic = NetworkTableInstance.getDefault() + .getStringTopic("elastic/robotnotifications"); private static final StringPublisher publisher = topic.publish(PubSubOption.sendAll(true)); private static final ObjectMapper objectMapper = new ObjectMapper(); - public static void sendAlert(RobotAlert alert) { + public static void sendAlert(ElasticNotification alert) { try { publisher.set(objectMapper.writeValueAsString(alert)); } catch (JsonProcessingException e) { @@ -23,18 +22,18 @@ public static void sendAlert(RobotAlert alert) { } } - static class RobotAlert { - private final AlertLevel level; - private final String title; - private final String description; + public static class ElasticNotification { + private NotificationLevel level; + private String title; + private String description; - public RobotAlert(AlertLevel level, String title, String description) { + public ElasticNotification(NotificationLevel level, String title, String description) { this.level = level; this.title = title; this.description = description; } - public AlertLevel getLevel() { + public NotificationLevel getLevel() { return level; } @@ -45,9 +44,12 @@ public String getTitle() { public String getDescription() { return description; } - } - public enum AlertLevel { - INFO, WARNING, ERROR + public enum NotificationLevel { + INFO, + WARNING, + ERROR + } } + } \ No newline at end of file diff --git a/lib/pages/dashboard_page.dart b/lib/pages/dashboard_page.dart index 1c936be8..06eb394b 100644 --- a/lib/pages/dashboard_page.dart +++ b/lib/pages/dashboard_page.dart @@ -1,25 +1,13 @@ import 'dart:convert'; import 'dart:io'; -import 'package:elastic_dashboard/services/robot_alerts.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:flutter/services.dart'; - import 'package:collection/collection.dart'; import 'package:dot_cast/dot_cast.dart'; -import 'package:elegant_notification/elegant_notification.dart'; -import 'package:file_selector/file_selector.dart'; -import 'package:popover/popover.dart'; -import 'package:screen_retriever/screen_retriever.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:window_manager/window_manager.dart'; - import 'package:elastic_dashboard/services/hotkey_manager.dart'; import 'package:elastic_dashboard/services/ip_address_util.dart'; import 'package:elastic_dashboard/services/log.dart'; import 'package:elastic_dashboard/services/nt_connection.dart'; +import 'package:elastic_dashboard/services/robot_notifications_listener.dart'; import 'package:elastic_dashboard/services/settings.dart'; import 'package:elastic_dashboard/services/shuffleboard_nt_listener.dart'; import 'package:elastic_dashboard/services/update_checker.dart'; @@ -32,6 +20,17 @@ import 'package:elastic_dashboard/widgets/editable_tab_bar.dart'; import 'package:elastic_dashboard/widgets/network_tree/networktables_tree.dart'; import 'package:elastic_dashboard/widgets/settings_dialog.dart'; import 'package:elastic_dashboard/widgets/tab_grid.dart'; +import 'package:elegant_notification/elegant_notification.dart'; +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter/services.dart'; +import 'package:popover/popover.dart'; +import 'package:screen_retriever/screen_retriever.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:window_manager/window_manager.dart'; + import '../widgets/draggable_containers/models/layout_container_model.dart'; class DashboardPage extends StatefulWidget { @@ -53,7 +52,7 @@ class DashboardPage extends StatefulWidget { class _DashboardPageState extends State with WindowListener { late final SharedPreferences _preferences; late final UpdateChecker _updateChecker; - late final RobotAlerts _robotAlerts; + late final RobotNotificationsListener _robotAlerts; final List _grids = []; @@ -209,7 +208,7 @@ class _DashboardPageState extends State with WindowListener { Future(() => _checkForUpdates(notifyIfLatest: false, notifyIfError: false)); - _robotAlerts = RobotAlerts(); + _robotAlerts = RobotNotificationsListener(); _robotAlerts.listen(ntConnection, context); } diff --git a/lib/services/robot_alerts.dart b/lib/services/robot_notifications_listener.dart similarity index 93% rename from lib/services/robot_alerts.dart rename to lib/services/robot_notifications_listener.dart index 8242d000..f253295d 100644 --- a/lib/services/robot_alerts.dart +++ b/lib/services/robot_notifications_listener.dart @@ -5,11 +5,11 @@ import 'package:elegant_notification/elegant_notification.dart'; import 'package:elegant_notification/resources/stacked_options.dart'; import 'package:flutter/material.dart'; -class RobotAlerts { +class RobotNotificationsListener { bool _alertFirstRun = true; void listen(NTConnection nt, BuildContext context) { - var notifications = ntConnection.subscribe("elastic/robotalerts"); + var notifications = ntConnection.subscribe("elastic/robotnotifications"); notifications.listen((alertData, alertTimestamp) { _onAlert(alertData!, alertTimestamp, context); }); @@ -64,7 +64,7 @@ class RobotAlerts { icon: icon, description: Text(description), stackedOptions: StackedOptions( - key: 'robotalert', + key: 'robotnotification', type: StackedType.above, itemOffset: const Offset(0, 5), ), From ea5c1ff2f92b008d68fb2c3c9a2c6ff698b24442 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:57:33 -0400 Subject: [PATCH 09/14] dont use context --- lib/pages/dashboard_page.dart | 35 +++++++++++++-- .../robot_notifications_listener.dart | 43 ++++--------------- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/lib/pages/dashboard_page.dart b/lib/pages/dashboard_page.dart index 06eb394b..e29323e9 100644 --- a/lib/pages/dashboard_page.dart +++ b/lib/pages/dashboard_page.dart @@ -21,6 +21,7 @@ import 'package:elastic_dashboard/widgets/network_tree/networktables_tree.dart'; import 'package:elastic_dashboard/widgets/settings_dialog.dart'; import 'package:elastic_dashboard/widgets/tab_grid.dart'; import 'package:elegant_notification/elegant_notification.dart'; +import 'package:elegant_notification/resources/stacked_options.dart'; import 'package:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; @@ -52,7 +53,7 @@ class DashboardPage extends StatefulWidget { class _DashboardPageState extends State with WindowListener { late final SharedPreferences _preferences; late final UpdateChecker _updateChecker; - late final RobotNotificationsListener _robotAlerts; + late final RobotNotificationsListener _robotNotificationListener; final List _grids = []; @@ -208,8 +209,36 @@ class _DashboardPageState extends State with WindowListener { Future(() => _checkForUpdates(notifyIfLatest: false, notifyIfError: false)); - _robotAlerts = RobotNotificationsListener(); - _robotAlerts.listen(ntConnection, context); + _robotNotificationListener = RobotNotificationsListener( + connection: ntConnection, + onNotification: (title, description, icon) { + setState(() { + ColorScheme colorScheme = Theme.of(context).colorScheme; + TextTheme textTheme = Theme.of(context).textTheme; + var widget = ElegantNotification( + autoDismiss: true, + showProgressIndicator: true, + background: colorScheme.surface, + width: 350, + position: Alignment.bottomRight, + title: Text( + title, + style: textTheme.bodyMedium!.copyWith( + fontWeight: FontWeight.bold, + ), + ), + icon: icon, + description: Text(description), + stackedOptions: StackedOptions( + key: 'robotnotification', + type: StackedType.above, + itemOffset: const Offset(0, 5), + ), + ); + if (mounted) widget.show(context); + }); + }); + _robotNotificationListener.listen(); } @override diff --git a/lib/services/robot_notifications_listener.dart b/lib/services/robot_notifications_listener.dart index f253295d..2da094d9 100644 --- a/lib/services/robot_notifications_listener.dart +++ b/lib/services/robot_notifications_listener.dart @@ -1,21 +1,24 @@ import 'dart:convert'; import 'package:elastic_dashboard/services/nt_connection.dart'; -import 'package:elegant_notification/elegant_notification.dart'; -import 'package:elegant_notification/resources/stacked_options.dart'; import 'package:flutter/material.dart'; class RobotNotificationsListener { bool _alertFirstRun = true; + final NTConnection connection; + final Function(String title, String description, Icon icon) onNotification; - void listen(NTConnection nt, BuildContext context) { + RobotNotificationsListener( + {required this.connection, required this.onNotification}); + + void listen() { var notifications = ntConnection.subscribe("elastic/robotnotifications"); notifications.listen((alertData, alertTimestamp) { - _onAlert(alertData!, alertTimestamp, context); + _onAlert(alertData!, alertTimestamp); }); } - void _onAlert(Object alertData, int timestamp, BuildContext context) { + void _onAlert(Object alertData, int timestamp) { //prevent showing a notification when we connect to NT if (_alertFirstRun) { _alertFirstRun = false; @@ -40,34 +43,6 @@ class RobotNotificationsListener { } else { icon = const Icon(Icons.question_mark); } - - _buildNotification(data["title"], data["description"], icon, context) - .show(context); - } - - ElegantNotification _buildNotification( - String title, String description, Icon icon, BuildContext context) { - ColorScheme colorScheme = Theme.of(context).colorScheme; - TextTheme textTheme = Theme.of(context).textTheme; - return ElegantNotification( - autoDismiss: true, - showProgressIndicator: true, - background: colorScheme.surface, - width: 350, - position: Alignment.bottomRight, - title: Text( - title, - style: textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.bold, - ), - ), - icon: icon, - description: Text(description), - stackedOptions: StackedOptions( - key: 'robotnotification', - type: StackedType.above, - itemOffset: const Offset(0, 5), - ), - ); + onNotification(data["title"], data["description"], icon); } } From edcdac8069d9d710ca9a60b6d4accebf081a6522 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Mon, 24 Jun 2024 20:37:36 -0400 Subject: [PATCH 10/14] turn subscribing to all topics its own method --- lib/services/nt4_client.dart | 15 +++++++++------ lib/services/nt_connection.dart | 7 +++++-- .../robot_notifications_listener.dart | 3 ++- test/pages/dashboard_page_test.dart | 19 +++++++++++-------- .../shuffleboard_nt_listener_test.dart | 10 +++++++--- test/test_util.dart | 13 ++++++++++--- 6 files changed, 44 insertions(+), 23 deletions(-) diff --git a/lib/services/nt4_client.dart b/lib/services/nt4_client.dart index dbefd0f9..ced53478 100644 --- a/lib/services/nt4_client.dart +++ b/lib/services/nt4_client.dart @@ -5,16 +5,14 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; -import 'package:flutter/foundation.dart'; - import 'package:collection/collection.dart'; import 'package:dot_cast/dot_cast.dart'; +import 'package:elastic_dashboard/services/log.dart'; +import 'package:flutter/foundation.dart'; import 'package:messagepack/messagepack.dart'; import 'package:msgpack_dart/msgpack_dart.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; -import 'package:elastic_dashboard/services/log.dart'; - class NT4TypeStr { static final Map typeMap = { 'boolean': 0, @@ -322,11 +320,12 @@ class NT4Client { _topicAnnounceListeners.remove(onAnnounce); } - NT4Subscription subscribe(String topic, [double period = 0.1]) { + NT4Subscription subscribe(String topic, + [double period = 0.1, bool all = false]) { NT4Subscription newSub = NT4Subscription( topic: topic, uid: getNewSubUID(), - options: NT4SubscriptionOptions(periodicRateSeconds: period, all: true), + options: NT4SubscriptionOptions(periodicRateSeconds: period, all: all), ); if (_subscribedTopics.contains(newSub)) { @@ -351,6 +350,10 @@ class NT4Client { return newSub; } + NT4Subscription subscribeAll(String topic, [double period = 0.1]) { + return subscribe(topic, period, true); + } + NT4Subscription subscribeAllSamples(String topic, [double period = 0.1]) { NT4Subscription newSub = NT4Subscription( topic: topic, diff --git a/lib/services/nt_connection.dart b/lib/services/nt_connection.dart index db9f6dba..49ff5e47 100644 --- a/lib/services/nt_connection.dart +++ b/lib/services/nt_connection.dart @@ -1,7 +1,6 @@ -import 'package:flutter/foundation.dart'; - import 'package:elastic_dashboard/services/ds_interop.dart'; import 'package:elastic_dashboard/services/nt4_client.dart'; +import 'package:flutter/foundation.dart'; NTConnection get ntConnection => NTConnection.instance; @@ -132,6 +131,10 @@ class NTConnection { return _ntClient.subscribe(topic, period); } + NT4Subscription subscribeAll(String topic, [double period = 0.1]) { + return _ntClient.subscribeAll(topic, period); + } + void unSubscribe(NT4Subscription subscription) { _ntClient.unSubscribe(subscription); } diff --git a/lib/services/robot_notifications_listener.dart b/lib/services/robot_notifications_listener.dart index 2da094d9..36a4eaa9 100644 --- a/lib/services/robot_notifications_listener.dart +++ b/lib/services/robot_notifications_listener.dart @@ -12,7 +12,8 @@ class RobotNotificationsListener { {required this.connection, required this.onNotification}); void listen() { - var notifications = ntConnection.subscribe("elastic/robotnotifications"); + var notifications = + ntConnection.subscribeAll("elastic/robotnotifications", 0.2); notifications.listen((alertData, alertTimestamp) { _onAlert(alertData!, alertTimestamp); }); diff --git a/test/pages/dashboard_page_test.dart b/test/pages/dashboard_page_test.dart index e33559d1..64233bb4 100644 --- a/test/pages/dashboard_page_test.dart +++ b/test/pages/dashboard_page_test.dart @@ -1,14 +1,6 @@ import 'dart:convert'; import 'dart:io'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:titlebar_buttons/titlebar_buttons.dart'; - import 'package:elastic_dashboard/pages/dashboard_page.dart'; import 'package:elastic_dashboard/services/field_images.dart'; import 'package:elastic_dashboard/services/nt4_client.dart'; @@ -26,6 +18,13 @@ import 'package:elastic_dashboard/widgets/nt_widgets/multi-topic/combo_box_choos import 'package:elastic_dashboard/widgets/nt_widgets/single_topic/boolean_box.dart'; import 'package:elastic_dashboard/widgets/settings_dialog.dart'; import 'package:elastic_dashboard/widgets/tab_grid.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:titlebar_buttons/titlebar_buttons.dart'; + import '../test_util.dart'; import '../test_util.mocks.dart'; @@ -372,6 +371,10 @@ void main() { when(mockNT4Connection.subscribe(any)).thenReturn(mockSubscription); + when(mockNT4Connection.subscribeAll(any, any)).thenReturn(mockSubscription); + + when(mockNT4Connection.subscribeAll(any)).thenReturn(mockSubscription); + when(mockNT4Connection.subscribeAndRetrieveData>( '/Shuffleboard/.metadata/Test-Tab/Shuffleboard Test Number/Position')) .thenAnswer((realInvocation) => Future.value([2.0, 0.0])); diff --git a/test/services/shuffleboard_nt_listener_test.dart b/test/services/shuffleboard_nt_listener_test.dart index c0d8bf55..6f3ab3ba 100644 --- a/test/services/shuffleboard_nt_listener_test.dart +++ b/test/services/shuffleboard_nt_listener_test.dart @@ -1,10 +1,10 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - import 'package:elastic_dashboard/services/nt4_client.dart'; import 'package:elastic_dashboard/services/nt_connection.dart'; import 'package:elastic_dashboard/services/settings.dart'; import 'package:elastic_dashboard/services/shuffleboard_nt_listener.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + import '../test_util.mocks.dart'; void main() { @@ -48,6 +48,10 @@ void main() { when(mockNT4Connection.subscribe(any)).thenReturn(mockSubscription); + when(mockNT4Connection.subscribeAll(any, any)).thenReturn(mockSubscription); + + when(mockNT4Connection.subscribeAll(any)).thenReturn(mockSubscription); + NTConnection.instance = mockNT4Connection; Map announcedWidgetData = {}; diff --git a/test/test_util.dart b/test/test_util.dart index 2f117a4f..ecf4dcec 100644 --- a/test/test_util.dart +++ b/test/test_util.dart @@ -1,12 +1,11 @@ import 'dart:io'; +import 'package:elastic_dashboard/services/nt4_client.dart'; +import 'package:elastic_dashboard/services/nt_connection.dart'; import 'package:flutter/material.dart'; - import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:elastic_dashboard/services/nt4_client.dart'; -import 'package:elastic_dashboard/services/nt_connection.dart'; import 'test_util.mocks.dart'; @GenerateNiceMocks([ @@ -41,6 +40,10 @@ void setupMockOfflineNT4() { when(mockNT4Connection.subscribe(any)).thenReturn(mockSubscription); + when(mockNT4Connection.subscribeAll(any, any)).thenReturn(mockSubscription); + + when(mockNT4Connection.subscribeAll(any)).thenReturn(mockSubscription); + when(mockNT4Connection.getTopicFromName(any)) .thenReturn(NT4Topic(name: '', type: NT4TypeStr.kString, properties: {})); @@ -87,6 +90,10 @@ void setupMockOnlineNT4() { when(mockNT4Connection.subscribe(any)).thenReturn(mockSubscription); + when(mockNT4Connection.subscribeAll(any, any)).thenReturn(mockSubscription); + + when(mockNT4Connection.subscribeAll(any)).thenReturn(mockSubscription); + when(mockNT4Connection.getTopicFromName(any)) .thenReturn(NT4Topic(name: '', type: NT4TypeStr.kString, properties: {})); From 983d8e878ba2c00476933e5d5e0b59d13ef55370 Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Mon, 24 Jun 2024 20:42:12 -0400 Subject: [PATCH 11/14] make elastic robot notification variables mutable --- elasticlib/Elastic.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/elasticlib/Elastic.java b/elasticlib/Elastic.java index 3ff4c845..2c58ab7c 100644 --- a/elasticlib/Elastic.java +++ b/elasticlib/Elastic.java @@ -33,14 +33,26 @@ public ElasticNotification(NotificationLevel level, String title, String descrip this.description = description; } + public void setLevel(NotificationLevel level) { + this.level = level; + } + public NotificationLevel getLevel() { return level; } + public void setTitle(String title) { + this.title = title; + } + public String getTitle() { return title; } + public void setDescription(String description) { + this.description = description; + } + public String getDescription() { return description; } @@ -51,5 +63,4 @@ public enum NotificationLevel { ERROR } } - } \ No newline at end of file From 07fb8e96be5ce2a1784178efe74f1fb4d9360e4e Mon Sep 17 00:00:00 2001 From: Ishaan <68785503+EmeraldWither@users.noreply.github.com> Date: Mon, 24 Jun 2024 20:53:49 -0400 Subject: [PATCH 12/14] change jackson annotations in elasticlib --- elasticlib/Elastic.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/elasticlib/Elastic.java b/elasticlib/Elastic.java index 2c58ab7c..0a7f8694 100644 --- a/elasticlib/Elastic.java +++ b/elasticlib/Elastic.java @@ -1,5 +1,6 @@ package frc.robot; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -23,8 +24,11 @@ public static void sendAlert(ElasticNotification alert) { } public static class ElasticNotification { + @JsonProperty("level") private NotificationLevel level; + @JsonProperty("title") private String title; + @JsonProperty("description") private String description; public ElasticNotification(NotificationLevel level, String title, String description) { From 079530d0d185bb44c12c064443588c2b1fbfe6b1 Mon Sep 17 00:00:00 2001 From: Gold87 <91761103+Gold872@users.noreply.github.com> Date: Mon, 24 Jun 2024 21:02:16 -0400 Subject: [PATCH 13/14] Add null checks for title and description --- lib/services/robot_notifications_listener.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/services/robot_notifications_listener.dart b/lib/services/robot_notifications_listener.dart index 36a4eaa9..27927267 100644 --- a/lib/services/robot_notifications_listener.dart +++ b/lib/services/robot_notifications_listener.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:dot_cast/dot_cast.dart'; import 'package:elastic_dashboard/services/nt_connection.dart'; import 'package:flutter/material.dart'; @@ -44,6 +45,13 @@ class RobotNotificationsListener { } else { icon = const Icon(Icons.question_mark); } - onNotification(data["title"], data["description"], icon); + String? title = tryCast(data['title']); + String? description = tryCast(data['description']); + + if (title == null || description == null) { + return; + } + + onNotification(title, description, icon); } } From cce8f914b076e230fedcd05a794a0956c8610b42 Mon Sep 17 00:00:00 2001 From: Gold87 <91761103+Gold872@users.noreply.github.com> Date: Mon, 24 Jun 2024 21:08:13 -0400 Subject: [PATCH 14/14] Fix formatting --- lib/pages/dashboard_page.dart | 25 ++++++++++--------- lib/services/nt4_client.dart | 6 +++-- lib/services/nt_connection.dart | 3 ++- .../robot_notifications_listener.dart | 12 ++++++--- test/pages/dashboard_page_test.dart | 15 +++++------ .../shuffleboard_nt_listener_test.dart | 6 ++--- test/test_util.dart | 5 ++-- 7 files changed, 41 insertions(+), 31 deletions(-) diff --git a/lib/pages/dashboard_page.dart b/lib/pages/dashboard_page.dart index e29323e9..018f5f01 100644 --- a/lib/pages/dashboard_page.dart +++ b/lib/pages/dashboard_page.dart @@ -1,8 +1,21 @@ import 'dart:convert'; import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter/services.dart'; + import 'package:collection/collection.dart'; import 'package:dot_cast/dot_cast.dart'; +import 'package:elegant_notification/elegant_notification.dart'; +import 'package:elegant_notification/resources/stacked_options.dart'; +import 'package:file_selector/file_selector.dart'; +import 'package:popover/popover.dart'; +import 'package:screen_retriever/screen_retriever.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:window_manager/window_manager.dart'; + import 'package:elastic_dashboard/services/hotkey_manager.dart'; import 'package:elastic_dashboard/services/ip_address_util.dart'; import 'package:elastic_dashboard/services/log.dart'; @@ -20,18 +33,6 @@ import 'package:elastic_dashboard/widgets/editable_tab_bar.dart'; import 'package:elastic_dashboard/widgets/network_tree/networktables_tree.dart'; import 'package:elastic_dashboard/widgets/settings_dialog.dart'; import 'package:elastic_dashboard/widgets/tab_grid.dart'; -import 'package:elegant_notification/elegant_notification.dart'; -import 'package:elegant_notification/resources/stacked_options.dart'; -import 'package:file_selector/file_selector.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:flutter/services.dart'; -import 'package:popover/popover.dart'; -import 'package:screen_retriever/screen_retriever.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:window_manager/window_manager.dart'; - import '../widgets/draggable_containers/models/layout_container_model.dart'; class DashboardPage extends StatefulWidget { diff --git a/lib/services/nt4_client.dart b/lib/services/nt4_client.dart index ced53478..4240f2d0 100644 --- a/lib/services/nt4_client.dart +++ b/lib/services/nt4_client.dart @@ -5,14 +5,16 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; +import 'package:flutter/foundation.dart'; + import 'package:collection/collection.dart'; import 'package:dot_cast/dot_cast.dart'; -import 'package:elastic_dashboard/services/log.dart'; -import 'package:flutter/foundation.dart'; import 'package:messagepack/messagepack.dart'; import 'package:msgpack_dart/msgpack_dart.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:elastic_dashboard/services/log.dart'; + class NT4TypeStr { static final Map typeMap = { 'boolean': 0, diff --git a/lib/services/nt_connection.dart b/lib/services/nt_connection.dart index 49ff5e47..79089ac5 100644 --- a/lib/services/nt_connection.dart +++ b/lib/services/nt_connection.dart @@ -1,6 +1,7 @@ +import 'package:flutter/foundation.dart'; + import 'package:elastic_dashboard/services/ds_interop.dart'; import 'package:elastic_dashboard/services/nt4_client.dart'; -import 'package:flutter/foundation.dart'; NTConnection get ntConnection => NTConnection.instance; diff --git a/lib/services/robot_notifications_listener.dart b/lib/services/robot_notifications_listener.dart index 27927267..de3c1b3d 100644 --- a/lib/services/robot_notifications_listener.dart +++ b/lib/services/robot_notifications_listener.dart @@ -1,16 +1,20 @@ import 'dart:convert'; +import 'package:flutter/material.dart'; + import 'package:dot_cast/dot_cast.dart'; + import 'package:elastic_dashboard/services/nt_connection.dart'; -import 'package:flutter/material.dart'; class RobotNotificationsListener { bool _alertFirstRun = true; final NTConnection connection; final Function(String title, String description, Icon icon) onNotification; - RobotNotificationsListener( - {required this.connection, required this.onNotification}); + RobotNotificationsListener({ + required this.connection, + required this.onNotification, + }); void listen() { var notifications = @@ -51,7 +55,7 @@ class RobotNotificationsListener { if (title == null || description == null) { return; } - + onNotification(title, description, icon); } } diff --git a/test/pages/dashboard_page_test.dart b/test/pages/dashboard_page_test.dart index 64233bb4..2079816c 100644 --- a/test/pages/dashboard_page_test.dart +++ b/test/pages/dashboard_page_test.dart @@ -1,6 +1,14 @@ import 'dart:convert'; import 'dart:io'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:titlebar_buttons/titlebar_buttons.dart'; + import 'package:elastic_dashboard/pages/dashboard_page.dart'; import 'package:elastic_dashboard/services/field_images.dart'; import 'package:elastic_dashboard/services/nt4_client.dart'; @@ -18,13 +26,6 @@ import 'package:elastic_dashboard/widgets/nt_widgets/multi-topic/combo_box_choos import 'package:elastic_dashboard/widgets/nt_widgets/single_topic/boolean_box.dart'; import 'package:elastic_dashboard/widgets/settings_dialog.dart'; import 'package:elastic_dashboard/widgets/tab_grid.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:titlebar_buttons/titlebar_buttons.dart'; - import '../test_util.dart'; import '../test_util.mocks.dart'; diff --git a/test/services/shuffleboard_nt_listener_test.dart b/test/services/shuffleboard_nt_listener_test.dart index 6f3ab3ba..816af343 100644 --- a/test/services/shuffleboard_nt_listener_test.dart +++ b/test/services/shuffleboard_nt_listener_test.dart @@ -1,10 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; + import 'package:elastic_dashboard/services/nt4_client.dart'; import 'package:elastic_dashboard/services/nt_connection.dart'; import 'package:elastic_dashboard/services/settings.dart'; import 'package:elastic_dashboard/services/shuffleboard_nt_listener.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - import '../test_util.mocks.dart'; void main() { diff --git a/test/test_util.dart b/test/test_util.dart index ecf4dcec..9428e11a 100644 --- a/test/test_util.dart +++ b/test/test_util.dart @@ -1,11 +1,12 @@ import 'dart:io'; -import 'package:elastic_dashboard/services/nt4_client.dart'; -import 'package:elastic_dashboard/services/nt_connection.dart'; import 'package:flutter/material.dart'; + import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import 'package:elastic_dashboard/services/nt4_client.dart'; +import 'package:elastic_dashboard/services/nt_connection.dart'; import 'test_util.mocks.dart'; @GenerateNiceMocks([