aboutsummaryrefslogtreecommitdiff
path: root/lib/views/recipe_view.dart
diff options
context:
space:
mode:
Diffstat (limited to 'lib/views/recipe_view.dart')
-rw-r--r--lib/views/recipe_view.dart136
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;
}