|
|
|
@ -1,24 +1,26 @@
@@ -1,24 +1,26 @@
|
|
|
|
|
import 'package:flutter/material.dart'; |
|
|
|
|
import 'package:provider/provider.dart'; |
|
|
|
|
import 'package:win_text_editor/app/components/text_editor.dart'; |
|
|
|
|
import 'package:win_text_editor/app/modules/content_search/content_search_controller.dart'; |
|
|
|
|
|
|
|
|
|
class SearchSettings extends StatelessWidget { |
|
|
|
|
final ContentSearchController controller; |
|
|
|
|
final GlobalKey<TextEditorState> _searchEditorKey = GlobalKey(); |
|
|
|
|
|
|
|
|
|
SearchSettings({super.key, required this.controller}); |
|
|
|
|
SearchSettings({super.key}); |
|
|
|
|
|
|
|
|
|
@override |
|
|
|
|
Widget build(BuildContext context) { |
|
|
|
|
final controller = context.watch<ContentSearchController>(); |
|
|
|
|
|
|
|
|
|
return Card( |
|
|
|
|
child: Padding( |
|
|
|
|
padding: const EdgeInsets.all(8.0), |
|
|
|
|
child: Row( |
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
|
children: [ |
|
|
|
|
// 搜索内容框 |
|
|
|
|
// 搜索内容框 (保持原样) |
|
|
|
|
SizedBox( |
|
|
|
|
width: MediaQuery.of(context).size.width * 0.5, // 占据一半宽度 |
|
|
|
|
width: MediaQuery.of(context).size.width * 0.5, |
|
|
|
|
height: 300, |
|
|
|
|
child: TextEditor( |
|
|
|
|
key: _searchEditorKey, |
|
|
|
@ -31,84 +33,160 @@ class SearchSettings extends StatelessWidget {
@@ -31,84 +33,160 @@ class SearchSettings extends StatelessWidget {
|
|
|
|
|
// 设置按钮区域 |
|
|
|
|
Expanded( |
|
|
|
|
child: Container( |
|
|
|
|
height: 300, |
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
border: Border.all(color: Colors.grey), // 设置边框颜色 |
|
|
|
|
borderRadius: BorderRadius.circular(4), // 设置边框圆角 |
|
|
|
|
border: Border.all(color: Colors.grey), |
|
|
|
|
borderRadius: BorderRadius.circular(4), |
|
|
|
|
), |
|
|
|
|
padding: const EdgeInsets.all(8.0), |
|
|
|
|
child: Column( |
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
|
children: [ |
|
|
|
|
// 搜索方式 |
|
|
|
|
Column( |
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
|
children: [ |
|
|
|
|
const Text('搜索方式:', style: TextStyle(fontSize: 12)), |
|
|
|
|
Row( |
|
|
|
|
children: [ |
|
|
|
|
Radio<SearchMode>( |
|
|
|
|
value: SearchMode.locate, |
|
|
|
|
groupValue: controller.searchMode, |
|
|
|
|
onChanged: (value) => controller.searchMode = value!, |
|
|
|
|
child: Column( |
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
|
children: [ |
|
|
|
|
// 搜索方式 - 两选项排在一行 |
|
|
|
|
const Text('搜索方式:', style: TextStyle(fontSize: 12)), |
|
|
|
|
const SizedBox(height: 4), |
|
|
|
|
Row( |
|
|
|
|
children: [ |
|
|
|
|
Expanded( |
|
|
|
|
child: Row( |
|
|
|
|
children: [ |
|
|
|
|
Radio<SearchMode>( |
|
|
|
|
value: SearchMode.locate, |
|
|
|
|
groupValue: controller.searchMode, |
|
|
|
|
onChanged: (value) => controller.searchMode = value!, |
|
|
|
|
), |
|
|
|
|
const Text('定位', style: TextStyle(fontSize: 12)), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
const Text('定位', style: TextStyle(fontSize: 12)), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
Row( |
|
|
|
|
), |
|
|
|
|
Expanded( |
|
|
|
|
child: Row( |
|
|
|
|
children: [ |
|
|
|
|
Radio<SearchMode>( |
|
|
|
|
value: SearchMode.count, |
|
|
|
|
groupValue: controller.searchMode, |
|
|
|
|
onChanged: (value) => controller.searchMode = value!, |
|
|
|
|
), |
|
|
|
|
const Text('计数', style: TextStyle(fontSize: 12)), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
const SizedBox(height: 8), |
|
|
|
|
// 匹配规则 |
|
|
|
|
const Text('匹配规则:', style: TextStyle(fontSize: 12)), |
|
|
|
|
const SizedBox(height: 4), |
|
|
|
|
// 第一行复选框 |
|
|
|
|
Row( |
|
|
|
|
children: [ |
|
|
|
|
Expanded( |
|
|
|
|
child: CheckboxListTile( |
|
|
|
|
dense: true, |
|
|
|
|
contentPadding: EdgeInsets.zero, |
|
|
|
|
controlAffinity: ListTileControlAffinity.leading, |
|
|
|
|
title: const Text('大小写敏感', style: TextStyle(fontSize: 12)), |
|
|
|
|
value: controller.caseSensitive, |
|
|
|
|
onChanged: |
|
|
|
|
controller.customRule |
|
|
|
|
? null |
|
|
|
|
: (value) { |
|
|
|
|
controller.caseSensitive = value!; |
|
|
|
|
controller.customRule = false; |
|
|
|
|
}, |
|
|
|
|
activeColor: controller.customRule ? Colors.grey : null, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
Expanded( |
|
|
|
|
child: CheckboxListTile( |
|
|
|
|
dense: true, |
|
|
|
|
contentPadding: EdgeInsets.zero, |
|
|
|
|
controlAffinity: ListTileControlAffinity.leading, |
|
|
|
|
title: const Text('全字匹配', style: TextStyle(fontSize: 12)), |
|
|
|
|
value: controller.wholeWord, |
|
|
|
|
onChanged: |
|
|
|
|
controller.customRule |
|
|
|
|
? null |
|
|
|
|
: (value) { |
|
|
|
|
controller.wholeWord = value!; |
|
|
|
|
controller.customRule = false; |
|
|
|
|
}, |
|
|
|
|
activeColor: controller.customRule ? Colors.grey : null, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
// 第二行复选框 |
|
|
|
|
Row( |
|
|
|
|
children: [ |
|
|
|
|
Expanded( |
|
|
|
|
child: CheckboxListTile( |
|
|
|
|
dense: true, |
|
|
|
|
contentPadding: EdgeInsets.zero, |
|
|
|
|
controlAffinity: ListTileControlAffinity.leading, |
|
|
|
|
title: const Text('正则匹配', style: TextStyle(fontSize: 12)), |
|
|
|
|
value: controller.useRegex, |
|
|
|
|
onChanged: |
|
|
|
|
controller.customRule |
|
|
|
|
? null |
|
|
|
|
: (value) { |
|
|
|
|
controller.useRegex = value!; |
|
|
|
|
controller.customRule = false; |
|
|
|
|
}, |
|
|
|
|
activeColor: controller.customRule ? Colors.grey : null, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
Expanded( |
|
|
|
|
child: CheckboxListTile( |
|
|
|
|
dense: true, |
|
|
|
|
contentPadding: EdgeInsets.zero, |
|
|
|
|
controlAffinity: ListTileControlAffinity.leading, |
|
|
|
|
title: const Text('自定义规则', style: TextStyle(fontSize: 12)), |
|
|
|
|
value: controller.customRule, |
|
|
|
|
onChanged: (value) { |
|
|
|
|
controller.customRule = value!; |
|
|
|
|
if (value) { |
|
|
|
|
controller.caseSensitive = false; |
|
|
|
|
controller.wholeWord = false; |
|
|
|
|
controller.useRegex = false; |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
const SizedBox(height: 8), |
|
|
|
|
// 仅在自定义规则选中时显示的JS函数说明 |
|
|
|
|
Visibility( |
|
|
|
|
visible: controller.customRule, |
|
|
|
|
child: const Column( |
|
|
|
|
children: [ |
|
|
|
|
Radio<SearchMode>( |
|
|
|
|
value: SearchMode.count, |
|
|
|
|
groupValue: controller.searchMode, |
|
|
|
|
onChanged: (value) => controller.searchMode = value!, |
|
|
|
|
Text.rich( |
|
|
|
|
TextSpan( |
|
|
|
|
text: |
|
|
|
|
"在搜索内容输入框中输入js函数体:\n" |
|
|
|
|
"function boolean match(content) {//content为单行文本\n" |
|
|
|
|
"}//返回true或者false", |
|
|
|
|
style: TextStyle(fontSize: 12, fontFamily: 'monospace'), |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
const Text('计数', style: TextStyle(fontSize: 12)), |
|
|
|
|
SizedBox(height: 8), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
const SizedBox(height: 8), |
|
|
|
|
// 匹配规则 |
|
|
|
|
Column( |
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
|
children: [ |
|
|
|
|
const Text('匹配规则:', style: TextStyle(fontSize: 12)), |
|
|
|
|
CheckboxListTile( |
|
|
|
|
contentPadding: EdgeInsets.zero, |
|
|
|
|
controlAffinity: ListTileControlAffinity.leading, |
|
|
|
|
title: const Text('大小写敏感', style: TextStyle(fontSize: 12)), |
|
|
|
|
value: controller.caseSensitive, |
|
|
|
|
onChanged: (value) => controller.caseSensitive = value!, |
|
|
|
|
), |
|
|
|
|
CheckboxListTile( |
|
|
|
|
contentPadding: EdgeInsets.zero, |
|
|
|
|
controlAffinity: ListTileControlAffinity.leading, |
|
|
|
|
title: const Text('全字匹配', style: TextStyle(fontSize: 12)), |
|
|
|
|
value: controller.wholeWord, |
|
|
|
|
onChanged: (value) => controller.wholeWord = value!, |
|
|
|
|
), |
|
|
|
|
CheckboxListTile( |
|
|
|
|
contentPadding: EdgeInsets.zero, |
|
|
|
|
controlAffinity: ListTileControlAffinity.leading, |
|
|
|
|
title: const Text('正则匹配', style: TextStyle(fontSize: 12)), |
|
|
|
|
value: controller.useRegex, |
|
|
|
|
onChanged: (value) => controller.useRegex = value!, |
|
|
|
|
), |
|
|
|
|
// 开始搜索按钮 |
|
|
|
|
Align( |
|
|
|
|
alignment: Alignment.bottomCenter, |
|
|
|
|
child: ElevatedButton.icon( |
|
|
|
|
icon: const Icon(Icons.search, size: 20), |
|
|
|
|
label: const Text('开始搜索'), |
|
|
|
|
onPressed: controller.startSearch, |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
const SizedBox(height: 8), |
|
|
|
|
// 开始搜索按钮 |
|
|
|
|
Align( |
|
|
|
|
alignment: Alignment.centerLeft, |
|
|
|
|
child: ElevatedButton.icon( |
|
|
|
|
icon: const Icon(Icons.search, size: 20), |
|
|
|
|
label: const Text('开始搜索'), |
|
|
|
|
onPressed: controller.startSearch, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|