moved to a wrapped scaffold, to get some consistency and one place to add the nav drawer

This commit is contained in:
broodjeaap89 2021-09-05 13:35:56 +02:00
parent 44cedd1a29
commit af0be6fe8b
10 changed files with 577 additions and 580 deletions

View file

@ -7,6 +7,7 @@ import 'package:fluttericon/font_awesome5_icons.dart';
import 'package:pizzaplanner/entities/pizza_event.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/pizza_recipe.dart';
import 'package:pizzaplanner/main.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:pizzaplanner/util.dart';
import 'package:hive/hive.dart';
@ -31,178 +32,172 @@ class AddPizzaEventPageState extends State<AddPizzaEventPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Add Pizza Event"),
),
resizeToAvoidBottomInset: false,
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: <Widget>[
Expanded(
flex: 40,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
const Icon(Icons.title),
Container(width: 25),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: "Event Name",
errorText: nameValidation ? """Name can't be empty""" : null
),
onChanged: (String newName) {
setState(() {
name = newName;
});
},
),
)
]
),
Row(
children: <Widget>[
const Icon(FontAwesome5.hashtag),
Expanded(
child: Slider(
return PizzaPlannerScaffold(
title: const Text("Add Pizza Event"),
body: Column(
children: <Widget>[
Expanded(
flex: 40,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
const Icon(Icons.title),
Container(width: 25),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: "Event Name",
errorText: nameValidation ? """Name can't be empty""" : null
),
onChanged: (String newName) {
setState(() {
name = newName;
});
},
),
)
]
),
Row(
children: <Widget>[
const Icon(FontAwesome5.hashtag),
Expanded(
child: Slider(
value: pizzaCount.toDouble(),
min: 1,
max: 20,
divisions: 19,
label: pizzaCount.toString(),
onChanged: (double newPizzaCount) {
setState(() {pizzaCount = newPizzaCount.round();});
},
)
),
SizedBox(
width: 25,
child: Text(pizzaCount.toString())
value: pizzaCount.toDouble(),
min: 1,
max: 20,
divisions: 19,
label: pizzaCount.toString(),
onChanged: (double newPizzaCount) {
setState(() {pizzaCount = newPizzaCount.round();});
},
)
]
),
Row(
children: <Widget>[
const Icon(FontAwesome5.weight_hanging),
Expanded(
child: Slider(
value: doughBallSize.toDouble(),
min: 100,
max: 400,
divisions: 30,
label: doughBallSize.toString(),
onChanged: (double newDoughBallSize) {
setState(() {doughBallSize = newDoughBallSize.round();});
},
)
),
SizedBox(
width: 25,
child: Text(doughBallSize.toString())
),
SizedBox(
width: 25,
child: Text(pizzaCount.toString())
)
]
),
Row(
children: <Widget>[
const Icon(FontAwesome5.weight_hanging),
Expanded(
child: Slider(
value: doughBallSize.toDouble(),
min: 100,
max: 400,
divisions: 30,
label: doughBallSize.toString(),
onChanged: (double newDoughBallSize) {
setState(() {doughBallSize = newDoughBallSize.round();});
},
)
]
),
widget.pizzaRecipe.getIngredientsTable(pizzaCount, doughBallSize),
]
)
),
const Divider(),
Expanded(
flex: 45,
child: ListView(
children: <Widget>[
Column(
children: widget.pizzaRecipe.recipeSteps.where((recipeStep) => recipeStep.waitDescription.isNotEmpty).map((recipeStep) {
return <Widget>[
Text(recipeStep.waitDescription),
Row(
children: <Widget>[
Expanded(
child: Slider(
value: recipeStep.waitValue!.toDouble(),
min: recipeStep.waitMin.toDouble(),
max: recipeStep.waitMax.toDouble(),
divisions: recipeStep.waitMax - recipeStep.waitMin,
label: recipeStep.waitValue.toString(),
onChanged: (newValue) => setState(() => recipeStep.waitValue = newValue.toInt()),
)
),
SizedBox(
width: 25,
child: Text(recipeStep.waitValue.toString())
),
SizedBox(
width: 25,
child: Text(doughBallSize.toString())
)
]
),
widget.pizzaRecipe.getIngredientsTable(pizzaCount, doughBallSize),
]
)
),
const Divider(),
Expanded(
flex: 45,
child: ListView(
children: <Widget>[
Column(
children: widget.pizzaRecipe.recipeSteps.where((recipeStep) => recipeStep.waitDescription.isNotEmpty).map((recipeStep) {
return <Widget>[
Text(recipeStep.waitDescription),
Row(
children: <Widget>[
Expanded(
child: Slider(
value: recipeStep.waitValue!.toDouble(),
min: recipeStep.waitMin.toDouble(),
max: recipeStep.waitMax.toDouble(),
divisions: recipeStep.waitMax - recipeStep.waitMin,
label: recipeStep.waitValue.toString(),
onChanged: (newValue) => setState(() => recipeStep.waitValue = newValue.toInt()),
)
]
)
];
}).expand((option) => option).toList()
)
]
)
),
const Divider(),
const Spacer(),
SizedBox(
width: double.infinity,
height: 70,
child: Container(
color: Colors.blue,
child: TextButton(
onPressed: () async {
),
SizedBox(
width: 25,
child: Text(recipeStep.waitValue.toString())
)
]
)
];
}).expand((option) => option).toList()
)
]
)
),
const Divider(),
const Spacer(),
SizedBox(
width: double.infinity,
height: 70,
child: Container(
color: Colors.blue,
child: TextButton(
onPressed: () async {
if (name.isEmpty){
setState(() { nameValidation = true; });
return;
}
setState(() { nameValidation = false; });
FocusScope.of(context).unfocus();
DateTime? eventTime = await showDialog(
context: context,
builder: (context) {
return ConfirmPizzaEventDialog(name: name, pizzaRecipe: widget.pizzaRecipe, pizzaCount: pizzaCount, doughBallSize: doughBallSize);
}
);
if (eventTime == null){
return;
}
// if the user waited to long on the confirmation dialog that the first step time is now in the past
final durationUntilFirstStep = Duration(seconds: widget.pizzaRecipe.getCurrentDuration().inSeconds);
final firstStepDateTime = eventTime.subtract(durationUntilFirstStep);
if (firstStepDateTime.isBefore(DateTime.now())){
eventTime = DateTime.now()
.add(durationUntilFirstStep)
.add(const Duration(minutes: 1));
if (name.isEmpty){
setState(() { nameValidation = true; });
return;
}
setState(() { nameValidation = false; });
FocusScope.of(context).unfocus();
DateTime? eventTime = await showDialog(
context: context,
builder: (context) {
return ConfirmPizzaEventDialog(name: name, pizzaRecipe: widget.pizzaRecipe, pizzaCount: pizzaCount, doughBallSize: doughBallSize);
}
);
if (eventTime == null){
return;
}
final pizzaEventsBox = Hive.box<PizzaEvent>("PizzaEvents");
final PizzaEvent pizzaEvent = PizzaEvent(
name,
widget.pizzaRecipe,
pizzaCount,
doughBallSize,
eventTime
);
await pizzaEventsBox.add(pizzaEvent);
// if the user waited to long on the confirmation dialog that the first step time is now in the past
final durationUntilFirstStep = Duration(seconds: widget.pizzaRecipe.getCurrentDuration().inSeconds);
final firstStepDateTime = eventTime.subtract(durationUntilFirstStep);
if (firstStepDateTime.isBefore(DateTime.now())){
eventTime = DateTime.now()
.add(durationUntilFirstStep)
.add(const Duration(minutes: 1));
}
pizzaEvent.createPizzaEventNotifications();
if(!mounted) {
return; //https://dart-lang.github.io/linter/lints/use_build_context_synchronously.html
}
Navigator.of(context).pop();
Navigator.of(context).pop(); // two times because of the pick recipe page
},
child: const Text("Review", style: TextStyle(color: Colors.white)),
)
final pizzaEventsBox = Hive.box<PizzaEvent>("PizzaEvents");
final PizzaEvent pizzaEvent = PizzaEvent(
name,
widget.pizzaRecipe,
pizzaCount,
doughBallSize,
eventTime
);
await pizzaEventsBox.add(pizzaEvent);
pizzaEvent.createPizzaEventNotifications();
if(!mounted) {
return; //https://dart-lang.github.io/linter/lints/use_build_context_synchronously.html
}
Navigator.of(context).pop();
Navigator.of(context).pop(); // two times because of the pick recipe page
},
child: const Text("Review", style: TextStyle(color: Colors.white)),
)
)
]
)
)
)
]
),
);
}
}

