diff --git a/lib/main.dart b/lib/main.dart index 7a5ee9f..491726d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,7 @@ import 'package:rezepte/pages/dashboard_page.dart'; import 'package:rezepte/services/providers/recipe_list_provider.dart'; import 'package:rezepte/services/providers/recipe_provider.dart'; +import 'pages/recipe_detail_page.dart'; import 'theme.dart'; void main() { @@ -30,6 +31,7 @@ class MyApp extends StatelessWidget { routes: { Dashboard.routeName: (_) => const Dashboard(), CreateRecipe.routeName: (_) => const CreateRecipe(), + RecipeDetail.routeName: (_) => const RecipeDetail(), }, ); } diff --git a/lib/models/recipe.dart b/lib/models/recipe.dart index 4574847..69ccaf0 100644 --- a/lib/models/recipe.dart +++ b/lib/models/recipe.dart @@ -3,18 +3,16 @@ import 'cooking_step.dart'; import 'ingredient_list_entry.dart'; class Recipe { - final String title; - final String description; - final Difficulty? difficulty; - final List ingredients; - final List steps; + String title; + String description; + Difficulty? difficulty; + final List ingredients = []; + final List steps = []; Recipe({ required this.title, this.description = '', this.difficulty, - this.ingredients = const [], - this.steps = const [], }); void addIngredient(IngredientListEntry ingredient) => @@ -33,4 +31,24 @@ class Recipe { void addStep(CookingStep step) => steps.add(step); void removeStepAt(int index) => steps.removeAt(index); + + bool get isEmpty { + return title.isEmpty && + description.isEmpty && + difficulty == null && + ingredients.isEmpty && + steps.isEmpty; + } + + bool get isNotEmpty { + return !isEmpty; + } + + void clear() { + title = ''; + description = ''; + difficulty = null; + ingredients.clear(); + steps.clear(); + } } diff --git a/lib/pages/create_recipe_page.dart b/lib/pages/create_recipe_page.dart index 05c1edb..15c048e 100644 --- a/lib/pages/create_recipe_page.dart +++ b/lib/pages/create_recipe_page.dart @@ -4,6 +4,7 @@ import 'package:rezepte/widgets/ingredients_bottomsheet.dart'; import 'package:rezepte/widgets/will_pop_scope.dart'; import '../models/difficulty.dart'; import '../models/ingredient_list_entry.dart'; +import '../models/recipe.dart'; import '../services/providers/recipe_list_provider.dart'; import '../services/providers/recipe_provider.dart'; @@ -16,28 +17,35 @@ class CreateRecipe extends StatefulWidget { } class _CreateRecipeState extends State { - late RecipeProvider recipeProvider; late RecipeListProvider recipeListProvider; + late RecipeProvider recipeProvider; + late Recipe recipe; + + @override + void initState() { + super.initState(); + } @override void dispose() { + recipeProvider.disposeRecipe(); super.dispose(); - recipeProvider.clearRecipe(silent: true); } @override Widget build(BuildContext context) { - recipeProvider = Provider.of(context); + recipe = Provider.of(context).recipe; + recipeProvider = Provider.of(context, listen: false); recipeListProvider = Provider.of(context, listen: false); return CustomWillPopScope( context, - ignore: recipeProvider.isEmpty, + ignore: recipe.isEmpty, child: Scaffold( appBar: AppBar( title: const Text('Create Recipe'), ), - floatingActionButton: recipeProvider.isNotEmpty + floatingActionButton: recipe.isNotEmpty ? FloatingActionButton( onPressed: _onRecipeSubmitted, child: const Icon(Icons.save), @@ -50,7 +58,7 @@ class _CreateRecipeState extends State { children: [ TextFormField( onTapOutside: (event) => FocusScope.of(context).unfocus(), - onChanged: (value) => recipeProvider.title = value, + onChanged: (value) => recipe.title = value, decoration: const InputDecoration( label: Text('Title'), ), @@ -61,7 +69,7 @@ class _CreateRecipeState extends State { onTapOutside: (event) => FocusScope.of(context).unfocus(), minLines: 1, maxLines: 4, - onChanged: (value) => recipeProvider.description = value, + onChanged: (value) => recipe.description = value, decoration: const InputDecoration( label: Text('Description'), ), @@ -70,7 +78,7 @@ class _CreateRecipeState extends State { ), DropdownMenu( dropdownMenuEntries: DifficultyUtil.getDropdownList(), - onSelected: (value) => recipeProvider.difficulty = value, + onSelected: (value) => recipe.difficulty = value, label: const Text('Difficulty'), textStyle: TextStyle( color: Theme.of(context).colorScheme.onBackground), @@ -81,7 +89,7 @@ class _CreateRecipeState extends State { ), Expanded( child: ListView.separated( - itemCount: recipeProvider.ingredients.length, + itemCount: recipe.ingredients.length, itemBuilder: _ingredientListBuilder, separatorBuilder: (context, index) => const Divider(), ), @@ -104,27 +112,27 @@ class _CreateRecipeState extends State { } void _onIngredientSubmitted(IngredientListEntry ingredient) => setState(() { - recipeProvider.ingredients.add(ingredient); + recipe.ingredients.add(ingredient); }); void _onIngredientRemoveTapped(int index) { - final removedIngredient = recipeProvider.ingredients.elementAt(index); + final removedIngredient = recipe.ingredients.elementAt(index); - recipeProvider.removeIngredientAt(index); + recipe.removeIngredientAt(index); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('Ingredient Removed'), action: SnackBarAction( label: 'Undo', onPressed: () { - recipeProvider.addIngredient(removedIngredient); + recipe.addIngredient(removedIngredient); }), ), ); } Widget? _ingredientListBuilder(BuildContext context, int index) { - final ingredient = recipeProvider.ingredients.elementAt(index); + final ingredient = recipe.ingredients.elementAt(index); return ListTile( contentPadding: EdgeInsets.zero, @@ -165,8 +173,8 @@ class _CreateRecipeState extends State { void _onRecipeSubmitted() { // TODO implement onRecipeSubmitted - if (recipeProvider.isEmpty) return; - recipeListProvider.addRecipe(recipeProvider.recipe); + if (recipe.isEmpty) return; + recipeListProvider.addRecipe(recipe); Navigator.of(context).pop(); } } diff --git a/lib/pages/recipe_detail_page.dart b/lib/pages/recipe_detail_page.dart new file mode 100644 index 0000000..7b2e45a --- /dev/null +++ b/lib/pages/recipe_detail_page.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:rezepte/services/providers/recipe_provider.dart'; + +class RecipeDetail extends StatelessWidget { + const RecipeDetail({super.key}); + static const routeName = '/recipeDetail'; + + @override + Widget build(BuildContext context) { + final recipe = Provider.of(context, listen: false).recipe; + + return Scaffold( + appBar: AppBar(), + body: Center( + child: Text(recipe.title), + ), + ); + } +} diff --git a/lib/services/providers/recipe_provider.dart b/lib/services/providers/recipe_provider.dart index 4cfb5f4..f811207 100644 --- a/lib/services/providers/recipe_provider.dart +++ b/lib/services/providers/recipe_provider.dart @@ -1,99 +1,71 @@ import 'package:flutter/material.dart'; -import '../../models/difficulty.dart'; -import '../../models/cooking_step.dart'; -import '../../models/ingredient_list_entry.dart'; import '../../models/recipe.dart'; class RecipeProvider extends ChangeNotifier { - String _title = ''; - String _description = ''; - Difficulty? _difficulty; - final List _ingredients = []; - final List _steps = []; + Recipe? _recipe; - Recipe get recipe => Recipe( - title: _title, - description: _description, - difficulty: _difficulty, - ingredients: _ingredients, - steps: _steps); + Recipe get recipe => _recipe ??= Recipe(title: ''); - void clearRecipe({silent = false}) { - _title = ''; - _description = ''; - _difficulty = null; - _ingredients.clear(); - _steps.clear(); - if (!silent) { - notifyListeners(); - } - } - - bool get isEmpty { - return _title.isEmpty && - _description.isEmpty && - _difficulty == null && - _ingredients.isEmpty && - steps.isEmpty; - } - - bool get isNotEmpty { - return !isEmpty; - } - - String get description => _description; - - set description(String description) { - _description = description; + set recipe(Recipe recipe) { + _recipe = recipe; notifyListeners(); } - String get title => _title; - - set title(String title) { - _title = title; - notifyListeners(); + void disposeRecipe() { + _recipe = null; } - Difficulty? get difficulty => _difficulty; + // set description(String description) { + // _description = description; + // notifyListeners(); + // } - set difficulty(Difficulty? difficulty) { - _difficulty = difficulty; - notifyListeners(); - } + // String get title => _title; - List get ingredients => _ingredients; + // set title(String title) { + // _title = title; + // notifyListeners(); + // } - void addIngredient(IngredientListEntry ingredient) { - _ingredients.add(ingredient); - notifyListeners(); - } + // Difficulty? get difficulty => _difficulty; - void clearIngredients({silent = false}) { - ingredients.clear(); - if (!silent) notifyListeners(); - } + // set difficulty(Difficulty? difficulty) { + // _difficulty = difficulty; + // notifyListeners(); + // } - void removeIngredientAt(int index, {silent = false}) { - ingredients.removeAt(index); - if (!silent) notifyListeners(); - } + // List get ingredients => _ingredients; - void removeIngredient(IngredientListEntry ingredient, {silent = false}) { - ingredients.removeWhere((element) => element == ingredient); - if (!silent) notifyListeners(); - } + // void addIngredient(IngredientListEntry ingredient) { + // _ingredients.add(ingredient); + // notifyListeners(); + // } - List get steps => _steps; + // void clearIngredients({silent = false}) { + // ingredients.clear(); + // if (!silent) notifyListeners(); + // } - void addStep(CookingStep step, {silent = false}) { - steps.add(step); - if (!silent) notifyListeners(); - } + // void removeIngredientAt(int index, {silent = false}) { + // ingredients.removeAt(index); + // if (!silent) notifyListeners(); + // } - void removeStepAt(int index, {silent = false}) { - steps.removeAt(index); - if (!silent) notifyListeners(); - } + // void removeIngredient(IngredientListEntry ingredient, {silent = false}) { + // ingredients.removeWhere((element) => element == ingredient); + // if (!silent) notifyListeners(); + // } + + // List get steps => _steps; + + // void addStep(CookingStep step, {silent = false}) { + // steps.add(step); + // if (!silent) notifyListeners(); + // } + + // void removeStepAt(int index, {silent = false}) { + // steps.removeAt(index); + // if (!silent) notifyListeners(); + // } } diff --git a/lib/widgets/recipe_list.dart b/lib/widgets/recipe_list.dart index 08a0b0c..6199c65 100644 --- a/lib/widgets/recipe_list.dart +++ b/lib/widgets/recipe_list.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:rezepte/pages/recipe_detail_page.dart'; import 'package:rezepte/services/providers/recipe_list_provider.dart'; +import 'package:rezepte/services/providers/recipe_provider.dart'; import '../models/recipe.dart'; @@ -11,6 +13,7 @@ class RecipeList extends StatelessWidget { Widget build(BuildContext context) { final recipes = Provider.of(context, listen: true).recipes; + return ListView.builder( itemCount: recipes.length, itemBuilder: (context, index) => @@ -20,9 +23,18 @@ class RecipeList extends StatelessWidget { Widget? _recipeListBuilder(BuildContext context, int index, Recipe entry) { return Card( - child: ListTile( - title: Text(entry.title), + child: InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () => _onRecipeTapped(context, entry), + child: ListTile( + title: Text(entry.title), + ), ), ); } + + void _onRecipeTapped(BuildContext context, Recipe recipe) { + Provider.of(context, listen: false).recipe = recipe; + Navigator.of(context).pushNamed(RecipeDetail.routeName); + } }