Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: prices - top contributors now within the app #5383

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
);
}
Loading