diff --git a/lib/providers/nutrition.dart b/lib/providers/nutrition.dart index c7052c73..70fab715 100644 --- a/lib/providers/nutrition.dart +++ b/lib/providers/nutrition.dart @@ -339,6 +339,18 @@ class NutritionPlansProvider extends WgerBaseProvider with ChangeNotifier { notifyListeners(); } +// Log custom ingredient to nutrition diary + Future logIngredentToDiary(MealItem mealItem, int planId) async { + final plan = findById(planId); + mealItem.ingredientObj = await fetchIngredient(mealItem.ingredientId); + final Log log = Log.fromMealItem(mealItem, plan.id!, null); + + final data = await post(log.toJson(), makeUrl(_nutritionDiaryPath)); + log.id = data['id']; + plan.logs.add(log); + notifyListeners(); + } + /// Deletes a log entry Future deleteLog(int logId, int planId) async { await deleteRequest(_nutritionDiaryPath, logId); diff --git a/lib/widgets/nutrition/forms.dart b/lib/widgets/nutrition/forms.dart index 3a0815e6..afaf22c8 100644 --- a/lib/widgets/nutrition/forms.dart +++ b/lib/widgets/nutrition/forms.dart @@ -236,6 +236,104 @@ class MealItemForm extends StatelessWidget { } } +class IngredientForm extends StatelessWidget { + late MealItem _mealItem; + final int _planId; + + IngredientForm(this._planId) { + _mealItem = MealItem.empty(); + } + + final _form = GlobalKey(); + final _ingredientController = TextEditingController(); + final _amountController = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(20), + child: Form( + key: _form, + child: Column( + children: [ + TypeAheadFormField( + textFieldConfiguration: TextFieldConfiguration( + controller: _ingredientController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).ingredient), + ), + suggestionsCallback: (pattern) async { + return Provider.of(context, + listen: false) + .searchIngredient( + pattern, + Localizations.localeOf(context).languageCode, + ); + }, + itemBuilder: (context, dynamic suggestion) { + return ListTile( + title: Text(suggestion['value']), + subtitle: Text(suggestion['data']['id'].toString()), + ); + }, + transitionBuilder: (context, suggestionsBox, controller) { + return suggestionsBox; + }, + onSuggestionSelected: (dynamic suggestion) { + _mealItem.ingredientId = suggestion['data']['id']; + _ingredientController.text = suggestion['value']; + }, + validator: (value) { + if (value!.isEmpty) { + return AppLocalizations.of(context).selectIngredient; + } + return null; + }, + ), + TextFormField( + decoration: InputDecoration( + labelText: AppLocalizations.of(context).weight), + controller: _amountController, + keyboardType: TextInputType.number, + onFieldSubmitted: (_) {}, + onSaved: (newValue) { + _mealItem.amount = double.parse(newValue!); + }, + validator: (value) { + try { + double.parse(value!); + } catch (error) { + return AppLocalizations.of(context).enterValidNumber; + } + return null; + }, + ), + ElevatedButton( + child: Text(AppLocalizations.of(context).save), + onPressed: () async { + if (!_form.currentState!.validate()) { + return; + } + _form.currentState!.save(); + + try { + Provider.of(context, listen: false) + .logIngredentToDiary(_mealItem, _planId); + } on WgerHttpException catch (error) { + showHttpExceptionErrorDialog(error, context); + } catch (error) { + showErrorDialog(error, context); + } + Navigator.of(context).pop(); + }, + ), + ], + ), + ), + ); + } +} + class PlanForm extends StatelessWidget { final _form = GlobalKey(); final _descriptionController = TextEditingController(); diff --git a/lib/widgets/nutrition/nutritional_plan_detail.dart b/lib/widgets/nutrition/nutritional_plan_detail.dart index bb7043a0..689a673f 100644 --- a/lib/widgets/nutrition/nutritional_plan_detail.dart +++ b/lib/widgets/nutrition/nutritional_plan_detail.dart @@ -67,6 +67,22 @@ class NutritionalPlanDetailWidget extends StatelessWidget { }, ), ), + Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( + child: Text(AppLocalizations.of(context).addIngredient), + onPressed: () { + Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context).addIngredient, + IngredientForm(_nutritionalPlan.id!), + ), + ); + }, + ), + ), Container( padding: const EdgeInsets.all(15), height: 220, diff --git a/pubspec.lock b/pubspec.lock index f333a21c..d957b2c6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -14,7 +14,7 @@ packages: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "1.7.2" + version: "1.7.1" android_metadata: dependency: "direct main" description: @@ -42,7 +42,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.1" + version: "2.6.1" boolean_selector: dependency: transitive description: @@ -133,7 +133,7 @@ packages: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.2.0" charts_common: dependency: transitive description: @@ -524,7 +524,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.3.0" mime: dependency: transitive description: @@ -692,7 +692,7 @@ packages: name: rive url: "https://pub.dartlang.org" source: hosted - version: "0.7.33" + version: "0.7.28" shared_preferences: dependency: "direct main" description: @@ -823,7 +823,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.2" + version: "0.3.0" timing: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ac73cd78..b97a1891 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,7 +47,7 @@ dependencies: version: ^2.0.0 package_info: ^2.0.2 provider: ^5.0.0 - rive: ^0.7.33 + rive: 0.7.28 shared_preferences: ^2.0.7 table_calendar: ^3.0.2 url_launcher: ^6.0.10