Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 4674 - immediate access to "other" pictures if possible #4928

Merged
merged 6 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 4 additions & 15 deletions packages/smooth_app/lib/background/background_task_crop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,22 +125,11 @@ class BackgroundTaskCrop extends BackgroundTaskUpload {
),
);

@override
Future<void> preExecute(final LocalDatabase localDatabase) async {
await localDatabase.upToDate.addChange(
uniqueId,
Product(
barcode: barcode,
images: <ProductImage>[_getProductImage()],
),
);
await putTransientImage(localDatabase);
}

/// Returns the actual crop parameters.
///
/// cf. [UpToDateChanges._overwrite] regarding `images` field.
ProductImage _getProductImage() => ProductImage(
@override
ProductImage getProductImageChange() => ProductImage(
field: ImageField.fromOffTag(imageField)!,
language: getLanguage(),
size: ImageSize.ORIGINAL,
Expand Down Expand Up @@ -176,10 +165,10 @@ class BackgroundTaskCrop extends BackgroundTaskUpload {
/// Uploads the product image.
@override
Future<void> upload() async {
final ProductImage productImage = _getProductImage();
final ProductImage productImage = getProductImageChange();
final String? imageUrl = await OpenFoodAPIClient.setProductImageCrop(
barcode: barcode,
imageField: productImage.field,
imageField: productImage.field!,
language: getLanguage(),
imgid: productImage.imgid!,
angle: productImage.angle!,
Expand Down
11 changes: 7 additions & 4 deletions packages/smooth_app/lib/background/background_task_details.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/background/background_task_barcode.dart';
import 'package:smooth_app/background/background_task_product_change.dart';
import 'package:smooth_app/background/operation_type.dart';
import 'package:smooth_app/database/local_database.dart';

Expand All @@ -31,7 +32,8 @@ enum BackgroundTaskDetailsStamp {
}

/// Background task that changes product details (data, but no image upload).
class BackgroundTaskDetails extends BackgroundTaskBarcode {
class BackgroundTaskDetails extends BackgroundTaskBarcode
implements BackgroundTaskProductChange {
BackgroundTaskDetails._({
required super.processName,
required super.uniqueId,
Expand Down Expand Up @@ -60,7 +62,7 @@ class BackgroundTaskDetails extends BackgroundTaskBarcode {

@override
Future<void> preExecute(final LocalDatabase localDatabase) async =>
localDatabase.upToDate.addChange(uniqueId, _getProduct());
localDatabase.upToDate.addChange(uniqueId, getProductChange());

/// Adds the background task about changing a product.
static Future<void> addTask(
Expand Down Expand Up @@ -114,7 +116,8 @@ class BackgroundTaskDetails extends BackgroundTaskBarcode {
static String getStamp(final String barcode, final String stamp) =>
'$barcode;detail;$stamp';

Product _getProduct() {
@override
Product getProductChange() {
final Product result =
Product.fromJson(json.decode(inputMap) as Map<String, dynamic>);
// for good multilingual management
Expand All @@ -127,7 +130,7 @@ class BackgroundTaskDetails extends BackgroundTaskBarcode {
/// Uploads the product changes.
@override
Future<void> upload() async {
final Product product = _getProduct();
final Product product = getProductChange();
if (product.packagings != null || product.packagingsComplete != null) {
// For the moment, some fields can only be saved in V3,
// and V3 can only save those fields.
Expand Down
15 changes: 2 additions & 13 deletions packages/smooth_app/lib/background/background_task_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,25 +141,14 @@ class BackgroundTaskImage extends BackgroundTaskUpload {
static bool isOtherStamp(final String stamp) =>
stamp.contains(';image;${ImageField.OTHER.offTag};');

@override
Future<void> preExecute(final LocalDatabase localDatabase) async {
await localDatabase.upToDate.addChange(
uniqueId,
Product(
barcode: barcode,
images: <ProductImage>[_getProductImage()],
),
);
await putTransientImage(localDatabase);
}

/// Returns a fake value that means: "remove the previous value when merging".
///
/// If we use this task, it means that we took a brand new picture. Therefore,
/// all previous crop parameters are attached to a different imageid, and
/// to avoid confusion we need to clear them.
/// cf. [UpToDateChanges._overwrite] regarding `images` field.
ProductImage _getProductImage() => ProductImage(
@override
ProductImage getProductImageChange() => ProductImage(
field: ImageField.fromOffTag(imageField)!,
language: getLanguage(),
size: ImageSize.ORIGINAL,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:openfoodfacts/openfoodfacts.dart';

/// Interface for background tasks that change a product.
abstract class BackgroundTaskProductChange {
/// Product change, as a minimal Product.
Product getProductChange();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/background/background_task_barcode.dart';
import 'package:smooth_app/background/background_task_product_change.dart';
import 'package:smooth_app/background/background_task_refresh_later.dart';
import 'package:smooth_app/background/background_task_upload.dart';
import 'package:smooth_app/background/operation_type.dart';
Expand All @@ -11,7 +12,8 @@ import 'package:smooth_app/database/transient_file.dart';
import 'package:smooth_app/helpers/image_field_extension.dart';

/// Background task about unselecting a product image.
class BackgroundTaskUnselect extends BackgroundTaskBarcode {
class BackgroundTaskUnselect extends BackgroundTaskBarcode
implements BackgroundTaskProductChange {
BackgroundTaskUnselect._({
required super.processName,
required super.uniqueId,
Expand Down Expand Up @@ -91,7 +93,7 @@ class BackgroundTaskUnselect extends BackgroundTaskBarcode {

@override
Future<void> preExecute(final LocalDatabase localDatabase) async {
localDatabase.upToDate.addChange(uniqueId, _getUnselectedProduct());
localDatabase.upToDate.addChange(uniqueId, getProductChange());
_getTransientFile().removeImage(localDatabase);
}

Expand Down Expand Up @@ -132,7 +134,8 @@ class BackgroundTaskUnselect extends BackgroundTaskBarcode {
/// * "I don't change this value"
/// * "I change the value to null"
/// Here we put an empty string instead, to be understood as "force to null!".
Product _getUnselectedProduct() {
@override
Product getProductChange() {
final Product result = Product(barcode: barcode);
ImageField.fromOffTag(imageField)!.setUrl(result, '');
return result;
Expand Down
24 changes: 23 additions & 1 deletion packages/smooth_app/lib/background/background_task_upload.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import 'package:flutter/material.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:path_provider/path_provider.dart';
import 'package:smooth_app/background/background_task_barcode.dart';
import 'package:smooth_app/background/background_task_product_change.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/database/transient_file.dart';

/// Abstract background task about generic file upload.
abstract class BackgroundTaskUpload extends BackgroundTaskBarcode {
abstract class BackgroundTaskUpload extends BackgroundTaskBarcode
implements BackgroundTaskProductChange {
BackgroundTaskUpload({
required super.processName,
required super.uniqueId,
Expand Down Expand Up @@ -117,4 +119,24 @@ abstract class BackgroundTaskUpload extends BackgroundTaskBarcode {
}
return File(path);
}

@override
Future<void> preExecute(final LocalDatabase localDatabase) async {
await localDatabase.upToDate.addChange(
uniqueId,
getProductChange(),
);
await putTransientImage(localDatabase);
}

@override
Product getProductChange() => Product(
barcode: barcode,
images: <ProductImage>[getProductImageChange()],
);

/// Changed [ProductImage] for this product change.
///
/// cf. [UpToDateChanges._overwrite] regarding `images` field.
ProductImage getProductImageChange();
}
45 changes: 43 additions & 2 deletions packages/smooth_app/lib/helpers/product_cards_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,8 @@ ProductImageData getProductImageData(
// we found a localized version for this image
return ProductImageData(
imageField: imageField,
imageUrl: ImageHelper.getLocalizedProductImageUrl(
imageUrl: productImage.getUrl(
product.barcode!,
productImage,
imageSize: ImageSize.DISPLAY,
),
language: language,
Expand Down Expand Up @@ -323,3 +322,45 @@ Iterable<OpenFoodFactsLanguage> getProductImageLanguages(
}
return result;
}

/// Returns an id-sorted list of raw images matching the imageSize if possible.
List<ProductImage> getRawProductImages(
final Product product,
final ImageSize imageSize,
) {
final List<ProductImage> result = <ProductImage>[];
final List<ProductImage>? rawImages = product.getRawImages();
if (rawImages == null) {
return result;
}
final Map<int, ProductImage> map = <int, ProductImage>{};
for (final ProductImage productImage in rawImages) {
final int? imageId = int.tryParse(productImage.imgid!);
if (imageId == null) {
// highly unlikely
continue;
}
final ProductImage? previous = map[imageId];
if (previous == null) {
map[imageId] = productImage;
continue;
}
final ImageSize? currentImageSize = productImage.size;
if (currentImageSize == null) {
// highly unlikely
continue;
}
final ImageSize? previousImageSize = previous.size;
if (previousImageSize == imageSize) {
// we already have the best
continue;
}
map[imageId] = productImage;
}
final List<int> sortedIds = List<int>.of(map.keys);
sortedIds.sort();
for (final int id in sortedIds) {
result.add(map[id]!);
}
return result;
}
Loading