Skip to content

Commit

Permalink
feat: 5205 - new "my prices" page (#5347)
Browse files Browse the repository at this point in the history
* feat: 5205 - new "my prices" page

Deleted files:
* `product_price_item.dart`
* `product_prices_page.dart`

New files:
* `get_prices_model.dart`: Model that stores what we need to know for "get latest prices" queries.
* `price_button.dart`: Simple price button: displaying data with optional action.
* `price_count_widget.dart`: Price Count display.
* `price_data_widget.dart`: Price Data display (no product data here).
* `price_product_widget.dart`: Price Product display (no price data here).
* `prices_page.dart`: Page that displays the latest prices according to a model.

Impacted files:
* `labeler.yml`: deleted and new files
* `prices_card.dart`: refactored using new classes
* `product_prices_list.dart`: refactored using new classes
* `user_preferences_account.dart`: refactored using new classes

* typo fix

* typo fix
  • Loading branch information
monsieurtanuki authored Jun 8, 2024
1 parent e94d61f commit 13072eb
Show file tree
Hide file tree
Showing 11 changed files with 411 additions and 159 deletions.
8 changes: 6 additions & 2 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,18 +258,22 @@ Prices:
- any-glob-to-any-file: 'packages/smooth_app/lib/database/dao_osm_location.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/locations/location_map_page.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/locations/search_location_preloaded_item.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/get_prices_model.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_amount_card.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_amount_field.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_button.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_count_widget.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_currency_card.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_currency_selector.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_data_widget.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_date_card.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_location_card.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_model.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_product_widget.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/prices_page.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/price_proof_card.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/prices_card.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/product_price_add_page.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/product_price_item.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/prices/product_prices_page.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/onboarding/currency_selector.dart'
- any-glob-to-any-file: 'packages/smooth_app/lib/pages/onboarding/currency_selector_helper.dart'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
Expand All @@ -16,6 +17,8 @@ import 'package:smooth_app/pages/preferences/account_deletion_webview.dart';
import 'package:smooth_app/pages/preferences/user_preferences_item.dart';
import 'package:smooth_app/pages/preferences/user_preferences_list_tile.dart';
import 'package:smooth_app/pages/preferences/user_preferences_page.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/product/common/product_query_page_helper.dart';
import 'package:smooth_app/pages/user_management/login_page.dart';
import 'package:smooth_app/query/paged_product_query.dart';
Expand Down Expand Up @@ -210,9 +213,35 @@ class UserPreferencesAccount extends AbstractUserPreferences {
localDatabase: localDatabase,
myCount: _getMyCount(UserSearchType.TO_BE_COMPLETED),
),
_getPriceListTile(
_getListTile(
appLocalizations.user_search_prices_title,
'app/dashboard/prices',
() async => Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) => PricesPage(
GetPricesModel(
parameters: GetPricesParameters()
..owner = userId
..orderBy = <OrderBy<GetPricesOrderField>>[
const OrderBy<GetPricesOrderField>(
field: GetPricesOrderField.created,
ascending: false,
),
]
..pageSize = GetPricesModel.pageSize
..pageNumber = 1,
displayOwner: false,
displayProduct: true,
uri: OpenPricesAPIClient.getUri(
path: 'app/users/${ProductQuery.getWriteUser().userId}',
uriHelper: ProductQuery.uriProductHelper,
),
title: appLocalizations.user_search_prices_title,
subtitle: ProductQuery.getWriteUser().userId,
),
),
),
),
CupertinoIcons.money_dollar_circle,
myCount: _getMyPricesCount(),
),
_getPriceListTile(
Expand Down
38 changes: 38 additions & 0 deletions packages/smooth_app/lib/pages/prices/get_prices_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:openfoodfacts/openfoodfacts.dart';

/// Model that stores what we need to know for "get latest prices" queries.
class GetPricesModel {
const GetPricesModel({
required this.parameters,
required this.displayOwner,
required this.displayProduct,
required this.uri,
required this.title,
this.subtitle,
this.addButton,
});

/// Query parameters.
final GetPricesParameters parameters;

/// Should we display the owner for each price? No if it's an owner query.
final bool displayOwner;

/// Should we display the product for each price? No if it's a product query.
final bool displayProduct;

/// Related web app URI.
final Uri uri;

/// Page title.
final String title;

/// Page subtitle.
final String? subtitle;

/// "Add a price" callback.
final VoidCallback? addButton;

static const int pageSize = 10;
}
40 changes: 40 additions & 0 deletions packages/smooth_app/lib/pages/prices/price_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:flutter/material.dart';

/// Simple price button: displaying data with optional action.
class PriceButton extends StatelessWidget {
const PriceButton({
this.title,
this.iconData,
this.buttonStyle,
required this.onPressed,
});

final String? title;
final IconData? iconData;
final ButtonStyle? buttonStyle;
final VoidCallback? onPressed;

@override
Widget build(BuildContext context) {
if (iconData == null) {
return ElevatedButton(
onPressed: onPressed,
style: buttonStyle,
child: Text(title!),
);
}
if (title == null) {
return ElevatedButton(
onPressed: onPressed,
style: buttonStyle,
child: Icon(iconData),
);
}
return ElevatedButton.icon(
onPressed: onPressed,
icon: Icon(iconData),
label: Text(title!),
style: buttonStyle,
);
}
}
32 changes: 32 additions & 0 deletions packages/smooth_app/lib/pages/prices/price_count_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
import 'package:smooth_app/pages/prices/price_button.dart';

/// Price Count display.
class PriceCountWidget extends StatelessWidget {
const PriceCountWidget(this.count);

final int count;

@override
Widget build(BuildContext context) => PriceButton(
onPressed: null,
iconData: Icons.label,
title: '$count',
buttonStyle: ElevatedButton.styleFrom(
disabledForegroundColor: _getForegroundColor(),
disabledBackgroundColor: _getBackgroundColor(),
),
);

Color? _getForegroundColor() => switch (count) {
0 => Colors.red,
1 => Colors.orange,
_ => Colors.green,
};

Color? _getBackgroundColor() => switch (count) {
0 => Colors.red[100],
1 => Colors.orange[100],
_ => Colors.green[100],
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/widgets/smooth_card.dart';
import 'package:smooth_app/helpers/launch_url_helper.dart';
import 'package:smooth_app/pages/prices/emoji_helper.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/product/common/product_query_page_helper.dart';
import 'package:smooth_app/query/product_query.dart';

/// Single product price widget.
class ProductPriceItem extends StatelessWidget {
const ProductPriceItem(this.price);
/// Price Data display (no product data here).
class PriceDataWidget extends StatelessWidget {
const PriceDataWidget(
this.price, {
required this.model,
});

final Price price;
final GetPricesModel model;

@override
Widget build(BuildContext context) {
Expand All @@ -31,7 +36,7 @@ class ProductPriceItem extends StatelessWidget {
if (price.product == null) {
return null;
}
if (price.product!.quantityUnit != 'g') {
if ((price.product!.quantityUnit ?? 'g') != 'g') {
return null;
}
return '${currencyFormat.format(price.price / (price.product!.quantity! / 1000))} / kg';
Expand All @@ -52,62 +57,59 @@ class ProductPriceItem extends StatelessWidget {

final String? pricePerKg = getPricePerKg();
final String? notDiscountedPrice = getNotDiscountedPrice();
return SmoothCard(
child: ListTile(
title: Text(

return Wrap(
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: MEDIUM_SPACE,
children: <Widget>[
Text(
'${currencyFormat.format(price.price)}'
'${pricePerKg == null ? '' : ' ($pricePerKg)'}'
' '
'${dateFormat.format(price.date)}'
'${notDiscountedPrice == null ? '' : ' ($notDiscountedPrice)'}',
' ${pricePerKg == null ? '' : ' ($pricePerKg)'}',
),
subtitle: Wrap(
spacing: MEDIUM_SPACE,
children: <Widget>[
if (locationTitle != null)
ElevatedButton.icon(
// TODO(monsieurtanuki): open a still-to-be-done "price x location" page
onPressed: () {},
icon: const Icon(Icons.location_on_outlined),
label: Text(locationTitle),
),
ElevatedButton.icon(
// TODO(monsieurtanuki): open a still-to-be-done "price x user" page
onPressed: () {},
icon: const Icon(Icons.account_box),
label: Text(price.owner),
),
Tooltip(
message: '${dateFormat.format(price.created)}'
' '
'${timeFormat.format(price.created)}',
child: ElevatedButton.icon(
// TODO(monsieurtanuki): misleading "active" button
onPressed: () {},
icon: const Icon(Icons.history),
label: Text(
ProductQueryPageHelper.getDurationStringFromTimestamp(
price.created.millisecondsSinceEpoch,
context,
compact: true,
),
),
),
Text(dateFormat.format(price.date)),
if (notDiscountedPrice != null) Text('($notDiscountedPrice)'),
if (locationTitle != null)
// TODO(monsieurtanuki): open a still-to-be-done "price x location" page
PriceButton(
title: locationTitle,
iconData: Icons.location_on_outlined,
onPressed: () {},
),
if (model.displayOwner)
PriceButton(
// TODO(monsieurtanuki): open a still-to-be-done "price x owner" page
title: price.owner,
iconData: Icons.account_box,
onPressed: () {},
),
Tooltip(
message: '${dateFormat.format(price.created)}'
' '
'${timeFormat.format(price.created)}',
child: PriceButton(
// TODO(monsieurtanuki): misleading "active" button
onPressed: () {},
iconData: Icons.history,
title: ProductQueryPageHelper.getDurationStringFromTimestamp(
price.created.millisecondsSinceEpoch,
context,
compact: true,
),
if (price.proof?.filePath != null)
ElevatedButton(
onPressed: () async => LaunchUrlHelper.launchURL(
price.proof!
.getFileUrl(
uriProductHelper: ProductQuery.uriProductHelper,
)
.toString(),
),
child: const Icon(Icons.image),
),
],
),
),
),
if (price.proof?.filePath != null)
PriceButton(
iconData: Icons.image,
onPressed: () async => LaunchUrlHelper.launchURL(
price.proof!
.getFileUrl(
uriProductHelper: ProductQuery.uriProductHelper,
)
.toString(),
),
),
],
);
}

Expand Down
Loading

0 comments on commit 13072eb

Please sign in to comment.