Skip to content

Commit

Permalink
Merge branch 'develop' into flutter_316
Browse files Browse the repository at this point in the history
  • Loading branch information
monsieurtanuki authored Jan 8, 2024
2 parents c870899 + e0b3111 commit cf5c0fe
Show file tree
Hide file tree
Showing 26 changed files with 231 additions and 279 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class BackgroundTaskDownloadProducts extends BackgroundTaskProgressing {
if (downloadFlag & flagMaskExcludeKP != 0) {
fields.remove(ProductField.KNOWLEDGE_PANELS);
}
final OpenFoodFactsLanguage language = ProductQuery.getLanguage();
final SearchResult searchResult = await OpenFoodAPIClient.searchProducts(
getUser(),
ProductSearchQueryConfiguration(
Expand All @@ -121,7 +122,7 @@ class BackgroundTaskDownloadProducts extends BackgroundTaskProgressing {
const PageNumber(page: 1),
BarcodeParameter.list(barcodes),
],
language: ProductQuery.getLanguage(),
language: language,
country: ProductQuery.getCountry(),
version: ProductQuery.productQueryVersion,
),
Expand All @@ -134,7 +135,7 @@ class BackgroundTaskDownloadProducts extends BackgroundTaskProgressing {
final DaoProduct daoProduct = DaoProduct(localDatabase);
for (final Product product in downloadedProducts) {
if (await _shouldBeUpdated(daoProduct, product.barcode!)) {
await daoProduct.put(product);
await daoProduct.put(product, language);
}
}
final int deleted = await daoWorkBarcode.deleteBarcodes(work, barcodes);
Expand Down
63 changes: 57 additions & 6 deletions packages/smooth_app/lib/cards/category_cards/svg_safe_network.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,69 @@ class _SvgSafeNetworkState extends State<SvgSafeNetwork> {
late final Future<String> _loading = _load();

String get _url => widget.helper.url;

// TODO(monsieurtanuki): Change /dist/ url to be the first try when the majority of products have been updated
/// Loads the SVG file from url or from alternate url.
///
/// In Autumn 2023, the web image folders were moved to a /dist/ subfolder.
/// Before:
/// https://static.openfoodfacts.org/images/attributes/nova-group-3.svg
/// After:
/// https://static.openfoodfacts.org/images/attributes/dist/nova-group-3.svg
/// Products that haven't been refreshed still reference the previous web
/// folder. If we cannot find the URL, we try with the alternate /dist/ URL.
Future<String> _load() async {
const int statusOk = 200;
const int statusNotFound = 404;

final String? alternateUrl = _getAlternateUrl();

// is the url already cached?
String? cached = _networkCache[_url];
if (cached != null) {
return cached;
}
final http.Response response = await http.get(Uri.parse(_url));
if (response.statusCode != 200) {
throw Exception('Failed to load SVG: $_url ${response.statusCode}');
// is the alternate url already cached?
if (alternateUrl != null) {
cached = _networkCache[alternateUrl];
if (cached != null) {
return cached;
}
}

// try with the url
final http.Response response1 = await http.get(Uri.parse(_url));
if (response1.statusCode == statusOk) {
_networkCache[_url] = cached = response1.body;
return cached;
}
if (response1.statusCode == statusNotFound && alternateUrl != null) {
// try with the alternate url
final http.Response response2 = await http.get(Uri.parse(alternateUrl));
if (response2.statusCode == statusOk) {
_networkCache[alternateUrl] = cached = response2.body;
return cached;
}
}

throw Exception('Failed to load SVG: $_url ${response1.statusCode}');
}

/// Returns the alternate /dist/ url or null if irrelevant.
String? _getAlternateUrl() {
const String lastPathSegment = '/dist/';
if (_url.contains(lastPathSegment)) {
return null;
}
final int lastSlashPos = _url.lastIndexOf('/');
if (lastSlashPos == -1 ||
lastSlashPos == 0 ||
lastSlashPos == _url.length - 1) {
// very unlikely
return null;
}
_networkCache[_url] = cached = response.body;
return cached;
return '${_url.substring(0, lastSlashPos)}'
'$lastPathSegment'
'${_url.substring(lastSlashPos + 1)}';
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class OnboardingDataProduct extends AbstractOnboardingData<Product> {
OpenFoodAPIClient.getProductString(
ProductRefresher().getBarcodeQueryConfiguration(
AbstractOnboardingData.barcode,
ProductQuery.getLanguage(),
),
uriHelper: ProductQuery.uriProductHelper,
).timeout(SnackBarDuration.long);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ class QueryProductListSupplier extends ProductListSupplier {
productList.setAll(searchResult.products!);
productList.totalSize = searchResult.count ?? 0;
partialProductList.add(productList);
await DaoProduct(localDatabase).putAll(searchResult.products!);
await DaoProduct(localDatabase).putAll(
searchResult.products!,
productQuery.language,
);
}
await DaoProductList(localDatabase).put(productList);
return null;
Expand Down
47 changes: 1 addition & 46 deletions packages/smooth_app/lib/database/dao_hive_product.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'dart:convert';
import 'package:hive/hive.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:smooth_app/database/abstract_dao.dart';
import 'package:smooth_app/database/dao_product_migration.dart';
import 'package:smooth_app/database/local_database.dart';

/// Hive type adapter for [Product]
Expand All @@ -24,7 +23,7 @@ class _ProductAdapter extends TypeAdapter<Product> {
/// But Hive needs it - it doesn't like data to be removed...
/// Where we store the products as "barcode => product".
@Deprecated('use [DaoProduct] instead')
class DaoHiveProduct extends AbstractDao implements DaoProductMigrationSource {
class DaoHiveProduct extends AbstractDao {
@Deprecated('use [DaoProduct] instead')
DaoHiveProduct(final LocalDatabase localDatabase) : super(localDatabase);

Expand All @@ -35,48 +34,4 @@ class DaoHiveProduct extends AbstractDao implements DaoProductMigrationSource {

@override
void registerAdapter() => Hive.registerAdapter(_ProductAdapter());

LazyBox<Product> _getBox() => Hive.lazyBox<Product>(_hiveBoxName);

Future<Product?> get(final String barcode) async => _getBox().get(barcode);

@override
Future<Map<String, Product>> getAll(final List<String> barcodes) async {
final LazyBox<Product> box = _getBox();
final Map<String, Product> result = <String, Product>{};
for (final String barcode in barcodes) {
final Product? product = await box.get(barcode);
if (product != null) {
result[barcode] = product;
}
}
return result;
}

Future<void> put(final Product product) async => putAll(<Product>[product]);

Future<void> putAll(final Iterable<Product> products) async {
final Map<String, Product> upserts = <String, Product>{};
for (final Product product in products) {
upserts[product.barcode!] = product;
}
await _getBox().putAll(upserts);
}

@override
Future<List<String>> getAllKeys() async {
final LazyBox<Product> box = _getBox();
final List<String> result = <String>[];
for (final dynamic key in box.keys) {
result.add(key.toString());
}
return result;
}

// Just for the migration
@override
Future<void> deleteAll(final List<String> barcodes) async {
final LazyBox<Product> box = _getBox();
await box.deleteAll(barcodes);
}
}
36 changes: 27 additions & 9 deletions packages/smooth_app/lib/database/dao_product.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,24 @@ import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:smooth_app/database/abstract_sql_dao.dart';
import 'package:smooth_app/database/bulk_deletable.dart';
import 'package:smooth_app/database/bulk_manager.dart';
import 'package:smooth_app/database/dao_product_migration.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:sqflite/sqflite.dart';

class DaoProduct extends AbstractSqlDao
implements BulkDeletable, DaoProductMigrationDestination {
class DaoProduct extends AbstractSqlDao implements BulkDeletable {
DaoProduct(super.localDatabase);

static const String _TABLE_PRODUCT = 'gzipped_product';
static const String _TABLE_PRODUCT_COLUMN_BARCODE = 'barcode';
static const String _TABLE_PRODUCT_COLUMN_GZIPPED_JSON =
'encoded_gzipped_json';
static const String _TABLE_PRODUCT_COLUMN_LAST_UPDATE = 'last_update';
static const String _TABLE_PRODUCT_COLUMN_LANGUAGE = 'lc';

static const List<String> _columns = <String>[
_TABLE_PRODUCT_COLUMN_BARCODE,
_TABLE_PRODUCT_COLUMN_GZIPPED_JSON,
_TABLE_PRODUCT_COLUMN_LAST_UPDATE,
_TABLE_PRODUCT_COLUMN_LANGUAGE,
];

static FutureOr<void> onUpgrade(
Expand All @@ -41,6 +41,10 @@ class DaoProduct extends AbstractSqlDao
',$_TABLE_PRODUCT_COLUMN_LAST_UPDATE INT NOT NULL'
')');
}
if (oldVersion < 4) {
await db.execute('alter table $_TABLE_PRODUCT add column '
'$_TABLE_PRODUCT_COLUMN_LANGUAGE TEXT');
}
}

/// Returns the [Product] that matches the [barcode], or null.
Expand Down Expand Up @@ -87,17 +91,28 @@ class DaoProduct extends AbstractSqlDao
return result;
}

Future<void> put(final Product product) async => putAll(<Product>[product]);
Future<void> put(
final Product product,
final OpenFoodFactsLanguage language,
) async =>
putAll(
<Product>[product],
language,
);

/// Replaces products in database
@override
Future<void> putAll(final Iterable<Product> products) async =>
Future<void> putAll(
final Iterable<Product> products,
final OpenFoodFactsLanguage language,
) async =>
localDatabase.database.transaction(
(final Transaction transaction) async =>
_bulkReplaceLoop(transaction, products),
(final Transaction transaction) async => _bulkReplaceLoop(
transaction,
products,
language,
),
);

@override
Future<List<String>> getAllKeys() async {
final List<String> result = <String>[];
final List<Map<String, dynamic>> queryResults =
Expand Down Expand Up @@ -126,6 +141,7 @@ class DaoProduct extends AbstractSqlDao
Future<void> _bulkReplaceLoop(
final DatabaseExecutor databaseExecutor,
final Iterable<Product> products,
final OpenFoodFactsLanguage language,
) async {
final int lastUpdate = LocalDatabase.nowInMillis();
final BulkManager bulkManager = BulkManager();
Expand All @@ -138,6 +154,7 @@ class DaoProduct extends AbstractSqlDao
),
);
insertParameters.add(lastUpdate);
insertParameters.add(language.offTag);
}
await bulkManager.insert(
bulkInsertable: this,
Expand Down Expand Up @@ -223,6 +240,7 @@ class DaoProduct extends AbstractSqlDao
await localDatabase.database.rawQuery('''
select sum(length($_TABLE_PRODUCT_COLUMN_BARCODE)) +
sum(length($_TABLE_PRODUCT_COLUMN_LAST_UPDATE)) +
sum(length($_TABLE_PRODUCT_COLUMN_LANGUAGE)) +
sum(length($_TABLE_PRODUCT_COLUMN_GZIPPED_JSON))
from $_TABLE_PRODUCT
'''),
Expand Down
55 changes: 0 additions & 55 deletions packages/smooth_app/lib/database/dao_product_migration.dart

This file was deleted.

2 changes: 1 addition & 1 deletion packages/smooth_app/lib/database/local_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class LocalDatabase extends ChangeNotifier {
final String databasePath = join(databasesRootPath, 'smoothie.db');
final Database database = await openDatabase(
databasePath,
version: 3,
version: 4,
singleInstance: true,
onUpgrade: _onUpgrade,
);
Expand Down
27 changes: 19 additions & 8 deletions packages/smooth_app/lib/helpers/product_cards_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,26 @@ import 'package:smooth_app/generic_lib/widgets/smooth_card.dart';
import 'package:smooth_app/helpers/image_field_extension.dart';
import 'package:smooth_app/helpers/ui_helpers.dart';
import 'package:smooth_app/query/product_query.dart';
import 'package:smooth_app/widgets/smooth_app_bar.dart';

Widget buildProductTitle(
final Product product,
final AppLocalizations appLocalizations,
) =>
Text(
getProductNameAndBrands(product, appLocalizations),
overflow: TextOverflow.ellipsis,
maxLines: 1,
SmoothAppBar buildEditProductAppBar({
required final BuildContext context,
required final String title,
required final Product product,
}) =>
SmoothAppBar(
centerTitle: false,
title: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subTitle: Text(
getProductNameAndBrands(product, AppLocalizations.of(context)),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
ignoreSemanticsForSubtitle: true,
);

String getProductNameAndBrands(
Expand Down
Loading

0 comments on commit cf5c0fe

Please sign in to comment.