From 1ddb63525fbfeb22133780e03b818427c23be649 Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Sat, 19 Feb 2022 15:13:53 +0100 Subject: [PATCH] Implement cart store --- lib/app.dart | 5 +- lib/screens/product_list/cart_button.dart | 4 +- lib/screens/product_list/product_item.dart | 8 ++- lib/stores/cart_store.dart | 82 ++++++++++++++++++++++ lib/stores/product_selection_store.dart | 31 -------- lib/stores/product_store.dart | 6 ++ 6 files changed, 102 insertions(+), 34 deletions(-) create mode 100644 lib/stores/cart_store.dart delete mode 100644 lib/stores/product_selection_store.dart diff --git a/lib/app.dart b/lib/app.dart index 6290b9b..41137d9 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -3,6 +3,7 @@ import 'package:thesis_shop/route_key.dart'; import 'package:thesis_shop/screens/cart/cart_screen.dart'; import 'package:thesis_shop/screens/product_list/product_list_screen.dart'; import 'package:thesis_shop/service/product_service.dart'; +import 'package:thesis_shop/stores/cart_store.dart'; import 'package:thesis_shop/stores/product_store.dart'; import 'package:thesis_shop/stores/user_store.dart'; import 'package:thesis_shop/utils/map_keys_extension.dart'; @@ -16,7 +17,9 @@ class ThesisShopApp extends StatelessWidget { return UserStoreImplementation( child: ProductStoreImplementation( productService: productService, - child: child, + child: CartStoreImplementation( + child: child, + ), ), ); } diff --git a/lib/screens/product_list/cart_button.dart b/lib/screens/product_list/cart_button.dart index 5256e5e..40fad9d 100644 --- a/lib/screens/product_list/cart_button.dart +++ b/lib/screens/product_list/cart_button.dart @@ -1,17 +1,19 @@ import 'package:flutter/material.dart'; import 'package:thesis_shop/benchmark_counter.dart'; import 'package:thesis_shop/route_key.dart'; +import 'package:thesis_shop/stores/cart_store.dart'; class CartButton extends StatelessWidget { const CartButton() : super(key: const Key('cart_button')); @override Widget build(BuildContext context) { + final cartStore = CartStore.of(context); BenchmarkCounters.cartButton++; return ElevatedButton.icon( onPressed: () => Navigator.of(context).pushRouteKey(RouteKey.cart), icon: const Icon(Icons.shopping_basket), - label: const Text('Warenkorb (3 Produkte)'), + label: Text('Warenkorb (${cartStore.cartItems.length} Produkte)'), ); } } diff --git a/lib/screens/product_list/product_item.dart b/lib/screens/product_list/product_item.dart index 62e813d..439369e 100644 --- a/lib/screens/product_list/product_item.dart +++ b/lib/screens/product_list/product_item.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:thesis_shop/models/product.dart'; +import 'package:thesis_shop/stores/cart_store.dart'; import 'package:thesis_shop/widgets/number_picker.dart'; class ProductItem extends StatelessWidget { @@ -8,9 +9,14 @@ class ProductItem extends StatelessWidget { @override Widget build(BuildContext context) { + final cartStore = CartStore.of(context); return ListTile( title: Text('${product.title} (${product.priceAsString}€/Stück)'), - trailing: NumberPicker(value: 5, onUp: () {}, onDown: () {}), + trailing: NumberPicker( + value: cartStore.amountOfProduct(product), + onUp: () => cartStore.increaseAmount(product), + onDown: () => cartStore.decreaseAmount(product), + ), ); } } diff --git a/lib/stores/cart_store.dart b/lib/stores/cart_store.dart new file mode 100644 index 0000000..6c56c0c --- /dev/null +++ b/lib/stores/cart_store.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:thesis_shop/models/cart_item.dart'; +import 'package:thesis_shop/models/product.dart'; +import 'package:thesis_shop/stores/product_store.dart'; + +class CartStoreImplementation extends StatefulWidget { + final Widget child; + const CartStoreImplementation({Key? key, required this.child}) + : super(key: key); + + @override + _CartStoreImplementationState createState() => + _CartStoreImplementationState(); +} + +class _CartStoreImplementationState extends State { + Map productAmounts = {}; + void increaseAmount(Product product) => setState(() { + final currentAmount = + productAmounts.putIfAbsent(product.title, () => 0); + productAmounts[product.title] = currentAmount + 1; + }); + void decreaseAmount(Product product) => setState(() { + final currentAmount = + productAmounts.putIfAbsent(product.title, () => 0); + productAmounts[product.title] = + currentAmount <= 0 ? 0 : currentAmount - 1; + }); + @override + Widget build(BuildContext context) { + final products = ProductStore.of(context).productsOrNull ?? const []; + final productsByTitle = { + for (var product in products) product.title: product + }; + final cartItems = productAmounts + .map((key, value) => MapEntry(productsByTitle[key], value)) + .entries + .where((entry) => entry.key != null && entry.value > 0) + .map((entry) => CartItem(product: entry.key!, amount: entry.value)) + .toList(); + return CartStore( + cartItems: cartItems, + increaseAmount: increaseAmount, + decreaseAmount: decreaseAmount, + child: widget.child, + ); + } +} + +class CartStore extends InheritedWidget { + const CartStore({ + Key? key, + required this.cartItems, + required this.increaseAmount, + required this.decreaseAmount, + required Widget child, + }) : super(key: key, child: child); + + final List cartItems; + + final Function(Product) increaseAmount; + final Function(Product) decreaseAmount; + + int amountOfProduct(Product product) { + final amounts = { + for (final item in cartItems) item.product: item.amount, + }; + return amounts.putIfAbsent(product, () => 0); + } + + static CartStore of(BuildContext context) { + final CartStore? result = + context.dependOnInheritedWidgetOfExactType(); + assert(result != null, 'No CartStore found in context'); + return result!; + } + + @override + bool updateShouldNotify(CartStore oldWidget) { + return cartItems != oldWidget.cartItems; + } +} diff --git a/lib/stores/product_selection_store.dart b/lib/stores/product_selection_store.dart deleted file mode 100644 index 168a4c4..0000000 --- a/lib/stores/product_selection_store.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:thesis_shop/models/product.dart'; - -class ProductSelectionStore extends InheritedWidget { - const ProductSelectionStore({ - Key? key, - required this.products, - required this.productAmounts, - required this.increaseAmount, - required this.decreaseAmount, - required Widget child, - }) : super(key: key, child: child); - - final List products; - final Map productAmounts; - - final Function(Product) increaseAmount; - final Function(Product) decreaseAmount; - - static ProductSelectionStore of(BuildContext context) { - final ProductSelectionStore? result = - context.dependOnInheritedWidgetOfExactType(); - assert(result != null, 'No ProductSelectionStore found in context'); - return result!; - } - - @override - bool updateShouldNotify(ProductSelectionStore oldWidget) { - return productAmounts != oldWidget.productAmounts; - } -} diff --git a/lib/stores/product_store.dart b/lib/stores/product_store.dart index 91f61d6..ffcf853 100644 --- a/lib/stores/product_store.dart +++ b/lib/stores/product_store.dart @@ -55,6 +55,12 @@ class ProductStore extends InheritedWidget { final RemoteResource> products; List get mustProducts => products.asFinished().value; + List? get productsOrNull { + if (products is FinishedRemoteResource) { + return mustProducts; + } + return null; + } static ProductStore of(BuildContext context) { final ProductStore? result =