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

Commit bdaf04d

Browse files
committed
add recipe delete
1 parent 43a4f83 commit bdaf04d

File tree

8 files changed

+150
-23
lines changed

8 files changed

+150
-23
lines changed

assets/i18n/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@
127127
"button": "Save",
128128
"errors": {
129129
"update_failed": "Update Failed {error_msg}"
130+
},
131+
"delete": {
132+
"title": "Delete Recipe",
133+
"dialog": "Are you sure you want to permanently delete {recipe}?"
130134
}
131135
},
132136
"recipe_create": {

lib/src/blocs/recipe/recipe_bloc.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class RecipeBloc extends Bloc<RecipeEvent, RecipeState> {
1414
on<RecipeUpdated>(_mapRecipeUpdatedToState);
1515
on<RecipeImported>(_mapRecipeImportedToState);
1616
on<RecipeCreated>(_mapRecipeCreatedToState);
17+
on<RecipeDeleted>(_mapRecipeDeletedToState);
1718
}
1819

1920
Future<void> _mapRecipeLoadedToState(
@@ -81,4 +82,22 @@ class RecipeBloc extends Bloc<RecipeEvent, RecipeState> {
8182
);
8283
}
8384
}
85+
86+
Future<void> _mapRecipeDeletedToState(
87+
RecipeDeleted recipeDeleted,
88+
Emitter<RecipeState> emit,
89+
) async {
90+
try {
91+
emit(RecipeState(status: RecipeStatus.deleteInProgress));
92+
await dataRepository.deleteRecipe(recipeDeleted.recipe);
93+
emit(RecipeState(status: RecipeStatus.delteSuccess));
94+
} catch (e) {
95+
emit(
96+
RecipeState(
97+
status: RecipeStatus.deleteFailure,
98+
error: e.toString(),
99+
),
100+
);
101+
}
102+
}
84103
}

lib/src/blocs/recipe/recipe_event.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,12 @@ class RecipeImported extends RecipeEvent {
4242
@override
4343
List<Object> get props => [url];
4444
}
45+
46+
class RecipeDeleted extends RecipeEvent {
47+
final Recipe recipe;
48+
49+
const RecipeDeleted(this.recipe);
50+
51+
@override
52+
List<Object> get props => [recipe];
53+
}

lib/src/blocs/recipe/recipe_state.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
part of 'recipe_bloc.dart';
22

