Skip to content

Commit

Permalink
feat: prices - top contributors now within the app (#5383)
Browse files Browse the repository at this point in the history
* feat: prices - top contributors now locally

New files:
* `price_user_button.dart`: Widget that displays a user, for Prices.
* `prices_users_page.dart`: Page that displays the top prices users.

Impacted files:
* `app_en.arb`: added 2 label for "Contributor prices"
* `app_fr.arb`: added 2 label for "Contributor prices"
* `price_count_widget.dart`: minor refactoring
* `price_data_widget.dart`: minor refactoring using new class `PriceUserButton`
* `user_preferences_account.dart`: local display of top users; minor refactoring using new class `PriceUserButton`

* Added comment.
  • Loading branch information
monsieurtanuki authored Jun 16, 2024
1 parent 9f7d9d4 commit 7809854
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 41 deletions.
16 changes: 16 additions & 0 deletions packages/smooth_app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,18 @@
}
}
},
"prices_users_list_length_many_pages": "Top {pageSize} contributors (total: {total})",
"@prices_users_list_length_many_pages": {
"description": "Number of users for one-page result",
"placeholders": {
"pageSize": {
"type": "int"
},
"total": {
"type": "int"
}
}
},
"prices_amount_subtitle": "Amount",
"prices_amount_is_discounted": "Is discounted?",
"prices_amount_price_normal": "Price",
Expand Down Expand Up @@ -1801,6 +1813,10 @@
"@user_search_prices_title": {
"description": "User prices: list tile title"
},
"user_any_search_prices_title": "Contributor prices",
"@user_any_search_prices_title": {
"description": "User prices (everybody except me): list tile title"
},
"all_search_prices_latest_title": "Latest Prices added",
"@all_search_prices_latest_title": {
"description": "Latest prices: list tile title"
Expand Down
16 changes: 16 additions & 0 deletions packages/smooth_app/lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,18 @@
}
}
},
"prices_users_list_length_many_pages": "Top {pageSize} contributeurs (total : {total})",
"@prices_users_list_length_many_pages": {
"description": "Number of users for one-page result",
"placeholders": {
"pageSize": {
"type": "int"
},
"total": {
"type": "int"
}
}
},
"prices_amount_subtitle": "Montant",
"prices_amount_is_discounted": "En promotion ?",
"prices_amount_price_normal": "Prix",
Expand Down Expand Up @@ -1798,6 +1810,10 @@
"@user_search_prices_title": {
"description": "User prices: list tile title"
},
"user_any_search_prices_title": "Prix d'un contributeur",
"@user_any_search_prices_title": {
"description": "User prices (everybody except me): list tile title"
},
"all_search_prices_latest_title": "Derniers prix ajoutés",
"@all_search_prices_latest_title": {
"description": "Latest prices: list tile title"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ 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/price_user_button.dart';
import 'package:smooth_app/pages/prices/prices_page.dart';
import 'package:smooth_app/pages/prices/prices_users_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 @@ -214,32 +216,13 @@ class UserPreferencesAccount extends AbstractUserPreferences {
myCount: _getMyCount(UserSearchType.TO_BE_COMPLETED),
),
_getListTile(
appLocalizations.user_search_prices_title,
() 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,
),
),
),
PriceUserButton.showUserTitle(
user: ProductQuery.getWriteUser().userId,
context: context,
),
() async => PriceUserButton.showUserPrices(
user: ProductQuery.getWriteUser().userId,
context: context,
),
CupertinoIcons.money_dollar_circle,
myCount: _getPricesCount(owner: ProductQuery.getWriteUser().userId),
Expand Down Expand Up @@ -273,9 +256,14 @@ class UserPreferencesAccount extends AbstractUserPreferences {
CupertinoIcons.money_dollar_circle,
myCount: _getPricesCount(),
),
_getPriceListTile(
_getListTile(
appLocalizations.all_search_prices_top_user_title,
'app/users',
() async => Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) => const PricesUsersPage(),
),
),
Icons.account_box,
),
_getPriceListTile(
appLocalizations.all_search_prices_top_location_title,
Expand Down
14 changes: 8 additions & 6 deletions packages/smooth_app/lib/pages/prices/price_count_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,23 @@ class PriceCountWidget extends StatelessWidget {
title: '$count',
buttonStyle: ElevatedButton.styleFrom(
disabledForegroundColor:
enableCountButton ? null : _getForegroundColor(),
enableCountButton ? null : getForegroundColor(count),
disabledBackgroundColor:
enableCountButton ? null : _getBackgroundColor(),
foregroundColor: !enableCountButton ? null : _getForegroundColor(),
backgroundColor: !enableCountButton ? null : _getBackgroundColor(),
enableCountButton ? null : getBackgroundColor(count),
foregroundColor:
!enableCountButton ? null : getForegroundColor(count),
backgroundColor:
!enableCountButton ? null : getBackgroundColor(count),
),
);

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

Color? _getBackgroundColor() => switch (count) {
static Color? getBackgroundColor(final int count) => switch (count) {
0 => Colors.red[100],
1 => Colors.orange[100],
_ => Colors.green[100],
Expand Down
9 changes: 2 additions & 7 deletions packages/smooth_app/lib/pages/prices/price_data_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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/prices/price_user_button.dart';
import 'package:smooth_app/pages/product/common/product_query_page_helper.dart';
import 'package:smooth_app/query/product_query.dart';

Expand Down Expand Up @@ -79,13 +80,7 @@ class PriceDataWidget extends StatelessWidget {
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: () {},
),
if (model.displayOwner) PriceUserButton(price.owner),
Tooltip(
message: '${dateFormat.format(price.created)}'
' '
Expand Down
63 changes: 63 additions & 0 deletions packages/smooth_app/lib/pages/prices/price_user_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.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';
import 'package:smooth_app/query/product_query.dart';

/// Widget that displays a user, for Prices.
class PriceUserButton extends StatelessWidget {
const PriceUserButton(this.user);

final String user;

static String showUserTitle({
required final String user,
required final BuildContext context,
}) =>
user == ProductQuery.getWriteUser().userId
? AppLocalizations.of(context).user_search_prices_title
: AppLocalizations.of(context).user_any_search_prices_title;

static Future<void> showUserPrices({
required final String user,
required final BuildContext context,
}) async =>
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) => PricesPage(
GetPricesModel(
parameters: GetPricesParameters()
..owner = user
..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/$user',
uriHelper: ProductQuery.uriProductHelper,
),
title: showUserTitle(user: user, context: context),
subtitle: user,
),
),
),
);

@override
Widget build(BuildContext context) => PriceButton(
title: user,
iconData: Icons.account_box,
onPressed: () async => showUserPrices(
user: user,
context: context,
),
);
}
143 changes: 143 additions & 0 deletions packages/smooth_app/lib/pages/prices/prices_users_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import 'package:flutter/material.dart';
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/smooth_back_button.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/price_button.dart';
import 'package:smooth_app/pages/prices/price_count_widget.dart';
import 'package:smooth_app/pages/prices/price_user_button.dart';
import 'package:smooth_app/query/product_query.dart';
import 'package:smooth_app/widgets/smooth_app_bar.dart';
import 'package:smooth_app/widgets/smooth_scaffold.dart';

