import 'package:flutter/services.dart'; /// Thin Dart wrapper over the native DJI Mobile SDK bridge. /// /// Mirrors the channels defined in `DjiSdkBridge.kt` (+ its per-subsystem /// helpers): /// * method channel `dji_msdk/methods` for imperative calls /// * event channel `dji_msdk/events` for the SDK's async updates /// /// Every method returns cleanly whether or not a product is connected; the /// native side answers with a typed error the UI can surface. The event stream /// carries maps keyed by `type`: `registration`, `connection`, `identity`, /// `telemetry`, `battery`, `camera`, `exposure`, `gimbal`, `mission`, /// `mediaList`, `mediaDownload`, `djiAccount`, `database`, `init`. class DjiService { static const MethodChannel _methods = MethodChannel('dji_msdk/methods'); static const EventChannel _events = EventChannel('dji_msdk/events'); Stream> events() { return _events .receiveBroadcastStream() .map((dynamic e) => Map.from(e as Map)); } // ── SDK / registration / connection ───────────────────────────────────────── Future getSdkVersion() async => await _methods.invokeMethod('getSdkVersion') ?? 'unknown'; Future registerApp() => _methods.invokeMethod('registerApp'); Future startConnection() async => await _methods.invokeMethod('startConnection') ?? false; Future stopConnection() => _methods.invokeMethod('stopConnection'); Future> getProductInfo() async { final dynamic info = await _methods.invokeMethod('getProductInfo'); return Map.from(info as Map); } // ── Flight controller commands ────────────────────────────────────────────── Future takeOff() => _methods.invokeMethod('takeOff'); Future land() => _methods.invokeMethod('land'); Future confirmLanding() => _methods.invokeMethod('confirmLanding'); Future cancelLanding() => _methods.invokeMethod('cancelLanding'); Future startGoHome() => _methods.invokeMethod('startGoHome'); Future cancelGoHome() => _methods.invokeMethod('cancelGoHome'); Future setHomeToCurrent() => _methods.invokeMethod('setHomeToCurrent'); // ── Flight settings (Safety / Control) ────────────────────────────────────── Future setMaxFlightHeight(int m) => _methods.invokeMethod('setMaxFlightHeight', {'value': m}); Future setMaxFlightRadius(int m) => _methods.invokeMethod('setMaxFlightRadius', {'value': m}); Future setMaxRadiusEnabled(bool on) => _methods.invokeMethod('setMaxRadiusEnabled', {'value': on}); Future setGoHomeHeight(int m) => _methods.invokeMethod('setGoHomeHeight', {'value': m}); Future setNoviceMode(bool on) => _methods.invokeMethod('setNoviceMode', {'value': on}); Future setObstacleAvoidance(bool on) => _methods.invokeMethod('setObstacleAvoidance', {'value': on}); // ── Camera ────────────────────────────────────────────────────────────────── /// mode: `photo` | `video` | `mediaDownload` | `playback` Future setCameraMode(String mode) => _methods.invokeMethod('setCameraMode', {'mode': mode}); Future startShootPhoto() => _methods.invokeMethod('startShootPhoto'); Future stopShootPhoto() => _methods.invokeMethod('stopShootPhoto'); Future startRecordVideo() => _methods.invokeMethod('startRecordVideo'); Future stopRecordVideo() => _methods.invokeMethod('stopRecordVideo'); /// mode: SINGLE | HDR | BURST | AEB | INTERVAL | PANORAMA Future setShootPhotoMode(String mode) => _methods.invokeMethod('setShootPhotoMode', {'mode': mode}); /// program: `auto` (PROGRAM) | `pro` (MANUAL) Future setExposureProgram(String program) => _methods.invokeMethod('setExposureProgram', {'program': program}); Future setISO(String value) => _methods.invokeMethod('setISO', {'value': value}); Future setShutterSpeed(String value) => _methods.invokeMethod('setShutterSpeed', {'value': value}); Future setAperture(String value) => _methods.invokeMethod('setAperture', {'value': value}); Future setEV(String value) => _methods.invokeMethod('setEV', {'value': value}); Future setWhiteBalance(String value) => _methods.invokeMethod('setWhiteBalance', {'value': value}); Future setHistogramEnabled(bool on) => _methods.invokeMethod('setHistogramEnabled', {'value': on}); // ── Gimbal ────────────────────────────────────────────────────────────────── Future rotateGimbalPitch(double deg) => _methods.invokeMethod('rotateGimbalPitch', {'pitch': deg}); Future resetGimbal() => _methods.invokeMethod('resetGimbal'); // ── Missions ──────────────────────────────────────────────────────────────── /// points: [{lat, lon, altitude}], finishAction: NO_ACTION|GO_HOME|AUTO_LAND|GO_FIRST_WAYPOINT Future uploadWaypointMission( List> points, { double speed = 8, String finishAction = 'NO_ACTION', }) => _methods.invokeMethod('uploadWaypointMission', { 'points': points, 'speed': speed, 'finishAction': finishAction, }); Future startWaypointMission() => _methods.invokeMethod('startWaypointMission'); Future stopWaypointMission() => _methods.invokeMethod('stopWaypointMission'); Future pauseWaypointMission() => _methods.invokeMethod('pauseWaypointMission'); Future resumeWaypointMission() => _methods.invokeMethod('resumeWaypointMission'); /// Rect is normalized 0..1 in the live view. mode: TRACE|PROFILE|SPOTLIGHT|QUICK_SHOT Future startActiveTrack( double x, double y, double w, double h, { String mode = 'TRACE', }) => _methods.invokeMethod('startActiveTrack', { 'x': x, 'y': y, 'w': w, 'h': h, 'mode': mode, }); Future stopActiveTrack() => _methods.invokeMethod('stopActiveTrack'); /// A DJI-Fly QuickShot by name (Dronie/Rocket/Circle/Helix/Boomerang/Asteroid). /// The native side maps each to the closest real operator or returns a typed /// "unsupported on this aircraft" error. Future startQuickShot(String name) => _methods.invokeMethod('startQuickShot', {'name': name}); // ── Media (MediaManager) ──────────────────────────────────────────────────── Future refreshMediaList() => _methods.invokeMethod('refreshMediaList'); Future fetchThumbnail(int index) => _methods.invokeMethod('fetchThumbnail', {'index': index}); Future downloadMedia(int index) => _methods.invokeMethod('downloadMedia', {'index': index}); Future deleteMedia(int index) => _methods.invokeMethod('deleteMedia', {'index': index}); // ── DJI account (optional) ────────────────────────────────────────────────── Future djiLogin() => _methods.invokeMethod('djiLogin'); Future djiLogout() => _methods.invokeMethod('djiLogout'); Future refreshDjiAccountState() => _methods.invokeMethod('getDjiAccountState'); }