Giter Site home page Giter Site logo

plante-app-team / plante Goto Github PK

View Code? Open in Web Editor NEW
29.0 1.0 12.0 10.91 MB

Community-based vegan groceries map

Home Page: https://planteapp.com

License: GNU General Public License v3.0

Kotlin 0.01% Ruby 0.13% Swift 0.02% Objective-C 0.01% Dart 99.60% Python 0.24%
vegan veganmap flutter openfoodfacts openstreetmap

plante's People

Contributors

blazern avatar cyclomaticcomplexity1981 avatar korablique avatar verilyanton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

plante's Issues

Put a button into the shop's range page: "Manage suggestions"

Design: https://www.figma.com/file/lHqzwSaWfsBiWNj9iyOaoh/plante-UI?node-id=2194%3A43274
image

The button should:

  • be at the bottom of each of the suggested-products sections of ShopProductRangePage,
  • open a settings subpage for the products suggestions.

The Suggestions Settings Subpage should function similarly to how SettingsCachePage works - the main settings page should have a button "Products suggestions settings", which would open it.

The new settings subpage should have toggles/checkboxes to enable/disable the according suggestions (OFF and Radius suggestions).
Checkboxe's values should be stored in Settings.

When suggestions of a type are disabled (by value stored in Settings), then ShopProductRangePage:

  • shouldn't load the suggestions of that type,
  • shouldn't even try to display them (so that when the suggestions are just disabled and the user returns to ShopProductRangePage, the page would hide already loaded suggestions.

ShopProductRangePage must be covered with tests:

  • ensure disabled suggestions don't load
  • ensure disabled suggestions aren't displayed when they were disabled after they've loaded

Store info of OffProductsManager persistently

We should store the list of products for a country persistently (when the list is loaded user’s country should be taken into account).
We should make a SQLite DB with pairs of “ShopUID” - “product barcode”.
The persistent data should be loaded before the network data.

Both types of data (list of shops and suggested pairs) should have a lifetime - after a month of storage they should be invalidated and then downloaded again.

Separate ProgressBarWithHints into 2 separate widgets

Hints should be at the top:
image

Progress bar should be at the bottom:
image

Figma: https://www.figma.com/file/lHqzwSaWfsBiWNj9iyOaoh/plante-UI?node-id=2194%3A42214

Because now they're separated, they should be in 2 separate widget with similar logic. E.g. the hints widget can be named TimedHints.

We should try to reuse the GradientSpinner as a progress bar widget. To reuse it, make it so that it would accept custom colors and borderRadius in its constructor.
If it's not possible, a new widget should be created with a logic similar to GradientSpinner.

The new progress bar widget should be at the bottom of the page.
TimedHints should be just below the search bar (find Column which contains the search bar in MapPage).

New design should not be applied yet.

Initial implementation of the Profile products lists

Design: https://www.figma.com/file/lHqzwSaWfsBiWNj9iyOaoh/plante-UI?node-id=2109%3A30271

The Profile page should contain a pager with 2 products lists and 2 check-buttons which should allow to switch between the lists.
When lists are switched, the checked button also switches. When a button is checked, lists switch.

The "My products" list should not yet be implemented.
The "History" page should contain same products as ViewedProductsHistoryPage does. ViewedProductsHistoryPage should be removed.

Ensure the products are not loaded when a list is not displayed (use VisibilityDetectorPlante).

First "Where am I" button click behaves not user-friendly

Describe the bug
When user starts the app for the first time and clicks the "Where am I" button, it takes the app too much of time to show user's location, and while app's figuring out the location, it doesn't show any kind of loading spinner, doesn't let the user know it didn't forget about the button press.

To Reproduce
Steps to reproduce the behavior:

  1. Fresh install.
  2. Click "Where am I".
  3. Give permission.
  4. See how long it takes to locate the user.

