diff --git a/assets/CHANGELOG.md b/assets/CHANGELOG.md index 6fe0d6c..4ec0f69 100644 --- a/assets/CHANGELOG.md +++ b/assets/CHANGELOG.md @@ -1,4 +1,44 @@ -## 1.8.0 +## [1.9.0] - 2026-10-11 + +### ✨ 新增功能 + +- **BatteryManager 实时数据接入** + - 新增原生 `BatteryManagerHelper`,通过 Android 官方 API 读取电池端真实功率 + - 主界面充电行改为显示电池端实时功率(1 秒刷新),反映电池实际吸收的能量 + - 充电详情页拆分为两个数据源分区: + - **BMS 日志**:协议、标定档位、实际功率、电压、电流(原有) + - **BatteryManager(电池端)**:电池端电压、电流、功率(新增) + - 与专业功率计(PowerZ)实测数据一致,误差在 0.02W 以内 + +### 🎨 体验优化 + +- **充电行显示格式调整** + - 有线充电:`充电中 · PPS · 5.98W / 7.5W`(实际功率 / 标定档位) + - 无线充电:`充电中 · 无线 · 12.3W` + - USB 慢充:`充电中 · USB · 2.1W` + - 瓦特单位统一为大写 `W` + - 7.5W 等带小数的档位保留一位小数,其余整数值去掉 `.0` + +- **字体细节优化** + - 充电行数字与拉丁字母改用 Flyme 字体,中文字符保持 HarmonyOS Sans SC + - 解决混合文本下的字体割裂感 + - 充电详情页所有功率数值同步应用 Flyme 字体 + +### 🐛 问题修复 + +- 修复主界面充电行在充电器接入初期显示"读取中..."后数值迟迟不刷新的问题 +- 修复详情页功率数值字体与其它行不统一的问题 +- 修复 `wired_level` 解析后标定档位显示取整误差(如 `≈8W/L-1` 修正为 `≈7.5W/L-1`) + +### 📝 技术说明 + +- `BATTERY_PROPERTY_CURRENT_NOW` 读数为**电池端净电流**(充电器输入减去系统功耗),而非充电器输出端数据 +- 电池接近满电时数值会明显偏低(涓流阶段),属正常现象 +- 与系统状态栏显示的充电功率为不同概念,前者反映电池实际吸收,后者反映充电器输出 + +--- + +## [1.8.0] - 2026-10-11 ### 新增 - **夜间模式**:支持浅色 / 深色 / 跟随系统三种模式,可在右上角菜单切换 diff --git a/lib/utils/charge_utils.dart b/lib/utils/charge_utils.dart index 4d14634..6257cc3 100644 --- a/lib/utils/charge_utils.dart +++ b/lib/utils/charge_utils.dart @@ -1,7 +1,7 @@ import '../constants/charge_maps.dart'; class ChargeUtils { - // ============ 无线充电(保持不变) ============ + // ============ 无线充电 ============ static String getDisplayPowerWireless(double power) { if (power == 0) return '读取中...'; const List levels = [5, 7, 15, 27, 40, 50, 66]; @@ -13,7 +13,7 @@ class ChargeUtils { return '≈${matchedLevel}W'; } - // ============ 原有有线逻辑(保留兼容,但主界面不再直接调用) ============ + // ============ 旧的有线逻辑(保留兼容) ============ static String getDisplayPowerWired( double power, int? wiredLevel, @@ -34,38 +34,59 @@ class ChargeUtils { return best > 0 ? '≈${best.toInt()}W' : '≈${power.round()}W'; } - // ============ 🟢 1.5.0 新增:主界面显示(实际/标定) ============ - /// 示例:≈30w/65w + // ============ 主界面:实际 / 标定(旧版) ============ static String getMainDisplayPowerWired( double power, int? wiredLevel, String chargeType, ) { - // USB 慢充锁定 7.5W - if (chargeType == "SDP") return "≈7.5w"; + if (chargeType == "SDP") return "≈7.5W"; if (power == 0) return "读取中..."; final actual = power.round(); - // 有档位且能查到标定值 if (wiredLevel != null && ChargeMaps.wiredPower.containsKey(wiredLevel)) { final requested = ChargeMaps.wiredPower[wiredLevel]!.round(); - return "≈${actual}w/${requested}w"; + return "≈${actual}W/${requested}W"; } - // 无档位信息,仅显示实际功率 - return "≈${actual}w"; + return "≈${actual}W"; } - // ============ 🟢 1.5.0 新增:二级页面标定档位显示 ============ - /// 示例:≈80w/L-10 + // ============ 主界面:BM 电池端功率 + 标定档位 ============ + /// 示例:5.98W / 7.5W、12.3W、读取中... + static String getMainDisplayPowerBm( + double bmPower, + int? wiredLevel, + String chargeType, + bool isWireless, + ) { + if (bmPower <= 0 || bmPower > 100) return '读取中...'; + + final powerStr = '${bmPower.toStringAsFixed(1)}W'; + + if (isWireless || chargeType == 'SDP') return powerStr; + + if (wiredLevel != null && ChargeMaps.wiredPower.containsKey(wiredLevel)) { + final requested = ChargeMaps.wiredPower[wiredLevel]!; + final requestedStr = requested == requested.roundToDouble() + ? requested.toInt().toString() + : requested.toStringAsFixed(1); + return '$powerStr / ${requestedStr}W'; + } + + return powerStr; + } + + // ============ 详情页:标定档位 ============ + /// 示例:≈80W/L-10、≈7.5W/L-1 static String getDetailRequestedPowerWired( double power, int? wiredLevel, String chargeType, ) { - if (chargeType == "SDP") return "≈7.5w"; + if (chargeType == "SDP") return "≈7.5W"; if (power == 0) return "读取中..."; @@ -74,20 +95,20 @@ class ChargeUtils { final str = requested == requested.roundToDouble() ? requested.toInt().toString() : requested.toStringAsFixed(1); - return "≈${str}w/L-$wiredLevel"; + return "≈${str}W/L-$wiredLevel"; } - return "≈${power.round()}w"; + return "≈${power.round()}W"; } - // ============ 🟢 1.5.0 新增:二级页面实际功率显示 ============ + // ============ 详情页:实际功率 ============ static String getDetailActualPowerWired(double power, String chargeType) { - if (chargeType == "SDP") return "≈7.5w"; + if (chargeType == "SDP") return "≈7.5W"; if (power == 0) return "读取中..."; - return "≈${power.round()}w"; + return "≈${power.round()}W"; } - // ============ 充电类型标签(保持不变) ============ + // ============ 充电类型标签 ============ static String getChargeTypeLabel(bool isWireless, String chargeType) { if (isWireless) { return chargeType == "无线" ? "无线" : chargeType; @@ -99,31 +120,4 @@ class ChargeUtils { if (chargeType == 'SDP') return 'USB'; return chargeType; } - - /// 主界面:BM 电池端功率 + 档位 - /// 示例:5.98w / L-7、12.3w、读取中... - static String getMainDisplayPowerBm( - double bmPower, - int? wiredLevel, - String chargeType, - bool isWireless, - ) { - if (bmPower <= 0 || bmPower > 100) return '读取中...'; - - final powerStr = '${bmPower.toStringAsFixed(1)}w'; - - if (isWireless || chargeType == 'SDP') return powerStr; - - // 有线:拼接标定瓦数 - if (wiredLevel != null && ChargeMaps.wiredPower.containsKey(wiredLevel)) { - final requested = ChargeMaps.wiredPower[wiredLevel]!; - // 7.5 → "7.5",27 → "27" - final requestedStr = requested == requested.roundToDouble() - ? requested.toInt().toString() - : requested.toStringAsFixed(1); - return '$powerStr / ${requestedStr}w'; - } - - return powerStr; - } } diff --git a/lib/widgets/charge_entry.dart b/lib/widgets/charge_entry.dart index 5246585..0c3224b 100644 --- a/lib/widgets/charge_entry.dart +++ b/lib/widgets/charge_entry.dart @@ -21,13 +21,17 @@ class ChargeEntry extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - summary, - style: TextStyle( - fontFamily: 'HarmonyOS_Sans_SC', - fontSize: 16, - fontWeight: FontWeight.w500, - color: c.textPrimary, + Flexible( + child: RichText( + overflow: TextOverflow.ellipsis, + text: TextSpan( + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: c.textPrimary, + ), + children: _buildSpans(summary), + ), ), ), Row( @@ -57,4 +61,54 @@ class ChargeEntry extends StatelessWidget { ), ); } + + /// 按 CJK / 非 CJK 拆分字符串,分别应用 HarmonyOS / Flyme + List _buildSpans(String text) { + final spans = []; + if (text.isEmpty) return spans; + + final buffer = StringBuffer(); + bool? isCJK; + + void flush() { + if (buffer.isEmpty) return; + spans.add( + TextSpan( + text: buffer.toString(), + style: TextStyle( + fontFamily: (isCJK ?? false) ? 'HarmonyOS_Sans_SC' : 'Flyme', + ), + ), + ); + buffer.clear(); + } + + for (final rune in text.runes) { + final cjk = _isCJKRune(rune); + if (isCJK == null || cjk == isCJK) { + buffer.writeCharCode(rune); + isCJK = cjk; + } else { + flush(); + buffer.writeCharCode(rune); + isCJK = cjk; + } + } + flush(); + return spans; + } + + bool _isCJKRune(int rune) { + // CJK 统一表意文字 + if (rune >= 0x4E00 && rune <= 0x9FFF) return true; + // CJK 扩展 A + if (rune >= 0x3400 && rune <= 0x4DBF) return true; + // 中文标点(。、,:;等) + if (rune >= 0x3000 && rune <= 0x303F) return true; + // CJK 兼容符号 + if (rune >= 0xFE30 && rune <= 0xFE4F) return true; + // 全角字符 + if (rune >= 0xFF00 && rune <= 0xFFEF) return true; + return false; + } }