Files
PilotVault/Fly App/lib/ui/pv_icons.dart
T
tajniak81andClaude Opus 4.8 a4a2709456 Rebuild Fly App to design v2 with full DJI SDK integration
Rebuild the Flutter/DJI-MSDK-V4 Fly App to the v2 UI kit and wire the
full SDK surface behind it.

Native (Kotlin): split DjiSdkBridge into a method/event router delegating
to per-subsystem SubBridge helpers sharing a BridgeCtx — FlightController
(takeoff/land/RTH + rich telemetry), Camera (mode/record/photo/exposure),
Gimbal, Mission (Waypoint + ActiveTrack; QuickShots via ActiveTrack
QUICK_SHOT), Media (MediaManager list/thumbnail/download), and optional
DJI account login. Manifest gains scoped media permissions.

Flutter: ten screens under lib/ui/ (Flight HUD, capture modes, camera
settings, settings menu, map+waypoints, home, album, academy, profile,
routes/flight logs), driven by an expanded FlightModel. New PVIcon renders
the kit's SVG paths via flutter_svg; map uses flutter_map + latlong2.

Pin transitive androidx.core/browser down to SDK-35-compatible versions
so the newer plugins don't force AGP 8.9.1 onto the DJI toolchain.

Verified with `flutter build apk --debug` (compiles Dart + all Kotlin);
runtime behaviour is untested here — it needs a physical DJI-connected
device.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:51:08 +02:00

