mirror of
https://github.com/openfoodfacts/smooth-app.git
synced 2025-08-26 20:00:15 +08:00
feat: 4423 - specific "Not connected to internet" displayed error (#4455)
* feat: 4423 - specific "Not connected to internet" displayed error Impacted files: * `barcode_product_query.dart`: removed useless `try` as already `catch`'ed * `continuous_scan_model.dart`: removed the `codeInvalid` case that could never happen * `fetched_product.dart`: refactored with explicit constructors and additional exception and connectivity fields; removed the `codeInvalid` case that could never happen * `new_product_page.dart`: minor refactoring * `product_dialog_helper.dart`: removed the `codeInvalid` case that could never happen; minor refactoting * `product_list_item_simple.dart`: removed the `codeInvalid` case that could never happen * `product_loader_page.dart`: removed useless `try` as already `catch`'ed * `product_refresher.dart`: added a specific "You're not connected to the internet" error message; refactored using more `FetchedProduct`; removed useless method * `pubspec.lock`: wtf * `pubspec.yaml`: added package `connectivity_plus` * `question_card.dart`: refactored using `FetchedProduct` * feat: 4423 - fixed pubspec.yaml * feat: 4423 - new "server down" message after a ping attempt Impacted files: * `fetched_product.dart`: added field `failedPingedHost` where we store the host that we couldn't ping * `generated_plugin_registrant.cc`: wtf * `generated_plugins.cmake`: wtf * `GeneratedPluginRegistrant.swift`: wtf * `main.dart`: registered `DartPingIOS` * `product_refresher.dart`: now trying to ping the server if exception and connection * `pubspec.lock`: wtf * `pubspec.yaml: added packages `dart_ping` and `dart_ping_ios` * feat: 4423 - stupid lint check part 1 * feat: 4423 - stupid lint check part 2 * feat: 4423 - stupid lint check part 3 * feat: 4423 - stupid lint check part 5 * feat: 4423 - localizations Impacted files: * `app_en.arb`: 4 new labels when we couldn't retrieve a product (not found, no internet, server down, server error) * `product_refresher.dart`: used the new labels
This commit is contained in:
@ -224,9 +224,6 @@ class ContinuousScanModel with ChangeNotifier {
|
||||
case FetchedProductStatus.internetError:
|
||||
_setBarcodeState(barcode, ScannedProductState.ERROR_INTERNET);
|
||||
return;
|
||||
case FetchedProductStatus.codeInvalid:
|
||||
_setBarcodeState(barcode, ScannedProductState.ERROR_INVALID_CODE);
|
||||
return;
|
||||
case FetchedProductStatus.userCancelled:
|
||||
// we do nothing
|
||||
return;
|
||||
@ -247,9 +244,6 @@ class ContinuousScanModel with ChangeNotifier {
|
||||
case FetchedProductStatus.internetError:
|
||||
_setBarcodeState(barcode, ScannedProductState.ERROR_INTERNET);
|
||||
return;
|
||||
case FetchedProductStatus.codeInvalid:
|
||||
_setBarcodeState(barcode, ScannedProductState.ERROR_INVALID_CODE);
|
||||
return;
|
||||
case FetchedProductStatus.userCancelled:
|
||||
// we do nothing
|
||||
return;
|
||||
|
@ -1,28 +1,63 @@
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:openfoodfacts/openfoodfacts.dart';
|
||||
|
||||
/// Status of a "fetch [Product]" operation
|
||||
enum FetchedProductStatus {
|
||||
// found locally or from internet
|
||||
ok,
|
||||
internetNotFound,
|
||||
internetError,
|
||||
userCancelled,
|
||||
codeInvalid,
|
||||
// TODO(monsieurtanuki): time-out
|
||||
}
|
||||
|
||||
/// A [Product] that we tried to fetch, but was it successful?..
|
||||
class FetchedProduct {
|
||||
// The reason behind the "ignore": I want to force "product" to be not null
|
||||
FetchedProduct(final Product product)
|
||||
// ignore: prefer_initializing_formals
|
||||
: product = product,
|
||||
status = FetchedProductStatus.ok;
|
||||
const FetchedProduct._({
|
||||
required this.status,
|
||||
this.product,
|
||||
this.connectivityResult,
|
||||
this.exceptionString,
|
||||
this.failedPingedHost,
|
||||
});
|
||||
|
||||
/// When the "fetch product" operation didn't go well (no status "ok" here)
|
||||
FetchedProduct.error(this.status)
|
||||
: product = null,
|
||||
assert(status != FetchedProductStatus.ok);
|
||||
// The reason behind the "ignore": I want to force "product" to be not null
|
||||
const FetchedProduct.found(final Product product)
|
||||
// ignore: prefer_initializing_formals
|
||||
: this._(
|
||||
status: FetchedProductStatus.ok,
|
||||
product: product,
|
||||
);
|
||||
|
||||
/// The internet Product search said it couldn't find the product.
|
||||
const FetchedProduct.internetNotFound()
|
||||
: this._(status: FetchedProductStatus.internetNotFound);
|
||||
|
||||
/// The user cancelled the operation.
|
||||
const FetchedProduct.userCancelled()
|
||||
: this._(status: FetchedProductStatus.userCancelled);
|
||||
|
||||
/// When the "fetch product" operation had an internet error.
|
||||
const FetchedProduct.error({
|
||||
required final String exceptionString,
|
||||
required final ConnectivityResult connectivityResult,
|
||||
final String? failedPingedHost,
|
||||
}) : this._(
|
||||
status: FetchedProductStatus.internetError,
|
||||
connectivityResult: connectivityResult,
|
||||
exceptionString: exceptionString,
|
||||
failedPingedHost: failedPingedHost,
|
||||
);
|
||||
|
||||
final Product? product;
|
||||
final FetchedProductStatus status;
|
||||
|
||||
/// When relevant, result of the connectivity check.
|
||||
final ConnectivityResult? connectivityResult;
|
||||
|
||||
/// When relevant, string of the exception.
|
||||
final String? exceptionString;
|
||||
|
||||
/// When relevant, host of the query that we couldn't even ping.
|
||||
final String? failedPingedHost;
|
||||
}
|
||||
|
@ -2272,6 +2272,32 @@
|
||||
"@contrast_low": {
|
||||
"description": "Low Contrast Text Color"
|
||||
},
|
||||
"product_refresher_internet_not_found": "Product not found!",
|
||||
"@product_refresher_internet_not_found": {
|
||||
"description": "When refreshing a product that does not exist on the server. Label is the body of a dialog."
|
||||
},
|
||||
"product_refresher_internet_not_connected": "You are not connected to internet!",
|
||||
"@product_refresher_internet_not_connected": {
|
||||
"description": "When refreshing a product and you're not even connected to internet. Label is the body of a dialog."
|
||||
},
|
||||
"product_refresher_internet_no_ping": "Server down ({host})",
|
||||
"@product_refresher_internet_no_ping": {
|
||||
"description": "When refreshing a product and you cannot even ping the server. Label is the body of a dialog.",
|
||||
"placeholders": {
|
||||
"host": {
|
||||
"type": "String?"
|
||||
}
|
||||
}
|
||||
},
|
||||
"product_refresher_internet_error": "Server error ({exception})",
|
||||
"@product_refresher_internet_error": {
|
||||
"description": "When refreshing a product and the server returned an exception. Label is the body of a dialog.",
|
||||
"placeholders": {
|
||||
"exception": {
|
||||
"type": "String?"
|
||||
}
|
||||
}
|
||||
},
|
||||
"product_loader_not_found_title": "Product not found!",
|
||||
"@product_loader_not_found_title": {
|
||||
"description": "When fetching a product opened via a link and it doesn't exist"
|
||||
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:app_store_shared/app_store_shared.dart';
|
||||
import 'package:dart_ping_ios/dart_ping_ios.dart';
|
||||
import 'package:device_preview/device_preview.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -120,6 +121,7 @@ Future<bool> _init1() async {
|
||||
return false;
|
||||
}
|
||||
|
||||
DartPingIOS.register();
|
||||
await SmoothServices().init(GlobalVars.appStore);
|
||||
await setupAppNetworkConfig();
|
||||
await UserManagementProvider.mountCredentials();
|
||||
|
@ -3,6 +3,7 @@ import 'package:openfoodfacts/openfoodfacts.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
import 'package:smooth_app/cards/product_cards/product_title_card.dart';
|
||||
import 'package:smooth_app/data_models/fetched_product.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';
|
||||
@ -24,22 +25,22 @@ class QuestionCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Future<Product?> productFuture = _getProduct(
|
||||
final Future<FetchedProduct> productFuture = _getProduct(
|
||||
question.barcode!,
|
||||
context.read<LocalDatabase>(),
|
||||
);
|
||||
|
||||
final Size screenSize = MediaQuery.of(context).size;
|
||||
|
||||
return FutureBuilder<Product?>(
|
||||
return FutureBuilder<FetchedProduct>(
|
||||
future: productFuture,
|
||||
builder: (
|
||||
BuildContext context,
|
||||
AsyncSnapshot<Product?> snapshot,
|
||||
AsyncSnapshot<FetchedProduct> snapshot,
|
||||
) {
|
||||
Product? product;
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
product = snapshot.data;
|
||||
product = snapshot.data?.product;
|
||||
// TODO(monsieurtanuki): do something aggressive if product is null here and we don't have a fallback value - like an error widget
|
||||
}
|
||||
// fallback version
|
||||
@ -131,13 +132,13 @@ class QuestionCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Future<Product?> _getProduct(
|
||||
Future<FetchedProduct> _getProduct(
|
||||
final String barcode,
|
||||
final LocalDatabase localDatabase,
|
||||
) async {
|
||||
final Product? result = await DaoProduct(localDatabase).get(barcode);
|
||||
if (result != null) {
|
||||
return result;
|
||||
return FetchedProduct.found(result);
|
||||
}
|
||||
return ProductRefresher().silentFetchAndRefresh(
|
||||
barcode: question.barcode!,
|
||||
|
@ -38,7 +38,7 @@ class ProductDialogHelper {
|
||||
Future<FetchedProduct> openBestChoice() async {
|
||||
final Product? product = await DaoProduct(localDatabase).get(barcode);
|
||||
if (product != null) {
|
||||
return FetchedProduct(product);
|
||||
return FetchedProduct.found(product);
|
||||
}
|
||||
return openUniqueProductSearch();
|
||||
}
|
||||
@ -52,7 +52,7 @@ class ProductDialogHelper {
|
||||
isScanned: false,
|
||||
).getFetchedProduct(),
|
||||
title: '${AppLocalizations.of(context).looking_for}: $barcode') ??
|
||||
FetchedProduct.error(FetchedProductStatus.userCancelled);
|
||||
const FetchedProduct.userCancelled();
|
||||
|
||||
void _openProductNotFoundDialog() => showDialog<Widget>(
|
||||
context: context,
|
||||
@ -175,9 +175,6 @@ class ProductDialogHelper {
|
||||
case FetchedProductStatus.internetNotFound:
|
||||
_openProductNotFoundDialog();
|
||||
return;
|
||||
case FetchedProductStatus.codeInvalid:
|
||||
_openErrorMessage(appLocalizations.barcode_invalid_error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,8 +100,6 @@ class _ProductListItemSimpleState extends State<ProductListItemSimple> {
|
||||
switch (_model.downloadingStatus) {
|
||||
case null:
|
||||
break;
|
||||
case FetchedProductStatus.codeInvalid:
|
||||
return appLocalizations.barcode_invalid_error;
|
||||
case FetchedProductStatus.internetNotFound:
|
||||
return appLocalizations.product_internet_error;
|
||||
default:
|
||||
|
@ -1,8 +1,11 @@
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:dart_ping/dart_ping.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:openfoodfacts/openfoodfacts.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:smooth_app/data_models/fetched_product.dart';
|
||||
import 'package:smooth_app/database/dao_product.dart';
|
||||
import 'package:smooth_app/database/local_database.dart';
|
||||
import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart';
|
||||
@ -93,14 +96,11 @@ class ProductRefresher {
|
||||
/// Fetches the product from the server and refreshes the local database.
|
||||
///
|
||||
/// Silent version.
|
||||
Future<Product?> silentFetchAndRefresh({
|
||||
Future<FetchedProduct> silentFetchAndRefresh({
|
||||
required final String barcode,
|
||||
required final LocalDatabase localDatabase,
|
||||
}) async {
|
||||
final _MetaProductRefresher meta =
|
||||
await _fetchAndRefresh(localDatabase, barcode);
|
||||
return meta.product;
|
||||
}
|
||||
}) async =>
|
||||
_fetchAndRefresh(localDatabase, barcode);
|
||||
|
||||
/// Fetches the products from the server and refreshes the local database.
|
||||
///
|
||||
@ -111,23 +111,6 @@ class ProductRefresher {
|
||||
}) async =>
|
||||
_fetchAndRefreshList(localDatabase, barcodes);
|
||||
|
||||
/// Fetches the product from the server and refreshes the local database.
|
||||
/// In the case of an error, it will be send throw an [Exception]
|
||||
/// Silent version.
|
||||
Future<Product?> silentFetchAndRefreshWithException({
|
||||
required final String barcode,
|
||||
required final LocalDatabase localDatabase,
|
||||
}) async {
|
||||
final _MetaProductRefresher meta =
|
||||
await _fetchAndRefresh(localDatabase, barcode);
|
||||
|
||||
if (meta.error != null) {
|
||||
throw Exception(meta.error);
|
||||
}
|
||||
|
||||
return meta.product;
|
||||
}
|
||||
|
||||
/// Fetches the product from the server and refreshes the local database.
|
||||
///
|
||||
/// With a waiting dialog.
|
||||
@ -139,18 +122,45 @@ class ProductRefresher {
|
||||
final LocalDatabase localDatabase = widget.context.read<LocalDatabase>();
|
||||
final AppLocalizations appLocalizations =
|
||||
AppLocalizations.of(widget.context);
|
||||
final _MetaProductRefresher? fetchAndRefreshed =
|
||||
await LoadingDialog.run<_MetaProductRefresher>(
|
||||
final FetchedProduct? fetchAndRefreshed =
|
||||
await LoadingDialog.run<FetchedProduct>(
|
||||
future: _fetchAndRefresh(localDatabase, barcode),
|
||||
context: widget.context,
|
||||
title: appLocalizations.refreshing_product,
|
||||
);
|
||||
if (fetchAndRefreshed == null) {
|
||||
// the user probably cancelled
|
||||
return false;
|
||||
}
|
||||
if (fetchAndRefreshed.product == null) {
|
||||
if (widget.mounted) {
|
||||
await LoadingDialog.error(context: widget.context);
|
||||
String getTitle(final FetchedProduct fetchedProduct) {
|
||||
switch (fetchAndRefreshed.status) {
|
||||
case FetchedProductStatus.ok:
|
||||
return 'Not supposed to happen...';
|
||||
case FetchedProductStatus.userCancelled:
|
||||
return 'Not supposed to happen either...';
|
||||
case FetchedProductStatus.internetNotFound:
|
||||
return appLocalizations.product_refresher_internet_not_found;
|
||||
case FetchedProductStatus.internetError:
|
||||
if (fetchAndRefreshed.connectivityResult ==
|
||||
ConnectivityResult.none) {
|
||||
return appLocalizations
|
||||
.product_refresher_internet_not_connected;
|
||||
}
|
||||
if (fetchAndRefreshed.failedPingedHost != null) {
|
||||
return appLocalizations.product_refresher_internet_no_ping(
|
||||
fetchAndRefreshed.failedPingedHost);
|
||||
}
|
||||
return appLocalizations.product_refresher_internet_no_ping(
|
||||
fetchAndRefreshed.exceptionString);
|
||||
}
|
||||
}
|
||||
|
||||
await LoadingDialog.error(
|
||||
context: widget.context,
|
||||
title: getTitle(fetchAndRefreshed),
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -165,7 +175,7 @@ class ProductRefresher {
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<_MetaProductRefresher> _fetchAndRefresh(
|
||||
Future<FetchedProduct> _fetchAndRefresh(
|
||||
final LocalDatabase localDatabase,
|
||||
final String barcode,
|
||||
) async {
|
||||
@ -177,12 +187,30 @@ class ProductRefresher {
|
||||
await DaoProduct(localDatabase).put(result.product!);
|
||||
localDatabase.upToDate.setLatestDownloadedProduct(result.product!);
|
||||
localDatabase.notifyListeners();
|
||||
return _MetaProductRefresher.product(result.product);
|
||||
return FetchedProduct.found(result.product!);
|
||||
}
|
||||
return const _MetaProductRefresher.error(null);
|
||||
return const FetchedProduct.internetNotFound();
|
||||
} catch (e) {
|
||||
Logs.e('Refresh from server error', ex: e);
|
||||
return _MetaProductRefresher.error(e.toString());
|
||||
final ConnectivityResult connectivityResult =
|
||||
await Connectivity().checkConnectivity();
|
||||
if (connectivityResult == ConnectivityResult.none) {
|
||||
return FetchedProduct.error(
|
||||
exceptionString: e.toString(),
|
||||
connectivityResult: connectivityResult,
|
||||
);
|
||||
}
|
||||
// TODO(monsieurtanuki): make things cleaner with off-dart
|
||||
final String host =
|
||||
OpenFoodAPIConfiguration.globalQueryType == QueryType.PROD
|
||||
? OpenFoodAPIConfiguration.uriProdHost
|
||||
: OpenFoodAPIConfiguration.uriTestHost;
|
||||
final PingData result = await Ping(host, count: 1).stream.first;
|
||||
return FetchedProduct.error(
|
||||
exceptionString: e.toString(),
|
||||
connectivityResult: connectivityResult,
|
||||
failedPingedHost: result.error == null ? null : host,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,12 +240,3 @@ class ProductRefresher {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _MetaProductRefresher {
|
||||
const _MetaProductRefresher.error(this.error) : product = null;
|
||||
|
||||
const _MetaProductRefresher.product(this.product) : error = null;
|
||||
|
||||
final String? error;
|
||||
final Product? product;
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ class _ProductPageState extends State<ProductPage>
|
||||
final LocalDatabase localDatabase = context.read<LocalDatabase>();
|
||||
final DaoProductList daoProductList = DaoProductList(localDatabase);
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => ProductRefresher().fetchAndRefresh(
|
||||
onRefresh: () async => ProductRefresher().fetchAndRefresh(
|
||||
barcode: barcode,
|
||||
widget: this,
|
||||
),
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:openfoodfacts/openfoodfacts.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:smooth_app/data_models/fetched_product.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';
|
||||
@ -42,28 +43,31 @@ class _ProductLoaderPageState extends State<ProductLoaderPage> {
|
||||
_state = _ProductLoaderState.loading;
|
||||
});
|
||||
|
||||
try {
|
||||
final Product? product =
|
||||
await ProductRefresher().silentFetchAndRefreshWithException(
|
||||
final FetchedProduct fetchedProduct =
|
||||
await ProductRefresher().silentFetchAndRefresh(
|
||||
barcode: widget.barcode,
|
||||
localDatabase: context.read<LocalDatabase>(),
|
||||
);
|
||||
|
||||
if (product != null && mounted) {
|
||||
if (mounted) {
|
||||
if (fetchedProduct.product != null) {
|
||||
navigator.pushReplacement(
|
||||
AppRoutes.PRODUCT(
|
||||
widget.barcode,
|
||||
heroTag: 'product_${widget.barcode}',
|
||||
),
|
||||
extra: product,
|
||||
extra: fetchedProduct.product,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (fetchedProduct.status == FetchedProductStatus.internetNotFound) {
|
||||
setState(() {
|
||||
_state = _ProductLoaderState.productNotFound;
|
||||
});
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
setState(() {
|
||||
// TODO(monsieurtanuki): put more details from FetchedProduct?
|
||||
_state = _ProductLoaderState.serverError;
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:openfoodfacts/openfoodfacts.dart';
|
||||
import 'package:smooth_app/data_models/fetched_product.dart';
|
||||
import 'package:smooth_app/database/dao_product.dart';
|
||||
import 'package:smooth_app/helpers/analytics_helper.dart';
|
||||
@ -19,21 +18,18 @@ class BarcodeProductQuery {
|
||||
final bool isScanned;
|
||||
|
||||
Future<FetchedProduct> getFetchedProduct() async {
|
||||
try {
|
||||
ProductQuery.setUserAgentComment(isScanned ? 'scan' : 'search');
|
||||
final Product? product = await ProductRefresher().silentFetchAndRefresh(
|
||||
final FetchedProduct fetchedProduct =
|
||||
await ProductRefresher().silentFetchAndRefresh(
|
||||
barcode: barcode,
|
||||
localDatabase: daoProduct.localDatabase,
|
||||
);
|
||||
if (product != null) {
|
||||
return FetchedProduct(product);
|
||||
}
|
||||
} catch (e) {
|
||||
return FetchedProduct.error(FetchedProductStatus.internetError);
|
||||
} finally {
|
||||
ProductQuery.setUserAgentComment('');
|
||||
if (fetchedProduct.product != null) {
|
||||
return fetchedProduct;
|
||||
}
|
||||
|
||||
if (fetchedProduct.status == FetchedProductStatus.internetNotFound) {
|
||||
if (isScanned) {
|
||||
AnalyticsHelper.trackEvent(
|
||||
AnalyticsEvent.couldNotScanProduct,
|
||||
@ -45,7 +41,8 @@ class BarcodeProductQuery {
|
||||
barcode: barcode,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return FetchedProduct.error(FetchedProductStatus.internetNotFound);
|
||||
return fetchedProduct;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import audioplayers_darwin
|
||||
import connectivity_plus
|
||||
import device_info_plus
|
||||
import file_selector_macos
|
||||
import flutter_secure_storage_macos
|
||||
@ -22,6 +23,7 @@ import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
|
||||
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
|
@ -293,6 +293,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.1"
|
||||
connectivity_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: connectivity_plus
|
||||
sha256: "77a180d6938f78ca7d2382d2240eb626c0f6a735d0bfdce227d8ffb80f95c48b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
connectivity_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: connectivity_plus_platform_interface
|
||||
sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.4"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -341,6 +357,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
dart_ping:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dart_ping
|
||||
sha256: dd3a93d9b986565cb2fadd0c9277cf9880298634ccc9588e353e63c6f736a386
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.0"
|
||||
dart_ping_ios:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dart_ping_ios
|
||||
sha256: ba60bcd1ef8f13d564e9490197fb32c34d38fd1c10a890143a52f5b71d82ea95
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -363,6 +395,14 @@ packages:
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.0"
|
||||
dbus:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dbus
|
||||
sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.8"
|
||||
device_frame:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -517,6 +557,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.1"
|
||||
flutter_icmp_ping:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_icmp_ping
|
||||
sha256: a06c2255a857c8f9d1b0a68f546b113557e48e7a543f91e38bd66aeab296f3a6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
flutter_image_compress:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1006,6 +1054,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
nm:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nm
|
||||
sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
openfoodfacts:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -70,6 +70,9 @@ dependencies:
|
||||
webview_flutter: 3.0.4
|
||||
flutter_custom_tabs: ^1.0.4
|
||||
flutter_image_compress: 2.0.4
|
||||
connectivity_plus: ^4.0.2
|
||||
dart_ping: 9.0.0
|
||||
dart_ping_ios: 4.0.0
|
||||
|
||||
# According to the build variant, only one "app store" implementation must be added when building a release
|
||||
# Call "flutter pub remove xxxx" to remove unused dependencies
|
||||
@ -97,7 +100,6 @@ dependencies:
|
||||
path: ../scanner/zxing
|
||||
|
||||
|
||||
|
||||
openfoodfacts: 2.10.0
|
||||
# openfoodfacts:
|
||||
# path: ../../../openfoodfacts-dart
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
@ -18,6 +19,8 @@
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
AudioplayersWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
|
||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
audioplayers_windows
|
||||
connectivity_plus
|
||||
file_selector_windows
|
||||
flutter_secure_storage_windows
|
||||
permission_handler_windows
|
||||
|
Reference in New Issue
Block a user