diff options
Diffstat (limited to 'lib/views/recipe_view.dart')
-rw-r--r-- | lib/views/recipe_view.dart | 136 |
1 files changed, 97 insertions, 39 deletions
diff --git a/lib/views/recipe_view.dart b/lib/views/recipe_view.dart index 960ba84..a0304c3 100644 --- a/lib/views/recipe_view.dart +++ b/lib/views/recipe_view.dart @@ -1,9 +1,9 @@ import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:http/http.dart'; import 'package:kulinar_app/constants.dart'; +import 'package:kulinar_app/models/data/shoplist_data_class.dart'; import 'package:kulinar_app/views/image_view.dart'; import 'package:kulinar_app/models/recipe_class.dart'; import 'package:kulinar_app/widgets/toastbar_widget.dart'; @@ -12,10 +12,13 @@ import 'package:kulinar_app/widgets/page_route_transitions.dart'; import 'package:kulinar_app/widgets/utility_icon_row_widget.dart'; import 'package:kulinar_app/models/data/settings_data_class.dart'; -import 'package:image_picker/image_picker.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:http/http.dart'; + +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class RecipeView extends StatefulWidget { const RecipeView({Key? key, this.remote = false, required this.readonly, this.recipe, this.redrawCallback, this.showToastCallback}) : super(key: key); @@ -108,7 +111,7 @@ class _RecipeViewState extends State<RecipeView> { } } - void _removeRecipe() { + void _removeRecipe(BuildContext _) { Navigator.pop(context); RecipeData.recipeList.remove(widget.recipe); RecipeData.save(); @@ -118,11 +121,12 @@ class _RecipeViewState extends State<RecipeView> { String _content = AppLocalizations.of(context)!.removed; String _actionLabel = AppLocalizations.of(context)!.undo; - // FIXME: This might throw due to "!" - widget.showToastCallback!(_content, _actionLabel, () { - _addRecipe(passedRecipe: _removedRecipe); - widget.redrawCallback!(); - }); + if (widget.showToastCallback != null) { + widget.showToastCallback!(_content, _actionLabel, () { + _addRecipe(passedRecipe: _removedRecipe); + widget.redrawCallback!(); + }); + } setState(() {}); } @@ -142,12 +146,10 @@ class _RecipeViewState extends State<RecipeView> { setState(() {}); } - // FIXME: doesnt refresh, should be passed from parent void _pickImage() async { XFile? _pickedFile; if (SettingsData.settings["photoSource"] == "0") { - // TODO: Maybe pick multi image? _pickedFile = await ImagePicker().pickImage(source: ImageSource.camera); } else { _pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery); @@ -167,7 +169,6 @@ class _RecipeViewState extends State<RecipeView> { setState(() {}); } - // FIXME: doesnt refresh, should be passed from parent void _removeImage() async { _unsavedRecipe.image = null; await RecipeData.save(); @@ -202,7 +203,7 @@ class _RecipeViewState extends State<RecipeView> { padding: const EdgeInsets.only(right: 20.0, left: 20.0), child: TextFormField( controller: _controller1, - style: cRecipeTextStyle, + style: cRecipeTitleStyle, cursorColor: cPrimaryColor, enabled: _isEditingAllowed(), focusNode: _detailsTitleFocus, @@ -226,7 +227,6 @@ class _RecipeViewState extends State<RecipeView> { Widget _buildImage() { if (_unsavedRecipe.image != null) { - // TODO: Use https://api.flutter.dev/flutter/widgets/InteractiveViewer-class.html return Padding( padding: const EdgeInsets.only(top: 12.0, left: 20.0, right: 20.0), child: GestureDetector( @@ -257,34 +257,92 @@ class _RecipeViewState extends State<RecipeView> { Widget _buildDescriptionInput() { return Padding( padding: const EdgeInsets.all(18.0), - child: TextField( - expands: true, - maxLines: null, - minLines: null, - decoration: null, - controller: _controller2, - cursorColor: cPrimaryColor, - focusNode: _detailsTextFocus, - style: cRecipeDescriptionStyle, - readOnly: !_isEditingAllowed(), - enableInteractiveSelection: true, - toolbarOptions: ToolbarOptions( - copy: true, - cut: true, - paste: true, - selectAll: true, + child: _isEditingAllowed() ? _buildInputDescriptuion() : _buildMarkdownDescription(), + ); + } + + TextField _buildInputDescriptuion() { + return TextField( + expands: true, + maxLines: null, + minLines: null, + decoration: null, + controller: _controller2, + cursorColor: cPrimaryColor, + focusNode: _detailsTextFocus, + style: cRecipeDescriptionStyle, + enableInteractiveSelection: true, + toolbarOptions: ToolbarOptions( + copy: true, + cut: true, + paste: true, + selectAll: true, + ), + ); + } + + MarkdownBody _buildMarkdownDescription() { + return MarkdownBody( + data: _controller2.text, + selectable: true, + onTapLink: (text, href, title) => null, + imageBuilder: (uri, title, alt) => Container(), + styleSheet: MarkdownStyleSheet( + tableBody: cRecipeDescriptionStyle, + a: cRecipeDescriptionStyle, + p: cRecipeDescriptionStyle, + h1: cRecipeSubtitleStyle, + h2: cRecipeSubtitleStyle, + h3: cRecipeSubtitleStyle, + h4: cRecipeSubtitleStyle, + h5: cRecipeSubtitleStyle, + h6: cRecipeSubtitleStyle, +/* TODO: remove code and quote block + blockquoteDecoration: BoxDecoration(color: Color.fromARGB(255, 255, 13, 13)), + code: cDetailsTextStyle, +*/ + listIndent: 15.0, + listBullet: cRecipeDescriptionStyle, + listBulletPadding: EdgeInsets.only(right: 10.0), + horizontalRuleDecoration: BoxDecoration( + border: Border.all( + color: Colors.grey, + width: 0.5, + ), ), ), ); } - void _shareData() { + void _shareData(BuildContext _) { Share.share("${_unsavedRecipe.title}\n\n${_unsavedRecipe.description}", subject: _unsavedRecipe.title); } - void _addToShoppingList() {} + void _addToShoppingList(BuildContext _) { + final _ingredients = _unsavedRecipe.description!.split("\n")..retainWhere((element) => element.startsWith("- ")); + + for (String _ingredient in _ingredients) { + String _item = _ingredient.substring(2).trim(); + + if (!ShoplistData.shoplist.contains(_item)) { + ShoplistData.shoplist.add(_item); + } + } + + ShoplistData.save(); + + if (widget.showToastCallback != null) { + // TODO: translation + widget.showToastCallback!("Added to Shoplist", "Ok", () { + _addRecipe(passedRecipe: _removedRecipe); + widget.redrawCallback!(); + }); + } + } void _uploadRecipe(BuildContext context) async { + return; + Map<String, String> _headers = {"Content-Type": "application/json; charset=UTF-8"}; String _body = _unsavedRecipe.toJsonString(); Response? res; @@ -310,13 +368,12 @@ class _RecipeViewState extends State<RecipeView> { List<Widget> _localActions = [ _buildAppBarCheckActions(), PopupMenuButton( - onSelected: (int value) => _actionList.elementAt(value)(), + onSelected: (int value) => _actionList.elementAt(value)(context), itemBuilder: (BuildContext context) => [ - // TODO: Translations - PopupMenuItem<int>(value: 0, child: Text("Teilen")), - PopupMenuItem<int>(value: 1, child: Text("Einkaufen")), - PopupMenuItem<int>(value: 2, child: Text("Hochladen")), - PopupMenuItem<int>(value: 3, child: Text("Löschen")), + PopupMenuItem<int>(value: 0, child: Text(AppLocalizations.of(context)!.menu1)), + PopupMenuItem<int>(value: 1, child: Text(AppLocalizations.of(context)!.menu2)), + PopupMenuItem<int>(value: 2, child: Text(AppLocalizations.of(context)!.menu3)), + PopupMenuItem<int>(value: 3, child: Text(AppLocalizations.of(context)!.menu4)), ], ), ]; @@ -333,12 +390,13 @@ class _RecipeViewState extends State<RecipeView> { List<Widget> _remoteLookupAction = [ IconButton( icon: Icon(Icons.menu_open_rounded), - onPressed: null, // TODO: IMPLEMENT: Show local recipe + onPressed: null, ), ]; if (widget.remote && RecipeData.recipeList.contains(recipe)) return _remoteLookupAction; if (widget.remote) return _remoteDownloadAction; + return _localActions; } |