Skip to content

Commit

Permalink
feat: Instant refresh views (#2901)
Browse files Browse the repository at this point in the history
* instant refresh views

* instantly update the state for all field changes

* documentation correction

* function refactor

* efficient way to merge the changes into chached P

* updated method for edit ingredients page

* simple input page refactored

* add missing data on nutritionpageloaded

* remove un nessary try catch and modularise
add_basic_details_page

* fix for ocr_packaging_helper.dart

* Refactor and suggested changes on pr

Co-authored-by: Abu Ghalib <abughalib@users.noreply.github.com>

Co-authored-by: Abu Ghalib <abughalib@users.noreply.github.com>
  • Loading branch information
AshAman999 and abughalib authored Sep 6, 2022
1 parent 54eae2b commit 0d2be11
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 98 deletions.
52 changes: 24 additions & 28 deletions packages/smooth_app/lib/pages/product/add_basic_details_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:openfoodfacts/utils/CountryHelper.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/cards/product_cards/product_image_carousel.dart';
import 'package:smooth_app/data_models/up_to_date_product_provider.dart';
import 'package:smooth_app/database/dao_product.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
Expand Down Expand Up @@ -51,11 +52,22 @@ class _AddBasicDetailsPageState extends State<AddBasicDetailsPage> {
_brandNameController.text = _product.brands ?? '';
}

/// Returns a [Product] with the values from the text fields.
Product _getChangedProduct(Product product) {
product.productName = _productNameController.text;
product.quantity = _weightController.text;
product.brands = _brandNameController.text;
return product;
}

@override
Widget build(BuildContext context) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final Size size = MediaQuery.of(context).size;
final LocalDatabase localDatabase = context.read<LocalDatabase>();
final UpToDateProductProvider provider =
context.read<UpToDateProductProvider>();
final DaoProduct daoProduct = DaoProduct(localDatabase);
return SmoothScaffold(
appBar: AppBar(
title: Text(appLocalizations.basic_details),
Expand Down Expand Up @@ -135,12 +147,15 @@ class _AddBasicDetailsPageState extends State<AddBasicDetailsPage> {
if (!_formKey.currentState!.validate()) {
return;
}
final Product inputProduct = Product(
productName: _productNameController.text,
quantity: _weightController.text,
brands: _brandNameController.text,
Product inputProduct = Product(
barcode: _product.barcode,
);
inputProduct = _getChangedProduct(inputProduct);
final Product? cachedProduct =
await daoProduct.get(_product.barcode!);
if (cachedProduct != null) {
_getChangedProduct(cachedProduct);
}
final String uniqueId = UniqueIdGenerator.generateUniqueId(
_product.barcode!, BASIC_DETAILS);
final BackgroundOtherDetailsInput
Expand All @@ -160,29 +175,10 @@ class _AddBasicDetailsPageState extends State<AddBasicDetailsPage> {
uniqueId: uniqueId,
),
);

final DaoProduct daoProduct = DaoProduct(localDatabase);
final Product? product = await daoProduct.get(
_product.barcode!,
);
// We go and chek in the local database if the product is
// already in the database. If it is, we update the fields of the product.
//And if it is not, we create a new product with the fields of the _product
// and we insert it in the database. (Giving the user an immediate feedback)
if (product == null) {
daoProduct.put(Product(
barcode: _product.barcode,
productName: _productNameController.text,
brands: _brandNameController.text,
quantity: _weightController.text,
lang: ProductQuery.getLanguage(),
));
} else {
product.productName = _productNameController.text;
product.brands = _brandNameController.text;
product.quantity = _weightController.text;
daoProduct.put(product);
}
final Product upToDateProduct =
cachedProduct ?? inputProduct;
await daoProduct.put(upToDateProduct);
provider.set(upToDateProduct);
localDatabase.notifyListeners();
if (!mounted) {
return;
Expand All @@ -195,7 +191,7 @@ class _AddBasicDetailsPageState extends State<AddBasicDetailsPage> {
duration: SnackBarDuration.medium,
),
);
Navigator.pop(context, product);
Navigator.pop(context, upToDateProduct);
},
),
),
Expand Down
47 changes: 18 additions & 29 deletions packages/smooth_app/lib/pages/product/edit_ingredients_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,9 @@ class _EditOcrPageState extends State<EditOcrPage> {

Future<void> _onSubmitField() async {
setState(() => _updatingText = true);

try {
await _updateText(_controller.text);
} catch (error) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
_showError(_helper.getError(appLocalizations));
}

final UpToDateProductProvider provider =
context.read<UpToDateProductProvider>();
await _updateText(_controller.text, provider);
setState(() => _updatingText = false);
}

Expand Down Expand Up @@ -129,18 +124,25 @@ class _EditOcrPageState extends State<EditOcrPage> {
}
}