/// Page that displays the top prices users.
class PricesUsersPage extends StatefulWidget {
const PricesUsersPage();

@override
State<PricesUsersPage> createState() => _PricesUsersPageState();
}

class _PricesUsersPageState extends State<PricesUsersPage> {
late final Future<MaybeError<GetUsersResult>> _users = _showTopUsers();

// In this specific page, let's never try to go beyond the top 10.
// cf. https://github.com/openfoodfacts/smooth-app/pull/5383#issuecomment-2171117141
static const int _pageSize = 10;

@override
Widget build(BuildContext context) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
return SmoothScaffold(
appBar: SmoothAppBar(
centerTitle: false,
leading: const SmoothBackButton(),
title: Text(
appLocalizations.all_search_prices_top_user_title,
),
actions: <Widget>[
IconButton(
tooltip: appLocalizations.prices_app_button,
icon: const Icon(Icons.open_in_new),
onPressed: () async => LaunchUrlHelper.launchURL(
OpenPricesAPIClient.getUri(
path: 'app/users',
uriHelper: ProductQuery.uriProductHelper,
).toString(),
),
),
],
),
body: FutureBuilder<MaybeError<GetUsersResult>>(
future: _users,
builder: (
final BuildContext context,
final AsyncSnapshot<MaybeError<GetUsersResult>> snapshot,
) {
if (snapshot.connectionState != ConnectionState.done) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text(snapshot.error!.toString());
}
// highly improbable
if (!snapshot.hasData) {
return const Text('no data');
}
if (snapshot.data!.isError) {
return Text(snapshot.data!.error!);
}
final GetUsersResult result = snapshot.data!.value;
// highly improbable
if (result.items == null) {
return const Text('empty list');
}
final List<Widget> children = <Widget>[];

for (final PriceUser item in result.items!) {
children.add(
SmoothCard(
child: Wrap(
spacing: VERY_SMALL_SPACE,
children: <Widget>[
PriceUserButton(item.userId),
PriceButton(
onPressed: () async => PriceUserButton.showUserPrices(
user: item.userId,
context: context,
),
iconData: Icons.label,
title: '${item.priceCount}',
buttonStyle: ElevatedButton.styleFrom(
foregroundColor: PriceCountWidget.getForegroundColor(
item.priceCount,
),
backgroundColor: PriceCountWidget.getBackgroundColor(
item.priceCount,
),
),
),
],
),
),
);
}
final AppLocalizations appLocalizations =
AppLocalizations.of(context);
final String title =
appLocalizations.prices_users_list_length_many_pages(
_pageSize,
result.total!,
);
children.insert(
0,
SmoothCard(child: ListTile(title: Text(title))),
);
// so that the last content gets not hidden by the FAB
children.add(
const SizedBox(height: 2 * MINIMUM_TOUCH_SIZE),
);
return ListView(
children: children,
);
},
),
);
}

static Future<MaybeError<GetUsersResult>> _showTopUsers() async =>
OpenPricesAPIClient.getUsers(
GetUsersParameters()
..orderBy = <OrderBy<GetUsersOrderField>>[
const OrderBy<GetUsersOrderField>(
field: GetUsersOrderField.priceCount,
ascending: false,
),
]
..pageSize = _pageSize
..pageNumber = 1,
uriHelper: ProductQuery.uriProductHelper,
);
}

0 comments on commit 7809854

Please sign in to comment.