1. filter 상태값도 provider로 설정해보자.
- providers/filters_provider.dart(new)
import 'package:flutter_riverpod/flutter_riverpod.dart';
enum Filter {
glutenFree,
lactoseFree,
vegetarian,
vegan,
}
class FiltersNotifier extends StateNotifier<Map<Filter, bool>> {
FiltersNotifier()
: super({
Filter.glutenFree: false,
Filter.lactoseFree: false,
Filter.vegetarian: false,
Filter.vegan: false
});
void setFilters(Map<Filter, bool> chosenFilters) {
state = chosenFilters;
}
void setFilter(Filter filter, bool isActive) {
// state[filter] = isActive; // not allowed! => mutating state
state = {
...state,
filter: isActive,
};
}
}
final filtersProvider =
StateNotifierProvider<FiltersNotifier, Map<Filter, bool>>(
(ref) => FiltersNotifier(),
);
super를 통해 초기값 설정.
1) 이전 favorites_provider.dart와 유사하다.
2) setFilters (최종 선택된 값), setFilter(새롭게 설정한 값) 함수를 만들어주었다.
3) 이제 기존 위 값을 사용했던 위젯들의 값을 삭제해주고, 위 provider를 연결해주자.
- filters.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// import 'package:meals/screens/tabs.dart';
// import 'package:meals/widgets/main_drawer.dart';
import 'package:meals/providers/filters_provider.dart';
class FiltersScreen extends ConsumerStatefulWidget {
const FiltersScreen({super.key});
@override
ConsumerState<FiltersScreen> createState() {
return _FiltersScreenState();
}
}
class _FiltersScreenState extends ConsumerState<FiltersScreen> {
var _glutenFreeFilterSet = false;
var _lactoseFreeFilterSet = false;
var _vegetarianFilterSet = false;
var _veganFilterSet = false;
@override
void initState() {
super.initState();
final activeFilters = ref.read(filtersProvider);
_glutenFreeFilterSet = activeFilters[Filter.glutenFree]!;
_lactoseFreeFilterSet = activeFilters[Filter.lactoseFree]!;
_vegetarianFilterSet = activeFilters[Filter.vegetarian]!;
_veganFilterSet = activeFilters[Filter.vegan]!;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Your Filters'),
),
// drawer: MainDrawer(
// onSelectScreen: (identifier) {
// Navigator.of(context).pop();
// if (identifier == 'meals') {
// Navigator.of(context).pushReplacement(
// MaterialPageRoute(
// builder: (ctx) => const TabsScreen(),
// ),
// );
// }
// },
// ),
body: WillPopScope(
onWillPop: () async {
ref.read(filtersProvider.notifier).setFilters({
Filter.glutenFree: _glutenFreeFilterSet,
Filter.lactoseFree: _lactoseFreeFilterSet,
Filter.vegetarian: _vegetarianFilterSet,
Filter.vegan: _veganFilterSet,
});
// Navigator.of(context).pop();
return true;
},
child: Column(
children: [
SwitchListTile(
value: _glutenFreeFilterSet,
onChanged: (isChecked) {
setState(() {
_glutenFreeFilterSet = 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),
),
SwitchListTile(
value: _lactoseFreeFilterSet,
onChanged: (isChecked) {
setState(() {
_lactoseFreeFilterSet = 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),
),
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),
),
],
),
),
);
}
}
ㅇ1) initState부분에 ref를 통해 filterProvider값을 연결해주었다. init값은 초기값으로 한번만 쓰이기 떄문에 read를 사용한다.
2) onWillPop의 기존값은 뒤로 갈때 값을 전달해주는것이었는데, 이제 provider로 값을 전달해준다. 그리고 return은 true로 변경해준다. (기존 pop뒤로 가기가 없어졌기 때문에 뒤로 가야함.)
- tabs.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:meals/screens/categories.dart';
import 'package:meals/screens/filters.dart';
import 'package:meals/screens/meals.dart';
import 'package:meals/widgets/main_drawer.dart';
import 'package:meals/providers/meals_provider.dart';
import 'package:meals/providers/favorites_provider.dart';
import 'package:meals/providers/filters_provider.dart';
const kInitialFilters = {
Filter.glutenFree: false,
Filter.lactoseFree: false,
Filter.vegetarian: false,
Filter.vegan: false
};
class TabsScreen extends ConsumerStatefulWidget {
const TabsScreen({super.key});
@override
ConsumerState<TabsScreen> createState() {
return _TabsScreenState();
}
}
class _TabsScreenState extends ConsumerState<TabsScreen> {
int _selectedPageIndex = 0;
void _selectPage(int index) {
setState(() {
_selectedPageIndex = index;
});
}
void _setScreen(String identifier) async {
Navigator.of(context).pop();
if (identifier == 'filters') {
await Navigator.of(context).push<Map<Filter, bool>>(
MaterialPageRoute(
builder: (ctx) => const FiltersScreen(),
),
);
}
}
@override
Widget build(BuildContext context) {
final meals = ref.watch(mealsProvider);
final activeFilters = ref.watch(filtersProvider);
final availableMeals = meals.where((meal) {
if (activeFilters[Filter.glutenFree]! && !meal.isGlutenFree) {
return false;
}
if (activeFilters[Filter.lactoseFree]! && !meal.isLactoseFree) {
return false;
}
if (activeFilters[Filter.vegetarian]! && !meal.isVegetarian) {
return false;
}
if (activeFilters[Filter.vegan]! && !meal.isVegan) {
return false;
}
return true;
}).toList();
Widget activePage = CategoriesScreen(
availableMeals: availableMeals,
);
var activePageTitle = 'Categories';
if (_selectedPageIndex == 1) {
final favoriteMeals = ref.watch(favoriteMealsProvider);
activePage = MealsScreen(
meals: favoriteMeals,
);
activePageTitle = 'Your Favorites';
}
return Scaffold(
appBar: AppBar(
title: Text(activePageTitle),
),
drawer: MainDrawer(
onSelectScreen: _setScreen,
),
body: activePage,
bottomNavigationBar: BottomNavigationBar(
onTap: _selectPage,
currentIndex: _selectedPageIndex,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.set_meal),
label: 'Categories',
),
BottomNavigationBarItem(
icon: Icon(Icons.star),
label: 'Favorites',
),
],
),
);
}
}
1) availableMeals 부분도 provider와 연결
--> 다음 강의에 이어서 내용 추가
'코딩강의 > meals_app(플러터-유데미)' 카테고리의 다른 글
189. Connecting Multiple Providers With Each Other (Dependent Providers) (0) | 2023.11.05 |
---|---|
188. Outsourcing State Into The Provider (0) | 2023.11.05 |
~185. Triggering a Notifier Method (0) | 2023.11.02 |
~182. Using a Provider (0) | 2023.11.02 |
~174. Applying Filters (네비게이션 강의 부분 마지막) (0) | 2023.11.01 |