Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: Ingredients Page #707

Merged
merged 41 commits into from
Mar 27, 2022
Merged

feat: Ingredients Page #707

merged 41 commits into from
Mar 27, 2022

Conversation

justinmc
Copy link
Contributor

@justinmc justinmc commented Dec 3, 2021

Related issues

My attempt at the ingredients input page. I'm struggling to put together a full PR, so I'll plan to ask a bunch of questions about the mocks, process, etc. and point people to this PR.

How it looks currently

Mocks I've been using

From Figma: https://www.figma.com/file/WXBmNSPweKqXpoSNRSQWDc/Product-Addition---Nutrition?node-id=0%3A1
And from the issues:

Changes from this PR

  1. I've added an "Edit Ingredients" button that navigates to the new EditIngredientsPae inside of the Ingredients AttributeListExpandable. I'm sure this isn't right, but it kind of looked like this mock? What is the correct way to access the EditIngredientsPage? (Code is hacky here because I'm assuming it needs to be changed)
Mock Mine
Screen Shot 2021-12-03 at 11 47 10 AM Screen Shot 2021-12-03 at 11 46 01 AM
  1. Clicking on that "Edit Ingredients" button goes to the EditIngredientsPage. I made it look similar to the Figma nutrition editing mock. Is that right? Pictured at the very top of this PR description.

That's it! Is there anywhere else that's supposed to link to the EditIngredientsPage or anything else I'm missing in this flow? Below I have many other specific questions for me to move forward.

Questions

  • Process

    • What's the process for getting text localized, or introducing new strings?
  • Design/product

    • Tapping the ingredients image at the top of the product page goes to a photo view of the ingredients. Should that remain, or somehow be combined with this "edit ingredients" flow? Am I missing any part of the flow/navigation for editing ingredients? Screen Shot 2021-12-03 at 10 22 19 AM

    • What is the light grey text that is seen below the ingredients TextField in the mock? Screen Shot 2021-12-03 at 11 57 20 AM

    • On my EditIngredientsPage pictured farther above, I used BoxFit.cover for the image fit, which results in wide images like the one pictured being cut off. Is that ok, or should I use BoxFit.contain or some other layout?

  • Engineering

    • Running the app locally, if I upload a product image via one of the ImageUploadCards, it doesn't persist. Navigating out of the product and back again, the new product image will be gone. Is that a bug or is that how the development server works?
    • How do I edit a product? Specifically, I need to modify the ingredients. Do I call OpenFoodAPIClient.saveProduct? If so, which of the many ingredient-related fields in Product do I actually need to set?

@justinmc justinmc self-assigned this Dec 3, 2021
@justinmc justinmc requested a review from jasmeet0817 December 3, 2021 21:44
@jasmeet0817
Copy link
Contributor

Related issues: #512 #107

My attempt at the ingredients input page. I'm struggling to put together a full PR, so I'll plan to ask a bunch of questions about the mocks, process, etc. and point people to this PR.

How it looks currently:

Mocks I've been using

From Figma: https://www.figma.com/file/WXBmNSPweKqXpoSNRSQWDc/Product-Addition---Nutrition?node-id=0%3A1 And from the issues:

Changes from this PR

  1. I've added an "Edit Ingredients" button that navigates to the new EditIngredientsPae inside of the Ingredients AttributeListExpandable. I'm sure this isn't right, but it kind of looked like this mock? What is the correct way to access the EditIngredientsPage? (Code is hacky here because I'm assuming it needs to be changed)

Mock Mine
Screen Shot 2021-12-03 at 11 47 10 AM Screen Shot 2021-12-03 at 11 46 01 AM
2. Clicking on that "Edit Ingredients" button goes to the EditIngredientsPage. I made it look similar to the Figma nutrition editing mock. Is that right? Pictured at the very top of this PR description.

That's it! Is there anywhere else that's supposed to link to the EditIngredientsPage or anything else I'm missing in this flow? Below I have many other specific questions for me to move forward.

Questions

  • Process

    • What's the process for getting text localized, or introducing new strings?

I think you just update this file with a new string.

packages/smooth_app/lib/l10n/app_en.arb

