Give the Fly App a GO 4-style settings sheet
The "•••" button now opens a right-side glass sheet over the live view with Safety, Vision, Remote, Video link, Battery, Gimbal and General tabs. Each row is a one-line spec bound to a KeyManager key: rows hide when the aircraft does not support their key, writes show at once and roll back if refused, and ground-only settings lock in flight. KeyBridge gains argument-less action keys and converts range and LED settings values. settings_menu_page.dart is retired. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
60c2fd7f64
commit
284de5442a
19 files changed
+2132
-342
No files matched your search
@@ -2,8 +2,10 @@ package com.pilotvault.flyapp
|
||||
|
||||
import dji.common.camera.ResolutionAndFrameRate
|
||||
import dji.common.error.DJIError
|
||||
import dji.common.flightcontroller.LEDsSettings
|
||||
import dji.common.flightcontroller.LocationCoordinate3D
|
||||
import dji.common.model.LocationCoordinate2D
|
||||
import dji.common.util.DJIParamMinMaxCapability
|
||||
import dji.keysdk.AirLinkKey
|
||||
import dji.keysdk.BatteryKey
|
||||
import dji.keysdk.CameraKey
|
||||
@@ -13,6 +15,7 @@ import dji.keysdk.GimbalKey
|
||||
import dji.keysdk.KeyManager
|
||||
import dji.keysdk.ProductKey
|
||||
import dji.keysdk.RemoteControllerKey
|
||||
import dji.keysdk.callback.ActionCallback
|
||||
import dji.keysdk.callback.GetCallback
|
||||
import dji.keysdk.callback.KeyListener
|
||||
import dji.keysdk.callback.SetCallback
|
||||
@@ -21,8 +24,9 @@ import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
/**
|
||||
* Generic MSDK V4 `KeyManager` access (plan §1.3): one `getKey` / `setKey` /
|
||||
* `listenKey` / `cancelKey` / `isKeySupported` method set instead of a bespoke
|
||||
* method per simple value, so a settings row (P6) is one key name, not new Kotlin.
|
||||
* `listenKey` / `cancelKey` / `isKeySupported` / `performKeyAction` method set
|
||||
* instead of a bespoke method per simple value, so a settings row (P6) is one
|
||||
* key name, not new Kotlin.
|
||||
*
|
||||
* A key is addressed as `{component, key, index?, subIndex?}`:
|
||||
* - `component`: `FlightController`, `FlightAssistant`, `RTK`, `Camera`, `Gimbal`,
|
||||
@@ -44,7 +48,7 @@ class KeyBridge(private val ctx: BridgeCtx) : SubBridge {
|
||||
|
||||
override fun handle(call: MethodCall, result: MethodChannel.Result): Boolean {
|
||||
when (call.method) {
|
||||
"getKey", "setKey", "listenKey", "isKeySupported" -> Unit
|
||||
"getKey", "setKey", "listenKey", "isKeySupported", "performKeyAction" -> Unit
|
||||
"cancelKey" -> {
|
||||
val id = call.argument<String>("id")
|
||||
ctx.mainHandler.post {
|
||||
@@ -79,6 +83,17 @@ class KeyBridge(private val ctx: BridgeCtx) : SubBridge {
|
||||
}
|
||||
})
|
||||
"setKey" -> setKey(km, key, call.argument<Any>("value"), result)
|
||||
// Action keys (`START_PAIRING`, …) without arguments; ones that take SDK
|
||||
// objects keep a bespoke method.
|
||||
"performKeyAction" -> km.performAction(key, object : ActionCallback {
|
||||
override fun onSuccess() {
|
||||
ctx.mainHandler.post { result.success(null) }
|
||||
}
|
||||
|
||||
override fun onFailure(error: DJIError) {
|
||||
ctx.mainHandler.post { result.error("DJI_ERROR", error.description, null) }
|
||||
}
|
||||
})
|
||||
"listenKey" -> ctx.mainHandler.post {
|
||||
val id = idOf(call)
|
||||
if (!listeners.containsKey(id)) {
|
||||
@@ -226,12 +241,29 @@ object KeyValues {
|
||||
is ResolutionAndFrameRate -> mapOf("resolution" to v.resolution?.name, "frameRate" to v.frameRate?.name)
|
||||
is LocationCoordinate3D -> mapOf("latitude" to v.latitude, "longitude" to v.longitude, "altitude" to v.altitude.toDouble())
|
||||
is LocationCoordinate2D -> mapOf("latitude" to v.latitude, "longitude" to v.longitude)
|
||||
// `…_RANGE` keys (max flight height / radius, cinematic sensitivities).
|
||||
is DJIParamMinMaxCapability -> mapOf("supported" to v.isSupported(), "min" to v.min?.toDouble(), "max" to v.max?.toDouble())
|
||||
is LEDsSettings -> mapOf(
|
||||
"front" to v.areFrontLEDsOn(),
|
||||
"rear" to v.areRearLEDsOn(),
|
||||
"statusIndicator" to v.isStatusIndicatorOn(),
|
||||
"beacons" to v.areBeaconsOn(),
|
||||
)
|
||||
else -> v.toString()
|
||||
}
|
||||
|
||||
/** Converts a Dart value to the Java type of [sample], the key's current value. */
|
||||
fun coerce(raw: Any, sample: Any?): Any {
|
||||
if (sample == null) return raw
|
||||
if (sample is LEDsSettings && raw is Map<*, *>) {
|
||||
fun on(k: String, was: Boolean) = raw[k] as? Boolean ?: was
|
||||
return LEDsSettings.Builder()
|
||||
.frontLEDsOn(on("front", sample.areFrontLEDsOn()))
|
||||
.rearLEDsOn(on("rear", sample.areRearLEDsOn()))
|
||||
.statusIndicatorOn(on("statusIndicator", sample.isStatusIndicatorOn()))
|
||||
.beaconsOn(on("beacons", sample.areBeaconsOn()))
|
||||
.build()
|
||||
}
|
||||
if (sample is Enum<*>) {
|
||||
val cls = sample.javaClass.let { if (it.isEnum) it else it.superclass }
|
||||
return cls.enumConstants?.firstOrNull { (it as Enum<*>).name == raw.toString() } ?: raw
|
||||
|
||||
Reference in new issue
Block a user