diff --git a/Raleway-Black.ttf b/Raleway-Black.ttf new file mode 100644 index 0000000..faef6a8 Binary files /dev/null and b/Raleway-Black.ttf differ diff --git a/Raleway-Bold.ttf b/Raleway-Bold.ttf new file mode 100644 index 0000000..62d4a91 Binary files /dev/null and b/Raleway-Bold.ttf differ diff --git a/Raleway-Regular.ttf b/Raleway-Regular.ttf new file mode 100644 index 0000000..9824df0 Binary files /dev/null and b/Raleway-Regular.ttf differ diff --git a/RobotoCondensed-Bold.ttf b/RobotoCondensed-Bold.ttf new file mode 100644 index 0000000..af5e395 Binary files /dev/null and b/RobotoCondensed-Bold.ttf differ diff --git a/RobotoCondensed-Italic.ttf b/RobotoCondensed-Italic.ttf new file mode 100644 index 0000000..7347b73 Binary files /dev/null and b/RobotoCondensed-Italic.ttf differ diff --git a/RobotoCondensed-Light.ttf b/RobotoCondensed-Light.ttf new file mode 100644 index 0000000..6a4c71c Binary files /dev/null and b/RobotoCondensed-Light.ttf differ diff --git a/RobotoCondensed-Regular.ttf b/RobotoCondensed-Regular.ttf new file mode 100644 index 0000000..9a1418d Binary files /dev/null and b/RobotoCondensed-Regular.ttf differ diff --git a/dummy-data.dart b/dummy-data.dart new file mode 100644 index 0000000..8351bdb --- /dev/null +++ b/dummy-data.dart @@ -0,0 +1,408 @@ +import 'package:flutter/material.dart'; + +import './models/category.dart'; +import './models/meal.dart'; + +const DUMMY_CATEGORIES = const [ + Category( + id: 'c1', + title: 'Italian', + color: Colors.purple, + ), + Category( + id: 'c2', + title: 'Quick & Easy', + color: Colors.red, + ), + Category( + id: 'c3', + title: 'Hamburgers', + color: Colors.orange, + ), + Category( + id: 'c4', + title: 'German', + color: Colors.amber, + ), + Category( + id: 'c5', + title: 'Light & Lovely', + color: Colors.blue, + ), + Category( + id: 'c6', + title: 'Exotic', + color: Colors.green, + ), + Category( + id: 'c7', + title: 'Breakfast', + color: Colors.lightBlue, + ), + Category( + id: 'c8', + title: 'Asian', + color: Colors.lightGreen, + ), + Category( + id: 'c9', + title: 'French', + color: Colors.pink, + ), + Category( + id: 'c10', + title: 'Summer', + color: Colors.teal, + ), +]; + +const DUMMY_MEALS = const [ + Meal( + id: 'm1', + categories: [ + 'c1', + 'c2', + ], + title: 'Spaghetti with Tomato Sauce', + affordability: Affordability.Affordable, + complexity: Complexity.Simple, + imageUrl: + 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg/800px-Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg', + duration: 20, + ingredients: [ + '4 Tomatoes', + '1 Tablespoon of Olive Oil', + '1 Onion', + '250g Spaghetti', + 'Spices', + 'Cheese (optional)' + ], + // steps: [ + // 'Cut the tomatoes and the onion into small pieces.', + // 'Boil some water - add salt to it once it boils.', + // 'Put the spaghetti into the boiling water - they should be done in about 10 to 12 minutes.', + // 'In the meantime, heaten up some olive oil and add the cut onion.', + // 'After 2 minutes, add the tomato pieces, salt, pepper and your other spices.', + // 'The sauce will be done once the spaghetti are.', + // 'Feel free to add some cheese on top of the finished dish.' + // ], + isGlutenFree: false, + isVegan: true, + isVegetarian: true, + isLactoseFree: true, + ), + Meal( + id: 'm2', + categories: [ + 'c2', + ], + title: 'Toast Hawaii', + affordability: Affordability.Affordable, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/07/11/21/51/toast-3532016_1280.jpg', + duration: 10, + ingredients: [ + '1 Slice White Bread', + '1 Slice Ham', + '1 Slice Pineapple', + '1-2 Slices of Cheese', + 'Butter' + ], + // steps: [ + // 'Butter one side of the white bread', + // 'Layer ham, the pineapple and cheese on the white bread', + // 'Bake the toast for round about 10 minutes in the oven at 200°C' + // ], + isGlutenFree: false, + isVegan: false, + isVegetarian: false, + isLactoseFree: false, + ), + Meal( + id: 'm3', + categories: [ + 'c2', + 'c3', + ], + title: 'Classic Hamburger', + affordability: Affordability.Pricey, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2014/10/23/18/05/burger-500054_1280.jpg', + duration: 45, + ingredients: [ + '300g Cattle Hack', + '1 Tomato', + '1 Cucumber', + '1 Onion', + 'Ketchup', + '2 Burger Buns' + ], + // steps: [ + // 'Form 2 patties', + // 'Fry the patties for c. 4 minutes on each side', + // 'Quickly fry the buns for c. 1 minute on each side', + // 'Bruch buns with ketchup', + // 'Serve burger with tomato, cucumber and onion' + // ], + isGlutenFree: false, + isVegan: false, + isVegetarian: false, + isLactoseFree: true, + ), + Meal( + id: 'm4', + categories: [ + 'c4', + ], + title: 'Wiener Schnitzel', + affordability: Affordability.Luxurious, + complexity: Complexity.Challenging, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/03/31/19/29/schnitzel-3279045_1280.jpg', + duration: 60, + ingredients: [ + '8 Veal Cutlets', + '4 Eggs', + '200g Bread Crumbs', + '100g Flour', + '300ml Butter', + '100g Vegetable Oil', + 'Salt', + 'Lemon Slices' + ], + // steps: [ + // 'Tenderize the veal to about 2–4mm, and salt on both sides.', + // 'On a flat plate, stir the eggs briefly with a fork.', + // 'Lightly coat the cutlets in flour then dip into the egg, and finally, coat in breadcrumbs.', + // 'Heat the butter and oil in a large pan (allow the fat to get very hot) and fry the schnitzels until golden brown on both sides.', + // 'Make sure to toss the pan regularly so that the schnitzels are surrounded by oil and the crumbing becomes ‘fluffy’.', + // 'Remove, and drain on kitchen paper. Fry the parsley in the remaining oil and drain.', + // 'Place the schnitzels on awarmed plate and serve garnishedwith parsley and slices of lemon.' + // ], + isGlutenFree: false, + isVegan: false, + isVegetarian: false, + isLactoseFree: false, + ), + Meal( + id: 'm5', + categories: [ + 'c2' + 'c5', + 'c10', + ], + title: 'Salad with Smoked Salmon', + affordability: Affordability.Luxurious, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2016/10/25/13/29/smoked-salmon-salad-1768890_1280.jpg', + duration: 15, + ingredients: [ + 'Arugula', + 'Lamb\'s Lettuce', + 'Parsley', + 'Fennel', + '200g Smoked Salmon', + 'Mustard', + 'Balsamic Vinegar', + 'Olive Oil', + 'Salt and Pepper' + ], + // steps: [ + // 'Wash and cut salad and herbs', + // 'Dice the salmon', + // 'Process mustard, vinegar and olive oil into a dessing', + // 'Prepare the salad', + // 'Add salmon cubes and dressing' + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: true, + isLactoseFree: true, + ), + Meal( + id: 'm6', + categories: [ + 'c6', + 'c10', + ], + title: 'Delicious Orange Mousse', + affordability: Affordability.Affordable, + complexity: Complexity.Hard, + imageUrl: + 'https://cdn.pixabay.com/photo/2017/05/01/05/18/pastry-2274750_1280.jpg', + duration: 240, + ingredients: [ + '4 Sheets of Gelatine', + '150ml Orange Juice', + '80g Sugar', + '300g Yoghurt', + '200g Cream', + 'Orange Peel', + ], + // steps: [ + // 'Dissolve gelatine in pot', + // 'Add orange juice and sugar', + // 'Take pot off the stove', + // 'Add 2 tablespoons of yoghurt', + // 'Stir gelatin under remaining yoghurt', + // 'Cool everything down in the refrigerator', + // 'Whip the cream and lift it under die orange mass', + // 'Cool down again for at least 4 hours', + // 'Serve with orange peel', + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: true, + isLactoseFree: false, + ), + Meal( + id: 'm7', + categories: [ + 'c7', + ], + title: 'Pancakes', + affordability: Affordability.Affordable, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/07/10/21/23/pancake-3529653_1280.jpg', + duration: 20, + ingredients: [ + '1 1/2 Cups all-purpose Flour', + '3 1/2 Teaspoons Baking Powder', + '1 Teaspoon Salt', + '1 Tablespoon White Sugar', + '1 1/4 cups Milk', + '1 Egg', + '3 Tablespoons Butter, melted', + ], + // steps: [ + // 'In a large bowl, sift together the flour, baking powder, salt and sugar.', + // 'Make a well in the center and pour in the milk, egg and melted butter; mix until smooth.', + // 'Heat a lightly oiled griddle or frying pan over medium high heat.', + // 'Pour or scoop the batter onto the griddle, using approximately 1/4 cup for each pancake. Brown on both sides and serve hot.' + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: true, + isLactoseFree: false, + ), + Meal( + id: 'm8', + categories: [ + 'c8', + ], + title: 'Creamy Indian Chicken Curry', + affordability: Affordability.Pricey, + complexity: Complexity.Challenging, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/06/18/16/05/indian-food-3482749_1280.jpg', + duration: 35, + ingredients: [ + '4 Chicken Breasts', + '1 Onion', + '2 Cloves of Garlic', + '1 Piece of Ginger', + '4 Tablespoons Almonds', + '1 Teaspoon Cayenne Pepper', + '500ml Coconut Milk', + ], + // steps: [ + // 'Slice and fry the chicken breast', + // 'Process onion, garlic and ginger into paste and sauté everything', + // 'Add spices and stir fry', + // 'Add chicken breast + 250ml of water and cook everything for 10 minutes', + // 'Add coconut milk', + // 'Serve with rice' + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: false, + isLactoseFree: true, + ), + Meal( + id: 'm9', + categories: [ + 'c9', + ], + title: 'Chocolate Souffle', + affordability: Affordability.Affordable, + complexity: Complexity.Hard, + imageUrl: + 'https://cdn.pixabay.com/photo/2014/08/07/21/07/souffle-412785_1280.jpg', + duration: 45, + ingredients: [ + '1 Teaspoon melted Butter', + '2 Tablespoons white Sugar', + '2 Ounces 70% dark Chocolate, broken into pieces', + '1 Tablespoon Butter', + '1 Tablespoon all-purpose Flour', + '4 1/3 tablespoons cold Milk', + '1 Pinch Salt', + '1 Pinch Cayenne Pepper', + '1 Large Egg Yolk', + '2 Large Egg Whites', + '1 Pinch Cream of Tartar', + '1 Tablespoon white Sugar', + ], + // steps: [ + // 'Preheat oven to 190°C. Line a rimmed baking sheet with parchment paper.', + // 'Brush bottom and sides of 2 ramekins lightly with 1 teaspoon melted butter; cover bottom and sides right up to the rim.', + // 'Add 1 tablespoon white sugar to ramekins. Rotate ramekins until sugar coats all surfaces.', + // 'Place chocolate pieces in a metal mixing bowl.', + // 'Place bowl over a pan of about 3 cups hot water over low heat.', + // 'Melt 1 tablespoon butter in a skillet over medium heat. Sprinkle in flour. Whisk until flour is incorporated into butter and mixture thickens.', + // 'Whisk in cold milk until mixture becomes smooth and thickens. Transfer mixture to bowl with melted chocolate.', + // 'Add salt and cayenne pepper. Mix together thoroughly. Add egg yolk and mix to combine.', + // 'Leave bowl above the hot (not simmering) water to keep chocolate warm while you whip the egg whites.', + // 'Place 2 egg whites in a mixing bowl; add cream of tartar. Whisk until mixture begins to thicken and a drizzle from the whisk stays on the surface about 1 second before disappearing into the mix.', + // 'Add 1/3 of sugar and whisk in. Whisk in a bit more sugar about 15 seconds.', + // 'whisk in the rest of the sugar. Continue whisking until mixture is about as thick as shaving cream and holds soft peaks, 3 to 5 minutes.', + // 'Transfer a little less than half of egg whites to chocolate.', + // 'Mix until egg whites are thoroughly incorporated into the chocolate.', + // 'Add the rest of the egg whites; gently fold into the chocolate with a spatula, lifting from the bottom and folding over.', + // 'Stop mixing after the egg white disappears. Divide mixture between 2 prepared ramekins. Place ramekins on prepared baking sheet.', + // 'Bake in preheated oven until scuffles are puffed and have risen above the top of the rims, 12 to 15 minutes.', + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: true, + isLactoseFree: false, + ), + Meal( + id: 'm10', + categories: [ + 'c2', + 'c5', + 'c10', + ], + title: 'Asparagus Salad with Cherry Tomatoes', + affordability: Affordability.Luxurious, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/04/09/18/26/asparagus-3304997_1280.jpg', + duration: 30, + ingredients: [ + 'White and Green Asparagus', + '30g Pine Nuts', + '300g Cherry Tomatoes', + 'Salad', + 'Salt, Pepper and Olive Oil' + ], + // steps: [ + // 'Wash, peel and cut the asparagus', + // 'Cook in salted water', + // 'Salt and pepper the asparagus', + // 'Roast the pine nuts', + // 'Halve the tomatoes', + // 'Mix with asparagus, salad and dressing', + // 'Serve with Baguette' + // ], + isGlutenFree: true, + isVegan: true, + isVegetarian: true, + isLactoseFree: true, + ), +]; diff --git a/dummy-data2.dart b/dummy-data2.dart new file mode 100644 index 0000000..2a5364b --- /dev/null +++ b/dummy-data2.dart @@ -0,0 +1,408 @@ +import 'package:flutter/material.dart'; + +import './models/category.dart'; +import './models/meal.dart'; + +const DUMMY_CATEGORIES = const [ + Category( + id: 'c1', + title: 'Sweet', + color: Colors.purple, + ), + Category( + id: 'c2', + title: '', + color: Colors.red, + ), + Category( + id: 'c3', + title: 'Hamburgers', + color: Colors.orange, + ), + Category( + id: 'c4', + title: 'German', + color: Colors.amber, + ), + Category( + id: 'c5', + title: 'Light & Lovely', + color: Colors.blue, + ), + Category( + id: 'c6', + title: 'Exotic', + color: Colors.green, + ), + Category( + id: 'c7', + title: 'Breakfast', + color: Colors.lightBlue, + ), + Category( + id: 'c8', + title: 'Asian', + color: Colors.lightGreen, + ), + Category( + id: 'c9', + title: 'French', + color: Colors.pink, + ), + Category( + id: 'c10', + title: 'Summer', + color: Colors.teal, + ), +]; + +const DUMMY_MEALS = const [ + Meal( + id: 'm1', + categories: [ + 'c1', + 'c2', + ], + title: 'Spaghetti with Tomato Sauce', + affordability: Affordability.Affordable, + complexity: Complexity.Simple, + imageUrl: + 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg/800px-Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg', + duration: 20, + ingredients: [ + '4 Tomatoes', + '1 Tablespoon of Olive Oil', + '1 Onion', + '250g Spaghetti', + 'Spices', + 'Cheese (optional)' + ], + // steps: [ + // 'Cut the tomatoes and the onion into small pieces.', + // 'Boil some water - add salt to it once it boils.', + // 'Put the spaghetti into the boiling water - they should be done in about 10 to 12 minutes.', + // 'In the meantime, heaten up some olive oil and add the cut onion.', + // 'After 2 minutes, add the tomato pieces, salt, pepper and your other spices.', + // 'The sauce will be done once the spaghetti are.', + // 'Feel free to add some cheese on top of the finished dish.' + // ], + isGlutenFree: false, + isVegan: true, + isVegetarian: true, + isLactoseFree: true, + ), + Meal( + id: 'm2', + categories: [ + 'c2', + ], + title: 'Toast Hawaii', + affordability: Affordability.Affordable, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/07/11/21/51/toast-3532016_1280.jpg', + duration: 10, + ingredients: [ + '1 Slice White Bread', + '1 Slice Ham', + '1 Slice Pineapple', + '1-2 Slices of Cheese', + 'Butter' + ], + // steps: [ + // 'Butter one side of the white bread', + // 'Layer ham, the pineapple and cheese on the white bread', + // 'Bake the toast for round about 10 minutes in the oven at 200°C' + // ], + isGlutenFree: false, + isVegan: false, + isVegetarian: false, + isLactoseFree: false, + ), + Meal( + id: 'm3', + categories: [ + 'c2', + 'c3', + ], + title: 'Classic Hamburger', + affordability: Affordability.Pricey, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2014/10/23/18/05/burger-500054_1280.jpg', + duration: 45, + ingredients: [ + '300g Cattle Hack', + '1 Tomato', + '1 Cucumber', + '1 Onion', + 'Ketchup', + '2 Burger Buns' + ], + // steps: [ + // 'Form 2 patties', + // 'Fry the patties for c. 4 minutes on each side', + // 'Quickly fry the buns for c. 1 minute on each side', + // 'Bruch buns with ketchup', + // 'Serve burger with tomato, cucumber and onion' + // ], + isGlutenFree: false, + isVegan: false, + isVegetarian: false, + isLactoseFree: true, + ), + Meal( + id: 'm4', + categories: [ + 'c4', + ], + title: 'Wiener Schnitzel', + affordability: Affordability.Luxurious, + complexity: Complexity.Challenging, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/03/31/19/29/schnitzel-3279045_1280.jpg', + duration: 60, + ingredients: [ + '8 Veal Cutlets', + '4 Eggs', + '200g Bread Crumbs', + '100g Flour', + '300ml Butter', + '100g Vegetable Oil', + 'Salt', + 'Lemon Slices' + ], + // steps: [ + // 'Tenderize the veal to about 2–4mm, and salt on both sides.', + // 'On a flat plate, stir the eggs briefly with a fork.', + // 'Lightly coat the cutlets in flour then dip into the egg, and finally, coat in breadcrumbs.', + // 'Heat the butter and oil in a large pan (allow the fat to get very hot) and fry the schnitzels until golden brown on both sides.', + // 'Make sure to toss the pan regularly so that the schnitzels are surrounded by oil and the crumbing becomes ‘fluffy’.', + // 'Remove, and drain on kitchen paper. Fry the parsley in the remaining oil and drain.', + // 'Place the schnitzels on awarmed plate and serve garnishedwith parsley and slices of lemon.' + // ], + isGlutenFree: false, + isVegan: false, + isVegetarian: false, + isLactoseFree: false, + ), + Meal( + id: 'm5', + categories: [ + 'c2' + 'c5', + 'c10', + ], + title: 'Salad with Smoked Salmon', + affordability: Affordability.Luxurious, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2016/10/25/13/29/smoked-salmon-salad-1768890_1280.jpg', + duration: 15, + ingredients: [ + 'Arugula', + 'Lamb\'s Lettuce', + 'Parsley', + 'Fennel', + '200g Smoked Salmon', + 'Mustard', + 'Balsamic Vinegar', + 'Olive Oil', + 'Salt and Pepper' + ], + // steps: [ + // 'Wash and cut salad and herbs', + // 'Dice the salmon', + // 'Process mustard, vinegar and olive oil into a dessing', + // 'Prepare the salad', + // 'Add salmon cubes and dressing' + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: true, + isLactoseFree: true, + ), + Meal( + id: 'm6', + categories: [ + 'c6', + 'c10', + ], + title: 'Delicious Orange Mousse', + affordability: Affordability.Affordable, + complexity: Complexity.Hard, + imageUrl: + 'https://cdn.pixabay.com/photo/2017/05/01/05/18/pastry-2274750_1280.jpg', + duration: 240, + ingredients: [ + '4 Sheets of Gelatine', + '150ml Orange Juice', + '80g Sugar', + '300g Yoghurt', + '200g Cream', + 'Orange Peel', + ], + // steps: [ + // 'Dissolve gelatine in pot', + // 'Add orange juice and sugar', + // 'Take pot off the stove', + // 'Add 2 tablespoons of yoghurt', + // 'Stir gelatin under remaining yoghurt', + // 'Cool everything down in the refrigerator', + // 'Whip the cream and lift it under die orange mass', + // 'Cool down again for at least 4 hours', + // 'Serve with orange peel', + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: true, + isLactoseFree: false, + ), + Meal( + id: 'm7', + categories: [ + 'c7', + ], + title: 'Pancakes', + affordability: Affordability.Affordable, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/07/10/21/23/pancake-3529653_1280.jpg', + duration: 20, + ingredients: [ + '1 1/2 Cups all-purpose Flour', + '3 1/2 Teaspoons Baking Powder', + '1 Teaspoon Salt', + '1 Tablespoon White Sugar', + '1 1/4 cups Milk', + '1 Egg', + '3 Tablespoons Butter, melted', + ], + // steps: [ + // 'In a large bowl, sift together the flour, baking powder, salt and sugar.', + // 'Make a well in the center and pour in the milk, egg and melted butter; mix until smooth.', + // 'Heat a lightly oiled griddle or frying pan over medium high heat.', + // 'Pour or scoop the batter onto the griddle, using approximately 1/4 cup for each pancake. Brown on both sides and serve hot.' + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: true, + isLactoseFree: false, + ), + Meal( + id: 'm8', + categories: [ + 'c8', + ], + title: 'Creamy Indian Chicken Curry', + affordability: Affordability.Pricey, + complexity: Complexity.Challenging, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/06/18/16/05/indian-food-3482749_1280.jpg', + duration: 35, + ingredients: [ + '4 Chicken Breasts', + '1 Onion', + '2 Cloves of Garlic', + '1 Piece of Ginger', + '4 Tablespoons Almonds', + '1 Teaspoon Cayenne Pepper', + '500ml Coconut Milk', + ], + // steps: [ + // 'Slice and fry the chicken breast', + // 'Process onion, garlic and ginger into paste and sauté everything', + // 'Add spices and stir fry', + // 'Add chicken breast + 250ml of water and cook everything for 10 minutes', + // 'Add coconut milk', + // 'Serve with rice' + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: false, + isLactoseFree: true, + ), + Meal( + id: 'm9', + categories: [ + 'c9', + ], + title: 'Chocolate Souffle', + affordability: Affordability.Affordable, + complexity: Complexity.Hard, + imageUrl: + 'https://cdn.pixabay.com/photo/2014/08/07/21/07/souffle-412785_1280.jpg', + duration: 45, + ingredients: [ + '1 Teaspoon melted Butter', + '2 Tablespoons white Sugar', + '2 Ounces 70% dark Chocolate, broken into pieces', + '1 Tablespoon Butter', + '1 Tablespoon all-purpose Flour', + '4 1/3 tablespoons cold Milk', + '1 Pinch Salt', + '1 Pinch Cayenne Pepper', + '1 Large Egg Yolk', + '2 Large Egg Whites', + '1 Pinch Cream of Tartar', + '1 Tablespoon white Sugar', + ], + // steps: [ + // 'Preheat oven to 190°C. Line a rimmed baking sheet with parchment paper.', + // 'Brush bottom and sides of 2 ramekins lightly with 1 teaspoon melted butter; cover bottom and sides right up to the rim.', + // 'Add 1 tablespoon white sugar to ramekins. Rotate ramekins until sugar coats all surfaces.', + // 'Place chocolate pieces in a metal mixing bowl.', + // 'Place bowl over a pan of about 3 cups hot water over low heat.', + // 'Melt 1 tablespoon butter in a skillet over medium heat. Sprinkle in flour. Whisk until flour is incorporated into butter and mixture thickens.', + // 'Whisk in cold milk until mixture becomes smooth and thickens. Transfer mixture to bowl with melted chocolate.', + // 'Add salt and cayenne pepper. Mix together thoroughly. Add egg yolk and mix to combine.', + // 'Leave bowl above the hot (not simmering) water to keep chocolate warm while you whip the egg whites.', + // 'Place 2 egg whites in a mixing bowl; add cream of tartar. Whisk until mixture begins to thicken and a drizzle from the whisk stays on the surface about 1 second before disappearing into the mix.', + // 'Add 1/3 of sugar and whisk in. Whisk in a bit more sugar about 15 seconds.', + // 'whisk in the rest of the sugar. Continue whisking until mixture is about as thick as shaving cream and holds soft peaks, 3 to 5 minutes.', + // 'Transfer a little less than half of egg whites to chocolate.', + // 'Mix until egg whites are thoroughly incorporated into the chocolate.', + // 'Add the rest of the egg whites; gently fold into the chocolate with a spatula, lifting from the bottom and folding over.', + // 'Stop mixing after the egg white disappears. Divide mixture between 2 prepared ramekins. Place ramekins on prepared baking sheet.', + // 'Bake in preheated oven until scuffles are puffed and have risen above the top of the rims, 12 to 15 minutes.', + // ], + isGlutenFree: true, + isVegan: false, + isVegetarian: true, + isLactoseFree: false, + ), + Meal( + id: 'm10', + categories: [ + 'c2', + 'c5', + 'c10', + ], + title: 'Asparagus Salad with Cherry Tomatoes', + affordability: Affordability.Luxurious, + complexity: Complexity.Simple, + imageUrl: + 'https://cdn.pixabay.com/photo/2018/04/09/18/26/asparagus-3304997_1280.jpg', + duration: 30, + ingredients: [ + 'White and Green Asparagus', + '30g Pine Nuts', + '300g Cherry Tomatoes', + 'Salad', + 'Salt, Pepper and Olive Oil' + ], + // steps: [ + // 'Wash, peel and cut the asparagus', + // 'Cook in salted water', + // 'Salt and pepper the asparagus', + // 'Roast the pine nuts', + // 'Halve the tomatoes', + // 'Mix with asparagus, salad and dressing', + // 'Serve with Baguette' + // ], + isGlutenFree: true, + isVegan: true, + isVegetarian: true, + isLactoseFree: true, + ), +]; diff --git a/main.dart b/main.dart new file mode 100644 index 0000000..5a661d5 --- /dev/null +++ b/main.dart @@ -0,0 +1,116 @@ +import 'package:flutter/material.dart'; +import './screens/category_meals_screen.dart'; +import './screens/meal_detail_screen.dart'; +import './screens/tab_screen.dart'; +import './screens/filters_screen.dart'; +import './screens/categories_screen.dart'; +import './dummy-data.dart'; +import './models/meal.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + Map _filters = { + 'gluten': false, + 'lactose': false, + 'vegan': false, + 'vegetarian': false, + }; + + List _availableMeals = DUMMY_MEALS; + List _favoriteMeals = []; + + void _setFilters(Map filterData) { + setState(() { + _filters = filterData; + + _availableMeals = DUMMY_MEALS.where((meal) { + if (_filters['gluten'] && !meal.isGlutenFree) { + return false; + } + if (_filters['lactose'] && !meal.isLactoseFree) { + return false; + } + if (_filters['vegan'] && !meal.isVegan) { + return false; + } + if (_filters['vegetarian'] && !meal.isVegetarian) { + return false; + } + return true; + }).toList(); + }); + } + + void _toggleFavorite(String mealId) { + final existingIndex = _favoriteMeals.indexWhere( + (meal) => meal.id == mealId, + ); + if (existingIndex >= 0) { + setState(() { + _favoriteMeals.removeAt(existingIndex); + }); + } else { + setState(() { + _favoriteMeals.add( + DUMMY_MEALS.firstWhere((meal) => meal.id == mealId), + ); + }); + } + } + + bool _isMealFavorite(String id) { + return _favoriteMeals.any((meal) => meal.id == id); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'DeliMeals', + theme: ThemeData( + primarySwatch: Colors.pink, + accentColor: Colors.amber, + canvasColor: Color.fromRGBO(255, 254, 229, 1), + fontFamily: 'Raleway', + textTheme: ThemeData.light().textTheme.copyWith( + bodyText1: TextStyle( + color: Color.fromRGBO(20, 51, 51, 1), + ), + bodyText2: TextStyle( + color: Color.fromRGBO(20, 51, 51, 1), + ), + headline6: TextStyle( + fontSize: 20, + fontFamily: 'RobotoCondensed', + fontWeight: FontWeight.bold, + ), + ), + ), + // home: CategoriesScreen(), + initialRoute: '/', + routes: { + '/': (ctx) => TabsScreen(_favoriteMeals), + CategoryMealsScreen.routeName: (ctx) => + CategoryMealsScreen(_availableMeals), + MealDetailScreen.routeName: (ctx) => MealDetailScreen(_toggleFavorite, _isMealFavorite), + FiltersScreen.routeName: (ctx) => FiltersScreen(_filters, _setFilters), + }, + onGenerateRoute: (settings) { + print(settings.arguments); + return MaterialPageRoute( + builder: (ctx) => CategoriesScreen(), + ); + }, + onUnknownRoute: (settings) { + return MaterialPageRoute( + builder: (ctx) => CategoriesScreen(), + ); + }, + ); + } +} diff --git a/models/category.dart b/models/category.dart new file mode 100644 index 0000000..9fe060c --- /dev/null +++ b/models/category.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; + +class Category { + final String id; + final String title; + final Color color; + + const Category({ + @required this.id, + @required this.title, + this.color = Colors.orange, + }); +} diff --git a/models/meal.dart b/models/meal.dart new file mode 100644 index 0000000..8e57b09 --- /dev/null +++ b/models/meal.dart @@ -0,0 +1,41 @@ +import 'package:flutter/foundation.dart'; + +enum Complexity { Simple, Challenging, Hard } + +enum Affordability { + Affordable, + Pricey, + Luxurious, +} + +class Meal { + final String id; + final List categories; + final String title; + final String imageUrl; + final List ingredients; + final List steps; + final int duration; + final Complexity complexity; + final Affordability affordability; + final bool isGlutenFree; + final bool isLactoseFree; + final bool isVegan; + final bool isVegetarian; + + const Meal({ + @required this.id, + @required this.categories, + @required this.title, + @required this.imageUrl, + @required this.ingredients, + @required this.steps, + @required this.duration, + @required this.complexity, + @required this.affordability, + @required this.isGlutenFree, + @required this.isLactoseFree, + @required this.isVegan, + @required this.isVegetarian, + }); +} diff --git a/screens/categories_screen.dart b/screens/categories_screen.dart new file mode 100644 index 0000000..4ea427e --- /dev/null +++ b/screens/categories_screen.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import '../dummy-data.dart'; +import '../widgets/category_item.dart'; + +class CategoriesScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return GridView( + padding: const EdgeInsets.all(25), + children: DUMMY_CATEGORIES + .map( + (catData) => CategoryItem( + catData.id, + catData.title, + catData.color, + ), + ) + .toList(), + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + childAspectRatio: 3 / 2, + crossAxisSpacing: 20, + mainAxisSpacing: 20, + ), + ); + } +} diff --git a/screens/category_meals_screen.dart b/screens/category_meals_screen.dart new file mode 100644 index 0000000..4a037f0 --- /dev/null +++ b/screens/category_meals_screen.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_complete_guide/widgets/meal_item.dart'; +import '../models/meal.dart'; +import '../dummy-data2.dart'; + +class CategoryMealsScreen extends StatefulWidget { + static const routeName = '/category-meals'; + + final List _availableMeals; + + CategoryMealsScreen(this._availableMeals); + + @override + _CategoryMealsScreenState createState() => _CategoryMealsScreenState(); + // final String categoryId; + // final String categoryTitle; + + // CategoryMealsScreen(this.categoryId, this.categoryTitle); +} + +class _CategoryMealsScreenState extends State { + String categoryTitle; + List displayedMeals; + var _loadedInitData = false; + + @override + void initState() { + // ... + super.initState(); + } + + @override + void didChangeDependencies() { + if (!_loadedInitData) { + final routeArgs = + ModalRoute.of(context).settings.arguments as Map; + categoryTitle = routeArgs['title']; + final categoryId = routeArgs['id']; + displayedMeals = widget._availableMeals.where((meal) { + return meal.categories.contains(categoryId); + }).toList(); + _loadedInitData = true; + } + super.didChangeDependencies(); + } + + void _removeMeal(String mealId) { + setState(() { + displayedMeals.removeWhere((meal) => meal.id == mealId); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(categoryTitle), + ), + body: Center( + child: ListView.builder( + itemBuilder: (ctx, index) { + return MealItem( + id: displayedMeals[index].id, + title: displayedMeals[index].title, + imageUrl: displayedMeals[index].imageUrl, + duration: displayedMeals[index].duration, + affordability: displayedMeals[index].affordability, + complexity: displayedMeals[index].complexity, + ); + }, + itemCount: displayedMeals.length, + ), + ), + ); + } +} diff --git a/screens/favorites_screen.dart b/screens/favorites_screen.dart new file mode 100644 index 0000000..afd68b4 --- /dev/null +++ b/screens/favorites_screen.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import '../models/meal.dart'; +import '../widgets/meal_item.dart'; + +class FavoritesScreen extends StatelessWidget { + final List favoriteMeals; + + FavoritesScreen(this.favoriteMeals); + + @override + Widget build(BuildContext context) { + if (favoriteMeals.isEmpty) { + return Center( + child: Text('You have no favorites yet - start adding some!'), + ); + } else { + return ListView.builder( + itemBuilder: (ctx, index) { + return MealItem( + id: favoriteMeals[index].id, + title: favoriteMeals[index].title, + imageUrl: favoriteMeals[index].imageUrl, + duration: favoriteMeals[index].duration, + affordability: favoriteMeals[index].affordability, + complexity: favoriteMeals[index].complexity, + ); + }, + itemCount: favoriteMeals.length, + ); + } + } +} diff --git a/screens/filters_screen.dart b/screens/filters_screen.dart new file mode 100644 index 0000000..d52e2ac --- /dev/null +++ b/screens/filters_screen.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import '../widgets/main_drawer.dart'; + +class FiltersScreen extends StatefulWidget { + static const routeName = '/filters'; + + final Function saveFilters; + final Map currentFilters; + + FiltersScreen(this.currentFilters, this.saveFilters); + + @override + _FiltersScreenState createState() => _FiltersScreenState(); +} + +class _FiltersScreenState extends State { + var _glutenFree = false; + var _vegetarian = false; + var _vegan = false; + var _lactoseFree = false; + + @override + void initState() { + _glutenFree = widget.currentFilters['gluten']; + _lactoseFree = widget.currentFilters['lactose']; + _vegetarian = widget.currentFilters['vegetarian']; + _vegan = widget.currentFilters['vegan']; + super.initState(); + } + + Widget _buildSwitchTile( + String title, + String description, + bool currentValue, + Function updateValue, + ) { + return SwitchListTile( + title: Text(title), + value: currentValue, + subtitle: Text( + description, + ), + onChanged: updateValue, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text( + 'Your Filters', + ), + actions: [ + IconButton( + icon: Icon(Icons.save), + onPressed: () { + final selectedFilters = { + 'gluten': _glutenFree, + 'lactose': _lactoseFree, + 'vegan': _vegan, + 'vegetarian': _vegetarian, + }; + widget.saveFilters(selectedFilters); + }, + ), + ], + ), + drawer: MainDrawer(), + body: Column( + children: [ + Container( + padding: EdgeInsets.all(20), + child: Text( + 'Adjust your meal selection.', + style: Theme.of(context).textTheme.headline6, + ), + ), + Expanded( + child: ListView( + children: [ + _buildSwitchTile( + 'Gluten-free', + 'Only include gluten-free meals.', + _glutenFree, + (newValue) { + setState( + () { + _glutenFree = newValue; + }, + ); + }, + ), + _buildSwitchTile( + 'Lactose-free', + 'Only include lactose-free meals.', + _lactoseFree, + (newValue) { + setState( + () { + _lactoseFree = newValue; + }, + ); + }, + ), + _buildSwitchTile( + 'Vegetarian', + 'Only include vegetarian meals.', + _vegetarian, + (newValue) { + setState( + () { + _vegetarian = newValue; + }, + ); + }, + ), + _buildSwitchTile( + 'Vegan', + 'Only include vegam meals.', + _vegan, + (newValue) { + setState( + () { + _vegan = newValue; + }, + ); + }, + ) + ], + ), + ), + ], + ), + ); + } +} diff --git a/screens/meal_detail_screen.dart b/screens/meal_detail_screen.dart new file mode 100644 index 0000000..5b4a6a9 --- /dev/null +++ b/screens/meal_detail_screen.dart @@ -0,0 +1,119 @@ +import 'package:flutter/material.dart'; + +import '../dummy-data.dart'; + +class MealDetailScreen extends StatelessWidget { + static const routeName = '/meal-detail'; + + final Function toggleFavorite; + final Function isFavorite; + + MealDetailScreen(this.toggleFavorite, this.isFavorite); + + Widget buildSectionTitle(BuildContext context, String text) { + return Container( + margin: EdgeInsets.symmetric(vertical: 10), + child: Text( + text, + style: Theme.of(context).textTheme.headline6, + ), + ); + } + + Widget buildContainer(Widget child) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(10), + ), + margin: EdgeInsets.all(10), + padding: EdgeInsets.all(10), + height: 150, + width: 300, + child: child, + ); + } + + @override + Widget build(BuildContext context) { + final mealId = ModalRoute.of(context).settings.arguments as String; + final selectedMeal = DUMMY_MEALS.firstWhere((meal) => meal.id == mealId); + return Scaffold( + appBar: AppBar( + title: Text( + '${selectedMeal.title}', + ), + ), + body: SingleChildScrollView( + child: Column( + children: [ + Container( + height: 300, + width: double.infinity, + child: Image.network( + selectedMeal.imageUrl, + fit: BoxFit.cover, + ), + ), + buildSectionTitle(context, 'Ingredients'), + buildContainer( + ListView.builder( + itemBuilder: (ctx, index) => Card( + color: Theme.of(context).colorScheme.secondary, + child: Padding( + padding: EdgeInsets.symmetric( + vertical: 5, + horizontal: 10, + ), + child: Text( + selectedMeal.ingredients[index], + ), + ), + ), + itemCount: selectedMeal.ingredients.length, + ), + ), + // buildSectionTitle(context, 'Steps'), + // buildContainer( + // ListView.builder( + // itemBuilder: (ctx, index) => Column( + // children: [ + // ListTile( + // leading: CircleAvatar( + // child: Text('# ${(index + 1)}'), + // ), + // title: Text( + // selectedMeal.steps[index], + // ), + // ), + // Divider() + // ], + // ), + // itemCount: selectedMeal.steps.length, + // ), + // ), + + ], + + ), + ), + // style: ElevatedButton + // floatingActionButton: FloatingActionButton( + // child: Icon( + // isFavorite(mealId) ? Icons.star : Icons.star_border, + // ), + // onPressed: () => toggleFavorite(mealId), + // ), + floatingActionButton: FloatingActionButton( + // child: Icon( + // isFavorite(mealId) ? Icons.star : Icons.star_border, + // ), + // child: Icon( + // Icons + // ), + // onPressed: () => toggleFavorite(mealId), + ), + ); + } +} diff --git a/screens/tab_screen.dart b/screens/tab_screen.dart new file mode 100644 index 0000000..5c58030 --- /dev/null +++ b/screens/tab_screen.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import '../widgets/main_drawer.dart'; +import './favorites_screen.dart'; +import './categories_screen.dart'; +import '../models/meal.dart'; + +class TabsScreen extends StatefulWidget { + final List favoriteMeals; + + TabsScreen(this.favoriteMeals); + + @override + State createState() => _TabsScreenState(); +} + +class _TabsScreenState extends State { + List> _pages; + + int _selectedPageIndex = 0; + + @override + void initState() { + _pages = [ + { + 'page': CategoriesScreen(), + 'title': 'Categories', + }, + { + 'page': FavoritesScreen(widget.favoriteMeals), + 'title': 'Your Favorites', + }, + ]; + super.initState(); + } + + void _selectPage(int index) { + setState(() { + _selectedPageIndex = index; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(((_pages[_selectedPageIndex])['title']).toString()), + ), + drawer: MainDrawer(), + body: _pages[_selectedPageIndex]['page'], + bottomNavigationBar: BottomNavigationBar( + onTap: _selectPage, + backgroundColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.white, + selectedItemColor: Theme.of(context).colorScheme.secondary, + currentIndex: _selectedPageIndex, + // type: BottomNavigationBarType.shifting, + items: [ + BottomNavigationBarItem( + backgroundColor: Theme.of(context).primaryColor, + icon: Icon(Icons.category), + label: 'Categories', + ), + BottomNavigationBarItem( + backgroundColor: Theme.of(context).primaryColor, + icon: Icon(Icons.star), + label: 'Favorites', + ), + ], + ), + ); + } +} diff --git a/screens/taste_screen.dart b/screens/taste_screen.dart new file mode 100644 index 0000000..31fbba0 --- /dev/null +++ b/screens/taste_screen.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import '../dummy-data2.dart'; +import '../widgets/category_item2.dart'; + +class TasteScreen extends StatelessWidget { + // const TasteScreen({super.key}); + + @override + Widget build(BuildContext context) { + return GridView( + padding: const EdgeInsets.all(25), + children: DUMMY_CATEGORIES + .map( + (catData) => CategoryItem( + catData.id, + catData.title, + catData.color, + ), + ) + .toList(), + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + childAspectRatio: 3 / 2, + crossAxisSpacing: 20, + mainAxisSpacing: 20, + ), + ); + } +} diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..ed00b63 --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_complete_guide/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/widgets/category_item.dart b/widgets/category_item.dart new file mode 100644 index 0000000..6569fbe --- /dev/null +++ b/widgets/category_item.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import '../screens/category_meals_screen.dart'; +// import './categories_screen.dart'; + +class CategoryItem extends StatelessWidget { + final String id; + final String title; + final Color color; + + CategoryItem(this.id, this.title, this.color); + + void selectCategory(BuildContext ctx) { + Navigator.of(ctx).pushNamed( + CategoryMealsScreen.routeName, + arguments: { + 'id': id, + 'title': title, + }, + // MaterialPageRoute( + // builder: (_) { + // return CategoryMealsScreen(id, title); + // }, + // ), + ); + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => selectCategory(context), + splashColor: Theme.of(context).primaryColor, + borderRadius: BorderRadius.circular(15), + child: Container( + padding: const EdgeInsets.all(15), + child: Text( + title, + style: Theme.of(context).textTheme.headline6, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + color.withOpacity(0.7), + color, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(15), + ), + ), + ); + } +} diff --git a/widgets/category_item2.dart b/widgets/category_item2.dart new file mode 100644 index 0000000..6569fbe --- /dev/null +++ b/widgets/category_item2.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import '../screens/category_meals_screen.dart'; +// import './categories_screen.dart'; + +class CategoryItem extends StatelessWidget { + final String id; + final String title; + final Color color; + + CategoryItem(this.id, this.title, this.color); + + void selectCategory(BuildContext ctx) { + Navigator.of(ctx).pushNamed( + CategoryMealsScreen.routeName, + arguments: { + 'id': id, + 'title': title, + }, + // MaterialPageRoute( + // builder: (_) { + // return CategoryMealsScreen(id, title); + // }, + // ), + ); + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => selectCategory(context), + splashColor: Theme.of(context).primaryColor, + borderRadius: BorderRadius.circular(15), + child: Container( + padding: const EdgeInsets.all(15), + child: Text( + title, + style: Theme.of(context).textTheme.headline6, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + color.withOpacity(0.7), + color, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(15), + ), + ), + ); + } +} diff --git a/widgets/main_drawer.dart b/widgets/main_drawer.dart new file mode 100644 index 0000000..db084d2 --- /dev/null +++ b/widgets/main_drawer.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import '../screens/filters_screen.dart'; + +class MainDrawer extends StatelessWidget { + Widget buildListTile(String title, IconData icon, Function tapHandler) { + return ListTile( + leading: Icon( + icon, + size: 26, + ), + title: Text( + title, + style: TextStyle( + fontFamily: 'RobotoCondensed', + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + onTap: tapHandler, + ); + } + + @override + Widget build(BuildContext context) { + return Drawer( + child: Column( + children: [ + Container( + height: 120, + width: double.infinity, + padding: EdgeInsets.all(20), + alignment: Alignment.centerLeft, + color: Theme.of(context).colorScheme.secondary, + child: Text( + 'Cooking Up!', + style: TextStyle( + fontWeight: FontWeight.w900, + fontSize: 30, + color: Theme.of(context).primaryColor, + ), + ), + ), + SizedBox( + height: 20, + ), + buildListTile( + 'Meals', + Icons.restaurant, + () { + Navigator.of(context).pushReplacementNamed('/'); + }, + ), + buildListTile( + 'Filters', + Icons.settings, + () { + Navigator.of(context).pushReplacementNamed(FiltersScreen.routeName); + }, + ), + buildListTile( + 'Taste', + Icons.restaurant, + () { + Navigator.of(context).pushReplacementNamed('/'); + }, + ), + ], + ), + ); + } +} diff --git a/widgets/meal-item.dart b/widgets/meal-item.dart new file mode 100644 index 0000000..6a40dac --- /dev/null +++ b/widgets/meal-item.dart @@ -0,0 +1,162 @@ +import 'package:flutter/material.dart'; +import '../models/meal.dart'; +import '../screens/meal_detail_screen.dart'; + +class MealItem extends StatelessWidget { + final String id; + final String title; + final String imageUrl; + final int duration; + final Complexity complexity; + final Affordability affordability; + + MealItem({ + @required this.id, + @required this.title, + @required this.imageUrl, + @required this.duration, + @required this.affordability, + @required this.complexity, + }); + + String get complexityText { + switch (complexity) { + case Complexity.Simple: + return 'Simple'; + break; + case Complexity.Challenging: + return 'Challenging'; + break; + case Complexity.Hard: + return 'Hard'; + break; + default: + return 'Unknown'; + } + } + + String get affordabilityText { + switch (affordability) { + case Affordability.Affordable: + return 'Affordable'; + break; + case Affordability.Pricey: + return 'Pricey'; + break; + case Affordability.Luxurious: + return 'Expensive'; + break; + default: + return 'Unknown'; + } + } + + void selectMeal(BuildContext context) { + Navigator.of(context) + .pushNamed( + MealDetailScreen.routeName, + arguments: id, + ) + .then((result) { + if (result != null) { + // removeItem(result); + } + }); + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => selectMeal(context), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + elevation: 4, + margin: EdgeInsets.all(10), + child: Column( + children: [ + Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(15), + topRight: Radius.circular(15), + ), + child: Image.network( + imageUrl, + height: 250, + width: double.infinity, + fit: BoxFit.cover, + ), + ), + Positioned( + bottom: 20, + right: 10, + child: Container( + width: 300, + color: Colors.black54, + padding: EdgeInsets.symmetric( + vertical: 5, + horizontal: 20, + ), + child: Text( + title, + style: TextStyle( + fontSize: 26, + color: Colors.white, + ), + softWrap: true, + overflow: TextOverflow.fade, + ), + ), + ), + ], + ), + Padding( + padding: EdgeInsets.all(20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Row( + children: [ + Icon( + Icons.schedule, + ), + SizedBox( + width: 6, + ), + Text('$duration min'), + ], + ), + Row( + children: [ + Icon( + Icons.work, + ), + SizedBox( + width: 6, + ), + Text(complexityText), + ], + ), + Row( + children: [ + Icon( + Icons.attach_money, + ), + SizedBox( + width: 6, + ), + Text(affordabilityText), + ], + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/widgets/meal_item.dart b/widgets/meal_item.dart new file mode 100644 index 0000000..6a40dac --- /dev/null +++ b/widgets/meal_item.dart @@ -0,0 +1,162 @@ +import 'package:flutter/material.dart'; +import '../models/meal.dart'; +import '../screens/meal_detail_screen.dart'; + +class MealItem extends StatelessWidget { + final String id; + final String title; + final String imageUrl; + final int duration; + final Complexity complexity; + final Affordability affordability; + + MealItem({ + @required this.id, + @required this.title, + @required this.imageUrl, + @required this.duration, + @required this.affordability, + @required this.complexity, + }); + + String get complexityText { + switch (complexity) { + case Complexity.Simple: + return 'Simple'; + break; + case Complexity.Challenging: + return 'Challenging'; + break; + case Complexity.Hard: + return 'Hard'; + break; + default: + return 'Unknown'; + } + } + + String get affordabilityText { + switch (affordability) { + case Affordability.Affordable: + return 'Affordable'; + break; + case Affordability.Pricey: + return 'Pricey'; + break; + case Affordability.Luxurious: + return 'Expensive'; + break; + default: + return 'Unknown'; + } + } + + void selectMeal(BuildContext context) { + Navigator.of(context) + .pushNamed( + MealDetailScreen.routeName, + arguments: id, + ) + .then((result) { + if (result != null) { + // removeItem(result); + } + }); + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => selectMeal(context), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + elevation: 4, + margin: EdgeInsets.all(10), + child: Column( + children: [ + Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(15), + topRight: Radius.circular(15), + ), + child: Image.network( + imageUrl, + height: 250, + width: double.infinity, + fit: BoxFit.cover, + ), + ), + Positioned( + bottom: 20, + right: 10, + child: Container( + width: 300, + color: Colors.black54, + padding: EdgeInsets.symmetric( + vertical: 5, + horizontal: 20, + ), + child: Text( + title, + style: TextStyle( + fontSize: 26, + color: Colors.white, + ), + softWrap: true, + overflow: TextOverflow.fade, + ), + ), + ), + ], + ), + Padding( + padding: EdgeInsets.all(20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Row( + children: [ + Icon( + Icons.schedule, + ), + SizedBox( + width: 6, + ), + Text('$duration min'), + ], + ), + Row( + children: [ + Icon( + Icons.work, + ), + SizedBox( + width: 6, + ), + Text(complexityText), + ], + ), + Row( + children: [ + Icon( + Icons.attach_money, + ), + SizedBox( + width: 6, + ), + Text(affordabilityText), + ], + ), + ], + ), + ), + ], + ), + ), + ); + } +}