Keep action rows when their key cannot be read
e3917e6 hid any row whose key failed its seeding read, which also hid
"Link remote controller": an action key has no value to read. Unreadable is
now tracked apart from supported, and only rows that show a value hide on it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
128220dcb7
commit
415c6184b1
3 files changed
+33
-8
No files matched your search
@@ -40,6 +40,9 @@ sealed class SettingSpec {
|
||||
/// The key the row reads, or null for app-side rows.
|
||||
DjiKey? get key => null;
|
||||
|
||||
/// Whether the row shows the key's value; an unreadable key hides it.
|
||||
bool get readsValue => true;
|
||||
|
||||
/// Every key the row needs listened to.
|
||||
Iterable<DjiKey> get watched => key == null ? const <DjiKey>[] : <DjiKey>[key!];
|
||||
|
||||
@@ -47,6 +50,7 @@ sealed class SettingSpec {
|
||||
if (requires != null && c.connected && !requires!.enabledFor(c.profile)) return false;
|
||||
final DjiKey? k = key;
|
||||
if (k != null && c.keys.supported(k) == false) return false;
|
||||
if (k != null && readsValue && c.keys.unreadable(k)) return false;
|
||||
return visibleWhen?.call(c) ?? true;
|
||||
}
|
||||
|
||||
@@ -264,6 +268,10 @@ class KeyActionSpec extends SettingSpec {
|
||||
super.groundOnly,
|
||||
}) : _key = key;
|
||||
|
||||
/// It performs the key's action; there is no value to read.
|
||||
@override
|
||||
bool get readsValue => false;
|
||||
|
||||
final DjiKey _key;
|
||||
final String button;
|
||||
final String? confirmTitle;
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'settings_overlay.dart';
|
||||
/// known to be unsupported, and stays visible (as "—") while still unknown.
|
||||
class KeyState extends ChangeNotifier with SettingsOverlay {
|
||||
final Map<String, bool> _supported = <String, bool>{};
|
||||
final Set<String> _unreadable = <String>{};
|
||||
|
||||
/// True / false once asked, null while unknown.
|
||||
bool? supported(DjiKey key) => _supported[key.id];
|
||||
@@ -25,30 +26,34 @@ class KeyState extends ChangeNotifier with SettingsOverlay {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// A key the aircraft calls supported but will not read: hidden like an
|
||||
/// unsupported one, until a value turns up after all.
|
||||
/// The aircraft calls the key supported but will not read it (the Mavic Pro
|
||||
/// remote's gimbal dial speed). Rows that show its value hide; action rows,
|
||||
/// which never read it, do not.
|
||||
bool unreadable(DjiKey key) => _unreadable.contains(key.id);
|
||||
|
||||
void markUnreadable(String id) {
|
||||
if (_supported[id] == false || reportedSettings.containsKey(id)) return;
|
||||
_supported[id] = false;
|
||||
if (reportedSettings.containsKey(id) || !_unreadable.add(id)) return;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// One `key` event: `{id, value}`.
|
||||
void apply(String id, Object? value) {
|
||||
if (_supported[id] == false) _supported.remove(id);
|
||||
_unreadable.remove(id);
|
||||
replaceReported(<String, dynamic>{...reportedSettings, id: value});
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// A new aircraft answers `isKeySupported` afresh.
|
||||
void forgetSupport() {
|
||||
if (_supported.isEmpty) return;
|
||||
if (_supported.isEmpty && _unreadable.isEmpty) return;
|
||||
_supported.clear();
|
||||
_unreadable.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_supported.clear();
|
||||
_unreadable.clear();
|
||||
clearSettings();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -151,12 +151,24 @@ void main() {
|
||||
final TelemetryReducer r = TelemetryReducer(m);
|
||||
m.keys.setSupported(SettingsKeys.gimbalDialSpeed, true);
|
||||
r.apply(<String, dynamic>{'type': 'key', 'id': SettingsKeys.gimbalDialSpeed.id, 'unreadable': true});
|
||||
expect(m.keys.supported(SettingsKeys.gimbalDialSpeed), isFalse);
|
||||
expect(m.keys.unreadable(SettingsKeys.gimbalDialSpeed), isTrue);
|
||||
final SettingsContext c = SettingsContext(profile: m.profile, keys: m.keys, aircraft: m.aircraft);
|
||||
final SettingSpec dial = spec<SettingSpec>(SettingsTabs.rc, 'gimbalDialSpeed');
|
||||
expect(dial.visible(c), isFalse);
|
||||
r.apply(<String, dynamic>{'type': 'key', 'id': SettingsKeys.gimbalDialSpeed.id, 'value': 40});
|
||||
expect(m.keys.supported(SettingsKeys.gimbalDialSpeed), isNot(isFalse));
|
||||
expect(dial.visible(c), isTrue);
|
||||
expect(m.keys.value(SettingsKeys.gimbalDialSpeed), 40);
|
||||
});
|
||||
|
||||
test('an action row stays when its key cannot be read (it never reads it)', () {
|
||||
final FlightModel m = connectedModel(phantom4);
|
||||
m.keys.setSupported(SettingsKeys.startPairing, true);
|
||||
TelemetryReducer(m).apply(<String, dynamic>{'type': 'key', 'id': SettingsKeys.startPairing.id, 'unreadable': true});
|
||||
final SettingsContext c = SettingsContext(profile: m.profile, keys: m.keys, aircraft: m.aircraft);
|
||||
final SettingSpec link = spec<SettingSpec>(SettingsTabs.rc, 'startPairing');
|
||||
expect(link.visible(c), isTrue);
|
||||
});
|
||||
|
||||
test('subscriptions listen only to supported keys and cancel on dispose', () async {
|
||||
final FakeDjiService dji = FakeDjiService()..unsupportedKeys.add('ESC_BEEPING_ENABLED');
|
||||
final KeyState s = KeyState();
|
||||
|
||||
Reference in new issue
Block a user