Files
PilotVault/Fly App/lib/fly/academy_content.dart
T
tajniak81andClaude Opus 5.5 91ca150a35 Give the Fly App GO 4-style playback, flight records, Find My Drone and live streaming
Playback: the flight screen's playback button opens the album over the
live view, so a video tapped there plays on the aircraft into the feed
with a transport bar. Long press selects files to download or delete
(delete asks first); one file opens in a viewer with the camera's
preview. Leaving the album puts the camera back in its capture mode.

Flight records: every flight is recorded from take-off to landing (1 Hz
track, max height / distance / speed, distance flown, battery used) and
kept on the phone. When it lands while signed in, it is uploaded to the
PilotVault logbook through the existing /api/drones/auto and
/api/flights endpoints as an automatic-path entry with the track as
GeoJSON. Simulator flights are never uploaded; flights recorded while
signed out retry on sign-in. Flight logs lists them with their upload
state and a track map, and the profile stats come from real flights.

Find My Drone: the aircraft's last fix is kept across lost links and
restarts, and shown against the phone's own GPS with distance, direction
and a hand-off to the maps app.

Live streaming: a new LiveStreamBridge streams the main camera to an
RTMP address set in Settings > General, with a LIVE pill on the flight
screen that turns amber when the uplink falls behind and stops on tap.

