From c8717e5e1f22e1365f294a14eb88366ca5080217 Mon Sep 17 00:00:00 2001 From: lxh2875931338 Date: Thu, 30 Jul 2026 21:57:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BD=9C=E5=BC=8A=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/data_abnormal_type.dart | 13 ++++++ lib/pages/battery_health_page.dart | 70 ++++++++++++++++++++++++++--- lib/pages/changelog_page.dart | 1 - lib/widgets/battery_info_panel.dart | 37 ++++++++++++--- lib/widgets/battery_summary.dart | 38 +++++++++++----- pubspec.yaml | 2 +- 6 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 lib/models/data_abnormal_type.dart diff --git a/lib/models/data_abnormal_type.dart b/lib/models/data_abnormal_type.dart new file mode 100644 index 0000000..16febd7 --- /dev/null +++ b/lib/models/data_abnormal_type.dart @@ -0,0 +1,13 @@ +enum DataAbnormalType { + /// 无异常 + none, + + /// 容量低于设计容量 60% + capacityTooLow, + + /// 容量高于设计容量 115% + capacityTooHigh, + + /// 电压异常(< 3.0V 或 > 5.0V) + voltageAbnormal, +} diff --git a/lib/pages/battery_health_page.dart b/lib/pages/battery_health_page.dart index 5cc5f27..3fd6c31 100644 --- a/lib/pages/battery_health_page.dart +++ b/lib/pages/battery_health_page.dart @@ -7,6 +7,7 @@ import 'package:device_info_plus/device_info_plus.dart'; // --- 本地导入 --- import '../models/device_matching.dart'; import '../models/saf_permission_state.dart'; +import '../models/data_abnormal_type.dart'; // 🆕 1.7.0 import '../services/database_service.dart'; import '../services/battery_data_service.dart'; import '../services/saf_storage_service.dart'; @@ -381,8 +382,11 @@ class _BatteryHealthPageState extends State { } } + // 🟢 1.7.0 容量有效性校验 + final validatedCap = _validateCapacity(finalCap, _designCap); + setState(() { - _currentCap = (finalCap ?? _currentCap).toDouble(); + _currentCap = (validatedCap ?? _currentCap).toDouble(); _cycleCount = cycle; _batteryTemp = temp; _batteryVolt = volt; @@ -409,6 +413,53 @@ class _BatteryHealthPageState extends State { } } + // ---------- 🆕 1.7.0 容量有效性校验 ---------- + int? _validateCapacity(int? capacity, int designCap) { + if (capacity == null) return null; + + // 容量必须大于 0 + if (capacity <= 0) { + dev.log('⚠️ 容量异常:<= 0,已忽略', name: 'BatteryHealth'); + return null; + } + + // 容量不能低于设计容量的 60% + if (capacity < designCap * 0.6) { + dev.log( + '⚠️ 容量异常:低于设计容量 60%($capacity < ${designCap * 0.6}),已忽略', + name: 'BatteryHealth', + ); + return null; + } + + // 容量不能超过设计容量的 115% + if (capacity > designCap * 1.15) { + dev.log( + '⚠️ 容量异常:高于设计容量 115%($capacity > ${designCap * 1.15}),已忽略', + name: 'BatteryHealth', + ); + return null; + } + + return capacity; + } + + // ---------- 🆕 1.7.0 异常检测(供 UI 使用) ---------- + DataAbnormalType _checkAbnormalType( + double currentCap, + int designCap, + double voltage, + ) { + // 容量异常:高于 115% 或低于 60% + if (currentCap > designCap * 1.15) return DataAbnormalType.capacityTooHigh; + if (currentCap < designCap * 0.6) return DataAbnormalType.capacityTooLow; + + // 电压异常:低于 3.0V 或高于 5.0V + if (voltage < 3.0 || voltage > 5.0) return DataAbnormalType.voltageAbnormal; + + return DataAbnormalType.none; + } + // ---------- 辅助提取方法 ---------- int _extractCycle(String line) { final reg = RegExp(r'cycle=(\d+)'); @@ -568,6 +619,13 @@ class _BatteryHealthPageState extends State { ? '充电中 · ${_getChargeTypeLabel()} · ${_getDisplayPower()}' : ''; + // 🆕 1.7.0 异常检测 + final abnormalType = _checkAbnormalType( + _currentCap, + _designCap, + _batteryVolt, + ); + return AnnotatedRegion( value: const SystemUiOverlayStyle( statusBarColor: Color.fromRGBO(157, 212, 237, 0.1), @@ -635,14 +693,12 @@ class _BatteryHealthPageState extends State { body: _hasData ? Column( children: [ - // 🟢 可滚动区域(带 RepaintBoundary) Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // 设备型号 Text( _deviceModel, style: const TextStyle( @@ -653,19 +709,19 @@ class _BatteryHealthPageState extends State { ), const SizedBox(height: 4), - // 🟢 BatterySummary 用 RepaintBoundary 隔离 + // 🟢 BatterySummary(带异常检测) RepaintBoundary( child: BatterySummary( healthPercent: healthPercent, cycleCount: _cycleCount, currentCap: _currentCap, designCap: _designCap, + abnormalType: abnormalType, // 🆕 1.7.0 ), ), const SizedBox(height: 24), - // 🟢 TrendChart 用 RepaintBoundary 隔离 RepaintBoundary( child: TrendChart( data: _trendData, @@ -675,7 +731,6 @@ class _BatteryHealthPageState extends State { const SizedBox(height: 8), - // 🟢 充电条目 - 保留 AnimatedOpacity,但加 RepaintBoundary RepaintBoundary( child: AnimatedOpacity( opacity: _isCharging ? 1.0 : 0.0, @@ -706,7 +761,7 @@ class _BatteryHealthPageState extends State { const SizedBox(height: 4), - // 🟢 BatteryInfoPanel 也用 RepaintBoundary + // 🟢 BatteryInfoPanel(带异常检测) RepaintBoundary( child: BatteryInfoPanel( batteryVolt: _batteryVolt, @@ -715,6 +770,7 @@ class _BatteryHealthPageState extends State { minVolt: _minVolt, maxTemp: _maxTemp, minTemp: _minTemp, + abnormalType: abnormalType, // 🆕 1.7.0 ), ), ], diff --git a/lib/pages/changelog_page.dart b/lib/pages/changelog_page.dart index 1ed2fdf..0ebcecf 100644 --- a/lib/pages/changelog_page.dart +++ b/lib/pages/changelog_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // 🟢 添加这一行 -import 'package:flutter/services.dart' show rootBundle; import 'package:flutter_markdown/flutter_markdown.dart'; class ChangelogPage extends StatefulWidget { diff --git a/lib/widgets/battery_info_panel.dart b/lib/widgets/battery_info_panel.dart index e77c45a..c4c0192 100644 --- a/lib/widgets/battery_info_panel.dart +++ b/lib/widgets/battery_info_panel.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import '../models/data_abnormal_type.dart'; class BatteryInfoPanel extends StatelessWidget { final double batteryVolt; @@ -8,6 +9,7 @@ class BatteryInfoPanel extends StatelessWidget { final double minVolt; final double maxTemp; final double minTemp; + final DataAbnormalType abnormalType; const BatteryInfoPanel({ super.key, @@ -17,10 +19,15 @@ class BatteryInfoPanel extends StatelessWidget { required this.minVolt, required this.maxTemp, required this.minTemp, + this.abnormalType = DataAbnormalType.none, }); @override Widget build(BuildContext context) { + final bool isVoltageAbnormal = + abnormalType == DataAbnormalType.voltageAbnormal; + final Color voltColor = isVoltageAbnormal ? Colors.red : Colors.black; + return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -32,6 +39,7 @@ class BatteryInfoPanel extends StatelessWidget { _buildIcon('voltage'), '电压', '${batteryVolt.toStringAsFixed(3)}V', + textColor: voltColor, ), const SizedBox(height: 8), Row( @@ -52,7 +60,12 @@ class BatteryInfoPanel extends StatelessWidget { color: Colors.red, ), ), - TextSpan(text: '${maxVolt.toStringAsFixed(3)}V'), + TextSpan( + text: '${maxVolt.toStringAsFixed(3)}V', + style: TextStyle( + color: isVoltageAbnormal ? Colors.red : Colors.red, + ), + ), ], ), ), @@ -73,7 +86,12 @@ class BatteryInfoPanel extends StatelessWidget { color: Colors.blue, ), ), - TextSpan(text: '${minVolt.toStringAsFixed(3)}V'), + TextSpan( + text: '${minVolt.toStringAsFixed(3)}V', + style: TextStyle( + color: isVoltageAbnormal ? Colors.red : Colors.blue, + ), + ), ], ), ), @@ -96,7 +114,7 @@ class BatteryInfoPanel extends StatelessWidget { children: [ RichText( text: TextSpan( - style: TextStyle( + style: const TextStyle( fontFamily: 'Flyme', fontSize: 14, fontWeight: FontWeight.w500, @@ -117,7 +135,7 @@ class BatteryInfoPanel extends StatelessWidget { const SizedBox(width: 12), RichText( text: TextSpan( - style: TextStyle( + style: const TextStyle( fontFamily: 'Flyme', fontSize: 14, fontWeight: FontWeight.w500, @@ -165,7 +183,12 @@ class BatteryInfoPanel extends StatelessWidget { } } - Widget _buildInfoItem(Widget icon, String label, String value) { + Widget _buildInfoItem( + Widget icon, + String label, + String value, { + Color textColor = Colors.black, + }) { return Row( children: [ icon, @@ -181,11 +204,11 @@ class BatteryInfoPanel extends StatelessWidget { const SizedBox(width: 6), Text( value, - style: const TextStyle( + style: TextStyle( fontFamily: 'Flyme', fontSize: 16, fontWeight: FontWeight.w500, - color: Colors.black, + color: textColor, ), ), ], diff --git a/lib/widgets/battery_summary.dart b/lib/widgets/battery_summary.dart index c6a02d8..7e1c31b 100644 --- a/lib/widgets/battery_summary.dart +++ b/lib/widgets/battery_summary.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; +import '../models/data_abnormal_type.dart'; class BatterySummary extends StatelessWidget { final double healthPercent; final int cycleCount; final double currentCap; final int designCap; + final DataAbnormalType abnormalType; const BatterySummary({ super.key, @@ -12,11 +14,25 @@ class BatterySummary extends StatelessWidget { required this.cycleCount, required this.currentCap, required this.designCap, + this.abnormalType = DataAbnormalType.none, }); @override Widget build(BuildContext context) { - final bool isLowHealth = healthPercent < 70; + final bool isAbnormal = abnormalType != DataAbnormalType.none; + final bool isCapacityAbnormal = + abnormalType == DataAbnormalType.capacityTooLow || + abnormalType == DataAbnormalType.capacityTooHigh; + + // 健康度颜色:异常时红色,否则按阈值 + final Color healthColor = isAbnormal + ? Colors.red + : (healthPercent < 70 ? Colors.red : Colors.black); + + // 容量颜色:异常时红色,否则灰色 + final Color capacityColor = isCapacityAbnormal + ? Colors.red + : const Color(0xFF5F5F5F); return Row( crossAxisAlignment: CrossAxisAlignment.end, @@ -33,7 +49,7 @@ class BatterySummary extends StatelessWidget { fontSize: 40, fontWeight: FontWeight.w500, height: 1.0, - color: isLowHealth ? Colors.red : Colors.black, + color: healthColor, ), ), const SizedBox(width: 2), @@ -44,7 +60,9 @@ class BatterySummary extends StatelessWidget { fontSize: 20, fontWeight: FontWeight.w300, height: 1.0, - color: isLowHealth ? Colors.red : Colors.grey.shade600, + color: healthColor == Colors.red + ? Colors.red + : Colors.grey.shade600, ), ), ], @@ -56,7 +74,7 @@ class BatterySummary extends StatelessWidget { children: [ RichText( text: TextSpan( - style: TextStyle( + style: const TextStyle( fontFamily: 'Flyme', fontSize: 16, fontWeight: FontWeight.w500, @@ -65,9 +83,9 @@ class BatterySummary extends StatelessWidget { ), children: [ TextSpan(text: '$cycleCount'), - TextSpan( + const TextSpan( text: ' cycles', - style: const TextStyle( + style: TextStyle( fontFamily: 'HarmonyOS_Sans_SC', color: Colors.black, ), @@ -83,7 +101,7 @@ class BatterySummary extends StatelessWidget { fontSize: 20, fontWeight: FontWeight.w300, height: 1.0, - color: const Color(0xFF5F5F5F), + color: capacityColor, ), children: [ TextSpan(text: currentCap.toStringAsFixed(0)), @@ -91,17 +109,17 @@ class BatterySummary extends StatelessWidget { text: ' / ', style: TextStyle( fontFamily: 'HarmonyOS_Sans_SC', - color: const Color(0xFF5F5F5F).withValues(alpha: 0.5), + color: capacityColor.withOpacity(0.5), ), ), TextSpan(text: designCap.toString()), TextSpan( text: ' mAh', - style: const TextStyle( + style: TextStyle( fontFamily: 'HarmonyOS_Sans_SC', fontSize: 16, fontWeight: FontWeight.w500, - color: Color(0xFF5F5F5F), + color: capacityColor, ), ), ], diff --git a/pubspec.yaml b/pubspec.yaml index ea4c1f7..d86b9bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.6.0 +version: 1.7.0 environment: sdk: ^3.9.2