import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'dart:async'; import '../models/client_status.dart'; import '../core/mining_manager.dart'; class MiningInfoScreen extends StatefulWidget { final MiningInfo miningInfo; const MiningInfoScreen({ super.key, required this.miningInfo, }); @override State createState() => _MiningInfoScreenState(); } class _MiningInfoScreenState extends State { final MiningManager _miningManager = MiningManager(); final ScrollController _logScrollController = ScrollController(); final List _minerLogs = []; StreamSubscription? _logSubscription; bool _autoScroll = true; @override void initState() { super.initState(); _startLogMonitoring(); } void _startLogMonitoring() { _logSubscription = _miningManager.minerLogStream.listen((log) { setState(() { _minerLogs.add(log); // 限制日志行数,避免内存溢出 if (_minerLogs.length > 1000) { _minerLogs.removeAt(0); } }); if (_autoScroll && _logScrollController.hasClients) { _scrollToBottom(); } }); } void _scrollToBottom() { if (_logScrollController.hasClients) { _logScrollController.animateTo( _logScrollController.position.maxScrollExtent, duration: const Duration(milliseconds: 300), curve: Curves.easeOut, ); } } @override void dispose() { _logSubscription?.cancel(); _logScrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final endTime = DateTime.fromMillisecondsSinceEpoch(widget.miningInfo.endTimestamp * 1000); final formatter = DateFormat('yyyy-MM-dd HH:mm:ss'); return Scaffold( appBar: AppBar( title: const Text('挖矿信息'), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 挖矿任务信息卡片 Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '当前挖矿任务', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), const Divider(), _buildInfoRow('币种', widget.miningInfo.coin), _buildInfoRow('算法', widget.miningInfo.algo), _buildInfoRow('矿池', widget.miningInfo.pool), _buildInfoRow('矿池地址', widget.miningInfo.poolUrl), _buildInfoRow('钱包地址', widget.miningInfo.walletAddress), _buildInfoRow('矿工号', widget.miningInfo.workerId), if (widget.miningInfo.miner != null) _buildInfoRow('挖矿软件', widget.miningInfo.miner!), if (widget.miningInfo.pid != null) _buildInfoRow('进程ID', widget.miningInfo.pid.toString()), _buildInfoRow( '结束时间', formatter.format(endTime), ), const SizedBox(height: 16), _buildTimeRemaining(endTime), ], ), ), ), const SizedBox(height: 16), // 挖矿日志卡片 Card( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ const Text( '挖矿日志', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), const Spacer(), IconButton( icon: Icon(_autoScroll ? Icons.arrow_downward : Icons.arrow_upward), onPressed: () { setState(() { _autoScroll = !_autoScroll; }); }, tooltip: _autoScroll ? '关闭自动滚动' : '开启自动滚动', ), IconButton( icon: const Icon(Icons.clear), onPressed: () { setState(() { _minerLogs.clear(); }); }, tooltip: '清空日志', ), ], ), ), const Divider(height: 1), Container( height: 400, padding: const EdgeInsets.all(8.0), child: _minerLogs.isEmpty ? const Center( child: Text( '暂无日志输出', style: TextStyle(color: Colors.grey), ), ) : SingleChildScrollView( controller: _logScrollController, child: SelectableText( _minerLogs.join('\n'), style: const TextStyle( fontFamily: 'monospace', fontSize: 12, ), ), ), ), ], ), ), ], ), ), ); } Widget _buildInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 100, child: Text( '$label:', style: const TextStyle(fontWeight: FontWeight.w500), ), ), Expanded( child: Text(value), ), ], ), ); } Widget _buildTimeRemaining(DateTime endTime) { final now = DateTime.now(); final remaining = endTime.difference(now); if (remaining.isNegative) { return const Card( color: Colors.red, child: Padding( padding: EdgeInsets.all(8.0), child: Text( '任务已结束', style: TextStyle(color: Colors.white), ), ), ); } final hours = remaining.inHours; final minutes = remaining.inMinutes.remainder(60); final seconds = remaining.inSeconds.remainder(60); return Card( color: Colors.green, child: Padding( padding: const EdgeInsets.all(8.0), child: Text( '剩余时间: ${hours}小时 ${minutes}分钟 ${seconds}秒', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ), ); } }