Pre-flight checklist (manual checks plus the aircraft's live status)
and an in-app Academy with six short guides that work offline.

None of this has run on hardware yet.

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

172 lines
8.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/foundation.dart';
/// One section of an [AcademyArticle]: a heading, then paragraphs; a paragraph
/// starting with `• ` renders as a bullet.
@immutable
class AcademySection {
const AcademySection(this.heading, this.paragraphs);
final String heading;
final List<String> paragraphs;
}
/// In-app Academy reading (plan P9): short guides written for this app, so
/// they work in the field without a connection.
@immutable
class AcademyArticle {
const AcademyArticle({
required this.id,
required this.icon,
required this.title,
required this.subtitle,
required this.sections,
});
final String id;
final String icon;
final String title;
final String subtitle;
final List<AcademySection> sections;
/// About 200 words a minute.
int get minutes {
final int words = sections.fold(0, (int n, AcademySection s) => n + s.paragraphs.fold(0, (int m, String p) => m + p.split(' ').length));
return (words / 200).ceil().clamp(1, 60);
}
}
const List<AcademyArticle> academyArticles = <AcademyArticle>[
AcademyArticle(
id: 'firstFlight',
icon: 'takeoff',
title: 'Your first flight',
subtitle: 'From the case to a safe landing',
sections: <AcademySection>[
AcademySection('Before you go', <String>[
'Charge the aircraft batteries, the remote controller and this phone the evening before. Check the fly zones and the weather for where you are going.',
'Sign in to PilotVault, so the flight lands in your logbook by itself.',
]),
AcademySection('On site', <String>[
'• Work through the pre-flight checklist in the Academy.',
'• Connect the aircraft from the home screen and tap GO FLY.',
'• Open the status chip at the top: every row should be green before take-off. The app also offers it before the first take-off of each connection.',
'• Wait for a strong GPS signal, so the home point is recorded where you stand.',
]),
AcademySection('Take-off and hover', <String>[
'Take off from the left rail and slide to confirm. The aircraft climbs to about 1.2 m and hovers. Stay there for a moment: if it drifts, land and check the compass and IMU.',
'Fly gently at first. Keep the aircraft in sight, in front of you, and away from people, roads and trees.',
]),
AcademySection('Landing', <String>[
'Bring the aircraft back over a clear spot, descend slowly, and hold the left stick down after touchdown until the motors stop, or use Land on the rail.',
'Back on the ground, the flight is saved under Flight logs.',
]),
],
),
AcademyArticle(
id: 'rth',
icon: 'rth',
title: 'Return to home',
subtitle: 'What the aircraft does when you let go',
sections: <AcademySection>[
AcademySection('The home point', <String>[
'The aircraft records its home point at take-off once it has a good GPS fix. The H on the map shows it. You can move it to your own position in Settings → Safety, for example when you walk with the aircraft.',
]),
AcademySection('When it flies home', <String>[
'• You tap RTH on the rail and slide to confirm.',
'• The battery is only just enough to get back (smart RTH counts down and lets you cancel).',
'• The signal from the remote controller is lost (failsafe).',
]),
AcademySection('Return-to-home height', <String>[
'Further than about 20 m away, the aircraft first climbs to the return-to-home height, then flies straight home. Set that height above the tallest obstacle on the way, in Settings → Safety.',
'Aircraft without obstacle sensing fly straight into anything below that height. Aircraft with sensing still cannot see thin branches or wires.',
]),
AcademySection('Taking back control', <String>[
'Cancel from the rail, or with the remote\'s pause button. On most aircraft, moving the sticks during the descent only adjusts the landing.',
]),
],
),
AcademyArticle(
id: 'modes',
icon: 'crosshair',
title: 'Intelligent flight modes',
subtitle: 'Waypoints, ActiveTrack, TapFly, on-screen sticks',
sections: <AcademySection>[
AcademySection('Before any mode', <String>[
'Every mode starts through the same safety checks as take-off: a connected aircraft, enough battery, a GPS fix, and no other mode running. If one fails, the app says why instead of starting.',
'A mode flies the aircraft for you; it does not watch out for you. Keep it in sight and your thumbs on the sticks.',
]),
AcademySection('Waypoints', <String>[
'Tap MODES → Waypoints. The map opens big: tap to drop points, then set height, speed, heading and camera actions per point. Saved routes sync to PilotVault when you are signed in.',
]),
AcademySection('ActiveTrack and TapFly', <String>[
'ActiveTrack follows a subject you draw a box around on the video. TapFly flies towards the point you tap. Both stop with the Stop button, the remote\'s pause button, or a firm stick input.',
]),
AcademySection('On-screen sticks', <String>[
'For aircraft flown without a remote, or for practice in the simulator. They are off in real flight on aircraft with a remote unless you enable them under Developer settings.',
]),
],
),
AcademyArticle(
id: 'batteries',
icon: 'battery',
title: 'Batteries and weather',
subtitle: 'Cold, wind and how long you really have',
sections: <AcademySection>[
AcademySection('Battery care', <String>[
'• Plan to land with 25–30 % left; the bar at the top shows where RTH and landing will start.',
'• Below about 15 °C, keep batteries warm before flight and hover for a minute after take-off.',
'• Store batteries at about half charge, and never charge one that is swollen or damaged.',
]),
AcademySection('Wind', <String>[
'Wind is stronger at height than on the ground. If the aircraft warns about strong wind, come lower and closer: flying home against the wind takes much more battery than flying out with it.',
]),
AcademySection('Rain, fog and cold', <String>[
'Most consumer aircraft are not water resistant. Fog and low cloud also hide the aircraft from you and from other airspace users.',
]),
],
),
AcademyArticle(
id: 'rules',
icon: 'shield',
title: 'Flying legally in the EU',
subtitle: 'Open category basics and your logbook',
sections: <AcademySection>[
AcademySection('The open category, in short', <String>[
'• Stay below 120 m above the ground and keep the aircraft in visual line of sight.',
'• Register as an operator with your national aviation authority and put your operator ID on the aircraft.',
'• Pass the online A1/A3 training for aircraft from 250 g and those with a C1 class label; A2 adds rules for flying closer to people.',
'• Never fly over gatherings of people, and respect airports and restricted zones.',
]),
AcademySection('Fly zones', <String>[
'The map shows DJI\'s GEO zones and the aircraft enforces them. National zones can differ: also check your authority\'s official drone map before a flight.',
]),
AcademySection('Your logbook', <String>[
'Some countries require a flight log (in Denmark, BEK 1649 § 5). PilotVault records each flight from this app and fills in the date, times, aircraft, area and maximum height for you. Check each entry in the PilotVault logbook.',
]),
AcademySection('Rules change', <String>[
'This is a summary, not legal advice. Your national authority\'s website has the current rules.',
]),
],
),
AcademyArticle(
id: 'emergencies',
icon: 'alert',
title: 'When things go wrong',
subtitle: 'Lost signal, compass errors, a missing aircraft',
sections: <AcademySection>[
AcademySection('Lost video or signal', <String>[
'Point the remote\'s antennas towards the aircraft and do not move the sticks hastily. If the signal is lost completely, the aircraft returns home on its own (unless set to hover or land): walk to open ground near the home point.',
]),
AcademySection('Compass or IMU error', <String>[
'In flight, the aircraft may drop to ATTI mode and drift with the wind. Fly it back manually, slowly, and land. On the ground, calibrate from Settings → Safety → Calibration & maintenance, away from metal.',
]),
AcademySection('Low battery far away', <String>[
'Start RTH early; if it cannot make it, land in the safest reachable spot and fetch it.',
]),
AcademySection('Find my drone', <String>[
'The app keeps the aircraft\'s last known position, even after the link is lost or the app restarts. Open Flight logs → Find my drone for the distance and direction from where you stand.',
]),
],
),
];