Skip to content

Commit d290e3f

Browse files
feat: hide past recipes during item adding (#1063)
Co-authored-by: Tom Bursch <tombursch@gmail.com>
1 parent c6e984d commit d290e3f

4 files changed

Lines changed: 103 additions & 26 deletions

File tree

kitchenowl/lib/cubits/item_selection_cubit.dart

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,19 @@ import 'package:kitchenowl/models/item.dart';
44
import 'package:kitchenowl/models/planner.dart';
55

66
class ItemSelectionCubit extends Cubit<ItemSelectionState> {
7-
ItemSelectionCubit(List<RecipePlan> plans)
8-
: super(
9-
ItemSelectionState(
10-
Map.fromEntries(plans.map(
11-
(e) => MapEntry(e, e.recipeWithYields.items),
12-
)),
13-
),
14-
);
7+
ItemSelectionCubit(List<RecipePlan> plans) : super(ItemSelectionState(plans));
8+
9+
bool _isPastPlan(RecipePlan plan) {
10+
if (plan.cookingDate == null || plan.isWithoutPlannedDay) return false;
11+
final now = DateTime.now();
12+
final today = DateTime(now.year, now.month, now.day);
13+
final planDay = DateTime(
14+
plan.cookingDate!.year,
15+
plan.cookingDate!.month,
16+
plan.cookingDate!.day,
17+
);
18+
return planDay.isBefore(today);
19+
}
1520

1621
void toggleItem(RecipePlan recipe, RecipeItem item) {
1722
final s = Map.of(state.selectedItems);
@@ -40,35 +45,90 @@ class ItemSelectionCubit extends Cubit<ItemSelectionState> {
4045
emit(state.copyWith(selectedItems: s));
4146
}
4247

48+
void toggleHidePastPlans() {
49+
final newHide = !state.hidePastPlans;
50+
if (newHide) {
51+
final s = Map.of(state.selectedItems);
52+
for (final plan in s.keys) {
53+
if (_isPastPlan(plan)) s[plan] = {};
54+
}
55+
emit(state.copyWith(hidePastPlans: newHide, selectedItems: s));
56+
} else {
57+
emit(state.copyWith(hidePastPlans: newHide));
58+
}
59+
}
60+
4361
List<RecipeItem> getResult() {
4462
return state.getResult();
4563
}
4664
}
4765

4866
class ItemSelectionState extends Equatable {
67+
final List<RecipePlan> plans;
4968
final Map<RecipePlan, Set<RecipeItem>> selectedItems;
69+
final bool hidePastPlans;
5070

51-
ItemSelectionState(Map<RecipePlan, List<RecipeItem>> items)
52-
: this.withSelection(
53-
items.map((key, value) =>
54-
MapEntry(key, value.where((e) => !e.optional).toSet())),
71+
ItemSelectionState(
72+
this.plans, {
73+
this.hidePastPlans = true,
74+
}) : selectedItems = Map.fromEntries(
75+
plans.map((plan) {
76+
final now = DateTime.now();
77+
final today = DateTime(now.year, now.month, now.day);
78+
var isPast = false;
79+
if (plan.cookingDate != null && !plan.isWithoutPlannedDay) {
80+
final planDay = DateTime(
81+
plan.cookingDate!.year,
82+
plan.cookingDate!.month,
83+
plan.cookingDate!.day,
84+
);
85+
isPast = planDay.isBefore(today);
86+
}
87+
return MapEntry(
88+
plan,
89+
isPast
90+
? <RecipeItem>{}
91+
: plan.recipeWithYields.mandatoryItems.toSet(),
92+
);
93+
}),
5594
);
5695

57-
const ItemSelectionState.withSelection(this.selectedItems);
58-
59-
const ItemSelectionState._all({
96+
const ItemSelectionState._({
97+
required this.plans,
6098
required this.selectedItems,
99+
required this.hidePastPlans,
61100
});
62101

63102
ItemSelectionState copyWith({
103+
List<RecipePlan>? plans,
64104
Map<RecipePlan, Set<RecipeItem>>? selectedItems,
105+
bool? hidePastPlans,
65106
}) =>
66-
ItemSelectionState._all(
107+
ItemSelectionState._(
108+
plans: plans ?? this.plans,
67109
selectedItems: selectedItems ?? this.selectedItems,
110+
hidePastPlans: hidePastPlans ?? this.hidePastPlans,
111+
);
112+
113+
List<RecipePlan> get filteredPlans {
114+
if (!hidePastPlans) return plans;
115+
116+
final now = DateTime.now();
117+
final today = DateTime(now.year, now.month, now.day);
118+
119+
return plans.where((plan) {
120+
if (plan.cookingDate == null || plan.isWithoutPlannedDay) return true;
121+
final planDay = DateTime(
122+
plan.cookingDate!.year,
123+
plan.cookingDate!.month,
124+
plan.cookingDate!.day,
68125
);
126+
return !planDay.isBefore(today);
127+
}).toList();
128+
}
69129

70130
@override
71-
List<Object?> get props => selectedItems.values.toList();
131+
List<Object?> get props => [plans, selectedItems, hidePastPlans];
72132

73133
List<RecipeItem> getResult() {
74134
return selectedItems.values.expand((e) => e).toList();

kitchenowl/lib/l10n/app_en.arb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@
601601
"grid": "Grid",
602602
"helpTranslate": "Help translate",
603603
"hi": "Hi {name}!",
604+
"hidePastPlans": "Hide past plans",
604605
"household": "Household",
605606
"householdDelete": "Delete household",
606607
"householdDeleteConfirmation": "Are you sure you want to delete {household}? This will delete any items, recipes, and expenses associated with that household.",
@@ -750,6 +751,7 @@
750751
"shoppingListKeepAwake": "Keep screen on while shopping",
751752
"shoppingListStyle": "Shopping list style",
752753
"shoppingLists": "Shopping lists",
754+
"showPastPlans": "Show all plans",
753755
"signInWith": "Sign in with {provider}",
754756
"signup": "Sign up",
755757
"skip": "Skip",

kitchenowl/lib/models/planner.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,8 @@ class RecipePlan extends Model {
4343
..addAll({
4444
"recipe": recipe.toJson(),
4545
});
46+
47+
bool get isWithoutPlannedDay =>
48+
cookingDate == null ||
49+
(cookingDate != null && cookingDate!.millisecondsSinceEpoch < 0);
4650
}

kitchenowl/lib/pages/item_selection_page.dart

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,26 @@ class _ItemSelectionPageState extends State<ItemSelectionPage> {
4545

4646
@override
4747
Widget build(BuildContext context) {
48-
return Scaffold(
49-
appBar: AppBar(
50-
title: Text(widget.title ?? AppLocalizations.of(context)!.itemsAdd),
51-
),
52-
body: BlocBuilder<ItemSelectionCubit, ItemSelectionState>(
53-
bloc: cubit,
54-
builder: (context, state) => CustomScrollView(
48+
return BlocBuilder<ItemSelectionCubit, ItemSelectionState>(
49+
bloc: cubit,
50+
builder: (context, state) => Scaffold(
51+
appBar: AppBar(
52+
title: Text(widget.title ?? AppLocalizations.of(context)!.itemsAdd),
53+
actions: [
54+
IconButton(
55+
icon: Icon(
56+
state.hidePastPlans ? Icons.filter_alt_off : Icons.filter_alt,
57+
),
58+
tooltip: state.hidePastPlans
59+
? AppLocalizations.of(context)!.showPastPlans
60+
: AppLocalizations.of(context)!.hidePastPlans,
61+
onPressed: cubit.toggleHidePastPlans,
62+
),
63+
],
64+
),
65+
body: CustomScrollView(
5566
slivers: [
56-
for (final plan in widget.plans) ...[
67+
for (final plan in state.filteredPlans) ...[
5768
if (plan.recipe.items.isNotEmpty)
5869
SliverToBoxAdapter(
5970
child: CheckboxListTile(
@@ -145,7 +156,7 @@ class _ItemSelectionPageState extends State<ItemSelectionPage> {
145156
builder: (context) => SelectDialog(
146157
title: AppLocalizations.of(context)!
147158
.addNumberIngredients(
148-
state.selectedItems.length),
159+
state.getResult().length),
149160
cancelText:
150161
AppLocalizations.of(context)!.cancel,
151162
options: widget.shoppingLists

0 commit comments

Comments
 (0)