connection settings cleanup and mock test added. removed bluetooth implementation

This commit is contained in:
Constantin Leue
2026-08-05 20:01:25 +02:00
parent 8e4df2d0d3
commit f65dceb338
15 changed files with 113 additions and 895 deletions
@@ -1,110 +0,0 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../transport/bluetooth/bluetooth_classic_transport.dart';
import '../../transport/bluetooth/bluetooth_device_info.dart';
import '../../transport/link_transport.dart';
import 'database_provider.dart';
/// App-lebenslanger Bluetooth-Classic-Transport (Doku Kommunikationsschicht
/// Abschnitt 3), verdrahtet gegen die gemerkte Geraete-MAC in den
/// Einstellungen. Bewusst nicht autoDispose: die Verbindung soll bestehen
/// bleiben, waehrend zwischen Fly- und Plan-Modus gewechselt wird, und erst
/// beim Verlassen des Fly-Modus explizit getrennt werden (Doku 3,
/// Robustheit: "Verbindung beim Verlassen des Fly-Modus sauber schliessen").
final bluetoothTransportProvider = Provider<BluetoothClassicTransport>((ref) {
final settingsRepo = ref.watch(appSettingsRepositoryProvider);
final transport = BluetoothClassicTransport(
getRememberedAddress: settingsRepo.loadConnectionDeviceAddress,
rememberAddress: settingsRepo.setConnectionDeviceAddress,
);
ref.onDispose(transport.dispose);
return transport;
});
/// Reaktiver [LinkState] des Bluetooth-Transports fuer die Oberflaeche
/// (Verbindungsindikator, Abnahmekriterium: "Zustand jederzeit sichtbar").
final linkStateProvider = StreamProvider<LinkState>((ref) {
final transport = ref.watch(bluetoothTransportProvider);
return transport.state;
});
/// Grund des zuletzt gemeldeten [LinkState.error] (Doku 3, Robustheit: "Grund
/// mitfuehren und in der Oberflaeche anzeigen"). Wird bei jedem neuen
/// LinkState neu ausgelesen, da der Transport ihn synchron mitfuehrt.
final linkErrorReasonProvider = Provider<LinkErrorReason?>((ref) {
ref.watch(linkStateProvider);
return ref.watch(bluetoothTransportProvider).lastErrorReason;
});
/// Gekoppelte Geraete fuer die manuelle Auswahlliste (Doku 3.2c). Wird bei
/// jedem [LinkState]-Wechsel neu geladen, damit eine frisch angeschlossene
/// Kopplung (ueber den "Geraet koppeln"-Knopf) ohne expliziten Reload
/// auftaucht.
final bondedDevicesProvider = FutureProvider<List<BluetoothDeviceInfo>>((ref) {
ref.watch(linkStateProvider);
return ref.watch(bluetoothTransportProvider).listBondedDevices();
});
/// Ein Eintrag im Verbindungsprotokoll (Doku 7: "einfache Textansicht der
/// letzten Ereignisse ... spart im Feld viel Ratearbeit").
class ConnectionLogEntry {
const ConnectionLogEntry(this.timestamp, this.message);
final DateTime timestamp;
final String message;
}
/// Verbindungsprotokoll + Paketzaehler (Doku 7). Haengt sich an den
/// LinkState- und den Rohdaten-Stream des Transports, damit auch ohne
/// MSP-Decoder schon sichtbar ist, dass ueberhaupt Bytes ankommen.
class ConnectionLogNotifier extends Notifier<List<ConnectionLogEntry>> {
static const _maxEntries = 50;
StreamSubscription<LinkState>? _stateSub;
StreamSubscription<void>? _dataSub;
int _packetCount = 0;
int get packetCount => _packetCount;
@override
List<ConnectionLogEntry> build() {
final transport = ref.watch(bluetoothTransportProvider);
_stateSub?.cancel();
_dataSub?.cancel();
_packetCount = 0;
_stateSub = transport.state.listen(_onStateChanged);
_dataSub = transport.incoming.listen((_) => _packetCount++);
ref.onDispose(() {
_stateSub?.cancel();
_dataSub?.cancel();
});
return const [];
}
void _onStateChanged(LinkState linkState) {
final transport = ref.read(bluetoothTransportProvider);
final message = switch (linkState) {
LinkState.disconnected => 'Disconnected',
LinkState.connecting => 'Connecting...',
LinkState.connected =>
'Connected${transport.connectedDevice != null ? ' (${transport.connectedDevice!.displayName})' : ''}',
LinkState.error =>
'Error: ${transport.lastErrorMessage ?? transport.lastErrorReason?.name ?? 'unknown'}',
};
_append(message);
}
void _append(String message) {
final entry = ConnectionLogEntry(DateTime.now(), message);
final next = [...state, entry];
state = next.length > _maxEntries
? next.sublist(next.length - _maxEntries)
: next;
}
}
final connectionLogProvider =
NotifierProvider<ConnectionLogNotifier, List<ConnectionLogEntry>>(
ConnectionLogNotifier.new);
+2 -5
View File
@@ -11,11 +11,8 @@ import 'wifi_connection_provider.dart';
/// FlightControllerLink fuer den Fly-Modus (Doku 3.1): bei WLAN als
/// gewaehlter Verbindungsart ein echter MSP-Link ueber den UDP-Transport,
/// sonst (Bluetooth/5G/USB, oder solange die Einstellungen noch nicht
/// geladen sind) weiterhin der Mock fuer UI-Entwicklung ohne Hardware -
/// Bluetooth ist auf der eingesetzten mLRS-Bruecke ohnehin nicht moeglich
/// (Doku Kommunikationsschicht v2, Abschnitt 1), 5G/USB sind noch nicht
/// umgesetzt.
/// sonst (ConnectionType.mock, oder solange die Einstellungen noch nicht
/// geladen sind) der Mock fuer UI-Entwicklung/Testphase ohne Hardware.
///
/// connectionType wird reaktiv beobachtet (ref.watch), nicht nur einmalig
/// gelesen - beim ersten App-Start ist connectionSettingsProvider oft noch