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: 5403 - improvements for "price adding" #5404

Closed
13 changes: 13 additions & 0 deletions packages/smooth_app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,15 @@
}
},
"prices_barcode_reader_action": "Barcode reader",
"prices_barcode_already": "Barcode {barcode} is already in the list!",
"@prices_barcode_already": {
"description": "Validation error message about barcode already being in the barcode list",
"placeholders": {
"barcode": {
"type": "String"
}
}
},
"prices_view_prices": "View the prices",
"prices_list_length_one_page": "{count,plural, =0{No price yet} =1{Only one price} other{All {count} prices}}",
"@prices_list_length_one_page": {
Expand Down Expand Up @@ -2354,6 +2363,10 @@
"@image_edit_url_error": {
"description": "Error message, when editing image fails, due to missing url."
},
"remember_my_choice_session": "Remember my choice for the current session",
"@remember_my_choice_session": {
"description": "Checkbox label when we want to remember the choice"
},
"user_picture_source_remember": "Remember my choice",
"@user_picture_source_remember": {
"description": "Checkbox label when select a picture source"
Expand Down
13 changes: 13 additions & 0 deletions packages/smooth_app/lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1704,6 +1704,15 @@
}
}
},
"prices_barcode_already": "Le code-barres {barcode} fait déjà partie de la liste !",
"@prices_barcode_already": {
"description": "Validation error message about barcode already being in the barcode list",
"placeholders": {
"barcode": {
"type": "String"
}
}
},
"prices_list_length_many_pages": "{pageSize} prix les plus récents (total : {total})",
"@prices_list_length_many_pages": {
"description": "Number of prices for one-page result",
Expand Down Expand Up @@ -2317,6 +2326,10 @@
"@image_edit_url_error": {
"description": "Error message, when editing image fails, due to missing url."
},
"remember_my_choice_session": "Mémoriser mon choix pour la session en cours",
"@remember_my_choice_session": {
"description": "Checkbox label when we want to remember the choice"
},
"user_picture_source_remember": "Mémoriser mon choix",
"@user_picture_source_remember": {
"description": "Checkbox label when select a picture source"
Expand Down
52 changes: 33 additions & 19 deletions packages/smooth_app/lib/pages/prices/price_amount_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ import 'package:smooth_app/pages/prices/price_product_search_page.dart';

/// Card that displays the amounts (discounted or not) for price adding.
class PriceAmountCard extends StatefulWidget {
PriceAmountCard({
const PriceAmountCard({
required this.priceModel,
required this.index,
required this.refresh,
}) : model = priceModel.priceAmountModels[index],
total = priceModel.priceAmountModels.length;
this.focusNode,
super.key,
});

final PriceModel priceModel;
final PriceAmountModel model;
final int index;
final int total;
// TODO(monsieurtanuki): not elegant, the display was not refreshed when removing an item
final VoidCallback refresh;
final FocusNode? focusNode;

@override
State<PriceAmountCard> createState() => _PriceAmountCardState();
Expand All @@ -35,22 +35,33 @@ class _PriceAmountCardState extends State<PriceAmountCard> {
final TextEditingController _controllerWithoutDiscount =
TextEditingController();

@override
void initState() {
super.initState();
_controllerPaid.text = _model.paidPrice;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's risky to change the text this way, as the setter may notify a client calling setState… and we're already in the dirty state.

To prevent any issue, I would just wrap it around a addPostFrameCallback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I've double-checked and I can't see how this could happen:

  • the only setter in this line is _controllerPaid.text
  • .text doesn't trigger anything, in particular not onChanged
  • besides, it's in the initState, when the widget isn't even built, so no setState expected.

That said, if you prefer a safer way (reviewing-wise) to do exactly the same thing, would you like me to rewrite it like that:

  late final TextEditingController _controllerPaid;
  late final TextEditingController _controllerWithoutDiscount;

  @override
  void initState() {
    super.initState();
    _controllerPaid = TextEditingController(text: _model.paidPrice);
    _controllerWithoutDiscount =
        TextEditingController(text: _model.priceWithoutDiscount);
  }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A TextEditingController is a ValueNotifier and text is linked the value.
Hence the dependency to listeners

_controllerWithoutDiscount.text = _model.priceWithoutDiscount;
}

PriceAmountModel get _model =>
widget.priceModel.priceAmountModels[widget.index];
int get _total => widget.priceModel.priceAmountModels.length;

@override
Widget build(BuildContext context) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final bool isEmpty = widget.model.product.barcode.isEmpty;
final bool isEmpty = _model.product.barcode.isEmpty;
return SmoothCard(
child: Column(
children: <Widget>[
Text(
'${appLocalizations.prices_amount_subtitle}'
'${widget.total == 1 ? '' : ' (${widget.index + 1}/${widget.total})'}',
'${_total == 1 ? '' : ' (${widget.index + 1}/$_total)'}',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not mandatoryuu here, but an improvement would be to use NumberFormat, because some languages has specific way to handle separators

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I think you read a bit quickly: here it's not a division (with a decimal separator), it's a lousy "current_item_number/total_number_of_items" description (like "step 1/3").
I'm not proud of that but it's helpful for a user to know where he is among the products.
I couldn't find anything about that in NumberFormat - though they probably display that differently depending on the countries.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and no.
My point is not on the /, but how you format the numbers between the /

),
PriceProductListTile(
product: widget.model.product,
product: _model.product,
trailingIconData: isEmpty
? Icons.edit
: widget.total == 1
: _total == 1
? null
: Icons.clear,
onPressed: isEmpty
Expand All @@ -59,15 +70,18 @@ class _PriceAmountCardState extends State<PriceAmountCard> {
await Navigator.of(context).push<PriceMetaProduct>(
MaterialPageRoute<PriceMetaProduct>(
builder: (BuildContext context) =>
const PriceProductSearchPage(),
PriceProductSearchPage(
barcodes: widget.priceModel.getBarcodes(),
),
),
);
if (product == null) {
return;
}
setState(() => widget.model.product = product);
_model.product = product;
widget.refresh.call();
}
: widget.total == 1
: _total == 1
? null
: () {
widget.priceModel.priceAmountModels
Expand All @@ -76,32 +90,32 @@ class _PriceAmountCardState extends State<PriceAmountCard> {
},
),
SmoothLargeButtonWithIcon(
icon: widget.model.promo
? Icons.check_box
: Icons.check_box_outline_blank,
icon:
_model.promo ? Icons.check_box : Icons.check_box_outline_blank,
text: appLocalizations.prices_amount_is_discounted,
onPressed: () => setState(
() => widget.model.promo = !widget.model.promo,
() => _model.promo = !_model.promo,
),
),
const SizedBox(height: SMALL_SPACE),
Row(
children: <Widget>[
Expanded(
child: PriceAmountField(
focusNode: widget.focusNode,
controller: _controllerPaid,
isPaidPrice: true,
model: widget.model,
model: _model,
),
),
const SizedBox(width: LARGE_SPACE),
Expanded(
child: !widget.model.promo
child: !_model.promo
? Container()
: PriceAmountField(
controller: _controllerWithoutDiscount,
isPaidPrice: false,
model: widget.model,
model: _model,
),
),
],
Expand Down
4 changes: 3 additions & 1 deletion packages/smooth_app/lib/pages/prices/price_amount_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ class PriceAmountField extends StatelessWidget {
required this.model,
required this.isPaidPrice,
required this.controller,
this.focusNode,
});

final PriceAmountModel model;
final bool isPaidPrice;
final TextEditingController controller;
final FocusNode? focusNode;

// TODO(monsieurtanuki): TextInputAction + focus
static const TextInputType _priceTextInputType =
TextInputType.numberWithOptions(
signed: false,
Expand All @@ -26,6 +27,7 @@ class PriceAmountField extends StatelessWidget {
Widget build(BuildContext context) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
return SmoothTextFormField(
focusNode: focusNode,
type: TextFieldTypes.PLAIN_TEXT,
controller: controller,
hintText: !isPaidPrice
Expand Down
14 changes: 5 additions & 9 deletions packages/smooth_app/lib/pages/prices/price_amount_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,8 @@ class PriceAmountModel {

PriceMetaProduct product;

String _paidPrice = '';
String _priceWithoutDiscount = '';

set paidPrice(final String value) => _paidPrice = value;

set priceWithoutDiscount(final String value) => _priceWithoutDiscount = value;
String paidPrice = '';
String priceWithoutDiscount = '';

late double _checkedPaidPrice;
double? _checkedPriceWithoutDiscount;
Expand All @@ -37,11 +33,11 @@ class PriceAmountModel {
if (product.barcode.isEmpty) {
return appLocalizations.prices_amount_no_product;
}
_checkedPaidPrice = validateDouble(_paidPrice)!;
_checkedPaidPrice = validateDouble(paidPrice)!;
_checkedPriceWithoutDiscount = null;
if (promo) {
if (_priceWithoutDiscount.isNotEmpty) {
_checkedPriceWithoutDiscount = validateDouble(_priceWithoutDiscount);
if (priceWithoutDiscount.isNotEmpty) {
_checkedPriceWithoutDiscount = validateDouble(priceWithoutDiscount);
if (_checkedPriceWithoutDiscount == null) {
return appLocalizations.prices_amount_price_incorrect;
}
Expand Down
8 changes: 8 additions & 0 deletions packages/smooth_app/lib/pages/prices/price_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ class PriceModel with ChangeNotifier {

final List<PriceAmountModel> priceAmountModels;

List<String> getBarcodes() {
final List<String> result = <String>[];
for (final PriceAmountModel priceAmountModel in priceAmountModels) {
result.add(priceAmountModel.product.barcode);
}
return result;
}

CropParameters? _cropParameters;

CropParameters? get cropParameters => _cropParameters;
Expand Down
Loading