Browse Source

文件夹名称解析OK

master
hejl 2 months ago
parent
commit
289f22ec2c
  1. 4
      win_text_editor/assets/config/uft_macro_list.yaml
  2. 24
      win_text_editor/lib/framework/controllers/file_provider.dart
  3. 8
      win_text_editor/lib/framework/models/file_node.dart
  4. 60
      win_text_editor/lib/framework/services/file_service.dart
  5. 65
      win_text_editor/lib/shared/components/file_explorer.dart
  6. 48
      win_text_editor/lib/shared/components/tree_view.dart

4
win_text_editor/assets/config/uft_macro_list.yaml

@ -35,13 +35,13 @@ templates:
[获取记录][{{tableName}}({{keyName}})][ [获取记录][{{tableName}}({{keyName}})][
{{#keyFields}} {{#keyFields}}
{{value}} = @{{value}} {{^isLast}}, {{/isLast}} {{value}} = @{{value}}
{{/keyFields}} {{/keyFields}}
] ]
[修改记录][{{tableName}}][ [修改记录][{{tableName}}][
{{#fields}} {{#fields}}
{{value}} = @{{value}} {{^isLast}}, {{/isLast}} {{value}} = @{{value}}
{{/fields}} {{/fields}}
] ]
} }

24
win_text_editor/lib/framework/controllers/file_provider.dart

@ -60,14 +60,15 @@ class FileProvider with ChangeNotifier {
try { try {
final directory = Directory(path); final directory = Directory(path);
final displayName = await FileService.getModuleDisplayName(directory.path);
final rootNode = FileNode( final rootNode = FileNode(
name: directory.path.split(Platform.pathSeparator).last, name: displayName ?? directory.path.split(Platform.pathSeparator).last,
path: directory.path, path: directory.path,
isDirectory: true, isDirectory: true,
isRoot: true, // isRoot: true,
children: await FileService.buildFileTree(directory.path), children: await FileService.buildFileTree(directory.path),
); );
_fileNodes = [rootNode]; // _fileNodes = [rootNode];
} catch (e) { } catch (e) {
Logger().error('Error loading directory: $e'); Logger().error('Error loading directory: $e');
_fileNodes = []; _fileNodes = [];
@ -84,9 +85,10 @@ class FileProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
try { try {
final displayName = await FileService.getModuleDisplayName(_currentRootPath!);
_fileNodes = [ _fileNodes = [
FileNode( FileNode(
name: _currentRootPath!.split(Platform.pathSeparator).last, name: displayName ?? _currentRootPath!.split(Platform.pathSeparator).last,
path: _currentRootPath!, path: _currentRootPath!,
isDirectory: true, isDirectory: true,
isRoot: true, isRoot: true,
@ -108,9 +110,10 @@ class FileProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
try { try {
final displayName = await FileService.getModuleDisplayName(path);
_fileNodes = [ _fileNodes = [
FileNode( FileNode(
name: path.split(Platform.pathSeparator).last, name: displayName ?? path.split(Platform.pathSeparator).last,
path: path, path: path,
isDirectory: true, isDirectory: true,
isRoot: true, isRoot: true,
@ -161,16 +164,9 @@ class FileProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
try { try {
final contents = await FileService.listDirectory( final contents = await FileService.listDirectory(dirNode.path, parentDepth: dirNode.depth);
dirNode.path,
parentDepth: dirNode.depth, //
);
final updatedNode = dirNode.copyWith( final updatedNode = dirNode.copyWith(children: contents, isExpanded: true);
children: contents,
isExpanded: true,
// depth copyWith
);
_replaceNodeInTree(dirNode, updatedNode); _replaceNodeInTree(dirNode, updatedNode);
} catch (e) { } catch (e) {

8
win_text_editor/lib/framework/models/file_node.dart

@ -97,19 +97,19 @@ class FileNode implements TreeNode {
String? name, String? name,
String? path, String? path,
bool? isDirectory, bool? isDirectory,
bool? isExpanded,
bool? isRoot, bool? isRoot,
int? depth, // depth参数
List<FileNode>? children, List<FileNode>? children,
bool? isExpanded, int? depth,
}) { }) {
return FileNode( return FileNode(
name: name ?? this.name, name: name ?? this.name,
path: path ?? this.path, path: path ?? this.path,
isDirectory: isDirectory ?? this.isDirectory, isDirectory: isDirectory ?? this.isDirectory,
isExpanded: isExpanded ?? this.isExpanded,
isRoot: isRoot ?? this.isRoot, isRoot: isRoot ?? this.isRoot,
depth: depth ?? this.depth, // depth或使用新值
children: children ?? this.children, children: children ?? this.children,
isExpanded: isExpanded ?? this.isExpanded, depth: depth ?? this.depth,
); );
} }

60
win_text_editor/lib/framework/services/file_service.dart

@ -1,42 +1,46 @@
import 'dart:io'; import 'dart:io';
import 'package:win_text_editor/framework/controllers/logger.dart';
import 'package:win_text_editor/framework/models/file_node.dart'; import 'package:win_text_editor/framework/models/file_node.dart';
import 'package:xml/xml.dart';
class FileService { class FileService {
/// ///
static Future<List<FileNode>> listDirectory(String path, {int parentDepth = 0}) async { static Future<List<FileNode>> listDirectory(String path, {int parentDepth = 0}) async {
final directory = Directory(path); final dir = Directory(path);
final List<FileSystemEntity> entities = await dir.list().toList();
final List<FileNode> nodes = []; final List<FileNode> nodes = [];
if (await directory.exists()) {
final entities = directory.listSync();
// FileNode
for (final entity in entities) { for (final entity in entities) {
nodes.add( final isDirectory = await FileSystemEntity.isDirectory(entity.path);
FileNode( final displayName = isDirectory
name: entity.path.split(Platform.pathSeparator).last, ? await getModuleDisplayName(entity.path)
path: entity.path, : null;
isDirectory: entity is Directory,
depth: parentDepth + 1, nodes.add(FileNode(
children: [], name: displayName ?? entity.path.split(Platform.pathSeparator).last,
), path: entity.path,
); isDirectory: isDirectory,
} depth: parentDepth + 1,
));
}
// return nodes;
nodes.sort((a, b) { }
if (a.isDirectory && !b.isDirectory) {
return -1; // a是文件夹b是文件a排在前面
} else if (!a.isDirectory && b.isDirectory) {
return 1; // a是文件b是文件夹b排在前面
} else {
//
return a.name.compareTo(b.name);
}
});
}
return nodes;
static Future<String?> getModuleDisplayName(String dirPath) async {
try {
final moduleFile = File('$dirPath${Platform.pathSeparator}module.xml');
if (await moduleFile.exists()) {
final content = await moduleFile.readAsString();
final xmlDoc = XmlDocument.parse(content);
final infoNode = xmlDoc.findAllElements('info').firstOrNull;
return infoNode?.getAttribute('cname');
}
} catch (e) {
Logger().debug('Error reading module.xml: $e');
}
return null;
} }
/// ///

65
win_text_editor/lib/shared/components/file_explorer.dart

@ -1,9 +1,7 @@
import 'dart:math'; import 'dart:math';
import 'package:file_picker/file_picker.dart';
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/framework/services/file_path_manager.dart';
import '../../framework/models/file_node.dart'; import '../../framework/models/file_node.dart';
import '../../framework/controllers/file_provider.dart'; import '../../framework/controllers/file_provider.dart';
@ -20,32 +18,18 @@ class FileExplorer extends StatefulWidget {
} }
class _FileExplorerState extends State<FileExplorer> { class _FileExplorerState extends State<FileExplorer> {
// ScrollController final ScrollController _scrollController = ScrollController(); // ScrollController
Future<void> _promptForDirectory(BuildContext context) async { @override
final fileProvider = Provider.of<FileProvider>(context, listen: false); void dispose() {
final String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); _scrollController.dispose(); // controller
super.dispose();
if (selectedDirectory != null) {
await FilePathManager.saveLastOpenedFolder(selectedDirectory);
await fileProvider.setRootPath(selectedDirectory);
}
}
Widget _buildEmptyPrompt(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('没有文件可显示'),
TextButton(onPressed: () => _promptForDirectory(context), child: const Text('打开目录')),
],
);
} }
// //
double calculateTotalWidth(BuildContext context, FileProvider fileProvider) { double calculateTotalWidth(BuildContext context, FileProvider fileProvider) {
final maxDepth = _getMaxDepth(fileProvider.fileNodes); final maxDepth = _getMaxDepth(fileProvider.fileNodes);
return maxDepth * 200 + MediaQuery.of(context).size.width * 0.5; return maxDepth * 60 + MediaQuery.of(context).size.width * 0.2;
} }
int _getMaxDepth(List<FileNode> nodes) { int _getMaxDepth(List<FileNode> nodes) {
@ -62,29 +46,24 @@ class _FileExplorerState extends State<FileExplorer> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final fileProvider = Provider.of<FileProvider>(context); final fileProvider = Provider.of<FileProvider>(context);
return Container( return Scrollbar(
color: Colors.white, controller: _scrollController, // controller
child: Column( thumbVisibility: true,
children: [ child: SingleChildScrollView(
Expanded( controller: _scrollController, // 使controller
child: ClipRect( scrollDirection: Axis.horizontal,
child: child: Container(
fileProvider.isLoading color: Colors.white,
? const Center(child: CircularProgressIndicator()) child: SizedBox(
: fileProvider.fileNodes.isEmpty width: calculateTotalWidth(context, fileProvider),
? Center(child: _buildEmptyPrompt(context)) child: TreeView(
: SizedBox( nodes: fileProvider.fileNodes,
width: calculateTotalWidth(context, fileProvider), config: const TreeViewConfig(showIcons: true, lazyLoad: true),
child: TreeView( onNodeTap: (node) => _handleNodeTap(context, node as FileNode),
nodes: fileProvider.fileNodes, onNodeDoubleTap: (node) => _handleNodeDoubleTap(node as FileNode),
config: const TreeViewConfig(showIcons: true, lazyLoad: true),
onNodeTap: (node) => _handleNodeTap(context, node as FileNode),
onNodeDoubleTap: (node) => _handleNodeDoubleTap(node as FileNode),
),
),
), ),
), ),
], ),
), ),
); );
} }

48
win_text_editor/lib/shared/components/tree_view.dart

@ -89,37 +89,33 @@ class _TreeViewState extends State<TreeView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scrollbar( return ListView.builder(
controller: _effectiveController, controller: _effectiveController,
thumbVisibility: true, physics: const ClampingScrollPhysics(),
notificationPredicate: (_) => true, // itemCount: _countVisibleNodes(widget.nodes),
child: ListView.builder( itemBuilder: (context, index) {
controller: _effectiveController, final node = _getVisibleNode(widget.nodes, index);
physics: const ClampingScrollPhysics(), final isSelected = _selectedIds.contains(node.id);
itemCount: _countVisibleNodes(widget.nodes),
itemBuilder: (context, index) { // 使
final node = _getVisibleNode(widget.nodes, index); return widget.nodeBuilder != null
final isSelected = _selectedIds.contains(node.id); ? widget.nodeBuilder!(context, node, isSelected, () => _handleNodeTap(node))
: TreeNodeWidget(
// 使 node: node,
return widget.nodeBuilder != null config: widget.config,
? widget.nodeBuilder!(context, node, isSelected, () => _handleNodeTap(node)) isSelected: isSelected,
: TreeNodeWidget( isChecked: _checkedIds.contains(node.id),
node: node, onTap: () => _handleNodeTap(node),
config: widget.config, onDoubleTap: () => widget.onNodeDoubleTap?.call(node),
isSelected: isSelected, onCheckChanged: (value) => _handleNodeCheckChanged(node, value),
isChecked: _checkedIds.contains(node.id), );
onTap: () => _handleNodeTap(node), },
onDoubleTap: () => widget.onNodeDoubleTap?.call(node),
onCheckChanged: (value) => _handleNodeCheckChanged(node, value),
);
},
),
); );
} }
void _handleNodeTap(TreeNode node) { void _handleNodeTap(TreeNode node) {
if (widget.config.singleSelect && !node.isDirectory) { // if (widget.config.singleSelect && !node.isDirectory) {
//
setState(() { setState(() {
_selectedIds.clear(); _selectedIds.clear();
_selectedIds.add(node.id); _selectedIds.add(node.id);

Loading…
Cancel
Save