See example: #647

  • Design/product

Working with PM/UX to get this straightened out by this week.

  • Tapping the ingredients image at the top of the product page goes to a photo view of the ingredients. Should that remain, or somehow be combined with this "edit ingredients" flow? Am I missing any part of the flow/navigation for editing ingredients? Screen Shot 2021-12-03 at 10 22 19 AM

  • What is the light grey text that is seen below the ingredients TextField in the mock? Screen Shot 2021-12-03 at 11 57 20 AM

  • On my EditIngredientsPage pictured farther above, I used BoxFit.cover for the image fit, which results in wide images like the one pictured being cut off. Is that ok, or should I use BoxFit.contain or some other layout?

  • Engineering

    • Running the app locally, if I upload a product image via one of the ImageUploadCards, it doesn't persist. Navigating out of the product and back again, the new product image will be gone. Is that a bug or is that how the development server works?

Oh I'm not sure, I think it might actually be a bug, I tried it using the smoothie app on my phone and the behavior was as you described.

I created #709

  • How do I edit a product? Specifically, I need to modify the ingredients. Do I call OpenFoodAPIClient.saveProduct? If so, which of the many ingredient-related fields in Product do I actually need to set?

Stephane's response
Product product = Product( barcode: '4250752200784', lang: OpenFoodFactsLanguage.GERMAN, ingredientsText: 'Johanneskraut, Maisöl, Phospholipide (Sojabohnen, Ponceau 4R)', ); Status status = await OpenFoodAPIClient.saveProduct( TestConstants.TEST_USER, product, );

@teolemon teolemon changed the title WIP Ingredients Page WIP - Ingredients Page Dec 18, 2021
@teolemon teolemon added the Product addition The easier it is to add a product and get Nutri-Score, Eco-Score, the happier the users. label Dec 18, 2021
@teolemon teolemon changed the title WIP - Ingredients Page WIP - feat: Ingredients Page Dec 27, 2021
@teolemon teolemon linked an issue Jan 15, 2022 that may be closed by this pull request
5 tasks
@github-actions github-actions bot removed the Product addition The easier it is to add a product and get Nutri-Score, Eco-Score, the happier the users. label Feb 3, 2022
@justinmc justinmc requested a review from a team as a code owner March 11, 2022 20:00
@justinmc justinmc requested a review from M123-dev March 11, 2022 20:02
@justinmc
Copy link
Contributor Author

@M123-dev I think this is ready to be reviewed and get merged. I put everything behind a dev mode flag so it shouldn't break anything. It just hides a button in the ingredient knowledge panel that looks like this:

Screen Shot 2022-03-11 at 11 45 56 AM

I may be missing some coding style things, or using the appropriate themes or constants in places, let me know what I can clean up.

Copy link
Contributor

@monsieurtanuki monsieurtanuki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @justinmc!
Many things here and there that could be refactored.
The most worrying thing is that I have the impression that the final button ("confirm") does nothing.
Please have a look at my comments.

@@ -336,6 +336,10 @@
},
"ingredients": "Ingredients",
"@ingredients": {},
"ingredients_editing_instructions": "Conserver l'ordre, indiquer le % lorsqu'il est précisé, séparer par une virgule ou -, utiliser les () pour les ingrédients d’un ingrédient, indiquer les allergènes entre _.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be in English instead of French.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got this French text from a mock. I'll give it my own best English translation.

Comment on lines 8 to 9
//import 'package:openfoodfacts/model/Product.dart';
//import 'package:smooth_app/data_models/product_preferences.dart';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, thanks.

final bool isUploaded = await uploadCapturedPicture(
context,
barcode: widget.product
.barcode!, //Probably throws an error, but this is not a big problem when we got a product without a barcode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove that comment: it's widely assumed that we don't care about barcode-less products.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I think I got this code originally from image_upload_card.dart but it's since changed.

Comment on lines 145 to 148
final OpenFoodFactsLanguage? language = ProductQuery.getLanguage();
if (language == null) {
throw Exception("Couldn't find language.");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just assume it is not null and put a !.

});
}

