import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../app_mode/app_mode_cubit.dart'; import '../dmc_colors.dart'; import 'header_wind_pill.dart'; import 'map_search_controls.dart'; /// Persistente Kopfleiste zum Umschalten zwischen Plan- und Fly-Modus /// (HTML-Demonstrator: #topBarWrap/#editModeBtn/#flyModeBtn). Die Leiste /// faerbt sich in der Farbe des aktiven Modus; der jeweils andere Modus wird /// als solider Button am Rand angeboten, um in ihn zu wechseln. /// /// Traegt ausserhalb des Fly-Modus zusaetzlich die Wind-Pille, Ortssuche und /// die Home-/Fit-Buttons in derselben Pille (HTML-Demonstrator: #headerWindPill/ /// #searchWrap/#homeBtn/#fitBtn sitzen alle in #topBarMiddle, nicht in einer /// separaten Leiste) - dafuer lebt der MapController im mapControllerProvider /// statt als PlanScreen-privates Feld, siehe dort. class TopModeBar extends StatelessWidget { const TopModeBar({super.key}); @override Widget build(BuildContext context) { final isFly = context.select((AppModeCubit c) => c.state.mode == AppMode.fly); final activeTint = isFly ? DmcColors.flyModeRed : DmcColors.editModeGreen; return SafeArea( bottom: false, child: FractionallySizedBox( widthFactor: 0.70, child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), decoration: BoxDecoration( color: activeTint.withValues(alpha: 0.55), borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(26), bottomRight: Radius.circular(26), ), ), child: Row( children: [ _ModeButton( label: 'Plan', isActive: !isFly, inactiveColor: DmcColors.editModeGreen, cornerRadius: const BorderRadius.only( bottomLeft: Radius.circular(26), ), onTap: () => context.read().toPlan(), ), if (isFly) const Spacer() else ...[ const SizedBox(width: 8), const HeaderWindPill(), const SizedBox(width: 8), const Expanded(child: MapSearchControls()), const SizedBox(width: 12), ], _ModeButton( label: 'Fly', isActive: isFly, inactiveColor: DmcColors.flyModeRed, cornerRadius: const BorderRadius.only( bottomRight: Radius.circular(26), ), onTap: () => _tryEnterFly(context), ), ], ), ), ), ); } void _tryEnterFly(BuildContext context) { try { context.read().toFly(); } on StateError { // Ready-to-Fly-Gate (Doku 2.2/4.5) nicht erfuellt - Upload/Verify-Flow // ist noch nicht verdrahtet, daher aktuell immer dieser Fall. ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Mission muss zuerst hochgeladen und verifiziert werden.', ), ), ); } } } class _ModeButton extends StatelessWidget { const _ModeButton({ required this.label, required this.isActive, required this.inactiveColor, required this.cornerRadius, required this.onTap, }); final String label; final bool isActive; final Color inactiveColor; final BorderRadius cornerRadius; final VoidCallback onTap; @override Widget build(BuildContext context) { return GestureDetector( onTap: isActive ? null : onTap, child: Container( padding: EdgeInsets.symmetric( horizontal: 24, vertical: isActive ? 6 : 11, ), decoration: BoxDecoration( color: isActive ? null : inactiveColor.withValues(alpha: 0.85), borderRadius: isActive ? null : cornerRadius, ), child: Text( label, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.w800, color: Color(0xFF141414), ), ), ), ); } }