Skip to content

Commit

Permalink
feat: 5586 - OxF filter for term searches (#5637)
Browse files Browse the repository at this point in the history
Impacted files:
* `category_product_query.dart`: refactored with new `productType` parameter
* `keywords_product_query.dart`: refactored with new `productType` parameter
* `paged_product_query.dart`: refactored with new `productType` parameter
* `paged_search_product_query.dart`: refactored with new `productType` parameter
* `paged_to_be_completed_product_query.dart`: refactored with new `productType` parameter
* `paged_user_product_query.dart`: refactored with new `productType` parameter
* `product_list.dart`: refactored with new `productType` parameter
* `product_query.dart`: added a "get label" method for `ProductType`
* `search_field.dart`: displayed the new optional "additional filter" (e.g. OxF)
* `search_helper.dart`: added a new optional "additional filter"
* `search_product_helper.dart`: new "product type filter" widget
* `summary_card.dart`: minor "productType" fix
* `user_preferences_account.dart`: added "productType.food" to user page counts
* `user_preferences_contribute.dart`: added "productType.food" to "to be completed" products
  • Loading branch information
monsieurtanuki committed Sep 27, 2024
1 parent 9564cfd commit 077bf5e
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 31 deletions.
21 changes: 20 additions & 1 deletion packages/smooth_app/lib/data_models/product_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class ProductList {
this.pageNumber = 0,
this.language,
this.country,
this.productType,
});

ProductList.keywordSearch(
Expand All @@ -55,13 +56,15 @@ class ProductList {
required int pageNumber,
required OpenFoodFactsLanguage language,
required OpenFoodFactsCountry? country,
required ProductType productType,
}) : this._(
listType: ProductListType.HTTP_SEARCH_KEYWORDS,
parameters: keywords,
pageSize: pageSize,
pageNumber: pageNumber,
language: language,
country: country,
productType: productType,
);

ProductList.categorySearch(
Expand All @@ -70,78 +73,90 @@ class ProductList {
required int pageNumber,
required OpenFoodFactsLanguage language,
required OpenFoodFactsCountry? country,
required ProductType productType,
}) : this._(
listType: ProductListType.HTTP_SEARCH_CATEGORY,
parameters: category,
pageSize: pageSize,
pageNumber: pageNumber,
language: language,
country: country,
productType: productType,
);

ProductList.contributor(
final String userId, {
required int pageSize,
required int pageNumber,
required OpenFoodFactsLanguage language,
required ProductType productType,
}) : this._(
listType: ProductListType.HTTP_USER_CONTRIBUTOR,
parameters: userId,
pageSize: pageSize,
pageNumber: pageNumber,
language: language,
productType: productType,
);

ProductList.informer(
final String userId, {
required int pageSize,
required int pageNumber,
required OpenFoodFactsLanguage language,
required ProductType productType,
}) : this._(
listType: ProductListType.HTTP_USER_INFORMER,
parameters: userId,
pageSize: pageSize,
pageNumber: pageNumber,
language: language,
productType: productType,
);

ProductList.photographer(
final String userId, {
required int pageSize,
required int pageNumber,
required OpenFoodFactsLanguage language,
required ProductType productType,
}) : this._(
listType: ProductListType.HTTP_USER_PHOTOGRAPHER,
parameters: userId,
pageSize: pageSize,
pageNumber: pageNumber,
language: language,
productType: productType,
);

ProductList.toBeCompleted(
final String userId, {
required int pageSize,
required int pageNumber,
required OpenFoodFactsLanguage language,
required ProductType productType,
}) : this._(
listType: ProductListType.HTTP_USER_TO_BE_COMPLETED,
parameters: userId,
pageSize: pageSize,
pageNumber: pageNumber,
language: language,
productType: productType,
);

ProductList.allToBeCompleted({
required int pageSize,
required int pageNumber,
required OpenFoodFactsLanguage language,
required OpenFoodFactsCountry? country,
required ProductType productType,
}) : this._(
listType: ProductListType.HTTP_ALL_TO_BE_COMPLETED,
pageSize: pageSize,
pageNumber: pageNumber,
language: language,
country: country,
productType: productType,
);

