import 'package:flutter/material.dart'; import '../services.dart'; import '../theme.dart'; import '../uplink/uplink.dart'; import 'flight_tab.dart'; import 'logbook_tab.dart'; import 'nearby_tab.dart'; import 'settings_page.dart'; /// Signed-in home: Flight (session), Nearby (Remote ID receiver), Logbook. class AgentShell extends StatefulWidget { const AgentShell({super.key}); @override State createState() => _AgentShellState(); } class _AgentShellState extends State { int _tab = 0; bool _started = false; @override void didChangeDependencies() { super.didChangeDependencies(); if (_started) return; _started = true; // Signing in is what turns the Agent on: GPS, the receiver and the uplink // all start here so the pilot only has to open DJI Fly. final Services s = Services.of(context); WidgetsBinding.instance.addPostFrameCallback((_) async { await s.pilot.start(); if (!s.rid.running) { try { await s.rid.start(); } catch (_) { // Shown on the Nearby tab; the session still works by hand. } } s.uplink.enable(s.api.serverUrl); }); } @override Widget build(BuildContext context) { const List titles = ['Flight', 'Nearby aircraft', 'Logbook']; return Scaffold( appBar: AppBar( title: Text(titles[_tab]), actions: [ const _UplinkChip(), IconButton( tooltip: 'Settings', icon: const Icon(Icons.settings_outlined), onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => const SettingsPage())), ), ], ), body: IndexedStack(index: _tab, children: const [FlightTab(), NearbyTab(), LogbookTab()]), bottomNavigationBar: NavigationBar( selectedIndex: _tab, onDestinationSelected: (int i) => setState(() => _tab = i), destinations: const [ NavigationDestination(icon: Icon(Icons.flight_takeoff), label: 'Flight'), NavigationDestination(icon: Icon(Icons.radar), label: 'Nearby'), NavigationDestination(icon: Icon(Icons.menu_book_outlined), label: 'Logbook'), ], ), ); } } class _UplinkChip extends StatelessWidget { const _UplinkChip(); @override Widget build(BuildContext context) { final Uplink uplink = Services.of(context).uplink; return ListenableBuilder( listenable: uplink, builder: (BuildContext context, _) { final (Color c, String t) = switch (uplink.status) { UplinkStatus.live => (PV.ready, 'LIVE'), UplinkStatus.connecting => (PV.inkMuted, 'IDLE'), UplinkStatus.offline => (PV.caution, 'OFFLINE'), UplinkStatus.off => (PV.inkMuted, 'OFF'), }; return Tooltip( message: 'Live uplink to PilotVault', child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: Row(children: [StatusDot(c), const SizedBox(width: 6), Text(t, style: PV.label)]), ), ); }, ); } }