Log mission name on send, log mission/drone-profile changes, auto-send on mission switch
Include the mission name in the "Mission sent"/"Mission upload failed" System Messages (was just the waypoint count before). Add MissionMeta.switchSeq, bumped only by an actual mission switch (startNew/startNewFromPlace/loadMission) - not by the id a brand-new mission gets from its first autosave, and not by restoreLastSession() on app start. FlyScreen compares it to detect a genuine switch and reacts two ways: logs "Mission changed to ..." and automatically re-uploads the new route to the flight controller, reusing the same send path as the manual send button (same _sending guard, same success/failure snackbar and log entry). Mission-change and drone-profile-change logging intentionally live in FlyScreen's ref.listen callbacks, not in mission_meta_provider.dart / active_drone_profile_provider.dart themselves - those providers have no notion of the app mode (Plan vs Fly, tracked separately by AppModeCubit), and logging there would record a change regardless of mode. Since FlyScreen only exists while Fly mode is active, scoping the listeners there means switching missions or drone profiles from Plan mode produces no System Messages entries, and only a mission switch (not a drone profile switch) triggers the automatic re-upload, matching what was asked for. Also splits systemMessageLogProvider (the plain message list + log(), no telemetry dependency) from the new systemMessageAutoLogProvider (the Connected/lost/battery/failsafe/connection-type auto-detection, which does watch telemetryProvider) - discovered while wiring the mission-change logging that logging a plain message from Plan-mode code was forcing the entire telemetry/transport stack to spin up as a side effect, which broke an unrelated Plan-mode test (UdpTransport threw on a double-disconnect during teardown). Keeping the two concerns apart means calling log() for a one-off message never has that side effect. Verified end to end on the Pixel_10a emulator: switching to an empty mission while in Fly mode correctly showed "No waypoints to send" and logged "Mission changed to ..." automatically, without touching the send button. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b09d00ab9f
commit
b68c16d8e6
@@ -6,96 +6,26 @@ 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.
|
||||
/// Haelt die Liste der System Messages plus das manuelle [log()] (Doku:
|
||||
/// "aendere das warnings Menü in System Messages"). Bewusst schlank, ohne
|
||||
/// jede Telemetrie-/Verbindungsbeobachtung: mission_meta_provider.dart und
|
||||
/// active_drone_profile_provider.dart rufen log() auch aus dem Plan-Modus
|
||||
/// heraus auf (Missions-/Drohnenprofilwechsel) - wuerde diese Klasse selbst
|
||||
/// telemetryProvider beobachten, risse schon ein simpler Missionswechsel im
|
||||
/// Plan-Modus ungewollt den kompletten Telemetrie-/Transport-Stack (inkl.
|
||||
/// echtem MSP/UDP-Transport) mit hoch. Die automatische Erkennung
|
||||
/// (Connected/Lost/Verbindungstyp-Wechsel) sitzt deshalb separat in
|
||||
/// [systemMessageAutoLogProvider], die ausschliesslich der Fly-Modus
|
||||
/// beobachtet.
|
||||
class SystemMessageLogNotifier extends Notifier<List<SystemMessage>> {
|
||||
TelemetryFrame? _previousFrame;
|
||||
bool _hadData = false;
|
||||
|
||||
@override
|
||||
List<SystemMessage> build() {
|
||||
ref.listen<AsyncValue<TelemetryFrame>>(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: () {},
|
||||
);
|
||||
});
|
||||
List<SystemMessage> build() => [];
|
||||
|
||||
// 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.
|
||||
/// Fuegt einen Eintrag manuell hinzu (Doku: "Wegpunkte uebertragen",
|
||||
/// "Wechsel der Mission oder des Drohnenprofils") - fuer Ereignisse, die
|
||||
/// vom Aufloeser einer konkreten Aktion gemeldet werden, statt aus
|
||||
/// Telemetrie/Einstellungen automatisch erkannt zu 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,
|
||||
@@ -108,3 +38,79 @@ class SystemMessageLogNotifier extends Notifier<List<SystemMessage>> {
|
||||
final systemMessageLogProvider =
|
||||
NotifierProvider<SystemMessageLogNotifier, List<SystemMessage>>(
|
||||
SystemMessageLogNotifier.new);
|
||||
|
||||
/// Automatische Erkennung von Connected/Connection-lost/Batterie-/Failsafe-/
|
||||
/// Verbindungstyp-Aenderungen (Doku: "wenn die Verbindung hergestellt
|
||||
/// wird/verloren geht, der verbindungstyp geaendert wird") - getrennt von
|
||||
/// [systemMessageLogProvider] selbst (siehe dessen Doku), damit Plan-Modus-
|
||||
/// Code, der nur log() fuer eine manuelle Meldung braucht, nicht versehentlich
|
||||
/// telemetryProvider mit hochzieht. autoDispose: nur beobachtet, waehrend
|
||||
/// irgendwer (FlyScreen) diesen Provider liest - verlaesst der Nutzer den
|
||||
/// Fly-Modus, wird die Beobachtung wieder abgebaut wie bei telemetryProvider
|
||||
/// selbst.
|
||||
final systemMessageAutoLogProvider = Provider.autoDispose<void>((ref) {
|
||||
TelemetryFrame? previousFrame;
|
||||
var hadData = false;
|
||||
|
||||
ref.listen<AsyncValue<TelemetryFrame>>(telemetryProvider, (previous, next) {
|
||||
next.when(
|
||||
data: (frame) {
|
||||
final log = ref.read(systemMessageLogProvider.notifier);
|
||||
// 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.log('Connected');
|
||||
}
|
||||
final events = detectSystemMessages(
|
||||
previous: previousFrame,
|
||||
current: frame,
|
||||
now: DateTime.now(),
|
||||
);
|
||||
previousFrame = frame;
|
||||
hadData = true;
|
||||
for (final event in events) {
|
||||
log.log(event.message, severity: event.severity);
|
||||
}
|
||||
},
|
||||
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) {
|
||||
ref.read(systemMessageLogProvider.notifier)
|
||||
.log('Connection lost', severity: 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) {
|
||||
ref.read(systemMessageLogProvider.notifier)
|
||||
.log('Connection type changed to ${_connectionTypeLabel(type)}');
|
||||
previousType = type;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
String _connectionTypeLabel(ConnectionType type) => switch (type) {
|
||||
ConnectionType.wifi => 'WiFi mLRS UDP',
|
||||
ConnectionType.mock => 'Mock (Test)',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user