import 'dart:async'; import '../dji_service.dart'; import '../flight_model.dart'; /// Keeps [FlightModel.flyZones] stocked with the GEO zones around (plan P8): /// fetched around the aircraft's fix, or the phone's before it has one, again /// after moving 2 km or every 10 minutes; plus the unlocked list once per /// connection with the aircraft's licences, and the GEO database's state at /// start. One fetch at a time; failures wait for the next position. class FlyZoneLoader { FlyZoneLoader({required this.model, required this.dji}); final FlightModel model; final DjiService dji; bool _busy = false; bool _unlockedLoaded = false; void start() { model.aircraft.addListener(_check); model.addListener(_onModel); unawaited(refreshDatabase()); _check(); } void dispose() { model.aircraft.removeListener(_check); model.removeListener(_onModel); } void _onModel() { if (!model.connected) _unlockedLoaded = false; _check(); } /// The aircraft's fix, else the phone's. (double, double)? get _position { final double? lat = model.aircraft.latitude, lon = model.aircraft.longitude; if (lat != null && lon != null && !(lat == 0 && lon == 0)) return (lat, lon); final double? pLat = model.phoneLatitude, pLon = model.phoneLongitude; if (pLat != null && pLon != null) return (pLat, pLon); return null; } void _check() { if (model.connected && !_unlockedLoaded) { _unlockedLoaded = true; unawaited(refreshUnlocked()); unawaited(refreshLicences()); } final (double, double)? p = _position; if (p == null || _busy || !model.flyZones.needsZonesFor(p.$1, p.$2)) return; unawaited(_fetch(p)); } Future _fetch((double, double) p) async { _busy = true; try { final List> zones = await dji.getFlyZonesNearby(latitude: p.$1, longitude: p.$2); model.flyZones.applyZones(zones, latitude: p.$1, longitude: p.$2); } catch (_) { // Database not ready or offline: retry when the position moves on. } finally { _busy = false; } } /// The aircraft's licences (custom unlock zones). Future refreshLicences() async { try { model.flyZones.applyLicences(await dji.getFlyZoneLicences()); } catch (_) { // Not reported by this aircraft. } } /// The GEO database's versions and state (app-level, no aircraft needed). Future refreshDatabase() async { try { model.flyZones.applyDatabase(await dji.getFlyZoneDatabase()); } catch (_) { // SDK not registered yet. } } Future refreshUnlocked() async { try { model.flyZones.applyUnlocked(await dji.getUnlockedFlyZones()); } catch (_) { // Not reported by this aircraft. } } }