You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

227 lines
6.1 KiB

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:win_text_editor/app/models/file_node.dart';
import 'package:win_text_editor/app/services/file_service.dart';
class FileProvider with ChangeNotifier {
List<FileNode> _fileNodes = [];
bool _isLoading = false;
String _searchQuery = '';
String? _currentRootPath; // 跟踪当前根路径
bool get isLoading => _isLoading;
bool get hasRoot => _fileNodes.isNotEmpty && _fileNodes[0].isRoot;
// 移除构造函数的_initFileTree调用
FileProvider();
// 新增方法:手动设置根路径
Future<void> setRootPath(String path) async {
_currentRootPath = path;
await _loadRootDirectory();
}
List<FileNode> get fileNodes =>
_searchQuery.isEmpty ? _fileNodes : _fileNodes.where((node) => _filterNode(node)).toList();
bool _filterNode(FileNode node) {
if (node.name.toLowerCase().contains(_searchQuery.toLowerCase())) {
return true;
}
return node.children.any(_filterNode);
}
void searchFiles(String query) {
_searchQuery = query;
notifyListeners();
}
void toggleExpand(FileNode node) {
node.isExpanded = !node.isExpanded;
notifyListeners();
}
Future<void> pickAndOpenFile() async {
final result = await FilePicker.platform.pickFiles();
if (result != null && result.files.single.path != null) {
// 这里需要与编辑器提供者交互来打开文件
debugPrint('File selected: ${result.files.single.path}');
}
}
Future<void> loadDirectory(String path) async {
_isLoading = true;
notifyListeners();
try {
final directory = Directory(path);
final rootNode = FileNode(
name: directory.path.split(Platform.pathSeparator).last,
path: directory.path,
isDirectory: true,
isRoot: true, // 添加根节点标识
children: await FileService.buildFileTree(directory.path),
);
_fileNodes = [rootNode]; // 将根节点作为唯一顶层节点
} catch (e) {
debugPrint('Error loading directory: $e');
_fileNodes = [];
}
_isLoading = false;
notifyListeners();
}
Future<void> _loadRootDirectory() async {
if (_currentRootPath == null) return;
_isLoading = true;
notifyListeners();
try {
_fileNodes = [
FileNode(
name: _currentRootPath!.split(Platform.pathSeparator).last,
path: _currentRootPath!,
isDirectory: true,
isRoot: true,
depth: 0, // 根节点深度为0
children: [], // 初始为空,不加载内容
),
];
} catch (e) {
debugPrint('Error loading root directory: $e');
_fileNodes = [];
}
_isLoading = false;
notifyListeners();
}
Future<void> loadRootDirectory(String path) async {
_isLoading = true;
notifyListeners();
try {
_fileNodes = [
FileNode(
name: path.split(Platform.pathSeparator).last,
path: path,
isDirectory: true,
isRoot: true,
children: [], // 初始为空
),
];
} catch (e) {
debugPrint('Error loading root: $e');
_fileNodes = [];
}
_isLoading = false;
notifyListeners();
}
Future<void> toggleDirectory(FileNode dirNode) async {
if (dirNode.children.isEmpty) {
// 首次点击:加载内容
_isLoading = true;
notifyListeners();
try {
dirNode.children = await FileService.listDirectory(dirNode.path);
dirNode.isExpanded = true;
} catch (e) {
debugPrint('Error loading dir: $e');
dirNode.children = [];
}
_isLoading = false;
notifyListeners();
} else {
// 已加载过:只切换展开状态
dirNode.isExpanded = !dirNode.isExpanded;
notifyListeners();
}
}
Future<void> loadDirectoryContents(FileNode dirNode) async {
if (dirNode.children.isNotEmpty && dirNode.isExpanded) {
// 如果已经加载过且是展开状态,只切换展开状态
dirNode.isExpanded = !dirNode.isExpanded;
notifyListeners();
return;
}
_isLoading = true;
notifyListeners();
try {
final contents = await FileService.listDirectory(
dirNode.path,
parentDepth: dirNode.depth, // 确保传递父节点深度
);
final updatedNode = dirNode.copyWith(
children: contents,
isExpanded: true,
// 不需要设置 depth,因为 copyWith 会自动保留原值
);
_replaceNodeInTree(dirNode, updatedNode);
} catch (e) {
debugPrint('Error loading directory contents: $e');
final updatedNode = dirNode.copyWith(children: []);
_replaceNodeInTree(dirNode, updatedNode);
}
_isLoading = false;
notifyListeners();
}
void _replaceNodeInTree(FileNode oldNode, FileNode newNode) {
for (int i = 0; i < _fileNodes.length; i++) {
if (_fileNodes[i] == oldNode) {
_fileNodes[i] = newNode;
return;
}
_replaceNodeInChildren(_fileNodes[i], oldNode, newNode);
}
}
void _replaceNodeInChildren(FileNode parent, FileNode oldNode, FileNode newNode) {
for (int i = 0; i < parent.children.length; i++) {
if (parent.children[i] == oldNode) {
parent.children[i] = newNode;
return;
}
_replaceNodeInChildren(parent.children[i], oldNode, newNode);
}
}
Future<void> refreshFileTree({bool loadContent = false}) async {
_isLoading = true;
notifyListeners();
try {
final rootDir = await getApplicationDocumentsDirectory();
_fileNodes = [
FileNode(
name: rootDir.path.split(Platform.pathSeparator).last,
path: rootDir.path,
isDirectory: true,
isRoot: true,
// 初始不加载内容
children: loadContent ? await FileService.listDirectory(rootDir.path) : [],
),
];
} catch (e) {
debugPrint('Error refreshing file tree: $e');
_fileNodes = [];
}
_isLoading = false;
notifyListeners();
}
}