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(