Skip to content

Commit

Permalink
Improved error handling (#11)
Browse files Browse the repository at this point in the history
* increment version number to 0.0.8

Signed-off-by: Dmytro Turskyi <[email protected]>

* Improve not found barcode exception handling

Signed-off-by: Dmytro Turskyi <[email protected]>

* Improve image could not be uploaded internal server error handling

Signed-off-by: Dmytro Turskyi <[email protected]>

* Improve product could not be added bad request error handling.

Signed-off-by: Dmytro Turskyi <[email protected]>

* Add ability to control zoom for photo ingredients.

Signed-off-by: Dmytro Turskyi <[email protected]>

* Improve error handling and added message if upload photo was successful.

Signed-off-by: Dmytro Turskyi <[email protected]>

* Update links in README.md

Signed-off-by: Dmytro Turskyi <[email protected]>

---------

Signed-off-by: Dmytro Turskyi <[email protected]>
  • Loading branch information
Turskyi authored Feb 15, 2024
1 parent 6eef5a7 commit e0287cb
Show file tree
Hide file tree
Showing 22 changed files with 614 additions and 298 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://stand-with-ukraine.pp.ua)
[![Codemagic build status](https://api.codemagic.io/apps/659998e6caf611b8969ad389/659998e6caf611b8969ad388/status_badge.svg)](https://codemagic.io/apps/659998e6caf611b8969ad389/659998e6caf611b8969ad388/latest_build)
[![Build & upload to Firebase App Distribution](https://github.com/Turskyi/ethical_scanner/actions/workflows/flutter_ci.yml/badge.svg?branch=dev&event=push)](https://github.com/Turskyi/ethical_scanner/actions/workflows/flutter_ci.yml)
[![Code Quality](https://github.com/Turskyi/ethical_scanner/actions/workflows/code-quality-tests.yml/badge.svg?branch=master&event=push)](https://github.com/Turskyi/ethical_scanner/actions/workflows/code-quality-tests.yml)
[![Build & upload to Firebase App Distribution](https://github.com/Turskyi/ethical_scanner/actions/workflows/flutter_ci.yml/badge.svg?branch=dev&event=push)](https://appdistribution.firebase.dev/i/ad57d28bed182b15)
[![Code Quality](https://github.com/Turskyi/ethical_scanner/actions/workflows/code-quality-tests.yml/badge.svg?branch=master&event=push)](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo)
[![style: flutter lints](https://img.shields.io/badge/style-flutter__lints-blue)](https://pub.dev/packages/flutter_lints)

# Ethical Scanner
Expand All @@ -19,7 +19,8 @@ The app uses the data from various sources, such as
- [Yale chief executive leadership institute | List of Companies
Leaving and Staying in Russia](https://www.yalerussianbusinessretreat.com/);
- [U.S. bureau of counterterrorism | State Sponsors of Terrorism](https://www.state.gov/state-sponsors-of-terrorism/);
- [European Parliament](https://www.europarl.europa.eu/delegations/en/recognising-the-russian-federation-as-a-/product-details/20221124DPU34521).
- [European Parliament](https://www.europarl.europa.eu/delegations/en/recognising-the-russian-federation-as-a-/product-details/20221124DPU34521);
- [Don't Fund War](https://dontfundwar.com).

The app aims to help you shop with confidence and conscience.
For more information, please visit the project website at https://ethical-scanner.turskyi.com.
Expand Down
4 changes: 2 additions & 2 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.turskyi.ethical_scanner"
android:versionCode="7"
android:versionName="0.0.7">
android:versionCode="8"
android:versionName="0.0.8">

<queries>
<intent>
Expand Down
3 changes: 3 additions & 0 deletions components/core/entities/lib/entities.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export 'src/enums/language.dart';
export 'src/enums/product_info_type.dart';
export 'src/enums/vegan.dart';
export 'src/enums/vegetarian.dart';
export 'src/exception/bad_request_error.dart';
export 'src/exception/internal_server_error.dart';
export 'src/exception/not_found_exception.dart';
export 'src/logging_interceptor/logging_interceptor.dart';
export 'src/product/product_info.dart';
export 'src/product/product_photo.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class BadRequestError implements Exception {
const BadRequestError(this.message);

final String message;

@override
String toString() => message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class InternalServerError implements Exception {
const InternalServerError(this.message);

final String message;

@override
String toString() => message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class NotFoundException implements Exception {
const NotFoundException(this.message);

final String message;

@override
String toString() => message;
}
10 changes: 8 additions & 2 deletions components/interface_adapters/assets/i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"title": "Ethical Scanner",
"app_feedback": "App Feedback",
"copied_to_clipboard": "Copied to clipboard",
"menu": {
"home": "Home",
"scan": "Scan",
Expand All @@ -27,13 +28,18 @@
"ingredients_colon": "Ingredients: ",
"website_colon": "Website: ",
"country_ai_colon": "AI-Generated Country Information: ",
"error_colon": "Error: "
"error_colon": "Error: ",
"click": "Click ",
"here": "here",
"or": " or ",
"to_know_more": " to know more."
},
"scan": {
"scan_screen": "Scan screen",
"scanning": "Scanning..."
},
"photo": {
"capture_ingredients": "Make a photo of the ingredients."
"capture_ingredients": "Make a photo of the ingredients.",
"image_upload_successful": "Image upload successful!"
}
}
10 changes: 8 additions & 2 deletions components/interface_adapters/assets/i18n/uk.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"title": "Ethical Scanner",
"app_feedback": "Відгук про додаток",
"copied_to_clipboard": "Скопійовано в буфер обміну.",
"menu": {
"home": "Домашня сторінка",
"scan": "Сканер",
Expand All @@ -27,13 +28,18 @@
"ingredients_colon": "Інгредієнти: ",
"website_colon": "Веб-сайт: ",
"country_ai_colon": "Інформація про країну, згенерована ШІ: ",
"error_colon": "Помилка: "
"error_colon": "Помилка: ",
"click": "Натисніть ",
"here": "тут",
"or": " або ",
"to_know_more": " щоб дізнатися більше."
},
"scan": {
"scan_screen": "Вікно сканування",
"scanning": "Сканування..."
},
"photo": {
"capture_ingredients": "Сфотографуйте\nінгредієнти."
"capture_ingredients": "Сфотографуйте\nінгредієнти.",
"image_upload_successful": "Завантаження зображення успішне!"
}
}
1 change: 1 addition & 0 deletions components/interface_adapters/lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
const String scanSoundAsset =
'components/interface_adapters/assets/audio/store_scanner_beep.mp3';
const String mailToScheme = 'mailto';
35 changes: 30 additions & 5 deletions components/interface_adapters/lib/src/error_message_extractor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,41 @@ import 'package:html/parser.dart';
String extractErrorMessage(String exceptionSource) {
final Document document = parse(exceptionSource);

// Extract the text content within the <div class="main-content"> element
final Element? mainContentElement = document.querySelector(
'div.main-content',
);
// Prioritize the main content element if it exists.
final Element? mainContentElement =
document.querySelector('div.main-content');
if (mainContentElement != null) {
final String message = mainContentElement.text.trim();
return message;
}

// If the main content element is not found, extract from other potential
// elements.
final String message = _extractMessageFromAlternativeElements(document);
return message.isNotEmpty ? message : _defaultErrorMessage();
}

String _extractMessageFromAlternativeElements(Document document) {
final List<Element?> potentialElements = <Element?>[
document.querySelector('h1'),
document.querySelector('pre'),
document.querySelector('p'),
];

final StringBuffer messageBuffer = StringBuffer();
for (Element? element in potentialElements) {
if (element != null) {
messageBuffer.write(element.text.trim());
// Add a newline for better readability.
messageBuffer.write('\n');
}
}

return messageBuffer.toString().trim();
}

String _defaultErrorMessage() {
return 'We are currently undergoing a major migration, and our services, '
'including the Web platform, mobile app, API, and Producer Platform, '
'are temporarily unavailable.';
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:async';
import 'dart:developer';

import 'package:entities/entities.dart';
import 'package:flutter/foundation.dart';
import 'package:interface_adapters/src/data_sources/local/local_data_source.dart';
import 'package:interface_adapters/src/data_sources/remote/remote_data_source.dart';
import 'package:interface_adapters/src/error_message_extractor.dart';
Expand All @@ -19,7 +19,8 @@ class ProductInfoGatewayImpl implements ProductInfoGateway {
.getProductInfoAsFuture(input)
.onError((Object? error, StackTrace stackTrace) {
if (error is FormatException && error.source is String) {
log('Error in $runtimeType: ${extractErrorMessage(error.source)}.'
debugPrint(
'Error in $runtimeType: ${extractErrorMessage(error.source)}.'
'\nStacktrace: $stackTrace');
}
if (_isBarcode(input.code)) {
Expand All @@ -28,10 +29,13 @@ class ProductInfoGatewayImpl implements ProductInfoGateway {
return ProductInfo(website: input.code);
} else if (_isAmazonAsin(input.code)) {
return const ProductInfo(brand: 'Amazon');
} else if (error is NotFoundException) {
throw error;
} else {
throw Exception(
'Product information not found for barcode: $input.\nError: $error',
);
}
throw Exception(
'Product information not found for barcode: $input.\nError: $error',
);
}).then((ProductInfo info) {
if (info.origin.isNotEmpty || info.country.isNotEmpty) {
return info;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ class HomePresenter extends Bloc<HomeEvent, HomeViewModel> {
modifiableProductInfo[ProductInfoType.companyTerrorismSponsor] =
productInfo.isCompanyTerrorismSponsor
? (state.language.isEnglish
? 'Probably yes'
: 'Напевно так')
? 'Probably yes. '
: 'Напевно так. ')
: 'No';
if (state is LoadingProductInfoState) {
LoadingProductInfoState loadingState =
Expand Down Expand Up @@ -193,6 +193,7 @@ class HomePresenter extends Bloc<HomeEvent, HomeViewModel> {
);
}
}

if (productInfo.vegan != Vegan.unknown) {
modifiableProductInfo[ProductInfoType.isVegan] =
productInfo.vegan == Vegan.positive ? 'Yes' : 'No';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';

class ProductInfoBody extends StatelessWidget {
const ProductInfoBody({
super.key,
});
const ProductInfoBody({super.key});

@override
Widget build(BuildContext context) {
Expand All @@ -40,12 +38,12 @@ class ProductInfoBody extends StatelessWidget {
builder: (_, HomeViewModel viewModel) {
if (viewModel is ProductInfoState) {
return RefreshIndicator(
onRefresh: () =>
PackageInfo.fromPlatform().then((PackageInfo packageInfo) {
return BetterFeedback.of(context).show((UserFeedback feedback) {
return _sendFeedback(feedback, packageInfo);
});
}),
onRefresh: () => PackageInfo.fromPlatform().then(
(PackageInfo packageInfo) => BetterFeedback.of(context).show(
(UserFeedback feedback) =>
_sendFeedback(feedback, packageInfo),
),
),
child: ListView.builder(
padding: EdgeInsets.only(
top: dimens.productInfoListTopPadding,
Expand Down
Loading

0 comments on commit e0287cb

Please sign in to comment.