From 543c59bfcc238e8527bd1601a6b8ccbd10aa5ec7 Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Sun, 20 Feb 2022 18:48:57 +0100 Subject: [PATCH] Add user discount --- lib/app.dart | 2 +- lib/bloc/cart_bloc.dart | 11 +++--- lib/bloc/product_bloc.dart | 39 ++++++++++++++++++++-- lib/models/product.dart | 19 +++++++++++ lib/screens/cart/total_price_text.dart | 2 +- lib/screens/product_list/product_item.dart | 8 ++--- 6 files changed, 69 insertions(+), 12 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index 5842e49..606937e 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -16,7 +16,7 @@ class ThesisShopApp extends StatelessWidget { BlocProvider setupBlocs() { final userBloc = UserBloc(); - final productBloc = ProductBloc(productService); + final productBloc = ProductBloc(productService, userBloc); final cartBloc = CartBloc(productBloc); return BlocProvider( productBloc: productBloc, diff --git a/lib/bloc/cart_bloc.dart b/lib/bloc/cart_bloc.dart index 9cfe112..538577d 100644 --- a/lib/bloc/cart_bloc.dart +++ b/lib/bloc/cart_bloc.dart @@ -20,10 +20,10 @@ class CartBloc implements Disposable { int get numberOfProducts => _cart.length; late final Stream numberOfProductsStream; - +/* int numberOfProduct(Product product) => _cart[product] ?? 0; Stream numberOfProductStream(Product product) => - cartStream.map((event) => event[product] ?? 0); + cartStream.map((event) => event[product] ?? 0);*/ double get totalPrice => cart.calculateTotalPrice(); Stream get totalPriceStream => @@ -53,7 +53,7 @@ class CartBloc implements Disposable { final productsByName = { for (final product in products) product.title: product }; - _cart.removeWhere((key, _) => productsByName.containsKey(key.title)); + _cart.removeWhere((key, _) => !productsByName.containsKey(key.title)); _cart = _cart .map((key, value) => MapEntry(productsByName[key.title]!, value)); _cartSink.add(_cart); @@ -74,6 +74,7 @@ class CartBloc implements Disposable { final old = _cart.putIfAbsent(event.product, () => 0); final newQuantity = old + summand; _cart[event.product] = newQuantity.isNegative ? 0 : newQuantity; + if (_cart[event.product]! <= 0) _cart.remove(event.product); _cartSink.add(_cart); }); } @@ -89,5 +90,7 @@ extension CartItemConverter on Cart { entries.map((e) => CartItem(product: e.key, amount: e.value)).toList(); double calculateTotalPrice() => entries.fold( - 0, (previousValue, element) => previousValue + element.key.price); + 0, + (previousValue, element) => + previousValue + element.key.price * element.value); } diff --git a/lib/bloc/product_bloc.dart b/lib/bloc/product_bloc.dart index 9f3580a..dd59341 100644 --- a/lib/bloc/product_bloc.dart +++ b/lib/bloc/product_bloc.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:thesis_shop/bloc/user_bloc.dart'; import 'package:thesis_shop/models/product.dart'; import 'package:thesis_shop/service/product_service.dart'; import 'package:thesis_shop/utils/disposable.dart'; @@ -9,7 +10,9 @@ part 'product_bloc_states.dart'; class ProductBloc implements Disposable { final ProductService _productService; + final UserBloc _userBloc; + bool _hasDiscount; var _productsState = ProductsState.loading(); ProductsState get productsState => _productsState; @@ -23,17 +26,49 @@ class ProductBloc implements Disposable { Sink get loadProductSink => _loadProductEventController.sink; - ProductBloc(this._productService) { + ProductBloc(this._productService, this._userBloc) + : _hasDiscount = _userBloc.isSignedIn { + _handleUserEvents(); _handleLoadProductEvents(); } + void _handleUserEvents() { + _userBloc.isSignedInStream.listen((isSignedIn) { + if (isSignedIn && !_hasDiscount) { + if (_productsState.isLoaded()) { + final discountedProducts = _productsState + .as() + .products + .map((product) => product.copyWithDiscount()) + .toList(); + _productsState = ProductsState.loaded(discountedProducts); + _productsStateSink.add(_productsState); + } + } else if (!isSignedIn && _hasDiscount) { + final undiscountedProducts = _productsState + .as() + .products + .map((product) => product.copyWithoutDiscount()) + .toList(); + _productsState = ProductsState.loaded(undiscountedProducts); + _productsStateSink.add(_productsState); + } + _hasDiscount = isSignedIn; + }); + } + void _handleLoadProductEvents() { _loadProductEventController.stream.listen((_) async { _productsState = ProductsState.loading(); _productsStateSink.add(_productsState); try { - final products = await _productService.fetchProducts(); + var products = await _productService.fetchProducts(); + _hasDiscount = _userBloc.isSignedIn; + if (_hasDiscount) { + products = + products.map((product) => product.copyWithDiscount()).toList(); + } _productsState = ProductsState.loaded(products); _productsStateSink.add(_productsState); } catch (err) { diff --git a/lib/models/product.dart b/lib/models/product.dart index 1b73556..81f3316 100644 --- a/lib/models/product.dart +++ b/lib/models/product.dart @@ -8,4 +8,23 @@ class Product { String get priceAsString => price.toStringAsFixed(2); const Product({required this.title, required this.price}); + + Product copyWithDiscount() { + return Product(title: title, price: price * 0.8); + } + + Product copyWithoutDiscount() { + return Product(title: title, price: price * 1.25); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Product && + runtimeType == other.runtimeType && + title == other.title && + price == other.price; + + @override + int get hashCode => title.hashCode ^ price.hashCode; } diff --git a/lib/screens/cart/total_price_text.dart b/lib/screens/cart/total_price_text.dart index c7a301d..34b51f1 100644 --- a/lib/screens/cart/total_price_text.dart +++ b/lib/screens/cart/total_price_text.dart @@ -15,7 +15,7 @@ class TotalPriceText extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(8.0), child: Text( - 'Gesamtpreis: ${snapshot.requireData}€', + 'Gesamtpreis: ${snapshot.requireData.toStringAsFixed(2)}€', style: Theme.of(context) .textTheme .labelLarge diff --git a/lib/screens/product_list/product_item.dart b/lib/screens/product_list/product_item.dart index eac8987..c951670 100644 --- a/lib/screens/product_list/product_item.dart +++ b/lib/screens/product_list/product_item.dart @@ -13,12 +13,12 @@ class ProductItem extends StatelessWidget { final cartBloc = AppState.of(context).blocProvider.cartBloc; return ListTile( title: Text('${product.title} (${product.priceAsString}€/Stück)'), - trailing: StreamBuilder( - stream: cartBloc.numberOfProductStream(product), - initialData: cartBloc.numberOfProduct(product), + trailing: StreamBuilder( + stream: cartBloc.cartStream, + initialData: cartBloc.cart, builder: (context, snapshot) { return NumberPicker( - value: snapshot.requireData, + value: snapshot.requireData[product] ?? 0, onUp: () => cartBloc.quantityEventSink .add(IncreaseQuantityEvent(product)), onDown: () => cartBloc.quantityEventSink