View file

@ -3,6 +3,7 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/ingredient.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/pizza_recipe.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/recipe_step.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:url_launcher/url_launcher.dart';
class AddRecipePage extends StatefulWidget {
@ -34,107 +35,101 @@ class AddRecipePageState extends State<AddRecipePage> {
@override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: const Text("Add Pizza Recipe"),
),
resizeToAvoidBottomInset: false,
body: Container(
padding: const EdgeInsets.all(16),
child: ListView(
children: <Widget>[
TextField(
decoration: InputDecoration(
hintText: "Recipe Name",
errorText: nameValidation ? """Name can't be empty""" : null
),
onChanged: (String newName) {
setState(() {
pizzaRecipe.name = newName;
});
},
return PizzaPlannerScaffold(
title: const Text("Add Recipe"),
body: ListView(
children: <Widget>[
TextField(
decoration: InputDecoration(
hintText: "Recipe Name",
errorText: nameValidation ? """Name can't be empty""" : null
),
const Divider(),
TextField(
decoration: InputDecoration(
hintText: "Recipe Description",
errorText: nameValidation ? """Description can't be empty""" : null
),
maxLines: 8,
onChanged: (String newDescription) {
setState(() {
pizzaRecipe.description = newDescription;
});
},
onChanged: (String newName) {
setState(() {
pizzaRecipe.name = newName;
});
},
),
const Divider(),
TextField(
decoration: InputDecoration(
hintText: "Recipe Description",
errorText: nameValidation ? """Description can't be empty""" : null
),
const Divider(),
Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return PreviewMarkdownDescription(pizzaRecipe.description);
}
);
},
child: const Text("Preview", style: TextStyle(color: Colors.white)),
)
)
),
const Expanded(
maxLines: 8,
onChanged: (String newDescription) {
setState(() {
pizzaRecipe.description = newDescription;
});
},
),
const Divider(),
Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return PreviewMarkdownDescription(pizzaRecipe.description);
}
);
},
child: const Text("Preview", style: TextStyle(color: Colors.white)),
)
)
),
const Expanded(
child: SizedBox()
),
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () {
launch("https://guides.github.com/features/mastering-markdown/");
},
child: const Text("Markdown?", style: TextStyle(color: Colors.white)),
)
)
)
],
),
const Divider(),
const Center(
),
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () {
launch("https://guides.github.com/features/mastering-markdown/");
},
child: const Text("Markdown?", style: TextStyle(color: Colors.white)),
)
)
)
],
),
const Divider(),
const Center(
child: Text("Ingredients")
),
const Divider(),
Container(
color: Colors.blue,
child: TextButton(
onPressed: () {
setState(() {
pizzaRecipe.ingredients.add(
Ingredient(
"",
"",
0.0
)
);
});
},
child: const Text("Add Ingredient", style: TextStyle(color: Colors.white)),
)
),
const Divider(),
] + pizzaRecipe.ingredients.map((ingredient) => buildIngredientRow(ingredient)).toList() + [
],
)
)
),
const Divider(),
Container(
color: Colors.blue,
child: TextButton(
onPressed: () {
setState(() {
pizzaRecipe.ingredients.add(
Ingredient(
"",
"",
0.0
)
);
});
},
child: const Text("Add Ingredient", style: TextStyle(color: Colors.white)),
)
),
const Divider(),
] + pizzaRecipe.ingredients.map((ingredient) => buildIngredientRow(ingredient)).toList() + [
],
),
);
}

