From 536eae48b1d780e9d77d08c101dec271f32300fd Mon Sep 17 00:00:00 2001 From: monsieurtanuki Date: Mon, 10 Jun 2024 19:29:29 +0200 Subject: [PATCH] feat: 5352 - now opening the related product price page from count button (#5353) Impacted files: * `edit_product_page.dart`: minor refactoring * `get_prices_model.dart`: refactored with 2 new constructors * `price_count_widget.dart`: now opening the related product price page (if relevant) * `price_product_widget.dart`: minor refactoring * `prices_card.dart`: minor refactoring * `product_price_add_page.dart`: minor refactoring * `product_prices_list.dart`: minor refactoring; minor bug fix * `user_preferences_account.dart`: minor refactoring --- .../preferences/user_preferences_account.dart | 13 ++-- .../lib/pages/prices/get_prices_model.dart | 73 +++++++++++++++++++ .../lib/pages/prices/price_count_widget.dart | 55 +++++++++++++- .../pages/prices/price_product_widget.dart | 14 +++- .../lib/pages/prices/prices_card.dart | 31 +------- .../pages/prices/product_price_add_page.dart | 44 +++++++++-- .../lib/pages/prices/product_prices_list.dart | 16 +++- .../lib/pages/product/edit_product_page.dart | 2 +- 8 files changed, 196 insertions(+), 52 deletions(-) diff --git a/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart b/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart index e2411941db1d..a8b3e6499b79 100644 --- a/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart +++ b/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart @@ -242,7 +242,7 @@ class UserPreferencesAccount extends AbstractUserPreferences { ), ), CupertinoIcons.money_dollar_circle, - myCount: _getMyPricesCount(), + myCount: _getPricesCount(owner: ProductQuery.getWriteUser().userId), ), _getListTile( appLocalizations.all_search_prices_latest_title, @@ -271,6 +271,7 @@ class UserPreferencesAccount extends AbstractUserPreferences { ), ), CupertinoIcons.money_dollar_circle, + myCount: _getPricesCount(), ), _getPriceListTile( appLocalizations.all_search_prices_top_user_title, @@ -337,9 +338,8 @@ class UserPreferencesAccount extends AbstractUserPreferences { UserPreferencesItem _getPriceListTile( final String title, - final String path, { - final Future? myCount, - }) => + final String path, + ) => _getListTile( title, () async => LaunchUrlHelper.launchURL( @@ -349,7 +349,6 @@ class UserPreferencesAccount extends AbstractUserPreferences { ).toString(), ), Icons.open_in_new, - myCount: myCount, ); Future _confirmLogout() async => showDialog( @@ -402,11 +401,11 @@ class UserPreferencesAccount extends AbstractUserPreferences { } } - Future _getMyPricesCount() async { + Future _getPricesCount({final String? owner}) async { final MaybeError result = await OpenPricesAPIClient.getPrices( GetPricesParameters() - ..owner = ProductQuery.getWriteUser().userId + ..owner = owner ..pageSize = 1, uriHelper: ProductQuery.uriProductHelper, ); diff --git a/packages/smooth_app/lib/pages/prices/get_prices_model.dart b/packages/smooth_app/lib/pages/prices/get_prices_model.dart index 1b91fcb83f63..5caa7ae2f52a 100644 --- a/packages/smooth_app/lib/pages/prices/get_prices_model.dart +++ b/packages/smooth_app/lib/pages/prices/get_prices_model.dart @@ -1,5 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; +import 'package:smooth_app/helpers/product_cards_helper.dart'; +import 'package:smooth_app/pages/prices/product_price_add_page.dart'; +import 'package:smooth_app/query/product_query.dart'; /// Model that stores what we need to know for "get latest prices" queries. class GetPricesModel { @@ -9,10 +13,76 @@ class GetPricesModel { required this.displayProduct, required this.uri, required this.title, + this.enableCountButton = true, this.subtitle, this.addButton, }); + /// Gets latest prices for a product. + factory GetPricesModel.product({ + required final Product product, + required final BuildContext context, + }) => + GetPricesModel( + parameters: _getProductPricesParameters(product.barcode!), + displayOwner: true, + displayProduct: false, + uri: _getProductPricesUri(product.barcode!), + title: getProductNameAndBrands( + product, + AppLocalizations.of(context), + ), + subtitle: product.barcode, + addButton: () async => ProductPriceAddPage.showProductPage( + context: context, + product: product, + ), + enableCountButton: false, + ); + + /// Gets latest prices for a barcode. + factory GetPricesModel.barcode({ + required final String barcode, + required final String name, + required final BuildContext context, + }) => + GetPricesModel( + parameters: _getProductPricesParameters(barcode), + displayOwner: true, + displayProduct: false, + uri: _getProductPricesUri(barcode), + title: name, + subtitle: barcode, + addButton: () async => ProductPriceAddPage.showBarcodePage( + context: context, + barcode: barcode, + title: name, + ), + enableCountButton: false, + ); + + static GetPricesParameters _getProductPricesParameters( + final String barcode, + ) => + GetPricesParameters() + ..productCode = barcode + ..orderBy = >[ + const OrderBy( + field: GetPricesOrderField.created, + ascending: false, + ), + ] + ..pageSize = pageSize + ..pageNumber = 1; + + static Uri _getProductPricesUri( + final String barcode, + ) => + OpenPricesAPIClient.getUri( + path: 'app/products/$barcode', + uriHelper: ProductQuery.uriProductHelper, + ); + /// Query parameters. final GetPricesParameters parameters; @@ -34,5 +104,8 @@ class GetPricesModel { /// "Add a price" callback. final VoidCallback? addButton; + /// "Enable the count button?". Typically "false" for product price pages. + final bool enableCountButton; + static const int pageSize = 10; } diff --git a/packages/smooth_app/lib/pages/prices/price_count_widget.dart b/packages/smooth_app/lib/pages/prices/price_count_widget.dart index f703a7b1da41..85e9c0125a2f 100644 --- a/packages/smooth_app/lib/pages/prices/price_count_widget.dart +++ b/packages/smooth_app/lib/pages/prices/price_count_widget.dart @@ -1,20 +1,67 @@ import 'package:flutter/material.dart'; +import 'package:openfoodfacts/openfoodfacts.dart'; +import 'package:provider/provider.dart'; +import 'package:smooth_app/database/dao_product.dart'; +import 'package:smooth_app/database/local_database.dart'; +import 'package:smooth_app/pages/prices/get_prices_model.dart'; import 'package:smooth_app/pages/prices/price_button.dart'; +import 'package:smooth_app/pages/prices/prices_page.dart'; /// Price Count display. class PriceCountWidget extends StatelessWidget { - const PriceCountWidget(this.count); + const PriceCountWidget( + this.count, { + required this.barcode, + required this.name, + required this.enableCountButton, + }); final int count; + final String barcode; + + /// Product name to display in case we have only the barcode, not the product. + final String name; + + final bool enableCountButton; @override Widget build(BuildContext context) => PriceButton( - onPressed: null, + onPressed: !enableCountButton + ? null + : () async { + final LocalDatabase localDatabase = + context.read(); + final Product? product = + await DaoProduct(localDatabase).get(barcode); + if (!context.mounted) { + return; + } + return Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) => PricesPage( + product != null + ? GetPricesModel.product( + product: product, + context: context, + ) + : GetPricesModel.barcode( + barcode: barcode, + name: name, + context: context, + ), + ), + ), + ); + }, iconData: Icons.label, title: '$count', buttonStyle: ElevatedButton.styleFrom( - disabledForegroundColor: _getForegroundColor(), - disabledBackgroundColor: _getBackgroundColor(), + disabledForegroundColor: + enableCountButton ? null : _getForegroundColor(), + disabledBackgroundColor: + enableCountButton ? null : _getBackgroundColor(), + foregroundColor: !enableCountButton ? null : _getForegroundColor(), + backgroundColor: !enableCountButton ? null : _getBackgroundColor(), ), ); diff --git a/packages/smooth_app/lib/pages/prices/price_product_widget.dart b/packages/smooth_app/lib/pages/prices/price_product_widget.dart index 68f1408159df..e8631362a86f 100644 --- a/packages/smooth_app/lib/pages/prices/price_product_widget.dart +++ b/packages/smooth_app/lib/pages/prices/price_product_widget.dart @@ -4,14 +4,19 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/widgets/images/smooth_image.dart'; +import 'package:smooth_app/pages/prices/get_prices_model.dart'; import 'package:smooth_app/pages/prices/price_button.dart'; import 'package:smooth_app/pages/prices/price_count_widget.dart'; /// Price Product display (no price data here). class PriceProductWidget extends StatelessWidget { - const PriceProductWidget(this.priceProduct); + const PriceProductWidget( + this.priceProduct, { + required this.model, + }); final PriceProduct priceProduct; + final GetPricesModel model; static const double _imageSize = 75; @@ -65,7 +70,12 @@ class PriceProductWidget extends StatelessWidget { crossAxisAlignment: WrapCrossAlignment.center, runSpacing: 0, children: [ - PriceCountWidget(priceCount), + PriceCountWidget( + priceCount, + barcode: priceProduct.code, + name: name, + enableCountButton: model.enableCountButton, + ), if (brands != null) for (final String brand in brands) PriceButton( diff --git a/packages/smooth_app/lib/pages/prices/prices_card.dart b/packages/smooth_app/lib/pages/prices/prices_card.dart index a4b5968dffbd..cc362a0b26a8 100644 --- a/packages/smooth_app/lib/pages/prices/prices_card.dart +++ b/packages/smooth_app/lib/pages/prices/prices_card.dart @@ -8,7 +8,6 @@ import 'package:smooth_app/helpers/product_cards_helper.dart'; import 'package:smooth_app/pages/prices/get_prices_model.dart'; import 'package:smooth_app/pages/prices/prices_page.dart'; import 'package:smooth_app/pages/prices/product_price_add_page.dart'; -import 'package:smooth_app/query/product_query.dart'; /// Card that displays buttons related to prices. class PricesCard extends StatelessWidget { @@ -40,31 +39,9 @@ class PricesCard extends StatelessWidget { onPressed: () async => Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) => PricesPage( - GetPricesModel( - parameters: GetPricesParameters() - ..productCode = product.barcode - ..orderBy = >[ - const OrderBy( - field: GetPricesOrderField.created, - ascending: false, - ), - ] - ..pageSize = GetPricesModel.pageSize - ..pageNumber = 1, - displayOwner: true, - displayProduct: false, - uri: OpenPricesAPIClient.getUri( - path: 'app/products/${product.barcode!}', - uriHelper: ProductQuery.uriProductHelper, - ), - title: getProductNameAndBrands( - product, - appLocalizations, - ), - addButton: () async => ProductPriceAddPage.showPage( - context: context, - product: product, - ), + GetPricesModel.product( + product: product, + context: context, ), ), ), @@ -76,7 +53,7 @@ class PricesCard extends StatelessWidget { child: SmoothLargeButtonWithIcon( text: appLocalizations.prices_add_a_price, icon: Icons.add, - onPressed: () async => ProductPriceAddPage.showPage( + onPressed: () async => ProductPriceAddPage.showProductPage( context: context, product: product, ), diff --git a/packages/smooth_app/lib/pages/prices/product_price_add_page.dart b/packages/smooth_app/lib/pages/prices/product_price_add_page.dart index 5354c4c62425..bbee46f73981 100644 --- a/packages/smooth_app/lib/pages/prices/product_price_add_page.dart +++ b/packages/smooth_app/lib/pages/prices/product_price_add_page.dart @@ -22,17 +22,44 @@ import 'package:smooth_app/widgets/smooth_scaffold.dart'; /// Single page that displays all the elements of price adding. class ProductPriceAddPage extends StatefulWidget { - const ProductPriceAddPage( - this.product, { + const ProductPriceAddPage({ + required this.barcode, + required this.title, required this.latestOsmLocations, }); - final Product product; + final String barcode; + final String title; final List latestOsmLocations; - static Future showPage({ + static Future showBarcodePage({ + required final BuildContext context, + required final String barcode, + required final String title, + }) async => + _showPage( + context: context, + barcode: barcode, + title: title, + ); + + static Future showProductPage({ required final BuildContext context, required final Product product, + }) async => + _showPage( + context: context, + barcode: product.barcode!, + title: getProductNameAndBrands( + product, + AppLocalizations.of(context), + ), + ); + + static Future _showPage({ + required final BuildContext context, + required final String barcode, + required final String title, }) async { if (!await ProductRefresher().checkIfLoggedIn( context, @@ -52,7 +79,8 @@ class ProductPriceAddPage extends StatefulWidget { await Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) => ProductPriceAddPage( - product, + barcode: barcode, + title: title, latestOsmLocations: osmLocations, ), ), @@ -67,7 +95,7 @@ class _ProductPriceAddPageState extends State { late final PriceModel _model = PriceModel( proofType: ProofType.priceTag, locations: widget.latestOsmLocations, - barcode: widget.product.barcode!, + barcode: widget.barcode, ); final GlobalKey _formKey = GlobalKey(); @@ -85,10 +113,10 @@ class _ProductPriceAddPageState extends State { centerTitle: false, leading: const SmoothBackButton(), title: Text( - getProductNameAndBrands(widget.product, appLocalizations), + widget.title, maxLines: 1, ), - subTitle: Text(widget.product.barcode!), + subTitle: Text(widget.barcode), actions: [ IconButton( icon: const Icon(Icons.info), diff --git a/packages/smooth_app/lib/pages/prices/product_prices_list.dart b/packages/smooth_app/lib/pages/prices/product_prices_list.dart index b2b6d86de7d1..61b82d542032 100644 --- a/packages/smooth_app/lib/pages/prices/product_prices_list.dart +++ b/packages/smooth_app/lib/pages/prices/product_prices_list.dart @@ -62,7 +62,12 @@ class _ProductPricesListState extends State { continue; } children.add( - SmoothCard(child: PriceProductWidget(priceProduct)), + SmoothCard( + child: PriceProductWidget( + priceProduct, + model: widget.model, + ), + ), ); break; } @@ -77,7 +82,10 @@ class _ProductPricesListState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.model.displayProduct && priceProduct != null) - PriceProductWidget(priceProduct), + PriceProductWidget( + priceProduct, + model: widget.model, + ), PriceDataWidget( price, model: widget.model, @@ -90,7 +98,9 @@ class _ProductPricesListState extends State { final AppLocalizations appLocalizations = AppLocalizations.of(context); final String title = result.numberOfPages == 1 - ? appLocalizations.prices_list_length_one_page(children.length) + ? appLocalizations.prices_list_length_one_page( + result.items!.length, + ) : appLocalizations.prices_list_length_many_pages( widget.model.parameters.pageSize!, result.total!, diff --git a/packages/smooth_app/lib/pages/product/edit_product_page.dart b/packages/smooth_app/lib/pages/product/edit_product_page.dart index cbf4ca4b4ec4..ebf61e83145e 100644 --- a/packages/smooth_app/lib/pages/product/edit_product_page.dart +++ b/packages/smooth_app/lib/pages/product/edit_product_page.dart @@ -257,7 +257,7 @@ class _EditProductPageState extends State with UpToDateMixin { _ListTitleItem( title: appLocalizations.prices_add_a_price, leading: const Icon(Icons.add), - onTap: () async => ProductPriceAddPage.showPage( + onTap: () async => ProductPriceAddPage.showProductPage( context: context, product: upToDateProduct, ),