import 'state/aircraft_state.dart'; import 'state/alert_state.dart'; /// How the status chip is coloured, worst last. enum StatusLevel { neutral, ready, caution, danger } /// The status chip at the left of the HUD's top bar (GO 4's "Ready to Go (GPS)"). class FlightStatus { const FlightStatus(this.text, this.level); final String text; final StatusLevel level; /// GPS level the flight controller needs before it will record a home point. static const int minGpsLevel = 3; /// Reads the chip off the flight controller state and the live diagnostics. /// Ordered by what the pilot most needs to know: an automatic manoeuvre in /// progress first, then battery, then faults, then the plain flight state. static FlightStatus of({required bool connected, required AircraftState a, AlertState? alerts}) { if (!connected) return const FlightStatus('Disconnected', StatusLevel.neutral); if (a.updatedAt == null) return const FlightStatus('Connecting…', StatusLevel.neutral); final String mode = a.flightModeEnum ?? ''; final bool flying = a.isFlying == true; final AlertSeverity? worst = alerts?.worst; if (a.landingConfirmationNeeded == true) return const FlightStatus('Confirm landing', StatusLevel.caution); if (a.goingHome == true || mode == 'GO_HOME') { return const FlightStatus('Returning to Home', StatusLevel.caution); } if (mode == 'AUTO_LANDING' || mode == 'CONFIRM_LANDING') return const FlightStatus('Landing', StatusLevel.caution); if (mode == 'AUTO_TAKEOFF' || mode == 'ASSISTED_TAKEOFF') return const FlightStatus('Taking off', StatusLevel.ready); if (a.seriousLowBattery == true) return const FlightStatus('Battery critical', StatusLevel.danger); if (a.lowBattery == true) return const FlightStatus('Low battery', StatusLevel.caution); if (worst == AlertSeverity.critical) { return FlightStatus(flying ? 'Warning' : 'Cannot take off', StatusLevel.danger); } if (a.imuPreheating == true) return const FlightStatus('IMU preheating', StatusLevel.caution); final String fix = _positioning(a); if (flying) { return FlightStatus('In Flight ($fix)', worst == AlertSeverity.warning ? StatusLevel.caution : StatusLevel.ready); } final bool noFix = fix == 'ATTI'; return FlightStatus( 'Ready to Go ($fix)', noFix || worst == AlertSeverity.warning ? StatusLevel.caution : StatusLevel.ready, ); } /// What the aircraft is holding position with: GPS, the vision system, or nothing. static String _positioning(AircraftState a) { if ((a.gpsSignalLevel ?? 0) >= minGpsLevel) return 'GPS'; if (a.visionPositioningBeingUsed == true) return 'Vision'; return 'ATTI'; } @override bool operator ==(Object other) => other is FlightStatus && other.text == text && other.level == level; @override int get hashCode => Object.hash(text, level); @override String toString() => 'FlightStatus($text, $level)'; }