import 'package:flutter/foundation.dart'; import 'parse.dart'; /// Radio links and the remote controller's battery. Fed from the `links` and /// `rc` groups of the telemetry tick (≤2 Hz). class LinkState extends ChangeNotifier { /// `ocusync` / `lightbridge` / `wifi` as the air link reports it at runtime. String? kind; /// RC → aircraft control-link quality, 0–100. int? uplinkQuality; /// Aircraft → RC video-link quality, 0–100. int? downlinkQuality; int? rcBatteryPercent; int? rcBatteryMah; bool? rcCharging; /// `RCMode` name on dual-operator remotes: `MASTER` / `SLAVE` / `NORMAL` … String? rcMode; bool? masterSlaveConnected; /// "M" / "S" for the HUD's dual-operator badge, null when flying solo. String? get rcRoleBadge => switch (rcMode) { 'MASTER' || 'MASTER_SUB' => 'M', 'SLAVE' || 'SLAVE_SUB' => 'S', _ => null, }; DateTime? updatedAt; /// 0–5 bars, the way the top bar draws a 0–100 quality. static int bars(int? quality) => quality == null ? 0 : ((quality.clamp(0, 100) + 19) ~/ 20); void apply({Map? links, Map? rc}) { kind = asString(links?['kind']); uplinkQuality = asInt(links?['uplinkQuality']); downlinkQuality = asInt(links?['downlinkQuality']); rcBatteryPercent = asInt(rc?['batteryPercent']); rcBatteryMah = asInt(rc?['batteryMah']); rcCharging = asBool(rc?['isCharging']); rcMode = asString(rc?['mode']); masterSlaveConnected = asBool(rc?['masterSlaveConnected']); updatedAt = DateTime.now(); notifyListeners(); } void clear() { kind = rcMode = null; uplinkQuality = downlinkQuality = rcBatteryPercent = rcBatteryMah = null; rcCharging = masterSlaveConnected = null; updatedAt = null; notifyListeners(); } }