diff --git a/lib/model/Insight.dart b/lib/model/Insight.dart index 113160bd35..9bef44e3c4 100644 --- a/lib/model/Insight.dart +++ b/lib/model/Insight.dart @@ -15,16 +15,27 @@ extension InsightAnnotationExtension on InsightAnnotation { } enum InsightType { + @JsonValue('ingredient_spellcheck') INGREDIENT_SPELLCHECK, + @JsonValue('packager_code') PACKAGER_CODE, + @JsonValue('label') LABEL, + @JsonValue('category') CATEGORY, + @JsonValue('product_weight') PRODUCT_WEIGHT, + @JsonValue('expiration_date') EXPIRATION_DATE, + @JsonValue('brand') BRAND, + @JsonValue('store') STORE, + @JsonValue('nutrient') NUTRIENT, - UNDEFINED + @JsonValue('undefined') + UNDEFINED, + UNKNOWN } extension InsightTypesExtension on InsightType? { diff --git a/lib/model/RobotoffQuestion.dart b/lib/model/RobotoffQuestion.dart index ff2e5ce81b..dad089a174 100644 --- a/lib/model/RobotoffQuestion.dart +++ b/lib/model/RobotoffQuestion.dart @@ -7,11 +7,7 @@ part 'RobotoffQuestion.g.dart'; @JsonSerializable() class RobotoffQuestionResult extends JsonObject { final String? status; - @JsonKey( - name: 'questions', - includeIfNull: false, - fromJson: RobotoffQuestion.fromJson, - toJson: RobotoffQuestion.toJson) + final List? questions; const RobotoffQuestionResult({this.status, this.questions}); @@ -23,14 +19,15 @@ class RobotoffQuestionResult extends JsonObject { Map toJson() => _$RobotoffQuestionResultToJson(this); } -class RobotoffQuestion { +@JsonSerializable() +class RobotoffQuestion extends JsonObject { final String? barcode; final String? type; final String? value; final String? question; @JsonKey(name: 'insight_id') final String? insightId; - @JsonKey(name: 'insight_type') + @JsonKey(name: 'insight_type', unknownEnumValue: InsightType.UNKNOWN) final InsightType? insightType; @JsonKey(name: 'source_image_url') final String? imageUrl; @@ -44,44 +41,8 @@ class RobotoffQuestion { this.insightType, this.imageUrl}); - static List fromJson(List json) { - List result = []; - for (Map jsonQuestion - in json as Iterable>) { - InsightType insightType = - InsightTypesExtension.getType(jsonQuestion['insight_type']); - - result.add(RobotoffQuestion( - barcode: jsonQuestion['barcode'], - type: jsonQuestion['type'], - value: jsonQuestion['value'], - question: jsonQuestion['question'], - insightId: jsonQuestion['insight_id'], - insightType: insightType, - imageUrl: jsonQuestion['source_image_url'])); - } - return result; - } - - static List> toJson(List? questions) { - if (questions == null) { - return []; - } - List> result = []; - - for (RobotoffQuestion question in questions) { - Map jsonQuestion = {}; - - jsonQuestion['barcode'] = question.barcode; - jsonQuestion['type'] = question.type; - jsonQuestion['value'] = question.value; - jsonQuestion['question'] = question.question; - jsonQuestion['insight_id'] = question.insightId; - jsonQuestion['insight_type'] = question.insightType.value; - jsonQuestion['insight_url'] = question.imageUrl; + factory RobotoffQuestion.fromJson(Map json) => + _$RobotoffQuestionFromJson(json); - result.add(jsonQuestion); - } - return result; - } + Map toJson() => _$RobotoffQuestionToJson(this); } diff --git a/lib/model/RobotoffQuestion.g.dart b/lib/model/RobotoffQuestion.g.dart index 9c3d497ccc..8ae4ce5b08 100644 --- a/lib/model/RobotoffQuestion.g.dart +++ b/lib/model/RobotoffQuestion.g.dart @@ -10,21 +10,89 @@ RobotoffQuestionResult _$RobotoffQuestionResultFromJson( Map json) => RobotoffQuestionResult( status: json['status'] as String?, - questions: RobotoffQuestion.fromJson(json['questions'] as List), + questions: (json['questions'] as List?) + ?.map((e) => RobotoffQuestion.fromJson(e as Map)) + .toList(), ); Map _$RobotoffQuestionResultToJson( - RobotoffQuestionResult instance) { - final val = { - 'status': instance.status, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } + RobotoffQuestionResult instance) => + { + 'status': instance.status, + 'questions': instance.questions, + }; + +RobotoffQuestion _$RobotoffQuestionFromJson(Map json) => + RobotoffQuestion( + barcode: json['barcode'] as String?, + type: json['type'] as String?, + value: json['value'] as String?, + question: json['question'] as String?, + insightId: json['insight_id'] as String?, + insightType: _$enumDecodeNullable( + _$InsightTypeEnumMap, json['insight_type'], + unknownValue: InsightType.UNKNOWN), + imageUrl: json['source_image_url'] as String?, + ); + +Map _$RobotoffQuestionToJson(RobotoffQuestion instance) => + { + 'barcode': instance.barcode, + 'type': instance.type, + 'value': instance.value, + 'question': instance.question, + 'insight_id': instance.insightId, + 'insight_type': _$InsightTypeEnumMap[instance.insightType], + 'source_image_url': instance.imageUrl, + }; + +K _$enumDecode( + Map enumValues, + Object? source, { + K? unknownValue, +}) { + if (source == null) { + throw ArgumentError( + 'A value must be provided. Supported values: ' + '${enumValues.values.join(', ')}', + ); } - writeNotNull('questions', RobotoffQuestion.toJson(instance.questions)); - return val; + return enumValues.entries.singleWhere( + (e) => e.value == source, + orElse: () { + if (unknownValue == null) { + throw ArgumentError( + '`$source` is not one of the supported values: ' + '${enumValues.values.join(', ')}', + ); + } + return MapEntry(unknownValue, enumValues.values.first); + }, + ).key; } + +K? _$enumDecodeNullable( + Map enumValues, + dynamic source, { + K? unknownValue, +}) { + if (source == null) { + return null; + } + return _$enumDecode(enumValues, source, unknownValue: unknownValue); +} + +const _$InsightTypeEnumMap = { + InsightType.INGREDIENT_SPELLCHECK: 'ingredient_spellcheck', + InsightType.PACKAGER_CODE: 'packager_code', + InsightType.LABEL: 'label', + InsightType.CATEGORY: 'category', + InsightType.PRODUCT_WEIGHT: 'product_weight', + InsightType.EXPIRATION_DATE: 'expiration_date', + InsightType.BRAND: 'brand', + InsightType.STORE: 'store', + InsightType.NUTRIENT: 'nutrient', + InsightType.UNDEFINED: 'undefined', + InsightType.UNKNOWN: 'UNKNOWN', +}; diff --git a/lib/openfoodfacts.dart b/lib/openfoodfacts.dart index ca917ef514..fe57bd72ea 100644 --- a/lib/openfoodfacts.dart +++ b/lib/openfoodfacts.dart @@ -444,8 +444,8 @@ class OpenFoodAPIClient { /// By default the query will hit the PROD DB static Future getRobotoffQuestionsForProduct( String barcode, - String lang, - User user, { + String lang, { + User? user, int? count, QueryType? queryType, }) async { diff --git a/test/api_getRobotoff_test.dart b/test/api_getRobotoff_test.dart index f564feed6f..38e075b504 100644 --- a/test/api_getRobotoff_test.dart +++ b/test/api_getRobotoff_test.dart @@ -15,7 +15,7 @@ void main() { await OpenFoodAPIClient.getRobotoffQuestionsForProduct( '3274570800026', 'en', - TestConstants.TEST_USER, + user: TestConstants.TEST_USER, count: 1, ); @@ -41,7 +41,7 @@ void main() { await OpenFoodAPIClient.getRobotoffQuestionsForProduct( '3274570800026', 'fr', - TestConstants.TEST_USER, + user: TestConstants.TEST_USER, ); if (result.status != 'no_questions') { diff --git a/test/api_postRobotoff_test.dart b/test/api_postRobotoff_test.dart index 8ab6c25922..7f556e0caa 100644 --- a/test/api_postRobotoff_test.dart +++ b/test/api_postRobotoff_test.dart @@ -11,8 +11,8 @@ void main() { test('get questions for Noix de Saint-Jacques EN and answer', () async { RobotoffQuestionResult result = await OpenFoodAPIClient.getRobotoffQuestionsForProduct( - '0080868000633', 'en', TestConstants.TEST_USER, - count: 1); + '0080868000633', 'en', + user: TestConstants.TEST_USER, count: 1); if (result.status == 'found') { Status postResult = await OpenFoodAPIClient.postInsightAnnotation(