View file

@ -2,42 +2,36 @@ import 'package:flutter/material.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/pizza_recipe.dart';
import 'package:pizzaplanner/pages/nav_drawer.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:pizzaplanner/widgets/pizza_recipe_widget.dart';
class PickPizzaRecipePage extends StatelessWidget {
@override
Widget build(BuildContext context){
return Scaffold(
drawer: NavDrawer(),
appBar: AppBar(
title: const Text("Pick Pizza Recipe"),
),
resizeToAvoidBottomInset: false,
body: Container(
padding: const EdgeInsets.all(16),
child: ValueListenableBuilder(
valueListenable: Hive.box<PizzaRecipe>("PizzaRecipes").listenable(),
builder: (context, Box<PizzaRecipe> pizzaRecipesBox, widget) {
return ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: pizzaRecipesBox.length,
itemBuilder: (context, i) {
final pizzaRecipe = pizzaRecipesBox.get(i);
if (pizzaRecipe == null){
return const SizedBox();
}
return InkWell(
onTap: () {
Navigator.pushNamed(context, "/event/add", arguments: pizzaRecipe);
},
child: PizzaRecipeWidget(pizzaRecipe),
);
},
separatorBuilder: (BuildContext context, int i) => const Divider(),
);
}
)
)
return PizzaPlannerScaffold(
title: const Text("Pick Recipe"),
body: ValueListenableBuilder(
valueListenable: Hive.box<PizzaRecipe>("PizzaRecipes").listenable(),
builder: (context, Box<PizzaRecipe> pizzaRecipesBox, widget) {
return ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: pizzaRecipesBox.length,
itemBuilder: (context, i) {
final pizzaRecipe = pizzaRecipesBox.get(i);
if (pizzaRecipe == null){
return const SizedBox();
}
return InkWell(
onTap: () {
Navigator.pushNamed(context, "/event/add", arguments: pizzaRecipe);
},
child: PizzaRecipeWidget(pizzaRecipe),
);
},
separatorBuilder: (BuildContext context, int i) => const Divider(),
);
}
),
);
}
}

