P7a of the GO 4-parity plan. The rail's GRID button becomes MODES, which opens a picker of the product's intelligent flight modes with first-use terms; Waypoints is the first one built. Waypoints opens on the big map: tap to add waypoints or POIs, long-press to drag, "+" to insert on a leg, and a point editor for altitude, speed, heading (route / custom / POI), gimbal (set or aim at POI), camera action and hover, and turn radius, with a swipe-to-adjust readout. Route settings, a local mission library and undo sit in a tool column. Start runs the SafetyGate's pre-start check in the slide-to-confirm dialog, then uploads and starts; a run panel shows upload and flight progress with Pause, Resume and Stop. MissionBridge now listens to the waypoint operator and builds the full V1 mission (per-waypoint headings, turn direction, gimbal pitch, actions). Not yet run on a simulator or aircraft. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
48 lines
2.1 KiB
Dart
48 lines
2.1 KiB
Dart
import 'dart:math' as math;
|
||
|
||
import 'package:flutter/material.dart';
|
||
|
||
import '../../../../fly/hud_geometry.dart';
|
||
import '../../../../fly/modes/waypoint_mission.dart';
|
||
import '../../../../fly/safety_gate.dart';
|
||
import '../../dialogs/slide_to_confirm.dart';
|
||
|
||
/// Starts a waypoint mission the GO 4 way (plan P7): the pre-start check —
|
||
/// the [SafetyGate]'s mission checks against the aircraft's limits, the RTH
|
||
/// altitude, the route summary — then slide to start. The gate re-checks,
|
||
/// uploads (the run panel shows the progress) and starts.
|
||
Future<void> startWaypointFlow(
|
||
BuildContext context, {
|
||
required SafetyGate gate,
|
||
required WaypointMissionSpec spec,
|
||
required void Function(String label, Object error) onError,
|
||
}) async {
|
||
final MissionLimits limits = await gate.missionLimits();
|
||
if (!context.mounted) return;
|
||
final List<GateCheck> checks = gate.checkWaypointStart(spec, limits);
|
||
final double top = spec.points.fold(0.0, (double h, WaypointSpec p) => math.max(h, p.altitude));
|
||
final int rth = (gate.model.aircraft.goHomeHeight ?? 60).round().clamp(SafetyGate.minRthHeight, SafetyGate.maxRthHeight);
|
||
final String length = spec.length >= 1000 ? '${(spec.length / 1000).toStringAsFixed(2)} km' : '${spec.length.round()} m';
|
||
|
||
final SlideResult? r = await showSlideToConfirm(
|
||
context,
|
||
SlideConfirmSpec(
|
||
icon: 'route',
|
||
title: 'Start "${spec.name}"',
|
||
description: '${spec.points.length} waypoints · $length · about ${formatDuration(spec.estimatedSeconds)}'
|
||
'${spec.repeatTimes > 1 ? ' · ${spec.repeatTimes}×' : ''}. '
|
||
'Highest waypoint ${top.round()} m. When finished: ${spec.finishAction.label.toLowerCase()}. '
|
||
'Pause or Stop at any time, or press the remote\'s pause button.',
|
||
sliderLabel: 'Slide to start',
|
||
checks: checks,
|
||
number: SlideNumber(label: 'RTH altitude', initial: rth, min: SafetyGate.minRthHeight, max: SafetyGate.maxRthHeight),
|
||
),
|
||
);
|
||
if (r == null) return;
|
||
try {
|
||
await gate.startWaypointMission(spec, limits: limits, rthHeight: r.number);
|
||
} catch (e) {
|
||
onError('Waypoint mission', e);
|
||
}
|
||
}
|