mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Merge pull request #604 from wger-project/show-kcal-macros-total-for-meal
kcal/macros total for meals + fix alignments
This commit is contained in:
@@ -122,6 +122,7 @@
|
||||
"@searchExercise": {
|
||||
"description": "Label on set form. Selected exercises are added to the set"
|
||||
},
|
||||
"noIngredientsDefined": "No ingredients defined yet",
|
||||
"noMatchingExerciseFound": "No matching exercises found",
|
||||
"@noMatchingExerciseFound": {
|
||||
"description": "Message returned if no exercises match the searched string"
|
||||
|
||||
@@ -22,7 +22,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:wger/models/nutrition/meal.dart';
|
||||
import 'package:wger/providers/nutrition.dart';
|
||||
import 'package:wger/widgets/nutrition/meal.dart';
|
||||
import 'package:wger/widgets/nutrition/widgets.dart';
|
||||
import 'package:wger/widgets/nutrition/nutrition_tiles.dart';
|
||||
|
||||
class LogMealArguments {
|
||||
final Meal meal;
|
||||
@@ -51,7 +51,7 @@ class _LogMealScreenState extends State<LogMealScreen> {
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Log meal to diary'),
|
||||
title: Text(AppLocalizations.of(context).logMeal),
|
||||
),
|
||||
body: Consumer<NutritionPlansProvider>(
|
||||
builder: (context, nutritionProvider, child) => SingleChildScrollView(
|
||||
@@ -64,13 +64,13 @@ class _LogMealScreenState extends State<LogMealScreen> {
|
||||
children: [
|
||||
Text(meal.name, style: Theme.of(context).textTheme.headlineSmall),
|
||||
if (meal.mealItems.isEmpty)
|
||||
const ListTile(title: Text('No ingredients defined yet'))
|
||||
ListTile(title: Text(AppLocalizations.of(context).noIngredientsDefined))
|
||||
else
|
||||
Column(
|
||||
children: [
|
||||
const NutritionDiaryheader(),
|
||||
...meal.mealItems
|
||||
.map((item) => MealItemWidget(item, viewMode.withAllDetails, false)),
|
||||
const DiaryheaderTile(),
|
||||
...meal.mealItems.map(
|
||||
(item) => MealItemEditableFullTile(item, viewMode.withAllDetails, false)),
|
||||
const SizedBox(height: 32),
|
||||
Text(
|
||||
'Portion: ${portionPct.round()} %',
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -21,10 +21,12 @@ import 'package:flutter/material.dart';
|
||||
class MutedText extends StatelessWidget {
|
||||
final String _text;
|
||||
final TextAlign textAlign;
|
||||
final TextOverflow? overflow;
|
||||
|
||||
const MutedText(
|
||||
this._text, {
|
||||
this.textAlign = TextAlign.left,
|
||||
this.overflow,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -33,6 +35,7 @@ class MutedText extends StatelessWidget {
|
||||
_text,
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
||||
textAlign: textAlign,
|
||||
overflow: overflow,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import 'package:wger/models/nutrition/nutritional_plan.dart';
|
||||
import 'package:wger/providers/nutrition.dart';
|
||||
import 'package:wger/screens/nutritional_plan_screen.dart';
|
||||
import 'package:wger/widgets/nutrition/helpers.dart';
|
||||
import 'package:wger/widgets/nutrition/nutrition_tiles.dart';
|
||||
import 'package:wger/widgets/nutrition/widgets.dart';
|
||||
|
||||
class MealForm extends StatelessWidget {
|
||||
@@ -341,7 +342,7 @@ class IngredientFormState extends State<IngredientForm> {
|
||||
builder: (BuildContext context, AsyncSnapshot<Ingredient> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
_mealItem.ingredient = snapshot.data!;
|
||||
return MealItemTile(
|
||||
return MealItemValuesTile(
|
||||
ingredient: _mealItem.ingredient,
|
||||
nutritionalValues: _mealItem.nutritionalValues,
|
||||
);
|
||||
|
||||
@@ -23,25 +23,55 @@ import 'package:wger/models/nutrition/meal.dart';
|
||||
import 'package:wger/models/nutrition/nutritional_values.dart';
|
||||
import 'package:wger/widgets/core/core.dart';
|
||||
|
||||
List<Widget> getMutedNutritionalValues(NutritionalValues values, BuildContext context) => [
|
||||
MutedText(
|
||||
AppLocalizations.of(context).kcalValue(values.energy.toStringAsFixed(0)),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
MutedText(
|
||||
AppLocalizations.of(context).gValue(values.protein.toStringAsFixed(0)),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
MutedText(
|
||||
AppLocalizations.of(context).gValue(values.carbohydrates.toStringAsFixed(0)),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
MutedText(
|
||||
AppLocalizations.of(context).gValue(values.fat.toStringAsFixed(0)),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
List<String> getNutritionColumnNames(BuildContext context) => [
|
||||
AppLocalizations.of(context).energy,
|
||||
AppLocalizations.of(context).protein,
|
||||
AppLocalizations.of(context).carbohydrates,
|
||||
AppLocalizations.of(context).fat,
|
||||
];
|
||||
|
||||
List<String> getNutritionalValues(NutritionalValues values, BuildContext context) => [
|
||||
AppLocalizations.of(context).kcalValue(values.energy.toStringAsFixed(0)),
|
||||
AppLocalizations.of(context).gValue(values.protein.toStringAsFixed(0)),
|
||||
AppLocalizations.of(context).gValue(values.carbohydrates.toStringAsFixed(0)),
|
||||
AppLocalizations.of(context).gValue(values.fat.toStringAsFixed(0)),
|
||||
];
|
||||
|
||||
List<int> getNutritionColumnFlexes(BuildContext context) {
|
||||
return getNutritionColumnNames(context).map((e) {
|
||||
final l = e.characters.length;
|
||||
// if the word is really small (e.g. "fat"),
|
||||
// we still want to have a minimum value to keep some spacing,
|
||||
// especially because column values might become like "123 g"
|
||||
return (l <= 3) ? 4 : l;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<Widget> muted(List<String> children) => children
|
||||
.map((e) => MutedText(
|
||||
e,
|
||||
textAlign: TextAlign.right,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
))
|
||||
.toList();
|
||||
|
||||
// return a row of elements in the standard macros spacing
|
||||
Row getNutritionRow(BuildContext context, List<Widget> children) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: children.indexed
|
||||
.map(
|
||||
(e) => Flexible(
|
||||
fit: FlexFit.tight,
|
||||
flex: getNutritionColumnFlexes(context)[e.$1],
|
||||
child: e.$2,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
String getShortNutritionValues(NutritionalValues values, BuildContext context) {
|
||||
final loc = AppLocalizations.of(context);
|
||||
final e = '${loc.energyShort} ${loc.kcalValue(values.energy.toStringAsFixed(0))}';
|
||||
|
||||
@@ -21,7 +21,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_svg_icons/flutter_svg_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/helpers/consts.dart';
|
||||
import 'package:wger/models/nutrition/log.dart';
|
||||
import 'package:wger/models/nutrition/meal.dart';
|
||||
import 'package:wger/models/nutrition/meal_item.dart';
|
||||
import 'package:wger/providers/nutrition.dart';
|
||||
@@ -30,6 +29,8 @@ import 'package:wger/screens/log_meal_screen.dart';
|
||||
import 'package:wger/widgets/nutrition/charts.dart';
|
||||
import 'package:wger/widgets/nutrition/forms.dart';
|
||||
import 'package:wger/widgets/nutrition/helpers.dart';
|
||||
import 'package:wger/widgets/nutrition/nutrition_tile.dart';
|
||||
import 'package:wger/widgets/nutrition/nutrition_tiles.dart';
|
||||
import 'package:wger/widgets/nutrition/widgets.dart';
|
||||
|
||||
enum viewMode {
|
||||
@@ -157,15 +158,33 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
)),
|
||||
if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails)
|
||||
const Divider(),
|
||||
if (_viewMode == viewMode.withAllDetails) const NutritionDiaryheader(),
|
||||
if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails)
|
||||
const DiaryheaderTile(),
|
||||
if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails)
|
||||
if (widget._meal.mealItems.isEmpty && widget._meal.isRealMeal)
|
||||
const ListTile(title: Text('No ingredients defined yet'))
|
||||
NutritionTile(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).noIngredientsDefined,
|
||||
textAlign: TextAlign.left,
|
||||
))
|
||||
else
|
||||
...widget._meal.mealItems.map((item) => MealItemWidget(item, _viewMode, _editing)),
|
||||
...widget._meal.mealItems
|
||||
.map((item) => MealItemEditableFullTile(item, _viewMode, _editing)),
|
||||
if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails)
|
||||
const Divider(),
|
||||
if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails)
|
||||
NutritionTile(
|
||||
vPadding: 0,
|
||||
leading: const Text('total'),
|
||||
title: getNutritionRow(
|
||||
context,
|
||||
muted(getNutritionalValues(widget._meal.plannedNutritionalValues, context)),
|
||||
),
|
||||
),
|
||||
if (_viewMode == viewMode.withAllDetails)
|
||||
Column(
|
||||
children: [
|
||||
const Divider(),
|
||||
Center(
|
||||
child: Text(
|
||||
AppLocalizations.of(context).loggedToday,
|
||||
@@ -181,7 +200,7 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
NutritionDiaryEntry(diaryEntry: item),
|
||||
DiaryEntryTile(diaryEntry: item),
|
||||
],
|
||||
),
|
||||
)),
|
||||
@@ -194,12 +213,13 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
}
|
||||
}
|
||||
|
||||
class MealItemWidget extends StatelessWidget {
|
||||
/// An editable NutritionTile showing the avatar, name, nutritional values
|
||||
class MealItemEditableFullTile extends StatelessWidget {
|
||||
final bool _editing;
|
||||
final viewMode _viewMode;
|
||||
final MealItem _item;
|
||||
|
||||
const MealItemWidget(this._item, this._viewMode, this._editing);
|
||||
const MealItemEditableFullTile(this._item, this._viewMode, this._editing);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -213,22 +233,24 @@ class MealItemWidget extends StatelessWidget {
|
||||
final String unit = AppLocalizations.of(context).g;
|
||||
final values = _item.nutritionalValues;
|
||||
|
||||
return ListTile(
|
||||
return NutritionTile(
|
||||
leading: IngredientAvatar(ingredient: _item.ingredient),
|
||||
title: Text(
|
||||
'${_item.amount.toStringAsFixed(0)}$unit ${_item.ingredient.name}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
title: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
if (_viewMode == viewMode.withAllDetails) ...getMutedNutritionalValues(values, context)
|
||||
Text(
|
||||
'${_item.amount.toStringAsFixed(0)}$unit ${_item.ingredient.name}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: (_viewMode != viewMode.withAllDetails && !_editing)
|
||||
? null
|
||||
: getNutritionRow(context, muted(getNutritionalValues(values, context))),
|
||||
trailing: _editing
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
icon: const Icon(Icons.delete, size: ICON_SIZE_SMALL),
|
||||
tooltip: AppLocalizations.of(context).delete,
|
||||
iconSize: ICON_SIZE_SMALL,
|
||||
onPressed: () {
|
||||
@@ -250,38 +272,6 @@ class MealItemWidget extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class LogDiaryItemWidget extends StatelessWidget {
|
||||
final Log _item;
|
||||
|
||||
const LogDiaryItemWidget(this._item);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO(x): add real support for weight units
|
||||
/*
|
||||
String unit = _item.weightUnitId == null
|
||||
? AppLocalizations.of(context).g
|
||||
: _item.weightUnitObj!.weightUnit.name;
|
||||
|
||||
*/
|
||||
final String unit = AppLocalizations.of(context).g;
|
||||
final values = _item.nutritionalValues;
|
||||
|
||||
return ListTile(
|
||||
leading: IngredientAvatar(ingredient: _item.ingredient),
|
||||
title: Text(
|
||||
'${_item.amount.toStringAsFixed(0)}$unit ${_item.ingredient.name}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [...getMutedNutritionalValues(values, context)],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MealHeader extends StatelessWidget {
|
||||
final Meal _meal;
|
||||
final bool _editing;
|
||||
|
||||
49
lib/widgets/nutrition/nutrition_tile.dart
Normal file
49
lib/widgets/nutrition/nutrition_tile.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// NutritionTile is similar to a non-interactive ListTile,
|
||||
/// but uses a fixed, easy to understand layout.
|
||||
class NutritionTile extends StatelessWidget {
|
||||
final Widget? leading; // always constrained to 40px wide
|
||||
final double vPadding;
|
||||
final Widget? title;
|
||||
final Widget? subtitle;
|
||||
final Widget? trailing; // always constrained to 20px wide
|
||||
|
||||
const NutritionTile({
|
||||
this.leading,
|
||||
this.title,
|
||||
this.subtitle,
|
||||
this.trailing,
|
||||
this.vPadding = 8,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: vPadding),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 40, maxWidth: 40),
|
||||
child: leading ?? const SizedBox(width: 40),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
if (title != null) title!,
|
||||
if (subtitle != null) subtitle!,
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 20, maxWidth: 20),
|
||||
child: trailing ?? const SizedBox(width: 20),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
85
lib/widgets/nutrition/nutrition_tiles.dart
Normal file
85
lib/widgets/nutrition/nutrition_tiles.dart
Normal file
@@ -0,0 +1,85 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/helpers/consts.dart';
|
||||
import 'package:wger/models/nutrition/ingredient.dart';
|
||||
import 'package:wger/models/nutrition/log.dart';
|
||||
import 'package:wger/models/nutrition/nutritional_plan.dart';
|
||||
import 'package:wger/models/nutrition/nutritional_values.dart';
|
||||
import 'package:wger/providers/nutrition.dart';
|
||||
import 'package:wger/widgets/nutrition/helpers.dart';
|
||||
import 'package:wger/widgets/nutrition/nutrition_tile.dart';
|
||||
import 'package:wger/widgets/nutrition/widgets.dart';
|
||||
|
||||
/// a NutritionTitle showing an ingredient, with its
|
||||
/// avatar and nutritional values
|
||||
class MealItemValuesTile extends StatelessWidget {
|
||||
final Ingredient ingredient;
|
||||
final NutritionalValues nutritionalValues;
|
||||
|
||||
const MealItemValuesTile({
|
||||
super.key,
|
||||
required this.ingredient,
|
||||
required this.nutritionalValues,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return NutritionTile(
|
||||
leading: IngredientAvatar(ingredient: ingredient),
|
||||
title: Text(getShortNutritionValues(nutritionalValues, context)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// a NutritionTitle showing the header for the diary
|
||||
class DiaryheaderTile extends StatelessWidget {
|
||||
final Widget? leading;
|
||||
|
||||
const DiaryheaderTile({this.leading});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return NutritionTile(title: getNutritionRow(context, muted(getNutritionColumnNames(context))));
|
||||
}
|
||||
}
|
||||
|
||||
/// a NutritionTitle showing diary entries
|
||||
class DiaryEntryTile extends StatelessWidget {
|
||||
const DiaryEntryTile({
|
||||
super.key,
|
||||
required this.diaryEntry,
|
||||
this.nutritionalPlan,
|
||||
});
|
||||
|
||||
final Log diaryEntry;
|
||||
final NutritionalPlan? nutritionalPlan;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return NutritionTile(
|
||||
leading: Text(
|
||||
DateFormat.Hm(Localizations.localeOf(context).languageCode).format(diaryEntry.datetime),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
title: Text(
|
||||
'${AppLocalizations.of(context).gValue(diaryEntry.amount.toStringAsFixed(0))} ${diaryEntry.ingredient.name}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: getNutritionRow(
|
||||
context, muted(getNutritionalValues(diaryEntry.nutritionalValues, context))),
|
||||
trailing: (nutritionalPlan == null)
|
||||
? null
|
||||
: IconButton(
|
||||
tooltip: AppLocalizations.of(context).delete,
|
||||
onPressed: () {
|
||||
Provider.of<NutritionPlansProvider>(context, listen: false)
|
||||
.deleteLog(diaryEntry.id!, nutritionalPlan!.id!);
|
||||
},
|
||||
icon: const Icon(Icons.delete_outline),
|
||||
iconSize: ICON_SIZE_SMALL,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:wger/models/nutrition/nutritional_plan.dart';
|
||||
import 'package:wger/models/nutrition/nutritional_values.dart';
|
||||
import 'package:wger/widgets/nutrition/charts.dart';
|
||||
import 'package:wger/widgets/nutrition/widgets.dart';
|
||||
import 'package:wger/widgets/nutrition/nutrition_tiles.dart';
|
||||
|
||||
class NutritionalDiaryDetailWidget extends StatelessWidget {
|
||||
final NutritionalPlan _nutritionalPlan;
|
||||
@@ -60,15 +60,10 @@ class NutritionalDiaryDetailWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
const NutritionDiaryheader(),
|
||||
...logs.map((e) => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
NutritionDiaryEntry(diaryEntry: e, nutritionalPlan: _nutritionalPlan),
|
||||
],
|
||||
),
|
||||
)),
|
||||
const DiaryheaderTile(),
|
||||
...logs.map(
|
||||
(e) => DiaryEntryTile(diaryEntry: e, nutritionalPlan: _nutritionalPlan),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:flutter_zxing/flutter_zxing.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/helpers/consts.dart';
|
||||
import 'package:wger/helpers/misc.dart';
|
||||
@@ -30,12 +29,9 @@ import 'package:wger/helpers/platform.dart';
|
||||
import 'package:wger/helpers/ui.dart';
|
||||
import 'package:wger/models/exercises/ingredient_api.dart';
|
||||
import 'package:wger/models/nutrition/ingredient.dart';
|
||||
import 'package:wger/models/nutrition/log.dart';
|
||||
import 'package:wger/models/nutrition/nutritional_plan.dart';
|
||||
import 'package:wger/models/nutrition/nutritional_values.dart';
|
||||
import 'package:wger/providers/nutrition.dart';
|
||||
import 'package:wger/widgets/core/core.dart';
|
||||
import 'package:wger/widgets/nutrition/helpers.dart';
|
||||
import 'package:wger/widgets/nutrition/nutrition_tiles.dart';
|
||||
|
||||
class ScanReader extends StatelessWidget {
|
||||
@override
|
||||
@@ -214,7 +210,7 @@ class _IngredientTypeaheadState extends State<IngredientTypeahead> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(AppLocalizations.of(context).productFoundDescription(result.name)),
|
||||
MealItemTile(
|
||||
MealItemValuesTile(
|
||||
ingredient: result,
|
||||
nutritionalValues: result.nutritionalValues,
|
||||
),
|
||||
@@ -272,92 +268,6 @@ class _IngredientTypeaheadState extends State<IngredientTypeahead> {
|
||||
}
|
||||
}
|
||||
|
||||
class NutritionDiaryheader extends StatelessWidget {
|
||||
final Widget? leading;
|
||||
|
||||
const NutritionDiaryheader({this.leading});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: leading ??
|
||||
const CircleIconAvatar(
|
||||
Icon(Icons.image, color: Colors.transparent),
|
||||
color: Colors.transparent,
|
||||
),
|
||||
subtitle: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
AppLocalizations.of(context).energy,
|
||||
AppLocalizations.of(context).protein,
|
||||
AppLocalizations.of(context).carbohydrates,
|
||||
AppLocalizations.of(context).fat
|
||||
]
|
||||
.map((e) => MutedText(
|
||||
e,
|
||||
textAlign: TextAlign.right,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NutritionDiaryEntry extends StatelessWidget {
|
||||
const NutritionDiaryEntry({
|
||||
super.key,
|
||||
required this.diaryEntry,
|
||||
this.nutritionalPlan,
|
||||
});
|
||||
|
||||
final Log diaryEntry;
|
||||
final NutritionalPlan? nutritionalPlan;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
DateFormat.Hm(Localizations.localeOf(context).languageCode).format(diaryEntry.datetime),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${AppLocalizations.of(context).gValue(diaryEntry.amount.toStringAsFixed(0))} ${diaryEntry.ingredient.name}',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
...getMutedNutritionalValues(diaryEntry.nutritionalValues, context),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (nutritionalPlan != null)
|
||||
IconButton(
|
||||
tooltip: AppLocalizations.of(context).delete,
|
||||
onPressed: () {
|
||||
Provider.of<NutritionPlansProvider>(context, listen: false)
|
||||
.deleteLog(diaryEntry.id!, nutritionalPlan!.id!);
|
||||
},
|
||||
icon: const Icon(Icons.delete_outline)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class IngredientAvatar extends StatelessWidget {
|
||||
final Ingredient ingredient;
|
||||
|
||||
@@ -377,23 +287,3 @@ class IngredientAvatar extends StatelessWidget {
|
||||
: const CircleIconAvatar(Icon(Icons.image, color: Colors.grey));
|
||||
}
|
||||
}
|
||||
|
||||
class MealItemTile extends StatelessWidget {
|
||||
final Ingredient ingredient;
|
||||
final NutritionalValues nutritionalValues;
|
||||
|
||||
const MealItemTile({
|
||||
super.key,
|
||||
required this.ingredient,
|
||||
required this.nutritionalValues,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: IngredientAvatar(ingredient: ingredient),
|
||||
title: Text(getShortNutritionValues(nutritionalValues, context)),
|
||||
// subtitle: Text(ingredient.id.toString()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 69 KiB |
Reference in New Issue
Block a user