View file

@ -9,6 +9,7 @@ import 'package:pizzaplanner/entities/pizza_event.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/recipe_step.dart';
import 'package:pizzaplanner/main.dart';
import 'package:pizzaplanner/pages/recipe_step_instruction_page.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:vibration/vibration.dart';
@ -56,98 +57,92 @@ class PizzaEventNotificationState extends State<PizzaEventNotificationPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("From notification"),
return PizzaPlannerScaffold(
title: Text(recipeStep.name),
body: Column(
children: <Widget>[
Expanded(
flex: 10,
child: Center(
child: Text(pizzaEvent.name),
),
),
Expanded(
flex: 10,
child: Center(
child: Text(recipeStep.name)
),
),
const Divider(),
Expanded(
flex: 10,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () async {
showDialog(context: context, builder: (BuildContext context) {
return buildIgnoreDialog();
});
},
child: const Text("Ignore", style: TextStyle(color: Colors.white)),
)
)
),
const Divider(),
Expanded(
flex: 30,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () async {
setRecipeStepNotification(DateTime.now().add(const Duration(minutes: 15)));
Navigator.pop(context);
},
onLongPress: () async {
final future5Min = DateTime.now().add(const Duration(minutes: 5));
DatePicker.showDateTimePicker(context,
minTime: future5Min,
currentTime: future5Min,
maxTime: DateTime.now().add(const Duration(days: 365*10)),
onConfirm: (newEventTime) {
setState((){
setRecipeStepNotification(newEventTime);
Navigator.pop(context);
});
}
);
},
child: const Text("Snooze 15 minutes", style: TextStyle(color: Colors.white)),
)
)
),
const Divider(),
Expanded(
flex: 40,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () async {
Navigator.pop(context);
Navigator.pushNamed(
context,
"/event/recipe_step",
arguments: RecipeStepInstructionPageArguments(
pizzaEvent,
recipeStep
)
);
},
child: const Text("Start!", style: TextStyle(color: Colors.white)),
)
)
),
]
),
resizeToAvoidBottomInset: false,
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: <Widget>[
Expanded(
flex: 10,
child: Center(
child: Text(pizzaEvent.name),
),
),
Expanded(
flex: 10,
child: Center(
child: Text(recipeStep.name)
),
),
const Divider(),
Expanded(
flex: 10,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () async {
showDialog(context: context, builder: (BuildContext context) {
return buildIgnoreDialog();
});
},
child: const Text("Ignore", style: TextStyle(color: Colors.white)),
)
)
),
const Divider(),
Expanded(
flex: 30,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () async {
setRecipeStepNotification(DateTime.now().add(const Duration(minutes: 15)));
Navigator.pop(context);
},
onLongPress: () async {
final future5Min = DateTime.now().add(const Duration(minutes: 5));
DatePicker.showDateTimePicker(context,
minTime: future5Min,
currentTime: future5Min,
maxTime: DateTime.now().add(const Duration(days: 365*10)),
onConfirm: (newEventTime) {
setState((){
setRecipeStepNotification(newEventTime);
Navigator.pop(context);
});
}
);
},
child: const Text("Snooze 15 minutes", style: TextStyle(color: Colors.white)),
)
)
),
const Divider(),
Expanded(
flex: 40,
child: Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () async {
Navigator.pop(context);
Navigator.pushNamed(
context,
"/event/recipe_step",
arguments: RecipeStepInstructionPageArguments(
pizzaEvent,
recipeStep
)
);
},
child: const Text("Start!", style: TextStyle(color: Colors.white)),
)
)
),
]
)
)
);
}