33
enum RecipeStatus {
4-
failure,
5-
success,
64
loadSuccess,
75
loadFailure,
86
loadInProgress,
@@ -12,6 +10,9 @@ enum RecipeStatus {
1210
createFailure,
1311
createSuccess,
1412
createInProgress,
13+
deleteInProgress,
14+
deleteFailure,
15+
delteSuccess,
1516
importSuccess,
1617
importFailure,
1718
importInProgress;
@@ -34,18 +35,19 @@ class RecipeState extends Equatable {
3435
case RecipeStatus.updateInProgress:
3536
case RecipeStatus.createInProgress:
3637
case RecipeStatus.importInProgress:
38+
case RecipeStatus.deleteInProgress:
39+
case RecipeStatus.delteSuccess:
3740
assert(error == null && recipe == null && recipeId == null);
3841
break;
3942
case RecipeStatus.createSuccess:
4043
case RecipeStatus.updateSuccess:
4144
assert(error == null && recipe == null && recipeId != null);
4245
break;
43-
case RecipeStatus.success:
4446
case RecipeStatus.loadSuccess:
4547
case RecipeStatus.importSuccess:
4648
assert(error == null && recipe != null && recipeId == null);
4749
break;
48-
case RecipeStatus.failure:
50+
case RecipeStatus.deleteFailure:
4951
case RecipeStatus.loadFailure:
5052
case RecipeStatus.updateFailure:
5153
case RecipeStatus.createFailure:

lib/src/screens/recipe/recipe_screen.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class RecipeScreen extends StatelessWidget {
5151
child: CircularProgressIndicator(),
5252
);
5353
break;
54-
case RecipeStatus.failure:
54+
case RecipeStatus.loadFailure:
5555
child = Center(
5656
child: Text(state.error!),
5757
);

lib/src/screens/recipe_edit_screen.dart

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
22
import 'package:flutter_bloc/flutter_bloc.dart';
33
import 'package:flutter_translate/flutter_translate.dart';
44
import 'package:nc_cookbook_api/nc_cookbook_api.dart';
5+
import 'package:nextcloud_cookbook_flutter/src/blocs/categories/categories_bloc.dart';
56
import 'package:nextcloud_cookbook_flutter/src/blocs/recipe/recipe_bloc.dart';
67
import 'package:nextcloud_cookbook_flutter/src/screens/form/recipe_form.dart';
8+
import 'package:nextcloud_cookbook_flutter/src/widget/alerts/recipe_delete_alert.dart';
79

810
class RecipeEditScreen extends StatelessWidget {
911
final Recipe recipe;
@@ -27,29 +29,74 @@ class RecipeEditScreen extends StatelessWidget {
2729
appBar: AppBar(
2830
title: BlocListener<RecipeBloc, RecipeState>(
2931
listener: (BuildContext context, RecipeState state) {
30-
if (state.status == RecipeStatus.updateFailure) {
31-
ScaffoldMessenger.of(context).showSnackBar(
32-
SnackBar(
33-
content: Text(
34-
translate(
35-
'recipe_edit.errors.update_failed',
36-
args: {"error_msg": state.error},
32+
switch (state.status) {
33+
case RecipeStatus.updateFailure:
34+
ScaffoldMessenger.of(context).showSnackBar(
35+
SnackBar(
36+
content: Text(
37+
translate(
38+
'recipe_edit.errors.update_failed',
39+
args: {"error_msg": state.error},
40+
),
41+
style: TextStyle(
42+
color: Theme.of(context).colorScheme.onError,
43+
),
3744
),
38-
style: TextStyle(
39-
color: Theme.of(context).colorScheme.onError,
45+
backgroundColor: Theme.of(context).colorScheme.error,
46+
),
47+
);
48+
break;
49+
case RecipeStatus.deleteFailure:
50+
ScaffoldMessenger.of(context).showSnackBar(
51+
SnackBar(
52+
content: Text(
53+
translate(
54+
'recipe_edit.errors.update_failed',
55+
args: {"error_msg": state.error},
56+
),
57+
style: TextStyle(
58+
color: Theme.of(context).colorScheme.onError,
59+
),
4060
),
61+
backgroundColor: Theme.of(context).colorScheme.error,
4162
),
42-
backgroundColor: Theme.of(context).colorScheme.error,
43-
),
44-
);
45-
} else if (state.status == RecipeStatus.updateSuccess) {
46-
BlocProvider.of<RecipeBloc>(context)
47-
.add(RecipeLoaded(state.recipeId!));
48-
Navigator.pop(context);
63+
);
64+
break;
65+
case RecipeStatus.updateSuccess:
66+
BlocProvider.of<RecipeBloc>(context)
67+
.add(RecipeLoaded(state.recipeId!));
68+
Navigator.pop(context);
69+
break;
70+
case RecipeStatus.delteSuccess:
71+
BlocProvider.of<CategoriesBloc>(context)
72+
.add(const CategoriesLoaded());
73+
Navigator.pop(context);
74+
Navigator.pop(context);
75+
break;
76+
default:
4977
}
5078
},
5179
child: Text(translate('recipe_edit.title')),
5280
),
81+
actions: [
82+
IconButton(
83+
icon: const Icon(Icons.delete),
84+
tooltip: translate("recipe_edit.delete.title").toLowerCase(),
85+
color: Theme.of(context).colorScheme.error,
86+
onPressed: () async {
87+
final decision = await showDialog<bool>(
88+
context: context,
89+
builder: (_) => DeleteRecipeAlert(recipe: recipe),
90+
);
91+
92+
if (decision ?? false) {
93+
// ignore: use_build_context_synchronously
94+
BlocProvider.of<RecipeBloc>(context)
95+
.add(RecipeDeleted(recipe));
96+
}
97+
},
98+
),
99+
],
53100
),
54101
body: RecipeForm(recipe: recipe),
55102
),

lib/src/services/data_repository.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,17 @@ class DataRepository {
4242
Future<String?> updateRecipe(Recipe recipe) async {
4343
final response =
4444
await api.recipeApi.updateRecipe(id: recipe.id!, recipe: recipe);
45-
return response.data?.toString();
45+
return response.data;
4646
}
4747

4848
Future<String?> createRecipe(Recipe recipe) async {
4949
final response = await api.recipeApi.newRecipe(recipe: recipe);
50-
return response.data?.toString();
50+
return response.data;
51+
}
52+
53+
Future<String?> deleteRecipe(Recipe recipe) async {
54+
final response = await api.recipeApi.deleteRecipe(id: recipe.id!);
55+
return response.data;
5156
}
5257

5358
Future<Recipe?> importRecipe(String url) async {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_translate/flutter_translate.dart';
3+
import 'package:nc_cookbook_api/nc_cookbook_api.dart';
4+
5+
class DeleteRecipeAlert extends StatelessWidget {
6+
const DeleteRecipeAlert({
7+
required this.recipe,
8+
super.key,
9+
});
10+
11+
final Recipe recipe;
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return AlertDialog(
16+
icon: const Icon(Icons.delete_forever),
17+
iconColor: Theme.of(context).colorScheme.error,
18+
title: Text(translate("recipe_edit.delete.title")),
19+
content: Text(
20+
translate(
21+
"recipe_edit.delete.dialog",
22+
args: {"recipe": recipe.name},
23+
),
24+
),
25+
actions: [
26+
TextButton(
27+
onPressed: () {
28+
Navigator.of(context).pop(true);
29+
},
30+
child: Text(translate("alert.yes")),
31+
),
32+
TextButton(
33+
onPressed: () {
34+
Navigator.of(context).pop();
35+
},
36+
child: Text(translate("alert.no")),
37+
),
38+
],
39+
);
40+
}
41+
}

0 commit comments

Comments
 (0)