mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
support NutritionalPlan start & end dates
This commit is contained in:
@@ -384,6 +384,14 @@
|
||||
"@date": {
|
||||
"description": "The date of a workout log or body weight entry"
|
||||
},
|
||||
"creationDate": "Start date",
|
||||
"@creationDate": {
|
||||
"description": "The Start date of a nutritional plan"
|
||||
},
|
||||
"endDate": "End date",
|
||||
"@endDate": {
|
||||
"description": "The End date of a nutritional plan"
|
||||
},
|
||||
"value": "Value",
|
||||
"@value": {
|
||||
"description": "The value of a measurement entry"
|
||||
|
||||
@@ -41,6 +41,12 @@ class NutritionalPlan {
|
||||
@JsonKey(required: true, name: 'creation_date', toJson: dateToYYYYMMDD)
|
||||
late DateTime creationDate;
|
||||
|
||||
@JsonKey(required: true, name: 'start', toJson: dateToYYYYMMDD)
|
||||
late DateTime startDate;
|
||||
|
||||
@JsonKey(required: true, name: 'end', toJson: dateToYYYYMMDD)
|
||||
late DateTime? endDate;
|
||||
|
||||
@JsonKey(required: true, name: 'only_logging')
|
||||
late bool onlyLogging;
|
||||
|
||||
@@ -84,6 +90,8 @@ class NutritionalPlan {
|
||||
|
||||
NutritionalPlan.empty() {
|
||||
creationDate = DateTime.now();
|
||||
startDate = DateTime.now();
|
||||
endDate = null;
|
||||
description = '';
|
||||
onlyLogging = false;
|
||||
goalEnergy = null;
|
||||
@@ -94,12 +102,15 @@ class NutritionalPlan {
|
||||
}
|
||||
|
||||
// Boilerplate
|
||||
factory NutritionalPlan.fromJson(Map<String, dynamic> json) => _$NutritionalPlanFromJson(json);
|
||||
factory NutritionalPlan.fromJson(Map<String, dynamic> json) =>
|
||||
_$NutritionalPlanFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$NutritionalPlanToJson(this);
|
||||
|
||||
String getLabel(BuildContext context) {
|
||||
return description != '' ? description : AppLocalizations.of(context).nutritionalPlan;
|
||||
return description != ''
|
||||
? description
|
||||
: AppLocalizations.of(context).nutritionalPlan;
|
||||
}
|
||||
|
||||
bool get hasAnyGoals {
|
||||
@@ -154,7 +165,9 @@ class NutritionalPlan {
|
||||
final now = DateTime.now();
|
||||
final today = DateTime(now.year, now.month, now.day);
|
||||
|
||||
return logEntriesValues.containsKey(today) ? logEntriesValues[today]! : NutritionalValues();
|
||||
return logEntriesValues.containsKey(today)
|
||||
? logEntriesValues[today]!
|
||||
: NutritionalValues();
|
||||
}
|
||||
|
||||
NutritionalValues get loggedNutritionalValues7DayAvg {
|
||||
@@ -170,7 +183,8 @@ class NutritionalPlan {
|
||||
Map<DateTime, NutritionalValues> get logEntriesValues {
|
||||
final out = <DateTime, NutritionalValues>{};
|
||||
for (final log in diaryEntries) {
|
||||
final date = DateTime(log.datetime.year, log.datetime.month, log.datetime.day);
|
||||
final date =
|
||||
DateTime(log.datetime.year, log.datetime.month, log.datetime.day);
|
||||
|
||||
if (!out.containsKey(date)) {
|
||||
out[date] = NutritionalValues();
|
||||
@@ -195,7 +209,8 @@ class NutritionalPlan {
|
||||
final List<Log> out = [];
|
||||
for (final log in diaryEntries) {
|
||||
final dateKey = DateTime(date.year, date.month, date.day);
|
||||
final logKey = DateTime(log.datetime.year, log.datetime.month, log.datetime.day);
|
||||
final logKey =
|
||||
DateTime(log.datetime.year, log.datetime.month, log.datetime.day);
|
||||
|
||||
if (dateKey == logKey) {
|
||||
out.add(log);
|
||||
@@ -212,7 +227,9 @@ class NutritionalPlan {
|
||||
for (final meal in meals) {
|
||||
for (final mealItem in meal.mealItems) {
|
||||
final found = out.firstWhereOrNull(
|
||||
(e) => e.amount == mealItem.amount && e.ingredientId == mealItem.ingredientId,
|
||||
(e) =>
|
||||
e.amount == mealItem.amount &&
|
||||
e.ingredientId == mealItem.ingredientId,
|
||||
);
|
||||
|
||||
if (found == null) {
|
||||
|
||||
@@ -42,7 +42,8 @@ class MealForm extends StatelessWidget {
|
||||
final _nameController = TextEditingController();
|
||||
|
||||
MealForm(this._planId, [meal]) {
|
||||
_meal = meal ?? Meal(plan: _planId, time: TimeOfDay.fromDateTime(DateTime.now()));
|
||||
_meal = meal ??
|
||||
Meal(plan: _planId, time: TimeOfDay.fromDateTime(DateTime.now()));
|
||||
_timeController.text = timeToString(_meal.time)!;
|
||||
_nameController.text = _meal.name;
|
||||
}
|
||||
@@ -57,7 +58,8 @@ class MealForm extends StatelessWidget {
|
||||
children: [
|
||||
TextFormField(
|
||||
key: const Key('field-time'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context).time),
|
||||
decoration:
|
||||
InputDecoration(labelText: AppLocalizations.of(context).time),
|
||||
controller: _timeController,
|
||||
onTap: () async {
|
||||
// Stop keyboard from appearing
|
||||
@@ -79,7 +81,8 @@ class MealForm extends StatelessWidget {
|
||||
TextFormField(
|
||||
maxLength: 25,
|
||||
key: const Key('field-name'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context).name),
|
||||
decoration:
|
||||
InputDecoration(labelText: AppLocalizations.of(context).name),
|
||||
controller: _nameController,
|
||||
onSaved: (newValue) {
|
||||
_meal.name = newValue as String;
|
||||
@@ -125,7 +128,8 @@ Widget MealItemForm(
|
||||
recent: recent.map((e) => Log.fromMealItem(e, 0, e.mealId)).toList(),
|
||||
onSave: (BuildContext context, MealItem mealItem, DateTime? dt) {
|
||||
mealItem.mealId = meal.id!;
|
||||
Provider.of<NutritionPlansProvider>(context, listen: false).addMealItem(mealItem, meal);
|
||||
Provider.of<NutritionPlansProvider>(context, listen: false)
|
||||
.addMealItem(mealItem, meal);
|
||||
},
|
||||
barcode: barcode ?? '',
|
||||
test: test ?? false,
|
||||
@@ -235,9 +239,11 @@ class IngredientFormState extends State<IngredientForm> {
|
||||
Widget build(BuildContext context) {
|
||||
final String unit = AppLocalizations.of(context).g;
|
||||
final queryLower = _searchQuery.toLowerCase();
|
||||
final suggestions =
|
||||
widget.recent.where((e) => e.ingredient.name.toLowerCase().contains(queryLower)).toList();
|
||||
final numberFormat = NumberFormat.decimalPattern(Localizations.localeOf(context).toString());
|
||||
final suggestions = widget.recent
|
||||
.where((e) => e.ingredient.name.toLowerCase().contains(queryLower))
|
||||
.toList();
|
||||
final numberFormat =
|
||||
NumberFormat.decimalPattern(Localizations.localeOf(context).toString());
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.all(20),
|
||||
@@ -344,7 +350,8 @@ class IngredientFormState extends State<IngredientForm> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (ingredientIdController.text.isNotEmpty && _amountController.text.isNotEmpty)
|
||||
if (ingredientIdController.text.isNotEmpty &&
|
||||
_amountController.text.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
@@ -395,7 +402,8 @@ class IngredientFormState extends State<IngredientForm> {
|
||||
return;
|
||||
}
|
||||
_form.currentState!.save();
|
||||
_mealItem.ingredientId = int.parse(_ingredientIdController.text);
|
||||
_mealItem.ingredientId =
|
||||
int.parse(_ingredientIdController.text);
|
||||
|
||||
var date = DateTime.parse(_dateController.text);
|
||||
final tod = stringToTime(_timeController.text);
|
||||
@@ -508,6 +516,8 @@ class _PlanFormState extends State<PlanForm> {
|
||||
GoalType _goalType = GoalType.meals;
|
||||
|
||||
final _descriptionController = TextEditingController();
|
||||
final _startDateController = TextEditingController();
|
||||
final _endDateController = TextEditingController();
|
||||
final TextEditingController colorController = TextEditingController();
|
||||
|
||||
GoalType? selectedGoal;
|
||||
@@ -518,6 +528,12 @@ class _PlanFormState extends State<PlanForm> {
|
||||
|
||||
_onlyLogging = widget._plan.onlyLogging;
|
||||
_descriptionController.text = widget._plan.description;
|
||||
_startDateController.text =
|
||||
'${widget._plan.startDate.year}-${widget._plan.startDate.month.toString().padLeft(2, '0')}-${widget._plan.startDate.day.toString().padLeft(2, '0')}';
|
||||
if (widget._plan.endDate != null) {
|
||||
_endDateController.text =
|
||||
'${widget._plan.endDate!.year}-${widget._plan.endDate!.month.toString().padLeft(2, '0')}-${widget._plan.endDate!.day.toString().padLeft(2, '0')}';
|
||||
}
|
||||
if (widget._plan.hasAnyAdvancedGoals) {
|
||||
_goalType = GoalType.advanced;
|
||||
} else if (widget._plan.hasAnyGoals) {
|
||||
@@ -530,6 +546,8 @@ class _PlanFormState extends State<PlanForm> {
|
||||
@override
|
||||
void dispose() {
|
||||
_descriptionController.dispose();
|
||||
_startDateController.dispose();
|
||||
_endDateController.dispose();
|
||||
colorController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@@ -551,6 +569,66 @@ class _PlanFormState extends State<PlanForm> {
|
||||
widget._plan.description = newValue!;
|
||||
},
|
||||
),
|
||||
// Start Date
|
||||
TextFormField(
|
||||
key: const Key('field-start-date'),
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).start,
|
||||
hintText: 'YYYY-MM-DD',
|
||||
),
|
||||
controller: _startDateController,
|
||||
readOnly: true,
|
||||
onTap: () async {
|
||||
// Stop keyboard from appearing
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
|
||||
// Open date picker
|
||||
final pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: widget._plan.startDate,
|
||||
firstDate: DateTime(2000),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
|
||||
if (pickedDate != null) {
|
||||
setState(() {
|
||||
_startDateController.text =
|
||||
'${pickedDate.year}-${pickedDate.month.toString().padLeft(2, '0')}-${pickedDate.day.toString().padLeft(2, '0')}';
|
||||
widget._plan.startDate = pickedDate;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
// End Date
|
||||
TextFormField(
|
||||
key: const Key('field-end-date'),
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).endDate,
|
||||
hintText: 'YYYY-MM-DD',
|
||||
),
|
||||
controller: _endDateController,
|
||||
readOnly: true,
|
||||
onTap: () async {
|
||||
// Stop keyboard from appearing
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
|
||||
// Open date picker
|
||||
final pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: widget._plan.endDate,
|
||||
firstDate: DateTime(2000),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
|
||||
if (pickedDate != null) {
|
||||
setState(() {
|
||||
_endDateController.text =
|
||||
'${pickedDate.year}-${pickedDate.month.toString().padLeft(2, '0')}-${pickedDate.day.toString().padLeft(2, '0')}';
|
||||
widget._plan.endDate = pickedDate;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(AppLocalizations.of(context).onlyLogging),
|
||||
subtitle: Text(AppLocalizations.of(context).onlyLoggingHelpText),
|
||||
@@ -626,7 +704,8 @@ class _PlanFormState extends State<PlanForm> {
|
||||
val: widget._plan.goalCarbohydrates?.toString(),
|
||||
label: AppLocalizations.of(context).goalCarbohydrates,
|
||||
suffix: AppLocalizations.of(context).g,
|
||||
onSave: (double value) => widget._plan.goalCarbohydrates = value,
|
||||
onSave: (double value) =>
|
||||
widget._plan.goalCarbohydrates = value,
|
||||
key: const Key('field-goal-carbohydrates'),
|
||||
),
|
||||
GoalMacros(
|
||||
@@ -706,7 +785,8 @@ class GoalMacros extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final numberFormat = NumberFormat.decimalPattern(Localizations.localeOf(context).toString());
|
||||
final numberFormat =
|
||||
NumberFormat.decimalPattern(Localizations.localeOf(context).toString());
|
||||
|
||||
return TextFormField(
|
||||
initialValue: val ?? '',
|
||||
|
||||
Reference in New Issue
Block a user