Skip to content

Commit

Permalink
feat: The compare feature only accepts two existing products (#4139)
Browse files Browse the repository at this point in the history
* The compare feature only accepts two existing products

* Update packages/smooth_app/lib/helpers/collections_helper.dart

Co-authored-by: monsieurtanuki <fabrice_fontaine@hotmail.com>

---------

Co-authored-by: monsieurtanuki <fabrice_fontaine@hotmail.com>
  • Loading branch information
g123k and monsieurtanuki authored Jun 15, 2023
1 parent 595fb75 commit 421661c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 37 deletions.
12 changes: 12 additions & 0 deletions packages/smooth_app/lib/data_models/continuous_scan_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:smooth_app/database/dao_product_list.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/generic_lib/duration_constants.dart';
import 'package:smooth_app/helpers/analytics_helper.dart';
import 'package:smooth_app/helpers/collections_helper.dart';
import 'package:smooth_app/query/barcode_product_query.dart';
import 'package:smooth_app/services/smooth_services.dart';

Expand Down Expand Up @@ -41,8 +42,16 @@ class ContinuousScanModel with ChangeNotifier {

ProductList get productList => _productList;

/// List all barcodes scanned (even products being loaded or not found)
List<String> getBarcodes() => _barcodes;

/// List only barcodes where the product exists
Iterable<String> getAvailableBarcodes() => _states
.where((MapEntry<String, ScannedProductState> entry) =>
entry.value == ScannedProductState.FOUND ||
entry.value == ScannedProductState.CACHED)
.keys;

String? get latestConsultedBarcode => _latestConsultedBarcode;

set lastConsultedBarcode(String? barcode) {
Expand Down Expand Up @@ -79,6 +88,7 @@ class ContinuousScanModel with ChangeNotifier {
_states[barcode] = ScannedProductState.CACHED;
_latestScannedBarcode = barcode;
}

return true;
} catch (e) {
Logs.e('Refresh database error', ex: e);
Expand Down Expand Up @@ -271,7 +281,9 @@ class ContinuousScanModel with ChangeNotifier {
barcode,
false,
);

_barcodes.remove(barcode);
_states.remove(barcode);

if (barcode == _latestScannedBarcode) {
_latestScannedBarcode = null;
Expand Down
3 changes: 3 additions & 0 deletions packages/smooth_app/lib/helpers/collections_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,7 @@ extension MapStringKeyExtensions<V> on Map<String, V> {
final String? mapKey = keyStartingWith(key, ignoreCase: ignoreCase);
return this[mapKey];
}

Map<String, V> where(bool Function(MapEntry<String, V>) check) =>
Map<String, V>.fromEntries(entries.where(check));
}
12 changes: 12 additions & 0 deletions packages/smooth_app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1838,6 +1838,18 @@
"@product_card_remove_product_tooltip": {
"description": "Tooltip (message visible with a long-press) on a product item in the carousel"
},
"scan_header_clear_button_tooltip": "Remove all products from the carousel",
"@scan_header_clear_button_tooltip": {
"description": "Tooltip (message visible with a long-press) on the Clear button on top of the scanner"
},
"scan_header_compare_button_invalid_state_tooltip": "Please scan at least two products to compare them",
"@scan_header_compare_button_invalid_state_tooltip": {
"description": "Tooltip (message visible with a long-press) on the Compare button on top of the scanner, when there is just one product scanned"
},
"scan_header_compare_button_valid_state_tooltip": "Click to compare the products you have scanned",
"@scan_header_compare_button_valid_state_tooltip": {
"description": "Tooltip (message visible with a long-press) on the Compare button on top of the scanner, when there is at least two prodiucts"
},
"portion_calculator_description": "Calculate nutrition facts for a specific quantity",
"@portion_calculator_description": {
"description": "Sort of title that describes the portion calculator."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,9 @@ class _CompareProductsButton extends StatelessWidget {

final bool enabled = selectedBarcodes.length >= 2;

return Opacity(
return AnimatedOpacity(
opacity: enabled ? 1.0 : 0.5,
duration: SmoothAnimationsDuration.brief,
child: FloatingActionButton.extended(
label: Text(appLocalizations.compare_products_mode),
icon: const Icon(Icons.compare_arrows),
Expand Down
91 changes: 55 additions & 36 deletions packages/smooth_app/lib/pages/scan/scan_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/duration_constants.dart';
import 'package:smooth_app/pages/personalized_ranking_page.dart';
import 'package:smooth_app/pages/product/common/product_query_page_helper.dart';
import 'package:smooth_app/widgets/ranking_floating_action_button.dart';

class ScanHeader extends StatefulWidget {
const ScanHeader();
Expand All @@ -32,9 +31,11 @@ class _ScanHeaderState extends State<ScanHeader> {
),
);

final int validBarcodes = model.getAvailableBarcodes().length;
final bool compareFeatureAvailable = validBarcodes >= 2;

return AnimatedOpacity(
opacity:
model.getBarcodes().isNotEmpty ? _visibleOpacity : _invisibleOpacity,
opacity: validBarcodes > 0 ? _visibleOpacity : _invisibleOpacity,
duration: SmoothAnimationsDuration.brief,
child: Padding(
padding: const EdgeInsets.symmetric(
Expand All @@ -50,48 +51,66 @@ class _ScanHeaderState extends State<ScanHeader> {
constraints: BoxConstraints(
maxWidth: constraints.maxWidth * 0.4,
),
child: ElevatedButton.icon(
style: buttonStyle,
icon: const Icon(Icons.cancel_outlined),
onPressed: model.clearScanSession,
label: Text(appLocalizations.clear),
child: Tooltip(
message: appLocalizations.scan_header_clear_button_tooltip,
child: ElevatedButton.icon(
style: buttonStyle,
icon: const Icon(Icons.clear_all),
onPressed: model.clearScanSession,
label: Text(appLocalizations.clear),
),
),
),
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: constraints.maxWidth * 0.6,
),
child: ElevatedButton.icon(
style: buttonStyle,
icon:
const Icon(RankingFloatingActionButton.rankingIconData),
onPressed: () async {
final ContinuousScanModel model =
context.read<ContinuousScanModel>();
await model.refreshProductList();
if (!mounted) {
return;
}
await Navigator.push<void>(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) =>
PersonalizedRankingPage(
barcodes: model.productList.barcodes,
title: ProductQueryPageHelper.getProductListLabel(
model.productList,
context,
child: Tooltip(
message: compareFeatureAvailable
? appLocalizations
.scan_header_compare_button_valid_state_tooltip
: appLocalizations
.scan_header_compare_button_invalid_state_tooltip,
child: AnimatedOpacity(
opacity: compareFeatureAvailable ? 1.0 : 0.5,
duration: SmoothAnimationsDuration.brief,
child: ElevatedButton.icon(
style: buttonStyle,
icon: const Icon(Icons.compare_arrows),
onPressed: compareFeatureAvailable
? () async {
final ContinuousScanModel model =
context.read<ContinuousScanModel>();
await model.refreshProductList();
if (!mounted) {
return;
}
await Navigator.push<void>(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) =>
PersonalizedRankingPage(
barcodes: model
.getAvailableBarcodes()
.toList(growable: false),
title: ProductQueryPageHelper
.getProductListLabel(
model.productList,
context,
),
),
),
);
}
: null,
label: FittedBox(
child: Text(
appLocalizations.plural_compare_x_products(
validBarcodes,
),
maxLines: 1,
),
),
);
},
label: FittedBox(
child: Text(
appLocalizations.plural_compare_x_products(
model.getBarcodes().length,
),
maxLines: 1,
),
),
),
Expand Down

0 comments on commit 421661c

Please sign in to comment.