ProductList.history() : this._(listType: ProductListType.HISTORY);
Expand Down Expand Up @@ -171,6 +186,9 @@ class ProductList {
/// Country at query time.
final OpenFoodFactsCountry? country;

/// ProductType at query time.
final ProductType? productType;

/// "Total size" returned by the query.
int totalSize = 0;

Expand Down Expand Up @@ -251,7 +269,8 @@ class ProductList {
',$pageSize'
',$pageNumber'
',${language?.code ?? ''}'
',${country?.offTag ?? ''}';
',${country?.offTag ?? ''}'
'${productType == null || productType == ProductType.food ? '' : ',${productType!.offTag}'}';
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ class UserPreferencesAccount extends AbstractUserPreferences {
productQuery: PagedUserProductQuery(
userId: userId,
type: UserSearchType.CONTRIBUTOR,
// TODO(monsieurtanuki): only food?
productType: ProductType.food,
),
title: appLocalizations.user_search_contributor_title,
iconData: Icons.add_circle_outline,
Expand All @@ -182,6 +184,7 @@ class UserPreferencesAccount extends AbstractUserPreferences {
productQuery: PagedUserProductQuery(
userId: userId,
type: UserSearchType.INFORMER,
productType: ProductType.food,
),
title: appLocalizations.user_search_informer_title,
iconData: Icons.edit,
Expand All @@ -193,6 +196,7 @@ class UserPreferencesAccount extends AbstractUserPreferences {
productQuery: PagedUserProductQuery(
userId: userId,
type: UserSearchType.PHOTOGRAPHER,
productType: ProductType.food,
),
title: appLocalizations.user_search_photographer_title,
iconData: Icons.add_a_photo,
Expand All @@ -204,6 +208,7 @@ class UserPreferencesAccount extends AbstractUserPreferences {
productQuery: PagedUserProductQuery(
userId: userId,
type: UserSearchType.TO_BE_COMPLETED,
productType: ProductType.food,
),
title: appLocalizations.user_search_to_be_completed_title,
iconData: Icons.more_horiz,
Expand Down Expand Up @@ -296,7 +301,9 @@ class UserPreferencesAccount extends AbstractUserPreferences {
'app/products',
),
_buildProductQueryTile(
productQuery: PagedToBeCompletedProductQuery(),
productQuery: PagedToBeCompletedProductQuery(
productType: ProductType.food,
),
title: appLocalizations.all_search_to_be_completed_title,
iconData: Icons.more_outlined,
context: context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:http/http.dart' as http;
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:provider/provider.dart';
import 'package:share_plus/share_plus.dart';
import 'package:smooth_app/data_models/github_contributors_model.dart';
Expand Down Expand Up @@ -170,7 +171,10 @@ class UserPreferencesContribute extends AbstractUserPreferences {
ProductQueryPageHelper.openBestChoice(
name: appLocalizations.all_search_to_be_completed_title,
localDatabase: localDatabase,
productQuery: PagedToBeCompletedProductQuery(),
productQuery: PagedToBeCompletedProductQuery(
// TODO(monsieurtanuki): only food?
productType: ProductType.food,
),
// the other "context"s being popped
context: this.context,
editableAppBarTitle: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ abstract class SearchHelper extends ValueNotifier<SearchQuery?> {
/// Hint text for the search field.
String getHintText(final AppLocalizations appLocalizations);

Widget? getAdditionalFilter() => null;

/// Returns all the previous queries, in reverse order.
List<String> getAllQueries(final LocalDatabase localDatabase) =>
DaoStringList(localDatabase).getAll(historyKey).reversed.toList();
Expand Down
5 changes: 4 additions & 1 deletion packages/smooth_app/lib/pages/product/summary_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,10 @@ class _SummaryCardState extends State<SummaryCard> with UpToDateMixin {
onPressed: () async => ProductQueryPageHelper.openBestChoice(
name: categoryLabel!,
localDatabase: context.read<LocalDatabase>(),
productQuery: CategoryProductQuery(categoryTag!),
productQuery: CategoryProductQuery(
categoryTag!,
productType: upToDateProduct.productType ?? ProductType.food,
),
context: context,
searchResult: false,
),
Expand Down
32 changes: 19 additions & 13 deletions packages/smooth_app/lib/pages/search/search_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class _SearchFieldState extends State<SearchField> {

final TextStyle textStyle = SearchFieldUIHelper.textStyle(context);

final Widget? additionalFilter = widget.searchHelper.getAdditionalFilter();
return ChangeNotifierProvider<TextEditingController>.value(
value: _controller!,
child: SmoothHero(
Expand All @@ -90,19 +91,24 @@ class _SearchFieldState extends State<SearchField> {
: null,
child: Material(
// ↑ Needed by the Hero Widget
child: TextField(
controller: _controller,
focusNode: _focusNode,
onSubmitted: (String query) => _performSearch(context, query),
textInputAction: TextInputAction.search,
enableSuggestions: widget.enableSuggestions,
autocorrect: widget.autocorrect,
style: textStyle,
decoration: _getInputDecoration(
context,
localizations,
),
cursorColor: textStyle.color,
child: Column(
children: <Widget>[
TextField(
controller: _controller,
focusNode: _focusNode,
onSubmitted: (String query) => _performSearch(context, query),
textInputAction: TextInputAction.search,
enableSuggestions: widget.enableSuggestions,
autocorrect: widget.autocorrect,
style: textStyle,
decoration: _getInputDecoration(
context,
localizations,
),
cursorColor: textStyle.color,
),
if (additionalFilter != null) additionalFilter,
],
),
),
),
Expand Down
48 changes: 46 additions & 2 deletions packages/smooth_app/lib/pages/search/search_product_helper.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/data_models/fetched_product.dart';
import 'package:smooth_app/database/dao_string_list.dart';
Expand All @@ -12,18 +13,25 @@ import 'package:smooth_app/pages/product/common/product_dialog_helper.dart';
import 'package:smooth_app/pages/product/common/product_query_page_helper.dart';
import 'package:smooth_app/pages/product/common/search_helper.dart';
import 'package:smooth_app/query/keywords_product_query.dart';
import 'package:smooth_app/query/product_query.dart';

/// Search helper dedicated to product search.
class SearchProductHelper extends SearchHelper {
SearchProductHelper();

// TODO(monsieurtanuki): maybe reinit it with latest value
ProductType _productType = ProductType.food;

@override
String get historyKey => DaoStringList.keySearchProductHistory;

@override
String getHintText(final AppLocalizations appLocalizations) =>
appLocalizations.search;

@override
Widget getAdditionalFilter() => _ProductTypeFilter(this);

@override
void search(
BuildContext context,
Expand Down Expand Up @@ -71,6 +79,7 @@ class SearchProductHelper extends SearchHelper {
final FetchedProduct fetchedProduct =
await productDialogHelper.openBestChoice();
if (fetchedProduct.status == FetchedProductStatus.ok) {
// TODO(monsieurtanuki): add OxF to Matomo data?
AnalyticsHelper.trackSearch(
search: value,
searchCategory: 'barcode',
Expand All @@ -95,7 +104,6 @@ class SearchProductHelper extends SearchHelper {
}
}

// used to be in now defunct `ChoosePage`
Future<void> _onSubmittedText(
final String value,
final BuildContext context,
Expand All @@ -107,11 +115,47 @@ class SearchProductHelper extends SearchHelper {
widget: await ProductQueryPageHelper.getBestChoiceWidget(
name: value,
localDatabase: localDatabase,
productQuery: KeywordsProductQuery(value),
productQuery: KeywordsProductQuery(
value,
productType: _productType,
),
context: context,
editableAppBarTitle: false,
),
),
);
}
}

class _ProductTypeFilter extends StatefulWidget {
const _ProductTypeFilter(this.searchProductHelper);

final SearchProductHelper searchProductHelper;

@override
State<_ProductTypeFilter> createState() => _ProductTypeFilterState();
}

class _ProductTypeFilterState extends State<_ProductTypeFilter> {
@override
Widget build(BuildContext context) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final List<ButtonSegment<ProductType>> segments =
<ButtonSegment<ProductType>>[];
for (final ProductType productType in ProductType.values) {
segments.add(
ButtonSegment<ProductType>(
value: productType,
label: Text(productType.getLabel(appLocalizations)),
),
);
}
return SegmentedButton<ProductType>(
segments: segments,
selected: <ProductType>{widget.searchProductHelper._productType},
onSelectionChanged: (Set<ProductType> newSelection) => setState(
() => widget.searchProductHelper._productType = newSelection.first,
),
);
}
}
Loading

0 comments on commit 077bf5e

Please sign in to comment.