switched the addPizzaEventPage to a recipe list from yamls on the device
This commit is contained in:
parent
2ffe58e75c
commit
c43d92c0f1
8 changed files with 296 additions and 144 deletions
54
assets/recipes/neapolitan_quick.yaml
Normal file
54
assets/recipes/neapolitan_quick.yaml
Normal 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!
|
54
assets/recipes/new_york.yaml
Normal file
54
assets/recipes/new_york.yaml
Normal 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!
|
|
@ -1,14 +1,16 @@
|
||||||
|
|
||||||
|
import 'package:pizzaplanner/entities/PizzaRecipe/PizzaRecipe.dart';
|
||||||
|
|
||||||
class PizzaEvent {
|
class PizzaEvent {
|
||||||
final String name;
|
final String name;
|
||||||
final String type;
|
final PizzaRecipe recipe;
|
||||||
final int pizzaCount;
|
final int pizzaCount;
|
||||||
final int doughBallSize;
|
final int doughBallSize;
|
||||||
final DateTime dateTime;
|
final DateTime dateTime;
|
||||||
|
|
||||||
PizzaEvent(
|
PizzaEvent(
|
||||||
this.name,
|
this.name,
|
||||||
this.type,
|
this.recipe,
|
||||||
this.pizzaCount,
|
this.pizzaCount,
|
||||||
this.doughBallSize,
|
this.doughBallSize,
|
||||||
this.dateTime
|
this.dateTime
|
||||||
|
|
|
@ -15,8 +15,8 @@ class PizzaRecipe {
|
||||||
|
|
||||||
PizzaRecipe(this.name, this.description, this.ingredients, this.recipeSteps);
|
PizzaRecipe(this.name, this.description, this.ingredients, this.recipeSteps);
|
||||||
|
|
||||||
static Future<PizzaRecipe> fromYaml() async{
|
static Future<PizzaRecipe> fromYaml(yamlPath) async{
|
||||||
String yamlString = await loadAsset("assets/recipes/neapolitan_cold.yaml");
|
String yamlString = await loadAsset(yamlPath);
|
||||||
var yaml = loadYaml(yamlString);
|
var yaml = loadYaml(yamlString);
|
||||||
var recipe = yaml["recipe"];
|
var recipe = yaml["recipe"];
|
||||||
|
|
||||||
|
@ -38,11 +38,16 @@ class PizzaRecipe {
|
||||||
String stepName = step["name"];
|
String stepName = step["name"];
|
||||||
String stepDescription = step["description"];
|
String stepDescription = step["description"];
|
||||||
|
|
||||||
YamlMap waitMap = step.containsKey("wait") ? step["wait"] : YamlList();
|
String waitUnit = "none";
|
||||||
String waitUnit = waitMap["unit"];
|
int waitMin = 0;
|
||||||
int waitMin = waitMap["min"];
|
int waitMax = 0;
|
||||||
int waitMax = waitMap["max"];
|
|
||||||
print(step);
|
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();
|
YamlList subSteps = step.containsKey("substeps") ? step["substeps"] : YamlList();
|
||||||
var newSubSteps = List.generate(subSteps.length, (j) {
|
var newSubSteps = List.generate(subSteps.length, (j) {
|
||||||
|
@ -66,5 +71,9 @@ class PizzaRecipe {
|
||||||
newRecipeSteps
|
newRecipeSteps
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toString() {
|
||||||
|
return "PizzaRecipe(${this.name}, ${this.ingredients.ingredients.length}, ${this.recipeSteps.length})";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
|
||||||
import 'package:fluttericon/font_awesome5_icons.dart';
|
import 'package:fluttericon/font_awesome5_icons.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:pizzaplanner/entities/PizzaEvent.dart';
|
import 'package:pizzaplanner/entities/PizzaEvent.dart';
|
||||||
|
import 'package:pizzaplanner/entities/PizzaRecipe/PizzaRecipe.dart';
|
||||||
|
import 'package:pizzaplanner/util.dart';
|
||||||
|
|
||||||
class AddPizzaEventPage extends StatefulWidget {
|
class AddPizzaEventPage extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
|
@ -15,156 +17,167 @@ class AddPizzaEventPageState extends State<AddPizzaEventPage> {
|
||||||
final DateFormat dateFormatter = DateFormat("yyyy-MM-dd hh:mm");
|
final DateFormat dateFormatter = DateFormat("yyyy-MM-dd hh:mm");
|
||||||
|
|
||||||
String name = "";
|
String name = "";
|
||||||
String pizzaType = "Neapolitan";
|
bool initialized = false;
|
||||||
|
late PizzaRecipe pizzaRecipe;
|
||||||
|
late List<PizzaRecipe> pizzaTypes;
|
||||||
int pizzaCount = 1;
|
int pizzaCount = 1;
|
||||||
int doughBallSize = 250;
|
int doughBallSize = 250;
|
||||||
DateTime eventTime = DateTime.now();
|
DateTime eventTime = DateTime.now();
|
||||||
|
|
||||||
bool nameValidation = false;
|
bool nameValidation = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
getRecipes().then((pTypes) {
|
||||||
|
this.pizzaTypes = pTypes;
|
||||||
|
this.pizzaRecipe = this.pizzaTypes.first;
|
||||||
|
setState(() {this.initialized = true;});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text("Add Pizza Event"),
|
title: Text("Add Pizza Event"),
|
||||||
),
|
),
|
||||||
body: Container(
|
body: Container(
|
||||||
padding: EdgeInsets.fromLTRB(40, 10, 40, 10),
|
padding: EdgeInsets.fromLTRB(40, 10, 40, 10),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
|
||||||
Row(
|
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Icon(Icons.title),
|
Row(
|
||||||
Container(width: 25),
|
children: <Widget>[
|
||||||
Expanded(
|
Icon(Icons.title),
|
||||||
child: TextField(
|
Container(width: 25),
|
||||||
decoration: InputDecoration(
|
Expanded(
|
||||||
hintText: "Event Name",
|
child: TextField(
|
||||||
errorText: this.nameValidation ? "Name can\'t be empty" : null
|
decoration: InputDecoration(
|
||||||
),
|
hintText: "Event Name",
|
||||||
onChanged: (String newName) {
|
errorText: this.nameValidation ? "Name can\'t be empty" : null
|
||||||
setState(() {
|
),
|
||||||
name = newName;
|
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();});
|
|
||||||
},
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
Container(
|
Row(
|
||||||
width: 25,
|
children: <Widget>[
|
||||||
child: Text(this.pizzaCount.toString())
|
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>(
|
||||||
Row(
|
value: this.pizzaRecipe.name,
|
||||||
children: <Widget>[
|
onChanged: (String? newType) {
|
||||||
Icon(FontAwesome5.weight_hanging),
|
setState(() => this.pizzaRecipe = this.pizzaTypes.firstWhere((pizzaRecipe) => pizzaRecipe.name == newType));
|
||||||
Expanded(
|
},
|
||||||
child: Slider(
|
items: this.pizzaTypes.map((pizzaRecipe) {
|
||||||
value: doughBallSize.toDouble(),
|
return DropdownMenuItem(
|
||||||
min: 100,
|
value: pizzaRecipe.name,
|
||||||
max: 400,
|
child: Text(pizzaRecipe.name)
|
||||||
divisions: 30,
|
);
|
||||||
label: this.doughBallSize.toString(),
|
}).toList()
|
||||||
onChanged: (double newDoughBallSize) {
|
) : CircularProgressIndicator()
|
||||||
setState(() {this.doughBallSize = newDoughBallSize.round();});
|
)
|
||||||
},
|
]
|
||||||
)
|
|
||||||
),
|
),
|
||||||
Container(
|
Row(
|
||||||
width: 25,
|
children: <Widget>[
|
||||||
child: Text(this.doughBallSize.toString())
|
Icon(FontAwesome5.hashtag),
|
||||||
)
|
Expanded(
|
||||||
]
|
child: Slider(
|
||||||
),
|
value: pizzaCount.toDouble(),
|
||||||
Row(
|
min: 1,
|
||||||
children: <Widget>[
|
max: 20,
|
||||||
Icon(FontAwesome5.calendar_alt),
|
divisions: 19,
|
||||||
Expanded(
|
label: this.pizzaCount.toString(),
|
||||||
child: InkWell(
|
onChanged: (double newPizzaCount) {
|
||||||
child: Center(
|
setState(() {this.pizzaCount = newPizzaCount.round();});
|
||||||
child: Text(dateFormatter.format(this.eventTime)),
|
},
|
||||||
|
)
|
||||||
),
|
),
|
||||||
onTap: () {
|
Container(
|
||||||
DatePicker.showDateTimePicker(context,
|
width: 25,
|
||||||
showTitleActions: true,
|
child: Text(this.pizzaCount.toString())
|
||||||
minTime: DateTime.now(),
|
)
|
||||||
currentTime: this.eventTime.difference(DateTime.now()).isNegative ? DateTime.now() : this.eventTime,
|
]
|
||||||
maxTime: DateTime.now().add(Duration(days: 365*10)),
|
),
|
||||||
onConfirm: (newEventTime) {
|
Row(
|
||||||
setState((){ this.eventTime = newEventTime; });
|
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
|
|
||||||
));
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
]
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:pizzaplanner/entities/PizzaEvent.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';
|
import 'package:pizzaplanner/widgets/PizzaEventWidget.dart';
|
||||||
|
|
||||||
class PizzaEventsPage extends StatefulWidget {
|
class PizzaEventsPage extends StatefulWidget {
|
||||||
|
@ -30,6 +32,7 @@ class PizzaEventsState extends State<PizzaEventsPage> {
|
||||||
context,
|
context,
|
||||||
"/add",
|
"/add",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (newPizzaEvent != null){
|
if (newPizzaEvent != null){
|
||||||
this.addPizzaEvent(newPizzaEvent);
|
this.addPizzaEvent(newPizzaEvent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,21 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/services.dart' show rootBundle;
|
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 {
|
Future<String> loadAsset(String path) async {
|
||||||
return await rootBundle.loadString(path);
|
return await rootBundle.loadString(path);
|
||||||
|
|
|
@ -70,7 +70,7 @@ class PizzaEventWidget extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(dateFormatter.format(pizzaEvent.dateTime)),
|
Text(dateFormatter.format(pizzaEvent.dateTime)),
|
||||||
Text(pizzaEvent.type)
|
Text(pizzaEvent.recipe.name)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue