Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion backend/app/controller/shoppinglist/shoppinglist_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,16 @@ def updateShoppinglist(args, id):
shoppinglist.name = args["name"]

shoppinglist.save()
return jsonify(shoppinglist.obj_to_dict())
shoppinglist_dict = shoppinglist.obj_to_dict();
socketio.emit(
"shoppinglist:update",
{
"shoppinglist": shoppinglist_dict
},
to=shoppinglist.household_id
)

return jsonify(shoppinglist_dict)


@shoppinglist.route("/<int:id>", methods=["DELETE"])
Expand Down
49 changes: 48 additions & 1 deletion kitchenowl/lib/cubits/shoppinglist_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import 'package:kitchenowl/models/shoppinglist.dart';
import 'package:kitchenowl/services/api/api_service.dart';
import 'package:kitchenowl/services/storage/storage.dart';
import 'package:kitchenowl/services/transactions/category.dart';
import 'package:kitchenowl/services/transactions/household.dart';
import 'package:kitchenowl/services/transactions/shoppinglist.dart';
import 'package:kitchenowl/services/transaction_handler.dart';

class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
final Household household;
Household household;
Future<void>? _refreshThread;
String? _refreshCurrentQuery;

Expand All @@ -35,6 +36,7 @@ class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
refresh();
ApiService.getInstance().onShoppinglistAdd(onShoppinglistAdd);
ApiService.getInstance().onShoppinglistDelete(onShoppinglistDelete);
ApiService.getInstance().onShoppinglistUpdate(onShoppinglistUpdate);
ApiService.getInstance().onShoppinglistItemAdd(onShoppinglistItemAdd);
ApiService.getInstance().onShoppinglistItemRemove(onShoppinglistItemRemove);
}
Expand All @@ -43,6 +45,7 @@ class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
Future<void> close() async {
ApiService.getInstance().offShoppinglistAdd(onShoppinglistAdd);
ApiService.getInstance().offShoppinglistDelete(onShoppinglistDelete);
ApiService.getInstance().offShoppinglistUpdate(onShoppinglistUpdate);
ApiService.getInstance().offShoppinglistItemAdd(onShoppinglistItemAdd);
ApiService.getInstance()
.offShoppinglistItemRemove(onShoppinglistItemRemove);
Expand All @@ -57,6 +60,23 @@ class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
refresh();
}

void onShoppinglistUpdate(dynamic data) {
refresh();
}

Future<void> updateHousehold() async {
final maybeHousehold =
await TransactionHandler.getInstance().runTransaction(
TransactionHouseholdGet(
household: household,
),
);

if (maybeHousehold != null) {
household = maybeHousehold;
}
}

void onShoppinglistItemAdd(dynamic data) {
final item = ShoppinglistItem.fromJson(data["item"]);
TransactionHandler.getInstance().runTransaction(
Expand Down Expand Up @@ -272,6 +292,22 @@ class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
emit(state.copyWith(sorting: sorting));
}

Future<bool> addShoppingList(String name) async {
final res = await ApiService.getInstance()
.addShoppingList(household, ShoppingList(name: name));
refresh();

return res;
}

Future<bool> deleteShoppingList(ShoppingList shoppingList) async {
if (household.defaultShoppingList == shoppingList) return false;
final res = await ApiService.getInstance().deleteShoppingList(shoppingList);
refresh();

return res;
}

void setShoppingList(ShoppingList shoppingList) {
if (shoppingList.id != null) {
PreferenceStorage.getInstance().writeInt(
Expand Down Expand Up @@ -351,6 +387,7 @@ class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
shoppingList!.items.firstWhereOrNull((item) => item.id == e.id))
.nonNulls
.toList(),
defaultShoppingList: household.defaultShoppingList,
);

if (state is LoadingShoppinglistCubitState) {
Expand All @@ -371,9 +408,11 @@ class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
sorting: state.sorting,
categories: state.categories,
selectedListItems: state.selectedListItems,
defaultShoppingList: state.defaultShoppingList,
));
}

await updateHousehold();
final shoppingLists = await fetchShoppingLists(false);

int? selectedShoppinglistId = state.selectedShoppinglistId;
Expand Down Expand Up @@ -436,6 +475,7 @@ class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
shoppinglist?.items.firstWhereOrNull((item) => item.id == e.id))
.nonNulls
.toList(),
defaultShoppingList: household.defaultShoppingList,
);
} else {
resState = ShoppinglistCubitState(
Expand All @@ -448,6 +488,7 @@ class ShoppinglistCubit extends Cubit<ShoppinglistCubitState> {
shoppinglist?.items.firstWhereOrNull((item) => item.id == e.id))
.nonNulls
.toList(),
defaultShoppingList: household.defaultShoppingList,
);
}
if (query == _refreshCurrentQuery) {
Expand Down Expand Up @@ -487,6 +528,7 @@ class ShoppinglistCubitState extends Equatable {
final List<Category> categories;
final ShoppinglistSorting sorting;
final List<ShoppinglistItem> selectedListItems;
final ShoppingList? defaultShoppingList;
final ShoppingList? _selectedShoppinglist;

const ShoppinglistCubitState._({
Expand All @@ -495,6 +537,7 @@ class ShoppinglistCubitState extends Equatable {
this.sorting = ShoppinglistSorting.alphabetical,
this.selectedListItems = const [],
this.selectedShoppinglistId = null,
required this.defaultShoppingList,
}) : this._selectedShoppinglist = null;

ShoppinglistCubitState({
Expand All @@ -503,6 +546,7 @@ class ShoppinglistCubitState extends Equatable {
this.categories = const [],
this.sorting = ShoppinglistSorting.alphabetical,
this.selectedListItems = const [],
required this.defaultShoppingList,
}) : _selectedShoppinglist = shoppinglists[selectedShoppinglistId];

ShoppingList? get selectedShoppinglist => _selectedShoppinglist;
Expand All @@ -521,6 +565,7 @@ class ShoppinglistCubitState extends Equatable {
categories: categories ?? this.categories,
sorting: sorting ?? this.sorting,
selectedListItems: selectedListItems ?? this.selectedListItems,
defaultShoppingList: this.defaultShoppingList,
);

@override
Expand All @@ -540,6 +585,7 @@ class LoadingShoppinglistCubitState extends ShoppinglistCubitState {
super.shoppinglists,
super.categories,
super.selectedListItems,
super.defaultShoppingList,
}) : super._();

@override
Expand Down Expand Up @@ -574,6 +620,7 @@ class SearchShoppinglistCubitState extends ShoppinglistCubitState {
this.query = "",
this.result = const [],
super.selectedListItems,
super.defaultShoppingList,
});

@override
Expand Down
2 changes: 2 additions & 0 deletions kitchenowl/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@
"@setupTitle": {},
"@share": {},
"@shoppingList": {},
"@shoppingListAddTooltip": {},
"@shoppingListContainsEntries": {
"placeholders": {
"entriesCount": {
Expand Down Expand Up @@ -600,6 +601,7 @@
"setupTitle": "Hey there! Ready to shop?",
"share": "Share",
"shoppingList": "Shopping list",
"shoppingListAddTooltip": "Add a shopping list",
"shoppingListContainsEntries": "{entriesCount, plural, =0{The shopping list contains no items.} =1{The shopping list contains 1 item.} other{The shopping list contains {entriesCount} items.}}",
"shoppingListDelete": "Delete shopping list",
"shoppingListDeleteConfirmation": "Are you sure you want to delete {shoppingList}?",
Expand Down
6 changes: 5 additions & 1 deletion kitchenowl/lib/models/household.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Household extends Model {
member = List.from(map['member'].map((e) => Member.fromJson(e)));
}

return Household(
final household = Household(
id: map['id'],
name: map['name'],
image: map['photo'],
Expand All @@ -57,6 +57,8 @@ class Household extends Model {
? ShoppingList.fromJson(map['default_shopping_list'])
: null,
);

return household;
}

Household copyWith({
Expand All @@ -66,6 +68,7 @@ class Household extends Model {
bool? featurePlanner,
bool? featureExpenses,
List<ViewsEnum>? viewOrdering,
ShoppingList? defaultShoppingList
}) =>
Household(
id: id,
Expand All @@ -76,6 +79,7 @@ class Household extends Model {
featurePlanner: featurePlanner ?? this.featurePlanner,
featureExpenses: featureExpenses ?? this.featureExpenses,
viewOrdering: viewOrdering ?? this.viewOrdering,
defaultShoppingList: defaultShoppingList ?? this.defaultShoppingList
);

@override
Expand Down
88 changes: 65 additions & 23 deletions kitchenowl/lib/pages/household_page/shoppinglist.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:kitchenowl/cubits/shoppinglist_cubit.dart';
import 'package:kitchenowl/enums/shoppinglist_sorting.dart';
import 'package:kitchenowl/models/item.dart';
import 'package:kitchenowl/kitchenowl.dart';
import 'package:kitchenowl/pages/settings_household/household_settings_shoppinglist_page.dart';
import 'package:kitchenowl/widgets/choice_scroll.dart';
import 'package:kitchenowl/widgets/shopping_list/shopping_list_choice_chip.dart';
import 'package:kitchenowl/widgets/shopping_list/sliver_shopinglist_item_view.dart';
Expand Down Expand Up @@ -120,29 +121,70 @@ class _ShoppinglistPageState extends State<ShoppinglistPage> {
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverToBoxAdapter(
child: LeftRightWrap(
left: (state.shoppinglists.length < 2)
? const SizedBox()
: ChoiceScroll(
children: state.shoppinglists.values
.sorted((a, b) => b.items.length
.compareTo(a.items.length))
.map(
(shoppinglist) =>
ShoppingListChoiceChip(
shoppingList: shoppinglist,
selected: shoppinglist.id ==
state.selectedShoppinglistId,
onSelected: (bool selected) {
if (selected) {
cubit.setShoppingList(
shoppinglist,
);
}
},
),
)
.toList(),
),
left: Row(
children: [
IconButton(
tooltip: AppLocalizations.of(context)!
.shoppingListAddTooltip,
onPressed: () async {
final res =
await HouseholdSettingsShoppinglistPage
.getShoppingListName(context,
state.shoppinglists.values);
if (res != null) {
BlocProvider.of<ShoppinglistCubit>(
context)
.addShoppingList(res);
}
},
icon: Icon(Icons.add,
color: Theme.of(context)
.colorScheme
.primary)),
(state.shoppinglists.length < 2)
? const SizedBox()
: ChoiceScroll(
paddingLeft: 0,
children: state.shoppinglists.values
.sorted((a, b) =>
a.name.compareTo(b.name))
.map(
(shoppinglist) =>
ShoppingListChoiceChip(
canDelete: state
.defaultShoppingList !=
shoppinglist,
shoppingList:
shoppinglist,
selected: shoppinglist
.id ==
state
.selectedShoppinglistId,
onSelected:
(bool selected) {
if (selected) {
cubit
.setShoppingList(
shoppinglist,
);
}
},
onDeleted: () async {
final doIt =
await HouseholdSettingsShoppinglistPage
.confirmDeleteShoppingList(
context,
shoppinglist);
if (doIt) {
cubit.deleteShoppingList(
shoppinglist);
}
}),
)
.toList(),
),
],
),
right: Padding(
padding:
const EdgeInsets.only(right: 16, bottom: 6),
Expand Down
Loading