Expected behavior
The app should either:

  1. Show user's location much faster.
  2. Let the user know loading is taking place (by a spinner of some sort).

The 1st behavior would be much more preferred of course.
Maybe it can be done by:

  1. After the button is pressed request user's last known location and move the map there.
  2. Immediately after request user's current location and move the map there.
    Last known and current locations shouldn't be too far off.

Maybe there's a better way to do that, but it needs to be researched.

Implement profile editing

Design: https://www.figma.com/file/lHqzwSaWfsBiWNj9iyOaoh/plante-UI?node-id=2027%3A30674

Create EditUserDataPage.
When the "Edit profile" button is clicked in the Profile page, the new page should be opened.

The new page should use EditUserDataWidget, created in #99

The new page should has similar logic to what's implemented in #99 - it should allow to edit user's data and send it to the backend when the "Save" button is clicked.

Also, similarly to the Init User page, inserted data should be validated - too short user names shouldn't be allowed.

Display empty shops by default

UPD: Disregard all of the below, just show empty shops by default.


After cold start, when the first shops area is loaded - display empty stores if the loaded area has <5 of shops with products.

Currently map filtering options are managed in lib/ui/map/map_page/map_page_mode_default.dart.
The options are stored in shared preferences, and can be safely moved to a new singleton (and should be).
The singleton should be named MapFiltersManager, its file should be put into the lib/ui/map/map_page dir.

Nearby should be created a new enum MapFilter, with values NOT_EMPTY_SHOPS, SHOPS_WITH_SUGGESTIONS, EMPTY_SHOPS.

MapFiltersManager should have next methods:

/// Whether the [setValue] method was called with `byUser == true`.
Future<bool> wasValueSetByUser(MapFilter filter);

/// Stores value for the filter persistently (into shared prefs)
Future<void> setValue(MapFilter filter, bool value, bool byUser);

/// Returns stored value, or some default value if nothing is stored yet.
Future<bool> getValue(MapFilter filter);

MapFiltersManager should store and retrieve persistent values in the same way map_page_mode_default.dart currently does.
The byUser value should be stored separately for each of the MapFilter entries.

MapFiltersManager should observe the ShopsManager singleton.
When first shops area is loaded, MapFiltersManager should check if MapFilter.EMPTY_SHOPS wasn't set by user yet, and if it wasn't:

  1. Set value to true if the loaded shops area has <5 of shops with products.
  2. Set value to false otherwise.

NOTE: feel free to tweak the description above if needed

Compress images before sending them to Open Food Facts

Feedback:

Nice User — 01/14/2022
Creating new products is really slow for me. I can fill text fields and take pictures normally, but after clicking "submit" it will usually take 3 minutes to upload.

I think it's because of a combination of slow Internet (1Mbps upload) and very large filesizes. It's a bug of a pain in the butt because it means I can't easily scan products. Are there any plans to implement some form of image compression (prior to the upload of a new product)? Or does it already exist and my issue is happening for another reason?

It happens both on my Mi A3 and my Redmi Note 10 Pro - Android 11 for both - and it's been happening since I downloaded the app (i.e. since I joined the server). :P

