Files
dmc/app/lib/ui/widgets/drone_follow_icon.dart
T
Constantin Leue 0d3dba2482 Unify header pill/button height to 38px, matching the HTML prototype
Measured the prototype screenshot pixel-for-pixel: content pills take
up ~79% of the header's total height, matching its own CSS
(height:38px, topBarWrap padding:5px 10px -> 48px total). The Flutter
port had drifted to 34px for HeaderWindPill, MapSearchControls, and
NavIconButton, while FlightModePill was left at the original 38px -
so Fly mode looked inconsistent against itself, and both modes wasted
more header height as margin than the prototype does. Bringing all
four back to a shared 38px fixes both.
2026-08-07 22:06:23 +02:00

76 lines
2.5 KiB
Dart

import 'package:flutter/material.dart';
/// Statisches (nicht rotierendes) Papierflieger-Symbol fuer den
/// Kartenfolge-Knopf in der Kopfleiste (FlyMapControls) - dieselbe
/// Silhouette wie [DroneMarkerIcon] auf der Karte, hier aber einfarbig
/// statt zweifarbig: nur Umriss im inaktiven Zustand, komplett mit dem
/// Akzent-Pink gefuellt im aktiven Folgemodus.
class DroneFollowIcon extends StatelessWidget {
const DroneFollowIcon({super.key, this.size = 16, this.active = false});
final double size;
final bool active;
@override
Widget build(BuildContext context) {
// NavIconButton zwingt seinem Kind straffe 38x38-Constraints auf - ohne
// Center/SizedBox wuerde CustomPaint sein size-Argument ignorieren und
// auf die volle Knopfgroesse aufgeblasen (RenderCustomPaint hat anders
// als Icon kein eingebautes Center, das die Constraints fuer sein Kind
// lockert). Center() lockert die Constraints, die SizedBox erzwingt
// danach die tatsaechlich gewuenschte, kleinere Zeichenflaeche.
return Center(
child: SizedBox(
width: size,
height: size,
child: CustomPaint(painter: _DroneFollowPainter(active: active)),
),
);
}
}
class _DroneFollowPainter extends CustomPainter {
_DroneFollowPainter({required this.active});
final bool active;
// Gleiche Koordinaten wie DroneMarkerIcon._PaperPlanePainter (viewBox
// 0 0 200 200, aus design/B_paperplane.svg), hier als ein einzelner
// Umriss statt zweier separat gefuellter Haelften.
static const _viewBoxSize = 200.0;
static const _nose = Offset(100, 22);
static const _rightWing = Offset(164, 172);
static const _tailNotch = Offset(100, 138);
static const _leftWing = Offset(36, 172);
static const _pink = Color(0xFFFF2E93);
static const _strokeWidth = 16.0;
@override
void paint(Canvas canvas, Size size) {
final scale = size.width / _viewBoxSize;
Offset s(Offset p) => p * scale;
final outline = Path()
..moveTo(s(_nose).dx, s(_nose).dy)
..lineTo(s(_rightWing).dx, s(_rightWing).dy)
..lineTo(s(_tailNotch).dx, s(_tailNotch).dy)
..lineTo(s(_leftWing).dx, s(_leftWing).dy)
..close();
canvas.drawPath(
outline,
active
? (Paint()..color = _pink)
: (Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = _strokeWidth * scale
..strokeJoin = StrokeJoin.round),
);
}
@override
bool shouldRepaint(covariant _DroneFollowPainter oldDelegate) =>
oldDelegate.active != active;
}