Files
PilotVault/Fly App/lib/fly/state/settings_overlay.dart
T
tajniak81andClaude Opus 5.5 60c2fd7f64 Give the Fly App GO 4-style gimbal controls
Plan P5: a value bubble on the pitch slider while dragging, press-and-drag
on the video as a speed joystick (re-sent at 10 Hz, zero on release), and a
gimbal settings sheet: mode, 30° extension, yaw follow, recenter / face down /
yaw recenter, roll fine-tune, auto calibration and advanced speed/smoothness
rows gated by the gimbal's capability ranges.

GimbalBridge reports mode, trim, calibration and stop/overload state in the
gimbal telemetry group, and getter-only settings in a new gimbalSettings slow
group. The reported-plus-pending overlay moves out of CameraState into a
SettingsOverlay mixin shared by camera and gimbal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:22:42 +02:00

54 lines
1.8 KiB
Dart

import 'package:flutter/foundation.dart';
import 'parse.dart';
/// Settings as a component reported them, overlaid with the HUD's optimistic
/// writes (plan P4, reused by the gimbal in P5).
///
/// A pending value stands until the component reports that setting changed,
/// the write fails, or the writer gives up waiting ([dropPending]) — so a
/// value the component silently refused snaps back.
mixin SettingsOverlay on ChangeNotifier {
Map<String, dynamic> _reported = const <String, dynamic>{};
final Map<String, Object?> _pending = <String, Object?>{};
/// What the component reported, overlaid with pending writes.
Map<String, dynamic> get settings => _pending.isEmpty ? _reported : <String, dynamic>{..._reported, ..._pending};
/// Only what the component itself reported.
Map<String, dynamic> get reportedSettings => _reported;
bool isPending(String id) => _pending.containsKey(id);
Object? setting(String id) => settings[id];
/// Shows [values] ahead of the component's read-back.
void setPending(Map<String, Object?> values) {
_pending.addAll(values);
notifyListeners();
}
/// Rolls [ids] back to what the component last reported.
void dropPending(Iterable<String> ids) {
bool changed = false;
for (final String id in ids) {
changed = _pending.remove(id) != null || changed;
}
if (changed) notifyListeners();
}
/// Takes a new report; a pending write is answered once its setting moves.
/// Does not notify — the caller does, with its other fields.
@protected
void replaceReported(Map<String, dynamic> reported) {
_pending.removeWhere((String id, _) => !deepEquals(_reported[id], reported[id]));
_reported = reported;
}
@protected
void clearSettings() {
_reported = const <String, dynamic>{};
_pending.clear();
}
}