import 'package:diameter/components/detail.dart'; import 'package:diameter/utils/dialog_utils.dart'; import 'package:diameter/components/forms/auto_complete_dropdown_button.dart'; import 'package:diameter/components/forms/form_wrapper.dart'; import 'package:diameter/models/ingredient.dart'; import 'package:diameter/models/meal.dart'; import 'package:diameter/models/recipe.dart'; import 'package:diameter/models/settings.dart'; import 'package:diameter/navigation.dart'; import 'package:diameter/screens/meal/meal_detail.dart'; import 'package:flutter/material.dart'; class RecipeDetailScreen extends StatefulWidget { static const String routeName = '/recipe'; final int id; const RecipeDetailScreen({Key? key, this.id = 0}) : super(key: key); @override _RecipeDetailScreenState createState() => _RecipeDetailScreenState(); } class _RecipeDetailScreenState extends State { Recipe? _recipe; List _ingredients = []; bool _isNew = true; bool _isSaving = false; final GlobalKey _recipeForm = GlobalKey(); final ScrollController _scrollController = ScrollController(); final _nameController = TextEditingController(text: ''); final _notesController = TextEditingController(text: ''); double _servings = 1; final List _ingredientControllers = []; List _meals = []; @override void initState() { super.initState(); reload(); _meals = Meal.getAll(); if (_recipe != null) { _nameController.text = _recipe!.name; _servings = _recipe!.servings ?? 1; _notesController.text = _recipe!.notes ?? ''; if (_ingredients.isNotEmpty) { for (Ingredient ingredient in _ingredients) { _ingredientControllers.add( TextEditingController(text: ingredient.ingredient.target?.value)); } } } } void reload({String? message}) { if (widget.id != 0) { setState(() { _recipe = Recipe.get(widget.id); _ingredients = Ingredient.getAllForRecipe(widget.id); }); } _isNew = _recipe == null; setState(() { if (message != null) { var snackBar = SnackBar( content: Text(message), duration: const Duration(seconds: 2), ); ScaffoldMessenger.of(context) ..removeCurrentSnackBar() ..showSnackBar(snackBar); } }); } void onAddIngredient() { final newIngredient = Ingredient(amount: 0); setState(() { newIngredient.recipe.target = _recipe; _ingredients.add(newIngredient); _ingredientControllers.add(TextEditingController(text: '')); }); } void handleSaveAction({bool close = false}) async { setState(() { _isSaving = true; }); if (_recipeForm.currentState!.validate()) { Recipe recipe = Recipe( id: widget.id, name: _nameController.text, servings: _servings, notes: _notesController.text, ); Recipe.put(recipe); List ingredients = _ingredients.map((ingredient) { if (ingredient.id != 0 && (!ingredient.ingredient.hasValue || ingredient.amount == 0)) { ingredient.deleted = true; } return ingredient; }).toList(); ingredients.retainWhere((ingredient) { return ingredient.id != 0 || (ingredient.amount > 0 && ingredient.ingredient.hasValue); }); Ingredient.putMany(ingredients); if (close) { Navigator.pop(context, ['${_isNew ? 'New' : ''} Recipe Saved', recipe]); } else { if (_isNew) { Navigator.push( context, MaterialPageRoute( builder: (context) => RecipeDetailScreen(id: recipe.id), ), ).then((result) => Navigator.pop(context, result)); } else { reload(message: 'Recipe saved'); } } setState(() { _isSaving = false; }); } } void handleCancelAction() { if (Settings.get().showConfirmationDialogOnCancel && ((_isNew && (_nameController.text != '' || _servings != 1 || _notesController.text != '')) || (!_isNew && (_nameController.text != _recipe!.name || _servings != _recipe!.servings || _notesController.text != (_recipe!.notes ?? ''))))) { DialogUtils.showCancelConfirmationDialog( context: context, isNew: _isNew, onSave: handleSaveAction, ); } else { Navigator.pop(context); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(_isNew ? 'New Recipe' : _recipe!.name), ), drawer: const Navigation(currentLocation: RecipeDetailScreen.routeName), body: Scrollbar( controller: _scrollController, child: SingleChildScrollView( controller: _scrollController, child: Column( children: [ FormWrapper( formState: _recipeForm, fields: [ TextFormField( controller: _nameController, decoration: const InputDecoration( labelText: 'Name', ), validator: (value) { if (value!.trim().isEmpty) { return 'Empty title'; } return null; }, ), // NumberFormField( // value: _servings, // label: 'Servings', // suffix: ' portions', // min: 0, // onChanged: (value) { // if (value != null && value >= 0) { // setState(() { // _servings = value.toDouble(); // }); // } // }, // ), TextFormField( keyboardType: TextInputType.multiline, controller: _notesController, decoration: const InputDecoration( labelText: 'Notes', ), minLines: 2, maxLines: 5, ), const Divider(), GestureDetector( onTap: onAddIngredient, child: Row( children: [ Text( 'INGREDIENTS', style: Theme.of(context).textTheme.subtitle2, ), const Spacer(), IconButton( onPressed: onAddIngredient, icon: const Icon(Icons.add), ), ], ), ), ], ), !_isNew && _ingredients.isNotEmpty ? ListBody( children: _ingredients.map((item) { final ingredient = item.ingredient.target; final index = _ingredients.indexOf(item); return Padding( padding: const EdgeInsets.symmetric( horizontal: 10.0, vertical: 5.0), child: Column( children: [ Row( children: [ Expanded( child: AutoCompleteDropdownButton( controller: _ingredientControllers[index], selectedItem: ingredient, label: 'Meal Category', items: _meals, onChanged: (value) { setState(() { _ingredients[index] .ingredient .target = value; _ingredientControllers[index].text = value?.value ?? ''; }); }, ), ), IconButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ingredient == null ? const MealDetailScreen() : MealDetailScreen( id: ingredient.id), ), ).then((result) { _ingredients[index].ingredient.target = result?[1]; _ingredientControllers[index].text = result?[1].value ?? ''; reload(message: result?[0]); }); }, icon: Icon(ingredient == null ? Icons.add : Icons.edit), ), ], ), // Padding( // padding: const EdgeInsets.only(top: 10.0), // child: NumberFormField( // controller: // _ingredients[index].amount, // label: 'Amount', // suffix: Settings.nutritionMeasurementSuffix, // min: 0, // onChanged: (value) { // if (value != null && value >= 0) { // setState(() { // _ingredients[index].amount = value.toDouble(); // }); // } // }, // ), // ), ], ), ); }).toList(), ) : Center( child: Text(_isNew ? 'Save the Recipe in order to add ingredients!' : 'You have not added any Ingredients yet!'), ) ], ), ), ), bottomNavigationBar: DetailBottomRow( onCancel: handleCancelAction, onAction: _isSaving ? null : handleSaveAction, onMiddleAction: _isSaving ? null : () => handleSaveAction(close: true), ), ); } }