Product.fromJson constructor

Product.fromJson(
  1. Map<String, dynamic> json
)

Implementation

factory Product.fromJson(Map<String, dynamic> json) {
  final Product result = _$ProductFromJson(json);

  void setLanguageString(
    final ProductField productField,
    final OpenFoodFactsLanguage language,
    final String label,
  ) {
    switch (productField) {
      case ProductField.NAME_IN_LANGUAGES:
      case ProductField.NAME_ALL_LANGUAGES:
        result.productNameInLanguages ??= {};
        result.productNameInLanguages![language] = label;
        break;
      case ProductField.GENERIC_NAME_IN_LANGUAGES:
      case ProductField.GENERIC_NAME_ALL_LANGUAGES:
        result.genericNameInLanguages ??= {};
        result.genericNameInLanguages![language] = label;
        break;
      case ProductField.ABBREVIATED_NAME_IN_LANGUAGES:
      case ProductField.ABBREVIATED_NAME_ALL_LANGUAGES:
        result.abbreviatedNameInLanguages ??= {};
        result.abbreviatedNameInLanguages![language] = label;
        break;
      case ProductField.INGREDIENTS_TEXT_IN_LANGUAGES:
      case ProductField.INGREDIENTS_TEXT_ALL_LANGUAGES:
        result.ingredientsTextInLanguages ??= {};
        result.ingredientsTextInLanguages![language] = label;
        break;
      case ProductField.PACKAGING_TEXT_IN_LANGUAGES:
      case ProductField.PACKAGING_TEXT_ALL_LANGUAGES:
        result.packagingTextInLanguages ??= {};
        result.packagingTextInLanguages![language] = label;
        break;
      default:
        // not supposed to be called with other ProductField values.
        assert(false);
    }
  }

  void setLanguageListString(
    final ProductField productField,
    final OpenFoodFactsLanguage language,
    final Map<String, dynamic> json,
    final String key,
  ) {
    final List<String>? labels = _jsonValueToList(json[key]);
    if (labels == null) {
      return;
    }
    switch (productField) {
      case ProductField.CATEGORIES_TAGS_IN_LANGUAGES:
        result.categoriesTagsInLanguages ??= {};
        result.categoriesTagsInLanguages![language] = labels;
        break;
      case ProductField.TRACES_TAGS_IN_LANGUAGES:
        result.tracesTagsInLanguages ??= {};
        result.tracesTagsInLanguages![language] = labels;
        break;
      case ProductField.BRANDS_TAGS_IN_LANGUAGES:
        result.brandsTagsInLanguages ??= {};
        result.brandsTagsInLanguages![language] = labels;
        break;
      case ProductField.STATES_TAGS_IN_LANGUAGES:
        result.statesTagsInLanguages ??= {};
        result.statesTagsInLanguages![language] = labels;
        break;
      case ProductField.STORES_TAGS_IN_LANGUAGES:
        result.storesTagsInLanguages ??= {};
        result.storesTagsInLanguages![language] = labels;
        break;
      case ProductField.MISC_TAGS_IN_LANGUAGES:
        result.miscTagsInLanguages ??= {};
        result.miscTagsInLanguages![language] = labels;
        break;
      case ProductField.INGREDIENTS_ANALYSIS_TAGS_IN_LANGUAGES:
        result.ingredientsAnalysisTagsInLanguages ??= {};
        result.ingredientsAnalysisTagsInLanguages![language] = labels;
        break;
      case ProductField.INGREDIENTS_TAGS_IN_LANGUAGES:
        result.ingredientsTagsInLanguages ??= {};
        result.ingredientsTagsInLanguages![language] = labels;
        break;
      case ProductField.LABELS_TAGS_IN_LANGUAGES:
        result.labelsTagsInLanguages ??= {};
        result.labelsTagsInLanguages![language] = labels;
        break;
      case ProductField.COUNTRIES_TAGS_IN_LANGUAGES:
        result.countriesTagsInLanguages ??= {};
        result.countriesTagsInLanguages![language] = labels;
        break;
      default:
        // not supposed to be called with other ProductField values.
        assert(false);
    }
  }

  void addInLanguagesData(
    final ProductField productField,
    final OpenFoodFactsLanguage language,
    final Map<String, dynamic> json,
    final String key,
  ) {
    switch (productField) {
      case ProductField.NAME_IN_LANGUAGES:
      case ProductField.GENERIC_NAME_IN_LANGUAGES:
      case ProductField.ABBREVIATED_NAME_IN_LANGUAGES:
      case ProductField.INGREDIENTS_TEXT_IN_LANGUAGES:
      case ProductField.PACKAGING_TEXT_IN_LANGUAGES:
        setLanguageString(productField, language, json[key]);
        return;
      case ProductField.CATEGORIES_TAGS_IN_LANGUAGES:
      case ProductField.TRACES_TAGS_IN_LANGUAGES:
      case ProductField.BRANDS_TAGS_IN_LANGUAGES:
      case ProductField.STATES_TAGS_IN_LANGUAGES:
      case ProductField.STORES_TAGS_IN_LANGUAGES:
      case ProductField.MISC_TAGS_IN_LANGUAGES:
      case ProductField.INGREDIENTS_ANALYSIS_TAGS_IN_LANGUAGES:
      case ProductField.INGREDIENTS_TAGS_IN_LANGUAGES:
      case ProductField.LABELS_TAGS_IN_LANGUAGES:
      case ProductField.COUNTRIES_TAGS_IN_LANGUAGES:
        setLanguageListString(productField, language, json, key);
        return;
      case ProductField.IMAGES_FRESHNESS_IN_LANGUAGES:
        final Map<ImageField, int> values =
            _jsonValueToImagesFreshness(json[key], language);
        result.imagesFreshnessInLanguages ??= {};
        result.imagesFreshnessInLanguages![language] = values;
        return;
      default:
        if (fieldsInLanguages.contains(productField)) {
          throw Exception('Unhandled in-languages case for $productField');
        }
    }
  }

  ProductField? extractProductField(
    final String key,
    final Iterable<ProductField> iterable,
  ) {
    for (final ProductField productField in iterable) {
      if (key.startsWith(productField.offTag)) {
        return productField;
      }
    }
    return null;
  }

  for (final String key in json.keys) {
    if (key.contains('debug')) {
      continue;
    }
    // If the JSON contained *_in_languages fields,
    // _$ProductFromJson(json) already decoded them
    if (key.endsWith('_in_languages')) {
      continue;
    }
    // The OFF API can give values in all available languages for some
    // of the fields ('product_name_languages'), and in a requested list of
    // languages for an additional number of fields
    // (`product_name_[2 letter language code]`).
    // We store those values in a more structured maps like
    // [productNameInLanguages].

    ProductField? productField = extractProductField(key, fieldsAllLanguages);
    if (productField != null) {
      final Map<OpenFoodFactsLanguage, String>? localized =
          _getLocalizedStrings(json[key]);
      if (localized != null) {
        for (final MapEntry<OpenFoodFactsLanguage, String> entry
            in localized.entries) {
          setLanguageString(productField, entry.key, entry.value);
        }
      }
      continue;
    }

    productField = extractProductField(key, fieldsInLanguages);
    if (productField != null) {
      final OpenFoodFactsLanguage language =
          _langFrom(key, productField.offTag);
      if (language != OpenFoodFactsLanguage.UNDEFINED) {
        addInLanguagesData(productField, language, json, key);
      }
      continue;
    }
  }
  return result;
}