diff --git a/lib/main.dart b/lib/main.dart index 667e39a..0caba2d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,6 +7,7 @@ import 'package:pizzaplanner/entities/PizzaRecipe/pizza_recipe.dart'; import 'package:pizzaplanner/entities/PizzaRecipe/recipe_step.dart'; import 'package:pizzaplanner/entities/PizzaRecipe/recipe_substep.dart'; import 'package:pizzaplanner/pages/add_pizza_event_page.dart'; +import 'package:pizzaplanner/pages/add_recipe_url.dart'; import 'package:pizzaplanner/pages/edit_recipe_page.dart'; import 'package:pizzaplanner/pages/edit_recipe_step_page.dart'; import 'package:pizzaplanner/pages/edit_recipe_sub_step_page.dart'; @@ -187,6 +188,9 @@ class RouteGenerator { } return MaterialPageRoute(builder: (context) => EditRecipeSubStepPage(subStep)); } + case "/recipes/add/url": { + return MaterialPageRoute(builder: (context) => AddRecipeURLPage(settings.arguments as String?)); + } default: { return MaterialPageRoute(builder: (context) => PizzaEventsPage()); } diff --git a/lib/pages/add_recipe_url.dart b/lib/pages/add_recipe_url.dart new file mode 100644 index 0000000..5cf000a --- /dev/null +++ b/lib/pages/add_recipe_url.dart @@ -0,0 +1,151 @@ +import 'package:flutter/material.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:pizzaplanner/entities/PizzaRecipe/pizza_recipe.dart'; +import 'package:pizzaplanner/pages/scaffold.dart'; + +import 'package:http/http.dart' as http; +import 'package:pizzaplanner/widgets/pizza_recipe_widget.dart'; + +class AddRecipeURLPage extends StatefulWidget { + final String? url; + + const AddRecipeURLPage(this.url); + + @override + AddRecipeURLPageState createState() => AddRecipeURLPageState(); +} + +class AddRecipeURLPageState extends State { + String? url; + String tempUrl = "?"; + List itemList = []; + + @override + void initState() { + super.initState(); + url = widget.url; + } + + @override + Widget build(BuildContext context){ + return PizzaPlannerScaffold( + title: const Text("Fetch Pizza Recipe"), + body: Column( + children: [ + Expanded( + flex: 5, + child: InkWell( + onTap: () async { + showDialog(context: context, builder: (BuildContext context) { + return AlertDialog( + title: const Text("URL"), + content: TextFormField( + decoration: const InputDecoration( + hintText: "Recipe URL", + ), + initialValue: url ?? "", + onChanged: (String newUrl) { + setState(() { + tempUrl = newUrl; + }); + }, + ), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text("Cancel"), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + url = tempUrl; + setState(() { + fetchUrl(); + }); + }, + child: const Text("Fetch"), + ), + ], + ); + }); + }, + child: Text(url ?? "?"), + ), + ), + Expanded( + flex: 45, + child: ListView( + children: itemList, + ) + ) + ] + ) + ); + } + + Future fetchUrl() async { + if (url == null){ + return; + } + final uri = Uri.parse(url!); + if (!uri.isAbsolute){ + return; + } + try { + final response = await http.get(uri); + if (response.statusCode != 200) { + return; + } + + final yamlBody = response.body; + final pizzaRecipe = await PizzaRecipe.fromYaml(yamlBody); + + + itemList.clear(); + itemList.add( + InkWell( + onTap: () { + showDialog(context: context, builder: (BuildContext context) { + return AlertDialog( + title: Text(pizzaRecipe.name), + content: const Text("What do you want to do?"), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + Navigator.pushNamed(context, "/recipe/view", arguments: pizzaRecipe); + }, + child: const Text("View"), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + addPizzaRecipeToBox(pizzaRecipe); + }, + child: const Text("Add"), + ), + ] + ); + }); + }, + child: PizzaRecipeWidget(pizzaRecipe), + ) + ); + } catch (exception) { + print(exception); + return; + } + } + + Future addPizzaRecipeToBox(PizzaRecipe pizzaRecipe) async { + final pizzaRecipeBox = Hive.box("PizzaRecipes"); + if (pizzaRecipeBox.containsKey(pizzaRecipe.key)) { + return; // this recipe is already in the box + } + setState(() { + pizzaRecipeBox.add(pizzaRecipe); + }); + } +} \ No newline at end of file diff --git a/lib/pages/recipes_page.dart b/lib/pages/recipes_page.dart index cbeb1df..4d13f9d 100644 --- a/lib/pages/recipes_page.dart +++ b/lib/pages/recipes_page.dart @@ -154,7 +154,30 @@ class RecipesPageState extends State { width: double.infinity, child: TextButton( onPressed: () async { - loadRecipe(); + FocusScope.of(context).unfocus(); + showDialog(context: context, builder: (BuildContext context) { + return AlertDialog( + title: const Text("Source"), + content: const Text("Add from a local file or from an URL?"), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + loadLocalRecipe(); + }, + child: const Text("Local"), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + Navigator.pushNamed(context, "/recipes/add/url"); + }, + child: const Text("URL"), + ) + ] + ); + }); + }, child: const Text("Load Recipe", style: TextStyle(color: Colors.white)), ) @@ -185,7 +208,7 @@ class RecipesPageState extends State { ); } - Future loadRecipe() async { + Future loadLocalRecipe() async { final result = await FilePicker.platform.pickFiles(); if (result == null){ return; diff --git a/pubspec.yaml b/pubspec.yaml index e053913..ef35bfb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -56,6 +56,8 @@ dependencies: file_picker: ^4.0.2 + http: ^0.13.3 + dev_dependencies: flutter_test: sdk: flutter diff --git a/todo.md b/todo.md index 850df12..8f172ff 100644 --- a/todo.md +++ b/todo.md @@ -2,9 +2,7 @@ ## Feature - add 'capturing' sharing intent -- add import of recipes - - from raw url - - maybe allow a 'dir' yaml, that just points to other raw pizza yaml urls +- maybe allow a 'dir' yaml when importing from url, that just points to other raw pizza yaml urls - add settings page - option for type of notification, full screen or just in the appbar - pick alarm sound @@ -15,6 +13,8 @@ - RecipeStep.waitUnit should probably be an enum? - refactor to const page names instead of loose strings everywhere ('/path/page') - also do this with hive box names +- make the url fetching less shit + - probably use a stream for adding to the listview ? ## Bug - add option to start recipe step instruction after step datetime and not completed