284299b946
Complete Flutter app (Android + iOS) mirroring the web frontend: - Core: Riverpod state, Dio networking with auth interceptor + auto-refresh, go_router navigation, flutter_secure_storage, light/dark theme with MedievalSharp/Crimson Pro fonts, German l10n - Market: search with text/GPS/radius/date/sort filters, list + map views (flutter_map + OSM), detail screen with opening hours, admission prices, single-marker map, pagination - Auth: login (password + magic link tabs), register, OAuth button placeholders, 2FA code prompt on 401, sealed auth state provider - User: profile view/edit/delete with confirm dialog, 2FA setup/disable on security screen - GPS: geolocator with IP-based fallback (geojs.io) matching web behavior - Platform: Android internet + location permissions, iOS NSLocation description - Tests: date/currency/distance formatter unit tests (13 passing) - Zero analysis issues, debug APK builds successfully
53 lines
1.2 KiB
Dart
53 lines
1.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
class AppScaffold extends StatelessWidget {
|
|
final Widget child;
|
|
|
|
const AppScaffold({super.key, required this.child});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(
|
|
'Marktvogt',
|
|
style: Theme.of(context).appBarTheme.titleTextStyle,
|
|
),
|
|
),
|
|
body: child,
|
|
bottomNavigationBar: _BottomNav(),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _BottomNav extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final location = GoRouterState.of(context).uri.toString();
|
|
final currentIndex = location.startsWith('/profil') ? 1 : 0;
|
|
|
|
return BottomNavigationBar(
|
|
currentIndex: currentIndex,
|
|
onTap: (index) {
|
|
switch (index) {
|
|
case 0:
|
|
context.go('/');
|
|
case 1:
|
|
context.go('/profil');
|
|
}
|
|
},
|
|
items: const [
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.search),
|
|
label: 'Suche',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.person),
|
|
label: 'Profil',
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|