2024-12-07 12:29:34 +00:00
|
|
|
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
2024-12-07 12:39:11 +00:00
|
|
|
/* Copyright (C) 2024 Marco Groß <mgross@sw-gross.de> */
|
2024-09-06 16:51:24 +00:00
|
|
|
import 'dart:convert';
|
2024-09-07 23:57:40 +00:00
|
|
|
import 'dart:developer';
|
2024-09-06 16:51:24 +00:00
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
class FoodFactLookupClient {
|
|
|
|
FoodFactLookupClient();
|
|
|
|
|
|
|
|
static const String url = "https://world.openfoodfacts.org/api/v3/product/";
|
|
|
|
|
|
|
|
String getProductUrl(String ean) {
|
|
|
|
return "$url$ean.json";
|
|
|
|
}
|
|
|
|
|
2024-09-07 23:57:40 +00:00
|
|
|
Future<FoodFactResponse> retrieveFoodInfo(String ean) async {
|
2024-09-06 16:51:24 +00:00
|
|
|
HttpClient client = HttpClient();
|
2024-09-07 23:57:40 +00:00
|
|
|
String asString = "";
|
|
|
|
|
|
|
|
try {
|
|
|
|
var request = await client.getUrl(Uri.parse(getProductUrl(ean)));
|
|
|
|
|
|
|
|
var response = await request.close();
|
|
|
|
|
|
|
|
if (response.statusCode != HttpStatus.ok) {
|
|
|
|
return FoodFactResponse(
|
2024-09-08 13:07:39 +00:00
|
|
|
food: null, status: FoodFactResponseStatus.barcodeNotFound);
|
2024-09-07 23:57:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
asString = await response.transform(utf8.decoder).join();
|
|
|
|
} on SocketException {
|
|
|
|
return FoodFactResponse(
|
|
|
|
food: null,
|
|
|
|
status: FoodFactResponseStatus.foodFactServerNotReachable);
|
|
|
|
} catch (e) {
|
|
|
|
log(e.toString());
|
|
|
|
} finally {
|
|
|
|
client.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
return FoodFactResponse(
|
|
|
|
food: FoodFactModel.fromJson(jsonDecode(asString)),
|
|
|
|
status: FoodFactResponseStatus.ok);
|
2024-09-06 16:51:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class FoodFactModel {
|
|
|
|
final String name;
|
2024-09-06 22:02:01 +00:00
|
|
|
final int kcalPer100g;
|
2024-12-22 17:13:29 +00:00
|
|
|
final int kcalPer100gPrepared;
|
2024-09-09 20:41:48 +00:00
|
|
|
final int mass;
|
2024-09-06 16:51:24 +00:00
|
|
|
|
2024-09-09 20:41:48 +00:00
|
|
|
FoodFactModel({
|
|
|
|
required this.name,
|
|
|
|
required this.mass,
|
|
|
|
required this.kcalPer100g,
|
2024-12-22 17:13:29 +00:00
|
|
|
required this.kcalPer100gPrepared,
|
2024-09-09 20:41:48 +00:00
|
|
|
});
|
2024-09-06 16:51:24 +00:00
|
|
|
|
|
|
|
factory FoodFactModel.fromJson(Map<String, dynamic> json) {
|
2024-12-22 17:13:29 +00:00
|
|
|
int kcalPer100g = json['product']['nutriments']['energy-kcal_100g'] ?? 0;
|
|
|
|
int kcalPer100gPrepared =
|
|
|
|
json['product']['nutriments']['energy-kcal_prepared_100g'] ?? 0;
|
|
|
|
|
2024-09-09 20:41:48 +00:00
|
|
|
String quantityString = json['product']['product_quantity'] ?? "0";
|
|
|
|
int quantity;
|
|
|
|
|
|
|
|
try {
|
|
|
|
quantity = int.parse(quantityString);
|
|
|
|
} catch (e) {
|
|
|
|
quantity = 0;
|
|
|
|
}
|
|
|
|
|
2024-09-06 22:02:01 +00:00
|
|
|
return FoodFactModel(
|
2024-12-22 17:13:29 +00:00
|
|
|
name: json['product']['product_name'] ?? "",
|
|
|
|
kcalPer100g: kcalPer100g,
|
|
|
|
kcalPer100gPrepared: kcalPer100gPrepared,
|
2024-09-09 20:41:48 +00:00
|
|
|
mass: quantity);
|
2024-09-06 16:51:24 +00:00
|
|
|
}
|
|
|
|
}
|
2024-09-07 23:57:40 +00:00
|
|
|
|
|
|
|
enum FoodFactResponseStatus {
|
|
|
|
foodFactServerNotReachable,
|
2024-09-08 13:07:39 +00:00
|
|
|
barcodeNotFound,
|
2024-09-07 23:57:40 +00:00
|
|
|
ok,
|
|
|
|
}
|
|
|
|
|
|
|
|
class FoodFactResponse {
|
|
|
|
final FoodFactModel? food;
|
|
|
|
final FoodFactResponseStatus status;
|
|
|
|
|
|
|
|
FoodFactResponse({required this.food, required this.status});
|
|
|
|
}
|