Skip to content
This repository has been archived by the owner on Sep 14, 2024. It is now read-only.

Commit

Permalink
Merge branch 'feature/edit-recipe' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Teifun2 committed Aug 15, 2020
2 parents 257f290 + 57ea590 commit 34de89e
Show file tree
Hide file tree
Showing 11 changed files with 441 additions and 109 deletions.
15 changes: 14 additions & 1 deletion lib/src/blocs/recipe/recipe_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class RecipeBloc extends Bloc<RecipeEvent, RecipeState> {
Stream<RecipeState> mapEventToState(RecipeEvent event) async* {
if (event is RecipeLoaded) {
yield* _mapRecipeLoadedToState(event);
} else if (event is RecipeUpdated) {
yield* _mapRecipeUpdatedToState(event);
}
}

Expand All @@ -20,9 +22,20 @@ class RecipeBloc extends Bloc<RecipeEvent, RecipeState> {
try {
yield RecipeLoadInProgress();
final recipe = await dataRepository.fetchRecipe(recipeLoaded.recipeId);
yield RecipeLoadSuccess(recipe: recipe);
yield RecipeLoadSuccess(recipe);
} catch (_) {
yield RecipeLoadFailure(_.toString());
}
}

Stream<RecipeState> _mapRecipeUpdatedToState(
RecipeUpdated recipeUpdated) async* {
try {
yield RecipeUpdateInProgress();
int recipeId = await dataRepository.updateRecipe(recipeUpdated.recipe);
yield RecipeUpdateSuccess(recipeId);
} catch (_) {
yield RecipeUpdateFailure(_.toString());
}
}
}
12 changes: 11 additions & 1 deletion lib/src/blocs/recipe/recipe_event.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:nextcloud_cookbook_flutter/src/models/recipe.dart';

abstract class RecipeEvent extends Equatable {
const RecipeEvent();
Expand All @@ -15,4 +16,13 @@ class RecipeLoaded extends RecipeEvent {

@override
List<Object> get props => [recipeId];
}
}

class RecipeUpdated extends RecipeEvent {
final Recipe recipe;

const RecipeUpdated(this.recipe);

@override
List<Object> get props => [recipe];
}
38 changes: 30 additions & 8 deletions lib/src/blocs/recipe/recipe_state.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:nextcloud_cookbook_flutter/src/models/recipe.dart';