View file

@ -7,6 +7,7 @@ import 'package:pizzaplanner/entities/PizzaRecipe/ingredient.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/recipe_step.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/recipe_substep.dart';
import 'package:pizzaplanner/main.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:pizzaplanner/util.dart';
import 'package:pizzaplanner/widgets/pizza_recipe_widget.dart';
import 'package:url_launcher/url_launcher.dart';
@ -26,35 +27,30 @@ class PizzaEventPageState extends State<PizzaEventPage> {
Widget build(BuildContext context) {
final recipeStepCount = widget.pizzaEvent.recipe.recipeSteps.length;
final completedRecipeStepCount = widget.pizzaEvent.recipe.recipeSteps.where((recipeStep) => recipeStep.completed).length;
return Scaffold(
appBar: AppBar(
title: Text(widget.pizzaEvent.name),
),
resizeToAvoidBottomInset: false,
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: <Widget>[
Expanded(
flex: 15,
child: Column(
children: <Widget>[
Text(widget.pizzaEvent.name),
Text(getTimeRemainingString(widget.pizzaEvent.dateTime)),
Container(
color: Colors.blue,
child: TextButton(
onPressed: () {
Navigator.pushNamed(context, "/recipe/view", arguments: widget.pizzaEvent.recipe);
},
child: Text(widget.pizzaEvent.recipe.name, style: const TextStyle(color: Colors.white)),
)
)
],
),
return PizzaPlannerScaffold(
title: Text(widget.pizzaEvent.name),
body: Column(
children: <Widget>[
Expanded(
flex: 15,
child: Column(
children: <Widget>[
Text(widget.pizzaEvent.name),
Text(getTimeRemainingString(widget.pizzaEvent.dateTime)),
Container(
color: Colors.blue,
child: TextButton(
onPressed: () {
Navigator.pushNamed(context, "/recipe/view", arguments: widget.pizzaEvent.recipe);
},
child: Text(widget.pizzaEvent.recipe.name, style: const TextStyle(color: Colors.white)),
)
)
],
),
const Divider(),
Expanded(
),
const Divider(),
Expanded(
flex: 80,
child: ListView(
children: <Widget>[
@ -78,28 +74,27 @@ class PizzaEventPageState extends State<PizzaEventPage> {
] + widget.pizzaEvent.recipe.ingredients.map((ingredient) => buildIngredientWidget(ingredient)).toList(),
),
Table(
columnWidths: const <int, TableColumnWidth>{
0: FlexColumnWidth(4),
1: FlexColumnWidth(3),
2: FlexColumnWidth(),
},
children: <TableRow>[
TableRow(
children: <TableCell>[
const TableCell(child: Text("Recipe Step")),
const TableCell(child: Text("When")),
TableCell(child: Text("$completedRecipeStepCount/$recipeStepCount")),
]
)
] + widget.pizzaEvent.recipe.recipeSteps.map((recipeStep) => buildRecipeStepWhenWidget(recipeStep)).toList()
columnWidths: const <int, TableColumnWidth>{
0: FlexColumnWidth(4),
1: FlexColumnWidth(3),
2: FlexColumnWidth(),
},
children: <TableRow>[
TableRow(
children: <TableCell>[
const TableCell(child: Text("Recipe Step")),
const TableCell(child: Text("When")),
TableCell(child: Text("$completedRecipeStepCount/$recipeStepCount")),
]
)
] + widget.pizzaEvent.recipe.recipeSteps.map((recipeStep) => buildRecipeStepWhenWidget(recipeStep)).toList()
),
const Divider(),
]
]
)
),
],
)
)
),
],
),
);
}

