Skip to content

Commit

Permalink
feat: Add all scanned products to list (#3401)
Browse files Browse the repository at this point in the history
* feat: Add all scanned products to list

* Code review

* refactoring from product_list_user_dialog_helper

* Update all_user_product_list_page.dart

* Correct use of pop'ed bools

* Now showing if all products are included

* Await + rename

* Remove loading dialog

* Update product_list_user_dialog_helper.dart

* Update dao_product_list.dart
  • Loading branch information
M123-dev authored Dec 22, 2022
1 parent 07d1f87 commit 1cce8cc
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 251 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class SmoothProductCardFound extends StatelessWidget {
},
child: Hero(
tag: heroTag,
child: Ink(
child: Container(
decoration: BoxDecoration(
borderRadius: ROUNDED_BORDER_RADIUS,
color:
Expand Down
53 changes: 47 additions & 6 deletions packages/smooth_app/lib/database/dao_product_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,37 @@ class DaoProductList extends AbstractDao {
return true;
}

/// Adds or removes list of barcodes to/from a [productList] in one go (depending on [include])
Future<void> bulkSet(
final ProductList productList,
final List<String> barcodes, {
final bool include = true,
}) async {
final _BarcodeList? list = await _get(productList);
final List<String> allBarcodes;

if (list == null) {
allBarcodes = <String>[];
} else {
allBarcodes = _getSafeBarcodeListCopy(list.barcodes);
}

for (final String barcode in barcodes) {
if (include) {
if (!allBarcodes.contains(barcode)) {
allBarcodes.add(barcode);
}
} else {
if (allBarcodes.contains(barcode)) {
allBarcodes.remove(barcode);
}
}
}

final _BarcodeList newList = _BarcodeList.now(allBarcodes);
await _put(_getKey(productList), newList);
}

Future<ProductList> rename(
final ProductList initialList,
final String newName,
Expand Down Expand Up @@ -257,23 +288,33 @@ class DaoProductList extends AbstractDao {

/// Returns the names of the user lists.
///
/// Possibly restricted to the user lists that contain the given barcode.
Future<List<String>> getUserLists({String? withBarcode}) async {
/// Possibly restricted to the user lists that contains ALL the given barcodes.
Future<List<String>> getUserLists({List<String>? withBarcodes}) async {
// TODO(m123): change return type to a set
final List<String> result = <String>[];
for (final dynamic key in _getBox().keys) {
final String tmp = key.toString();
final ProductListType productListType = getProductListType(tmp);
if (productListType != ProductListType.USER) {
continue;
}
if (withBarcode != null) {
if (withBarcodes != null) {
final _BarcodeList? barcodeList = await _getBox().get(key);
if (barcodeList == null ||
!barcodeList.barcodes.contains(withBarcode)) {
if (barcodeList == null) {
continue;
}
for (final String barcode in withBarcodes) {
if (!barcodeList.barcodes.contains(barcode)) {
break;
}
if (withBarcodes.last == barcode) {
result.add(getProductListParameters(tmp));
break;
}
}
} else {
result.add(getProductListParameters(tmp));
}
result.add(getProductListParameters(tmp));
}
return result;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/smooth_app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,10 @@
"@user_list_button_add_product": {
"description": "Short label of an 'add to list' button from a product context"
},
"added_to_list_msg": "Added to list",
"@added_to_list_msg": {
"description": "Message when products have been successfully added to a list"
},
"user_list_popup_clear": "Clear",
"@user_list_popup_clear": {
"description": "Short label of a 'clear list' popup"
Expand Down
50 changes: 50 additions & 0 deletions packages/smooth_app/lib/pages/personalized_ranking_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import 'package:openfoodfacts/personalized_search/matched_product_v2.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/data_models/personalized_ranking_model.dart';
import 'package:smooth_app/data_models/product_preferences.dart';
import 'package:smooth_app/database/dao_product_list.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/generic_lib/buttons/smooth_large_button_with_icon.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/duration_constants.dart';
import 'package:smooth_app/helpers/product_compatibility_helper.dart';
import 'package:smooth_app/pages/product/common/product_list_item_simple.dart';
import 'package:smooth_app/pages/product_list_user_dialog_helper.dart';
import 'package:smooth_app/pages/tmp_matched_product_v2.dart';
import 'package:smooth_app/widgets/smooth_scaffold.dart';

Expand Down Expand Up @@ -52,15 +54,63 @@ class _PersonalizedRankingPageState extends State<PersonalizedRankingPage>
);
}

Future<void> _addToLists(BuildContext context) async {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final LocalDatabase localDatabase = context.read<LocalDatabase>();
final DaoProductList daoProductList = DaoProductList(localDatabase);
final bool? added = await ProductListUserDialogHelper(daoProductList)
.showUserAddProductsDialog(
context,
widget.barcodes.toSet(),
);
if (!mounted) {
return;
}
if (added != null && added) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
appLocalizations.added_to_list_msg,
),
duration: SnackBarDuration.medium,
),
);
}
}

Future<void> _handlePopUpClick(String value) async {
switch (value) {
case 'add_to_list':
await _addToLists(context);
break;
default:
throw Exception('Unknown case $value');
}
}

@override
Widget build(BuildContext context) {
final ProductPreferences productPreferences =
context.watch<ProductPreferences>();
context.watch<LocalDatabase>();
final AppLocalizations appLocalizations = AppLocalizations.of(context);

return SmoothScaffold(
appBar: AppBar(
title: Text(widget.title, overflow: TextOverflow.fade),
actions: <Widget>[
PopupMenuButton<String>(
onSelected: _handlePopUpClick,
itemBuilder: (BuildContext context) {
return <PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'add_to_list',
child: Text(appLocalizations.user_list_button_add_product),
),
];
},
),
],
),
body: ChangeNotifierProvider<PersonalizedRankingModel>(
create: (final BuildContext context) => _model,
Expand Down
11 changes: 7 additions & 4 deletions packages/smooth_app/lib/pages/product/new_product_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,12 @@ class _ProductPageState extends State<ProductPage> with TraceableClientMixin {
Future<void> _editList() async {
final LocalDatabase localDatabase = context.read<LocalDatabase>();
final DaoProductList daoProductList = DaoProductList(localDatabase);
final bool refreshed = await ProductListUserDialogHelper(daoProductList)
.showUserListsWithBarcodeDialog(context, widget.product);
if (refreshed) {
final bool? refreshed = await ProductListUserDialogHelper(daoProductList)
.showUserAddProductsDialog(
context,
<String>{widget.product.barcode!},
);
if (refreshed != null && refreshed) {
setState(() {});
}
}
Expand Down Expand Up @@ -368,7 +371,7 @@ class _ProductPageState extends State<ProductPage> with TraceableClientMixin {
final DaoProductList daoProductList,
) =>
FutureBuilder<List<String>>(
future: daoProductList.getUserLists(withBarcode: _barcode),
future: daoProductList.getUserLists(withBarcodes: <String>[_barcode]),
builder: (
final BuildContext context,
final AsyncSnapshot<List<String>> snapshot,
Expand Down
Loading

0 comments on commit 1cce8cc

Please sign in to comment.