From d969edc4695b6db24e6ee334a6eb9960177dd5f5 Mon Sep 17 00:00:00 2001 From: hejl Date: Mon, 12 May 2025 18:07:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=9E=E5=A5=BD=E4=B8=8D=E8=A6=81=E5=86=8D?= =?UTF-8?q?=E5=86=B2=E7=AA=81=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- win_text_editor/lib/app/app.dart | 6 +- .../lib/app/widgets/template_parser_tab.dart | 122 ++++++++++++++++-- .../lib/app/widgets/text_editor.dart | 43 ++++-- 3 files changed, 142 insertions(+), 29 deletions(-) diff --git a/win_text_editor/lib/app/app.dart b/win_text_editor/lib/app/app.dart index 442c7c4..55c3645 100644 --- a/win_text_editor/lib/app/app.dart +++ b/win_text_editor/lib/app/app.dart @@ -85,10 +85,10 @@ class _ResizablePanelState extends State<_ResizablePanel> { ), ), // 右侧编辑器区域 - 添加Material背景 - Expanded( + const Expanded( child: Material( - color: Theme.of(context).colorScheme.surface, - child: const Column(children: [Expanded(child: EditorPane())]), + color: Colors.white, + child: Column(children: [Expanded(child: EditorPane())]), ), ), ], diff --git a/win_text_editor/lib/app/widgets/template_parser_tab.dart b/win_text_editor/lib/app/widgets/template_parser_tab.dart index 495d4b5..e7ddf8a 100644 --- a/win_text_editor/lib/app/widgets/template_parser_tab.dart +++ b/win_text_editor/lib/app/widgets/template_parser_tab.dart @@ -14,33 +14,131 @@ class TemplateParserTab extends StatefulWidget { class TemplateParserTabState extends State { late TabProvider _provider; + String? _editor1FileName; + String? _editor2FileName; + String _editor1Content = ''; + String _editor2Content = ''; + int _activeEditorIndex = 0; // 0表示第一个编辑器,1表示第二个 + final GlobalKey _editor1Key = GlobalKey(); + final GlobalKey _editor2Key = GlobalKey(); + + // 添加焦点监听 + void _setupFocusListeners() { + _editor1Key.currentState?.focusNode.addListener(() { + if (_editor1Key.currentState?.hasFocus ?? false) { + setState(() => _activeEditorIndex = 0); + } + }); + + _editor2Key.currentState?.focusNode.addListener(() { + if (_editor2Key.currentState?.hasFocus ?? false) { + setState(() => _activeEditorIndex = 1); + } + }); + } @override void initState() { super.initState(); _provider = Provider.of(context, listen: false); _provider.registerTextTabController(widget.tabId, this); + final tab = _provider.getTabById(widget.tabId); + if (tab != null) { + _editor1Content = tab.content; + _editor2Content = tab.content; + _editor1FileName = tab.fileName; + _editor2FileName = tab.fileName; + } + WidgetsBinding.instance.addPostFrameCallback((_) { + _setupFocusListeners(); + }); } - Future loadFile(BuildContext context, String filePath) async {} + // 修改loadFile方法使用_activeEditorIndex + Future loadFile(BuildContext context, String filePath) async { + if (_activeEditorIndex == 0) { + _editor1Key.currentState?.loadFile(context, filePath); + } else { + _editor2Key.currentState?.loadFile(context, filePath); + } + } @override Widget build(BuildContext context) { - final tab = _provider.tabs.firstWhere((t) => t.id == widget.tabId); + final tab = _provider.getTabById(widget.tabId); if (tab == null) { return const Center(child: Text('选项卡不存在')); } - return TextEditor( - tabId: widget.tabId, - initialContent: tab.content, - fileName: tab.fileName, - onContentChanged: (content, fileName) { - _provider.updateContent(widget.tabId, content, fileName); - }, - onFileLoaded: (filePath) { - // 可以在这里添加文件加载后的额外处理 - }, + return SingleChildScrollView( + child: ConstrainedBox( + constraints: const BoxConstraints(minHeight: 400), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: SizedBox( + height: MediaQuery.of(context).size.height / 2 - 100, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: _activeEditorIndex == 0 ? Colors.blue : Colors.transparent, + width: 2.0, + ), + ), + child: TextEditor( + key: _editor1Key, + tabId: '${widget.tabId}_1', + title: '源文本', // 可配置的标题 + initialContent: _editor1Content, + fileName: _editor1FileName, + onContentChanged: (content, fileName) { + setState(() { + _editor1Content = content; + _editor1FileName = fileName; + }); + _provider.updateContent(widget.tabId, content, fileName); + }, + onFileLoaded: (filePath) { + // 文件加载处理 + }, + ), + ), + ), + ), + Flexible( + child: SizedBox( + height: MediaQuery.of(context).size.height / 2 - 100, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: _activeEditorIndex == 1 ? Colors.blue : Colors.transparent, + width: 2.0, + ), + ), + child: TextEditor( + key: _editor2Key, + tabId: '${widget.tabId}_2', + title: '目标文本', // 可配置的标题 + initialContent: _editor2Content, + fileName: _editor2FileName, + onContentChanged: (content, fileName) { + setState(() { + _editor2Content = content; + _editor2FileName = fileName; + }); + _provider.updateContent(widget.tabId, content, fileName); + }, + onFileLoaded: (filePath) { + // 文件加载处理 + }, + ), + ), + ), + ), + ], + ), + ), ); } } diff --git a/win_text_editor/lib/app/widgets/text_editor.dart b/win_text_editor/lib/app/widgets/text_editor.dart index 9b0ae7f..a456803 100644 --- a/win_text_editor/lib/app/widgets/text_editor.dart +++ b/win_text_editor/lib/app/widgets/text_editor.dart @@ -9,6 +9,7 @@ class TextEditor extends StatefulWidget { final String tabId; final String? initialContent; final String? fileName; + final String title; final Function(String, String?)? onContentChanged; final Function(String)? onFileLoaded; @@ -17,29 +18,38 @@ class TextEditor extends StatefulWidget { required this.tabId, this.initialContent, this.fileName, + this.title = '未命名', this.onContentChanged, this.onFileLoaded, }); @override - State createState() => _TextEditorState(); + State createState() => TextEditorState(); } -class _TextEditorState extends State { +class TextEditorState extends State { late TextEditingController _controller; - late FocusNode _focusNode; + late ScrollController _scrollController; bool _isLoading = false; static const int maxFileSize = 1024 * 1024; // 1MB + bool get hasFocus => _focusNode.hasFocus; + FocusNode get _focusNode => focusNode; // 将原来的_focusNode改为focusNode + late FocusNode focusNode = FocusNode(); // 修改声明方式 + + void loadFile(BuildContext context, String filePath) async { + await _loadFile(context, filePath); + } + @override void initState() { super.initState(); _controller = TextEditingController(text: widget.initialContent ?? ''); - _focusNode = FocusNode(); + focusNode = FocusNode(); _scrollController = ScrollController(); WidgetsBinding.instance.addPostFrameCallback((_) { - FocusScope.of(context).requestFocus(_focusNode); + FocusScope.of(context).requestFocus(focusNode); }); } @@ -67,14 +77,19 @@ class _TextEditorState extends State { height: 40, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Colors.grey[100], - border: Border(bottom: BorderSide(color: Colors.grey[300]!)), + color: hasFocus ? Colors.blue[50] : Colors.grey[100], + border: Border( + bottom: BorderSide( + color: hasFocus ? Colors.blue : Colors.grey[300]!, + width: hasFocus ? 2.0 : 1.0, + ), + ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '源文本${_controller.text.isEmpty ? '' : ' (${widget.fileName ?? ''}${_controller.text.length}字符)'}', + '${widget.title}${_controller.text.isEmpty ? '' : ' (${widget.fileName ?? ''}${_controller.text.length}字符)'}', style: const TextStyle(fontWeight: FontWeight.bold), ), Row( @@ -135,10 +150,10 @@ class _TextEditorState extends State { border: InputBorder.none, contentPadding: EdgeInsets.all(16), ), - style: TextStyle( - fontFamily: 'monospace', - fontSize: 14, - color: Theme.of(context).textTheme.bodyLarge?.color, + style: const TextStyle( + fontFamily: 'Courier New', + fontSize: 16, + color: Colors.black, ), ), ], @@ -153,7 +168,7 @@ class _TextEditorState extends State { Future _openFile(BuildContext context) async { final result = await FilePicker.platform.pickFiles(type: FileType.any, allowMultiple: false); if (result != null && result.files.single.path != null) { - await loadFile(context, result.files.single.path!); + await _loadFile(context, result.files.single.path!); } } @@ -218,7 +233,7 @@ class _TextEditorState extends State { } } - Future loadFile(BuildContext context, String filePath) async { + Future _loadFile(BuildContext context, String filePath) async { try { setState(() => _isLoading = true); final file = File(filePath);