View file

@ -1,6 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pizzaplanner/entities/pizza_event.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:pizzaplanner/widgets/pizza_event_widget.dart';
import 'package:hive/hive.dart';
@ -17,47 +18,42 @@ class PizzaEventsState extends State<PizzaEventsPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Pizza Events"),
),
body: Container(
padding: const EdgeInsets.all(16),
child: ValueListenableBuilder(
valueListenable: Hive.box<PizzaEvent>("PizzaEvents").listenable(),
builder: (context, Box<PizzaEvent> box, widget) {
if (box.isEmpty){
return Container();
}
return ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: box.length,
itemBuilder: (BuildContext context, int i) => PizzaEventWidget(box.getAt(i)!),
separatorBuilder: (BuildContext context, int i) => const Divider(),
);
return PizzaPlannerScaffold(
title: const Text("Pizza Events"),
body: ValueListenableBuilder(
valueListenable: Hive.box<PizzaEvent>("PizzaEvents").listenable(),
builder: (context, Box<PizzaEvent> box, widget) {
if (box.isEmpty){
return Container();
}
),
return ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: box.length,
itemBuilder: (BuildContext context, int i) => PizzaEventWidget(box.getAt(i)!),
separatorBuilder: (BuildContext context, int i) => const Divider(),
);
}
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final dynamic newPizzaEvent = await Navigator.pushNamed(
context,
"/event/pick_recipe",
);
onPressed: () async {
final dynamic newPizzaEvent = await Navigator.pushNamed(
context,
"/event/pick_recipe",
);
if (newPizzaEvent != null){
addPizzaEvent(newPizzaEvent as PizzaEvent);
}
},
tooltip: "Add Pizza Plans",
child: Center(
child: Row(
children: const <Widget>[
Icon(Icons.add),
Icon(Icons.local_pizza_rounded),
]
if (newPizzaEvent != null){
addPizzaEvent(newPizzaEvent as PizzaEvent);
}
},
tooltip: "Add Pizza Plans",
child: Center(
child: Row(
children: const <Widget>[
Icon(Icons.add),
Icon(Icons.local_pizza_rounded),
]
)
)
)
),
);
}

