diff --git a/lib/globals.dart b/lib/globals.dart deleted file mode 100644 index d2022a9..0000000 --- a/lib/globals.dart +++ /dev/null @@ -1,7 +0,0 @@ -library; - -import "package:nt4/nt4.dart"; - - - -NT4Client? ntClient; diff --git a/lib/main.dart b/lib/main.dart index e3bdf04..bad9274 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,12 +1,16 @@ +import 'package:helm/ntutils.dart'; + import 'pages/dashboard.dart'; import 'package:flutter/material.dart'; void main() { - runApp(const MyApp()); + runApp(MyApp()); } class MyApp extends StatelessWidget { - const MyApp({super.key}); + MyApp({super.key}) { + NTUtils().connect("localhost"); + } // This widget is the root of your application. @override @@ -29,7 +33,10 @@ class MyApp extends StatelessWidget { // // This works for code too, not just values: Most code changes can be // tested with just a hot reload. - colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue, brightness: Brightness.dark), + colorScheme: ColorScheme.fromSeed( + seedColor: Colors.blue, + brightness: Brightness.dark, + ), ), home: const Dashboard(), ); diff --git a/lib/ntutils.dart b/lib/ntutils.dart new file mode 100644 index 0000000..e18b2e7 --- /dev/null +++ b/lib/ntutils.dart @@ -0,0 +1,89 @@ +import "dart:ui"; + +import "package:nt4/nt4.dart"; + +class NTUtils { + static final NTUtils _instance = NTUtils._internal(); + + factory NTUtils() { + return _instance; + } + + bool isConnected = false; + bool _isAttemptingToConnect = false; + String _serverAddress = ""; + + NT4Client? ntClient; + + final Map _nt4Subscriptions = {}; + + final List connectCallbacks = []; + final List disconnectCallbacks = []; + + void addConnectCallback(VoidCallback cb) { + connectCallbacks.add(cb); + } + + void addDisconnectCallback(VoidCallback cb) { + disconnectCallbacks.add(cb); + } + + void connect(String serverAddress) { + _serverAddress = serverAddress; + _isAttemptingToConnect = true; + ntClient = NT4Client( + serverBaseAddress: serverAddress, + onConnect: () { + isConnected = true; + _isAttemptingToConnect = false; + + for (VoidCallback cb in connectCallbacks) { + cb(); + } + }, + onDisconnect: () { + isConnected = false; + + for (VoidCallback cb in disconnectCallbacks) { + cb(); + } + }, + ); + } + + String connectionStatus() { + if (_isAttemptingToConnect) { + return "Attempting to connect to $_serverAddress"; + } + if (isConnected) { + return "Connected"; + } else { + return "Not Connected"; + } + } + + NT4Subscription subscribe(String topic) { + if (!_nt4Subscriptions.containsKey(topic)) { + NT4Subscription subscrip = ntClient!.subscribe( + topic, + NT4SubscriptionOptions(), + ); + _nt4Subscriptions[topic] = subscrip; + } + + return _nt4Subscriptions[topic]!; + } + + final Map _nt4Topics = {}; + + NT4Topic getPublicTopic(String topic, String type) { + if (!_nt4Topics.containsKey(topic)) { + NT4Topic top = ntClient!.publishNewTopic(topic, type); + _nt4Topics[topic] = top; + } + + return _nt4Topics[topic]!; + } + + NTUtils._internal(); +} diff --git a/lib/pages/dashboard.dart b/lib/pages/dashboard.dart index ba3475f..055ee00 100644 --- a/lib/pages/dashboard.dart +++ b/lib/pages/dashboard.dart @@ -1,11 +1,31 @@ import 'package:flutter/material.dart'; +import 'package:helm/ntutils.dart'; import 'package:helm/widgets/base_card.dart'; +import 'package:helm/widgets/posty_results_card.dart'; import 'package:responsive_grid/responsive_grid.dart'; import '../widgets/text_card.dart'; -class Dashboard extends StatelessWidget { +class Dashboard extends StatefulWidget { const Dashboard({super.key}); + @override + State createState() => _DashboardState(); +} + +class _DashboardState extends State { + String connectionState = NTUtils().connectionStatus(); + + _DashboardState() { + NTUtils().addConnectCallback(updateConnectionState); + NTUtils().addDisconnectCallback(updateConnectionState); + } + + void updateConnectionState() { + setState(() { + connectionState = NTUtils().connectionStatus(); + }); + } + @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done @@ -22,7 +42,7 @@ class Dashboard extends StatelessWidget { backgroundColor: Theme.of(context).colorScheme.inversePrimary, // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. - title: Text("Helm"), + title: Text("Helm - $connectionState"), ), body: ResponsiveGridRow( children: [ @@ -40,7 +60,10 @@ class Dashboard extends StatelessWidget { children: [ ResponsiveGridCol( md: 6, - child: TextCard(cardTitle: "Match State"), + child: TextCard( + cardTitle: "Match State", + ntTopic: "/FMSInfo/StationNumber", + ), ), ResponsiveGridCol( md: 6, @@ -48,7 +71,7 @@ class Dashboard extends StatelessWidget { ), ResponsiveGridCol( md: 6, - child: TextCard(cardTitle: "Blah Blah"), + child: TextCard(cardTitle: "Robot State"), ), ], ), diff --git a/lib/widgets/text_card.dart b/lib/widgets/text_card.dart index 6652273..bc1651f 100644 --- a/lib/widgets/text_card.dart +++ b/lib/widgets/text_card.dart @@ -1,11 +1,13 @@ import 'package:flutter/material.dart'; import './base_card.dart'; +import 'package:nt4/nt4.dart'; +import 'package:helm/ntutils.dart'; class TextCard extends StatefulWidget { const TextCard({ super.key, required this.cardTitle, - this.ntTopic, + this.ntTopic = '', this.height = 1, this.width = 1, }); @@ -20,15 +22,24 @@ class TextCard extends StatefulWidget { } class _TextCardState extends State { + String _val = ""; + + void setVal(String newVal) { + setState(() { + _val = newVal; + }); + } + @override Widget build(BuildContext context) { + NT4Subscription sub = NTUtils().subscribe(widget.ntTopic!); + sub.listen((data) => setVal(data.toString())); + return BaseCard( cardTitle: widget.cardTitle, width: widget.width, height: widget.height, - children: [ - Text("WAHOOOO") - ], + children: [Text(_val)], ); } } diff --git a/test/widget_test.dart b/test/widget_test.dart index c6af2d0..a359e10 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -5,26 +5,5 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:helm/main.dart'; - void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); }