Files
recipe-app/flutter/lib/core/router/app_router.dart
T
Nils-Johan Gynther e495a4b38e feat: add meal planning feature with API integration
- Introduced MealPlanApiPaths for handling meal plan related API endpoints.
- Added MealPlanScreen for displaying and managing meal plans.
- Implemented MealPlanRepository for fetching and updating meal plan data.
- Created data models: MealPlanEntry, MealPlanRecipe, InventoryCompareItem, ShoppingItem, and MealPlanDashboard.
- Integrated meal plan functionality into the app router and UI.
- Updated localization files for meal plan related strings in English and Swedish.
- Added state management for meal plan using Riverpod.
2026-04-22 19:51:33 +02:00

180 lines
6.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../ui/app_shell.dart';
import '../ui/async_state_views.dart';
import '../../features/auth/data/auth_providers.dart';
import '../../features/auth/presentation/login_screen.dart';
import '../../features/profile/presentation/profile_screen.dart';
import '../../features/recipes/presentation/create_recipe_screen.dart';
import '../../features/recipes/presentation/recipe_detail_screen.dart';
import '../../features/recipes/presentation/recipe_edit_screen.dart';
import '../../features/recipes/presentation/recipes_screen.dart';
import '../../features/inventory/presentation/inventory_screen.dart';
import '../../features/inventory/presentation/inventory_detail_screen.dart';
import '../../features/inventory/presentation/create_inventory_screen.dart';
import '../../features/inventory/presentation/inventory_edit_screen.dart';
import '../../features/inventory/presentation/consume_inventory_screen.dart';
import '../../features/inventory/presentation/consumption_history_screen.dart';
import '../../features/meal_plan/presentation/meal_plan_screen.dart';
import '../../features/pantry/presentation/pantry_screen.dart';
final appRouterProvider = Provider<GoRouter>((ref) {
final authState = ref.watch(authStateProvider);
return GoRouter(
initialLocation: '/',
redirect: (context, state) {
final isLoading = authState.isLoading;
final token = authState.valueOrNull;
final isLoggedIn = token != null && token.isNotEmpty;
final location = state.matchedLocation;
final isSplash = location == '/';
final isLogin = location == '/login';
if (isLoading) {
return isSplash ? null : '/';
}
if (isSplash) {
return isLoggedIn ? '/recipes' : '/login';
}
if (!isLoggedIn && !isLogin) {
return '/login';
}
if (isLoggedIn && isLogin) {
return '/recipes';
}
return null;
},
routes: [
GoRoute(
path: '/',
builder: (context, state) => const Scaffold(
body: LoadingStateView(label: 'Startar...'),
),
),
GoRoute(
path: '/login',
builder: (context, state) => const LoginScreen(),
),
// Detail routes — outside ShellRoute to get full-screen with back button.
// /recipes/create must be listed before /recipes/:id to avoid conflict.
GoRoute(
path: '/recipes/create',
builder: (context, state) => const CreateRecipeScreen(),
),
GoRoute(
path: '/recipes/:id',
redirect: (context, state) {
final raw = state.pathParameters['id'] ?? '';
if (int.tryParse(raw) == null) return '/recipes';
return null;
},
builder: (context, state) {
final id = int.parse(state.pathParameters['id']!);
return RecipeDetailScreen(recipeId: id);
},
),
GoRoute(
path: '/recipes/:id/edit',
redirect: (context, state) {
final raw = state.pathParameters['id'] ?? '';
if (int.tryParse(raw) == null) return '/recipes';
return null;
},
builder: (context, state) {
final id = int.parse(state.pathParameters['id']!);
return RecipeEditScreen(recipeId: id);
},
),
// Inventory detail routes — outside ShellRoute for full-screen.
// /inventory/create must be listed before /inventory/:id.
GoRoute(
path: '/inventory/create',
builder: (context, state) => const CreateInventoryScreen(),
),
GoRoute(
path: '/inventory/:id',
redirect: (context, state) {
final raw = state.pathParameters['id'] ?? '';
if (int.tryParse(raw) == null) return '/inventory';
return null;
},
builder: (context, state) {
final id = int.parse(state.pathParameters['id']!);
return InventoryDetailScreen(itemId: id);
},
),
GoRoute(
path: '/inventory/:id/edit',
redirect: (context, state) {
final raw = state.pathParameters['id'] ?? '';
if (int.tryParse(raw) == null) return '/inventory';
return null;
},
builder: (context, state) {
final id = int.parse(state.pathParameters['id']!);
return InventoryEditScreen(itemId: id);
},
),
GoRoute(
path: '/inventory/:id/consume',
redirect: (context, state) {
final raw = state.pathParameters['id'] ?? '';
if (int.tryParse(raw) == null) return '/inventory';
return null;
},
builder: (context, state) {
final id = int.parse(state.pathParameters['id']!);
return ConsumeInventoryScreen(itemId: id);
},
),
GoRoute(
path: '/inventory/:id/history',
redirect: (context, state) {
final raw = state.pathParameters['id'] ?? '';
if (int.tryParse(raw) == null) return '/inventory';
return null;
},
builder: (context, state) {
final id = int.parse(state.pathParameters['id']!);
return ConsumptionHistoryScreen(itemId: id);
},
),
// Shell routes — shared AppShell with navigation bar.
ShellRoute(
builder: (context, state, child) {
return AppShell(location: state.uri.path, child: child);
},
routes: [
GoRoute(
path: '/recipes',
builder: (context, state) => const RecipesScreen(),
),
GoRoute(
path: '/inventory',
builder: (context, state) => const InventoryScreen(),
),
GoRoute(
path: '/matsedel',
builder: (context, state) => const MealPlanScreen(),
),
GoRoute(
path: '/baslager',
builder: (context, state) => const PantryScreen(),
),
GoRoute(
path: '/profile',
builder: (context, state) => const ProfileScreen(),
),
],
),
],
);
});