Files
TelemetryMonitor/lib/ui/status_bar.dart

179 lines
5.3 KiB
Dart

import 'package:flutter/material.dart';
import '../session/status_snapshot.dart';
import '../session/view_state.dart';
import '../transport/connection_state.dart';
import 'app_scope.dart';
class StatusBar extends StatelessWidget {
const StatusBar({super.key});
@override
Widget build(BuildContext context) {
final scope = AppScope.of(context);
return Material(
color: Theme.of(context).colorScheme.surface,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
child: ValueListenableBuilder<StatusSnapshot>(
valueListenable: scope.session.statusSnapshot,
builder: (_, snap, __) {
return Wrap(
spacing: 14,
runSpacing: 6,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
_ConnectionPill(snap.connection, scope.settings.wsUrl),
_Sep(),
_PpsPill(snap.pps),
_Sep(),
_PausePill(scope.session.pauseSource),
_Sep(),
const Text('Status:',
style: TextStyle(fontSize: 11, color: Colors.grey)),
...List.generate(8, (i) {
return _StatusPill(
name: scope.layout.statusNames[i],
value: snap.statusValues[i],
);
}),
],
);
},
),
),
);
}
}
class _Sep extends StatelessWidget {
@override
Widget build(BuildContext context) =>
Container(width: 1, height: 14, color: Colors.grey.shade400);
}
class _ConnectionPill extends StatelessWidget {
const _ConnectionPill(this.state, this.url);
final WsConnectionState state;
final String url;
@override
Widget build(BuildContext context) {
final (color, label) = switch (state) {
WsConnectionState.connected => (Colors.green, 'WS connected'),
WsConnectionState.connecting => (Colors.orange, 'Connecting'),
WsConnectionState.reconnecting => (Colors.orange, 'Reconnecting'),
WsConnectionState.disconnected => (Colors.grey, 'Disconnected'),
};
return Row(mainAxisSize: MainAxisSize.min, children: [
_Dot(color),
const SizedBox(width: 6),
Text(label, style: const TextStyle(fontSize: 11)),
const SizedBox(width: 6),
Text(url,
style: const TextStyle(
fontFamily: 'monospace', fontSize: 11, color: Colors.grey)),
]);
}
}
class _PpsPill extends StatelessWidget {
const _PpsPill(this.pps);
final double pps;
@override
Widget build(BuildContext context) {
return Row(mainAxisSize: MainAxisSize.min, children: [
const Text('PPS ',
style: TextStyle(fontSize: 11, color: Colors.grey)),
SizedBox(
width: 32,
child: Text(
pps.round().toString(),
textAlign: TextAlign.right,
style: const TextStyle(
fontFamily: 'monospace',
fontSize: 11,
fontWeight: FontWeight.w500),
),
),
]);
}
}
class _PausePill extends StatelessWidget {
const _PausePill(this.source);
final PauseSource source;
@override
Widget build(BuildContext context) {
if (source == PauseSource.none) {
return const SizedBox.shrink();
}
final label = switch (source) {
PauseSource.user => 'Paused (user)',
PauseSource.proto => 'Paused (proto)',
PauseSource.both => 'Paused (user + proto)',
PauseSource.none => '',
};
return Row(mainAxisSize: MainAxisSize.min, children: [
_Dot(Colors.orange),
const SizedBox(width: 6),
Text(label, style: const TextStyle(fontSize: 11)),
]);
}
}
class _StatusPill extends StatelessWidget {
const _StatusPill({required this.name, required this.value});
final String name;
final int? value;
@override
Widget build(BuildContext context) {
final (bg, fg, dot, text) = switch (value) {
null => (Colors.grey.shade200, Colors.grey.shade700, Colors.grey,
'$name · ?'),
0 => (Colors.grey.shade200, Colors.grey.shade700, Colors.grey,
'$name · 0'),
1 => (Colors.red.shade100, Colors.red.shade900, Colors.red,
'$name · 1'),
2 => (Colors.amber.shade100, Colors.amber.shade900, Colors.amber,
'$name · 2'),
3 => (Colors.green.shade100, Colors.green.shade900, Colors.green,
'$name · 3'),
_ => (Colors.grey.shade200, Colors.grey.shade700, Colors.grey,
'$name · $value'),
};
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(10),
),
child: Row(mainAxisSize: MainAxisSize.min, children: [
_Dot(dot, size: 7),
const SizedBox(width: 5),
Text(
text,
style: TextStyle(
fontFamily: 'monospace',
fontSize: 10,
color: fg,
),
),
]),
);
}
}
class _Dot extends StatelessWidget {
const _Dot(this.color, {this.size = 8});
final Color color;
final double size;
@override
Widget build(BuildContext context) => Container(
width: size,
height: size,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
);
}