Future<bool> _updateText(final String text) async {
final Product minimalistProduct =
_helper.getMinimalistProduct(_product, text);
Future<bool> _updateText(
final String text, UpToDateProductProvider provider) async {
final LocalDatabase localDatabase = context.read<LocalDatabase>();
final DaoProduct daoProduct = DaoProduct(localDatabase);
Product changedProduct = Product(barcode: _product.barcode);
Product? cachedProduct = await daoProduct.get(_product.barcode!);
if (cachedProduct != null) {
cachedProduct = _helper.getMinimalistProduct(cachedProduct, text);
}
changedProduct = _helper.getMinimalistProduct(changedProduct, text);
final String uniqueId =
UniqueIdGenerator.generateUniqueId(_product.barcode!, INGREDIENT_EDIT);
final BackgroundOtherDetailsInput backgroundOtherDetailsInput =
BackgroundOtherDetailsInput(
processName: PRODUCT_EDIT_TASK,
uniqueId: uniqueId,
barcode: minimalistProduct.barcode!,
barcode: changedProduct.barcode!,
languageCode: ProductQuery.getLanguage().code,
inputMap: jsonEncode(minimalistProduct.toJson()),
inputMap: jsonEncode(changedProduct.toJson()),
user: jsonEncode(ProductQuery.getUser().toJson()),
country: ProductQuery.getCountry()!.iso2Code,
);
Expand All @@ -151,22 +153,9 @@ class _EditOcrPageState extends State<EditOcrPage> {
),
);

// ignore: use_build_context_synchronously
final LocalDatabase localDatabase = context.read<LocalDatabase>();
final DaoProduct daoProduct = DaoProduct(localDatabase);
final Product? localProduct =
await daoProduct.get(minimalistProduct.barcode!);
// We go and chek in the local database if the product is
// already in the database. If it is, we update the fields of the product.
//And if it is not, we create a new product with the fields of the minimalistProduct
// and we insert it in the database. (Giving the user an immediate feedback)
if (localProduct != null) {
localProduct.ingredientsText = minimalistProduct.ingredientsText;
await daoProduct.put(localProduct);
} else {
await daoProduct.put(minimalistProduct);
}

final Product upToDateProduct = cachedProduct ?? changedProduct;
await daoProduct.put(upToDateProduct);
provider.set(upToDateProduct);
localDatabase.notifyListeners();
if (!mounted) {
return false;
Expand Down
15 changes: 8 additions & 7 deletions packages/smooth_app/lib/pages/product/nutrition_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,14 @@ class NutritionContainer {
(!_added.contains(nutrientId));
}

/// Returns a [Product] with only nutrients data.
Product getProduct() => Product(
barcode: _barcode,
noNutritionData: noNutritionData,
nutriments: _getNutriments(),
servingSize: _servingSize,
);
/// Returns a [Product] with changed nutrients data.
Product getProduct(Product product) {
product.barcode = _barcode;
product.noNutritionData = noNutritionData;
product.nutriments = _getNutriments();
product.servingSize = _servingSize;
return product;
}

void copyUnitsFrom(final NutritionContainer other) =>
_units.addAll(other._units);
Expand Down
43 changes: 23 additions & 20 deletions packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:openfoodfacts/utils/CountryHelper.dart';
import 'package:openfoodfacts/utils/UnitHelper.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/data_models/up_to_date_product_provider.dart';
import 'package:smooth_app/database/dao_product.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
Expand Down Expand Up @@ -69,7 +70,7 @@ class _NutritionPageLoadedState extends State<NutritionPageLoaded> {
void initState() {
super.initState();
_product = widget.product;
_nutritionContainer = _getFreshContainer();
_nutritionContainer = _getFreshContainer(widget.product);
_numberFormat = NumberFormat('####0.#####', ProductQuery.getLocaleString());
_noNutritionData = _product.noNutritionData ?? false;
}
Expand Down Expand Up @@ -454,13 +455,13 @@ class _NutritionPageLoadedState extends State<NutritionPageLoaded> {
_noNutritionData,
);

Product? _getChangedProduct() {
Product? _getChangedProduct(Product product) {
if (!_formKey.currentState!.validate()) {
return null;
}
// We use a separate fresh container here.
// If something breaks while saving, we won't get a half written object.
final NutritionContainer output = _getFreshContainer();
final NutritionContainer output = _getFreshContainer(product);
// we copy the values
for (final String key in _controllers.keys) {
final TextEditingController controller = _controllers[key]!;
Expand All @@ -470,12 +471,12 @@ class _NutritionPageLoadedState extends State<NutritionPageLoaded> {
output.noNutritionData = _noNutritionData;
// we copy the units
output.copyUnitsFrom(_nutritionContainer);
return output.getProduct();
return output.getProduct(product);
}

NutritionContainer _getFreshContainer() => NutritionContainer(
NutritionContainer _getFreshContainer(Product product) => NutritionContainer(
orderedNutrients: widget.orderedNutrients,
product: _product,
product: product,
);

/// Exits the page if the [flag] is `true`.
Expand All @@ -495,6 +496,9 @@ class _NutritionPageLoadedState extends State<NutritionPageLoaded> {
}
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final LocalDatabase localDatabase = context.read<LocalDatabase>();
final UpToDateProductProvider provider =
context.read<UpToDateProductProvider>();
final DaoProduct daoProduct = DaoProduct(localDatabase);
if (!saving) {
final bool? pleaseSave = await showDialog<bool>(
context: context,
Expand All @@ -519,7 +523,16 @@ class _NutritionPageLoadedState extends State<NutritionPageLoaded> {
return true;
}
}
final Product? changedProduct = _getChangedProduct();

final Product? changedProduct =
_getChangedProduct(Product(barcode: widget.product.barcode));
Product? cachedProduct = await daoProduct.get(
_product.barcode!,
);
if (cachedProduct != null) {
cachedProduct = _getChangedProduct(_product);
}

if (changedProduct == null) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
Expand Down Expand Up @@ -550,19 +563,9 @@ class _NutritionPageLoadedState extends State<NutritionPageLoaded> {
uniqueId: uniqueId,
),
);
final DaoProduct daoProduct = DaoProduct(localDatabase);
final Product? product = await daoProduct.get(
_product.barcode!,
);
// We go and chek in the local database if the product is
// already in the database. If it is, we update the fields of the product.
//And if it is not, we create a new product with the fields of the _product
// and we insert it in the database. (Giving the user an immediate feedback)
if (product != null) {
product.servingSize = changedProduct.servingSize;
product.nutriments = changedProduct.nutriments;
await daoProduct.put(product);
}
final Product upToDateProduct = cachedProduct ?? changedProduct;
await daoProduct.put(upToDateProduct);
provider.set(upToDateProduct);
localDatabase.notifyListeners();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ class OcrIngredientsHelper extends OcrHelper {
String getText(final Product product) => product.ingredientsText ?? '';

@override
Product getMinimalistProduct(final Product product, final String text) =>
Product(
barcode: product.barcode,
ingredientsText: text,
);
Product getMinimalistProduct(final Product product, final String text) {
product.ingredientsText = text;
return product;
}

@override
String? getImageUrl(final Product product) => product.imageIngredientsUrl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ class OcrPackagingHelper extends OcrHelper {
String getText(final Product product) => product.packaging ?? '';

@override
Product getMinimalistProduct(final Product product, final String text) =>
Product(
barcode: product.barcode,
packaging: text,
);
Product getMinimalistProduct(Product product, final String text) {
product.packaging = text;
return product;
}

@override
String? getImageUrl(final Product product) => product.imagePackagingUrl;
Expand Down
23 changes: 19 additions & 4 deletions packages/smooth_app/lib/pages/product/simple_input_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:openfoodfacts/utils/CountryHelper.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/data_models/up_to_date_product_provider.dart';
import 'package:smooth_app/database/dao_product.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';
Expand Down Expand Up @@ -44,7 +46,6 @@ class SimpleInputPage extends StatefulWidget {

class _SimpleInputPageState extends State<SimpleInputPage> {
final List<TextEditingController> _controllers = <TextEditingController>[];

@override
void initState() {
super.initState();
Expand Down Expand Up @@ -149,6 +150,14 @@ class _SimpleInputPageState extends State<SimpleInputPage> {
/// or have we clicked on the "save" button?
Future<bool> _mayExitPage({required final bool saving}) async {
final Product changedProduct = Product(barcode: widget.product.barcode);
final LocalDatabase localDatabase = context.read<LocalDatabase>();
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final UpToDateProductProvider provider =
context.read<UpToDateProductProvider>();
final DaoProduct daoProduct = DaoProduct(localDatabase);
final Product? cachedProduct = await daoProduct.get(
changedProduct.barcode!,
);
bool changed = false;
bool added = false;
String pageName = '';
Expand All @@ -158,17 +167,19 @@ class _SimpleInputPageState extends State<SimpleInputPage> {
}
if (widget.helpers[i].getChangedProduct(changedProduct)) {
changed = true;
if (cachedProduct != null) {
widget.helpers[i].getChangedProduct(cachedProduct);
}
}
pageName = widget.helpers[i].getTitle(AppLocalizations.of(context));
pageName = widget.helpers[i].getTitle(appLocalizations);
}
if (added) {
setState(() {});
}
if (!changed) {
return true;
}
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final LocalDatabase localDatabase = context.read<LocalDatabase>();

if (!saving) {
final bool? pleaseSave = await showDialog<bool>(
context: context,
Expand Down Expand Up @@ -215,6 +226,10 @@ class _SimpleInputPageState extends State<SimpleInputPage> {
uniqueId: uniqueId,
),
);

final Product upToDateProduct = cachedProduct ?? changedProduct;
await daoProduct.put(upToDateProduct);
provider.set(upToDateProduct);
localDatabase.notifyListeners();
if (!mounted) {
return false;
Expand Down

0 comments on commit 0d2be11

Please sign in to comment.