Compare commits
3 Commits
22b863f2bf
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 58578c734e | |||
| 76f2c0ad58 | |||
| cfa61e1a8a |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 7.3 KiB |
BIN
assets/icon.png
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 356 B After Width: | Height: | Size: 521 B |
|
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 791 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 930 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 6.1 KiB |
@@ -1,15 +1,20 @@
|
|||||||
|
import 'package:dietary_guard/models/food_data.dart';
|
||||||
|
|
||||||
class AlertConfiguration {
|
class AlertConfiguration {
|
||||||
|
String name;
|
||||||
int nutrientId;
|
int nutrientId;
|
||||||
double maxValue;
|
double maxValue;
|
||||||
double minValue;
|
double minValue;
|
||||||
|
|
||||||
AlertConfiguration({
|
AlertConfiguration({
|
||||||
|
required this.name,
|
||||||
required this.nutrientId,
|
required this.nutrientId,
|
||||||
required this.maxValue,
|
required this.maxValue,
|
||||||
required this.minValue,
|
required this.minValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
|
'name': name,
|
||||||
'nutrient_id': nutrientId,
|
'nutrient_id': nutrientId,
|
||||||
'min_value': minValue,
|
'min_value': minValue,
|
||||||
'max_value': maxValue,
|
'max_value': maxValue,
|
||||||
@@ -17,6 +22,7 @@ class AlertConfiguration {
|
|||||||
|
|
||||||
factory AlertConfiguration.fromJson(Map<String, dynamic> json) =>
|
factory AlertConfiguration.fromJson(Map<String, dynamic> json) =>
|
||||||
AlertConfiguration(
|
AlertConfiguration(
|
||||||
|
name: json['name'],
|
||||||
nutrientId: json['nutrient_id'],
|
nutrientId: json['nutrient_id'],
|
||||||
minValue: json['min_value'],
|
minValue: json['min_value'],
|
||||||
maxValue: json['max_value'],
|
maxValue: json['max_value'],
|
||||||
@@ -25,18 +31,18 @@ class AlertConfiguration {
|
|||||||
|
|
||||||
class AlertDetectResult {
|
class AlertDetectResult {
|
||||||
AlertConfiguration config;
|
AlertConfiguration config;
|
||||||
|
FoodNutrient? nutrient;
|
||||||
String name;
|
String name;
|
||||||
String? unitName;
|
String? unitName;
|
||||||
double? current;
|
|
||||||
double? difference;
|
double? difference;
|
||||||
bool isOutOfRange;
|
bool isOutOfRange;
|
||||||
bool isUndetected;
|
bool isUndetected;
|
||||||
|
|
||||||
AlertDetectResult({
|
AlertDetectResult({
|
||||||
required this.config,
|
required this.config,
|
||||||
|
required this.nutrient,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.unitName,
|
required this.unitName,
|
||||||
required this.current,
|
|
||||||
required this.difference,
|
required this.difference,
|
||||||
required this.isOutOfRange,
|
required this.isOutOfRange,
|
||||||
required this.isUndetected,
|
required this.isUndetected,
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ class _FoodDetailsScreenState extends State<FoodDetailsScreen> {
|
|||||||
double? difference;
|
double? difference;
|
||||||
String name = 'undetected'.tr;
|
String name = 'undetected'.tr;
|
||||||
String? unitName;
|
String? unitName;
|
||||||
double? current;
|
FoodNutrient? current;
|
||||||
for (final nutrient in widget.item.foodNutrients) {
|
for (final nutrient in widget.item.foodNutrients) {
|
||||||
if (item.nutrientId != nutrient.nutrientId) continue;
|
if (item.nutrientId != nutrient.nutrientId) continue;
|
||||||
name = nutrient.nutrientName;
|
name = nutrient.nutrientName;
|
||||||
unitName = unitNameValues.reverse[nutrient.unitName];
|
unitName = unitNameValues.reverse[nutrient.unitName];
|
||||||
if (nutrient.value != null) {
|
if (nutrient.value != null) {
|
||||||
|
current = nutrient;
|
||||||
final value = nutrient.value!;
|
final value = nutrient.value!;
|
||||||
current = value;
|
|
||||||
if (value > item.maxValue) {
|
if (value > item.maxValue) {
|
||||||
difference = value - item.maxValue;
|
difference = value - item.maxValue;
|
||||||
isOutOfRange = true;
|
isOutOfRange = true;
|
||||||
@@ -54,9 +54,9 @@ class _FoodDetailsScreenState extends State<FoodDetailsScreen> {
|
|||||||
|
|
||||||
_alertDetectResult.add(AlertDetectResult(
|
_alertDetectResult.add(AlertDetectResult(
|
||||||
config: item,
|
config: item,
|
||||||
|
nutrient: current,
|
||||||
name: name,
|
name: name,
|
||||||
unitName: unitName,
|
unitName: unitName,
|
||||||
current: current,
|
|
||||||
difference: difference,
|
difference: difference,
|
||||||
isOutOfRange: isOutOfRange,
|
isOutOfRange: isOutOfRange,
|
||||||
isUndetected: isUndetected,
|
isUndetected: isUndetected,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class _QueryScreenState extends State<QueryScreen> {
|
|||||||
setState(() => _isLoading = true);
|
setState(() => _isLoading = true);
|
||||||
|
|
||||||
final FoodDataController data = Get.find();
|
final FoodDataController data = Get.find();
|
||||||
if (data.getApiKey() == null) {
|
if (data.getApiKey() == null || data.getApiKey()!.isEmpty) {
|
||||||
setState(() => _hasApiKey = false);
|
setState(() => _hasApiKey = false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,11 @@ class _QueryScreenState extends State<QueryScreen> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
final FoodDataController data = Get.find();
|
final FoodDataController data = Get.find();
|
||||||
data.initialize(context);
|
data.initialize(context).then((_) {
|
||||||
|
setState(() {
|
||||||
|
_hasApiKey = data.getApiKey() != null && data.getApiKey()!.isNotEmpty;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class _AlertSettingsScreenState extends State<AlertSettingsScreen> {
|
|||||||
void _addAlert() {
|
void _addAlert() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_currentAlerts.add(AlertConfiguration(
|
_currentAlerts.add(AlertConfiguration(
|
||||||
|
name: 'Alert #${_currentAlerts.length}',
|
||||||
nutrientId: 0,
|
nutrientId: 0,
|
||||||
maxValue: 0,
|
maxValue: 0,
|
||||||
minValue: 0,
|
minValue: 0,
|
||||||
@@ -64,16 +65,16 @@ class _AlertSettingsScreenState extends State<AlertSettingsScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
initialValue: x.nutrientId.toString(),
|
initialValue: x.name,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
label: Text("alertNutrientId".tr),
|
label: Text("alertName".tr),
|
||||||
isDense: true,
|
isDense: true,
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) =>
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
x.nutrientId = int.tryParse(value) ?? 0;
|
x.name = value;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -87,6 +88,20 @@ class _AlertSettingsScreenState extends State<AlertSettingsScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
TextFormField(
|
||||||
|
initialValue: x.nutrientId.toString(),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
label: Text("alertNutrientId".tr),
|
||||||
|
isDense: true,
|
||||||
|
),
|
||||||
|
onTapOutside: (_) =>
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
|
onChanged: (value) {
|
||||||
|
x.nutrientId = int.tryParse(value) ?? 0;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const i18nEnglish = {
|
|||||||
'alertNutrientId': 'Nutrient ID',
|
'alertNutrientId': 'Nutrient ID',
|
||||||
'alertMaxValue': 'Alert Max Value',
|
'alertMaxValue': 'Alert Max Value',
|
||||||
'alertMinValue': 'Alert Min Value',
|
'alertMinValue': 'Alert Min Value',
|
||||||
|
'alertName': 'Alert Name',
|
||||||
'alerts': 'Alerts',
|
'alerts': 'Alerts',
|
||||||
'alertOutOfRange':
|
'alertOutOfRange':
|
||||||
'@count alert rules triggered, click the button on the right for details',
|
'@count alert rules triggered, click the button on the right for details',
|
||||||
@@ -48,5 +49,5 @@ const i18nEnglish = {
|
|||||||
'searchHint': 'Type keywords below to search',
|
'searchHint': 'Type keywords below to search',
|
||||||
'searchNoKeyHint':
|
'searchNoKeyHint':
|
||||||
'No API key, please first set up the API key in "Settings" > "Data Source"',
|
'No API key, please first set up the API key in "Settings" > "Data Source"',
|
||||||
'searchResultHint': '@count records matched (up to the first 100)',
|
'searchResultHint': '@count records matched (showing 100)',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const i18nSimplifiedChinese = {
|
|||||||
'alertNutrientId': '营养物质编号',
|
'alertNutrientId': '营养物质编号',
|
||||||
'alertMaxValue': '告警上限',
|
'alertMaxValue': '告警上限',
|
||||||
'alertMinValue': '告警下限',
|
'alertMinValue': '告警下限',
|
||||||
|
'alertName': '告警规则名',
|
||||||
'alerts': '告警',
|
'alerts': '告警',
|
||||||
'alertOutOfRange': '有 @count 项告警规则触发,点击右侧按钮了解详情',
|
'alertOutOfRange': '有 @count 项告警规则触发,点击右侧按钮了解详情',
|
||||||
'alertUnclear': '有 @count 项告警规则并无数据支持,点击右侧按钮了解详情',
|
'alertUnclear': '有 @count 项告警规则并无数据支持,点击右侧按钮了解详情',
|
||||||
@@ -41,5 +42,5 @@ const i18nSimplifiedChinese = {
|
|||||||
'loading': '加载中',
|
'loading': '加载中',
|
||||||
'searchHint': '在下方键入关键词来搜索',
|
'searchHint': '在下方键入关键词来搜索',
|
||||||
'searchNoKeyHint': '无 API 令牌,请先在「设置」>「数据源」设置 API 密钥',
|
'searchNoKeyHint': '无 API 令牌,请先在「设置」>「数据源」设置 API 密钥',
|
||||||
'searchResultHint': '共命中 @count 条记录(截取前 100 条)',
|
'searchResultHint': '共命中 @count 条记录(显示前 100 条)',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ class AlertDetectResultDialog extends StatelessWidget {
|
|||||||
title: Row(
|
title: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(item.name),
|
Text(item.config.name),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Badge(label: Text('#${item.config.nutrientId}'))
|
Badge(label: Text('#${item.config.nutrientId}'))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'${item.current ?? 'undetected'.tr} ${(item.difference ?? 0) > 0 ? '↑' : '↓'}${item.difference?.abs().toPrecision(2) ?? '-'} ${item.unitName ?? ''}',
|
'${item.nutrient?.value ?? 'undetected'.tr} ${(item.difference ?? 0) > 0 ? '↑' : '↓'}${item.difference?.abs().toPrecision(2) ?? '-'} ${item.unitName ?? ''}',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 385 B |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 590 B After Width: | Height: | Size: 823 B |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.0+1
|
version: 1.0.0+2
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.0
|
sdk: ^3.5.0
|
||||||
|
|||||||
BIN
web/favicon.png
|
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 385 B |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 10 KiB |