From 5505bb374125c669ca5bcdd621abb0c3a85a99b5 Mon Sep 17 00:00:00 2001 From: Constantin Leue <77660791+Consti3D@users.noreply.github.com> Date: Tue, 28 Jul 2026 15:53:42 +0200 Subject: [PATCH] Fix wind marker slack and off-center header bar Zwei vom Nutzer per Screenshot gemeldete Probleme: 1. Der Wind-Marker auf der Karte liess bei kurzen Werten (z.B. "1 m/s") weiterhin sichtbaren Leerraum rechts neben dem Text - die letzte Anpassung hatte die Marker-Box auf den unguenstigsten Fall (zweistellig, "25 m/s") fixiert bemessen, wodurch einstellige Werte in derselben Box zu viel Platz hatten. flutter_map's Marker verlangt eine feste Breite (kein intrinsisches Sizing), also wird sie jetzt pro Wegpunkt aus der Ziffernzahl der Geschwindigkeit berechnet (+11px/Ziffer, per Widget-Messung ermittelt) statt eine einzelne Konstante fuer alle Faelle zu verwenden. 2. Die Kopfleiste sass nicht mittig, sondern wirkte nach rechts verschoben. Ursache: SafeArea wendet links/rechts die jeweils tatsaechlichen (auf diesem Emulator unterschiedlich grossen) Insets an - dadurch war der fuer FractionallySizedBox verfuegbare Bereich selbst schon asymmetrisch zur Bildschirmmitte verschoben. Ersetzt durch denselben symmetrischen Randabstand (max(links, rechts)), der in PlanScreen fuer die Drehraeder bereits etabliert ist. Verifiziert: flutter analyze (0 issues), flutter test (64/64), manuell auf Pixel_10a-Emulator - Kopfleiste jetzt sichtbar mittig, mehrere Wind-Marker mit "1 m/s" zeigen keinen Leerraum mehr. Co-Authored-By: Claude Sonnet 5 --- app/lib/ui/screens/plan/plan_screen.dart | 17 ++++++++++++++++- app/lib/ui/widgets/top_mode_bar.dart | 23 +++++++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/lib/ui/screens/plan/plan_screen.dart b/app/lib/ui/screens/plan/plan_screen.dart index b071a3b..fdbda1d 100644 --- a/app/lib/ui/screens/plan/plan_screen.dart +++ b/app/lib/ui/screens/plan/plan_screen.dart @@ -407,7 +407,7 @@ class _PlanScreenState extends ConsumerState { if (wp.windSpeedMs != null && wp.windDirFromDeg != null) Marker( point: LatLng(wp.lat, wp.lon), - width: 102, + width: _windMarkerWidth(wp.windSpeedMs!), height: 22, alignment: const Alignment(1.1, -1.5), child: WindMarkerPill( @@ -558,4 +558,19 @@ class _PlanScreenState extends ConsumerState { borderColor: Colors.white, ); } + + /// flutter_map's Marker verlangt eine feste Breite (kein intrinsisches + /// Sizing wie bei normalen Widgets) - eine einzelne fuer alle Faelle + /// grosszuegig bemessene Breite liesse bei kurzen Werten (z.B. "1 m/s") + /// sichtbaren Leerraum rechts neben dem Text. Stattdessen je Ziffernzahl + /// berechnet (per Widget-Messung ermittelt: +11px/Ziffer, siehe + /// WindMarkerPill). + double _windMarkerWidth(double speedMs) { + final digits = speedMs.round().abs().toString().length; + // +1px Puffer: MarkerLayer rendert ueber eine eigene Transform-/ + // OverflowBox-Kette, die im echten Baum minimal (< 1px) anders rundet + // als eine isolierte Messung - ohne Puffer fuehrte das zu einem + // 0.25px-Overflow. + return 81.0 + digits * 11.0; + } } diff --git a/app/lib/ui/widgets/top_mode_bar.dart b/app/lib/ui/widgets/top_mode_bar.dart index 2d19d5e..e449b0d 100644 --- a/app/lib/ui/widgets/top_mode_bar.dart +++ b/app/lib/ui/widgets/top_mode_bar.dart @@ -1,3 +1,5 @@ +import 'dart:math' as math; + import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -24,8 +26,25 @@ class TopModeBar extends StatelessWidget { final isFly = context.select((AppModeCubit c) => c.state.mode == AppMode.fly); final activeTint = isFly ? DmcColors.flyModeRed : DmcColors.editModeGreen; - return SafeArea( - bottom: false, + // Kein SafeArea: das wendet links/rechts die jeweils tatsaechlichen + // (oft asymmetrischen) Insets an, wodurch die Leiste sichtbar von der + // Bildschirmmitte abweicht, sobald eine Seite einen groesseren + // Aussparungsbereich meldet als die andere. Stattdessen derselbe + // symmetrische Randabstand wie bei den Drehraedern (PlanScreen: + // safeEdgeInset) - dadurch bleibt die per FractionallySizedBox + // zentrierte Leiste auch bei asymmetrischen Insets echt mittig. + final topInset = MediaQuery.of(context).padding.top; + final safeEdgeInset = math.max( + MediaQuery.of(context).padding.left, + MediaQuery.of(context).padding.right, + ); + + return Padding( + padding: EdgeInsets.only( + top: topInset, + left: safeEdgeInset, + right: safeEdgeInset, + ), child: FractionallySizedBox( widthFactor: 0.70, child: Container(