diff --git a/lib/helpers/json.dart b/lib/helpers/json.dart index c04bbda4..0eaa9281 100644 --- a/lib/helpers/json.dart +++ b/lib/helpers/json.dart @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; num toNum(String e) { @@ -48,20 +49,21 @@ String toDate(DateTime dateTime) { * Converts a time to a date object. * Needed e.g. when the wger api only sends a time but no date information. */ -DateTime fromTime(String time) { +TimeOfDay stringToTime(String time) { if (time == null) { return null; } - return DateTime.parse(DateFormat('yyyy-MM-dd').format(DateTime.now()).toString() + ' ' + time); + return TimeOfDay.fromDateTime( + DateTime.parse('2020-01-01 $time'), + ); } /* * Converts a datetime to time. - * Needed e.g. when the wger api only expects a time and no date information. */ -String toTime(DateTime dateTime) { - if (dateTime == null) { +String timeToString(TimeOfDay time) { + if (time == null) { return null; } - return DateFormat.Hms().format(dateTime).toString(); + return DefaultMaterialLocalizations().formatTimeOfDay(time, alwaysUse24HourFormat: true); } diff --git a/lib/locale/locales.dart b/lib/locale/locales.dart index 782320d7..8685599d 100644 --- a/lib/locale/locales.dart +++ b/lib/locale/locales.dart @@ -155,6 +155,14 @@ class AppLocalizations { ); } + String get time { + return Intl.message( + 'Time', + name: 'time', + desc: 'The time of a meal or workout', + ); + } + String get newEntry { return Intl.message( 'New entry', diff --git a/lib/models/nutrition/meal.dart b/lib/models/nutrition/meal.dart index ae9c58da..4e0bcf2f 100644 --- a/lib/models/nutrition/meal.dart +++ b/lib/models/nutrition/meal.dart @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import 'package:intl/intl.dart'; +import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:wger/helpers/json.dart'; import 'package:wger/models/nutrition/meal_item.dart'; @@ -28,16 +28,11 @@ class Meal { @JsonKey(required: true) final int id; - @JsonKey(required: true, toJson: toTime, fromJson: fromTime) - final DateTime time; - - /// returns the time component of the DateTime time as a string - String get getTime { - return DateFormat.jm().format(time).toString(); - } + @JsonKey(required: true, toJson: timeToString, fromJson: stringToTime) + TimeOfDay time; @JsonKey(required: true, name: 'meal_items') - final List mealItems; + List mealItems; Meal({ this.id, diff --git a/lib/models/nutrition/meal.g.dart b/lib/models/nutrition/meal.g.dart index 1edcf5df..48b77fda 100644 --- a/lib/models/nutrition/meal.g.dart +++ b/lib/models/nutrition/meal.g.dart @@ -10,16 +10,15 @@ Meal _$MealFromJson(Map json) { $checkKeys(json, requiredKeys: const ['id', 'time', 'meal_items']); return Meal( id: json['id'] as int, - time: fromTime(json['time'] as String), + time: stringToTime(json['time'] as String), mealItems: (json['meal_items'] as List) - ?.map((e) => - e == null ? null : MealItem.fromJson(e as Map)) + ?.map((e) => e == null ? null : MealItem.fromJson(e as Map)) ?.toList(), ); } Map _$MealToJson(Meal instance) => { 'id': instance.id, - 'time': toTime(instance.time), + 'time': timeToString(instance.time), 'meal_items': instance.mealItems, }; diff --git a/lib/providers/exercises.dart b/lib/providers/exercises.dart index fc4d3634..1da608b4 100644 --- a/lib/providers/exercises.dart +++ b/lib/providers/exercises.dart @@ -114,7 +114,7 @@ class Exercises with ChangeNotifier { //if (false) { final exerciseData = json.decode(prefs.getString('exerciseData')); if (DateTime.parse(exerciseData['expiresIn']).isAfter(DateTime.now())) { - exerciseData['results'].forEach((e) => _entries.add(Exercise.fromJson(e))); + exerciseData['exercises'].forEach((e) => _entries.add(Exercise.fromJson(e))); log("Read exercise data from cache. Valid till ${exerciseData['expiresIn']}"); return; } diff --git a/lib/widgets/nutrition/forms.dart b/lib/widgets/nutrition/forms.dart new file mode 100644 index 00000000..6306733b --- /dev/null +++ b/lib/widgets/nutrition/forms.dart @@ -0,0 +1,106 @@ +/* + * This file is part of wger Workout Manager . + * Copyright (C) 2020 wger Team + * + * wger Workout Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wger Workout Manager is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import 'package:flutter/material.dart'; +import 'package:wger/helpers/json.dart'; +import 'package:wger/locale/locales.dart'; +import 'package:wger/models/nutrition/meal.dart'; +import 'package:wger/models/nutrition/nutritional_plan.dart'; + +class MealForm extends StatelessWidget { + Meal meal; + NutritionalPlan _plan; + + MealForm(plan, [meal]) { + this._plan = plan; + this.meal = meal ?? Meal(); + } + + //MealForm(this._plan, {this.meal}); + + final _form = GlobalKey(); + final _timeController = TextEditingController( + text: timeToString(TimeOfDay.fromDateTime(DateTime.now())), + ); + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.all(20), + child: Form( + key: _form, + child: Column( + children: [ + Text('tttttt'), + TextFormField( + decoration: InputDecoration(labelText: AppLocalizations.of(context).time), + controller: _timeController, + onTap: () async { + // Stop keyboard from appearing + FocusScope.of(context).requestFocus(new FocusNode()); + + // Open time picker + var pickedTime = await showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ); + + _timeController.text = timeToString(pickedTime); + }, + onSaved: (newValue) { + meal.time = stringToTime(newValue); + }, + onFieldSubmitted: (_) {}, + ), + ElevatedButton( + child: Text(AppLocalizations.of(context).save), + onPressed: () async { + if (!_form.currentState.validate()) { + return; + } + _form.currentState.save(); + + try { + //Provider.of(context, listen: false) + //.addMe(_plan) + // .addDay(Day(description: dayController.text, daysOfWeek: [1]), workout); + } catch (error) { + await showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: Text('An error occurred!'), + content: Text('Something went wrong.'), + actions: [ + TextButton( + child: Text('Okay'), + onPressed: () { + Navigator.of(ctx).pop(); + }, + ) + ], + ), + ); + } + }, + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/nutrition/meal.dart b/lib/widgets/nutrition/meal.dart index 6b1a0d08..edd78dd2 100644 --- a/lib/widgets/nutrition/meal.dart +++ b/lib/widgets/nutrition/meal.dart @@ -58,17 +58,14 @@ class MealWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - //color: Colors.amber, - //width: double.infinity, child: Card( child: Column( - //mainAxisSize: MainAxisSize.max, children: [ Container( width: double.infinity, decoration: BoxDecoration(color: Colors.black12), padding: const EdgeInsets.symmetric(vertical: 10), - child: Text(_meal.getTime), + child: Text(_meal.time.format(context)), ), ..._meal.mealItems.map((item) => MealItemWidget(item)).toList(), ], diff --git a/lib/widgets/nutrition/nutritional_plan_detail.dart b/lib/widgets/nutrition/nutritional_plan_detail.dart index 73675cf2..8ac3cd64 100644 --- a/lib/widgets/nutrition/nutritional_plan_detail.dart +++ b/lib/widgets/nutrition/nutritional_plan_detail.dart @@ -21,6 +21,7 @@ import 'package:intl/intl.dart'; import 'package:wger/locale/locales.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/widgets/core/bottom_sheet.dart'; +import 'package:wger/widgets/nutrition/forms.dart'; import 'package:wger/widgets/nutrition/meal.dart'; class NutritionalPlanDetailWidget extends StatefulWidget { @@ -32,10 +33,6 @@ class NutritionalPlanDetailWidget extends StatefulWidget { } class _NutritionalPlanDetailWidgetState extends State { - Widget planForm = Form( - child: Text('forms come here...'), - ); - @override Widget build(BuildContext context) { return SingleChildScrollView( @@ -61,7 +58,7 @@ class _NutritionalPlanDetailWidgetState extends State