Browse Source

开始搞业务逻辑

master
hejl 2 months ago
parent
commit
5313a960ad
  1. 73
      win_text_editor/lib/app/modules/content_search/content_search_controller.dart
  2. 21
      win_text_editor/lib/app/modules/content_search/content_search_view.dart
  3. 25
      win_text_editor/lib/app/modules/content_search/directory_settings.dart
  4. 16
      win_text_editor/lib/app/modules/content_search/results_view.dart
  5. 218
      win_text_editor/lib/app/modules/content_search/search_settings.dart

73
win_text_editor/lib/app/modules/content_search/content_search_controller.dart

@ -1,21 +1,74 @@ @@ -1,21 +1,74 @@
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:win_text_editor/app/core/tab_manager.dart';
class ContentSearchController {
class ContentSearchController with ChangeNotifier {
final TabManager tabManager;
String searchQuery = '';
String searchDirectory = '';
String fileType = '*.*';
bool caseSensitive = false;
bool wholeWord = false;
bool useRegex = false;
SearchMode searchMode = SearchMode.locate;
final List<SearchResult> results = [];
String _searchQuery = '';
String _searchDirectory = '';
String _fileType = '*.*';
bool _caseSensitive = false;
bool _wholeWord = false;
bool _useRegex = false;
bool _customRule = false;
SearchMode _searchMode = SearchMode.locate;
final List<SearchResult> _results = [];
ContentSearchController({required this.tabManager});
// Getters
String get searchQuery => _searchQuery;
String get searchDirectory => _searchDirectory;
String get fileType => _fileType;
bool get caseSensitive => _caseSensitive;
bool get wholeWord => _wholeWord;
bool get useRegex => _useRegex;
bool get customRule => _customRule;
SearchMode get searchMode => _searchMode;
List<SearchResult> get results => _results;
set customRule(bool value) {
_customRule = value;
notifyListeners();
}
// Setters with notifyListeners
set searchQuery(String value) {
_searchQuery = value;
notifyListeners();
}
set searchDirectory(String value) {
_searchDirectory = value;
notifyListeners();
}
set fileType(String value) {
_fileType = value;
notifyListeners();
}
set caseSensitive(bool value) {
_caseSensitive = value;
notifyListeners();
}
set wholeWord(bool value) {
_wholeWord = value;
notifyListeners();
}
set useRegex(bool value) {
_useRegex = value;
notifyListeners();
}
set searchMode(SearchMode value) {
_searchMode = value;
notifyListeners();
}
Future<void> startSearch() async {
results.clear();
//

21
win_text_editor/lib/app/modules/content_search/content_search_view.dart

@ -28,16 +28,17 @@ class ContentSearchViewState extends State<ContentSearchView> { @@ -28,16 +28,17 @@ class ContentSearchViewState extends State<ContentSearchView> {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
DirectorySettings(controller: _controller),
const SizedBox(height: 16),
SearchSettings(controller: _controller),
const SizedBox(height: 16),
Expanded(child: ResultsView(controller: _controller)),
],
return ChangeNotifierProvider.value(
value: _controller,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Column(
children: [
const DirectorySettings(), // controller
SearchSettings(),
const Expanded(child: ResultsView()),
],
),
),
);
}

25
win_text_editor/lib/app/modules/content_search/directory_settings.dart

@ -1,22 +1,23 @@ @@ -1,22 +1,23 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:win_text_editor/app/modules/content_search/content_search_controller.dart';
class DirectorySettings extends StatelessWidget {
final ContentSearchController controller;
const DirectorySettings({super.key, required this.controller});
const DirectorySettings({super.key});
@override
Widget build(BuildContext context) {
final controller = context.watch<ContentSearchController>();
final searchDirectoryController = TextEditingController(text: controller.searchDirectory);
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
const Icon(Icons.folder, color: Colors.blue),
const SizedBox(width: 8),
Expanded(
child: TextField(
controller: searchDirectoryController,
decoration: const InputDecoration(labelText: '搜索目录', border: OutlineInputBorder()),
onChanged: (value) => controller.searchDirectory = value,
),
@ -25,17 +26,19 @@ class DirectorySettings extends StatelessWidget { @@ -25,17 +26,19 @@ class DirectorySettings extends StatelessWidget {
SizedBox(
width: 100,
child: TextField(
decoration: const InputDecoration(
labelText: '文件类型',
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 12),
),
decoration: const InputDecoration(labelText: '文件类型', border: OutlineInputBorder()),
controller: TextEditingController(text: controller.fileType),
onChanged: (value) => controller.fileType = value,
),
),
const SizedBox(width: 8),
IconButton(icon: const Icon(Icons.folder_open), onPressed: controller.pickDirectory),
IconButton(
icon: const Icon(Icons.folder_open),
onPressed: () async {
await controller.pickDirectory();
searchDirectoryController.text = controller.searchDirectory;
},
),
],
),
),

16
win_text_editor/lib/app/modules/content_search/results_view.dart

@ -1,13 +1,13 @@ @@ -1,13 +1,13 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:win_text_editor/app/modules/content_search/content_search_controller.dart';
class ResultsView extends StatelessWidget {
final ContentSearchController controller;
const ResultsView({super.key, required this.controller});
const ResultsView({super.key});
@override
Widget build(BuildContext context) {
final controller = context.watch<ContentSearchController>();
return Card(
child: Column(
children: [
@ -21,15 +21,15 @@ class ResultsView extends StatelessWidget { @@ -21,15 +21,15 @@ class ResultsView extends StatelessWidget {
Expanded(
child:
controller.searchMode == SearchMode.locate
? _buildLocateResults()
: _buildCountResults(),
? _buildLocateResults(controller)
: _buildCountResults(controller),
),
],
),
);
}
Widget _buildLocateResults() {
Widget _buildLocateResults(controller) {
return ListView.builder(
itemCount: controller.results.length,
itemBuilder: (ctx, index) {
@ -47,10 +47,10 @@ class ResultsView extends StatelessWidget { @@ -47,10 +47,10 @@ class ResultsView extends StatelessWidget {
);
}
Widget _buildCountResults() {
Widget _buildCountResults(controller) {
final counts = <String, int>{};
for (var r in controller.results) {
counts[r.filePath] = (counts[r.filePath] ?? 0) + r.matches.length;
// counts[r.filePath] = (counts[r.filePath] ?? 0) + r.matches.length;
}
return ListView.builder(

218
win_text_editor/lib/app/modules/content_search/search_settings.dart

@ -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,
),
),
],
],
),
),
),
),
],
),
),

Loading…
Cancel
Save