import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../domain/telemetry/system_message.dart'; import '../../transport/connection_type.dart'; import '../../transport/flight_controller_link.dart'; import 'connection_settings_provider.dart'; import 'telemetry_provider.dart'; /// Fuehrt das System-Messages-Log fuer den gleichnamigen Tab im /// Drohnen-Status-Menue (Doku: "aendere das warnings MenĂ¼ in System /// Messages ... Verbindung hergestellt/verloren, Verbindungstyp geaendert, /// Wegpunkte uebertragen") - beobachtet [telemetryProvider] und /// [connectionSettingsProvider] dauerhaft (bewusst KEIN autoDispose, siehe /// telemetry_provider.dart-Doku zur analogen Begruendung bei /// flightControllerLinkProvider), damit ein Ereignis auch dann protokolliert /// wird, wenn die System-Messages-Ansicht selbst gerade nicht geoeffnet ist. /// Beginnt zu beobachten, sobald irgendein Widget diesen Provider erstmals /// liest (siehe FlyScreen) - vor diesem Zeitpunkt liegende Ereignisse /// erscheinen nicht im Log, das ist fuer ein Live-Log erwartbar. class SystemMessageLogNotifier extends Notifier> { TelemetryFrame? _previousFrame; bool _hadData = false; @override List build() { ref.listen>(telemetryProvider, (previous, next) { next.when( data: (frame) { // Flankengetriggert wie "Connection lost" unten, nur umgekehrt - // anders als dort ist hier kein Sonderfall fuer die allererste // Verbindung noetig: der Uebergang "noch keine Daten" -> "erste // Daten" ist immer ein echtes "Connected", auch beim allerersten // Mal. if (!_hadData) { _log('Connected', SystemMessageSeverity.info); } final events = detectSystemMessages( previous: _previousFrame, current: frame, now: DateTime.now(), ); _previousFrame = frame; _hadData = true; if (events.isNotEmpty) { state = [...events.reversed, ...state]; } }, error: (error, stackTrace) { // Nur melden, wenn zuvor bereits Frames flossen - sonst wuerde // schon das (normale) Ausbleiben der allerersten Verbindung als // "Connection lost" auftauchen. if (_hadData) { _log('Connection lost', SystemMessageSeverity.critical); } _previousFrame = null; _hadData = false; }, loading: () {}, ); }); // Verbindungsart-Wechsel (Doku: "Verbindungstyp geaendert") - nur ab dem // zweiten geladenen Wert protokollieren, sonst wuerde bereits das // erstmalige Laden der Einstellungen aus der DB als "Wechsel" erscheinen. ConnectionType? previousType; var sawFirstLoad = false; ref.listen(connectionSettingsProvider, (previous, next) { final type = next.value?.connectionType; if (type == null) return; if (!sawFirstLoad) { sawFirstLoad = true; previousType = type; return; } if (type != previousType) { _log('Connection type changed to ${_connectionTypeLabel(type)}', SystemMessageSeverity.info); previousType = type; } }); return []; } String _connectionTypeLabel(ConnectionType type) => switch (type) { ConnectionType.wifi => 'WiFi mLRS UDP', ConnectionType.mock => 'Mock (Test)', }; /// Fuegt einen Eintrag manuell hinzu (Doku: "Wegpunkte uebertragen") - fuer /// Ereignisse, die nicht aus der Telemetrie/den Einstellungen ableitbar /// sind, sondern vom Aufloeser einer konkreten Aktion (z.B. FlyScreen nach /// einem Missions-Upload) gemeldet werden. void log(String message, {SystemMessageSeverity severity = SystemMessageSeverity.info}) { _log(message, severity); } void _log(String message, SystemMessageSeverity severity) { state = [ SystemMessage(timestamp: DateTime.now(), message: message, severity: severity), ...state, ]; } void clear() => state = []; } final systemMessageLogProvider = NotifierProvider>( SystemMessageLogNotifier.new);