132 lines
7.3 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/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
/// The v2 UI-kit line-icon library.
///
/// Ported verbatim from the `P = {…}` SVG-path map in
/// `Design/PilotVault Project logo/ui_kits/fly/index-v2.html`. Every icon is a
/// single `d` attribute drawn on a 24×24 grid with round caps/joins, matching
/// the kit's `<Icon>` component. Rendered through [PVIcon].
class PvPaths {
PvPaths._();
static const Map<String, String> d = <String, String>{
// nav / system
'chevronLeft': 'M15 6l-6 6 6 6',
'chevronRight': 'M9 6l6 6-6 6',
'chevronDown': 'M6 9l6 6 6-6',
'close': 'M6 6l12 12M18 6L6 18',
'more': 'M5 12h.01M12 12h.01M19 12h.01',
'home': 'M3 10.5 12 3l9 7.5M5 9.5V21h14V9.5',
'settings':
'M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z',
// flight status
'satellite':
'M13 7 9 3 5 7l4 4M17 11l4 4-4 4-4-4M8.5 8.5 3 14l7 7 5.5-5.5M16 16l1-1M18 3a3 3 0 0 1 3 3',
'battery': 'M3 8h14a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H3a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1zM22 11v2',
'radio':
'M4.9 19.1a10 10 0 0 1 0-14.2M7.8 16.2a6 6 0 0 1 0-8.4M16.2 7.8a6 6 0 0 1 0 8.4M19.1 4.9a10 10 0 0 1 0 14.2M12 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2z',
'rc': 'M7 8h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H7a3 3 0 0 1-3-3v-6a3 3 0 0 1 3-3zM8 4v4M16 4v4M9 14h2M8 13v2M15 13h.01M17 15h.01',
'obstacle': 'M12 3 2 20h20L12 3zM12 10v4M12 17h.01',
'compass': 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM15.5 8.5l-2 5-5 2 2-5 5-2z',
'gimbal': 'M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zM12 8v8M8 12h8',
'crosshair': 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM22 12h-4M6 12H2M12 6V2M12 22v-4',
'drone':
'M6 6l3.5 3.5M18 6l-3.5 3.5M6 18l3.5-3.5M18 18l-3.5-3.5M6 6a2.5 2.5 0 1 0-.01-.01M18 6a2.5 2.5 0 1 0-.01 0M6 18a2.5 2.5 0 1 0-.01 0M18 18a2.5 2.5 0 1 0-.01 0M9.5 9.5h5v5h-5z',
'takeoff': 'M12 20V8m0 0-4 4m4-4 4 4M4 4h16',
'rth': 'M12 3a9 9 0 1 0 9 9M12 3v6l4 2M20 4l-3 1 1-3',
'map': 'M9 4 3 6v14l6-2 6 2 6-2V4l-6 2-6-2zM9 4v14M15 6v14',
'pin': 'M12 21s7-6.4 7-12A7 7 0 0 0 5 9c0 5.6 7 12 7 12zM12 11a2 2 0 1 0 0-4 2 2 0 0 0 0 4z',
'route': 'M6 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 13V9a4 4 0 0 1 4-4h4',
// camera
'video': 'M23 7l-7 5 7 5V7zM3 5h11a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2z',
'image': 'M3 3h18v18H3zM8.5 10a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM21 15l-5-5L5 21',
'aperture':
'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM14.3 8 20 8M12.6 4.5 9.8 9.3M7 6 10 11.2M9.7 16 4 16M11.4 19.5l2.8-4.8M17 18l-3-5.2',
'iso': 'M4 7v10M8 7c-2 0-2 5 0 5s2 5 0 5M14 7a3 5 0 0 1 0 10 3 5 0 0 1 0-10M19 7v10',
'shutter': 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 12l6-3M12 12l-3 6M12 12l-3-6M12 12l6 3',
'ev': 'M4 6h10M4 12h7M4 18h10M17 9v6M20 12h-6',
'wb': 'M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10zM12 2v3M12 19v3M5 12H2M22 12h-3',
'timer': 'M12 22a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM12 10v4l2 2M9 2h6',
'burst': 'M7 8h10v10H7zM5 6h10M5 10v6',
'film': 'M3 3h18v18H3zM7 3v18M17 3v18M3 8h4M3 16h4M17 8h4M17 16h4',
'pano': 'M2 7l20-3v16L2 17V7zM2 7v10',
'grid': 'M3 3h18v18H3zM3 9h18M3 15h18M9 3v18M15 3v18',
'histogram': 'M4 20V10M9 20V4M14 20v-8M19 20v-6',
'focus':
'M3 8V5a2 2 0 0 1 2-2h3M16 3h3a2 2 0 0 1 2 2v3M21 16v3a2 2 0 0 1-2 2h-3M8 21H5a2 2 0 0 1-2-2v-3M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z',
'slowmo': 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM10 9v6l5-3z',
'hyperlapse': 'M12 8v4l3 2M4 12a8 8 0 1 1 3 6M4 20v-4h4',
'master': 'M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8L3.5 9.2l5.9-.9L12 3z',
'hdr': 'M4 8v8M4 12h4M8 8v8M12 8v8h2a3 3 0 0 0 0-6M12 12h2M18 8v8M18 12h2l1 4',
// quickshots
'dronie': 'M12 4a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM4 20l8-8 8 8',
'rocket': 'M12 3c4 2 5 7 5 10l-2 3H9l-2-3c0-3 1-8 5-10zM12 9v.01M8 17l-3 4M16 17l3 4',
'circle': 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z',
'helix': 'M6 3c12 3-12 15 0 18M6 6c9 2.2-9 11.6 0 13.5',
'boomerang': 'M4 20C4 10 10 4 20 4c0 10-6 16-16 16zM4 20l6-6',
'asteroid': 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM3 12h18M8 4c-2 2.5-2 13.5 0 16M16 4c2 2.5 2 13.5 0 16',
// home / library / misc
'academy': 'M22 10 12 5 2 10l10 5 10-5zM6 12v5c0 1 2.7 2.5 6 2.5s6-1.5 6-2.5v-5',
'album': 'M3 3h18v18H3zM8.5 10a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM21 15l-5-5L5 21',
'gauge': 'M12 15a3 3 0 1 0 0-6M3.5 18a9 9 0 1 1 17 0',
'user': 'M20 21a8 8 0 1 0-16 0M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z',
'sdcard': 'M18 2H8L4 6v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM10 6v2M13 6v2M16 6v2',
'link': 'M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1',
'play': 'M8 5v14l11-7z',
'pause': 'M8 5v14M16 5v14',
'sun': 'M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10zM12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4',
'bell': 'M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9M13.73 21a2 2 0 0 1-3.46 0',
'share': 'M4 12v8a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-8M16 6l-4-4-4 4M12 2v13',
'search': 'M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM21 21l-4.3-4.3',
'check': 'M20 6 9 17l-5-5',
'shield': 'M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6l8-3z',
'download': 'M12 3v12m0 0-4-4m4 4 4-4M4 21h16',
'play2': 'M8 5v14l11-7z',
};
}
/// A single v2 line icon. Strokes one of [PvPaths.d] on a 24×24 grid, round
/// caps/joins, matching the design's `<Icon>` component.
class PVIcon extends StatelessWidget {
const PVIcon(
this.name, {
super.key,
this.size = 20,
this.color = Colors.white,
this.stroke = 2,
this.fill = false,
});
final String name;
final double size;
final Color color;
final double stroke;
/// When true (e.g. play triangles), the path is filled with [color] and drawn
/// with no stroke — matches the kit's `fill="#fff" stroke="#fff"` usage.
final bool fill;
@override
Widget build(BuildContext context) {
final String d = PvPaths.d[name] ?? '';
final String hex = _hex(color);
final String fillAttr = fill ? hex : 'none';
final String strokeAttr = fill ? 'none' : hex;
final String svg =
'<svg xmlns="http://www.w3.org/2000/svg" width="$size" height="$size" '
'viewBox="0 0 24 24" fill="$fillAttr" stroke="$strokeAttr" '
'stroke-width="$stroke" stroke-linecap="round" stroke-linejoin="round">'
'<path d="$d"/></svg>';
return SvgPicture.string(svg, width: size, height: size);
}
static String _hex(Color c) {
final int r = (c.r * 255).round();
final int g = (c.g * 255).round();
final int b = (c.b * 255).round();
String two(int v) => v.toRadixString(16).padLeft(2, '0');
return '#${two(r)}${two(g)}${two(b)}';
}
}