import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter/services.dart'; // 用于复制到剪贴板 import 'package:win_text_editor/app/providers/logger.dart'; class ConsolePanel extends StatefulWidget { const ConsolePanel({super.key}); @override State createState() => _ConsolePanelState(); } class _ConsolePanelState extends State { double _height = 100; final double _minHeight = 50; final double _maxHeight = 300; final ScrollController _scrollController = ScrollController(); String? _selectedLog; // 当前选中的日志内容 @override void dispose() { _scrollController.dispose(); super.dispose(); } Color _getLogColor(LogLevel level) { switch (level) { case LogLevel.error: return Colors.red[400]!; case LogLevel.warning: return Colors.orange[400]!; case LogLevel.info: return Colors.blue[400]!; case LogLevel.debug: return Colors.grey; } } // 显示右键菜单 void _showContextMenu(BuildContext context, Offset position, String logContent) async { final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox; await showMenu( context: context, position: RelativeRect.fromRect( Rect.fromPoints(position, position), Offset.zero & overlay.size, ), items: [ PopupMenuItem( child: const Text('复制'), onTap: () async { await Clipboard.setData(ClipboardData(text: logContent)); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('已复制到剪贴板'), duration: Duration(seconds: 1)), ); }, ), PopupMenuItem( child: const Text('清除日志'), onTap: () { Provider.of(context, listen: false).clear(); }, ), ], ); } @override Widget build(BuildContext context) { final logger = Provider.of(context); final consoleHeight = _height.clamp(_minHeight, _maxHeight); WidgetsBinding.instance.addPostFrameCallback((_) { if (_scrollController.hasClients) { _scrollController.jumpTo(_scrollController.position.maxScrollExtent); } }); return Column( children: [ // 拖拽手柄 GestureDetector( behavior: HitTestBehavior.translucent, onPanUpdate: (details) { setState(() { _height = (_height - details.delta.dy).clamp(_minHeight, _maxHeight); }); }, child: MouseRegion( cursor: SystemMouseCursors.resizeUpDown, child: Container(height: 4, color: Colors.grey[300]), ), ), // 控制台内容区域 SizedBox( height: consoleHeight, child: Container( color: Colors.grey[100], padding: const EdgeInsets.all(8), child: ListView.builder( controller: _scrollController, itemCount: logger.logs.length, itemBuilder: (context, index) { final log = logger.logs[index]; final logContent = log.toString(); return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: GestureDetector( onSecondaryTapDown: (details) { _showContextMenu(context, details.globalPosition, logContent); }, child: MouseRegion( cursor: SystemMouseCursors.click, child: SelectableText( // 改为可选择的文本 logContent, style: TextStyle(fontFamily: 'monospace', color: _getLogColor(log.level)), ), ), ), ); }, ), ), ), ], ); } }