✨ Support named alert config
This commit is contained in:
		| @@ -1,15 +1,20 @@ | ||||
| import 'package:dietary_guard/models/food_data.dart'; | ||||
|  | ||||
| class AlertConfiguration { | ||||
|   String name; | ||||
|   int nutrientId; | ||||
|   double maxValue; | ||||
|   double minValue; | ||||
|  | ||||
|   AlertConfiguration({ | ||||
|     required this.name, | ||||
|     required this.nutrientId, | ||||
|     required this.maxValue, | ||||
|     required this.minValue, | ||||
|   }); | ||||
|  | ||||
|   Map<String, dynamic> toJson() => { | ||||
|         'name': name, | ||||
|         'nutrient_id': nutrientId, | ||||
|         'min_value': minValue, | ||||
|         'max_value': maxValue, | ||||
| @@ -17,6 +22,7 @@ class AlertConfiguration { | ||||
|  | ||||
|   factory AlertConfiguration.fromJson(Map<String, dynamic> json) => | ||||
|       AlertConfiguration( | ||||
|         name: json['name'], | ||||
|         nutrientId: json['nutrient_id'], | ||||
|         minValue: json['min_value'], | ||||
|         maxValue: json['max_value'], | ||||
| @@ -25,18 +31,18 @@ class AlertConfiguration { | ||||
|  | ||||
| class AlertDetectResult { | ||||
|   AlertConfiguration config; | ||||
|   FoodNutrient? nutrient; | ||||
|   String name; | ||||
|   String? unitName; | ||||
|   double? current; | ||||
|   double? difference; | ||||
|   bool isOutOfRange; | ||||
|   bool isUndetected; | ||||
|  | ||||
|   AlertDetectResult({ | ||||
|     required this.config, | ||||
|     required this.nutrient, | ||||
|     required this.name, | ||||
|     required this.unitName, | ||||
|     required this.current, | ||||
|     required this.difference, | ||||
|     required this.isOutOfRange, | ||||
|     required this.isUndetected, | ||||
|   | ||||
| @@ -33,14 +33,14 @@ class _FoodDetailsScreenState extends State<FoodDetailsScreen> { | ||||
|       double? difference; | ||||
|       String name = 'undetected'.tr; | ||||
|       String? unitName; | ||||
|       double? current; | ||||
|       FoodNutrient? current; | ||||
|       for (final nutrient in widget.item.foodNutrients) { | ||||
|         if (item.nutrientId != nutrient.nutrientId) continue; | ||||
|         name = nutrient.nutrientName; | ||||
|         unitName = unitNameValues.reverse[nutrient.unitName]; | ||||
|         if (nutrient.value != null) { | ||||
|           current = nutrient; | ||||
|           final value = nutrient.value!; | ||||
|           current = value; | ||||
|           if (value > item.maxValue) { | ||||
|             difference = value - item.maxValue; | ||||
|             isOutOfRange = true; | ||||
| @@ -54,9 +54,9 @@ class _FoodDetailsScreenState extends State<FoodDetailsScreen> { | ||||
|  | ||||
|       _alertDetectResult.add(AlertDetectResult( | ||||
|         config: item, | ||||
|         nutrient: current, | ||||
|         name: name, | ||||
|         unitName: unitName, | ||||
|         current: current, | ||||
|         difference: difference, | ||||
|         isOutOfRange: isOutOfRange, | ||||
|         isUndetected: isUndetected, | ||||
|   | ||||
| @@ -16,6 +16,7 @@ class _AlertSettingsScreenState extends State<AlertSettingsScreen> { | ||||
|   void _addAlert() { | ||||
|     setState(() { | ||||
|       _currentAlerts.add(AlertConfiguration( | ||||
|         name: 'Alert #${_currentAlerts.length}', | ||||
|         nutrientId: 0, | ||||
|         maxValue: 0, | ||||
|         minValue: 0, | ||||
| @@ -64,16 +65,16 @@ class _AlertSettingsScreenState extends State<AlertSettingsScreen> { | ||||
|                       children: [ | ||||
|                         Expanded( | ||||
|                           child: TextFormField( | ||||
|                             initialValue: x.nutrientId.toString(), | ||||
|                             initialValue: x.name, | ||||
|                             decoration: InputDecoration( | ||||
|                               border: const OutlineInputBorder(), | ||||
|                               label: Text("alertNutrientId".tr), | ||||
|                               label: Text("alertName".tr), | ||||
|                               isDense: true, | ||||
|                             ), | ||||
|                             onTapOutside: (_) => | ||||
|                                 FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                             onChanged: (value) { | ||||
|                               x.nutrientId = int.tryParse(value) ?? 0; | ||||
|                               x.name = value; | ||||
|                             }, | ||||
|                           ), | ||||
|                         ), | ||||
| @@ -87,6 +88,20 @@ class _AlertSettingsScreenState extends State<AlertSettingsScreen> { | ||||
|                       ], | ||||
|                     ), | ||||
|                     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( | ||||
|                       children: [ | ||||
|                         Expanded( | ||||
|   | ||||
| @@ -17,6 +17,7 @@ const i18nEnglish = { | ||||
|   'alertNutrientId': 'Nutrient ID', | ||||
|   'alertMaxValue': 'Alert Max Value', | ||||
|   'alertMinValue': 'Alert Min Value', | ||||
|   'alertName': 'Alert Name', | ||||
|   'alerts': 'Alerts', | ||||
|   'alertOutOfRange': | ||||
|       '@count alert rules triggered, click the button on the right for details', | ||||
|   | ||||
| @@ -17,6 +17,7 @@ const i18nSimplifiedChinese = { | ||||
|   'alertNutrientId': '营养物质编号', | ||||
|   'alertMaxValue': '告警上限', | ||||
|   'alertMinValue': '告警下限', | ||||
|   'alertName': '告警规则名', | ||||
|   'alerts': '告警', | ||||
|   'alertOutOfRange': '有 @count 项告警规则触发,点击右侧按钮了解详情', | ||||
|   'alertUnclear': '有 @count 项告警规则并无数据支持,点击右侧按钮了解详情', | ||||
|   | ||||
| @@ -60,13 +60,13 @@ class AlertDetectResultDialog extends StatelessWidget { | ||||
|                   title: Row( | ||||
|                     crossAxisAlignment: CrossAxisAlignment.center, | ||||
|                     children: [ | ||||
|                       Text(item.name), | ||||
|                       Text(item.config.name), | ||||
|                       const SizedBox(width: 6), | ||||
|                       Badge(label: Text('#${item.config.nutrientId}')) | ||||
|                     ], | ||||
|                   ), | ||||
|                   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 ?? ''}', | ||||
|                   ), | ||||
|                 ); | ||||
|               }, | ||||
|   | ||||
| @@ -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 | ||||
| # 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. | ||||
| version: 1.0.0+1 | ||||
| version: 1.0.0+2 | ||||
|  | ||||
| environment: | ||||
|   sdk: ^3.5.0 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user