UI adjustments
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
@@ -7,9 +9,11 @@ import '../providers/mission_meta_provider.dart';
|
||||
import 'missions_drones_panel.dart';
|
||||
|
||||
/// Statuszeile am unteren Bildschirmrand (HTML-Demonstrator: #bottomBar/
|
||||
/// #statsRow). Details-Pille (mittig) oeffnet die Wegpunktliste; die
|
||||
/// Mission-/Drohnen-Chips (links) oeffnen das Verwaltungsmenue mit dem
|
||||
/// passenden Starttab (HTML-Demonstrator: #missionNameBtn/#droneNameBtn).
|
||||
/// #statsRow). Details-Pille bleibt mittig und oeffnet die Wegpunktliste;
|
||||
/// Mission-Chip links und Drohnen-Chip rechts oeffnen das Verwaltungsmenue
|
||||
/// mit dem passenden Starttab (HTML-Demonstrator: #missionNameBtn/
|
||||
/// #droneNameBtn). Warnungs- und Settings-Knopf sitzen neben dem
|
||||
/// Drohnen-Chip rechts aussen.
|
||||
/// Der Send-Button ist bewusst nicht Teil dieses Schritts - die dafuer
|
||||
/// noetige Upload-Anbindung existiert noch nicht.
|
||||
class BottomStatsBar extends ConsumerWidget {
|
||||
@@ -44,6 +48,18 @@ class BottomStatsBar extends ConsumerWidget {
|
||||
final missionName = ref.watch(currentMissionMetaProvider).name;
|
||||
final droneName = ref.watch(activeDroneProfileProvider).name;
|
||||
|
||||
// Gespiegelter Randabstand (wie in PlanScreen fuer die Drehraeder, Doku:
|
||||
// "Symmetrischer Randabstand auf beiden Seiten"): die groessere der
|
||||
// beiden echten Seiten-Insets wird auf BEIDE Seiten angewendet, statt
|
||||
// SafeAreas Standardverhalten (jede Seite nur ihren eigenen, ggf. 0)
|
||||
// zu uebernehmen - sonst waere z.B. eine Frontkamera-Aussparung im
|
||||
// Querformat nur auf einer Seite der Fusszeile sichtbar beruecksichtigt,
|
||||
// je nachdem wie herum das Geraet gehalten wird.
|
||||
final safeEdgeInset = math.max(
|
||||
MediaQuery.of(context).padding.left,
|
||||
MediaQuery.of(context).padding.right,
|
||||
);
|
||||
|
||||
// Row statt Stack: ein Align/Center ohne width-/heightFactor nimmt sich
|
||||
// immer den gesamten verfuegbaren Platz seines Elternwidgets (auch wenn
|
||||
// sein Kind viel kleiner ist) - in einem Stack ohne begrenzende
|
||||
@@ -53,49 +69,57 @@ class BottomStatsBar extends ConsumerWidget {
|
||||
// dagegen zuverlaessig zentriert.
|
||||
return SafeArea(
|
||||
top: false,
|
||||
left: false,
|
||||
right: false,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12),
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
12 + safeEdgeInset,
|
||||
10,
|
||||
12 + safeEdgeInset,
|
||||
10,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// Nur noch die Mission-Pille links - sie darf die gesamte
|
||||
// verfuegbare Breite dieser Seite nutzen (Align loosent die
|
||||
// Constraints statt sie wie Expanded zu erzwingen, das
|
||||
// begrenzt auf die verfuegbare Breite, ohne einen kuenstlich
|
||||
// kleinen Fixwert vorzugeben).
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: _NameChip(
|
||||
label: 'Mission: $missionName',
|
||||
color: Colors.white.withValues(alpha: 0.12),
|
||||
textColor: Colors.white,
|
||||
maxWidth: 160,
|
||||
onTap: () => Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => const MissionsDronesPanel.missions(),
|
||||
)),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Flexible(
|
||||
child: _NameChip(
|
||||
label: 'Drone: $droneName',
|
||||
color: const Color(0xFF4D9DFF).withValues(alpha: 0.18),
|
||||
textColor: const Color(0xFFCFE2FF),
|
||||
maxWidth: 140,
|
||||
onTap: () => Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => const MissionsDronesPanel.drones(),
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
child: _NameChip(
|
||||
label: 'Mission: $missionName',
|
||||
color: Colors.white.withValues(alpha: 0.12),
|
||||
textColor: Colors.white,
|
||||
onTap: () => Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => const MissionsDronesPanel.missions(),
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
_detailsPill(),
|
||||
// Drohnen-Pille + Warnungs-/Settings-Knopf rechts. Die Pille
|
||||
// sitzt in Flexible, damit sie bei langen Namen zu Gunsten der
|
||||
// beiden festgroessen Rundknoepfe schrumpft/ellipsiert, statt
|
||||
// sie aus dem sichtbaren Bereich zu draengen.
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: _NameChip(
|
||||
label: 'Drone: $droneName',
|
||||
color: const Color(0xFF4D9DFF).withValues(alpha: 0.18),
|
||||
textColor: const Color(0xFFCFE2FF),
|
||||
onTap: () => Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => const MissionsDronesPanel.drones(),
|
||||
)),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
if (warnings.isNotEmpty) ...[
|
||||
_WarningButton(onTap: onWarningsTap),
|
||||
const SizedBox(width: 6),
|
||||
@@ -215,36 +239,34 @@ class _NameChip extends StatelessWidget {
|
||||
required this.color,
|
||||
required this.textColor,
|
||||
required this.onTap,
|
||||
required this.maxWidth,
|
||||
});
|
||||
|
||||
final String label;
|
||||
final Color color;
|
||||
final Color textColor;
|
||||
final VoidCallback onTap;
|
||||
final double maxWidth;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Kein fester maxWidth mehr - die Pille darf die verfuegbare Breite
|
||||
// ihres Elternwidgets nutzen (Align/Flexible am Aufrufort begrenzen sie
|
||||
// bereits auf die dort tatsaechlich verfuegbare Breite).
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: maxWidth),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7),
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7),
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user