Rebuild the Flutter/DJI-MSDK-V4 Fly App to the v2 UI kit and wire the full SDK surface behind it. Native (Kotlin): split DjiSdkBridge into a method/event router delegating to per-subsystem SubBridge helpers sharing a BridgeCtx — FlightController (takeoff/land/RTH + rich telemetry), Camera (mode/record/photo/exposure), Gimbal, Mission (Waypoint + ActiveTrack; QuickShots via ActiveTrack QUICK_SHOT), Media (MediaManager list/thumbnail/download), and optional DJI account login. Manifest gains scoped media permissions. Flutter: ten screens under lib/ui/ (Flight HUD, capture modes, camera settings, settings menu, map+waypoints, home, album, academy, profile, routes/flight logs), driven by an expanded FlightModel. New PVIcon renders the kit's SVG paths via flutter_svg; map uses flutter_map + latlong2. Pin transitive androidx.core/browser down to SDK-35-compatible versions so the newer plugins don't force AGP 8.9.1 onto the DJI toolchain. Verified with `flutter build apk --debug` (compiles Dart + all Kotlin); runtime behaviour is untested here — it needs a physical DJI-connected device. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
79 lines
2.7 KiB
Dart
79 lines
2.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
import '../theme.dart';
|
|
import 'pv_icons.dart';
|
|
|
|
/// Shared chrome for the landscape flight overlays (Capture modes, Camera
|
|
/// settings, Settings menu). Locks landscape/immersive like the HUD, paints the
|
|
/// dark app ground, and provides a title row + close button.
|
|
class FlightOverlayScaffold extends StatefulWidget {
|
|
const FlightOverlayScaffold({
|
|
super.key,
|
|
required this.title,
|
|
required this.body,
|
|
this.leading,
|
|
this.trailing,
|
|
this.padded = true,
|
|
});
|
|
|
|
final String title;
|
|
final Widget body;
|
|
final Widget? leading;
|
|
final Widget? trailing;
|
|
final bool padded;
|
|
|
|
@override
|
|
State<FlightOverlayScaffold> createState() => _FlightOverlayScaffoldState();
|
|
}
|
|
|
|
class _FlightOverlayScaffoldState extends State<FlightOverlayScaffold> {
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
SystemChrome.setPreferredOrientations(<DeviceOrientation>[
|
|
DeviceOrientation.landscapeLeft,
|
|
DeviceOrientation.landscapeRight,
|
|
]);
|
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: const Color(0xFF0A1120),
|
|
body: SafeArea(
|
|
child: Padding(
|
|
padding: widget.padded ? const EdgeInsets.fromLTRB(16, 12, 16, 12) : EdgeInsets.zero,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: <Widget>[
|
|
Padding(
|
|
padding: widget.padded ? EdgeInsets.zero : const EdgeInsets.fromLTRB(16, 12, 16, 8),
|
|
child: Row(children: <Widget>[
|
|
if (widget.leading != null) ...<Widget>[widget.leading!, const SizedBox(width: 10)],
|
|
Text(widget.title,
|
|
style: const TextStyle(fontFamily: PV.fontSans, fontSize: 16, fontWeight: FontWeight.w700, color: Glass.ink)),
|
|
const Spacer(),
|
|
if (widget.trailing != null) ...<Widget>[widget.trailing!, const SizedBox(width: 8)],
|
|
GestureDetector(
|
|
onTap: () => Navigator.of(context).maybePop(),
|
|
child: Container(
|
|
width: 30, height: 30,
|
|
decoration: BoxDecoration(color: const Color(0x1FFFFFFF), borderRadius: BorderRadius.circular(9)),
|
|
alignment: Alignment.center,
|
|
child: const PVIcon('close', size: 17, color: Glass.ink),
|
|
),
|
|
),
|
|
]),
|
|
),
|
|
const SizedBox(height: 10),
|
|
Expanded(child: widget.body),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|