View file

@ -3,6 +3,7 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/pizza_recipe.dart';
import 'package:pizzaplanner/entities/pizza_event.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/recipe_step.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:url_launcher/url_launcher.dart';
class RecipePage extends StatefulWidget {
@ -41,38 +42,35 @@ class RecipePageState extends State<RecipePage> {
);
}
}
return Scaffold(
appBar: AppBar(
return PizzaPlannerScaffold(
title: Text(widget.pizzaRecipe.name),
),
resizeToAvoidBottomInset: false,
body: Column(
children: <Widget>[
Expanded(
flex: 95,
child: PageView(
onPageChanged: (newPage) => setState(() {page = newPage;}),
controller: controller,
children: <Widget>[
Markdown(
data: widget.pizzaRecipe.description,
onTapLink: (text, url, title) {
launch(url!);
},
),
] + widget.pizzaRecipe.recipeSteps.map((recipeStep) => buildRecipeStep(recipeStep)).toList()
)
),
Expanded(
flex: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: pageIndex
)
)
],
)
body: Column(
children: <Widget>[
Expanded(
flex: 95,
child: PageView(
onPageChanged: (newPage) => setState(() {page = newPage;}),
controller: controller,
children: <Widget>[
Markdown(
data: widget.pizzaRecipe.description,
onTapLink: (text, url, title) {
launch(url!);
},
),
] + widget.pizzaRecipe.recipeSteps.map((recipeStep) => buildRecipeStep(recipeStep)).toList()
)
),
Expanded(
flex: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: pageIndex
)
)
],
),
);
}

View file

@ -4,6 +4,7 @@ import 'package:pizzaplanner/entities/PizzaRecipe/recipe_step.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/recipe_substep.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:url_launcher/url_launcher.dart';
class RecipeStepInstructionPageArguments {
@ -49,41 +50,37 @@ class RecipeStepInstructionState extends State<RecipeStepInstructionPage> {
} else if (page > 0){
nextButtonText = "Next step";
}
return Scaffold(
appBar: AppBar(
return PizzaPlannerScaffold(
title: Text(widget.recipeStep.name),
),
resizeToAvoidBottomInset: false,
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
body: Column(
children: <Widget>[
Expanded(
flex: 90,
child: PageView(
controller: controller,
onPageChanged: (newPage) => setState(() {
page = newPage;
if (widget.recipeStep.subSteps.isNotEmpty && page != 0) {
currentSubStep = widget.recipeStep.subSteps.elementAt(newPage-1);
}
}),
children: <Widget>[
Markdown(
data: widget.recipeStep.description,
onTapLink: (text, url, title) {
launch(url!);
},
)
] + widget.recipeStep.subSteps.map((subStep) {
return Markdown(
data: subStep.description,
onTapLink: (text, url, title) {
launch(url!);
},
);
}).toList()
)
flex: 90,
child: PageView(
controller: controller,
onPageChanged: (newPage) => setState(() {
page = newPage;
if (widget.recipeStep.subSteps.isNotEmpty && page != 0) {
currentSubStep = widget.recipeStep.subSteps.elementAt(newPage-1);
}
}),
children: <Widget>[
Markdown(
data: widget.recipeStep.description,
onTapLink: (text, url, title) {
launch(url!);
},
)
] + widget.recipeStep.subSteps.map((subStep) {
return Markdown(
data: subStep.description,
onTapLink: (text, url, title) {
launch(url!);
},
);
}).toList()
)
),
Expanded(
flex: 10,
@ -139,8 +136,7 @@ class RecipeStepInstructionState extends State<RecipeStepInstructionPage> {
),
)
]
)
)
),
);
}
}

View file

