import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../features/auth/presentation/login_screen.dart'; import '../../features/household/presentation/household_screen.dart'; import '../../features/locations/presentation/location_detail_screen.dart'; import '../../features/locations/presentation/locations_screen.dart'; import '../../features/plants/domain/plant.dart'; import '../../features/plants/presentation/plant_detail_screen.dart'; import '../../features/plants/presentation/plant_diagnoses_screen.dart'; import '../../features/plants/presentation/plant_form_screen.dart'; import '../../features/plants/presentation/plants_screen.dart'; import '../../features/settings/presentation/settings_screen.dart'; import '../../features/today/presentation/today_screen.dart'; import '../firebase/firebase_providers.dart'; /// Zentrale Routen-Definition. Die Pfade werden auch vom Drawer genutzt, /// deshalb hier als Konstanten. abstract final class AppRoutes { static const today = '/'; static const login = '/login'; static const plants = '/plants'; static const plantAdd = '/plants/add'; static const plantEdit = '/plants/edit'; static const locations = '/locations'; static const household = '/household'; static const settings = '/settings'; /// Untersuchungs-Seite einer Pflanze. static String plantDiagnoses(String plantId) => '/plants/$plantId/diagnoses'; /// Detailseite eines Stellplatzes (Foto, Standort-Analyse, Eignung). static String locationDetail(String locationId) => '/locations/$locationId'; } /// Übersetzt einen Stream in ein Listenable, damit der Router bei /// Login/Logout sofort neu auswertet, wohin umgeleitet werden muss. class _StreamListenable extends ChangeNotifier { _StreamListenable(Stream stream) { _subscription = stream.listen((_) => notifyListeners()); } late final StreamSubscription _subscription; @override void dispose() { _subscription.cancel(); super.dispose(); } } final appRouterProvider = Provider((ref) { final auth = ref.watch(firebaseAuthProvider); final refreshListenable = _StreamListenable(auth.authStateChanges()); ref.onDispose(refreshListenable.dispose); final router = GoRouter( initialLocation: AppRoutes.today, refreshListenable: refreshListenable, redirect: (context, state) { final loggedIn = auth.currentUser != null; final onLoginScreen = state.matchedLocation == AppRoutes.login; if (!loggedIn) return onLoginScreen ? null : AppRoutes.login; if (onLoginScreen) return AppRoutes.today; return null; }, routes: [ GoRoute( path: AppRoutes.login, builder: (context, state) => const LoginScreen(), ), GoRoute( path: AppRoutes.today, builder: (context, state) => const TodayScreen(), ), GoRoute( path: AppRoutes.plants, builder: (context, state) => const PlantsScreen(), ), GoRoute( path: AppRoutes.plantAdd, builder: (context, state) => const PlantFormScreen(), ), GoRoute( path: AppRoutes.plantEdit, builder: (context, state) => PlantFormScreen(existing: state.extra as Plant?), ), GoRoute( path: '/plants/:id', builder: (context, state) => PlantDetailScreen(plantId: state.pathParameters['id']!), ), GoRoute( path: '/plants/:id/diagnoses', builder: (context, state) => PlantDiagnosesScreen(plantId: state.pathParameters['id']!), ), GoRoute( path: AppRoutes.locations, builder: (context, state) => const LocationsScreen(), ), GoRoute( path: '/locations/:id', builder: (context, state) => LocationDetailScreen(locationId: state.pathParameters['id']!), ), GoRoute( path: AppRoutes.household, builder: (context, state) => const HouseholdScreen(), ), GoRoute( path: AppRoutes.settings, builder: (context, state) => const SettingsScreen(), ), ], ); ref.onDispose(router.dispose); return router; });