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.
76 lines
2.5 KiB
Dart
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;
|
|
}
|