首次提交
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
/// 充电功率映射表(有线 / 无线)
|
||||
class ChargeMaps {
|
||||
/// 无线充电档位 → 功率(W)
|
||||
static const Map<int, double> wirelessPower = {
|
||||
1: 7.5,
|
||||
2: 15,
|
||||
3: 27,
|
||||
4: 40,
|
||||
5: 50,
|
||||
6: 66,
|
||||
};
|
||||
|
||||
/// 有线充电档位 → 功率(W)
|
||||
/// 新增 27W 档位(对应 9V/3A PPS)
|
||||
static const Map<int, double> wiredPower = {
|
||||
0: 0,
|
||||
1: 7.5,
|
||||
2: 15,
|
||||
3: 18,
|
||||
4: 24,
|
||||
5: 27, // 🟢 新增 27W(9V/3A PPS)
|
||||
6: 30,
|
||||
7: 45,
|
||||
8: 65,
|
||||
9: 80,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'pages/battery_health_page.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: '电池健康度',
|
||||
theme: ThemeData(
|
||||
fontFamily: 'HarmonyOS_Sans_SC',
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const BatteryHealthPage(),
|
||||
debugShowCheckedModeBanner: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/// 机型匹配:设计容量 + 机型名称
|
||||
class DeviceMatching {
|
||||
/// 根据机型返回设计容量(mAh)
|
||||
static int getDesignCapacity(String model) {
|
||||
if (model.contains('22')) return 5510;
|
||||
if (model.contains('21 Pro')) return 5050;
|
||||
if (model.contains('21')) return 4800;
|
||||
if (model.contains('20 Pro')) return 5000;
|
||||
if (model.contains('20 INFINITY')) return 4800;
|
||||
if (model.contains('20')) return 4700;
|
||||
if (model.contains('18s Pro')) return 4500;
|
||||
if (model.contains('18s')) return 4000;
|
||||
if (model.contains('18X')) return 4300;
|
||||
if (model.contains('18 Pro')) return 4500;
|
||||
if (model.contains('18')) return 4000;
|
||||
if (model.contains('17 Pro')) return 4500;
|
||||
if (model.contains('17')) return 4500;
|
||||
if (model.contains('16s Pro')) return 3600;
|
||||
if (model.contains('16s')) return 3600;
|
||||
if (model.contains('16T')) return 4500;
|
||||
if (model.contains('16X')) return 3100;
|
||||
if (model.contains('16Xs')) return 3900;
|
||||
if (model.contains('16th Plus')) return 3640;
|
||||
if (model.contains('16th')) return 3010;
|
||||
if (model.contains('15 Plus')) return 3430;
|
||||
if (model.contains('15')) return 3000;
|
||||
return 5050; // 默认 21 Pro
|
||||
}
|
||||
|
||||
/// 根据机型返回显示名称
|
||||
static String getModelName(String model) {
|
||||
if (model.contains('22')) return '魅族22';
|
||||
if (model.contains('21 Pro')) return '魅族21 Pro';
|
||||
if (model.contains('21')) return '魅族21';
|
||||
if (model.contains('20 Pro')) return '魅族20 Pro';
|
||||
if (model.contains('20 INFINITY')) return '魅族20 INFINITY';
|
||||
if (model.contains('20')) return '魅族20';
|
||||
if (model.contains('18s Pro')) return '魅族18s Pro';
|
||||
if (model.contains('18s')) return '魅族18s';
|
||||
if (model.contains('18X')) return '魅族18X';
|
||||
if (model.contains('18 Pro')) return '魅族18 Pro';
|
||||
if (model.contains('18')) return '魅族18';
|
||||
if (model.contains('17 Pro')) return '魅族17 Pro';
|
||||
if (model.contains('17')) return '魅族17';
|
||||
if (model.contains('16s Pro')) return '魅族16s Pro';
|
||||
if (model.contains('16s')) return '魅族16s';
|
||||
if (model.contains('16T')) return '魅族16T';
|
||||
if (model.contains('16X')) return '魅族16X';
|
||||
if (model.contains('16Xs')) return '魅族16Xs';
|
||||
if (model.contains('16th Plus')) return '魅族16th Plus';
|
||||
if (model.contains('16th')) return '魅族16th';
|
||||
if (model.contains('15 Plus')) return '魅族15 Plus';
|
||||
if (model.contains('15')) return '魅族15';
|
||||
return '魅族21 Pro (默认)';
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
import '../constants/charge_maps.dart';
|
||||
|
||||
class ChargeUtils {
|
||||
static String getDisplayPowerWireless(double power) {
|
||||
if (power == 0) return '读取中...';
|
||||
const List<int> levels = [5, 7, 15, 27, 40, 50, 66];
|
||||
if (power < 3) return '≈${power.round()}W';
|
||||
int matchedLevel = levels.firstWhere(
|
||||
(level) => power <= level + 2,
|
||||
orElse: () => levels.last,
|
||||
);
|
||||
return '≈${matchedLevel}W';
|
||||
}
|
||||
|
||||
static String getDisplayPowerWired(
|
||||
double power,
|
||||
int? wiredLevel,
|
||||
String chargeType,
|
||||
) {
|
||||
// USB 慢充锁定 7.5W
|
||||
if (chargeType == "SDP") return "≈7.5W";
|
||||
|
||||
// 🟢 优先使用 wiredLevel 精确匹配
|
||||
if (wiredLevel != null && ChargeMaps.wiredPower.containsKey(wiredLevel)) {
|
||||
double p = ChargeMaps.wiredPower[wiredLevel]!;
|
||||
if (p > 0) return '≈${p.toInt()}W';
|
||||
}
|
||||
|
||||
// 🟢 匹配阈值收窄到 ±3W,减少跳变
|
||||
double best = 0;
|
||||
for (var entry in ChargeMaps.wiredPower.entries) {
|
||||
if (entry.value <= power + 3 && entry.value > best) {
|
||||
best = entry.value;
|
||||
}
|
||||
}
|
||||
if (power == 0) return '读取中...';
|
||||
return best > 0 ? '≈${best.toInt()}W' : '≈${power.round()}W';
|
||||
}
|
||||
|
||||
static String getChargeTypeLabel(bool isWireless, String chargeType) {
|
||||
if (isWireless) {
|
||||
return chargeType == "无线" ? "无线" : chargeType;
|
||||
}
|
||||
// 🟢 空类型显示"识别中...",比"等待log信息"更友好
|
||||
if (chargeType.isEmpty) {
|
||||
return "识别中...";
|
||||
}
|
||||
if (chargeType == 'PPS') return 'PPS';
|
||||
if (chargeType == 'SDP') return 'USB';
|
||||
return chargeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../utils/charge_utils.dart';
|
||||
|
||||
/// 充电详情页
|
||||
class ChargeDetailPage extends StatelessWidget {
|
||||
final String chargeType;
|
||||
final bool isWireless;
|
||||
final double power;
|
||||
final double volt;
|
||||
final double curr;
|
||||
final int? wiredLevel;
|
||||
|
||||
const ChargeDetailPage({
|
||||
Key? key,
|
||||
required this.chargeType,
|
||||
required this.isWireless,
|
||||
required this.power,
|
||||
required this.volt,
|
||||
required this.curr,
|
||||
this.wiredLevel,
|
||||
}) : super(key: key);
|
||||
|
||||
String _getDisplayPower() {
|
||||
if (isWireless) {
|
||||
return ChargeUtils.getDisplayPowerWireless(power);
|
||||
} else {
|
||||
return ChargeUtils.getDisplayPowerWired(power, wiredLevel, chargeType);
|
||||
}
|
||||
}
|
||||
|
||||
String _getProtocolDisplay() {
|
||||
if (isWireless) return '无线充电($chargeType)';
|
||||
if (chargeType == 'PPS') return 'PPS 快充';
|
||||
if (chargeType == 'SDP') return 'USB 充电'; // 🟢 改成和主页面一致
|
||||
return chargeType;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('充电详情'),
|
||||
backgroundColor: const Color.fromARGB(0, 255, 255, 255),
|
||||
elevation: 0,
|
||||
foregroundColor: Colors.black,
|
||||
iconTheme: const IconThemeData(color: Colors.black),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildDetailRow('协议', _getProtocolDisplay()),
|
||||
const Divider(),
|
||||
_buildDetailRow('功率', _getDisplayPower()),
|
||||
const Divider(),
|
||||
_buildDetailRow('电压', '${volt.toStringAsFixed(2)}V'),
|
||||
const Divider(),
|
||||
_buildDetailRow('电流', '${curr.toStringAsFixed(2)}A'),
|
||||
const Divider(),
|
||||
if (!isWireless && wiredLevel != null)
|
||||
_buildDetailRow('档位', '$wiredLevel'),
|
||||
if (!isWireless && wiredLevel == null) _buildDetailRow('档位', '自动'),
|
||||
if (isWireless) _buildDetailRow('类型', '无线'),
|
||||
const Spacer(),
|
||||
Center(
|
||||
child: Text(
|
||||
'数据来自 BMS 实时日志',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey.shade500),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailRow(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user