import '../product_profile.dart'; /// The Intelligent Flight Modes picker's catalogue (plan P7, GO 4's /// `DJILeftMenuNavigationView` + `gs_main_view`). /// /// Which modes a product has comes from [ProductProfile.modes] (the product /// matrix until runtime capture confirms it); which of those this app can fly /// yet is [ModeInfo.built]. A mode that is supported but not built is listed /// greyed out rather than hidden, so the pilot sees what is coming. class ModeInfo { const ModeInfo({ required this.mode, required this.label, required this.icon, required this.group, required this.blurb, required this.terms, this.built = false, }); final IntelligentMode mode; final String label; /// A `PVIcon` name. final String icon; /// `Map`, `Vision`, `Shots` or `Orientation`, as the picker groups them. final String group; /// One line under the tile. final String blurb; /// The first-use disclaimer: what the pilot stays responsible for. final List terms; /// This app can fly the mode. final bool built; } abstract final class ModeCatalog { static const List _common = [ 'You remain responsible for the flight. Keep the aircraft in sight and be ready to take over with the remote.', 'The aircraft flies itself in this mode. Push the remote\'s pause button, or tap Stop, to make it hover.', ]; static const List all = [ ModeInfo( mode: IntelligentMode.waypoint, label: 'Waypoints', icon: 'route', group: 'Map', blurb: 'Plan a route on the map and fly it.', built: true, terms: [ ..._common, 'The route flies straight between waypoints at the altitudes you set. It does not avoid terrain, trees or buildings: check the route and its altitudes before you start.', 'If the remote loses signal the aircraft follows the route\'s signal-lost setting.', ], ), ModeInfo( mode: IntelligentMode.waypointV2, label: 'Waypoints 2.0', icon: 'route', group: 'Map', blurb: 'Enterprise waypoint missions.', terms: _common, ), ModeInfo( mode: IntelligentMode.pointOfInterest, label: 'Point of Interest', icon: 'circle', group: 'Map', blurb: 'Circle a subject at a set radius.', terms: _common, ), ModeInfo( mode: IntelligentMode.followMe, label: 'Follow Me', icon: 'user', group: 'Map', blurb: 'The aircraft follows this phone.', terms: _common, ), ModeInfo( mode: IntelligentMode.activeTrack, label: 'ActiveTrack', icon: 'crosshair', group: 'Vision', blurb: 'Draw a box around a subject to follow it.', built: true, terms: [ ..._common, 'ActiveTrack follows what the camera sees. It can lose the subject behind trees or in crowds, and it does not see obstacles to the sides or behind on every aircraft.', 'Do not use it to follow cars or boats at speed, or over water and roads you cannot see the end of.', ], ), ModeInfo( mode: IntelligentMode.tapFly, label: 'TapFly', icon: 'chevronsRight', group: 'Vision', blurb: 'Tap the video to fly that way.', built: true, terms: [ ..._common, 'TapFly keeps flying towards the point until you stop it. Obstacle avoidance only works in the direction the sensors face, and not at all in Free.', ], ), ModeInfo( mode: IntelligentMode.quickShots, label: 'QuickShots', icon: 'dronie', group: 'Shots', blurb: 'Dronie, Rocket, Circle, Helix…', terms: _common, ), ModeInfo( mode: IntelligentMode.hyperlapse, label: 'Hyperlapse', icon: 'hyperlapse', group: 'Shots', blurb: 'A moving timelapse.', terms: _common, ), ModeInfo( mode: IntelligentMode.courseLock, label: 'Course Lock', icon: 'compass', group: 'Orientation', blurb: 'Forward stays the current heading.', terms: _common, ), ModeInfo( mode: IntelligentMode.homeLock, label: 'Home Lock', icon: 'home', group: 'Orientation', blurb: 'Pulling back always flies home.', terms: _common, ), ModeInfo( mode: IntelligentMode.tripod, label: 'Tripod', icon: 'gauge', group: 'Orientation', blurb: 'Slow, precise control for framing.', terms: _common, ), ]; static const List groups = ['Map', 'Vision', 'Shots', 'Orientation']; static ModeInfo of(IntelligentMode m) => all.firstWhere((ModeInfo i) => i.mode == m); /// The modes to list for [p]: every mode when no product is connected (a /// preview, like the rest of the HUD), else the product's own. static List forProfile(ProductProfile p) => [for (final ModeInfo i in all) if (!p.connected || p.supportsMode(i.mode)) i]; }