switched the addPizzaEventPage to a recipe list from yamls on the device

This commit is contained in:
broodjeaap89 2021-07-10 21:01:30 +02:00
parent 2ffe58e75c
commit c43d92c0f1
8 changed files with 296 additions and 144 deletions

View file

@ -0,0 +1,54 @@
recipe:
name: "Neapolitan Day Dough"
description: >
A Neapolitan Style pizza prepared in a day
ingredients:
method: ratio
items:
- name: flour
unit: g
value: 0.595
- name: water
unit: ml
value: 0.386
- name: salt
unit: g
value: 0.0178
- name: yeast
unit: g
value: 0.0012
steps:
- name: Make the dough
wait:
unit: hours
min: 4
max: 6
description: >
Combine all the ingredients to make the dough, we start with just the water and salt and add the yeast after adding some of the flour to not kill the yeast.
substeps:
- name: Salt+Water
description: >
Combine the salt and the water in a bowl, stir until the salt dissolves.
- name: +20% flour
description: >
Add ~20% of the flour to the water/salt mixture and mix everything together.
- name: Yeast
description: >
Add the yeast to the mixture.
- name: Flour
description: >
Add the rest of the flour to the mixture, knead the dough for 15-20 minutes.
- name: Rise
description: >
Split the dough into doughballs and place the dough in a sealed/covered container at room temperature.
- name: Preheat Oven
wait:
unit: minutes
min: 30
max: 120
description: >
Preheat the oven in advance to ensure it's as hot as it can be
A high (250 to 300 degrees celsius) is recommended)
- name: Pizza Time!
description: >
Time to make pizza!

View file

@ -0,0 +1,54 @@
recipe:
name: "New York"
description: >
A Neapolitan Style pizza prepared in a day
ingredients:
method: ratio
items:
- name: flour
unit: g
value: 0.545
- name: water
unit: ml
value: 0.436
- name: salt
unit: g
value: 0.0178
- name: yeast
unit: g
value: 0.0012
steps:
- name: Make the dough
wait:
unit: hours
min: 4
max: 6
description: >
Combine all the ingredients to make the dough, we start with just the water and salt and add the yeast after adding some of the flour to not kill the yeast.
substeps:
- name: Salt+Water
description: >
Combine the salt and the water in a bowl, stir until the salt dissolves.
- name: +20% flour
description: >
Add ~20% of the flour to the water/salt mixture and mix everything together.
- name: Yeast
description: >
Add the yeast to the mixture.
- name: Flour
description: >
Add the rest of the flour to the mixture, knead the dough for 15-20 minutes.
- name: Rise
description: >
Split the dough into doughballs and place the dough in a sealed/covered container at room temperature.
- name: Preheat Oven
wait:
unit: minutes
min: 30
max: 120
description: >
Preheat the oven in advance to ensure it's as hot as it can be
A high (250 to 300 degrees celsius) is recommended)
- name: Pizza Time!
description: >
Time to make pizza!

View file

