Files
smooth-app/packages/smooth_app/lib/background/background_task_language_refresh.dart
Edouard Marquez e3bc40fdf3 chore: Migration to Dart 3.8 (#6668)
* Migration to Dart 3.8

* New GA

* Fix dartdoc
2025-06-23 18:14:17 +02:00

174 lines
5.6 KiB
Dart

import 'package:flutter/painting.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:smooth_app/background/background_task.dart';
import 'package:smooth_app/background/background_task_queue.dart';
import 'package:smooth_app/background/operation_type.dart';
import 'package:smooth_app/database/dao_product.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/l10n/app_localizations.dart';
import 'package:smooth_app/query/product_query.dart';
import 'package:smooth_app/query/search_products_manager.dart';
/// Background task about downloading products to translate.
class BackgroundTaskLanguageRefresh extends BackgroundTask {
BackgroundTaskLanguageRefresh._({
required super.processName,
required super.uniqueId,
required super.stamp,
required this.excludeBarcodes,
required this.productType,
});
BackgroundTaskLanguageRefresh.fromJson(super.json)
: excludeBarcodes = _getStringList(json, _jsonTagExcludeBarcodes),
productType =
ProductType.fromOffTag(json[_jsonTagProductType] as String?) ??
// for legacy reason (not refreshed products = no product type)
ProductType.food,
super.fromJson();
static List<String> _getStringList(
final Map<String, dynamic> json,
final String tag,
) {
final List<dynamic> dynamicList =
json[_jsonTagExcludeBarcodes] as List<dynamic>;
final List<String> result = <String>[];
for (final dynamic item in dynamicList) {
result.add(item.toString());
}
return result;
}
final List<String> excludeBarcodes;
final ProductType productType;
static const String _jsonTagExcludeBarcodes = 'excludeBarcodes';
static const String _jsonTagProductType = 'productType';
@override
Map<String, dynamic> toJson() {
final Map<String, dynamic> result = super.toJson();
result[_jsonTagExcludeBarcodes] = excludeBarcodes;
result[_jsonTagProductType] = productType.offTag;
return result;
}
static const OperationType _operationType = OperationType.languageRefresh;
UriProductHelper get _uriProductHelper =>
ProductQuery.getUriProductHelper(productType: productType);
static Future<void> addTask(final LocalDatabase localDatabase) async {
for (final ProductType productType in ProductType.values) {
await _addTask(
localDatabase,
excludeBarcodes: <String>[],
productType: productType,
);
}
}
static Future<void> _addTask(
final LocalDatabase localDatabase, {
required final List<String> excludeBarcodes,
required final ProductType productType,
}) async {
final String uniqueId = await _operationType.getNewKey(
localDatabase,
productType: productType,
);
final BackgroundTask task = _getNewTask(
uniqueId,
excludeBarcodes,
productType,
);
await task.addToManager(localDatabase, queue: BackgroundTaskQueue.longHaul);
}
@override
(String, AlignmentGeometry)? getFloatingMessage(
final AppLocalizations appLocalizations,
) => null;
static BackgroundTask _getNewTask(
final String uniqueId,
final List<String> excludeBarcodes,
final ProductType productType,
) => BackgroundTaskLanguageRefresh._(
processName: _operationType.processName,
uniqueId: uniqueId,
stamp: ';languageRefresh;${productType.offTag}',
excludeBarcodes: excludeBarcodes,
productType: productType,
);
@override
Future<void> preExecute(final LocalDatabase localDatabase) async {}
@override
bool get hasImmediateNextTask => true;
/// Number of products to download each time.
static const int _pageSize = 20;
@override
Future<void> execute(final LocalDatabase localDatabase) async {
final DaoProduct daoProduct = DaoProduct(localDatabase);
final OpenFoodFactsLanguage language = ProductQuery.getLanguage();
final List<String> barcodes = await daoProduct.getTopProductsToTranslate(
language,
limit: _pageSize,
excludeBarcodes: excludeBarcodes,
productType: productType,
);
if (barcodes.isEmpty) {
return;
}
final SearchResult searchResult =
await SearchProductsManager.searchProducts(
getUser(),
ProductSearchQueryConfiguration(
fields: ProductQuery.fields,
parametersList: <Parameter>[
const PageSize(size: _pageSize),
const PageNumber(page: 1),
BarcodeParameter.list(barcodes),
],
language: language,
country: ProductQuery.getCountry(),
version: ProductQuery.productQueryVersion,
),
uriHelper: _uriProductHelper,
type: SearchProductsType.background,
);
if (searchResult.products == null || searchResult.count == null) {
throw Exception('Cannot refresh language');
}
// save into database and refresh all visible products.
await daoProduct.putAll(
searchResult.products!,
language,
productType: productType,
);
localDatabase.upToDate.setLatestDownloadedProducts(searchResult.products!);
// Next page
final List<String> newExcludeBarcodes = <String>[];
// we keep the old "excluded" barcodes,...
newExcludeBarcodes.addAll(excludeBarcodes);
// ...add the new barcodes...
newExcludeBarcodes.addAll(barcodes);
// ...and remove barcodes we actually found on the server.
for (final Product product in searchResult.products!) {
newExcludeBarcodes.remove(product.barcode);
}
await _addTask(
localDatabase,
excludeBarcodes: newExcludeBarcodes,
productType: productType,
);
}
}