更新日志界面优化、主页部分动画调整

This commit is contained in:
2026-07-20 23:34:42 +08:00
parent 0d8c6b081d
commit 5e755d860f
4 changed files with 114 additions and 110 deletions
+1 -1
View File
@@ -54,7 +54,7 @@
flutter pub get flutter pub get
# Debug 版本 # Debug 版本
flutter run flutter run --debug
# Release APK # Release APK
flutter build apk --release --target-platform android-arm64 flutter build apk --release --target-platform android-arm64
+109 -108
View File
@@ -18,8 +18,8 @@ import '../widgets/battery_summary.dart';
import '../widgets/battery_info_panel.dart'; import '../widgets/battery_info_panel.dart';
import '../widgets/charge_entry.dart'; import '../widgets/charge_entry.dart';
import '../widgets/charge_detail_page.dart'; import '../widgets/charge_detail_page.dart';
import '../widgets/battery_data_layout.dart'; // 🆕 1.6.0 UI 拆分 import '../widgets/trend_chart.dart';
import '../pages/changelog_page.dart'; // 🆕 1.6.0 更新日志 import '../pages/changelog_page.dart';
// --- 潘通色定义 --- // --- 潘通色定义 ---
const Color kHealthGreen = Color(0xFF00B140); const Color kHealthGreen = Color(0xFF00B140);
@@ -33,8 +33,7 @@ class BatteryHealthPage extends StatefulWidget {
State<BatteryHealthPage> createState() => _BatteryHealthPageState(); State<BatteryHealthPage> createState() => _BatteryHealthPageState();
} }
class _BatteryHealthPageState extends State<BatteryHealthPage> class _BatteryHealthPageState extends State<BatteryHealthPage> {
with SingleTickerProviderStateMixin {
// ---------- 数据 ---------- // ---------- 数据 ----------
double _currentCap = 0; double _currentCap = 0;
int _cycleCount = 0; int _cycleCount = 0;
@@ -67,11 +66,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
final BatteryDataService _dataService = BatteryDataService(); final BatteryDataService _dataService = BatteryDataService();
SafPermissionState _safState = SafPermissionState.unauthorized; SafPermissionState _safState = SafPermissionState.unauthorized;
// 动画控制
late AnimationController _chargeAnimationController;
late Animation<double> _bottomSlide;
late Animation<double> _entryFadeIn;
// 平台通道 // 平台通道
static const _methodChannel = MethodChannel('com.lxh.battery_health/charge'); static const _methodChannel = MethodChannel('com.lxh.battery_health/charge');
static const _eventChannel = EventChannel( static const _eventChannel = EventChannel(
@@ -88,8 +82,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
super.initState(); super.initState();
dev.log('🔵 ========== initState 开始 ==========', name: 'BatteryHealth'); dev.log('🔵 ========== initState 开始 ==========', name: 'BatteryHealth');
_initAnimations();
_getInitialChargeState(); _getInitialChargeState();
_chargeEventSubscription = _eventChannel.receiveBroadcastStream().listen(( _chargeEventSubscription = _eventChannel.receiveBroadcastStream().listen((
@@ -135,31 +127,10 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
void dispose() { void dispose() {
_chargeEventSubscription?.cancel(); _chargeEventSubscription?.cancel();
_pollTimer?.cancel(); _pollTimer?.cancel();
_chargeAnimationController.dispose();
_dbService.database.then((db) => db.close()).ignore(); _dbService.database.then((db) => db.close()).ignore();
super.dispose(); super.dispose();
} }
// ---------- 动画初始化 ----------
void _initAnimations() {
_chargeAnimationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
_bottomSlide = Tween<double>(begin: 0, end: 24).animate(
CurvedAnimation(
parent: _chargeAnimationController,
curve: Curves.easeInOutCubic,
),
);
_entryFadeIn = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(
parent: _chargeAnimationController,
curve: const Interval(0.0, 0.5, curve: Curves.easeIn),
),
);
}
// ---------- 设备信息 ---------- // ---------- 设备信息 ----------
Future<void> _getDeviceInfo() async { Future<void> _getDeviceInfo() async {
dev.log('🔵 _getDeviceInfo 开始', name: 'BatteryHealth'); dev.log('🔵 _getDeviceInfo 开始', name: 'BatteryHealth');
@@ -276,7 +247,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
_chargeCurr = 0.0; _chargeCurr = 0.0;
_wiredLevel = null; _wiredLevel = null;
_chargingStartTime = null; _chargingStartTime = null;
_updateChargeState();
return; return;
} }
@@ -311,7 +281,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
_chargePower = 0.0; _chargePower = 0.0;
_chargeVolt = 0.0; _chargeVolt = 0.0;
_chargeCurr = 0.0; _chargeCurr = 0.0;
_updateChargeState();
}); });
if (_isCharging) { if (_isCharging) {
@@ -350,7 +319,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
_currentCap = recent.first['capacity'].toDouble(); _currentCap = recent.first['capacity'].toDouble();
_maxVolt = recent.first['volt_max'] ?? 0; _maxVolt = recent.first['volt_max'] ?? 0;
_minVolt = recent.first['volt_min'] ?? 0; _minVolt = recent.first['volt_min'] ?? 0;
// 🟢 数据库目前不存温度,后续升级可扩展,暂时保留为 0
_maxTemp = 0; _maxTemp = 0;
_minTemp = 0; _minTemp = 0;
_cycleCount = 0; _cycleCount = 0;
@@ -362,8 +330,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
setState(() => _hasData = false); setState(() => _hasData = false);
} }
if (_isCharging) _fetchChargeDataFromLog(); if (_isCharging) _fetchChargeDataFromLog();
_chargeAnimationController.reset();
_updateChargeState();
return; return;
} }
@@ -375,23 +341,16 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
dev.log('🔵 文件为空', name: 'BatteryHealth'); dev.log('🔵 文件为空', name: 'BatteryHealth');
setState(() => _hasData = false); setState(() => _hasData = false);
if (_isCharging) _fetchChargeDataFromLog(); if (_isCharging) _fetchChargeDataFromLog();
_chargeAnimationController.reset();
_updateChargeState();
return; return;
} }
// 🟢 提取所有有效行(包含 tbat=)
final validLines = lines.where((line) => line.contains('tbat=')).toList(); final validLines = lines.where((line) => line.contains('tbat=')).toList();
if (validLines.isEmpty) { if (validLines.isEmpty) {
dev.log('🔵 无有效数据行', name: 'BatteryHealth'); dev.log('🔵 无有效数据行', name: 'BatteryHealth');
setState(() => _hasData = false); setState(() => _hasData = false);
_chargeAnimationController.reset();
_updateChargeState();
return; return;
} }
// 🟢 1.4.7 核心改动:字段提取与容量提取解耦
// 无论 cap 是否为 null,都提取常规字段
final lastLine = validLines.last; final lastLine = validLines.last;
final cycle = _extractCycle(lastLine); final cycle = _extractCycle(lastLine);
final temp = _extractTemp(lastLine); final temp = _extractTemp(lastLine);
@@ -404,16 +363,13 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
name: 'BatteryHealth', name: 'BatteryHealth',
); );
// 🟢 容量提取(可能为 null)
final cap = CapacityExtractor.extractCapacity(lines); final cap = CapacityExtractor.extractCapacity(lines);
int? finalCap; int? finalCap;
if (cap != null) { if (cap != null) {
// ✅ 今日有充满记录,直接使用
finalCap = cap; finalCap = cap;
dev.log('🔵 从日志提取容量: $cap', name: 'BatteryHealth'); dev.log('🔵 从日志提取容量: $cap', name: 'BatteryHealth');
} else { } else {
// ⚠️ 今日无充满记录,尝试从数据库复制前一天容量
dev.log('🔵 今日无充满记录,尝试复制前一天容量', name: 'BatteryHealth'); dev.log('🔵 今日无充满记录,尝试复制前一天容量', name: 'BatteryHealth');
final recent = await _dbService.queryRecentData(1); final recent = await _dbService.queryRecentData(1);
if (recent.isNotEmpty) { if (recent.isNotEmpty) {
@@ -425,7 +381,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
} }
} }
// 🟢 一次性 setState 更新所有字段
setState(() { setState(() {
_currentCap = (finalCap ?? _currentCap).toDouble(); _currentCap = (finalCap ?? _currentCap).toDouble();
_cycleCount = cycle; _cycleCount = cycle;
@@ -444,8 +399,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
} }
await _updateTrendChart(); await _updateTrendChart();
_chargeAnimationController.reset();
_updateChargeState();
dev.log( dev.log(
'🔵 ========== readBatteryCapacity 完成 ==========', '🔵 ========== readBatteryCapacity 完成 ==========',
name: 'BatteryHealth', name: 'BatteryHealth',
@@ -453,8 +406,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
} catch (e) { } catch (e) {
dev.log('🔵 readBatteryCapacity 异常: $e', name: 'BatteryHealth'); dev.log('🔵 readBatteryCapacity 异常: $e', name: 'BatteryHealth');
setState(() => _hasData = false); setState(() => _hasData = false);
_chargeAnimationController.reset();
_updateChargeState();
} }
} }
@@ -588,26 +539,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
} }
} }
// ---------- 动画控制 ----------
void _startChargeAnimation() {
if (_chargeAnimationController.isAnimating) return;
_chargeAnimationController.forward();
}
void _stopChargeAnimation() {
if (_chargeAnimationController.isAnimating) return;
_chargeAnimationController.reverse();
}
void _updateChargeState() {
if (!mounted) return;
if (_isCharging) {
_startChargeAnimation();
} else {
_stopChargeAnimation();
}
}
// ---------- 显示辅助 ---------- // ---------- 显示辅助 ----------
String _getDisplayPower() { String _getDisplayPower() {
if (!_isCharging) return ''; if (!_isCharging) return '';
@@ -629,7 +560,6 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
// ---------- Build ---------- // ---------- Build ----------
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// 计算健康度百分比(显式转为 double)
final double healthPercent = (_designCap > 0) final double healthPercent = (_designCap > 0)
? (_currentCap / _designCap) * 100 ? (_currentCap / _designCap) * 100
: 0.0; : 0.0;
@@ -661,14 +591,12 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
), ),
), ),
actions: [ actions: [
// 刷新按钮(左移)
IconButton( IconButton(
icon: const Icon(Icons.refresh), icon: const Icon(Icons.refresh),
onPressed: readBatteryCapacity, onPressed: readBatteryCapacity,
tooltip: '刷新数据', tooltip: '刷新数据',
color: Colors.black, color: Colors.black,
), ),
// 三点菜单
PopupMenuButton<String>( PopupMenuButton<String>(
icon: const Icon(Icons.more_vert), icon: const Icon(Icons.more_vert),
color: Colors.white, color: Colors.white,
@@ -683,10 +611,8 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
); );
break; break;
case 'dark_mode': case 'dark_mode':
// 1.7 再实现
break; break;
case 'about': case 'about':
// 1.7 再实现
break; break;
} }
}, },
@@ -707,38 +633,113 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
], ],
), ),
body: _hasData body: _hasData
? AnimatedBuilder( ? Column(
animation: _chargeAnimationController, children: [
builder: (context, child) { // 🟢 可滚动区域(带 RepaintBoundary
// 🟢 修复:传入 healthPercent 为 double,移除未定义的动画参数 Expanded(
// 动画在 BatteryDataLayout 内部不处理,由父级 AnimatedBuilder 控制 child: SingleChildScrollView(
return BatteryDataLayout( padding: const EdgeInsets.all(20.0),
deviceModel: _deviceModel, child: Column(
healthPercent: healthPercent, crossAxisAlignment: CrossAxisAlignment.start,
cycleCount: _cycleCount, children: [
currentCap: _currentCap, // 设备型号
designCap: _designCap, Text(
trendData: _trendData, _deviceModel,
isCharging: _isCharging, style: const TextStyle(
chargeSummary: chargeSummary, fontSize: 14,
batteryVolt: _batteryVolt, color: Colors.grey,
batteryTemp: _batteryTemp, fontWeight: FontWeight.w400,
maxVolt: _maxVolt, ),
minVolt: _minVolt, ),
maxTemp: _maxTemp, const SizedBox(height: 4),
minTemp: _minTemp,
chargeType: _chargeType, // 🟢 BatterySummary 用 RepaintBoundary 隔离
isWireless: _isWireless, RepaintBoundary(
chargePower: _chargePower, child: BatterySummary(
chargeVolt: _chargeVolt, healthPercent: healthPercent,
chargeCurr: _chargeCurr, cycleCount: _cycleCount,
wiredLevel: _wiredLevel, currentCap: _currentCap,
// 🟢 动画参数由父级 AnimatedBuilder 控制, designCap: _designCap,
// BatteryDataLayout 不再需要透传 animation 参数 ),
); ),
},
const SizedBox(height: 24),
// 🟢 TrendChart 用 RepaintBoundary 隔离
RepaintBoundary(
child: TrendChart(
data: _trendData,
designCap: _designCap,
),
),
const SizedBox(height: 8),
// 🟢 充电条目 - 保留 AnimatedOpacity,但加 RepaintBoundary
RepaintBoundary(
child: AnimatedOpacity(
opacity: _isCharging ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
child: ChargeEntry(
summary: chargeSummary,
isCharging: _isCharging,
onTap: () {
if (_isCharging) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChargeDetailPage(
chargeType: _chargeType,
isWireless: _isWireless,
power: _chargePower,
volt: _chargeVolt,
curr: _chargeCurr,
wiredLevel: _wiredLevel,
),
),
);
}
},
),
),
),
const SizedBox(height: 4),
// 🟢 BatteryInfoPanel 也用 RepaintBoundary
RepaintBoundary(
child: BatteryInfoPanel(
batteryVolt: _batteryVolt,
batteryTemp: _batteryTemp,
maxVolt: _maxVolt,
minVolt: _minVolt,
maxTemp: _maxTemp,
minTemp: _minTemp,
),
),
],
),
),
),
],
) )
: const EmptyStateLayout(), : const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.battery_unknown, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text(
'暂无数据',
style: TextStyle(fontSize: 18, color: Colors.grey),
),
Text(
'点击右上角刷新尝试',
style: TextStyle(fontSize: 14, color: Colors.grey),
),
],
),
),
), ),
); );
} }
+3 -1
View File
@@ -65,9 +65,11 @@ class _ChangelogPageState extends State<ChangelogPage> {
), ),
) )
: SingleChildScrollView( : SingleChildScrollView(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(16.0),
child: Markdown( child: Markdown(
data: _markdownContent, data: _markdownContent,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
styleSheet: MarkdownStyleSheet( styleSheet: MarkdownStyleSheet(
h1: const TextStyle( h1: const TextStyle(
fontFamily: 'HarmonyOS_Sans_SC', fontFamily: 'HarmonyOS_Sans_SC',
+1
View File
@@ -81,6 +81,7 @@ flutter:
- asset: assets/fonts/flymeFont.ttf - asset: assets/fonts/flymeFont.ttf
assets: assets:
- assets/icons/ - assets/icons/
- assets/CHANGELOG.md
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
# assets: # assets: