Skip to content

Commit

Permalink
feat: 4674 - immediate access to "other" pictures if possible (#4928)
Browse files Browse the repository at this point in the history
New file:
* `background_task_product_change.dart`: Interface for background tasks that change a product.

Impacted files:
* `background_task_crop.dart`: minor refactoring
* `background_task_details.dart`: minor refactoring, implementing new interface `BackgroundTaskProductChange`
* `background_task_image.dart`: minor refactoring
* `background_task_unselected.dart`: minor refactoring, implementing new interface `BackgroundTaskProductChange`
* `background_task_upload.dart`: minor refactoring, implementing new interface `BackgroundTaskProductChange`
* `product_cards_helper.dart`: new method `getRawProductImages`
* `product_image_gallery_other_view.dart`: now we may have directly the raw images, and if needed we refresh the product instead of fetching specific image ids
* `product_image_gallery_view.dart`: minor refactoring
* `product_image_other_page.dart`: replaced deprecated method
* `product_image_server_button.dart`: now we may have directly the raw images, and if needed we refresh the product instead of fetching specific image ids
* `product_image_viewer.dart`: replaced deprecated method
* `pubspec.lock`: generated
* `pubspec.yaml`: upgraded to off-dart 3.3.0
* `uploaded_image_gallery.dart`: now using `List<ProductImage>` as input
  • Loading branch information
monsieurtanuki committed Jan 25, 2024
1 parent 03b747c commit 89cea10
Show file tree
Hide file tree
Showing 15 changed files with 281 additions and 163 deletions.
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;
}

0 comments on commit 89cea10

Please sign in to comment.