consistent, improved deduplication behavior across mealitems and logs

deduplicate by ingredient AND amount: so if you use the same
ingredient, but in a different amount, the different amount
will show up
this increases the list of suggestions for editing meals,
and decreases the list logging an ingredient (significantly,
if you often log the same ingredient in the same amount)
This commit is contained in:
Dieter Plaetinck
2024-05-28 11:54:55 +02:00
parent 68799b0112
commit a4bdf70582
5 changed files with 28 additions and 13 deletions

View File

@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:json_annotation/json_annotation.dart';
@@ -191,16 +192,16 @@ class NutritionalPlan {
return out;
}
/// Helper that returns all meal items for the current plan
///
/// Duplicated ingredients are removed
List<MealItem> get allMealItems {
/// returns meal items across all meals
/// deduped by the combination of amount and ingredient ID
List<MealItem> get dedupMealItems {
final List<MealItem> out = [];
for (final meal in meals) {
for (final mealItem in meal.mealItems) {
final ingredientInList = out.where((e) => e.ingredientId == mealItem.ingredientId);
final found = out.firstWhereOrNull(
(e) => e.amount == mealItem.amount && e.ingredientId == mealItem.ingredientId);
if (ingredientInList.isEmpty) {
if (found == null) {
out.add(mealItem);
}
}
@@ -208,6 +209,20 @@ class NutritionalPlan {
return out;
}
/// returns diary entries
/// deduped by the combination of amount and ingredient ID
List<Log> get dedupDiaryEntries {
final out = <Log>[];
for (final log in diaryEntries) {
final found =
out.firstWhereOrNull((e) => e.amount == log.amount && e.ingredientId == log.ingredientId);
if (found == null) {
out.add(log);
}
}
return out;
}
Meal pseudoMealOthers(String name) {
return Meal(
id: PSEUDO_MEAL_ID,

View File

@@ -131,7 +131,7 @@ Widget MealItemForm(Meal meal, List<MealItem> recent, [String? barcode, bool? te
Widget IngredientLogForm(NutritionalPlan plan) {
return IngredientForm(
recent: plan.diaryEntries,
recent: plan.dedupDiaryEntries,
onSave: (BuildContext context, MealItem mealItem, DateTime? dt) {
Provider.of<NutritionPlansProvider>(context, listen: false)
.logIngredientToDiary(mealItem, plan.id!, dt);

View File

@@ -39,11 +39,11 @@ enum viewMode {
class MealWidget extends StatefulWidget {
final Meal _meal;
final List<MealItem> _listMealItems;
final List<MealItem> _recentMealItems;
const MealWidget(
this._meal,
this._listMealItems,
this._recentMealItems,
);
@override
@@ -108,7 +108,7 @@ class _MealWidgetState extends State<MealWidget> {
FormScreen.routeName,
arguments: FormScreenArguments(
AppLocalizations.of(context).addIngredient,
MealItemForm(widget._meal, widget._listMealItems),
MealItemForm(widget._meal, widget._recentMealItems),
hasListView: true,
),
);

View File

@@ -56,11 +56,11 @@ class NutritionalPlanDetailWidget extends StatelessWidget {
const SizedBox(height: 10),
..._nutritionalPlan.meals.map((meal) => MealWidget(
meal,
_nutritionalPlan.allMealItems,
_nutritionalPlan.dedupMealItems,
)),
MealWidget(
_nutritionalPlan.pseudoMealOthers('Other logs'),
_nutritionalPlan.allMealItems,
_nutritionalPlan.dedupMealItems,
),
if (!_nutritionalPlan.onlyLogging)
Padding(

View File

@@ -101,7 +101,7 @@ void main() {
});
test('Test that the getter returns all meal items for a plan', () {
expect(plan.allMealItems, plan.meals[0].mealItems + plan.meals[1].mealItems);
expect(plan.dedupMealItems, plan.meals[0].mealItems + plan.meals[1].mealItems);
});
});
}