Skip to content

Commit 68799b0

Browse files
committed
log meal: separate confirmation page with portion choice
1 parent 436ee2a commit 68799b0

File tree

5 files changed

+196
-11
lines changed

5 files changed

+196
-11
lines changed

lib/main.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import 'package:wger/screens/form_screen.dart';
3838
import 'package:wger/screens/gallery_screen.dart';
3939
import 'package:wger/screens/gym_mode.dart';
4040
import 'package:wger/screens/home_tabs_screen.dart';
41+
import 'package:wger/screens/log_meal_screen.dart';
4142
import 'package:wger/screens/measurement_categories_screen.dart';
4243
import 'package:wger/screens/measurement_entries_screen.dart';
4344
import 'package:wger/screens/nutritional_diary_screen.dart';
@@ -158,6 +159,7 @@ class MyApp extends StatelessWidget {
158159
NutritionalPlansScreen.routeName: (ctx) => NutritionalPlansScreen(),
159160
NutritionalDiaryScreen.routeName: (ctx) => NutritionalDiaryScreen(),
160161
NutritionalPlanScreen.routeName: (ctx) => NutritionalPlanScreen(),
162+
LogMealScreen.routeName: (ctx) => LogMealScreen(),
161163
WeightScreen.routeName: (ctx) => WeightScreen(),
162164
WorkoutPlanScreen.routeName: (ctx) => WorkoutPlanScreen(),
163165
WorkoutPlansScreen.routeName: (ctx) => WorkoutPlansScreen(),

lib/models/nutrition/meal.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,22 @@ class Meal {
8888
factory Meal.fromJson(Map<String, dynamic> json) => _$MealFromJson(json);
8989

9090
Map<String, dynamic> toJson() => _$MealToJson(this);
91+
92+
Meal copyWith({
93+
int? id,
94+
int? planId,
95+
TimeOfDay? time,
96+
String? name,
97+
List<MealItem>? mealItems,
98+
List<Log>? diaryEntries,
99+
}) {
100+
return Meal(
101+
id: id ?? this.id,
102+
plan: planId ?? this.planId,
103+
time: time ?? this.time,
104+
name: name ?? this.name,
105+
mealItems: mealItems ?? this.mealItems,
106+
diaryEntries: diaryEntries ?? this.diaryEntries,
107+
);
108+
}
91109
}

lib/models/nutrition/meal_item.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,25 @@ class MealItem {
9191

9292
return out;
9393
}
94+
95+
MealItem copyWith({
96+
int? id,
97+
int? mealId,
98+
int? ingredientId,
99+
int? weightUnitId,
100+
num? amount,
101+
Ingredient? ingredient,
102+
IngredientWeightUnit? weightUnitObj,
103+
}) {
104+
final m = MealItem(
105+
id: id ?? this.id,
106+
mealId: mealId ?? this.mealId,
107+
ingredientId: ingredientId ?? this.ingredientId,
108+
weightUnitId: weightUnitId ?? this.weightUnitId,
109+
amount: amount ?? this.amount,
110+
ingredient: ingredient ?? this.ingredient,
111+
);
112+
m.weightUnitObj = weightUnitObj ?? this.weightUnitObj;
113+
return m;
114+
}
94115
}