Nice User — 01/14/2022
(Assuming 16MB/picture and two pictures - one for the front and one for the ingredients - and a stable connection of 1Mbps, it does check out. It's about 4 minutes and 15 seconds)

Uploading 16MB images is not good.

What needs to be done.

Add this package to the app: https://pub.dev/packages/flutter_image_compress
Apply it to the code - compress images before they're sent to Open Food Facts.

Experiment with image sizes and compression levels:

  1. Register in Open Food Facts (if not registered yet).
  2. Find a food product at home with a long ingredients list.
  3. If the product is already in Open Food Facts, delete its ingredients list photo.
  4. Tweak compression level and image scaling in the app, scan product's barcode, take a picture of the ingredients, send it to OFF.
  5. Check if the image is of an appropriate quality - if the ingredients text is clear, easy to read, OFF is able to auto-extract text from the image.
  6. Repeat steps 2-5 until good compression level and target size are found - they have to be low enough to downsize the image, and high enough for the requirements in the step №5 to be satisfied.
  7. Make a Pull Request.

Map progress bar forces other UI elements to move

Map progress bar is a part of a column aligned to widget's bottom, because of this it forces other UI elements (which are in the same column) to move when it appears and disappears.

It looks janky and should be fixed.

To fix it, the progress bar should be put into some some Stack, completely separate from the Column described above. And should be aligned to bottom.

The resulted widgets structure probably will be similar to the structure which existed back then when the progress bar was aligned to top.

"My products" list in the Profile page

Use the ContributionsStorage class to display the "My products" list.

While the products are being still loaded, show a spinner.
On loading errors, display error text with a Retry button.

Ensure the products are not loaded when a list is not displayed (use VisibilityDetectorPlante).

Transform map filters into a horizontal list

Working prototype: blazern@9e8c7b9
Design: https://www.figma.com/file/lHqzwSaWfsBiWNj9iyOaoh/plante-UI?node-id=2194%3A42059
image

The CheckButtonPlante widget should probably be used - it was created precisely to be a "checkbox, but it's a button".
Although current design of CheckButtonPlante does not match the design of new buttons in Figma.
To solve it, the CheckButtonPlante class should be changed to be more customizable - this way we would be able to use this widget for new filters and still use it where it's used at the moment.

Behavior:

  • The "Only shops with .." buttons should be named "Show shops with .." (not only).
  • When "All shops" button is checked (pressed), all other buttons should get unchecked.
  • When an "Only" button is checked, the "All shops" button should get unchecked.
  • The "Only" buttons are friends to each other - all of them can be checked simultaneously (they don't uncheck each other).

Fetching offshops in great britain is not working. the countrycode is GB while Off uses UK

Describe the bug
When we try to fetch offshops while we are in GB the request fails. We use countrycode GB instead while OFF expects a uk.openfoodfacts.org/shops

To Reproduce
Steps to reproduce the behavior:

  1. Enable showOffProducts in country_table.dart for Great Britain
  2. open the app while in greate britain
  3. check logs

Expected behavior
Offshops should be loaded for UK

Add to History all scanned products

Add to History all scanned products, even if the Product Display Page wasn't opened for them.
If the scanned product does not has all data yet, still add it to History.
When the Product Display Page is opened, still add the product to History - History will have 2 sources of products.

Do not prompt user to enable geolocation too often

Currently if an Android user uses the app without enabled geolocation services, the app prompts user to enable the services each time app's code tries to obtain user's current location.
The prompt dialog is shown by the OS.

This is bad - makes using the app harder.

To fix it, the UserLocationManager.currentPosition() function should accept a {required bool userRequest} parameter, which would signal whether the position was requested by user directly (e.g. they clicked the "Where am I" button), or by other places.

When userRequest == false, UserLocationManager should check if geolocation services are enabled on devices (not the permission, but the services), and return null if they're disabled.

NOTE: it's possible the prompt wouldn't be shown if not-the-best accuracy would be requested from the OS.
If that's so, instead of returning null the app should request such an accuracy from the OS (see GeolocatorWrapper.getCurrentPosition).

In ViewedProductsHistoryPage don't load products until the page is opened

Presently ViewedProductsHistoryPage loads products immediately after it's created. And the page can have a lot of products in it.

The page is rare opened though, but causes a lot of loadings on startups.

The products should start loading only when the page is opened. To achieve it, VisibilityDetectorPlante should be used.

Extract edit-user-name widget, add avatar updating to it

Extract edit-user-name widget into a EditUserDataWidget, just like langs editing is extracted into UserLangsWidget.
Just like UserLangsWidget, EditUserDataWidget should not send data to the backend itself. It should be only the representative of data added to it, accept callbacks and/or controllers (like TextField does).

When the avatar in EditUserDataWidget is clicked, the app should initiate photo selection process. The primary goal of such selection is to let user select a photo from their phone's gallery, not to take a new picture.

Once the photo is taken, ImageCropPage should immediately be opened. ImageCropPage must force the cropped area to be a square, user should see it's a square.

Once the photo is cropped, it should be downsized (if too big) according to the size figured out in plante-app-team/plante_server#5.

Once the photo is downsized, it should be set as the selected image of EditUserDataWidget.

Maybe it makes sense to create a AvatarSelectionHelper, which would: initiate photo selection, cropping, then would downsize the image.

When user clicks "Done" on the page after the avatar is chosen, the avatar is sent to the backend. The Backend class should support that.

Avatar selection is optional, not mandatory. This should be explicitly mentioned in the UI.

Connect map filters with suggestions enable/disable settings

This issue depends on: #65
See also: #67

The filters are managed by MapPageModeDefault.

The map filters for suggestions must be removed - instead of 2 separate filters for OFF and Radius suggestions, there should be just 0 filter-checkmark saying "Products seen in similar stores".

The "Stores with products" filter now performs the work previously done by the 2 removed filters - when "Stores with products" is checked, then shops with suggested products are shown on the map (and not shown if it's not checked).

MapPageModeDefault.filter should use values from settings - it should filter out shops (with suggestions) that are disabled by the settings (#65)

Of course, MapPageModeDefault.filter shouldn't filter out a shop with suggestions if the shop satisfies some other condition (the empty/not-empty filtering).

The changes must be covered with tests in map_page_map_filters_test.dart.

Add user-shop interactions persistent storage

Main usage:
When a user clicks “No it’s not sold here” on a suggested products, we should remove the suggested product from the list and stop asking the user about this product in this shop. For this, we should make an SQLite DB.

The DB should be made with keeping in mind its usefulness for other purposes. For example, in the future we should also store information about whether the user clicked the “It’s (not) sold here” button of main products list to not ask the user about same product again until it’s time.

Implement the bottom's bar Plus button behavior

Design: https://www.figma.com/file/lHqzwSaWfsBiWNj9iyOaoh/plante-UI?node-id=2109%3A30346

When pressed, shows a popup with "Add a product" and "Add a store" buttons.
When the "Add a product" button is clicked, barcode-scanning page is opened.
When the "Add a store" button is clicked, map is opened and the mode is switched to MapPageModeCreateShop.

Tests:

  1. While Map is opened, click Plus, click "Add a product", ensure the Scan page is opened, scan a barcode of a not-existing product, start adding it, ensure the Init Product page is opened.
  2. While Scan page is opened, click Plus, click "Add a store", ensure Map is opened, proceed to add a shop, ensure it's added.

Ensure cropped product image is not smaller than min size

If the image is smaller than min size, Open Food Facts rejects it, the app shows an error to the user.
This confuses users who want to send an image of a product to OFF.

It's not a very easy task because it requires the developer:

  • to be familiar with how Isolates in Dart works (or to learn it)

  • to investigate how image size can be obtained from either its binary data or from the image on the files system

  • ImageCropPage should accept min Size.

  • Min size for Open Food Facts is: width = 640, height = 160.

  • When user clicks "Done" in ImageCropPage, the page should check the image size and show a user-friendly message if it's too small.

  • Tests are appreciated, but at the same time it's not going to be easy to cover this functionality with tests, so they're not necessary.

Use Fuzzy Compare when searching for OFF shops by names

Problem
Shops in OFF can have slightly wrong names, and OSM can have slightly wrong names for shops.
When searching for products suggestions for a certain store, we should compare names not directly, but with fuzzy compare.

For example, if stores chain is named "Albert Heijn", and this store has products both in OFF (OffShopsManager) and in Plante (RadiusProductsSuggestionsManager), then all stores with very similar names should get products suggestions from both OFF and Plante.

A couple of examples of slightly differently named "Albert Heijn":

  • Albert Hein
  • Albert Heijn Central
  • Àlbert Heijn

Solution description

  • A shops_comparator.dart file should be created in lib/outside/products/suggestions/.
  • It should have a similar function to: bool areShopsNamesSimilar(String name1, String name2).
  • The areShopsNamesSimilar function should either:
    • use the existing FuzzySearch class,
    • use the fuzzywuzzy library directly,
    • or the FuzzySearch should be updated with new functionality which the areShopsNamesSimilar would use.
  • The areShopsNamesSimilar function should be used to compare stores in next places:
    • the RadiusProductsSuggestionsManager class (Plante's radius based suggestions),
    • the OffShopsListWrapper._backgroundFindAppropriateShop method (OFF suggestions).
  • New tests must cover:
    • the new comparing function (areShopsNamesSimilar),
    • the RadiusProductsSuggestionsManager class (to ensure it uses the function),
    • the OffShopsListWrapper class (to ensure it uses the function).

Add an ability to see and copy product barcode

  • In DisplayProductPage add a new item into the page's top-right menu: "See barcode".
  • When clicked, a dialog should be shown, its text should be the product's barcode.
  • The barcode should be selectable.
  • The dialog should have a "Copy to the clipboard" button which does what it says.
  • The feature should be covered with tests. Similar tests - 'send report' in display_product_page_test.dart (opens the menu and clicks an item in it).

Fix freezes at large cities

Steps to reproduce:

  1. Start the app, scroll to Moscow, load its territory.
  2. Scroll the map to another city.
  3. Close the app, start the app again.
  4. Scroll to Moscow - when it starts loading it freezes for quite some time.

The problem is most likely in RadiusProductsSuggestionsManager.getSuggestedBarcodesByRadius - it's code is not optimized for cities with enormous amounts of shops.
As much as possible of the code should be moved to a background isolate.

Let user enable products suggestions back from ShopProductRangePage

This issue depends on: #65
See also: #66

When all types of suggested products are disabled, ShopProductRangePage should display a "Products suggestions settings" button at the bottom of the list.
The button should open products suggestions settings subpage (added in #65).

If ShopProductRangePage didn't have any suggestions loaded when it was opened, then user opened the settings by the button, enabled suggestions and returned back to ShopProductRangePage - it should load the enabled suggestions.

The button should be covered with tests.

Label on products in product lists

What does "similar store" means on the labels of products in ShopProductRangePage? ("Seen in similar store")

The word "similar" doesn't give an idea that the product was seen in a store with the same name.
It looks like it means "seen in a store, that visually looks similar" or something like that.

We should try the label: "Seen in other <storename> stores".

Apply new design from Figma to ShopProductRangePage

Design: https://www.figma.com/file/lHqzwSaWfsBiWNj9iyOaoh/plante-UI?node-id=2194%3A43274

No white background for the header and the titles:
image
(Probably 197c86a need to be partially reverted)

The button should not yet be added:
image

The header should be scrollable - when user scrolls products, the header should be scrolled together with them, so that more products would fit to the screen.
image

An "up" FAB should appear when the list is scrolled down a bit, and disappear when the list is being scrolled back up. When button is clicked, the list should scroll back to the top (preferably with animation).
image

Create a ContributionsStorage class

Create a ContributionsStorage class.

The class should be lazy - it should retrieve list of user's contributions from the backend (using the user_contributions_data cmd (plante-app-team/plante_server#7)) only when asked for the first time.

After the class is (lazily) inited, it should start observing ShopsManager, and add to its local cache products which the user adds to shops.
It also should add to its local cache products created by the user.

Support user avatar deletion

When user clicks the appropriate button, send a cmd to the server to delete user's avatar (through UserAvatarManager).
On success, delete the avatar locally.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.