You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

130 lines
4.0 KiB

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<ConsolePanel> createState() => _ConsolePanelState();
}
class _ConsolePanelState extends State<ConsolePanel> {
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<Logger>(context, listen: false).clear();
},
),
],
);
}
@override
Widget build(BuildContext context) {
final logger = Provider.of<Logger>(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)),
),
),
),
);
},
),
),
),
],
);
}
}