flutter_meal final

This commit is contained in:
Gogs
2024-03-11 15:49:06 +01:00
parent 4d170f524c
commit e3931d8b82
6 changed files with 182 additions and 144 deletions
+1 -1
View File
@@ -40,4 +40,4 @@ class Meal {
final bool isLactoseFree; final bool isLactoseFree;
final bool isVegan; final bool isVegan;
final bool isVegetarian; final bool isVegetarian;
} }
+3 -1
View File
@@ -10,12 +10,14 @@ class CategoriesScreen extends StatelessWidget {
const CategoriesScreen({ const CategoriesScreen({
super.key, super.key,
required this.onToggleFavorites, required this.onToggleFavorites,
required this.availableMeals,
}); });
final void Function(Meal meal) onToggleFavorites; final void Function(Meal meal) onToggleFavorites;
final List<Meal> availableMeals;
void _selectCategory(BuildContext context, Category category) { void _selectCategory(BuildContext context, Category category) {
final filteredMeals = dummyMeals final filteredMeals = availableMeals
.where((meal) => meal.categories.contains(category.id)) .where((meal) => meal.categories.contains(category.id))
.toList(); .toList();
+117 -86
View File
@@ -3,11 +3,21 @@ import 'package:flutter/material.dart';
// import 'package:flutter_navigation/screens/tabs.dart'; // import 'package:flutter_navigation/screens/tabs.dart';
// import 'package:flutter_navigation/widgets/main_drawer.dart'; // import 'package:flutter_navigation/widgets/main_drawer.dart';
enum Filter {
glutenFree,
lactoseFree,
vegetarien,
vegan,
}
class FiltersScreen extends StatefulWidget { class FiltersScreen extends StatefulWidget {
const FiltersScreen({ const FiltersScreen({
super.key, super.key,
required this.currentFilters,
}); });
final Map<Filter, bool> currentFilters;
@override @override
State<StatefulWidget> createState() { State<StatefulWidget> createState() {
return _FiltersScreenState(); return _FiltersScreenState();
@@ -20,6 +30,16 @@ class _FiltersScreenState extends State<FiltersScreen> {
var _vegetarianFilterSet = false; var _vegetarianFilterSet = false;
var _veganFilterSet = false; var _veganFilterSet = false;
@override
void initState() {
super.initState();
_glutenFilterSet = widget.currentFilters[Filter.glutenFree]!;
_lactoseFilterSet = widget.currentFilters[Filter.lactoseFree]!;
_vegetarianFilterSet = widget.currentFilters[Filter.vegetarien]!;
_veganFilterSet = widget.currentFilters[Filter.vegan]!;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@@ -38,96 +58,107 @@ class _FiltersScreenState extends State<FiltersScreen> {
// } // }
// }, // },
// ), // ),
body: Column(children: [ body: WillPopScope(
SwitchListTile( onWillPop: () async {
value: _glutenFilterSet, Navigator.of(context).pop({
onChanged: (isChecked) { Filter.glutenFree: _glutenFilterSet,
setState(() { Filter.lactoseFree: _lactoseFilterSet,
_glutenFilterSet = isChecked; Filter.vegetarien: _vegetarianFilterSet,
}); Filter.vegan: _veganFilterSet,
}, });
title: Text( return false;
'Gluten-free', },
style: Theme.of(context).textTheme.titleLarge!.copyWith( child: Column(children: [
color: Theme.of(context).colorScheme.onBackground, SwitchListTile(
), value: _glutenFilterSet,
onChanged: (isChecked) {
setState(() {
_glutenFilterSet = isChecked;
});
},
title: Text(
'Gluten-free',
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
subtitle: Text(
'Only include gluten-free meals.',
style: Theme.of(context).textTheme.labelMedium!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
activeColor: Theme.of(context).colorScheme.tertiary,
contentPadding: const EdgeInsets.only(left: 34, right: 22),
), ),
subtitle: Text( SwitchListTile(
'Only include gluten-free meals.', value: _lactoseFilterSet,
style: Theme.of(context).textTheme.labelMedium!.copyWith( onChanged: (isChecked) {
color: Theme.of(context).colorScheme.onBackground, setState(() {
), _lactoseFilterSet = isChecked;
});
},
title: Text(
'Lactose-free',
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
subtitle: Text(
'Only include lactose-free meals.',
style: Theme.of(context).textTheme.labelMedium!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
activeColor: Theme.of(context).colorScheme.tertiary,
contentPadding: const EdgeInsets.only(left: 34, right: 22),
), ),
activeColor: Theme.of(context).colorScheme.tertiary, SwitchListTile(
contentPadding: const EdgeInsets.only(left: 34, right: 22), value: _vegetarianFilterSet,
), onChanged: (isChecked) {
SwitchListTile( setState(() {
value: _lactoseFilterSet, _vegetarianFilterSet = isChecked;
onChanged: (isChecked) { });
setState(() { },
_lactoseFilterSet = isChecked; title: Text(
}); 'Vegetarian',
}, style: Theme.of(context).textTheme.titleLarge!.copyWith(
title: Text( color: Theme.of(context).colorScheme.onBackground,
'Lactose-free', ),
style: Theme.of(context).textTheme.titleLarge!.copyWith( ),
color: Theme.of(context).colorScheme.onBackground, subtitle: Text(
), 'Only include vegetarian meals.',
style: Theme.of(context).textTheme.labelMedium!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
activeColor: Theme.of(context).colorScheme.tertiary,
contentPadding: const EdgeInsets.only(left: 34, right: 22),
), ),
subtitle: Text( SwitchListTile(
'Only include lactose-free meals.', value: _veganFilterSet,
style: Theme.of(context).textTheme.labelMedium!.copyWith( onChanged: (isChecked) {
color: Theme.of(context).colorScheme.onBackground, setState(() {
), _veganFilterSet = isChecked;
});
},
title: Text(
'Vegan',
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
subtitle: Text(
'Only include vegan meals.',
style: Theme.of(context).textTheme.labelMedium!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
activeColor: Theme.of(context).colorScheme.tertiary,
contentPadding: const EdgeInsets.only(left: 34, right: 22),
), ),
activeColor: Theme.of(context).colorScheme.tertiary, ]),
contentPadding: const EdgeInsets.only(left: 34, right: 22), ),
),
SwitchListTile(
value: _vegetarianFilterSet,
onChanged: (isChecked) {
setState(() {
_vegetarianFilterSet = isChecked;
});
},
title: Text(
'Vegetarian',
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
subtitle: Text(
'Only include vegetarian meals.',
style: Theme.of(context).textTheme.labelMedium!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
activeColor: Theme.of(context).colorScheme.tertiary,
contentPadding: const EdgeInsets.only(left: 34, right: 22),
),
SwitchListTile(
value: _veganFilterSet,
onChanged: (isChecked) {
setState(() {
_veganFilterSet = isChecked;
});
},
title: Text(
'Vegan',
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
subtitle: Text(
'Only include vegan meals.',
style: Theme.of(context).textTheme.labelMedium!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
activeColor: Theme.of(context).colorScheme.tertiary,
contentPadding: const EdgeInsets.only(left: 34, right: 22),
),
]),
); );
} }
} }
+39 -3
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_navigation/data/dummy_data.dart';
import 'package:flutter_navigation/screens/categories.dart'; import 'package:flutter_navigation/screens/categories.dart';
import 'package:flutter_navigation/screens/meals.dart'; import 'package:flutter_navigation/screens/meals.dart';
import 'package:flutter_navigation/widgets/main_drawer.dart'; import 'package:flutter_navigation/widgets/main_drawer.dart';
@@ -6,6 +7,13 @@ import 'package:flutter_navigation/widgets/main_drawer.dart';
import '../models/meal.dart'; import '../models/meal.dart';
import 'filters.dart'; import 'filters.dart';
const kInitialFilters = {
Filter.glutenFree: false,
Filter.lactoseFree: false,
Filter.vegetarien: false,
Filter.vegan: false,
};
class TabsScreen extends StatefulWidget { class TabsScreen extends StatefulWidget {
const TabsScreen({super.key}); const TabsScreen({super.key});
@@ -18,6 +26,7 @@ class TabsScreen extends StatefulWidget {
class _TabsScreenState extends State<TabsScreen> { class _TabsScreenState extends State<TabsScreen> {
int _selectedPageIndex = 0; int _selectedPageIndex = 0;
final List<Meal> _favoriteMeals = []; final List<Meal> _favoriteMeals = [];
Map<Filter, bool> _selectedFilters = kInitialFilters;
void _showInfoMessage(String message) { void _showInfoMessage(String message) {
ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).clearSnackBars();
@@ -46,21 +55,48 @@ class _TabsScreenState extends State<TabsScreen> {
}); });
} }
void _setScreen(String identifier) { void _setScreen(String identifier) async {
Navigator.of(context).pop(); Navigator.of(context).pop();
if (identifier == 'filters') { if (identifier == 'filters') {
Navigator.of(context).push( final result = await Navigator.of(context).push<Map<Filter, bool>>(
MaterialPageRoute( MaterialPageRoute(
builder: (ctx) => const FiltersScreen(), builder: (ctx) => FiltersScreen(
currentFilters: _selectedFilters,
),
), ),
); );
setState(() {
_selectedFilters = result ?? kInitialFilters;
});
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final availableMeals = dummyMeals.where((meal) {
if (_selectedFilters[Filter.glutenFree]! && !meal.isGlutenFree) {
return false;
}
if (_selectedFilters[Filter.lactoseFree]! && !meal.isLactoseFree) {
return false;
}
if (_selectedFilters[Filter.vegetarien]! && !meal.isVegetarian) {
return false;
}
if (_selectedFilters[Filter.vegan]! && !meal.isVegan) {
return false;
}
return true;
}).toList();
Widget activePage = CategoriesScreen( Widget activePage = CategoriesScreen(
onToggleFavorites: _toggleMealFavoriteStatus, onToggleFavorites: _toggleMealFavoriteStatus,
availableMeals: availableMeals,
); );
var activePageTitle = 'Categories'; var activePageTitle = 'Categories';
+2 -2
View File
@@ -34,8 +34,8 @@ class CategoryGridItem extends StatelessWidget {
child: Text( child: Text(
category.title, category.title,
style: Theme.of(context).textTheme.titleLarge!.copyWith( style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground, color: Theme.of(context).colorScheme.onBackground,
), ),
), ),
), ),
); );
+20 -51
View File
@@ -1,7 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class MainDrawer extends StatelessWidget { class MainDrawer extends StatelessWidget {
const MainDrawer({ super.key, required this .onSelectScreen,}); const MainDrawer({
super.key,
required this.onSelectScreen,
});
final void Function(String identifier) onSelectScreen; final void Function(String identifier) onSelectScreen;
@@ -15,12 +18,8 @@ class MainDrawer extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
colors: [ colors: [
Theme Theme.of(context).colorScheme.primaryContainer,
.of(context) Theme.of(context)
.colorScheme
.primaryContainer,
Theme
.of(context)
.colorScheme .colorScheme
.primaryContainer .primaryContainer
.withOpacity(0.8), .withOpacity(0.8),
@@ -34,24 +33,14 @@ class MainDrawer extends StatelessWidget {
Icon( Icon(
Icons.fastfood, Icons.fastfood,
size: 48, size: 48,
color: Theme color: Theme.of(context).colorScheme.primary,
.of(context)
.colorScheme
.primary,
), ),
const SizedBox(width: 18), const SizedBox(width: 18),
Text( Text(
'Cooking Up!', 'Cooking Up!',
style: Theme style: Theme.of(context).textTheme.titleLarge!.copyWith(
.of(context) color: Theme.of(context).colorScheme.primary,
.textTheme ),
.titleLarge!
.copyWith(
color: Theme
.of(context)
.colorScheme
.primary,
),
) )
], ],
), ),
@@ -60,24 +49,14 @@ class MainDrawer extends StatelessWidget {
leading: Icon( leading: Icon(
Icons.restaurant, Icons.restaurant,
size: 26, size: 26,
color: Theme color: Theme.of(context).colorScheme.onBackground,
.of(context)
.colorScheme
.onBackground,
), ),
title: Text( title: Text(
'Meals', 'Meals',
style: Theme style: Theme.of(context).textTheme.titleSmall!.copyWith(
.of(context) color: Theme.of(context).colorScheme.onBackground,
.textTheme fontSize: 24,
.titleSmall! ),
.copyWith(
color: Theme
.of(context)
.colorScheme
.onBackground,
fontSize: 24,
),
), ),
onTap: () { onTap: () {
onSelectScreen('meals'); onSelectScreen('meals');
@@ -87,24 +66,14 @@ class MainDrawer extends StatelessWidget {
leading: Icon( leading: Icon(
Icons.settings, Icons.settings,
size: 26, size: 26,
color: Theme color: Theme.of(context).colorScheme.onBackground,
.of(context)
.colorScheme
.onBackground,
), ),
title: Text( title: Text(
'Filters', 'Filters',
style: Theme style: Theme.of(context).textTheme.titleSmall!.copyWith(
.of(context) color: Theme.of(context).colorScheme.onBackground,
.textTheme fontSize: 24,
.titleSmall! ),
.copyWith(
color: Theme
.of(context)
.colorScheme
.onBackground,
fontSize: 24,
),
), ),
onTap: () { onTap: () {
onSelectScreen('filters'); onSelectScreen('filters');