Future<void> _getImage() async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should comment and make clear that this method throws exceptions from which an error message will be displayed.
As those messages will be displayed, they should be localized.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only a generic error message is shown to the user, and that one is already localized (ingredients_editing_image_error).

Comment on lines 308 to 311
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
if (!hasImage)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, it would be easier to read with something like return hasImage ? Row(...) : Row(...).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and pulled out a variable for the Stack children.

onPressed: getImage,
child: const Icon(Icons.refresh),
),
if (hasImage) const SizedBox(width: 12.0),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use MEDIUM_SPACE from design_constants.dart instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I figured something like that file existed but never noticed it.

Comment on lines 331 to 332
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The colors should match the user theme.

tooltip: 'Confirm',
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
onPressed: () {},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing happens here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, should return to the previous page.

Flexible(
flex: 1,
child: Container(
height: 400.0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does 400 come from? Please add a TODO if it's a temporary guess or use a constant from design_constants.dart.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, it's irrelevant now, it's sized by the Flexible above. Will remove it.

@teolemon teolemon requested a review from g123k March 16, 2022 12:22
if (ingredients == null) {
return '';
}
String string = '';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also a StringBuffer would be much better here, since you concatenate multiple strings

Comment on lines 46 to 53
for (int i = 0; i < ingredients.length; i += i) {
final Ingredient ingredient = ingredients[i];
if (i == ingredients.length - 1) {
string += ingredient.toString();
} else {
string += ', $ingredient';
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mm or maybe directly, the join(', ') method?

@justinmc
Copy link
Contributor Author

@g123k @monsieurtanuki Thanks for the review! I think I've responded to everything.

Copy link
Contributor

@monsieurtanuki monsieurtanuki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @justinmc, it looks better that way!
Still I have micro-comments that you can read.
Regarding the use of LoadingDialog I cannot really say what is expected precisely for this app UX-wise, I can only say the way I expect an app to behave (I'm old-fashioned). Besides, as there are recent open issues regarding offline product edit I guess whatever you could code here will soon be affected, so we should not put too much attention on details.

? <Widget>[
FloatingActionButton.small(
tooltip: 'Retake photo',
backgroundColor: Theme.of(context).buttonTheme.colorScheme!.background,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you could create and reuse a variable with Theme.of(context).buttonTheme.colorScheme!.

FloatingActionButton.small(
tooltip: 'Confirm',
backgroundColor: Theme.of(context).buttonTheme.colorScheme!.primary,
foregroundColor: Theme.of(context).buttonTheme.colorScheme!.onBackground,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it rather be onPrimary?

return Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all you "personal" paddings (like 16.0) and use constants from design_constants.dart instead.

}
}

// The actions for the page in a row of FloatingActionButtons.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here a /// comment makes more sense than a mere //.

@@ -336,6 +336,10 @@
},
"ingredients": "Ingredients",
"@ingredients": {},
"ingredients_editing_instructions": "Keep the original order. Indicate the percentage when specified. Separate with a comma or hyphen, use parentheses for ingredients of an ingredient, and indicate allergens between underscores.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you could provide values for app_fr.arb too.

this.barcode,
}) : super(key: key);

final String? barcode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of this barcode? If there's a clear use-case where it should not be product.barcode, please add a comment; if not, please remove this field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I think I had forgotten to remove this when I added product to the parameters.

});
}

Future<void> _onTapGetImage() async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about LoadingDialog here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's being used when I call out to picture_capture_helper and product_refresher here (see this comment and the video there).

Comment on lines 129 to 130
barcode: widget.product
.barcode!,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange format!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why I did that 😁

@justinmc justinmc changed the title WIP - feat: Ingredients Page feat: Ingredients Page Mar 27, 2022
@justinmc justinmc merged commit ce030c2 into develop Mar 27, 2022
@justinmc justinmc deleted the edit-ingredients branch March 27, 2022 22:13
@justinmc
Copy link
Contributor Author

Thanks for all the help on this PR! 🎉

@teolemon
Copy link
Member

Thanks @justinmc I've just triggered the playstore alpha build 🎉

@M123-dev
Copy link
Member

Thanks @justinmc, looking foreward to testing it out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Implement Ingredients input
6 participants