Files
windows-application/lib/screens/log_viewer_screen.dart

146 lines
4.0 KiB
Dart
Raw Normal View History

2026-01-22 15:14:27 +08:00
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/client_provider.dart';
import '../services/log_service.dart';
import 'dart:async';
class LogViewerScreen extends StatefulWidget {
const LogViewerScreen({super.key});
@override
State<LogViewerScreen> createState() => _LogViewerScreenState();
}
class _LogViewerScreenState extends State<LogViewerScreen> {
final LogService _logService = LogService();
final ScrollController _scrollController = ScrollController();
String _logs = '';
StreamSubscription<String>? _logSubscription;
StreamSubscription<String>? _clientLogSubscription;
bool _autoScroll = true;
@override
void initState() {
super.initState();
_loadLogs();
_startMonitoring();
}
Future<void> _loadLogs() async {
final logs = await _logService.getRecentLogs();
setState(() {
_logs = logs;
});
if (_autoScroll && _scrollController.hasClients) {
_scrollToBottom();
}
}
void _startMonitoring() {
// 监控日志文件
_logSubscription = _logService.logStream.listen((log) {
setState(() {
_logs += '\n$log';
});
if (_autoScroll && _scrollController.hasClients) {
_scrollToBottom();
}
});
// 监控客户端日志流
final clientProvider = Provider.of<ClientProvider>(context, listen: false);
_clientLogSubscription = clientProvider.logStream.listen((log) {
setState(() {
_logs += '\n$log';
});
if (_autoScroll && _scrollController.hasClients) {
_scrollToBottom();
}
});
}
void _scrollToBottom() {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
}
@override
void dispose() {
_logSubscription?.cancel();
_clientLogSubscription?.cancel();
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('日志查看'),
actions: [
IconButton(
icon: Icon(_autoScroll ? Icons.arrow_downward : Icons.arrow_upward),
onPressed: () {
setState(() {
_autoScroll = !_autoScroll;
});
},
tooltip: _autoScroll ? '关闭自动滚动' : '开启自动滚动',
),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _loadLogs,
tooltip: '刷新日志',
),
IconButton(
icon: const Icon(Icons.clear),
onPressed: () async {
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('确认清理'),
content: const Text('确定要清理所有日志吗?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('取消'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('确定'),
),
],
),
);
if (confirmed == true) {
await _logService.clearLogs();
_loadLogs();
}
},
tooltip: '清理日志',
),
],
),
body: Container(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
controller: _scrollController,
child: SelectableText(
_logs.isEmpty ? '暂无日志' : _logs,
style: const TextStyle(
fontFamily: 'monospace',
fontSize: 12,
),
),
),
),
);
}
}