@ -2,63 +2,57 @@ import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:pizzaplanner/entities/PizzaRecipe/pizza_recipe.dart';
import 'package:pizzaplanner/pages/nav_drawer.dart';
import 'package:pizzaplanner/pages/scaffold.dart';
import 'package:pizzaplanner/widgets/pizza_recipe_widget.dart';
class RecipesPage extends StatelessWidget {
@override
Widget build(BuildContext context){
return Scaffold(
drawer: NavDrawer(),
appBar: AppBar(
title: const Text("Recipes"),
),
resizeToAvoidBottomInset: false,
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: <Widget>[
const Expanded(
flex: 5,
child: Text("Search here maybe")
),
Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () async {
Navigator.pushNamed(context, "/recipes/add");
},
child: const Text("New Recipe", style: TextStyle(color: Colors.white)),
)
),
const Divider(),
Expanded(
flex: 50,
child: ValueListenableBuilder(
valueListenable: Hive.box<PizzaRecipe>("PizzaRecipes").listenable(),
builder: (context, Box<PizzaRecipe> pizzaRecipesBox, widget) {
return ListView.separated(
itemCount: pizzaRecipesBox.length,
itemBuilder: (context, i) {
final pizzaRecipe = pizzaRecipesBox.get(i);
if (pizzaRecipe == null){
return const SizedBox();
}
return InkWell(
onTap: () {
Navigator.pushNamed(context, "/recipe/view", arguments: pizzaRecipe);
},
child: PizzaRecipeWidget(pizzaRecipe),
);
},
separatorBuilder: (BuildContext context, int i) => const Divider(),
);
}
),
return PizzaPlannerScaffold(
title: const Text("Pizza Recipes"),
body: Column(
children: <Widget>[
const Expanded(
flex: 5,
child: Text("Search here maybe")
),
Container(
color: Colors.blue,
width: double.infinity,
child: TextButton(
onPressed: () async {
Navigator.pushNamed(context, "/recipes/add");
},
child: const Text("New Recipe", style: TextStyle(color: Colors.white)),
)
]
)
)
),
const Divider(),
Expanded(
flex: 50,
child: ValueListenableBuilder(
valueListenable: Hive.box<PizzaRecipe>("PizzaRecipes").listenable(),
builder: (context, Box<PizzaRecipe> pizzaRecipesBox, widget) {
return ListView.separated(
itemCount: pizzaRecipesBox.length,
itemBuilder: (context, i) {
final pizzaRecipe = pizzaRecipesBox.get(i);
if (pizzaRecipe == null){
return const SizedBox();
}
return InkWell(
onTap: () {
Navigator.pushNamed(context, "/recipe/view", arguments: pizzaRecipe);
},
child: PizzaRecipeWidget(pizzaRecipe),
);
},
separatorBuilder: (BuildContext context, int i) => const Divider(),
);
}
),
)
]
),
);
}
}

39
lib/pages/scaffold.dart Normal file
View file

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:pizzaplanner/pages/nav_drawer.dart';
class PizzaPlannerScaffold extends StatelessWidget {
late final Widget _body;
late final Widget _appBarTitle;
late final bool _resizeToAvoidBottomInset;
late final EdgeInsets _edgeInsets;
late final FloatingActionButton? _floatingActionButton;
PizzaPlannerScaffold({
required Widget body,
required Widget title,
bool resizeToAvoidBottomInset = false,
EdgeInsets edgeInsets = const EdgeInsets.all(16),
FloatingActionButton? floatingActionButton
}){
_body = body;
_appBarTitle = title;
_resizeToAvoidBottomInset = resizeToAvoidBottomInset;
_edgeInsets = edgeInsets;
_floatingActionButton = floatingActionButton;
}
@override
Widget build(BuildContext context){
return Scaffold(
body: Container(
padding: _edgeInsets,
child: _body
),
appBar: AppBar(
title: _appBarTitle,
),
resizeToAvoidBottomInset: _resizeToAvoidBottomInset,
drawer: NavDrawer(),
floatingActionButton: _floatingActionButton,
);
}
}