4cf7a786d6
The shell (shell.dart): a drawer from the left edge or each page's menu button. Dash, Signals, Captures; Tools (Camera, Link test, Orin power options), the rarely used ones, after pirate-station-aide; Settings (gateway address, dark/bright, build-time theme and landing). Landing view at build time: YUKART_HOME=dash|signals, signals for now. Dash, Signals and Captures stay alive while hidden; Captures has its own navigator, so a run survives switching views. Back goes inside Captures, then to the landing view, then out. The mock banner sits over every page. main.dart is startup only; the old home screen is pages/signals.dart; dialogs and sheets moved to actions/; the protocol client, USB binding and Reading to link/. lib/README.md catalogues it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
73 lines
2.0 KiB
Dart
73 lines
2.0 KiB
Dart
// An on/off lamp in the boxed pattern (lib/widgets/stat_box.dart): the label is the
|
|
// lamp. Takes a [Reading] (lib/link/reading.dart) so missing and stale draw as they do elsewhere.
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../link/reading.dart';
|
|
import '../theme/palette.dart';
|
|
|
|
/// An on/off lamp in the boxed pattern: the label is the lamp. Lit in foreground
|
|
/// (alarm when [warn]), dark in subdued; missing shows as a dash.
|
|
class Telltale extends StatelessWidget {
|
|
const Telltale({
|
|
super.key,
|
|
required this.label,
|
|
required this.reading,
|
|
this.icon,
|
|
this.warn = false,
|
|
this.flex = 1,
|
|
});
|
|
|
|
final String label;
|
|
|
|
/// Drawn instead of the label when set. Glyphs like ◀ ▶ come out as emoji on Android.
|
|
final IconData? icon;
|
|
final Reading reading;
|
|
final bool warn;
|
|
final int flex;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final p = AppTheme.of(context);
|
|
final missing = reading.value == null;
|
|
final lit = reading.on && !reading.dim;
|
|
final color = lit
|
|
? (warn ? p.alarm : p.foreground)
|
|
: p.subdued.withValues(alpha: missing ? 0.35 : 0.6);
|
|
return Expanded(
|
|
flex: flex,
|
|
child: LayoutBuilder(
|
|
builder: (context, c) {
|
|
final size = c.maxHeight * 0.3;
|
|
if (icon != null && !missing) {
|
|
return Center(
|
|
child: Icon(
|
|
icon,
|
|
size: c.maxHeight * 0.7,
|
|
color: color,
|
|
semanticLabel: label,
|
|
),
|
|
);
|
|
}
|
|
return Center(
|
|
child: FittedBox(
|
|
fit: BoxFit.scaleDown,
|
|
child: Text(
|
|
missing ? '—' : label,
|
|
maxLines: 1,
|
|
style: TextStyle(
|
|
fontFamily: hudFont,
|
|
fontSize: size,
|
|
fontWeight: lit ? FontWeight.w700 : FontWeight.w400,
|
|
color: color,
|
|
letterSpacing: 1,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|