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 { @@ -15,18 +15,25 @@ class AppScaffold extends StatelessWidget {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => FileProvider()),
ChangeNotifierProvider(create: (_) => TabManager()), // TabManager
ChangeNotifierProvider(create: (_) => TabManager()),
],
child: Scaffold(
backgroundColor: Colors.grey[100],
body: Column(
children: [
const AppMenu(), //
const AppMenu(),
Expanded(
child: Row(
children: [
//
const FileExplorerPane(),
// -
Consumer<TabManager>(
builder: (context, tabManager, child) {
return FileExplorerPane(
onFileDoubleTap: (path) => tabManager.handleFileDoubleTap(path),
onFolderDoubleTap: (path) => tabManager.handleFolderDoubleTap(path),
);
},
),
//
Expanded(
child: Consumer<TabManager>(
@ -38,7 +45,7 @@ class AppScaffold extends StatelessWidget { @@ -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 @@ @@ -1,6 +1,6 @@
import 'package:flutter/material.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';
class TabManager with ChangeNotifier {
@ -10,15 +10,7 @@ class TabManager with ChangeNotifier { @@ -10,15 +10,7 @@ class TabManager with ChangeNotifier {
List<AppTab> get tabs => _tabs;
String? get activeTabId => _activeTabId;
final Map<String, TemplateParserViewState> _tabControllers = {};
void registerTextTabController(String tabId, TemplateParserViewState controller) {
_tabControllers[tabId] = controller;
}
void unregisterTextTabController(String tabId) {
_tabControllers.remove(tabId);
}
BaseViewState? _activeViewState;
AppTab? get activeTab {
if (_activeTabId == null) return null;
@ -70,47 +62,18 @@ class TabManager with ChangeNotifier { @@ -70,47 +62,18 @@ class TabManager with ChangeNotifier {
notifyListeners();
}
void updateContent(String tabId, String content, String? name) {
try {
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');
}
void handleFolderDoubleTap(String folderPath) {
_activeViewState?.onOpenFolder(folderPath);
}
Future<void> requestLoadFile(BuildContext context, String filePath) async {
if (_activeTabId == null) {
Logger().warning("没有活动选项卡,无法加载文件");
return;
}
final parserTabState = _tabControllers[_activeTabId];
if (parserTabState == null) {
Logger().warning("找不到 TextTab 状态");
return;
}
if (!parserTabState.mounted) {
Logger().warning("TextTab 状态组件未挂载");
return;
}
void handleFileDoubleTap(String filePath) {
_activeViewState?.onOpenFile(filePath);
}
try {
await parserTabState.loadFile(context, filePath);
} catch (e) {
Logger().error("加载文件失败: ${e.toString()}");
if (context.mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('加载文件失败: ${e.toString()}')));
}
void setActiveViewState(BaseViewState? state) {
if (_activeViewState != state) {
_activeViewState = state;
// notifyListeners()
}
}
}

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

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
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/core/tab_manager.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/template_parser/template_parser_view.dart';
import 'package:provider/provider.dart';
class TabView extends StatelessWidget {
final List<AppTab> tabs;
@ -58,17 +58,22 @@ class TabView extends StatelessWidget { @@ -58,17 +58,22 @@ class TabView extends StatelessWidget {
index: tabs.indexWhere((tab) => tab.id == currentTabId).clamp(0, tabs.length - 1),
children:
tabs.map((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);
}
return findActiveView(tab);
}).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 {

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

@ -0,0 +1,24 @@ @@ -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'; @@ -2,34 +2,40 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:win_text_editor/app/core/tab_manager.dart';
// base_view.dart
abstract class BaseView extends StatefulWidget {
final String tabId;
const BaseView({super.key, required this.tabId});
@override
State<BaseView> createState() => BaseViewState();
//
void openFolder(String folderPath);
//
void openFile(String filePath);
BaseViewState createState();
}
class BaseViewState extends State<BaseView> {
late TabManager _tabManager;
TabManager get tabManager => _tabManager;
abstract class BaseViewState<T extends BaseView> extends State<T> {
late final TabManager tabManager;
@override
void initState() {
super.initState();
_tabManager = Provider.of<TabManager>(context, listen: false);
tabManager = Provider.of<TabManager>(context, listen: false);
}
@override
Widget build(BuildContext context) {
return Container(); //
void didChangeDependencies() {
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 @@ @@ -1,5 +1,6 @@
// content_search_controller.dart
import 'dart:async';
import 'dart:convert';
import 'dart:io';
@ -7,6 +8,7 @@ import 'package:flutter/material.dart'; @@ -7,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:path/path.dart' as path;
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 'content_search_service.dart';
import 'package:flutter_js/flutter_js.dart';
@ -53,10 +55,13 @@ class ContentSearchController with ChangeNotifier { @@ -53,10 +55,13 @@ class ContentSearchController with ChangeNotifier {
}
// Setters with notifyListeners
Timer? _searchDebounce;
set searchQuery(String value) {
if (_searchQuery == value) return;
_searchQuery = value;
notifyListeners();
_searchDebounce?.cancel();
_searchDebounce = Timer(const Duration(milliseconds: 500), () {
_searchQuery = value;
notifyListeners();
});
}
set searchDirectory(String value) {
@ -186,9 +191,6 @@ class ContentSearchController with ChangeNotifier { @@ -186,9 +191,6 @@ class ContentSearchController with ChangeNotifier {
Logger().error('自定规则逻辑错误,没有返回布尔值,返回值为: ${test.stringResult}');
return;
}
await performCustomSearch();
//
} catch (e) {
Logger().error('JavaScript 语法检查错误: $e');
return;
@ -196,6 +198,14 @@ class ContentSearchController with ChangeNotifier { @@ -196,6 +198,14 @@ class ContentSearchController with ChangeNotifier {
notifyListeners();
_jsRuntime.dispose();
}
_results.addAll(
await ContentSearchService.performCustomSearch(
directory: searchDirectory,
fileType: fileType,
jsFunction: searchQuery,
searchMode: searchMode,
),
);
} else {
try {
if (searchMode == SearchMode.locate) {
@ -252,5 +262,3 @@ class ContentSearchController with ChangeNotifier { @@ -252,5 +262,3 @@ class ContentSearchController with ChangeNotifier {
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 @@ @@ -1,9 +1,14 @@
// lib/app/modules/content_search/content_search_service.dart
import 'dart:convert';
import 'dart:io';
import 'package:flutter_js/flutter_js.dart';
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 {
///
static Future<List<SearchResult>> performLocateSearch({
required String directory,
required String query,
@ -65,6 +70,78 @@ class ContentSearchService { @@ -65,6 +70,78 @@ class ContentSearchService {
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) {
return query.split(',').map((q) => q.trim()).where((q) => q.isNotEmpty).toList();
@ -206,31 +283,7 @@ class ContentSearchService { @@ -206,31 +283,7 @@ class ContentSearchService {
counts[queryTerm] = (counts[queryTerm] ?? 0) + matches.length;
}
} 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 @@ @@ -1,7 +1,7 @@
import 'package:flutter/material.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/providers/logger.dart';
import 'content_search_controller.dart';
import 'directory_settings.dart';
import 'search_settings.dart';
@ -11,19 +11,7 @@ class ContentSearchView extends BaseView { @@ -11,19 +11,7 @@ class ContentSearchView extends BaseView {
const ContentSearchView({super.key, required String tabId}) : super(tabId: tabId);
@override
void openFolder(String folderPath) {
//
print('Opening folder: $folderPath');
}
@override
void openFile(String filePath) {
//
print('Opening file: $filePath');
}
@override
State<BaseView> createState() => ContentSearchViewState();
ContentSearchViewState createState() => ContentSearchViewState();
}
class ContentSearchViewState extends BaseViewState {
@ -32,7 +20,26 @@ class ContentSearchViewState extends BaseViewState { @@ -32,7 +20,26 @@ class ContentSearchViewState extends BaseViewState {
@override
void 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

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

@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; @@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
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_service.dart';
import 'package:file_picker/file_picker.dart';
import 'dart:io';

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

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
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/models/search_model.dart';
import 'package:win_text_editor/app/modules/content_search/content_search_controller.dart';
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 { @@ -6,19 +6,7 @@ class TemplateParserView extends BaseView {
const TemplateParserView({super.key, required String tabId}) : super(tabId: tabId);
@override
void openFolder(String folderPath) {
//
print('Opening folder: $folderPath');
}
@override
void openFile(String filePath) {
//
print('Opening file: $filePath');
}
@override
State<BaseView> createState() => TemplateParserViewState();
TemplateParserViewState createState() => TemplateParserViewState();
}
class TemplateParserViewState extends BaseViewState {
@ -37,6 +25,24 @@ 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
Future<void> loadFile(BuildContext context, String filePath) async {}

Loading…
Cancel
Save