abstract class RecipeState extends Equatable {
Expand All @@ -11,22 +10,45 @@ abstract class RecipeState extends Equatable {

class RecipeInitial extends RecipeState {}

class RecipeLoadSuccess extends RecipeState {
class RecipeFailure extends RecipeState {
final String errorMsg;

const RecipeFailure(this.errorMsg);

@override
List<Object> get props => [errorMsg];
}

class RecipeSuccess extends RecipeState {
final Recipe recipe;

RecipeLoadSuccess({@required this.recipe});
const RecipeSuccess(this.recipe);

@override
List<Object> get props => [recipe];
}

class RecipeLoadFailure extends RecipeState {
final String errorMsg;
class RecipeLoadSuccess extends RecipeSuccess {
RecipeLoadSuccess(Recipe recipe) : super(recipe);
}

const RecipeLoadFailure(this.errorMsg);
class RecipeLoadFailure extends RecipeFailure {
RecipeLoadFailure(String errorMsg) : super(errorMsg);
}

class RecipeLoadInProgress extends RecipeState {}

class RecipeUpdateFailure extends RecipeFailure {
RecipeUpdateFailure(String errorMsg) : super(errorMsg);
}

class RecipeUpdateSuccess extends RecipeState {
final int recipeId;

const RecipeUpdateSuccess(this.recipeId);

@override
List<Object> get props => [errorMsg];
List<Object> get props => [recipeId];
}

class RecipeLoadInProgress extends RecipeState {}
class RecipeUpdateInProgress extends RecipeState {}
93 changes: 91 additions & 2 deletions lib/src/models/recipe.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ class Recipe extends Equatable {
final String description;
final List<String> recipeIngredient;
final List<String> recipeInstructions;
final List<String> tool;
final int recipeYield;
final Duration prepTime;
final Duration cookTime;
final Duration totalTime;
final String keywords;
final String image;
final String url;

const Recipe._(
this.id,
Expand All @@ -24,10 +28,14 @@ class Recipe extends Equatable {
this.description,
this.recipeIngredient,
this.recipeInstructions,
this.tool,
this.recipeYield,
this.prepTime,
this.cookTime,
this.totalTime);
this.totalTime,
this.keywords,
this.image,
this.url);

factory Recipe(String jsonString) {
Map<String, dynamic> data = json.decode(jsonString);
Expand All @@ -41,6 +49,7 @@ class Recipe extends Equatable {
data["recipeIngredient"].cast<String>().toList();
List<String> recipeInstructions =
data["recipeInstructions"].cast<String>().toList();
List<String> tool = data["tool"].cast<String>().toList();
int recipeYield = data["recipeYield"];
Duration prepTime = data.containsKey("prepTime") && data["prepTime"] != ""
? IsoTimeFormat.toDuration(data["prepTime"])
Expand All @@ -52,6 +61,9 @@ class Recipe extends Equatable {
data.containsKey("totalTime") && data["totalTime"] != ""
? IsoTimeFormat.toDuration(data["totalTime"])
: null;
String keywords = data["keywords"];
String image = data["image"];
String url = data["url"];

return Recipe._(
id,
Expand All @@ -61,12 +73,89 @@ class Recipe extends Equatable {
description,
recipeIngredient,
recipeInstructions,
tool,
recipeYield,
prepTime,
cookTime,
totalTime);
totalTime,
keywords,
image,
url);
}

Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'imageUrl': imageUrl,
'recipeCategory': recipeCategory,
'description': description,
'recipeIngredient': recipeIngredient,
'recipeInstructions': recipeInstructions,
'tool': tool,
'recipeYield': recipeYield,
'prepTime': prepTime,
'cookTime': cookTime,
'totalTime': totalTime,
'keywords': keywords,
'image': image,
'url': url
};

MutableRecipe toMutableRecipe() {
MutableRecipe mutableRecipe = MutableRecipe();

mutableRecipe.id = this.id;
mutableRecipe.name = this.name;
mutableRecipe.imageUrl = this.imageUrl;
mutableRecipe.recipeCategory = this.recipeCategory;
mutableRecipe.description = this.description;
mutableRecipe.recipeIngredient = this.recipeIngredient;
mutableRecipe.recipeInstructions = this.recipeInstructions;
mutableRecipe.recipeYield = this.recipeYield;
mutableRecipe.prepTime = this.prepTime;
mutableRecipe.cookTime = this.cookTime;
mutableRecipe.totalTime = this.totalTime;

return mutableRecipe;
}

@override
List<Object> get props => [id];
}

class MutableRecipe {
int id;
String name;
String imageUrl;
String recipeCategory;
String description;
List<String> recipeIngredient;
List<String> recipeInstructions;
List<String> tool;
int recipeYield;
Duration prepTime;
Duration cookTime;
Duration totalTime;
String keywords;
String image;
String url;

Recipe toRecipe() {
return Recipe._(
id,
name,
imageUrl,
recipeCategory,
description,
recipeIngredient,
recipeInstructions,
tool,
recipeYield,
prepTime,
cookTime,
totalTime,
keywords,
image,
url);
}
}
65 changes: 65 additions & 0 deletions lib/src/screens/form/recipe_form.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:nextcloud_cookbook_flutter/src/blocs/recipe/recipe.dart';
import 'package:nextcloud_cookbook_flutter/src/models/recipe.dart';
import 'package:validators/validators.dart';

class RecipeForm extends StatefulWidget {
final Recipe recipe;

const RecipeForm(this.recipe);

@override
_RecipeFormState createState() => _RecipeFormState();
}

class _RecipeFormState extends State<RecipeForm> {
final _formKey = GlobalKey<FormState>();
Recipe recipe;
MutableRecipe _mutableRecipe;

@override
void initState() {
recipe = widget.recipe;
_mutableRecipe = recipe.toMutableRecipe();

super.initState();
}

@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
initialValue: recipe.name,
decoration: InputDecoration(hintText: "Recipe Name"),
onSaved: (value) {
_mutableRecipe.name = value;
},
),
TextFormField(
initialValue: recipe.recipeYield.toString(),
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: "Recipe Yield"),
validator: (value) =>
isNumeric(value) ? null : "Recipe Yield should be a number",
onSaved: (value) => _mutableRecipe.recipeYield = int.parse(value),
),
RaisedButton(
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();

BlocProvider.of<RecipeBloc>(context)
.add(RecipeUpdated(_mutableRecipe.toRecipe()));
}
},
child: Text("Update"),
)
],
),
);
}
}
3 changes: 1 addition & 2 deletions lib/src/screens/login_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';

import 'package:flutter_bloc/flutter_bloc.dart';

import '../blocs/authentication/authentication_bloc.dart';
Expand All @@ -13,7 +12,7 @@ class LoginPage extends StatelessWidget {
appBar: AppBar(
title: Text('Login'),
),
body: BlocProvider(
body: BlocProvider<LoginBloc>(
create: (context) {
return LoginBloc(
authenticationBloc: BlocProvider.of<AuthenticationBloc>(context),
Expand Down
45 changes: 45 additions & 0 deletions lib/src/screens/recipe_edit_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:nextcloud_cookbook_flutter/src/blocs/recipe/recipe.dart';
import 'package:nextcloud_cookbook_flutter/src/models/recipe.dart';
import 'package:nextcloud_cookbook_flutter/src/screens/form/recipe_form.dart';

class RecipeEditScreen extends StatelessWidget {
final Recipe recipe;

const RecipeEditScreen(this.recipe);

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
RecipeBloc recipeBloc = BlocProvider.of<RecipeBloc>(context);
if (recipeBloc.state is RecipeUpdateFailure) {
recipeBloc.add(RecipeLoaded(recipeId: recipe.id));
}
return Future(() => true);
},
child: Scaffold(
appBar: AppBar(
title: BlocListener<RecipeBloc, RecipeState>(
listener: (BuildContext context, RecipeState state) {
if (state is RecipeUpdateFailure) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text("Update Failed: ${state.errorMsg}"),
backgroundColor: Colors.red,
),
);
} else if (state is RecipeUpdateSuccess) {
BlocProvider.of<RecipeBloc>(context)
.add(RecipeLoaded(recipeId: state.recipeId));
Navigator.pop(context);
}
},
child: Text("Edit Recipe")),
),
body: RecipeForm(recipe),
),
);
}
}
Loading

0 comments on commit 34de89e

Please sign in to comment.