Files
dmc/app/lib/ui/providers/wifi_connection_provider.dart
T

94 lines
3.0 KiB
Dart

import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../transport/link_transport.dart';
import '../../transport/udp/udp_transport.dart';
import 'database_provider.dart';
/// App-lebenslanger UDP-Transport (Doku Kommunikationsschicht Abschnitt 3),
/// verdrahtet gegen Host/Port aus den Einstellungen. Analog zu
/// [bluetoothTransportProvider] bewusst nicht autoDispose - siehe dortige
/// Begruendung.
final wifiTransportProvider = Provider<UdpTransport>((ref) {
final settingsRepo = ref.watch(appSettingsRepositoryProvider);
final transport = UdpTransport(
getHost: settingsRepo.loadConnectionWifiHost,
getPort: settingsRepo.loadConnectionWifiPort,
);
ref.onDispose(transport.dispose);
return transport;
});
/// Reaktiver [LinkState] des WLAN-Transports fuer die Oberflaeche.
final wifiLinkStateProvider = StreamProvider<LinkState>((ref) {
final transport = ref.watch(wifiTransportProvider);
return transport.state;
});
/// Grund des zuletzt gemeldeten [LinkState.error] des WLAN-Transports.
final wifiLinkErrorReasonProvider = Provider<LinkErrorReason?>((ref) {
ref.watch(wifiLinkStateProvider);
return ref.watch(wifiTransportProvider).lastErrorReason;
});
/// Ein Eintrag im WLAN-Verbindungsprotokoll (Doku 7).
class WifiConnectionLogEntry {
const WifiConnectionLogEntry(this.timestamp, this.message);
final DateTime timestamp;
final String message;
}
/// Verbindungsprotokoll + Paketzaehler fuer den WLAN-Transport, analog zu
/// [ConnectionLogNotifier] fuer Bluetooth.
class WifiConnectionLogNotifier
extends Notifier<List<WifiConnectionLogEntry>> {
static const _maxEntries = 50;
StreamSubscription<LinkState>? _stateSub;
StreamSubscription<void>? _dataSub;
int _packetCount = 0;
int get packetCount => _packetCount;
@override
List<WifiConnectionLogEntry> build() {
final transport = ref.watch(wifiTransportProvider);
_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(wifiTransportProvider);
final message = switch (linkState) {
LinkState.disconnected => 'Disconnected',
LinkState.connecting => 'Connecting...',
LinkState.connected => 'Listening on port ${transport.boundPort}',
LinkState.error => 'Error: '
'${transport.lastErrorMessage ?? transport.lastErrorReason?.name ?? 'unknown'}',
};
_append(message);
}
void _append(String message) {
final entry = WifiConnectionLogEntry(DateTime.now(), message);
final next = [...state, entry];
state = next.length > _maxEntries
? next.sublist(next.length - _maxEntries)
: next;
}
}
final wifiConnectionLogProvider =
NotifierProvider<WifiConnectionLogNotifier, List<WifiConnectionLogEntry>>(
WifiConnectionLogNotifier.new);