From 650d357cfe89459d67c8fb9b669eeb090bf7e7e0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 20:24:40 +0100 Subject: [PATCH 1/5] Update assets (#5800) Co-authored-by: M123-dev --- .../onboarding/sample_product_data.json | 944 ++++-------------- 1 file changed, 202 insertions(+), 742 deletions(-) diff --git a/packages/smooth_app/assets/onboarding/sample_product_data.json b/packages/smooth_app/assets/onboarding/sample_product_data.json index 96286db761e6..401257f90dff 100644 --- a/packages/smooth_app/assets/onboarding/sample_product_data.json +++ b/packages/smooth_app/assets/onboarding/sample_product_data.json @@ -247,8 +247,6 @@ { "attributes" : [ { - "description" : "", - "description_short" : "Processed foods", "grade" : "b", "icon_url" : "https://static.openfoodfacts.org/images/attributes/dist/nova-group-3.svg", "id" : "nova", @@ -256,7 +254,7 @@ "name" : "NOVA group", "panel_id" : "nova", "status" : "known", - "title" : "NOVA 3" + "title" : "Processed foods" }, { "grade" : "a", @@ -276,15 +274,15 @@ "attributes" : [ { "description" : "", - "description_short" : "Very low environmental impact", - "grade" : "a", - "icon_url" : "https://static.openfoodfacts.org/images/attributes/dist/ecoscore-a-plus.svg", + "description_short" : "Unknown environmental impact", + "grade" : "unknown", + "icon_url" : "https://static.openfoodfacts.org/images/attributes/dist/green-score-unknown.svg", "id" : "ecoscore", - "match" : 100, - "name" : "Eco-Score", - "panel_id" : "ecoscore", - "status" : "known", - "title" : "Eco-Score A+" + "match" : 0, + "name" : "Green-Score", + "panel_id" : "environmental_score", + "status" : "unknown", + "title" : "Green-Score not computed" }, { "description" : "", @@ -332,12 +330,7 @@ ], "brands" : "Open Food Facts", "categories_tags_fr" : [ - "Aliments et boissons à base de végétaux", - "Aliments d'origine végétale", - "Aliments à base de fruits et de légumes", - "Plats préparés", - "Soupes", - "Soupes de légumes" + "en:tinned-potatoes" ], "code" : "093270067481501", "ecoscore_data" : { @@ -562,15 +555,15 @@ "non_recyclable_and_non_biodegradable_materials" : 0, "packagings" : [ { - "ecoscore_material_score" : 81, - "ecoscore_shape_ratio" : 1, + "environmental_score_material_score" : 81, + "environmental_score_shape_ratio" : 1, "material" : "en:glass", "recycling" : "en:recycle", "shape" : "en:bottle" }, { - "ecoscore_material_score" : 76, - "ecoscore_shape_ratio" : 0.1, + "environmental_score_material_score" : 76, + "environmental_score_shape_ratio" : 0.1, "material" : "en:steel", "recycling" : "en:recycle", "shape" : "en:bottle-cap" @@ -588,719 +581,61 @@ "threatened_species" : {} }, "agribalyse" : { - "agribalyse_proxy_food_code" : "25903", - "co2_agriculture" : 0.10371296, - "co2_consumption" : 0.011022624, - "co2_distribution" : 0.01567597, - "co2_packaging" : 0.09985047, - "co2_processing" : 0.14982524, - "co2_total" : 0.510081444, - "co2_transportation" : 0.12999418, - "code" : "25903", - "dqr" : "2.42", - "ef_agriculture" : 0.023583571, - "ef_consumption" : 0.0040337776, - "ef_distribution" : 0.0044793367, - "ef_packaging" : 0.0099157882, - "ef_processing" : 0.029435401, - "ef_total" : 0.0817923135, - "ef_transportation" : 0.010344439, - "is_beverage" : 0, - "name_en" : "Soup, mixed vegetables, prepacked, to be reheated", - "name_fr" : "Soupe aux légumes variés, préemballée à réchauffer", - "score" : 98, - "version" : "3.1.1" + "warning" : "missing_agribalyse_match" }, - "grade" : "a-plus", - "grades" : { - "ad" : "a-plus", - "al" : "a-plus", - "at" : "a-plus", - "ax" : "a-plus", - "ba" : "a-plus", - "be" : "a-plus", - "bg" : "a-plus", - "ch" : "a-plus", - "cy" : "a-plus", - "cz" : "a-plus", - "de" : "a-plus", - "dk" : "a-plus", - "dz" : "a-plus", - "ee" : "a-plus", - "eg" : "a-plus", - "es" : "a-plus", - "fi" : "a-plus", - "fo" : "a-plus", - "fr" : "a-plus", - "gg" : "a-plus", - "gi" : "a-plus", - "gr" : "a-plus", - "hr" : "a-plus", - "hu" : "a-plus", - "ie" : "a-plus", - "il" : "a-plus", - "im" : "a-plus", - "is" : "a-plus", - "it" : "a-plus", - "je" : "a-plus", - "lb" : "a-plus", - "li" : "a-plus", - "lt" : "a-plus", - "lu" : "a-plus", - "lv" : "a-plus", - "ly" : "a-plus", - "ma" : "a-plus", - "mc" : "a-plus", - "md" : "a-plus", - "me" : "a-plus", - "mk" : "a-plus", - "mt" : "a-plus", - "nl" : "a-plus", - "no" : "a-plus", - "pl" : "a-plus", - "ps" : "a-plus", - "pt" : "a-plus", - "ro" : "a-plus", - "rs" : "a-plus", - "se" : "a-plus", - "si" : "a-plus", - "sj" : "a-plus", - "sk" : "a-plus", - "sm" : "a-plus", - "sy" : "a-plus", - "tn" : "a-plus", - "tr" : "a-plus", - "ua" : "a-plus", - "uk" : "a-plus", - "us" : "a-plus", - "va" : "a-plus", - "world" : "a-plus", - "xk" : "a-plus" + "missing" : { + "agb_category" : 1 }, + "missing_agribalyse_match_warning" : 1, "previous_data" : { "agribalyse" : { - "agribalyse_proxy_food_code" : "25903", - "co2_agriculture" : 0.099163319, - "co2_consumption" : 0.0079267752, - "co2_distribution" : 0.025340163, - "co2_packaging" : 0.098786634, - "co2_processing" : 0.13521664, - "co2_total" : 0.49805172, - "co2_transportation" : 0.1316182, - "code" : "25903", - "dqr" : "2.42", - "ef_agriculture" : 0.023834065, - "ef_consumption" : 0.004012423, - "ef_distribution" : 0.0095369029, - "ef_packaging" : 0.014974093, - "ef_processing" : 0.030870892, - "ef_total" : 0.093465939, - "ef_transportation" : 0.010237564, + "agribalyse_food_code" : "36016", + "co2_agriculture" : 4.1407915, + "co2_consumption" : 0.0066736979, + "co2_distribution" : 0.037353873, + "co2_packaging" : 0.27530877, + "co2_processing" : 0.82298078, + "co2_total" : 5.5155941709, + "co2_transportation" : 0.23248555, + "code" : "36016", + "dqr" : "2.66", + "ef_agriculture" : 0.57882141, + "ef_consumption" : 0.002442269, + "ef_distribution" : 0.0090139963, + "ef_packaging" : 0.017876062, + "ef_processing" : 0.073724399, + "ef_total" : 0.7000516923, + "ef_transportation" : 0.018173556, "is_beverage" : 0, - "name_en" : "Soup, mixed vegetables, prepacked, to be reheated", - "name_fr" : "Soupe aux légumes variés, préemballée à réchauffer", - "score" : 97 + "name_en" : "Chicken, meat and skin, raw", + "name_fr" : "Poulet, viande et peau, cru", + "score" : 42, + "version" : "3.1.1" }, - "grade" : "a", - "score" : 122 - }, - "score" : 111, - "scores" : { - "ad" : 120, - "al" : 111, - "at" : 117, - "ax" : 121, - "ba" : 113, - "be" : 123, - "bg" : 114, - "ch" : 121, - "cy" : 117, - "cz" : 118, - "de" : 120, - "dk" : 117, - "dz" : 118, - "ee" : 122, - "eg" : 116, - "es" : 117, - "fi" : 121, - "fo" : 120, - "fr" : 123, - "gg" : 123, - "gi" : 112, - "gr" : 118, - "hr" : 116, - "hu" : 115, - "ie" : 118, - "il" : 116, - "im" : 119, - "is" : 119, - "it" : 118, - "je" : 122, - "lb" : 117, - "li" : 121, - "lt" : 120, - "lu" : 123, - "lv" : 122, - "ly" : 119, - "ma" : 120, - "mc" : 119, - "md" : 115, - "me" : 117, - "mk" : 115, - "mt" : 120, - "nl" : 123, - "no" : 114, - "pl" : 115, - "ps" : 117, - "pt" : 113, - "ro" : 116, - "rs" : 112, - "se" : 113, - "si" : 117, - "sj" : 119, - "sk" : 115, - "sm" : 117, - "sy" : 115, - "tn" : 112, - "tr" : 112, - "ua" : 117, - "uk" : 121, - "us" : 111, - "va" : 115, - "world" : 111, - "xk" : 115 + "grade" : "b", + "score" : 67 }, - "status" : "known" + "scores" : {}, + "status" : "unknown" }, - "ecoscore_grade" : "a-plus", - "ecoscore_score" : 111, + "ecoscore_grade" : "unknown", + "ecoscore_score" : 122, "environment_impact_level_tags" : [], + "image_front_small_url" : "https://images.openfoodfacts.org/images/products/932/700/674/81501/front_en.359.200.jpg", + "image_front_url" : "https://images.openfoodfacts.org/images/products/932/700/674/81501/front_en.359.400.jpg", + "image_small_url" : "https://images.openfoodfacts.org/images/products/932/700/674/81501/front_en.359.200.jpg", "ingredients_analysis_tags" : [ "en:palm-oil-free", "en:vegan", "en:vegetarian" ], "knowledge_panels" : { - "carbon_footprint" : { - "elements" : [ - { - "element_type" : "text", - "text_element" : { - "html" : "\n

The carbon emission figure comes from ADEME's Agribalyse database, for the category: \n Soup, mixed vegetables, prepacked, to be reheated\n (Source: ADEME Agribalyse Database)\n

\n ", - "type" : "summary" - } - }, - { - "element_type" : "table", - "table_element" : { - "columns" : [ - { - "text" : "Stage", - "type" : "text" - }, - { - "text" : "Impact", - "type" : "percent" - } - ], - "id" : "ecoscore_carbon_impact_by_stages_table", - "rows" : [ - { - "id" : "agriculture", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/agriculture.svg", - "text" : "Agriculture" - }, - { - "percent" : 20.3326275087945, - "text" : "20.3 %" - } - ] - }, - { - "id" : "processing", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/processing.svg", - "text" : "Processing" - }, - { - "percent" : 29.3728073746592, - "text" : "29.4 %" - } - ] - }, - { - "id" : "packaging", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/packaging.svg", - "text" : "Packaging" - }, - { - "percent" : 19.5753974535878, - "text" : "19.6 %" - } - ] - }, - { - "id" : "transportation", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/transportation.svg", - "text" : "Transportation" - }, - { - "percent" : 25.484985099752, - "text" : "25.5 %" - } - ] - }, - { - "id" : "distribution", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/distribution.svg", - "text" : "Distribution" - }, - { - "percent" : 3.0732288312766, - "text" : "3.1 %" - } - ] - }, - { - "id" : "consumption", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/consumption.svg", - "text" : "Consumption" - }, - { - "percent" : 2.16095373192992, - "text" : "2.2 %" - } - ] - } - ], - "table_type" : "percents", - "title" : "Details of the impacts by stages of the life cycle" - } - } - ], - "evaluation" : "good", - "expanded" : false, - "level" : "info", - "title_element" : { - "icon_color_from_evaluation" : true, - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/car.svg", - "subtitle" : "51 g CO₂e per 100g of product", - "title" : "Equal to driving 0.3 km in a petrol car" - }, - "topics" : [ - "environment" - ] - }, - "ecoscore" : { - "elements" : [ - { - "element_type" : "text", - "text_element" : { - "html" : "The Eco-Score is an experimental score that summarizes the environmental impacts of food products." - } - }, - { - "element_type" : "text", - "text_element" : { - "html" : "\n \n The Eco-Score was initially developped for France and it is being extended to other European countries. The Eco-Score formula is subject to change as it is regularly improved to make it more precise and better suited to each country.\n \n ", - "type" : "note" - } - }, - { - "element_type" : "panel_group", - "panel_group_element" : { - "panel_ids" : [ - "ecoscore_agribalyse" - ], - "title" : "Life cycle analysis" - } - }, - { - "element_type" : "panel_group", - "panel_group_element" : { - "panel_ids" : [ - "ecoscore_production_system", - "ecoscore_origins_of_ingredients", - "ecoscore_threatened_species", - "ecoscore_packaging" - ], - "title" : "Bonuses and maluses" - } - }, - { - "element_type" : "panel_group", - "panel_group_element" : { - "panel_ids" : [ - "ecoscore_total" - ], - "title" : "Eco-Score for this product" - } - }, - { - "element_type" : "text", - "text_element" : { - "html" : "\n

Learn more about the Eco-Score

\n" - } - } - ], - "level" : "info", - "title_element" : { - "grade" : "a_plus", - "icon_url" : "https://static.openfoodfacts.org/images/attributes/dist/ecoscore-a-plus.svg", - "name" : "Eco-Score", - "title" : "Eco-Score A-PLUS - Very low environmental impact", - "type" : "grade" - }, - "topics" : [ - "environment" - ] - }, - "ecoscore_agribalyse" : { - "elements" : [ - { - "element_type" : "text", - "text_element" : { - "html" : "\n

Category: \n Soup, mixed vegetables, prepacked, to be reheated\n

\n \n ", - "type" : "summary" - } - }, - { - "element_type" : "table", - "table_element" : { - "columns" : [ - { - "text" : "Stage", - "type" : "text" - }, - { - "text" : "Impact", - "type" : "percent" - } - ], - "id" : "ecoscore_lca_impacts_by_stages_table", - "rows" : [ - { - "id" : "agriculture", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/agriculture.svg", - "text" : "Agriculture" - }, - { - "percent" : 28.8334807891208, - "text" : "28.8 %" - } - ] - }, - { - "id" : "processing", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/processing.svg", - "text" : "Processing" - }, - { - "percent" : 35.987979481715, - "text" : "36.0 %" - } - ] - }, - { - "id" : "packaging", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/packaging.svg", - "text" : "Packaging" - }, - { - "percent" : 12.1231296385815, - "text" : "12.1 %" - } - ] - }, - { - "id" : "transportation", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/transportation.svg", - "text" : "Transportation" - }, - { - "percent" : 12.6472018669578, - "text" : "12.6 %" - } - ] - }, - { - "id" : "distribution", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/distribution.svg", - "text" : "Distribution" - }, - { - "percent" : 5.47647634395376, - "text" : "5.5 %" - } - ] - }, - { - "id" : "consumption", - "values" : [ - { - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/consumption.svg", - "text" : "Consumption" - }, - { - "percent" : 4.93173187967106, - "text" : "4.9 %" - } - ] - } - ], - "table_type" : "percents", - "title" : "Details of the impacts by stages of the life cycle" - } - } - ], - "level" : "info", - "title_element" : { - "grade" : "a_plus", - "icon_color_from_evaluation" : true, - "icon_size" : "small", - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/lca.svg", - "subtitle" : "Category: Soup, mixed vegetables, prepacked, to be reheated", - "title" : "Average impact of products of the same category: A+ (Score: 98/100)", - "type" : "grade" - }, - "topics" : [ - "environment" - ] - }, - "ecoscore_origins_of_ingredients" : { - "elements" : [ - { - "element_type" : "text", - "text_element" : { - "html" : "\n Environmental policy: 0
\n Transportation: 0
\n ", - "type" : "default" - } - }, - { - "element_type" : "table", - "table_element" : { - "columns" : [ - { - "text" : "Origin of the product and/or its ingredients", - "type" : "text" - }, - { - "text" : "% of ingredients", - "type" : "percent" - }, - { - "text" : "Impact", - "type" : "text" - } - ], - "id" : "ecoscore_origins_of_ingredients_table", - "rows" : [ - { - "values" : [ - { - "text" : "France" - }, - { - "evaluation" : "neutral", - "percent" : 100, - "text" : "100 %" - }, - { - "evaluation" : "neutral", - "text" : "Medium" - } - ] - } - ], - "title" : "Origins of ingredients" - } - } - ], - "evaluation" : "bad", - "level" : "info", - "title_element" : { - "icon_color_from_evaluation" : true, - "icon_size" : "small", - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/public.svg", - "subtitle" : "Malus: 0", - "title" : "Origins of ingredients with a high impact" - }, - "topics" : [ - "environment" - ] - }, - "ecoscore_packaging" : { - "elements" : [ - { - "element_type" : "table", - "table_element" : { - "columns" : [ - { - "text" : "Shape", - "type" : "text" - }, - { - "text" : "Material", - "type" : "text" - }, - { - "text" : "Recycling", - "type" : "text" - }, - { - "text" : "Impact", - "type" : "text" - } - ], - "id" : "ecoscore_packaging_components", - "rows" : [ - { - "values" : [ - { - "text" : "Bottle" - }, - { - "text" : "Glass" - }, - { - "evaluation" : "good", - "text" : "Recycle" - }, - { - "evaluation" : "good", - "text" : "Low" - } - ] - }, - { - "values" : [ - { - "text" : "Bottle cap" - }, - { - "text" : "Steel" - }, - { - "evaluation" : "good", - "text" : "Recycle" - }, - { - "evaluation" : "good", - "text" : "Low" - } - ] - } - ], - "title" : "Packaging parts" - } - } - ], - "evaluation" : "good", - "level" : "info", - "title_element" : { - "icon_color_from_evaluation" : true, - "icon_size" : "small", - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/packaging.svg", - "subtitle" : "Malus: -2", - "title" : "Packaging with a low impact" - }, - "topics" : [ - "environment" - ] - }, - "ecoscore_production_system" : { - "elements" : [ - { - "element_type" : "panel", - "panel_element" : { - "panel_id" : "environment_label_en:eu-organic" - } - } - ], - "evaluation" : "good", - "level" : "info", - "title_element" : { - "icon_color_from_evaluation" : true, - "icon_size" : "small", - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/agriculture.svg", - "subtitle" : "Bonus: +15", - "title" : "Labels with high environmental benefits" - }, - "topics" : [ - "environment" - ] - }, - "ecoscore_threatened_species" : { - "evaluation" : "good", - "level" : "info", - "title_element" : { - "icon_color_from_evaluation" : true, - "icon_size" : "small", - "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/monkey_happy.svg", - "title" : "No ingredients that threaten species" - }, - "topics" : [ - "environment" - ] - }, - "ecoscore_total" : { - "elements" : [ - { - "element_type" : "text", - "text_element" : { - "html" : "\n Life cycle analysis score: 98
\n Sum of bonuses and maluses:\n \n +13\n

\n Final score: 100/100\n ", - "type" : "summary" - } - } - ], - "level" : "info", - "title_element" : { - "grade" : "a_plus", - "icon_url" : "https://static.openfoodfacts.org/images/attributes/dist/ecoscore-a-plus.svg", - "subtitle" : "Product: A good product for you - Open Food Facts - 200 g", - "title" : "Impact for this product: A+ (Score: 100/100)", - "type" : "grade" - }, - "topics" : [ - "environment" - ] - }, "environment_card" : { "elements" : [ { "element_type" : "panel", "panel_element" : { - "panel_id" : "ecoscore" - } - }, - { - "element_type" : "panel_group", - "panel_group_element" : { - "panel_ids" : [ - "carbon_footprint" - ], - "title" : "Carbon footprint" + "panel_id" : "environmental_score" } }, { @@ -1363,6 +698,36 @@ "environment" ] }, + "environmental_score" : { + "elements" : [ + { + "element_type" : "text", + "text_element" : { + "html" : "We could not compute the Green-Score of this product as it is missing some data, could you help complete it?", + "type" : "summary" + } + }, + { + "action_element" : { + "actions" : [ + "add_categories" + ], + "html" : "Could you add a precise product category so that we can compute the Green-Score?" + }, + "element_type" : "action" + } + ], + "level" : "info", + "title_element" : { + "grade" : "unknown", + "icon_url" : "https://static.openfoodfacts.org/images/attributes/dist/green-score-unknown.svg", + "title" : "Green-Score not computed - Unknown environmental impact", + "type" : "grade" + }, + "topics" : [ + "environment" + ] + }, "health_card" : { "elements" : [ { @@ -1381,7 +746,8 @@ "element_type" : "panel_group", "panel_group_element" : { "panel_ids" : [ - "nutrition_facts_table" + "nutrition_facts_table", + "serving_size" ], "title" : "" } @@ -1442,6 +808,21 @@ "html" : "" }, "element_type" : "action" + }, + { + "element_type" : "text", + "text_element" : { + "html" : "\n If you want to report vandalism, inappropriate content or erroneous data you can't fix yourself, report it to our moderators team.\n " + } + }, + { + "action_element" : { + "actions" : [ + "report_product_to_nutripatrol" + ], + "html" : "" + }, + "element_type" : "action" } ], "evaluation" : "neutral", @@ -1654,13 +1035,13 @@ { "element_type" : "text", "text_element" : { - "html" : "\n\n \n \n

Elements that indicate the product is in the 3 - Processed foods group:

\n \n \n \n\n" + "html" : "\n\n \n \n

Elements that indicate the product is in the 3 - Processed foods group:

\n \n \n \n\n" } }, { "element_type" : "text", "text_element" : { - "html" : "\n

Food products are classified into 4 groups according to their degree of processing:

\n
    \n
  1. Unprocessed or minimally processed foods
  2. \n
  3. Processed culinary ingredients
  4. \n
  5. Processed foods
  6. \n
  7. Ultra processed foods
  8. \n
\n
\n

The determination of the group is based on the category of the product and on the ingredients it contains.

\n

Learn more about the NOVA classification

\n" + "html" : "\n

Food products are classified into 4 groups according to their degree of processing:

\n
    \n
  1. Unprocessed or minimally processed foods
  2. \n
  3. Processed culinary ingredients
  4. \n
  5. Processed foods
  6. \n
  7. Ultra-processed foods
  8. \n
\n
\n

The determination of the group is based on the category of the product and on the ingredients it contains.

\n

Learn more about the NOVA classification

\n" } } ], @@ -1864,6 +1245,12 @@ "type" : "warning" } }, + { + "element_type" : "panel", + "panel_element" : { + "panel_id" : "nutriscore_new_computation" + } + }, { "element_type" : "panel", "panel_element" : { @@ -1934,7 +1321,7 @@ "title_element" : { "icon_url" : "https://static.openfoodfacts.org/images/attributes/dist/points-negative-0-10.svg", "subtitle" : "0/10 points (120kJ)", - "title" : "Calories" + "title" : "Energy" }, "topics" : [ "health" @@ -2114,6 +1501,33 @@ "health" ] }, + "nutriscore_new_computation" : { + "elements" : [ + { + "element_type" : "text", + "text_element" : { + "html" : "

The computation of the Nutri-Score is evolving to provide better recommendations based on the latest scientific evidence.

Main improvements:

\n ", + "type" : "info" + } + }, + { + "element_type" : "text", + "text_element" : { + "html" : "\n

Discover all the improvements of the new Nutri-Score

\n" + } + } + ], + "level" : "info", + "title_element" : { + "icon_size" : "small", + "icon_url" : "https://static.openfoodfacts.org/images/icons/dist/info.svg", + "title" : "Discover the new Nutri-Score!", + "type" : "info" + }, + "topics" : [ + "health" + ] + }, "nutrition_facts_table" : { "elements" : [ { @@ -2133,9 +1547,10 @@ "type" : "text" }, { - "column_group_id" : "comparisons", - "shown_by_default" : true, - "text" : "Compared to: Vegetable soups", + "column_group_id" : "product", + "shown_by_default" : false, + "text" : "As sold
per serving (115g)", + "text_for_small_screens" : "per serving", "type" : "text" } ], @@ -2149,11 +1564,10 @@ "text" : "Energy" }, { - "text" : "120 kj
(29 kcal)" + "text" : "120 kj
(59 kcal)" }, { - "evaluation" : "good", - "text" : "-54%" + "text" : "138 kj
(67 kcal)" } ] }, @@ -2168,8 +1582,7 @@ "text" : "0.5 g" }, { - "evaluation" : "good", - "text" : "-69%" + "text" : "0.575 g" } ] }, @@ -2184,8 +1597,7 @@ "text" : "0.2 g" }, { - "evaluation" : "good", - "text" : "-42%" + "text" : "0.23 g" } ] }, @@ -2200,8 +1612,7 @@ "text" : "0.4 g" }, { - "evaluation" : "good", - "text" : "-39%" + "text" : "0.46 g" } ] }, @@ -2216,7 +1627,7 @@ "text" : "4 g" }, { - "text" : "-62%" + "text" : "4.6 g" } ] }, @@ -2231,8 +1642,7 @@ "text" : "3 g" }, { - "evaluation" : "good", - "text" : "+95%" + "text" : "3.45 g" } ] }, @@ -2247,8 +1657,7 @@ "text" : "0.5 g" }, { - "evaluation" : "good", - "text" : "-82%" + "text" : "0.575 g" } ] }, @@ -2263,8 +1672,7 @@ "text" : "1 g" }, { - "evaluation" : "bad", - "text" : "-56%" + "text" : "1.15 g" } ] }, @@ -2279,7 +1687,7 @@ "text" : "65 %" }, { - "text" : "" + "text" : "65 %" } ] } @@ -2320,7 +1728,7 @@ "type" : "text" } ], - "id" : "ecoscore_origins_of_ingredients_table", + "id" : "environmental_score_origins_of_ingredients_table", "rows" : [ { "values" : [ @@ -2536,6 +1944,22 @@ ], "expanded" : true, "type" : "root" + }, + "serving_size" : { + "elements" : [ + { + "element_type" : "text", + "text_element" : { + "html" : "\n Serving size:\n 115g\n " + } + } + ], + "expanded" : true, + "level" : "info", + "topics" : [ + "health" + ], + "type" : "inline" } }, "labels_tags" : [ @@ -2558,25 +1982,37 @@ "nutriments" : { "carbohydrates" : 4, "carbohydrates_100g" : 4, + "carbohydrates_serving" : 4.6, "carbohydrates_unit" : "g", "carbohydrates_value" : 4, "carbon-footprint-from-known-ingredients_100g" : 18, "carbon-footprint-from-known-ingredients_product" : 36, + "carbon-footprint-from-known-ingredients_serving" : 20.7, "energy" : 120, + "energy-kcal" : 59, + "energy-kcal_100g" : 59, + "energy-kcal_serving" : 67.8, + "energy-kcal_unit" : "kcal", + "energy-kcal_value" : 59, + "energy-kcal_value_computed" : 30.5, "energy-kj" : 120, "energy-kj_100g" : 120, + "energy-kj_serving" : 138, "energy-kj_unit" : "kJ", "energy-kj_value" : 120, "energy-kj_value_computed" : 127.5, "energy_100g" : 120, + "energy_serving" : 138, "energy_unit" : "kJ", "energy_value" : 120, "fat" : 0.5, "fat_100g" : 0.5, + "fat_serving" : 0.575, "fat_unit" : "g", "fat_value" : 0.5, "fiber" : 3, "fiber_100g" : 3, + "fiber_serving" : 3.45, "fiber_unit" : "g", "fiber_value" : 3, "fruits-vegetables-legumes-estimate-from-ingredients_100g" : 65, @@ -2586,26 +2022,31 @@ "nova-group" : 3, "nova-group_100g" : 3, "nova-group_serving" : 3, - "nutrition-score-fr" : -4, - "nutrition-score-fr_100g" : -4, + "nutrition-score-fr" : -1, + "nutrition-score-fr_100g" : -1, "proteins" : 1, "proteins_100g" : 1, + "proteins_serving" : 1.15, "proteins_unit" : "g", "proteins_value" : 1, "salt" : 0.4, "salt_100g" : 0.4, + "salt_serving" : 0.46, "salt_unit" : "g", "salt_value" : 0.4, "saturated-fat" : 0.2, "saturated-fat_100g" : 0.2, + "saturated-fat_serving" : 0.23, "saturated-fat_unit" : "g", "saturated-fat_value" : 0.2, "sodium" : 0.16, "sodium_100g" : 0.16, + "sodium_serving" : 0.184, "sodium_unit" : "g", "sodium_value" : 0.16, "sugars" : 0.5, "sugars_100g" : 0.5, + "sugars_serving" : 0.575, "sugars_unit" : "g", "sugars_value" : 0.5 }, @@ -2613,6 +2054,20 @@ "product_name" : "A good product for you", "product_quantity" : "200", "quantity" : "200 g", + "selected_images" : { + "front" : { + "display" : { + "en" : "https://images.openfoodfacts.org/images/products/932/700/674/81501/front_en.359.400.jpg" + }, + "small" : { + "en" : "https://images.openfoodfacts.org/images/products/932/700/674/81501/front_en.359.200.jpg" + }, + "thumb" : { + "en" : "https://images.openfoodfacts.org/images/products/932/700/674/81501/front_en.359.100.jpg" + } + } + }, + "serving_size" : "115g", "states_tags" : [ "en:to-be-completed", "en:nutrition-facts-completed", @@ -2626,7 +2081,12 @@ "en:packaging-to-be-completed", "en:quantity-completed", "en:product-name-completed", - "en:photos-to-be-uploaded" + "en:photos-to-be-validated", + "en:packaging-photo-to-be-selected", + "en:nutrition-photo-to-be-selected", + "en:ingredients-photo-to-be-selected", + "en:front-photo-selected", + "en:photos-uploaded" ] }, "status" : 1, From 863aa76e62087f493b344b434cb3f8e70b3e1693 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 10 Jan 2025 09:56:44 +0100 Subject: [PATCH 2/5] fix: Language selector + ingredients (text field + outdated) (#6170) * Language selector + ingredients text field * Minor fix * Outdated explanations * Remove shadow from edit buttons * Invert colors for Cancel/Save buttons in dark mode * Format * SafeArea for Edit Page --- .../product_cards/product_title_card.dart | 5 +++ .../smooth_large_button_with_icon.dart | 3 ++ .../buttons/smooth_simple_button.dart | 3 ++ .../widgets/language_selector.dart | 7 +++- .../lib/helpers/product_cards_helper.dart | 2 + packages/smooth_app/lib/l10n/app_en.arb | 5 +++ packages/smooth_app/lib/l10n/app_fr.arb | 5 +++ .../pages/product/edit_language_tabbar.dart | 2 +- .../product/edit_ocr/edit_ocr_image.dart | 42 +++++++++++++++---- .../product/edit_ocr/edit_ocr_textfield.dart | 2 + .../lib/pages/product/edit_product_page.dart | 4 +- .../pages/product/product_image_viewer.dart | 1 + .../product/simple_input_page_helpers.dart | 1 + .../lib/widgets/v2/smooth_buttons_bar.dart | 17 ++++---- 14 files changed, 81 insertions(+), 18 deletions(-) diff --git a/packages/smooth_app/lib/cards/product_cards/product_title_card.dart b/packages/smooth_app/lib/cards/product_cards/product_title_card.dart index 55a7ecae809b..41609b5bbf58 100644 --- a/packages/smooth_app/lib/cards/product_cards/product_title_card.dart +++ b/packages/smooth_app/lib/cards/product_cards/product_title_card.dart @@ -51,6 +51,7 @@ class ProductTitleCard extends StatelessWidget { const SizedBox(height: SMALL_SPACE), _ProductTitleCardBrand( selectable: isSelectable, + dense: dense, ), const SizedBox(height: 2.0), trailing, @@ -155,9 +156,11 @@ class _ProductTitleCardName extends StatelessWidget { class _ProductTitleCardBrand extends StatelessWidget { const _ProductTitleCardBrand({ required this.selectable, + this.dense = false, }); final bool selectable; + final bool dense; @override Widget build(BuildContext context) { @@ -168,6 +171,8 @@ class _ProductTitleCardBrand extends StatelessWidget { return Text( brands, + maxLines: dense ? 1 : 2, + overflow: dense ? TextOverflow.ellipsis : null, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.start, ); diff --git a/packages/smooth_app/lib/generic_lib/buttons/smooth_large_button_with_icon.dart b/packages/smooth_app/lib/generic_lib/buttons/smooth_large_button_with_icon.dart index 013a84218b54..d457d0fbcc5c 100644 --- a/packages/smooth_app/lib/generic_lib/buttons/smooth_large_button_with_icon.dart +++ b/packages/smooth_app/lib/generic_lib/buttons/smooth_large_button_with_icon.dart @@ -13,6 +13,7 @@ class SmoothLargeButtonWithIcon extends StatelessWidget { this.foregroundColor, this.textAlign, this.textStyle, + this.elevation, }); final String text; @@ -24,6 +25,7 @@ class SmoothLargeButtonWithIcon extends StatelessWidget { final Color? foregroundColor; final TextAlign? textAlign; final TextStyle? textStyle; + final WidgetStateProperty? elevation; Color _getBackgroundColor(final ThemeData themeData) => backgroundColor ?? themeData.colorScheme.secondary; @@ -44,6 +46,7 @@ class SmoothLargeButtonWithIcon extends StatelessWidget { minWidth: double.infinity, padding: padding ?? const EdgeInsets.all(10), onPressed: onPressed, + elevation: elevation, buttonColor: _getBackgroundColor(themeData), child: Row( mainAxisAlignment: MainAxisAlignment.start, diff --git a/packages/smooth_app/lib/generic_lib/buttons/smooth_simple_button.dart b/packages/smooth_app/lib/generic_lib/buttons/smooth_simple_button.dart index c60c671a6660..080efc88e3b8 100644 --- a/packages/smooth_app/lib/generic_lib/buttons/smooth_simple_button.dart +++ b/packages/smooth_app/lib/generic_lib/buttons/smooth_simple_button.dart @@ -12,6 +12,7 @@ class SmoothSimpleButton extends StatelessWidget { this.borderRadius = ROUNDED_BORDER_RADIUS, this.padding = const EdgeInsets.all(10), this.buttonColor, + this.elevation, }); final Widget child; @@ -21,6 +22,7 @@ class SmoothSimpleButton extends StatelessWidget { final BorderRadius borderRadius; final EdgeInsetsGeometry padding; final Color? buttonColor; + final WidgetStateProperty? elevation; @override Widget build(BuildContext context) { @@ -31,6 +33,7 @@ class SmoothSimpleButton extends StatelessWidget { ), child: ElevatedButton( style: ButtonStyle( + elevation: elevation, backgroundColor: buttonColor == null ? null : WidgetStateProperty.all(buttonColor!), diff --git a/packages/smooth_app/lib/generic_lib/widgets/language_selector.dart b/packages/smooth_app/lib/generic_lib/widgets/language_selector.dart index 7a05af986b99..31d10cc16101 100644 --- a/packages/smooth_app/lib/generic_lib/widgets/language_selector.dart +++ b/packages/smooth_app/lib/generic_lib/widgets/language_selector.dart @@ -22,6 +22,7 @@ class LanguageSelector extends StatelessWidget { this.padding, this.borderRadius, this.product, + this.checkedIcon, }); /// What to do when the language is selected. @@ -37,6 +38,7 @@ class LanguageSelector extends StatelessWidget { final Widget? icon; final EdgeInsetsGeometry? padding; final BorderRadius? borderRadius; + final Widget? checkedIcon; /// Product from which we can extract the languages that matter. final Product? product; @@ -67,6 +69,7 @@ class LanguageSelector extends StatelessWidget { context, selectedLanguages: selectedLanguages, languagePriority: languagePriority, + checkedIcon: checkedIcon, ); if (language != null) { await daoStringList.add( @@ -126,6 +129,7 @@ class LanguageSelector extends StatelessWidget { final BuildContext context, { final Iterable? selectedLanguages, required final LanguagePriority languagePriority, + final Widget? checkedIcon, }) async { final ScrollController scrollController = ScrollController(); final AppLocalizations appLocalizations = AppLocalizations.of(context); @@ -190,7 +194,8 @@ class LanguageSelector extends StatelessWidget { selectedLanguages.contains(language); return ListTile( dense: true, - trailing: selected ? const Icon(Icons.check) : null, + trailing: + selected ? (checkedIcon ?? const Icon(Icons.check)) : null, title: TextHighlighter( text: _getCompleteName(language), filter: languageSelectorController.text, diff --git a/packages/smooth_app/lib/helpers/product_cards_helper.dart b/packages/smooth_app/lib/helpers/product_cards_helper.dart index 86944bc36c9c..8ec4a7746add 100644 --- a/packages/smooth_app/lib/helpers/product_cards_helper.dart +++ b/packages/smooth_app/lib/helpers/product_cards_helper.dart @@ -312,12 +312,14 @@ Widget addPanelButton( final String? textAlign, final EdgeInsetsGeometry? padding, required final Function() onPressed, + WidgetStateProperty? elevation, }) => Padding( padding: const EdgeInsets.symmetric(vertical: SMALL_SPACE), child: SmoothLargeButtonWithIcon( text: label, icon: iconData ?? Icons.add, + elevation: elevation, onPressed: onPressed, textAlign: iconData == null ? TextAlign.center : null, padding: padding, diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index 985110dc085e..f7fc30d03e1b 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -793,6 +793,11 @@ } }, "product_image_outdated": "This image may be outdated", + "product_image_outdated_explanations_title": "This image may be outdated", + "product_image_outdated_explanations_content": "This image was taken more than a year ago.\n**Please check that's it's still up-to-date**.\n\nThis is **just a warning**. If the content is still the same, you can ignore this message.", + "@product_image_outdated_explanations_content": { + "description": "Please keep the ** syntax to make the text bold" + }, "product_image_action_replace_photo": "Replace photo ({type})", "@product_image_action_replace_photo": { "description": "Action on the photo gallery to replace an existing picture", diff --git a/packages/smooth_app/lib/l10n/app_fr.arb b/packages/smooth_app/lib/l10n/app_fr.arb index 207fd4a72a6d..be2932778748 100644 --- a/packages/smooth_app/lib/l10n/app_fr.arb +++ b/packages/smooth_app/lib/l10n/app_fr.arb @@ -793,6 +793,11 @@ } }, "product_image_outdated": "Cette image peut être obsolète", + "product_image_outdated_explanations_title": "Cette image peut-être obsolète", + "product_image_outdated_explanations_content": "Cette image a été prise il y a plus d'un an.\n**Merci de vérifier qu'elle est toujours d'actualité**.\n\nIl s'agit **uniquement d'une alerte**. Si le contenu n'a pas changé, vous pouvez ignorer ce message.", + "@product_image_outdated_explanations_content": { + "description": "Please keep the ** syntax to make the text bold" + }, "product_image_action_replace_photo": "Remplacer la photo ({type})", "@product_image_action_replace_photo": { "description": "Action on the photo gallery to replace an existing picture", diff --git a/packages/smooth_app/lib/pages/product/edit_language_tabbar.dart b/packages/smooth_app/lib/pages/product/edit_language_tabbar.dart index eb42af15596c..e0505e9323b9 100644 --- a/packages/smooth_app/lib/pages/product/edit_language_tabbar.dart +++ b/packages/smooth_app/lib/pages/product/edit_language_tabbar.dart @@ -253,7 +253,7 @@ class _EditLanguageTabBarAddLanguageButton extends StatelessWidget { width: lightTheme ? 1.5 : 2.0, ), ), - color: lightTheme ? theme.primaryDark : theme.primaryNormal, + color: lightTheme ? theme.primaryBlack : theme.primaryNormal, ), child: Material( type: MaterialType.transparency, diff --git a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_image.dart b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_image.dart index bb7219556b08..1133e09d9954 100644 --- a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_image.dart +++ b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_image.dart @@ -19,6 +19,7 @@ import 'package:smooth_app/themes/smooth_theme.dart'; import 'package:smooth_app/themes/smooth_theme_colors.dart'; import 'package:smooth_app/themes/theme_provider.dart'; import 'package:smooth_app/widgets/smooth_indicator_icon.dart'; +import 'package:smooth_app/widgets/smooth_text.dart'; class EditOCRImageWidget extends StatelessWidget { const EditOCRImageWidget({ @@ -76,14 +77,21 @@ class EditOCRImageWidget extends StatelessWidget { color: extension.warning, borderRadius: ROUNDED_BORDER_RADIUS, ), - child: const Padding( - padding: EdgeInsetsDirectional.only( - top: 6.5, - bottom: 7.5, - start: 7.0, - end: 7.0, + child: Material( + type: MaterialType.transparency, + child: InkWell( + customBorder: const CircleBorder(), + onTap: () => _openOutdatedPictureExplanations(context), + child: const Padding( + padding: EdgeInsetsDirectional.only( + top: 6.5, + bottom: 7.5, + start: 7.0, + end: 7.0, + ), + child: icons.Outdated(size: 15.0), + ), ), - child: icons.Outdated(size: 15.0), ), ), ); @@ -149,6 +157,26 @@ class EditOCRImageWidget extends StatelessWidget { ), ); } + + Future _openOutdatedPictureExplanations(BuildContext context) { + final AppLocalizations appLocalizations = AppLocalizations.of(context); + + return showSmoothModalSheet( + context: context, + builder: (BuildContext context) { + return SmoothModalSheet( + title: appLocalizations.product_image_outdated_explanations_title, + prefixIndicator: true, + body: SmoothModalSheetBodyContainer( + child: TextWithBoldParts( + text: + appLocalizations.product_image_outdated_explanations_content, + ), + ), + ); + }, + ); + } } class _EditOCRImageFound extends StatelessWidget { diff --git a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_textfield.dart b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_textfield.dart index a69efc021d9c..95451d2efecc 100644 --- a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_textfield.dart +++ b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_textfield.dart @@ -132,6 +132,8 @@ class EditOCRTextField extends StatelessWidget { ), ), ), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ), ); }, diff --git a/packages/smooth_app/lib/pages/product/edit_product_page.dart b/packages/smooth_app/lib/pages/product/edit_product_page.dart index 0299db5024c7..c2e852492dc3 100644 --- a/packages/smooth_app/lib/pages/product/edit_product_page.dart +++ b/packages/smooth_app/lib/pages/product/edit_product_page.dart @@ -142,11 +142,11 @@ class _EditProductPageState extends State with UpToDateMixin { child: Scrollbar( controller: _controller, child: ListView( - padding: const EdgeInsetsDirectional.only( + padding: EdgeInsetsDirectional.only( top: SMALL_SPACE, start: VERY_SMALL_SPACE, end: VERY_SMALL_SPACE, - bottom: MEDIUM_SPACE, + bottom: MEDIUM_SPACE + MediaQuery.viewPaddingOf(context).bottom, ), controller: _controller, children: [ diff --git a/packages/smooth_app/lib/pages/product/product_image_viewer.dart b/packages/smooth_app/lib/pages/product/product_image_viewer.dart index ab84f17c6021..39c7577b736c 100644 --- a/packages/smooth_app/lib/pages/product/product_image_viewer.dart +++ b/packages/smooth_app/lib/pages/product/product_image_viewer.dart @@ -238,6 +238,7 @@ class _ProductImageViewerState extends State displayedLanguage: widget.language, selectedLanguages: selectedLanguages, foregroundColor: Colors.white, + checkedIcon: const Icon(Icons.camera_alt_rounded), padding: const EdgeInsetsDirectional.symmetric( horizontal: 13.0, vertical: SMALL_SPACE, diff --git a/packages/smooth_app/lib/pages/product/simple_input_page_helpers.dart b/packages/smooth_app/lib/pages/product/simple_input_page_helpers.dart index 8aa501821f30..1e487e864721 100644 --- a/packages/smooth_app/lib/pages/product/simple_input_page_helpers.dart +++ b/packages/smooth_app/lib/pages/product/simple_input_page_helpers.dart @@ -137,6 +137,7 @@ abstract class AbstractSimpleInputPageHelper extends ChangeNotifier { isLoggedInMandatory: false, ), iconData: Icons.add_a_photo, + elevation: const WidgetStatePropertyAll(0.0), padding: const EdgeInsetsDirectional.only( top: SMALL_SPACE, bottom: SMALL_SPACE, diff --git a/packages/smooth_app/lib/widgets/v2/smooth_buttons_bar.dart b/packages/smooth_app/lib/widgets/v2/smooth_buttons_bar.dart index ac0f03d371e2..03a8746cd2e6 100644 --- a/packages/smooth_app/lib/widgets/v2/smooth_buttons_bar.dart +++ b/packages/smooth_app/lib/widgets/v2/smooth_buttons_bar.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/duration_constants.dart'; import 'package:smooth_app/helpers/keyboard_helper.dart'; +import 'package:smooth_app/themes/smooth_theme.dart'; import 'package:smooth_app/themes/smooth_theme_colors.dart'; import 'package:smooth_app/themes/theme_provider.dart'; @@ -152,13 +153,13 @@ class _SmoothPositiveButton2 extends StatelessWidget { @override Widget build(BuildContext context) { final SmoothColorsThemeExtension colors = - Theme.of(context).extension()!; + context.extension(); + final bool lightTheme = context.lightTheme(); return _SmoothBaseButton2( data: data, - backgroundColor: - context.lightTheme() ? colors.primaryBlack : colors.primaryDark, - foregroundColor: Colors.white, + backgroundColor: lightTheme ? colors.primaryBlack : colors.primaryLight, + foregroundColor: lightTheme ? Colors.white : colors.primaryDark, ); } } @@ -171,12 +172,14 @@ class _SmoothNegativeButton2 extends StatelessWidget { @override Widget build(BuildContext context) { final SmoothColorsThemeExtension colors = - Theme.of(context).extension()!; + context.extension(); + + final bool lightTheme = context.lightTheme(); return _SmoothBaseButton2( data: data, - backgroundColor: colors.primaryMedium, - foregroundColor: colors.primaryDark, + backgroundColor: lightTheme ? colors.primaryMedium : colors.primaryDark, + foregroundColor: lightTheme ? colors.primaryDark : colors.primaryLight, ); } } From 58c53fe166db183093d6fcfc5d970eccc6c995bd Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 10 Jan 2025 09:58:12 +0100 Subject: [PATCH 3/5] Add price with the "Edit UI" (#6171) --- .../pages/prices/price_add_product_card.dart | 14 ++- .../lib/pages/prices/price_amount_card.dart | 13 ++- .../lib/pages/prices/price_currency_card.dart | 14 ++- .../lib/pages/prices/price_date_card.dart | 69 ++++++------ .../lib/pages/prices/price_location_card.dart | 104 +++++++++--------- .../lib/pages/prices/price_proof_card.dart | 55 +++++---- .../pages/prices/product_price_add_page.dart | 17 ++- 7 files changed, 161 insertions(+), 125 deletions(-) diff --git a/packages/smooth_app/lib/pages/prices/price_add_product_card.dart b/packages/smooth_app/lib/pages/prices/price_add_product_card.dart index 2d4c29c86822..1f64f56e43e5 100644 --- a/packages/smooth_app/lib/pages/prices/price_add_product_card.dart +++ b/packages/smooth_app/lib/pages/prices/price_add_product_card.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import 'package:smooth_app/data_models/preferences/user_preferences.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/generic_lib/buttons/smooth_large_button_with_icon.dart'; +import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_card.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_text_form_field.dart'; @@ -40,14 +41,15 @@ class _PriceAddProductCardState extends State { @override Widget build(BuildContext context) { final AppLocalizations appLocalizations = AppLocalizations.of(context); - return SmoothCard( + return SmoothCardWithRoundedHeader( + title: appLocalizations.prices_add_an_item, + leading: const Icon(Icons.add_circle_outlined), + contentPadding: const EdgeInsetsDirectional.symmetric( + horizontal: SMALL_SPACE, + vertical: MEDIUM_SPACE, + ), child: Column( children: [ - ListTile( - title: Text( - appLocalizations.prices_add_an_item, - ), - ), SmoothLargeButtonWithIcon( text: appLocalizations.prices_barcode_reader_action, icon: Icons.barcode_reader, diff --git a/packages/smooth_app/lib/pages/prices/price_amount_card.dart b/packages/smooth_app/lib/pages/prices/price_amount_card.dart index 0a3b67465c75..24c12bbef54b 100644 --- a/packages/smooth_app/lib/pages/prices/price_amount_card.dart +++ b/packages/smooth_app/lib/pages/prices/price_amount_card.dart @@ -51,13 +51,16 @@ class _PriceAmountCardState extends State { final PriceAmountModel model = priceModel.elementAt(widget.index); final int total = priceModel.length; - return SmoothCard( + return SmoothCardWithRoundedHeader( + title: '${appLocalizations.prices_amount_subtitle}' + '${total == 1 ? '' : ' (${widget.index + 1}/$total)'}', + leading: const Icon(Icons.calculate_rounded), + contentPadding: const EdgeInsetsDirectional.symmetric( + vertical: MEDIUM_SPACE, + horizontal: SMALL_SPACE, + ), child: Column( children: [ - Text( - '${appLocalizations.prices_amount_subtitle}' - '${total == 1 ? '' : ' (${widget.index + 1}/$total)'}', - ), PriceProductListTile( product: model.product, trailingIconData: total == 1 ? null : Icons.clear, diff --git a/packages/smooth_app/lib/pages/prices/price_currency_card.dart b/packages/smooth_app/lib/pages/prices/price_currency_card.dart index fb82c1bf94ef..e711b9910a82 100644 --- a/packages/smooth_app/lib/pages/prices/price_currency_card.dart +++ b/packages/smooth_app/lib/pages/prices/price_currency_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_card.dart'; import 'package:smooth_app/pages/prices/price_currency_selector.dart'; @@ -10,13 +11,14 @@ class PriceCurrencyCard extends StatelessWidget { @override Widget build(BuildContext context) { final AppLocalizations appLocalizations = AppLocalizations.of(context); - return SmoothCard( - child: Column( - children: [ - Text(appLocalizations.prices_currency_subtitle), - PriceCurrencySelector(), - ], + return SmoothCardWithRoundedHeader( + title: appLocalizations.prices_currency_subtitle, + leading: const Icon(Icons.price_change), + contentPadding: const EdgeInsetsDirectional.symmetric( + horizontal: SMALL_SPACE, + vertical: MEDIUM_SPACE, ), + child: PriceCurrencySelector(), ); } } diff --git a/packages/smooth_app/lib/pages/prices/price_date_card.dart b/packages/smooth_app/lib/pages/prices/price_date_card.dart index 4acce28ac87d..df416c2bfb64 100644 --- a/packages/smooth_app/lib/pages/prices/price_date_card.dart +++ b/packages/smooth_app/lib/pages/prices/price_date_card.dart @@ -3,6 +3,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:smooth_app/generic_lib/buttons/smooth_large_button_with_icon.dart'; +import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_card.dart'; import 'package:smooth_app/pages/prices/price_model.dart'; import 'package:smooth_app/query/product_query.dart'; @@ -17,42 +18,42 @@ class PriceDateCard extends StatelessWidget { final AppLocalizations appLocalizations = AppLocalizations.of(context); final String locale = ProductQuery.getLocaleString(); final DateFormat dateFormat = DateFormat.yMd(locale); - return SmoothCard( - child: Column( - children: [ - Text(appLocalizations.prices_date_subtitle), - SmoothLargeButtonWithIcon( - text: dateFormat.format(model.date), - icon: Icons.calendar_month, - onPressed: model.proof != null - ? null - : () async { - final DateTime? newDate = await showDatePicker( - context: context, - locale: Locale(ProductQuery.getLanguage().offTag), - firstDate: model.firstDate, - lastDate: model.today, - builder: - (final BuildContext context, final Widget? child) { - // for some reason we don't have a fine display without that theme. - // cf. https://stackoverflow.com/questions/50321182/how-to-customize-a-date-picker - final ThemeData themeData = - Theme.of(context).brightness == Brightness.light - ? ThemeData.light() - : ThemeData.dark(); - return Theme( - data: themeData.copyWith(), - child: child!, - ); - }, + return SmoothCardWithRoundedHeader( + title: appLocalizations.prices_date_subtitle, + leading: const Icon(Icons.calendar_month), + contentPadding: const EdgeInsetsDirectional.symmetric( + horizontal: SMALL_SPACE, + vertical: MEDIUM_SPACE, + ), + child: SmoothLargeButtonWithIcon( + text: dateFormat.format(model.date), + icon: Icons.calendar_month, + onPressed: model.proof != null + ? null + : () async { + final DateTime? newDate = await showDatePicker( + context: context, + locale: Locale(ProductQuery.getLanguage().offTag), + firstDate: model.firstDate, + lastDate: model.today, + builder: (final BuildContext context, final Widget? child) { + // for some reason we don't have a fine display without that theme. + // cf. https://stackoverflow.com/questions/50321182/how-to-customize-a-date-picker + final ThemeData themeData = + Theme.of(context).brightness == Brightness.light + ? ThemeData.light() + : ThemeData.dark(); + return Theme( + data: themeData.copyWith(), + child: child!, ); - if (newDate == null) { - return; - } - model.date = newDate; }, - ), - ], + ); + if (newDate == null) { + return; + } + model.date = newDate; + }, ), ); } diff --git a/packages/smooth_app/lib/pages/prices/price_location_card.dart b/packages/smooth_app/lib/pages/prices/price_location_card.dart index 05d5e17eba64..f2ef9c15b1af 100644 --- a/packages/smooth_app/lib/pages/prices/price_location_card.dart +++ b/packages/smooth_app/lib/pages/prices/price_location_card.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import 'package:smooth_app/database/dao_osm_location.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/generic_lib/buttons/smooth_large_button_with_icon.dart'; +import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_card.dart'; import 'package:smooth_app/pages/locations/osm_location.dart'; import 'package:smooth_app/pages/locations/search_location_helper.dart'; @@ -21,57 +22,58 @@ class PriceLocationCard extends StatelessWidget { final PriceModel model = context.watch(); final AppLocalizations appLocalizations = AppLocalizations.of(context); final OsmLocation? location = model.location; - return SmoothCard( - child: Column( - children: [ - Text(appLocalizations.prices_location_subtitle), - SmoothLargeButtonWithIcon( - text: location == null - ? appLocalizations.prices_location_find - : location.getTitle() ?? - location.getSubtitle() ?? - location.getLatLng().toString(), - icon: location == null - ? Icons.shopping_cart - : PriceButton.locationIconData, - onPressed: model.proof != null - ? null - : () async { - final LocalDatabase localDatabase = - context.read(); - final List preloadedList = - []; - for (final OsmLocation osmLocation in model.locations!) { - preloadedList.add( - SearchLocationPreloadedItem( - osmLocation, - popFirst: false, - ), - ); - } - final OsmLocation? osmLocation = - await Navigator.push( - context, - MaterialPageRoute( - builder: (BuildContext context) => SearchPage( - SearchLocationHelper(), - preloadedList: preloadedList, - autofocus: false, - ), - ), - ); - if (osmLocation == null) { - return; - } - final DaoOsmLocation daoOsmLocation = - DaoOsmLocation(localDatabase); - await daoOsmLocation.put(osmLocation); - final List newOsmLocations = - await daoOsmLocation.getAll(); - model.locations = newOsmLocations; - }, - ), - ], + return SmoothCardWithRoundedHeader( + title: appLocalizations.prices_location_subtitle, + leading: const Icon(Icons.shopping_cart), + contentPadding: const EdgeInsetsDirectional.symmetric( + horizontal: SMALL_SPACE, + vertical: MEDIUM_SPACE, + ), + child: SmoothLargeButtonWithIcon( + text: location == null + ? appLocalizations.prices_location_find + : location.getTitle() ?? + location.getSubtitle() ?? + location.getLatLng().toString(), + icon: location == null + ? Icons.shopping_cart + : PriceButton.locationIconData, + onPressed: model.proof != null + ? null + : () async { + final LocalDatabase localDatabase = + context.read(); + final List preloadedList = + []; + for (final OsmLocation osmLocation in model.locations!) { + preloadedList.add( + SearchLocationPreloadedItem( + osmLocation, + popFirst: false, + ), + ); + } + final OsmLocation? osmLocation = + await Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => SearchPage( + SearchLocationHelper(), + preloadedList: preloadedList, + autofocus: false, + ), + ), + ); + if (osmLocation == null) { + return; + } + final DaoOsmLocation daoOsmLocation = + DaoOsmLocation(localDatabase); + await daoOsmLocation.put(osmLocation); + final List newOsmLocations = + await daoOsmLocation.getAll(); + model.locations = newOsmLocations; + }, ), ); } diff --git a/packages/smooth_app/lib/pages/prices/price_proof_card.dart b/packages/smooth_app/lib/pages/prices/price_proof_card.dart index 0e6027b9075c..e9c90c90ec18 100644 --- a/packages/smooth_app/lib/pages/prices/price_proof_card.dart +++ b/packages/smooth_app/lib/pages/prices/price_proof_card.dart @@ -7,6 +7,7 @@ import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:provider/provider.dart'; import 'package:smooth_app/data_models/preferences/user_preferences.dart'; import 'package:smooth_app/generic_lib/buttons/smooth_large_button_with_icon.dart'; +import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_card.dart'; import 'package:smooth_app/helpers/camera_helper.dart'; import 'package:smooth_app/pages/crop_parameters.dart'; @@ -27,10 +28,15 @@ class PriceProofCard extends StatelessWidget { Widget build(BuildContext context) { final PriceModel model = context.watch(); final AppLocalizations appLocalizations = AppLocalizations.of(context); - return SmoothCard( + return SmoothCardWithRoundedHeader( + title: appLocalizations.prices_proof_subtitle, + leading: const Icon(Icons.document_scanner_rounded), + contentPadding: const EdgeInsetsDirectional.symmetric( + horizontal: SMALL_SPACE, + vertical: MEDIUM_SPACE, + ), child: Column( children: [ - Text(appLocalizations.prices_proof_subtitle), if (model.proof != null) Image( image: NetworkImage( @@ -53,26 +59,31 @@ class PriceProofCard extends StatelessWidget { height: constraints.maxWidth, ), ), - SmoothLargeButtonWithIcon( - text: !model.hasImage - ? appLocalizations.prices_proof_find - : model.proofType == ProofType.receipt - ? appLocalizations.prices_proof_receipt - : appLocalizations.prices_proof_price_tag, - icon: !model.hasImage ? _iconTodo : _iconDone, - onPressed: model.proof != null - ? null - : () async { - final _ProofSource? proofSource = - await _ProofSource.select(context); - if (proofSource == null) { - return; - } - if (!context.mounted) { - return; - } - return proofSource.process(context, model); - }, + Padding( + padding: const EdgeInsetsDirectional.symmetric( + horizontal: SMALL_SPACE, + ), + child: SmoothLargeButtonWithIcon( + text: !model.hasImage + ? appLocalizations.prices_proof_find + : model.proofType == ProofType.receipt + ? appLocalizations.prices_proof_receipt + : appLocalizations.prices_proof_price_tag, + icon: !model.hasImage ? _iconTodo : _iconDone, + onPressed: model.proof != null + ? null + : () async { + final _ProofSource? proofSource = + await _ProofSource.select(context); + if (proofSource == null) { + return; + } + if (!context.mounted) { + return; + } + return proofSource.process(context, model); + }, + ), ), LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) => Row( diff --git a/packages/smooth_app/lib/pages/prices/product_price_add_page.dart b/packages/smooth_app/lib/pages/prices/product_price_add_page.dart index b9efbf90fbef..9f0cf80a2eef 100644 --- a/packages/smooth_app/lib/pages/prices/product_price_add_page.dart +++ b/packages/smooth_app/lib/pages/prices/product_price_add_page.dart @@ -21,7 +21,11 @@ import 'package:smooth_app/pages/prices/price_model.dart'; import 'package:smooth_app/pages/prices/price_proof_card.dart'; import 'package:smooth_app/pages/product/common/product_refresher.dart'; import 'package:smooth_app/pages/product/may_exit_page_helper.dart'; +import 'package:smooth_app/themes/smooth_theme.dart'; +import 'package:smooth_app/themes/smooth_theme_colors.dart'; +import 'package:smooth_app/themes/theme_provider.dart'; import 'package:smooth_app/widgets/smooth_app_bar.dart'; +import 'package:smooth_app/widgets/smooth_expandable_floating_action_button.dart'; import 'package:smooth_app/widgets/smooth_scaffold.dart'; import 'package:smooth_app/widgets/will_pop_scope.dart'; @@ -80,6 +84,7 @@ class ProductPriceAddPage extends StatefulWidget { class _ProductPriceAddPageState extends State with TraceableClientMixin { final GlobalKey _formKey = GlobalKey(); + final ScrollController _scrollController = ScrollController(); @override Widget build(BuildContext context) { @@ -117,7 +122,11 @@ class _ProductPriceAddPageState extends State ), ], ), + backgroundColor: context.lightTheme() + ? context.extension().primaryLight + : null, body: SingleChildScrollView( + controller: _scrollController, padding: const EdgeInsets.all(LARGE_SPACE), child: Column( children: [ @@ -134,13 +143,15 @@ class _ProductPriceAddPageState extends State key: Key(model.elementAt(i).product.barcode), index: i, ), + const SizedBox(height: LARGE_SPACE), const PriceAddProductCard(), // so that the last items don't get hidden by the FAB const SizedBox(height: MINIMUM_TOUCH_SIZE * 2), ], ), ), - floatingActionButton: FloatingActionButton.extended( + floatingActionButton: SmoothExpandableFloatingActionButton( + scrollController: _scrollController, onPressed: () async => _exitPage( await _mayExitPage( saving: true, @@ -152,6 +163,10 @@ class _ProductPriceAddPageState extends State appLocalizations.prices_send_n_prices( model.length, ), + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 15.0, + ), ), ), ), From 54b9f4010e5c9f8b4b8ea500965a4861e14a150b Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 10 Jan 2025 09:58:27 +0100 Subject: [PATCH 4/5] Use a SmoothFloatingSnackbar on all screens (#6169) --- .../generic_lib/widgets/smooth_snackbar.dart | 38 +++++++++++++++++++ .../lib/pages/offline_data_page.dart | 3 +- .../lib/pages/personalized_ranking_page.dart | 6 ++- .../preferences/user_preferences_rate_us.dart | 4 +- .../common/product_list_item_popup_items.dart | 3 +- .../product/common/product_list_page.dart | 13 ++++--- .../product/common/product_refresher.dart | 18 +-------- .../pages/product/nutrition_page_loaded.dart | 10 ++--- .../lib/pages/search/search_history_view.dart | 3 +- 9 files changed, 64 insertions(+), 34 deletions(-) diff --git a/packages/smooth_app/lib/generic_lib/widgets/smooth_snackbar.dart b/packages/smooth_app/lib/generic_lib/widgets/smooth_snackbar.dart index c400359b4dac..13986e939a41 100644 --- a/packages/smooth_app/lib/generic_lib/widgets/smooth_snackbar.dart +++ b/packages/smooth_app/lib/generic_lib/widgets/smooth_snackbar.dart @@ -35,6 +35,44 @@ class SmoothFloatingSnackbar extends SnackBar { behavior: SnackBarBehavior.floating, ); + SmoothFloatingSnackbar.positive({ + required BuildContext context, + required String text, + super.elevation, + super.padding, + super.width, + super.shape, + super.hitTestBehavior, + super.action, + super.actionOverflowThreshold, + super.showCloseIcon, + super.closeIconColor, + super.animation, + super.onVisible, + super.dismissDirection, + super.clipBehavior = Clip.hardEdge, + Duration? duration, + super.key, + }) : super( + margin: const EdgeInsetsDirectional.all(SMALL_SPACE), + duration: duration ?? + (action != null + ? const Duration(seconds: 10) + : SnackBarDuration.short), + behavior: SnackBarBehavior.floating, + backgroundColor: + context.extension().success, + content: Row( + children: [ + Expanded(child: Text(text)), + const Icon( + Icons.check_circle, + color: Colors.white, + ), + ], + ), + ); + SmoothFloatingSnackbar.error({ required BuildContext context, required String text, diff --git a/packages/smooth_app/lib/pages/offline_data_page.dart b/packages/smooth_app/lib/pages/offline_data_page.dart index 18c648aefed6..3fcee53c5729 100644 --- a/packages/smooth_app/lib/pages/offline_data_page.dart +++ b/packages/smooth_app/lib/pages/offline_data_page.dart @@ -10,6 +10,7 @@ import 'package:smooth_app/database/dao_product_last_access.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/duration_constants.dart'; +import 'package:smooth_app/generic_lib/widgets/smooth_snackbar.dart'; import 'package:smooth_app/helpers/app_helper.dart'; import 'package:smooth_app/pages/product/product_type_extensions.dart'; import 'package:smooth_app/widgets/smooth_app_bar.dart'; @@ -93,7 +94,7 @@ class _OfflineDataPageState extends State { await daoProductLastAccess.deleteAll(); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( + SmoothFloatingSnackbar( content: Text( appLocalizations.deleted_products(totalProductsDeleted), ), diff --git a/packages/smooth_app/lib/pages/personalized_ranking_page.dart b/packages/smooth_app/lib/pages/personalized_ranking_page.dart index cc4a9d31eae8..b7a451cd1e63 100644 --- a/packages/smooth_app/lib/pages/personalized_ranking_page.dart +++ b/packages/smooth_app/lib/pages/personalized_ranking_page.dart @@ -11,6 +11,7 @@ import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/generic_lib/buttons/smooth_large_button_with_icon.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/duration_constants.dart'; +import 'package:smooth_app/generic_lib/widgets/smooth_snackbar.dart'; import 'package:smooth_app/helpers/product_compatibility_helper.dart'; import 'package:smooth_app/pages/product/common/loading_status.dart'; import 'package:smooth_app/pages/product/common/product_list_item_simple.dart'; @@ -67,7 +68,7 @@ class _PersonalizedRankingPageState extends State } if (added != null && added) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( + SmoothFloatingSnackbar( content: Text( appLocalizations.added_to_list_msg, ), @@ -231,7 +232,7 @@ class _PersonalizedRankingPageState extends State onDismissed: (final DismissDirection direction) { _model.dismiss(matchedProduct.barcode); ScaffoldMessenger.of(context).showSnackBar( - SnackBar( + SmoothFloatingSnackbar( content: Text(appLocalizations.product_removed_comparison), duration: SnackBarDuration.medium, ), @@ -250,6 +251,7 @@ class _PersonalizedRankingPageState extends State /// Virtual item in the list: either a product or a status header class _VirtualItem { const _VirtualItem.score(this.score) : status = null; + const _VirtualItem.status(this.status) : score = null; final MatchedScoreV2? score; final MatchedProductStatusV2? status; diff --git a/packages/smooth_app/lib/pages/preferences/user_preferences_rate_us.dart b/packages/smooth_app/lib/pages/preferences/user_preferences_rate_us.dart index 3600c1330ab6..017642788d32 100644 --- a/packages/smooth_app/lib/pages/preferences/user_preferences_rate_us.dart +++ b/packages/smooth_app/lib/pages/preferences/user_preferences_rate_us.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; +import 'package:smooth_app/generic_lib/widgets/smooth_snackbar.dart'; import 'package:smooth_app/helpers/entry_points_helper.dart'; import 'package:smooth_app/helpers/global_vars.dart'; import 'package:smooth_app/pages/preferences/user_preferences_item.dart'; @@ -46,13 +47,12 @@ class UserPreferencesRateUs extends StatelessWidget { final ThemeData themeData = Theme.of(context); ScaffoldMessenger.of(context).showSnackBar( - SnackBar( + SmoothFloatingSnackbar( content: Text( appLocalizations.error_occurred, textAlign: TextAlign.center, style: TextStyle(color: themeData.colorScheme.surface), ), - behavior: SnackBarBehavior.floating, backgroundColor: themeData.colorScheme.onSurface, ), ); diff --git a/packages/smooth_app/lib/pages/product/common/product_list_item_popup_items.dart b/packages/smooth_app/lib/pages/product/common/product_list_item_popup_items.dart index a8e0d2f57cef..f2a3b1d7bc1b 100644 --- a/packages/smooth_app/lib/pages/product/common/product_list_item_popup_items.dart +++ b/packages/smooth_app/lib/pages/product/common/product_list_item_popup_items.dart @@ -7,6 +7,7 @@ import 'package:smooth_app/database/dao_product_list.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart'; +import 'package:smooth_app/generic_lib/widgets/smooth_snackbar.dart'; import 'package:smooth_app/pages/personalized_ranking_page.dart'; import 'package:smooth_app/pages/product/compare_products3_page.dart'; import 'package:smooth_app/pages/product/ordered_nutrients_cache.dart'; @@ -74,7 +75,7 @@ class ProductListItemPopupSideBySide extends ProductListItemPopupItem { if (context.mounted) { if (cache == null) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( + SmoothFloatingSnackbar( content: Text( AppLocalizations.of(context).nutrition_cache_loading_error, ), diff --git a/packages/smooth_app/lib/pages/product/common/product_list_page.dart b/packages/smooth_app/lib/pages/product/common/product_list_page.dart index 5470783ba0d6..8884734af976 100644 --- a/packages/smooth_app/lib/pages/product/common/product_list_page.dart +++ b/packages/smooth_app/lib/pages/product/common/product_list_page.dart @@ -19,6 +19,7 @@ import 'package:smooth_app/generic_lib/duration_constants.dart'; import 'package:smooth_app/generic_lib/loading_dialog.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_app_logo.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_responsive.dart'; +import 'package:smooth_app/generic_lib/widgets/smooth_snackbar.dart'; import 'package:smooth_app/helpers/app_helper.dart'; import 'package:smooth_app/helpers/robotoff_insight_helper.dart'; import 'package:smooth_app/pages/all_product_list_modal.dart'; @@ -409,7 +410,7 @@ class _ProductListPageState extends State } ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar( - SnackBar( + SmoothFloatingSnackbar( content: Text( removed ? appLocalizations.product_removed_list @@ -463,12 +464,12 @@ class _ProductListPageState extends State if (!mounted) { return; } + ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - appLocalizations.product_list_reloading_success_multiple( - products.length, - ), + SmoothFloatingSnackbar.positive( + context: context, + text: appLocalizations.product_list_reloading_success_multiple( + products.length, ), duration: SnackBarDuration.short, ), diff --git a/packages/smooth_app/lib/pages/product/common/product_refresher.dart b/packages/smooth_app/lib/pages/product/common/product_refresher.dart index 1727f39a1d2d..080630f3812c 100644 --- a/packages/smooth_app/lib/pages/product/common/product_refresher.dart +++ b/packages/smooth_app/lib/pages/product/common/product_refresher.dart @@ -15,7 +15,6 @@ import 'package:smooth_app/pages/user_management/login_page.dart'; import 'package:smooth_app/query/product_query.dart'; import 'package:smooth_app/query/search_products_manager.dart'; import 'package:smooth_app/services/smooth_services.dart'; -import 'package:smooth_app/themes/smooth_theme_colors.dart'; /// Refreshes a product on the BE then on the local database. class ProductRefresher { @@ -146,22 +145,9 @@ class ProductRefresher { return false; } if (context.mounted) { - final ThemeData themeData = Theme.of(context); - ScaffoldMessenger.of(context).showSnackBar( - SmoothFloatingSnackbar( - content: Row( - children: [ - Expanded(child: Text(appLocalizations.product_refreshed)), - const Icon( - Icons.check_circle, - color: Colors.white, - ), - ], - ), - backgroundColor: - themeData.extension()!.green, - ), + SmoothFloatingSnackbar.positive( + context: context, text: appLocalizations.product_refreshed), ); } return true; diff --git a/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart b/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart index faca7c3240e2..d29bd2a9efc2 100644 --- a/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart +++ b/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart @@ -10,6 +10,7 @@ import 'package:smooth_app/data_models/up_to_date_mixin.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_card.dart'; +import 'package:smooth_app/generic_lib/widgets/smooth_snackbar.dart'; import 'package:smooth_app/helpers/analytics_helper.dart'; import 'package:smooth_app/helpers/image_field_extension.dart'; import 'package:smooth_app/helpers/product_cards_helper.dart'; @@ -62,10 +63,9 @@ class NutritionPageLoaded extends StatefulWidget { if (context.mounted) { if (cache == null) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - AppLocalizations.of(context).nutrition_cache_loading_error, - ), + SmoothFloatingSnackbar.error( + context: context, + text: AppLocalizations.of(context).nutrition_cache_loading_error, ), ); return; @@ -536,7 +536,7 @@ class _NutritionPageLoadedState extends State return false; } ScaffoldMessenger.of(context).showSnackBar( - SnackBar( + SmoothFloatingSnackbar( // here I cheat and I reuse the only invalid case. content: Text(appLocalizations.nutrition_page_invalid_number), ), diff --git a/packages/smooth_app/lib/pages/search/search_history_view.dart b/packages/smooth_app/lib/pages/search/search_history_view.dart index 6f56e568d3ec..9e4a1a1a7b61 100644 --- a/packages/smooth_app/lib/pages/search/search_history_view.dart +++ b/packages/smooth_app/lib/pages/search/search_history_view.dart @@ -4,6 +4,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:provider/provider.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; +import 'package:smooth_app/generic_lib/widgets/smooth_snackbar.dart'; import 'package:smooth_app/pages/product/common/search_helper.dart'; import 'package:smooth_app/pages/product/common/search_preloaded_item.dart'; @@ -198,7 +199,7 @@ class _SearchItemPasteFromClipboard extends StatelessWidget { onData(data!.text!); } else if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( + SmoothFloatingSnackbar( content: Text(localizations.no_data_available_in_clipboard), ), ); From 13f559484e81d516392c68d3bb6599d8c4d13fab Mon Sep 17 00:00:00 2001 From: Pierre Slamich Date: Fri, 10 Jan 2025 09:58:43 +0100 Subject: [PATCH 5/5] fix: Update app_en.arb (#6168) --- packages/smooth_app/lib/l10n/app_en.arb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index f7fc30d03e1b..c48e186687a9 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -1316,7 +1316,7 @@ } }, "settings_app_app": "Application", - "settings_app_data": "Privacy & monitoring", + "settings_app_data": "Features & Crash monitoring", "settings_app_camera": "Camera", "settings_app_products": "Products", "settings_app_miscellaneous": "Miscellaneous", @@ -1343,7 +1343,7 @@ "@app_haptic_feedback_subtitle": { "description": "SubTitle for the Haptic feedback toggle" }, - "crash_reporting_toggle_title": "Crash reporting", + "crash_reporting_toggle_title": "Report us bugs and crashes", "@crash_reporting_toggle_title": { "description": "Title for the Crash reporting toggle" }, @@ -1351,11 +1351,11 @@ "@crash_reporting_toggle_subtitle": { "description": "SubTitle for the Crash reporting toggle" }, - "send_anonymous_data_toggle_title": "Send anonymous data", + "send_anonymous_data_toggle_title": "Report us feature usage", "@send_anonymous_toggle_title": { "description": "Title for the Send anonymous data toggle" }, - "send_anonymous_data_toggle_subtitle": "When enabled, some anonymous information regarding app usage will be sent to the Open Food Facts servers, so that we can understand how and how much features are used in order to improve them.", + "send_anonymous_data_toggle_subtitle": "When enabled, strictly anonymous information regarding feature usage will be sent to the Open Food Facts servers, so that we can understand how features are used in order to improve them. Otherwise, a 0 id will be sent.", "@send_anonymous_toggle_subtitle": { "description": "SubTitle for the Send anonymous data toggle" }, @@ -3538,4 +3538,4 @@ "@not_applicable_short": { "description": "Acronym for Not Applicable" } -} \ No newline at end of file +}