lib/screens/log_meal_screen.dart

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
* This file is part of wger Workout Manager <https://github.com/wger-project>.
3+
* Copyright (C) 2020, 2021 wger Team
4+
*
5+
* wger Workout Manager is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* wger Workout Manager is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
import 'package:flutter/material.dart';
20+
import 'package:flutter/services.dart';
21+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
22+
import 'package:provider/provider.dart';
23+
import 'package:wger/models/nutrition/meal.dart';
24+
import 'package:wger/models/nutrition/meal_item.dart';
25+
import 'package:wger/providers/nutrition.dart';
26+
import 'package:wger/widgets/nutrition/meal.dart';
27+
import 'package:wger/widgets/nutrition/widgets.dart';
28+
29+
class LogMealArguments {
30+
final Meal meal;
31+
32+
LogMealArguments(this.meal);
33+
}
34+
35+
class LogMealScreen extends StatefulWidget {
36+
static const routeName = '/log-meal';
37+
38+
@override
39+
State<LogMealScreen> createState() => _LogMealScreenState();
40+
}
41+
42+
class _LogMealScreenState extends State<LogMealScreen> {
43+
late TextEditingController _controller;
44+
int portionPct = 100;
45+
46+
@override
47+
void initState() {
48+
super.initState();
49+
_controller = TextEditingController();
50+
}
51+
52+
@override
53+
void dispose() {
54+
_controller.dispose();
55+
super.dispose();
56+
}
57+
58+
@override
59+
Widget build(BuildContext context) {
60+
final args = ModalRoute.of(context)!.settings.arguments as LogMealArguments;
61+
_controller.text = portionPct.toString();
62+
final meal = args.meal.copyWith(
63+
mealItems: args.meal.mealItems
64+
.map((mealItem) => mealItem.copyWith(amount: mealItem.amount * portionPct / 100))
65+
.toList());
66+
67+
return Scaffold(
68+
appBar: AppBar(
69+
title: Text('Log meal to diary'),
70+
),
71+
body: Consumer<NutritionPlansProvider>(
72+
builder: (context, nutritionProvider, child) => SingleChildScrollView(
73+
child: Padding(
74+
padding: const EdgeInsets.all(8.0),
75+
child: Column(
76+
children: [
77+
Text(meal.name, style: Theme.of(context).textTheme.headlineSmall),
78+
if (meal.mealItems.isEmpty)
79+
const ListTile(title: Text('No ingredients defined yet'))
80+
else
81+
Column(
82+
children: [
83+
const NutritionDiaryheader(),
84+
...meal.mealItems
85+
.map((item) => MealItemWidget(item, viewMode.withAllDetails, false)),
86+
Row(
87+
children: [
88+
Text('Portion size'),
89+
Expanded(
90+
child: TextField(
91+
maxLength: 4,
92+
maxLengthEnforcement: MaxLengthEnforcement.enforced,
93+
keyboardType: TextInputType.number,
94+
decoration: InputDecoration(
95+
hintText: 'Enter the portion size as a percent',
96+
),
97+
controller: _controller,
98+
onChanged: (value) {
99+
var v = int.tryParse(value);
100+
if (v == null) return;
101+
setState(() {
102+
portionPct = v;
103+
});
104+
},
105+
),
106+
),
107+
],
108+
),
109+
],
110+
),
111+
Row(
112+
mainAxisAlignment: MainAxisAlignment.end,
113+
children: [
114+
if (meal.mealItems.isNotEmpty)
115+
TextButton(
116+
child: const Text('Log'),
117+
onPressed: () async {
118+
await Provider.of<NutritionPlansProvider>(context, listen: false)
119+
.logMealToDiary(meal);
120+
// ignore: use_build_context_synchronously
121+
ScaffoldMessenger.of(context).showSnackBar(
122+
SnackBar(
123+
content: Text(
124+
// ignore: use_build_context_synchronously
125+
AppLocalizations.of(context).mealLogged,
126+
textAlign: TextAlign.center,
127+
),
128+
),
129+
);
130+
Navigator.of(context).pop();
131+
},
132+
),
133+
TextButton(
134+
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
135+
onPressed: () => Navigator.of(context).pop(),
136+
),
137+
],
138+
),
139+
],
140+
),
141+
),
142+
),
143+
),
144+
);
145+
}
146+
}

lib/widgets/nutrition/meal.dart

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import 'package:wger/models/nutrition/meal.dart';
2525
import 'package:wger/models/nutrition/meal_item.dart';
2626
import 'package:wger/providers/nutrition.dart';
2727
import 'package:wger/screens/form_screen.dart';
28+
import 'package:wger/screens/log_meal_screen.dart';
2829
import 'package:wger/widgets/nutrition/charts.dart';
2930
import 'package:wger/widgets/nutrition/forms.dart';
3031
import 'package:wger/widgets/nutrition/helpers.dart';
@@ -360,17 +361,14 @@ class MealHeader extends StatelessWidget {
360361
)
361362
],
362363
),
363-
onTap: () {
364-
Provider.of<NutritionPlansProvider>(context, listen: false).logMealToDiary(_meal);
365-
ScaffoldMessenger.of(context).showSnackBar(
366-
SnackBar(
367-
content: Text(
368-
AppLocalizations.of(context).mealLogged,
369-
textAlign: TextAlign.center,
370-
),
371-
),
372-
);
373-
},
364+
onTap: _meal.isRealMeal
365+
? () {
366+
Navigator.of(context).pushNamed(
367+
LogMealScreen.routeName,
368+
arguments: LogMealArguments(_meal),
369+
);
370+
}
371+
: null,
374372
),
375373
],
376374
);

0 commit comments

Comments
 (0)