@ -1,14 +1,16 @@
import 'package:pizzaplanner/entities/PizzaRecipe/PizzaRecipe.dart';
class PizzaEvent {
final String name;
final String type;
final PizzaRecipe recipe;
final int pizzaCount;
final int doughBallSize;
final DateTime dateTime;
PizzaEvent(
this.name,
this.type,
this.recipe,
this.pizzaCount,
this.doughBallSize,
this.dateTime

View file

@ -15,8 +15,8 @@ class PizzaRecipe {
PizzaRecipe(this.name, this.description, this.ingredients, this.recipeSteps);
static Future<PizzaRecipe> fromYaml() async{
String yamlString = await loadAsset("assets/recipes/neapolitan_cold.yaml");
static Future<PizzaRecipe> fromYaml(yamlPath) async{
String yamlString = await loadAsset(yamlPath);
var yaml = loadYaml(yamlString);
var recipe = yaml["recipe"];
@ -38,11 +38,16 @@ class PizzaRecipe {
String stepName = step["name"];
String stepDescription = step["description"];
YamlMap waitMap = step.containsKey("wait") ? step["wait"] : YamlList();
String waitUnit = waitMap["unit"];
int waitMin = waitMap["min"];
int waitMax = waitMap["max"];
print(step);
String waitUnit = "none";
int waitMin = 0;
int waitMax = 0;
if (step.containsKey("wait")) {
YamlMap waitMap = step["wait"];
waitUnit = waitMap["unit"];
waitMin = waitMap["min"];
waitMax = waitMap["max"];
}
YamlList subSteps = step.containsKey("substeps") ? step["substeps"] : YamlList();
var newSubSteps = List.generate(subSteps.length, (j) {
@ -66,5 +71,9 @@ class PizzaRecipe {
newRecipeSteps
);
}
String toString() {
return "PizzaRecipe(${this.name}, ${this.ingredients.ingredients.length}, ${this.recipeSteps.length})";
}
}

View file

@ -5,6 +5,8 @@ import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:fluttericon/font_awesome5_icons.dart';
import 'package:intl/intl.dart';
import 'package:pizzaplanner/entities/PizzaEvent.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/PizzaRecipe.dart';
import 'package:pizzaplanner/util.dart';
class AddPizzaEventPage extends StatefulWidget {
@override
@ -15,156 +17,167 @@ class AddPizzaEventPageState extends State<AddPizzaEventPage> {
final DateFormat dateFormatter = DateFormat("yyyy-MM-dd hh:mm");
String name = "";
String pizzaType = "Neapolitan";
bool initialized = false;
late PizzaRecipe pizzaRecipe;
late List<PizzaRecipe> pizzaTypes;
int pizzaCount = 1;
int doughBallSize = 250;
DateTime eventTime = DateTime.now();
bool nameValidation = false;
@override
void initState() {
super.initState();
getRecipes().then((pTypes) {
this.pizzaTypes = pTypes;
this.pizzaRecipe = this.pizzaTypes.first;
setState(() {this.initialized = true;});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add Pizza Event"),
),
body: Container(
padding: EdgeInsets.fromLTRB(40, 10, 40, 10),
child: Column(
children: <Widget>[
Row(
appBar: AppBar(
title: Text("Add Pizza Event"),
),
body: Container(
padding: EdgeInsets.fromLTRB(40, 10, 40, 10),
child: Column(
children: <Widget>[
Icon(Icons.title),
Container(width: 25),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: "Event Name",
errorText: this.nameValidation ? "Name can\'t be empty" : null
),
onChanged: (String newName) {
setState(() {
name = newName;
});
},
),
)
]
),
Row(
children: <Widget>[
Icon(FontAwesome5.pizza_slice),
Container(width: 25),
Expanded(
child: DropdownButton<String>(
value: pizzaType,
onChanged: (String? newType) {
setState(() => pizzaType = newType!);
},
items: <String>["Neapolitan", "New York", "Chicago"]
.map<DropdownMenuItem<String>>((String v) {
return DropdownMenuItem(
value: v,
child: Text(v)
);
}).toList()
),
)
]
),
Row(
children: <Widget>[
Icon(FontAwesome5.hashtag),
Expanded(
child: Slider(
value: pizzaCount.toDouble(),
min: 1,
max: 20,
divisions: 19,
label: this.pizzaCount.toString(),
onChanged: (double newPizzaCount) {
setState(() {this.pizzaCount = newPizzaCount.round();});
},
)
Row(
children: <Widget>[
Icon(Icons.title),
Container(width: 25),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: "Event Name",
errorText: this.nameValidation ? "Name can\'t be empty" : null
),
onChanged: (String newName) {
setState(() {
name = newName;
});
},
),
)
]
),
Container(
width: 25,
child: Text(this.pizzaCount.toString())
)
]
),
Row(
children: <Widget>[
Icon(FontAwesome5.weight_hanging),
Expanded(
child: Slider(
value: doughBallSize.toDouble(),
min: 100,
max: 400,
divisions: 30,
label: this.doughBallSize.toString(),
onChanged: (double newDoughBallSize) {
setState(() {this.doughBallSize = newDoughBallSize.round();});
},
)
Row(
children: <Widget>[
Icon(FontAwesome5.pizza_slice),
Container(width: 25),
Expanded(
child: this.initialized ? // Only render the dropdown if the recipes have been loaded from storage
DropdownButton<String>(
value: this.pizzaRecipe.name,
onChanged: (String? newType) {
setState(() => this.pizzaRecipe = this.pizzaTypes.firstWhere((pizzaRecipe) => pizzaRecipe.name == newType));
},
items: this.pizzaTypes.map((pizzaRecipe) {
return DropdownMenuItem(
value: pizzaRecipe.name,
child: Text(pizzaRecipe.name)
);
}).toList()
) : CircularProgressIndicator()
)
]
),
Container(
width: 25,
child: Text(this.doughBallSize.toString())
)
]
),
Row(
children: <Widget>[
Icon(FontAwesome5.calendar_alt),
Expanded(
child: InkWell(
child: Center(
child: Text(dateFormatter.format(this.eventTime)),
Row(
children: <Widget>[
Icon(FontAwesome5.hashtag),
Expanded(
child: Slider(
value: pizzaCount.toDouble(),
min: 1,
max: 20,
divisions: 19,
label: this.pizzaCount.toString(),
onChanged: (double newPizzaCount) {
setState(() {this.pizzaCount = newPizzaCount.round();});
},
)
),
onTap: () {
DatePicker.showDateTimePicker(context,
showTitleActions: true,
minTime: DateTime.now(),
currentTime: this.eventTime.difference(DateTime.now()).isNegative ? DateTime.now() : this.eventTime,
maxTime: DateTime.now().add(Duration(days: 365*10)),
onConfirm: (newEventTime) {
setState((){ this.eventTime = newEventTime; });
}
);
}
Container(
width: 25,
child: Text(this.pizzaCount.toString())
)
]
),
Row(
children: <Widget>[
Icon(FontAwesome5.weight_hanging),
Expanded(
child: Slider(
value: doughBallSize.toDouble(),
min: 100,
max: 400,
divisions: 30,
label: this.doughBallSize.toString(),
onChanged: (double newDoughBallSize) {
setState(() {this.doughBallSize = newDoughBallSize.round();});
},
)
),
Container(
width: 25,
child: Text(this.doughBallSize.toString())
)
]
),
Row(
children: <Widget>[
Icon(FontAwesome5.calendar_alt),
Expanded(
child: InkWell(
child: Center(
child: Text(dateFormatter.format(this.eventTime)),
),
onTap: () {
DatePicker.showDateTimePicker(context,
showTitleActions: true,
minTime: DateTime.now(),
currentTime: this.eventTime.difference(DateTime.now()).isNegative ? DateTime.now() : this.eventTime,
maxTime: DateTime.now().add(Duration(days: 365*10)),
onConfirm: (newEventTime) {
setState((){ this.eventTime = newEventTime; });
}
);
}
)
)
]
),
Spacer(),
SizedBox(
width: double.infinity,
height: 70,
child: Container(
color: Colors.blue,
child: TextButton(
child: Text("Add", style: TextStyle(color: Colors.white)),
onPressed: () {
if (this.name.length == 0){
setState(() { this.nameValidation = true; });
return;
}
Navigator.pop(context, PizzaEvent(
this.name,
this.pizzaRecipe,
this.pizzaCount,
this.doughBallSize,
this.eventTime
));
},
)
)
)
]
),
Spacer(),
SizedBox(
width: double.infinity,
height: 70,
child: Container(
color: Colors.blue,
child: TextButton(
child: Text("Add", style: TextStyle(color: Colors.white)),
onPressed: () {
if (this.name.length == 0){
setState(() { this.nameValidation = true; });
return;
}
Navigator.pop(context, PizzaEvent(
this.name,
this.pizzaType,
this.pizzaCount,
this.doughBallSize,
this.eventTime
));
},
)
)
)
]
]
)
)
)
);
}
}

View file

@ -1,6 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pizzaplanner/entities/PizzaEvent.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/PizzaRecipe.dart';
import 'package:pizzaplanner/util.dart';
import 'package:pizzaplanner/widgets/PizzaEventWidget.dart';
class PizzaEventsPage extends StatefulWidget {
@ -30,6 +32,7 @@ class PizzaEventsState extends State<PizzaEventsPage> {
context,
"/add",
);
if (newPizzaEvent != null){
this.addPizzaEvent(newPizzaEvent);
}

View file

@ -1,4 +1,21 @@
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
import 'package:pizzaplanner/entities/PizzaRecipe/PizzaRecipe.dart';
Future<List<PizzaRecipe>> getRecipes() async {
final manifestContent = await rootBundle.loadString('AssetManifest.json');
final Map<String, dynamic> manifestMap = json.decode(manifestContent);
final List<String> fileList = manifestMap.keys.toList();
final List<PizzaRecipe> pizzaRecipes = [];
for (var filePath in fileList) {
if (filePath.startsWith("assets/recipes") && filePath.endsWith(".yaml")) {
PizzaRecipe pizzaRecipe = await PizzaRecipe.fromYaml(filePath);
pizzaRecipes.add(pizzaRecipe);
}
}
return pizzaRecipes;
}
Future<String> loadAsset(String path) async {
return await rootBundle.loadString(path);

View file

@ -70,7 +70,7 @@ class PizzaEventWidget extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(dateFormatter.format(pizzaEvent.dateTime)),
Text(pizzaEvent.type)
Text(pizzaEvent.recipe.name)
],
),