Add top bar for switching between Plan and Fly mode
- TopModeBar widget: persistent pill-shaped header (HTML prototype: #topBarWrap/#editModeBtn/#flyModeBtn) tinted in the active mode's color, with the inactive mode offered as a solid button in the corner to switch into it. - AppShell now provides a single shared Scaffold + Stack, overlaying TopModeBar on top of whichever screen (Plan/Fly) is active, instead of each screen owning its own Scaffold. - Wired the Fly button to AppModeCubit.toFly(), which enforces the Ready-to-Fly gate (doc 4.5). Since upload/verify isn't wired up yet, the gate is never satisfied yet, so tapping Fly now shows a SnackBar instead of throwing an uncaught StateError. - Extended the widget test to cover both the bar's presence and the gate-rejection path (was the source of a real bug: an initial negative-margin Container hack for the "bleed into the corner" look violated Container's margin.isNonNegative assertion and crashed the whole tree - fixed with padding instead). Verified with flutter analyze, flutter test, and a real run on the Pixel_10a emulator (visually matches the prototype screenshots in design/, Fly-tap correctly shows the gate message without crashing or switching mode). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
02dd1bc11a
commit
fc7d014fda
@@ -7,20 +7,40 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:dmc_app/app_mode/app_mode_cubit.dart';
|
||||
import 'package:dmc_app/ui/app_shell.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('AppShell zeigt die Karte im Plan-Startzustand', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
child: BlocProvider(
|
||||
create: (_) => AppModeCubit(),
|
||||
child: const MaterialApp(home: AppShell()),
|
||||
),
|
||||
Widget _wrap(Widget child) => ProviderScope(
|
||||
child: BlocProvider(
|
||||
create: (_) => AppModeCubit(),
|
||||
child: MaterialApp(home: child),
|
||||
),
|
||||
);
|
||||
|
||||
void main() {
|
||||
testWidgets('AppShell zeigt die Karte und den Plan/Fly-Umschalter im Startzustand',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(_wrap(const AppShell()));
|
||||
// Nur ein Frame pumpen statt pumpAndSettle: TileLayer laedt echte
|
||||
// Netzwerk-Kacheln, die in der Testumgebung nie ankommen.
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(FlutterMap), findsOneWidget);
|
||||
expect(find.text('Plan'), findsOneWidget);
|
||||
expect(find.text('Fly'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Fly-Button ohne erfuellten Ready-to-Fly-Gate zeigt Hinweis statt Absturz',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(_wrap(const AppShell()));
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.text('Fly'));
|
||||
await tester.pump();
|
||||
|
||||
expect(
|
||||
find.text('Mission muss zuerst hochgeladen und verifiziert werden.'),
|
||||
findsOneWidget,
|
||||
);
|
||||
// Weiterhin im Plan-Modus, da das Gate nicht erfuellt war.
|
||||
expect(find.byType(FlutterMap), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user