From 2128f5fba52b2e5174f70d4af30c172f1f4b7e99 Mon Sep 17 00:00:00 2001 From: Gold87 <91761103+Gold872@users.noreply.github.com> Date: Sun, 27 Oct 2024 14:52:39 -0400 Subject: [PATCH 1/6] Added shortcut to open settings dialog --- lib/pages/dashboard_page.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/pages/dashboard_page.dart b/lib/pages/dashboard_page.dart index 255987f3..76b0b98a 100644 --- a/lib/pages/dashboard_page.dart +++ b/lib/pages/dashboard_page.dart @@ -859,6 +859,18 @@ class _DashboardPageState extends State with WindowListener { }); }, ); + // Open settings dialog (Ctrl + ,) + hotKeyManager.register( + HotKey( + LogicalKeyboardKey.comma, + modifiers: [KeyModifier.control], + ), + callback: () { + if ((ModalRoute.of(context)?.isCurrent ?? false) && mounted) { + _displaySettingsDialog(context); + } + }, + ); } void _lockLayout() async { From 3fd29cf961a85e0a06f41a932bccba31c87f8fe8 Mon Sep 17 00:00:00 2001 From: Gold87 <91761103+Gold872@users.noreply.github.com> Date: Sun, 27 Oct 2024 15:07:15 -0400 Subject: [PATCH 2/6] Added shortcuts for connecting to robot and sim --- lib/pages/dashboard_page.dart | 92 ++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/lib/pages/dashboard_page.dart b/lib/pages/dashboard_page.dart index 76b0b98a..cdf524e5 100644 --- a/lib/pages/dashboard_page.dart +++ b/lib/pages/dashboard_page.dart @@ -871,6 +871,39 @@ class _DashboardPageState extends State with WindowListener { } }, ); + // Connect to robot (Ctrl + K) + hotKeyManager.register( + HotKey( + LogicalKeyboardKey.keyK, + modifiers: [KeyModifier.control], + ), + callback: () { + if (preferences.getInt(PrefKeys.ipAddressMode) == + IPAddressMode.driverStation.index) { + return; + } + _updateIPAddress(IPAddressUtil.teamNumberToIP( + preferences.getInt(PrefKeys.teamNumber) ?? Defaults.teamNumber)); + _changeIPAddressMode(IPAddressMode.driverStation); + }, + ); + // Connect to sim (Ctrl + Shift + K) + hotKeyManager.register( + HotKey( + LogicalKeyboardKey.keyK, + modifiers: [ + KeyModifier.control, + KeyModifier.shift, + ], + ), + callback: () { + if (preferences.getInt(PrefKeys.ipAddressMode) == + IPAddressMode.localhost.index) { + return; + } + _changeIPAddressMode(IPAddressMode.localhost); + }, + ); } void _lockLayout() async { @@ -987,36 +1020,8 @@ class _DashboardPageState extends State with WindowListener { if (mode.index == preferences.getInt(PrefKeys.ipAddressMode)) { return; } - await preferences.setInt(PrefKeys.ipAddressMode, mode.index); - switch (mode) { - case IPAddressMode.driverStation: - String? lastAnnouncedIP = - widget.ntConnection.dsClient.lastAnnouncedIP; - - if (lastAnnouncedIP == null) { - break; - } - - _updateIPAddress(lastAnnouncedIP); - break; - case IPAddressMode.roboRIOmDNS: - _updateIPAddress(IPAddressUtil.teamNumberToRIOmDNS( - preferences.getInt(PrefKeys.teamNumber) ?? - Defaults.teamNumber)); - break; - case IPAddressMode.teamNumber: - _updateIPAddress(IPAddressUtil.teamNumberToIP( - preferences.getInt(PrefKeys.teamNumber) ?? - Defaults.teamNumber)); - break; - case IPAddressMode.localhost: - _updateIPAddress('localhost'); - break; - default: - setState(() {}); - break; - } + _changeIPAddressMode(mode); }, onIPAddressChanged: (String? data) async { if (data == null || @@ -1175,6 +1180,35 @@ class _DashboardPageState extends State with WindowListener { ); } + void _changeIPAddressMode(IPAddressMode mode) async { + await preferences.setInt(PrefKeys.ipAddressMode, mode.index); + switch (mode) { + case IPAddressMode.driverStation: + String? lastAnnouncedIP = widget.ntConnection.dsClient.lastAnnouncedIP; + + if (lastAnnouncedIP == null) { + break; + } + + _updateIPAddress(lastAnnouncedIP); + break; + case IPAddressMode.roboRIOmDNS: + _updateIPAddress(IPAddressUtil.teamNumberToRIOmDNS( + preferences.getInt(PrefKeys.teamNumber) ?? Defaults.teamNumber)); + break; + case IPAddressMode.teamNumber: + _updateIPAddress(IPAddressUtil.teamNumberToIP( + preferences.getInt(PrefKeys.teamNumber) ?? Defaults.teamNumber)); + break; + case IPAddressMode.localhost: + _updateIPAddress('localhost'); + break; + default: + setState(() {}); + break; + } + } + void _updateIPAddress(String newIPAddress) async { if (newIPAddress == preferences.getString(PrefKeys.ipAddress)) { return; From a7bbb758aebcd197dda935ebe00f612d21436f6c Mon Sep 17 00:00:00 2001 From: Gold87 <91761103+Gold872@users.noreply.github.com> Date: Sun, 27 Oct 2024 15:29:53 -0400 Subject: [PATCH 3/6] Added tests for new shortcuts --- test/pages/dashboard_page_test.dart | 92 +++++++++++++++++++++++++++++ test/test_util.dart | 4 +- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/test/pages/dashboard_page_test.dart b/test/pages/dashboard_page_test.dart index 822b593e..5bfaf5a7 100644 --- a/test/pages/dashboard_page_test.dart +++ b/test/pages/dashboard_page_test.dart @@ -14,6 +14,7 @@ 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/hotkey_manager.dart'; +import 'package:elastic_dashboard/services/ip_address_util.dart'; import 'package:elastic_dashboard/services/nt4_client.dart'; import 'package:elastic_dashboard/services/nt_connection.dart'; import 'package:elastic_dashboard/services/settings.dart'; @@ -46,7 +47,9 @@ void main() { await FieldImages.loadFields('assets/fields/'); jsonString = jsonEncode(jsonDecode(File(jsonFilePath).readAsStringSync())); + }); + setUp(() async { SharedPreferences.setMockInitialValues({ PrefKeys.layout: jsonString, PrefKeys.teamNumber: 353, @@ -1325,6 +1328,95 @@ void main() { expect(find.byType(SettingsDialog), findsOneWidget); }); + testWidgets('IP Address shortcuts', (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + SharedPreferences.setMockInitialValues({ + PrefKeys.ipAddressMode: IPAddressMode.custom.index, + PrefKeys.ipAddress: '127.0.0.1', + PrefKeys.teamNumber: 353, + }); + + MockNTConnection ntConnection = createMockOfflineNT4(); + MockDSInteropClient dsClient = MockDSInteropClient(); + when(dsClient.lastAnnouncedIP).thenReturn(null); + when(ntConnection.dsClient).thenReturn(dsClient); + + await widgetTester.pumpWidget( + MaterialApp( + home: DashboardPage( + ntConnection: ntConnection, + preferences: preferences, + version: '0.0.0.0', + ), + ), + ); + + await widgetTester.pumpAndSettle(); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.control); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.keyK); + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.keyK); + + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.control); + + await widgetTester.pumpAndSettle(); + + expect(preferences.getInt(PrefKeys.ipAddressMode), + IPAddressMode.driverStation.index); + expect(preferences.getString(PrefKeys.ipAddress), '10.3.53.2'); + + await preferences.setString(PrefKeys.ipAddress, '0.0.0.0'); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.control); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.keyK); + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.keyK); + + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.control); + + await widgetTester.pumpAndSettle(); + + // IP Address shouldn't change since it's already driver station + expect(preferences.getInt(PrefKeys.ipAddressMode), + IPAddressMode.driverStation.index); + expect(preferences.getString(PrefKeys.ipAddress), '0.0.0.0'); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.control); + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.shift); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.keyK); + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.keyK); + + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.control); + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.shift); + + await widgetTester.pumpAndSettle(); + + expect(preferences.getInt(PrefKeys.ipAddressMode), + IPAddressMode.localhost.index); + expect(preferences.getString(PrefKeys.ipAddress), 'localhost'); + + await preferences.setString(PrefKeys.ipAddress, '0.0.0.0'); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.control); + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.shift); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.keyK); + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.keyK); + + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.control); + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.shift); + + await widgetTester.pumpAndSettle(); + + // IP address shouldn't change since mode is set to localhost + expect(preferences.getInt(PrefKeys.ipAddressMode), + IPAddressMode.localhost.index); + expect(preferences.getString(PrefKeys.ipAddress), '0.0.0.0'); + }); + testWidgets( 'Robot Notifications', (widgetTester) async { diff --git a/test/test_util.dart b/test/test_util.dart index 5e69dfdd..08dfcbd4 100644 --- a/test/test_util.dart +++ b/test/test_util.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import 'package:elastic_dashboard/services/ds_interop.dart'; import 'package:elastic_dashboard/services/nt4_client.dart'; import 'package:elastic_dashboard/services/nt_connection.dart'; import 'test_util.mocks.dart'; @@ -12,7 +13,8 @@ import 'test_util.mocks.dart'; @GenerateNiceMocks([ MockSpec(), MockSpec(), - MockSpec() + MockSpec(), + MockSpec(), ]) MockNTConnection createMockOfflineNT4() { HttpOverrides.global = null; From 4fe2c2c4021ebc2c0487384771bdc13da7dd5cc8 Mon Sep 17 00:00:00 2001 From: Gold87 <91761103+Gold872@users.noreply.github.com> Date: Sun, 27 Oct 2024 15:34:26 -0400 Subject: [PATCH 4/6] Fixed shuffleboard listener tests --- test/pages/dashboard_page_test.dart | 1 + test/services/shuffleboard_nt_listener_test.dart | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/pages/dashboard_page_test.dart b/test/pages/dashboard_page_test.dart index 5bfaf5a7..7d2942bc 100644 --- a/test/pages/dashboard_page_test.dart +++ b/test/pages/dashboard_page_test.dart @@ -482,6 +482,7 @@ void main() { final mockSubscription = MockNT4Subscription(); when(mockNT4Connection.isNT4Connected).thenReturn(true); + when(mockNT4Connection.ntConnected).thenReturn(ValueNotifier(true)); when(mockNT4Connection.connectionStatus()) .thenAnswer((_) => Stream.value(true)); when(mockNT4Connection.latencyStream()).thenAnswer((_) => Stream.value(0)); diff --git a/test/services/shuffleboard_nt_listener_test.dart b/test/services/shuffleboard_nt_listener_test.dart index 77069d53..c9da9ea3 100644 --- a/test/services/shuffleboard_nt_listener_test.dart +++ b/test/services/shuffleboard_nt_listener_test.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -34,6 +35,7 @@ void main() { .thenAnswer((_) => Stream.value(null)); when(mockNT4Connection.isNT4Connected).thenReturn(true); + when(mockNT4Connection.ntConnected).thenReturn(ValueNotifier(true)); when(mockNT4Connection.latencyStream()).thenAnswer((_) => Stream.value(0)); From 3ef6635e4f8fcd0be49d2d3b4f5fd89cc6207d71 Mon Sep 17 00:00:00 2001 From: Gold87 <91761103+Gold872@users.noreply.github.com> Date: Sun, 27 Oct 2024 15:36:40 -0400 Subject: [PATCH 5/6] Added test for opening settings via shortcut --- test/pages/dashboard_page_test.dart | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/pages/dashboard_page_test.dart b/test/pages/dashboard_page_test.dart index 7d2942bc..5b2f94af 100644 --- a/test/pages/dashboard_page_test.dart +++ b/test/pages/dashboard_page_test.dart @@ -1329,6 +1329,33 @@ void main() { expect(find.byType(SettingsDialog), findsOneWidget); }); + testWidgets('Opening settings (shortcut)', (widgetTester) async { + FlutterError.onError = ignoreOverflowErrors; + + await widgetTester.pumpWidget( + MaterialApp( + home: DashboardPage( + ntConnection: createMockOfflineNT4(), + preferences: preferences, + version: '0.0.0.0', + ), + ), + ); + + await widgetTester.pumpAndSettle(); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.control); + + await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.comma); + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.comma); + + await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.control); + + await widgetTester.pumpAndSettle(); + + expect(find.byType(SettingsDialog), findsOneWidget); + }); + testWidgets('IP Address shortcuts', (widgetTester) async { FlutterError.onError = ignoreOverflowErrors; From b3c9438607c1d8a53b468e47e92e6c2a830f64e6 Mon Sep 17 00:00:00 2001 From: Gold87 <91761103+Gold872@users.noreply.github.com> Date: Sun, 27 Oct 2024 15:40:19 -0400 Subject: [PATCH 6/6] Fixed import sorting --- test/services/shuffleboard_nt_listener_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/test/services/shuffleboard_nt_listener_test.dart b/test/services/shuffleboard_nt_listener_test.dart index c9da9ea3..da34b293 100644 --- a/test/services/shuffleboard_nt_listener_test.dart +++ b/test/services/shuffleboard_nt_listener_test.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; + import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:shared_preferences/shared_preferences.dart';