feat(display): Sprint 4 — pantalla principal del autopilot
Archivos nuevos:
display/lib/data/autopilot_state.dart
- ChangeNotifier con todos los datos del autopilot
- Simulación de velero en mar (heading drift / P-controller)
- API pública estable: engage(), disengage(), adjustSetpoint(), selectMode()
- Sprint 7: los internos se reemplazan por Modbus RTU, la API no cambia
display/lib/screens/cockpit/cockpit_screen.dart
- Pantalla principal: TopBar, ModeSelector, CompassRose, DataStrip,
HeadingAdjustBar, RudderIndicator, ENGAGE/DISENGAGE
- Logo con triple-tap para ciclar temas (StateWidget con Timer)
- Indicador DEMO visible cuando isConnected == false
- Engranaje → AppearanceSettingsScreen
display/lib/widgets/themed/engage_button.dart
- Botón verde con glow; dimmed cuando ya está engaged
display/lib/widgets/themed/heading_adjust_bar.dart
- Botones << < [SET 048.0°] > >>
- Deshabilitado cuando mode == STANDBY
display/lib/widgets/themed/status_chip.dart
- Indicador de punto + label para NMEA / GPS (ok / warn / off)
Modificado:
display/lib/main.dart
- MultiProvider: agrega AutopilotState al árbol de providers
- Ruta inicial: CockpitScreen.routeName ('/') en lugar de Appearance
AR_electronics — AR-Autopilot Project
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../theme/autopilot_theme.dart';
|
||||
|
||||
/// Connection / data-source status indicator — coloured dot + label.
|
||||
///
|
||||
/// Used in the [CockpitScreen] top-bar to show NMEA and GPS link state.
|
||||
enum StatusLevel {
|
||||
/// Data valid and link active.
|
||||
ok,
|
||||
|
||||
/// Data stale, link degraded, or GPS fix lost.
|
||||
warn,
|
||||
|
||||
/// Link absent (serial port not open, concentrador not connected).
|
||||
off,
|
||||
}
|
||||
|
||||
class StatusChip extends StatelessWidget {
|
||||
const StatusChip({
|
||||
super.key,
|
||||
required this.theme,
|
||||
required this.label,
|
||||
required this.status,
|
||||
});
|
||||
|
||||
final AutopilotTheme theme;
|
||||
final String label;
|
||||
final StatusLevel status;
|
||||
|
||||
Color get _dotColor => switch (status) {
|
||||
StatusLevel.ok => theme.okColor,
|
||||
StatusLevel.warn => theme.warnColor,
|
||||
StatusLevel.off => theme.textDisabled,
|
||||
};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final dot = _dotColor;
|
||||
final glowing = status == StatusLevel.ok && theme.accentGlowRadius > 0;
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 7,
|
||||
height: 7,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: dot,
|
||||
boxShadow: glowing
|
||||
? [BoxShadow(color: dot.withValues(alpha: 0.6), blurRadius: 6)]
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color:
|
||||
status == StatusLevel.off ? theme.textDisabled : theme.textMuted,
|
||||
fontSize: 10,
|
||||
letterSpacing: 0.5,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user