Browse Source

重构代码之前

master
hejl 2 months ago
parent
commit
1f34392ef7
  1. 17
      win_text_editor/lib/app/core/app_scaffold.dart
  2. 59
      win_text_editor/lib/app/core/tab_manager.dart
  3. 23
      win_text_editor/lib/app/core/tab_view.dart
  4. 24
      win_text_editor/lib/app/models/search_model.dart
  5. 36
      win_text_editor/lib/app/modules/base_view.dart
  6. 24
      win_text_editor/lib/app/modules/content_search/content_search_controller.dart
  7. 103
      win_text_editor/lib/app/modules/content_search/content_search_service.dart
  8. 37
      win_text_editor/lib/app/modules/content_search/content_search_view.dart
  9. 2
      win_text_editor/lib/app/modules/content_search/results_view.dart
  10. 1
      win_text_editor/lib/app/modules/content_search/search_settings.dart
  11. 32
      win_text_editor/lib/app/modules/template_parser/template_parser_view.dart

17
win_text_editor/lib/app/core/app_scaffold.dart

@ -15,18 +15,25 @@ class AppScaffold extends StatelessWidget {
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider(create: (_) => FileProvider()), ChangeNotifierProvider(create: (_) => FileProvider()),
ChangeNotifierProvider(create: (_) => TabManager()), // TabManager ChangeNotifierProvider(create: (_) => TabManager()),
], ],
child: Scaffold( child: Scaffold(
backgroundColor: Colors.grey[100], backgroundColor: Colors.grey[100],
body: Column( body: Column(
children: [ children: [
const AppMenu(), // const AppMenu(),
Expanded( Expanded(
child: Row( child: Row(
children: [ children: [
// // -
const FileExplorerPane(), Consumer<TabManager>(
builder: (context, tabManager, child) {
return FileExplorerPane(
onFileDoubleTap: (path) => tabManager.handleFileDoubleTap(path),
onFolderDoubleTap: (path) => tabManager.handleFolderDoubleTap(path),
);
},
),
// //
Expanded( Expanded(
child: Consumer<TabManager>( child: Consumer<TabManager>(
@ -38,7 +45,7 @@ class AppScaffold extends StatelessWidget {
], ],
), ),
), ),
const ConsolePanel(), // const ConsolePanel(),
], ],
), ),
), ),

59
win_text_editor/lib/app/core/tab_manager.dart

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:win_text_editor/app/models/tab_model.dart'; import 'package:win_text_editor/app/models/tab_model.dart';
import 'package:win_text_editor/app/modules/template_parser/template_parser_view.dart'; import 'package:win_text_editor/app/modules/base_view.dart';
import 'package:win_text_editor/app/providers/logger.dart'; import 'package:win_text_editor/app/providers/logger.dart';
class TabManager with ChangeNotifier { class TabManager with ChangeNotifier {
@ -10,15 +10,7 @@ class TabManager with ChangeNotifier {
List<AppTab> get tabs => _tabs; List<AppTab> get tabs => _tabs;
String? get activeTabId => _activeTabId; String? get activeTabId => _activeTabId;
final Map<String, TemplateParserViewState> _tabControllers = {}; BaseViewState? _activeViewState;
void registerTextTabController(String tabId, TemplateParserViewState controller) {
_tabControllers[tabId] = controller;
}
void unregisterTextTabController(String tabId) {
_tabControllers.remove(tabId);
}
AppTab? get activeTab { AppTab? get activeTab {
if (_activeTabId == null) return null; if (_activeTabId == null) return null;
@ -70,47 +62,18 @@ class TabManager with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void updateContent(String tabId, String content, String? name) { void handleFolderDoubleTap(String folderPath) {
try { _activeViewState?.onOpenFolder(folderPath);
final tab = _tabs.firstWhere((t) => t.id == tabId);
tab.content = content;
if (name != null) {
tab.fileName = name;
}
// Logger().debug("内容更新成功,文件:${tab.fileName}, ${tab.content.length}");
notifyListeners();
} catch (e) {
Logger().error("更新内容失败: ${e.toString()}", source: 'EditorProvider');
}
} }
Future<void> requestLoadFile(BuildContext context, String filePath) async { void handleFileDoubleTap(String filePath) {
if (_activeTabId == null) { _activeViewState?.onOpenFile(filePath);
Logger().warning("没有活动选项卡,无法加载文件"); }
return;
}
final parserTabState = _tabControllers[_activeTabId];
if (parserTabState == null) {
Logger().warning("找不到 TextTab 状态");
return;
}
if (!parserTabState.mounted) {
Logger().warning("TextTab 状态组件未挂载");
return;
}
try { void setActiveViewState(BaseViewState? state) {
await parserTabState.loadFile(context, filePath); if (_activeViewState != state) {
} catch (e) { _activeViewState = state;
Logger().error("加载文件失败: ${e.toString()}"); // notifyListeners()
if (context.mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('加载文件失败: ${e.toString()}')));
}
} }
} }
} }

23
win_text_editor/lib/app/core/tab_view.dart

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; 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/components/text_editor.dart';
import 'package:win_text_editor/app/core/tab_manager.dart'; import 'package:win_text_editor/app/core/tab_manager.dart';
import 'package:win_text_editor/app/models/tab_model.dart'; import 'package:win_text_editor/app/models/tab_model.dart';
import 'package:win_text_editor/app/modules/content_search/content_search_view.dart'; import 'package:win_text_editor/app/modules/content_search/content_search_view.dart';
import 'package:win_text_editor/app/modules/template_parser/template_parser_view.dart'; import 'package:win_text_editor/app/modules/template_parser/template_parser_view.dart';
import 'package:provider/provider.dart';
class TabView extends StatelessWidget { class TabView extends StatelessWidget {
final List<AppTab> tabs; final List<AppTab> tabs;
@ -58,17 +58,22 @@ class TabView extends StatelessWidget {
index: tabs.indexWhere((tab) => tab.id == currentTabId).clamp(0, tabs.length - 1), index: tabs.indexWhere((tab) => tab.id == currentTabId).clamp(0, tabs.length - 1),
children: children:
tabs.map((tab) { tabs.map((tab) {
switch (tab.type) { return findActiveView(tab);
case 'template_parser':
return TemplateParserView(tabId: tab.id);
case 'content_search':
return ContentSearchView(tabId: tab.id);
default:
return TextEditor(tabId: tab.id, initialContent: tab.content);
}
}).toList(), }).toList(),
); );
} }
//
Widget findActiveView(AppTab tab) {
switch (tab.type) {
case 'template_parser':
return TemplateParserView(tabId: tab.id);
case 'content_search':
return ContentSearchView(tabId: tab.id);
default:
return TextEditor(tabId: tab.id, initialContent: tab.content);
}
}
} }
class _TabItem extends StatelessWidget { class _TabItem extends StatelessWidget {

24
win_text_editor/lib/app/models/search_model.dart

@ -0,0 +1,24 @@
class SearchResult {
final String filePath;
final int lineNumber;
final String lineContent;
final List<MatchResult> matches;
final String queryTerm; //
SearchResult({
required this.filePath,
required this.lineNumber,
required this.lineContent,
required this.matches,
required this.queryTerm,
});
}
class MatchResult {
final int start;
final int end;
const MatchResult({required this.start, required this.end});
}
enum SearchMode { locate, count }

36
win_text_editor/lib/app/modules/base_view.dart

@ -2,34 +2,40 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:win_text_editor/app/core/tab_manager.dart'; import 'package:win_text_editor/app/core/tab_manager.dart';
// base_view.dart
abstract class BaseView extends StatefulWidget { abstract class BaseView extends StatefulWidget {
final String tabId; final String tabId;
const BaseView({super.key, required this.tabId}); const BaseView({super.key, required this.tabId});
@override @override
State<BaseView> createState() => BaseViewState(); BaseViewState createState();
//
void openFolder(String folderPath);
//
void openFile(String filePath);
} }
class BaseViewState extends State<BaseView> { abstract class BaseViewState<T extends BaseView> extends State<T> {
late TabManager _tabManager; late final TabManager tabManager;
TabManager get tabManager => _tabManager;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_tabManager = Provider.of<TabManager>(context, listen: false); tabManager = Provider.of<TabManager>(context, listen: false);
} }
@override @override
Widget build(BuildContext context) { void didChangeDependencies() {
return Container(); // super.didChangeDependencies();
if (tabManager.activeTabId == widget.tabId) {
tabManager.setActiveViewState(this);
}
} }
@override
void dispose() {
//
tabManager.setActiveViewState(null);
super.dispose();
}
// State中定义
void onOpenFolder(String folderPath);
void onOpenFile(String filePath);
} }

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

@ -1,5 +1,6 @@
// content_search_controller.dart // content_search_controller.dart
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
@ -7,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:win_text_editor/app/core/tab_manager.dart'; import 'package:win_text_editor/app/core/tab_manager.dart';
import 'package:win_text_editor/app/models/search_model.dart';
import 'package:win_text_editor/app/providers/logger.dart'; import 'package:win_text_editor/app/providers/logger.dart';
import 'content_search_service.dart'; import 'content_search_service.dart';
import 'package:flutter_js/flutter_js.dart'; import 'package:flutter_js/flutter_js.dart';
@ -53,10 +55,13 @@ class ContentSearchController with ChangeNotifier {
} }
// Setters with notifyListeners // Setters with notifyListeners
Timer? _searchDebounce;
set searchQuery(String value) { set searchQuery(String value) {
if (_searchQuery == value) return; _searchDebounce?.cancel();
_searchQuery = value; _searchDebounce = Timer(const Duration(milliseconds: 500), () {
notifyListeners(); _searchQuery = value;
notifyListeners();
});
} }
set searchDirectory(String value) { set searchDirectory(String value) {
@ -186,9 +191,6 @@ class ContentSearchController with ChangeNotifier {
Logger().error('自定规则逻辑错误,没有返回布尔值,返回值为: ${test.stringResult}'); Logger().error('自定规则逻辑错误,没有返回布尔值,返回值为: ${test.stringResult}');
return; return;
} }
await performCustomSearch();
//
} catch (e) { } catch (e) {
Logger().error('JavaScript 语法检查错误: $e'); Logger().error('JavaScript 语法检查错误: $e');
return; return;
@ -196,6 +198,14 @@ class ContentSearchController with ChangeNotifier {
notifyListeners(); notifyListeners();
_jsRuntime.dispose(); _jsRuntime.dispose();
} }
_results.addAll(
await ContentSearchService.performCustomSearch(
directory: searchDirectory,
fileType: fileType,
jsFunction: searchQuery,
searchMode: searchMode,
),
);
} else { } else {
try { try {
if (searchMode == SearchMode.locate) { if (searchMode == SearchMode.locate) {
@ -252,5 +262,3 @@ class ContentSearchController with ChangeNotifier {
return ext == fileType.toLowerCase(); return ext == fileType.toLowerCase();
} }
} }
enum SearchMode { locate, count }

103
win_text_editor/lib/app/modules/content_search/content_search_service.dart

@ -1,9 +1,14 @@
// lib/app/modules/content_search/content_search_service.dart // lib/app/modules/content_search/content_search_service.dart
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter_js/flutter_js.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:win_text_editor/app/models/search_model.dart';
import 'package:win_text_editor/app/providers/logger.dart';
class ContentSearchService { class ContentSearchService {
///
static Future<List<SearchResult>> performLocateSearch({ static Future<List<SearchResult>> performLocateSearch({
required String directory, required String directory,
required String query, required String query,
@ -65,6 +70,78 @@ class ContentSearchService {
return counts; return counts;
} }
/// JavaScript
static Future<List<SearchResult>> performCustomSearch({
required String directory,
required String fileType,
required String jsFunction,
required SearchMode searchMode,
}) async {
final results = <SearchResult>[];
int count = 0;
final dir = Directory(directory);
final jsRuntime = getJavascriptRuntime();
try {
// JavaScript
final jsCode = 'function match(content){$jsFunction};';
jsRuntime.evaluate(jsCode);
await for (final entity in dir.list(recursive: true)) {
if (entity is File && _matchesFileType(entity.path, fileType)) {
try {
final lines = await entity.readAsLines();
for (int i = 0; i < lines.length; i++) {
final line = lines[i].trim();
if (line.length < 3) continue; //
final result = jsRuntime.evaluate('match(${jsonEncode(line)});');
if (result.isError) {
throw Exception('JS Error: ${result.stringResult}');
}
if (result.stringResult == 'true') {
if (searchMode == SearchMode.locate) {
results.add(
SearchResult(
filePath: entity.path,
lineNumber: i + 1,
lineContent: line,
matches: [],
queryTerm: "Custom Rule",
),
);
} else {
count++;
}
}
}
} catch (e) {
Logger().error('Error in file ${entity.path}: $e');
}
}
}
//
if (searchMode == SearchMode.count) {
results.add(
SearchResult(
filePath: "Custom Rule",
lineNumber: count,
lineContent: '',
matches: [],
queryTerm: "Custom Rule",
),
);
}
} finally {
jsRuntime.dispose();
}
return results;
}
/// ///
static List<String> _splitQuery(String query) { static List<String> _splitQuery(String query) {
return query.split(',').map((q) => q.trim()).where((q) => q.isNotEmpty).toList(); return query.split(',').map((q) => q.trim()).where((q) => q.isNotEmpty).toList();
@ -206,31 +283,7 @@ class ContentSearchService {
counts[queryTerm] = (counts[queryTerm] ?? 0) + matches.length; counts[queryTerm] = (counts[queryTerm] ?? 0) + matches.length;
} }
} catch (e) { } catch (e) {
print('Error reading file ${file.path}: $e'); Logger().error('Error reading file ${file.path}: $e');
} }
} }
} }
/// queryTerm
class SearchResult {
final String filePath;
final int lineNumber;
final String lineContent;
final List<MatchResult> matches;
final String queryTerm; //
SearchResult({
required this.filePath,
required this.lineNumber,
required this.lineContent,
required this.matches,
required this.queryTerm,
});
}
class MatchResult {
final int start;
final int end;
const MatchResult({required this.start, required this.end});
}

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

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:win_text_editor/app/core/tab_manager.dart';
import 'package:win_text_editor/app/modules/base_view.dart'; import 'package:win_text_editor/app/modules/base_view.dart';
import 'package:win_text_editor/app/providers/logger.dart';
import 'content_search_controller.dart'; import 'content_search_controller.dart';
import 'directory_settings.dart'; import 'directory_settings.dart';
import 'search_settings.dart'; import 'search_settings.dart';
@ -11,19 +11,7 @@ class ContentSearchView extends BaseView {
const ContentSearchView({super.key, required String tabId}) : super(tabId: tabId); const ContentSearchView({super.key, required String tabId}) : super(tabId: tabId);
@override @override
void openFolder(String folderPath) { ContentSearchViewState createState() => ContentSearchViewState();
//
print('Opening folder: $folderPath');
}
@override
void openFile(String filePath) {
//
print('Opening file: $filePath');
}
@override
State<BaseView> createState() => ContentSearchViewState();
} }
class ContentSearchViewState extends BaseViewState { class ContentSearchViewState extends BaseViewState {
@ -32,7 +20,26 @@ class ContentSearchViewState extends BaseViewState {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_controller = ContentSearchController(tabManager: super.tabManager); _controller = ContentSearchController(tabManager: tabManager);
}
@override
void dispose() {
_controller.dispose(); //
super.dispose();
}
@override
void onOpenFolder(String folderPath) {
//
Logger().debug('Opening folder: $folderPath');
_controller.searchDirectory = folderPath;
}
@override
void onOpenFile(String filePath) {
//
Logger().debug('Opening file: $filePath');
} }
@override @override

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

@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:win_text_editor/app/models/search_model.dart';
import 'package:win_text_editor/app/modules/content_search/content_search_controller.dart'; import 'package:win_text_editor/app/modules/content_search/content_search_controller.dart';
import 'package:win_text_editor/app/modules/content_search/content_search_service.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'dart:io'; import 'dart:io';

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

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:win_text_editor/app/components/text_editor.dart'; import 'package:win_text_editor/app/components/text_editor.dart';
import 'package:win_text_editor/app/models/search_model.dart';
import 'package:win_text_editor/app/modules/content_search/content_search_controller.dart'; import 'package:win_text_editor/app/modules/content_search/content_search_controller.dart';
class SearchSettings extends StatelessWidget { class SearchSettings extends StatelessWidget {

32
win_text_editor/lib/app/modules/template_parser/template_parser_view.dart

@ -6,19 +6,7 @@ class TemplateParserView extends BaseView {
const TemplateParserView({super.key, required String tabId}) : super(tabId: tabId); const TemplateParserView({super.key, required String tabId}) : super(tabId: tabId);
@override @override
void openFolder(String folderPath) { TemplateParserViewState createState() => TemplateParserViewState();
//
print('Opening folder: $folderPath');
}
@override
void openFile(String filePath) {
//
print('Opening file: $filePath');
}
@override
State<BaseView> createState() => TemplateParserViewState();
} }
class TemplateParserViewState extends BaseViewState { class TemplateParserViewState extends BaseViewState {
@ -37,6 +25,24 @@ class TemplateParserViewState extends BaseViewState {
}); });
} }
@override
void dispose() {
//_controller.dispose(); //
super.dispose();
}
@override
void onOpenFolder(String folderPath) {
//
print('Opening folder: $folderPath');
}
@override
void onOpenFile(String filePath) {
//
print('Opening file: $filePath');
}
// loadFile方法使用_activeEditorIndex // loadFile方法使用_activeEditorIndex
Future<void> loadFile(BuildContext context, String filePath) async {} Future<void> loadFile(BuildContext context, String filePath) async {}

Loading…
Cancel
Save