Layout
This commit is contained in:
parent
cfbad36dd7
commit
7971bf8201
|
|
@ -10,12 +10,9 @@ class NTUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConnected = false;
|
bool isConnected = false;
|
||||||
bool _isAttemptingToConnect = false;
|
|
||||||
String _serverAddress = "";
|
String _serverAddress = "";
|
||||||
|
|
||||||
NT4Client? ntClient;
|
NT4Client? _ntClient;
|
||||||
|
|
||||||
final Map<String, NT4Subscription> _nt4Subscriptions = {};
|
|
||||||
|
|
||||||
final List<VoidCallback> connectCallbacks = [];
|
final List<VoidCallback> connectCallbacks = [];
|
||||||
final List<VoidCallback> disconnectCallbacks = [];
|
final List<VoidCallback> disconnectCallbacks = [];
|
||||||
|
|
@ -30,12 +27,10 @@ class NTUtils {
|
||||||
|
|
||||||
void connect(String serverAddress) {
|
void connect(String serverAddress) {
|
||||||
_serverAddress = serverAddress;
|
_serverAddress = serverAddress;
|
||||||
_isAttemptingToConnect = true;
|
_ntClient = NT4Client(
|
||||||
ntClient = NT4Client(
|
|
||||||
serverBaseAddress: serverAddress,
|
serverBaseAddress: serverAddress,
|
||||||
onConnect: () {
|
onConnect: () {
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
_isAttemptingToConnect = false;
|
|
||||||
|
|
||||||
for (VoidCallback cb in connectCallbacks) {
|
for (VoidCallback cb in connectCallbacks) {
|
||||||
cb();
|
cb();
|
||||||
|
|
@ -52,33 +47,26 @@ class NTUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
String connectionStatus() {
|
String connectionStatus() {
|
||||||
if (_isAttemptingToConnect) {
|
|
||||||
return "Attempting to connect to $_serverAddress";
|
|
||||||
}
|
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
return "Connected";
|
return "Connected";
|
||||||
} else {
|
} else {
|
||||||
return "Not Connected";
|
return "Not Connected. Attempting to connect to $_serverAddress";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NT4Subscription subscribe(String topic) {
|
NT4Subscription subscribe(String topic) {
|
||||||
if (!_nt4Subscriptions.containsKey(topic)) {
|
NT4Subscription subscrip = _ntClient!.subscribe(
|
||||||
NT4Subscription subscrip = ntClient!.subscribe(
|
|
||||||
topic,
|
topic,
|
||||||
NT4SubscriptionOptions(),
|
NT4SubscriptionOptions(),
|
||||||
);
|
);
|
||||||
_nt4Subscriptions[topic] = subscrip;
|
return subscrip;
|
||||||
}
|
|
||||||
|
|
||||||
return _nt4Subscriptions[topic]!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, NT4Topic> _nt4Topics = {};
|
final Map<String, NT4Topic> _nt4Topics = {};
|
||||||
|
|
||||||
NT4Topic getPublicTopic(String topic, String type) {
|
NT4Topic getPublicTopic(String topic, String type) {
|
||||||
if (!_nt4Topics.containsKey(topic)) {
|
if (!_nt4Topics.containsKey(topic)) {
|
||||||
NT4Topic top = ntClient!.publishNewTopic(topic, type);
|
NT4Topic top = _ntClient!.publishNewTopic(topic, type);
|
||||||
_nt4Topics[topic] = top;
|
_nt4Topics[topic] = top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:helm/ntutils.dart';
|
import 'package:helm/ntutils.dart';
|
||||||
import 'package:helm/widgets/base_card.dart';
|
import 'package:helm/widgets/base_card.dart';
|
||||||
import 'package:helm/widgets/posty_results_card.dart';
|
import 'package:helm/widgets/posty/posty_results_card.dart';
|
||||||
|
import 'package:helm/widgets/posty/posty_summary_card.dart';
|
||||||
import 'package:responsive_grid/responsive_grid.dart';
|
import 'package:responsive_grid/responsive_grid.dart';
|
||||||
import '../widgets/text_card.dart';
|
import '../widgets/text_card.dart';
|
||||||
|
|
||||||
|
|
@ -34,7 +35,10 @@ class _DashboardState extends State<Dashboard> {
|
||||||
// The Flutter framework has been optimized to make rerunning build methods
|
// The Flutter framework has been optimized to make rerunning build methods
|
||||||
// fast, so that you can just rebuild anything that needs updating rather
|
// fast, so that you can just rebuild anything that needs updating rather
|
||||||
// than having to individually change instances of widgets.
|
// than having to individually change instances of widgets.
|
||||||
return Scaffold(
|
return DefaultTabController(
|
||||||
|
length: 1,
|
||||||
|
initialIndex: 0,
|
||||||
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
// TRY THIS: Try changing the color here to a specific color (to
|
// TRY THIS: Try changing the color here to a specific color (to
|
||||||
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
|
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
|
||||||
|
|
@ -43,8 +47,11 @@ class _DashboardState extends State<Dashboard> {
|
||||||
// Here we take the value from the MyHomePage object that was created by
|
// 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.
|
// the App.build method, and use it to set our appbar title.
|
||||||
title: Text("Helm - $connectionState"),
|
title: Text("Helm - $connectionState"),
|
||||||
|
bottom: TabBar(tabs: <Widget>[Tab(icon: Icon(Icons.home))]),
|
||||||
),
|
),
|
||||||
body: ResponsiveGridRow(
|
body: TabBarView(
|
||||||
|
children: <Widget>[
|
||||||
|
ResponsiveGridRow(
|
||||||
children: [
|
children: [
|
||||||
ResponsiveGridCol(
|
ResponsiveGridCol(
|
||||||
md: 12,
|
md: 12,
|
||||||
|
|
@ -69,10 +76,7 @@ class _DashboardState extends State<Dashboard> {
|
||||||
md: 6,
|
md: 6,
|
||||||
child: TextCard(cardTitle: "Match Time"),
|
child: TextCard(cardTitle: "Match Time"),
|
||||||
),
|
),
|
||||||
ResponsiveGridCol(
|
ResponsiveGridCol(md: 6, child: PostyResultsCard()),
|
||||||
md: 6,
|
|
||||||
child: TextCard(cardTitle: "Robot State"),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -80,7 +84,10 @@ class _DashboardState extends State<Dashboard> {
|
||||||
md: 6,
|
md: 6,
|
||||||
child: ResponsiveGridRow(
|
child: ResponsiveGridRow(
|
||||||
children: [
|
children: [
|
||||||
ResponsiveGridCol(child: TextCard(cardTitle: "Blah")),
|
ResponsiveGridCol(
|
||||||
|
child: TextCard(cardTitle: "Blah"),
|
||||||
|
),
|
||||||
|
ResponsiveGridCol(child: PostySummaryCard()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -89,6 +96,9 @@ class _DashboardState extends State<Dashboard> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:helm/ntutils.dart';
|
||||||
|
import 'package:helm/widgets/base_card.dart';
|
||||||
|
import 'package:nt4/nt4.dart';
|
||||||
|
|
||||||
|
class PostyResultsCard extends StatefulWidget {
|
||||||
|
const PostyResultsCard({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _PostyResultsCardState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostyResultsCardState extends State<PostyResultsCard> {
|
||||||
|
final String _ntTopic = "/Posty/results/post/resultsJson";
|
||||||
|
|
||||||
|
List<PostyResultModel> resultsData = [];
|
||||||
|
|
||||||
|
_PostyResultsCardState() {
|
||||||
|
NT4Subscription sub = NTUtils().subscribe(_ntTopic);
|
||||||
|
sub.listen((data) {
|
||||||
|
setState(() {
|
||||||
|
List<dynamic> tmp = jsonDecode(data.toString());
|
||||||
|
|
||||||
|
for (dynamic json in tmp) {
|
||||||
|
resultsData.add(PostyResultModel.fromJson(json));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Widget> children = [];
|
||||||
|
|
||||||
|
resultsData.sort((a, b) => a.subsystemName.compareTo(b.subsystemName));
|
||||||
|
|
||||||
|
children =
|
||||||
|
resultsData.map((result) {
|
||||||
|
Color statusColor = Colors.green;
|
||||||
|
if (result.result == "FAILED") {
|
||||||
|
statusColor = Colors.red;
|
||||||
|
} else if (result.result == "SKIPPED") {
|
||||||
|
statusColor = Colors.grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
"${result.testName} -- ${result.result}",
|
||||||
|
style: TextStyle(color: statusColor),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
return BaseCard(
|
||||||
|
width: 6,
|
||||||
|
height: 2,
|
||||||
|
cardTitle: "Self Test Results",
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PostyResultModel {
|
||||||
|
String testName = "";
|
||||||
|
String subsystemName = "";
|
||||||
|
String result = "";
|
||||||
|
String failReason = "";
|
||||||
|
|
||||||
|
PostyResultModel(
|
||||||
|
this.testName,
|
||||||
|
this.subsystemName,
|
||||||
|
this.result,
|
||||||
|
this.failReason,
|
||||||
|
);
|
||||||
|
|
||||||
|
PostyResultModel.fromJson(Map<String, dynamic> json)
|
||||||
|
: testName = json['testName'] as String,
|
||||||
|
subsystemName = json['subsystemName'] as String,
|
||||||
|
result = json['result'] as String,
|
||||||
|
failReason = json['failReason'] as String;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:helm/ntutils.dart';
|
||||||
|
import 'package:helm/widgets/base_card.dart';
|
||||||
|
import 'package:nt4/nt4.dart';
|
||||||
|
|
||||||
|
class PostySummaryCard extends StatefulWidget {
|
||||||
|
const PostySummaryCard({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _PostySummaryCardState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostySummaryCardState extends State<PostySummaryCard> {
|
||||||
|
final String _ntTopic = "/Posty/results/post/resultsJson";
|
||||||
|
|
||||||
|
List<PostyResultModel> resultsData = [];
|
||||||
|
|
||||||
|
_PostySummaryCardState() {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
NT4Subscription sub = NTUtils().subscribe(_ntTopic);
|
||||||
|
sub.listen((data) {
|
||||||
|
setState(() {
|
||||||
|
List<dynamic> tmp = jsonDecode(data.toString());
|
||||||
|
|
||||||
|
for (dynamic json in tmp) {
|
||||||
|
resultsData.add(PostyResultModel.fromJson(json));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
bool systemNotReady = false;
|
||||||
|
|
||||||
|
for (PostyResultModel result in resultsData) {
|
||||||
|
systemNotReady |= result.result == "FAILED";
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> children = [
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
decoration: BoxDecoration(color: Colors.grey, shape: BoxShape.circle),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(2),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: !systemNotReady ? Colors.green : Colors.red,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
return BaseCard(
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
cardTitle: "System Status",
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PostyResultModel {
|
||||||
|
String testName = "";
|
||||||
|
String subsystemName = "";
|
||||||
|
String result = "";
|
||||||
|
String failReason = "";
|
||||||
|
|
||||||
|
PostyResultModel(
|
||||||
|
this.testName,
|
||||||
|
this.subsystemName,
|
||||||
|
this.result,
|
||||||
|
this.failReason,
|
||||||
|
);
|
||||||
|
|
||||||
|
PostyResultModel.fromJson(Map<String, dynamic> json)
|
||||||
|
: testName = json['testName'] as String,
|
||||||
|
subsystemName = json['subsystemName'] as String,
|
||||||
|
result = json['result'] as String,
|
||||||
|
failReason = json['failReason'] as String;
|
||||||
|
}
|
||||||
|
|
@ -4,16 +4,16 @@ import 'package:nt4/nt4.dart';
|
||||||
import 'package:helm/ntutils.dart';
|
import 'package:helm/ntutils.dart';
|
||||||
|
|
||||||
class TextCard extends StatefulWidget {
|
class TextCard extends StatefulWidget {
|
||||||
const TextCard({
|
TextCard({
|
||||||
super.key,
|
super.key,
|
||||||
required this.cardTitle,
|
required this.cardTitle,
|
||||||
this.ntTopic = '',
|
this.ntTopic = "",
|
||||||
this.height = 1,
|
this.height = 1,
|
||||||
this.width = 1,
|
this.width = 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String cardTitle;
|
final String cardTitle;
|
||||||
final String? ntTopic;
|
String ntTopic = "";
|
||||||
|
|
||||||
final int width, height;
|
final int width, height;
|
||||||
|
|
||||||
|
|
@ -24,6 +24,8 @@ class TextCard extends StatefulWidget {
|
||||||
class _TextCardState extends State<TextCard> {
|
class _TextCardState extends State<TextCard> {
|
||||||
String _val = "";
|
String _val = "";
|
||||||
|
|
||||||
|
_TextCardState() {}
|
||||||
|
|
||||||
void setVal(String newVal) {
|
void setVal(String newVal) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_val = newVal;
|
_val = newVal;
|
||||||
|
|
@ -32,9 +34,8 @@ class _TextCardState extends State<TextCard> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
NT4Subscription sub = NTUtils().subscribe(widget.ntTopic!);
|
NT4Subscription sub = NTUtils().subscribe(widget.ntTopic);
|
||||||
sub.listen((data) => setVal(data.toString()));
|
sub.listen((data) => setVal(data.toString()));
|
||||||
|
|
||||||
return BaseCard(
|
return BaseCard(
|
||||||
cardTitle: widget.cardTitle,
|
cardTitle: widget.cardTitle,
|
||||||
width: widget.width,
|
width: widget.width,
|
||||||
|
|
|
||||||
26
pubspec.lock
26
pubspec.lock
|
|
@ -87,26 +87,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker
|
name: leak_tracker
|
||||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.9"
|
version: "11.0.2"
|
||||||
leak_tracker_flutter_testing:
|
leak_tracker_flutter_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker_flutter_testing
|
name: leak_tracker_flutter_testing
|
||||||
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.9"
|
version: "3.0.10"
|
||||||
leak_tracker_testing:
|
leak_tracker_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker_testing
|
name: leak_tracker_testing
|
||||||
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.2"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -143,10 +143,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.16.0"
|
version: "1.17.0"
|
||||||
msgpack_dart:
|
msgpack_dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -228,10 +228,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.4"
|
version: "0.7.7"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -244,10 +244,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.2.0"
|
||||||
vm_service:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -273,5 +273,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5"
|
version: "2.4.5"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.7.0 <4.0.0"
|
dart: ">=3.8.0-0 <4.0.0"
|
||||||
flutter: ">=3.18.0-18.0.pre.54"
|
flutter: ">=3.18.0-18.0.pre.54"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue