feat: unp4k UI update

This commit is contained in:
xkeyC
2025-12-04 17:43:12 +08:00
parent aaa97429b9
commit 1c4eafccca
13 changed files with 1632 additions and 254 deletions

View File

@@ -16,6 +16,24 @@ part 'unp4kc.freezed.dart';
part 'unp4kc.g.dart';
/// 排序类型枚举
enum Unp4kSortType {
/// 默认排序(文件夹优先,按名称)
defaultSort,
/// 文件大小升序
sizeAsc,
/// 文件大小降序
sizeDesc,
/// 修改时间升序
dateAsc,
/// 修改时间降序
dateDesc,
}
@freezed
abstract class Unp4kcState with _$Unp4kcState {
const factory Unp4kcState({
@@ -26,6 +44,21 @@ abstract class Unp4kcState with _$Unp4kcState {
String? endMessage,
MapEntry<String, String>? tempOpenFile,
@Default("") String errorMessage,
@Default("") String searchQuery,
@Default(false) bool isSearching,
/// 搜索结果的虚拟文件系统(支持分级展示)
MemoryFileSystem? searchFs,
/// 搜索匹配的文件路径集合
Set<String>? searchMatchedFiles,
@Default(Unp4kSortType.defaultSort) Unp4kSortType sortType,
/// 是否处于多选模式
@Default(false) bool isMultiSelectMode,
/// 多选模式下选中的文件路径集合
@Default({}) Set<String> selectedItems,
}) = _Unp4kcState;
}
@@ -110,20 +143,15 @@ class Unp4kCModel extends _$Unp4kCModel {
List<AppUnp4kP4kItemData>? getFiles() {
final path = state.curPath.replaceAll("\\", "/");
final fs = state.fs;
// 如果有搜索结果,使用搜索的虚拟文件系统
final fs = state.searchFs ?? state.fs;
if (fs == null) return null;
final dir = fs.directory(path);
if (!dir.existsSync()) return [];
final files = dir.listSync(recursive: false, followLinks: false);
files.sort((a, b) {
if (a is Directory && b is File) {
return -1;
} else if (a is File && b is Directory) {
return 1;
} else {
return a.path.compareTo(b.path);
}
});
final result = <AppUnp4kP4kItemData>[];
for (var file in files) {
if (file is File) {
@@ -138,10 +166,211 @@ class Unp4kCModel extends _$Unp4kCModel {
result.add(AppUnp4kP4kItemData(name: file.path.replaceAll("/", "\\"), isDirectory: true));
}
}
// 应用排序
_sortFiles(result);
return result;
}
/// 对文件列表进行排序
void _sortFiles(List<AppUnp4kP4kItemData> files) {
switch (state.sortType) {
case Unp4kSortType.defaultSort:
// 默认排序:文件夹优先,按名称排序
files.sort((a, b) {
if ((a.isDirectory ?? false) && !(b.isDirectory ?? false)) {
return -1;
} else if (!(a.isDirectory ?? false) && (b.isDirectory ?? false)) {
return 1;
} else {
return (a.name ?? "").compareTo(b.name ?? "");
}
});
break;
case Unp4kSortType.sizeAsc:
// 文件大小升序文件夹大小视为0
files.sort((a, b) {
if ((a.isDirectory ?? false) && !(b.isDirectory ?? false)) {
return -1;
} else if (!(a.isDirectory ?? false) && (b.isDirectory ?? false)) {
return 1;
}
final sizeA = (a.isDirectory ?? false) ? 0 : (a.size ?? 0);
final sizeB = (b.isDirectory ?? false) ? 0 : (b.size ?? 0);
return sizeA.compareTo(sizeB);
});
break;
case Unp4kSortType.sizeDesc:
// 文件大小降序
files.sort((a, b) {
if ((a.isDirectory ?? false) && !(b.isDirectory ?? false)) {
return -1;
} else if (!(a.isDirectory ?? false) && (b.isDirectory ?? false)) {
return 1;
}
final sizeA = (a.isDirectory ?? false) ? 0 : (a.size ?? 0);
final sizeB = (b.isDirectory ?? false) ? 0 : (b.size ?? 0);
return sizeB.compareTo(sizeA);
});
break;
case Unp4kSortType.dateAsc:
// 修改时间升序
files.sort((a, b) {
if ((a.isDirectory ?? false) && !(b.isDirectory ?? false)) {
return -1;
} else if (!(a.isDirectory ?? false) && (b.isDirectory ?? false)) {
return 1;
}
final dateA = a.dateModified ?? 0;
final dateB = b.dateModified ?? 0;
return dateA.compareTo(dateB);
});
break;
case Unp4kSortType.dateDesc:
// 修改时间降序
files.sort((a, b) {
if ((a.isDirectory ?? false) && !(b.isDirectory ?? false)) {
return -1;
} else if (!(a.isDirectory ?? false) && (b.isDirectory ?? false)) {
return 1;
}
final dateA = a.dateModified ?? 0;
final dateB = b.dateModified ?? 0;
return dateB.compareTo(dateA);
});
break;
}
}
/// 设置排序类型
void setSortType(Unp4kSortType sortType) {
state = state.copyWith(sortType: sortType);
}
/// 执行搜索(异步)
Future<void> search(String query) async {
if (query.isEmpty) {
// 清除搜索,返回根目录
state = state.copyWith(
searchQuery: "",
searchFs: null,
searchMatchedFiles: null,
isSearching: false,
curPath: "\\",
);
return;
}
// 保存当前路径,用于搜索后尝试保持
final currentPath = state.curPath;
state = state.copyWith(searchQuery: query, isSearching: true, endMessage: S.current.tools_unp4k_searching);
// 使用 compute 在后台线程执行搜索
final allFiles = state.files;
if (allFiles == null) {
state = state.copyWith(isSearching: false);
return;
}
try {
final searchResult = await compute(_searchFiles, _SearchParams(allFiles, query));
final matchedFiles = searchResult.matchedFiles;
// 构建搜索结果的虚拟文件系统
final searchFs = MemoryFileSystem(style: FileSystemStyle.posix);
for (var filePath in matchedFiles) {
await searchFs.file(filePath.replaceAll("\\", "/")).create(recursive: true);
}
// 检查当前路径是否有搜索结果
String targetPath = "\\";
if (currentPath != "\\") {
final checkPath = currentPath.replaceAll("\\", "/");
final dir = searchFs.directory(checkPath);
if (dir.existsSync() && dir.listSync().isNotEmpty) {
// 当前目录有结果,保持当前路径
targetPath = currentPath;
}
}
state = state.copyWith(
searchFs: searchFs,
searchMatchedFiles: matchedFiles,
isSearching: false,
curPath: targetPath,
endMessage: matchedFiles.isEmpty
? S.current.tools_unp4k_search_no_result
: S.current.tools_unp4k_msg_read_completed(matchedFiles.length, 0),
);
} catch (e) {
dPrint("[unp4k] search error: $e");
state = state.copyWith(isSearching: false, endMessage: e.toString());
}
}
/// 清除搜索
void clearSearch() {
state = state.copyWith(
searchQuery: "",
searchFs: null,
searchMatchedFiles: null,
isSearching: false,
curPath: "\\",
);
}
/// 进入多选模式
void enterMultiSelectMode() {
state = state.copyWith(isMultiSelectMode: true, selectedItems: {});
}
/// 退出多选模式
void exitMultiSelectMode() {
state = state.copyWith(isMultiSelectMode: false, selectedItems: {});
}
/// 切换选中状态
void toggleSelectItem(String itemPath) {
final currentSelected = Set<String>.from(state.selectedItems);
if (currentSelected.contains(itemPath)) {
currentSelected.remove(itemPath);
} else {
currentSelected.add(itemPath);
}
state = state.copyWith(selectedItems: currentSelected);
}
/// 全选当前目录的文件
void selectAll(List<AppUnp4kP4kItemData>? files) {
if (files == null) return;
final currentSelected = Set<String>.from(state.selectedItems);
for (var file in files) {
final path = file.name ?? "";
if (path.isNotEmpty) {
currentSelected.add(path);
}
}
state = state.copyWith(selectedItems: currentSelected);
}
/// 取消全选当前目录的文件
void deselectAll(List<AppUnp4kP4kItemData>? files) {
if (files == null) return;
final currentSelected = Set<String>.from(state.selectedItems);
for (var file in files) {
final path = file.name ?? "";
currentSelected.remove(path);
}
state = state.copyWith(selectedItems: currentSelected);
}
void changeDir(String name, {bool fullPath = false}) {
// 切换目录时退出多选模式
if (state.isMultiSelectMode) {
state = state.copyWith(isMultiSelectMode: false, selectedItems: {});
}
// 切换目录时不清除搜索,只改变当前路径
if (fullPath) {
state = state.copyWith(curPath: name);
} else {
@@ -197,6 +426,202 @@ class Unp4kCModel extends _$Unp4kCModel {
}
}
/// 提取文件或文件夹到指定目录(带进度回调和取消支持)
/// [item] 要提取的文件或文件夹
/// [outputDir] 输出目录
/// [onProgress] 进度回调 (当前文件索引, 总文件数, 当前文件名)
/// [isCancelled] 取消检查函数,返回 true 表示取消
/// 返回值:(是否成功, 已提取文件数, 错误信息)
Future<(bool, int, String?)> extractToDirectoryWithProgress(
AppUnp4kP4kItemData item,
String outputDir, {
void Function(int current, int total, String currentFile)? onProgress,
bool Function()? isCancelled,
}) async {
try {
final itemPath = item.name ?? "";
var filePath = itemPath;
if (filePath.startsWith("\\")) {
filePath = filePath.substring(1);
}
if (item.isDirectory ?? false) {
// 提取文件夹:遍历所有以该路径为前缀的文件
final allFiles = state.files;
if (allFiles != null) {
final prefix = itemPath.endsWith("\\") ? itemPath : "$itemPath\\";
// 收集所有需要提取的文件
final filesToExtract = <MapEntry<String, AppUnp4kP4kItemData>>[];
for (var entry in allFiles.entries) {
if (entry.key.startsWith(prefix) && !(entry.value.isDirectory ?? false)) {
filesToExtract.add(entry);
}
}
final total = filesToExtract.length;
var current = 0;
for (var entry in filesToExtract) {
// 检查是否取消
if (isCancelled?.call() == true) {
return (false, current, S.current.tools_unp4k_extract_cancelled);
}
var entryPath = entry.key;
if (entryPath.startsWith("\\")) {
entryPath = entryPath.substring(1);
}
current++;
onProgress?.call(current, total, entryPath);
final fullOutputPath = "$outputDir\\$entryPath";
await unp4k_api.p4KExtractToDisk(filePath: entryPath, outputPath: fullOutputPath);
}
state = state.copyWith(endMessage: S.current.tools_unp4k_extract_completed(current));
return (true, current, null);
}
return (true, 0, null);
} else {
// 提取单个文件
onProgress?.call(1, 1, filePath);
// 检查是否取消
if (isCancelled?.call() == true) {
return (false, 0, S.current.tools_unp4k_extract_cancelled);
}
final fullOutputPath = "$outputDir\\$filePath";
await unp4k_api.p4KExtractToDisk(filePath: filePath, outputPath: fullOutputPath);
state = state.copyWith(endMessage: S.current.tools_unp4k_extract_completed(1));
return (true, 1, null);
}
} catch (e) {
dPrint("[unp4k] extractToDirectoryWithProgress error: $e");
return (false, 0, e.toString());
}
}
/// 获取文件夹中需要提取的文件数量
int getFileCountInDirectory(AppUnp4kP4kItemData item) {
if (!(item.isDirectory ?? false)) {
return 1;
}
final itemPath = item.name ?? "";
final prefix = itemPath.endsWith("\\") ? itemPath : "$itemPath\\";
final allFiles = state.files;
if (allFiles == null) return 0;
int count = 0;
for (var entry in allFiles.entries) {
if (entry.key.startsWith(prefix) && !(entry.value.isDirectory ?? false)) {
count++;
}
}
return count;
}
/// 获取多选项的总文件数量
int getFileCountForSelectedItems(Set<String> selectedItems) {
int count = 0;
final allFiles = state.files;
if (allFiles == null) return 0;
for (var itemPath in selectedItems) {
final item = allFiles[itemPath];
if (item != null) {
if (item.isDirectory ?? false) {
count += getFileCountInDirectory(item);
} else {
count += 1;
}
} else {
// 可能是文件夹(虚拟路径)
final prefix = itemPath.endsWith("\\") ? itemPath : "$itemPath\\";
for (var entry in allFiles.entries) {
if (entry.key.startsWith(prefix) && !(entry.value.isDirectory ?? false)) {
count++;
}
}
}
}
return count;
}
/// 批量提取多个选中项到指定目录(带进度回调和取消支持)
Future<(bool, int, String?)> extractSelectedItemsWithProgress(
Set<String> selectedItems,
String outputDir, {
void Function(int current, int total, String currentFile)? onProgress,
bool Function()? isCancelled,
}) async {
try {
final allFiles = state.files;
if (allFiles == null) return (true, 0, null);
// 收集所有需要提取的文件
final filesToExtract = <String>[];
for (var itemPath in selectedItems) {
final item = allFiles[itemPath];
if (item != null) {
if (item.isDirectory ?? false) {
// 文件夹:收集所有子文件
final prefix = itemPath.endsWith("\\") ? itemPath : "$itemPath\\";
for (var entry in allFiles.entries) {
if (entry.key.startsWith(prefix) && !(entry.value.isDirectory ?? false)) {
filesToExtract.add(entry.key);
}
}
} else {
// 单个文件
filesToExtract.add(itemPath);
}
} else {
// 可能是虚拟文件夹路径
final prefix = itemPath.endsWith("\\") ? itemPath : "$itemPath\\";
for (var entry in allFiles.entries) {
if (entry.key.startsWith(prefix) && !(entry.value.isDirectory ?? false)) {
filesToExtract.add(entry.key);
}
}
}
}
final total = filesToExtract.length;
var current = 0;
for (var filePath in filesToExtract) {
// 检查是否取消
if (isCancelled?.call() == true) {
return (false, current, S.current.tools_unp4k_extract_cancelled);
}
var extractPath = filePath;
if (extractPath.startsWith("\\")) {
extractPath = extractPath.substring(1);
}
current++;
onProgress?.call(current, total, extractPath);
final fullOutputPath = "$outputDir\\$extractPath";
await unp4k_api.p4KExtractToDisk(filePath: extractPath, outputPath: fullOutputPath);
}
state = state.copyWith(endMessage: S.current.tools_unp4k_extract_completed(current));
return (true, current, null);
} catch (e) {
dPrint("[unp4k] extractSelectedItemsWithProgress error: $e");
return (false, 0, e.toString());
}
}
/// 从 P4K 文件中提取指定文件到内存
/// [p4kPath] P4K 文件路径
/// [filePath] 要提取的文件路径P4K 内部路径)
@@ -211,3 +636,54 @@ class Unp4kCModel extends _$Unp4kCModel {
}
}
}
/// 搜索参数类
class _SearchParams {
final Map<String, AppUnp4kP4kItemData> files;
final String query;
_SearchParams(this.files, this.query);
}
/// 搜索结果类
class _SearchResult {
final Set<String> matchedFiles;
_SearchResult(this.matchedFiles);
}
/// 在后台线程执行搜索
_SearchResult _searchFiles(_SearchParams params) {
final matchedFiles = <String>{};
// 尝试编译正则表达式,如果失败则使用普通字符串匹配
RegExp? regex;
try {
regex = RegExp(params.query, caseSensitive: false);
} catch (e) {
// 正则无效,回退到普通字符串匹配
regex = null;
}
for (var entry in params.files.entries) {
final item = entry.value;
final name = item.name ?? "";
// 跳过文件夹本身
if (item.isDirectory ?? false) continue;
bool matches = false;
if (regex != null) {
matches = regex.hasMatch(name);
} else {
matches = name.toLowerCase().contains(params.query.toLowerCase());
}
if (matches) {
// 添加匹配的文件路径
matchedFiles.add(name.startsWith("\\") ? name : "\\$name");
}
}
return _SearchResult(matchedFiles);
}

View File

@@ -14,7 +14,11 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$Unp4kcState implements DiagnosticableTreeMixin {
bool get startUp; Map<String, AppUnp4kP4kItemData>? get files; MemoryFileSystem? get fs; String get curPath; String? get endMessage; MapEntry<String, String>? get tempOpenFile; String get errorMessage;
bool get startUp; Map<String, AppUnp4kP4kItemData>? get files; MemoryFileSystem? get fs; String get curPath; String? get endMessage; MapEntry<String, String>? get tempOpenFile; String get errorMessage; String get searchQuery; bool get isSearching;/// 搜索结果的虚拟文件系统(支持分级展示)
MemoryFileSystem? get searchFs;/// 搜索匹配的文件路径集合
Set<String>? get searchMatchedFiles; Unp4kSortType get sortType;/// 是否处于多选模式
bool get isMultiSelectMode;/// 多选模式下选中的文件路径集合
Set<String> get selectedItems;
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -26,21 +30,21 @@ $Unp4kcStateCopyWith<Unp4kcState> get copyWith => _$Unp4kcStateCopyWithImpl<Unp4
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
properties
..add(DiagnosticsProperty('type', 'Unp4kcState'))
..add(DiagnosticsProperty('startUp', startUp))..add(DiagnosticsProperty('files', files))..add(DiagnosticsProperty('fs', fs))..add(DiagnosticsProperty('curPath', curPath))..add(DiagnosticsProperty('endMessage', endMessage))..add(DiagnosticsProperty('tempOpenFile', tempOpenFile))..add(DiagnosticsProperty('errorMessage', errorMessage));
..add(DiagnosticsProperty('startUp', startUp))..add(DiagnosticsProperty('files', files))..add(DiagnosticsProperty('fs', fs))..add(DiagnosticsProperty('curPath', curPath))..add(DiagnosticsProperty('endMessage', endMessage))..add(DiagnosticsProperty('tempOpenFile', tempOpenFile))..add(DiagnosticsProperty('errorMessage', errorMessage))..add(DiagnosticsProperty('searchQuery', searchQuery))..add(DiagnosticsProperty('isSearching', isSearching))..add(DiagnosticsProperty('searchFs', searchFs))..add(DiagnosticsProperty('searchMatchedFiles', searchMatchedFiles))..add(DiagnosticsProperty('sortType', sortType))..add(DiagnosticsProperty('isMultiSelectMode', isMultiSelectMode))..add(DiagnosticsProperty('selectedItems', selectedItems));
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is Unp4kcState&&(identical(other.startUp, startUp) || other.startUp == startUp)&&const DeepCollectionEquality().equals(other.files, files)&&(identical(other.fs, fs) || other.fs == fs)&&(identical(other.curPath, curPath) || other.curPath == curPath)&&(identical(other.endMessage, endMessage) || other.endMessage == endMessage)&&(identical(other.tempOpenFile, tempOpenFile) || other.tempOpenFile == tempOpenFile)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
return identical(this, other) || (other.runtimeType == runtimeType&&other is Unp4kcState&&(identical(other.startUp, startUp) || other.startUp == startUp)&&const DeepCollectionEquality().equals(other.files, files)&&(identical(other.fs, fs) || other.fs == fs)&&(identical(other.curPath, curPath) || other.curPath == curPath)&&(identical(other.endMessage, endMessage) || other.endMessage == endMessage)&&(identical(other.tempOpenFile, tempOpenFile) || other.tempOpenFile == tempOpenFile)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.searchQuery, searchQuery) || other.searchQuery == searchQuery)&&(identical(other.isSearching, isSearching) || other.isSearching == isSearching)&&(identical(other.searchFs, searchFs) || other.searchFs == searchFs)&&const DeepCollectionEquality().equals(other.searchMatchedFiles, searchMatchedFiles)&&(identical(other.sortType, sortType) || other.sortType == sortType)&&(identical(other.isMultiSelectMode, isMultiSelectMode) || other.isMultiSelectMode == isMultiSelectMode)&&const DeepCollectionEquality().equals(other.selectedItems, selectedItems));
}
@override
int get hashCode => Object.hash(runtimeType,startUp,const DeepCollectionEquality().hash(files),fs,curPath,endMessage,tempOpenFile,errorMessage);
int get hashCode => Object.hash(runtimeType,startUp,const DeepCollectionEquality().hash(files),fs,curPath,endMessage,tempOpenFile,errorMessage,searchQuery,isSearching,searchFs,const DeepCollectionEquality().hash(searchMatchedFiles),sortType,isMultiSelectMode,const DeepCollectionEquality().hash(selectedItems));
@override
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
return 'Unp4kcState(startUp: $startUp, files: $files, fs: $fs, curPath: $curPath, endMessage: $endMessage, tempOpenFile: $tempOpenFile, errorMessage: $errorMessage)';
return 'Unp4kcState(startUp: $startUp, files: $files, fs: $fs, curPath: $curPath, endMessage: $endMessage, tempOpenFile: $tempOpenFile, errorMessage: $errorMessage, searchQuery: $searchQuery, isSearching: $isSearching, searchFs: $searchFs, searchMatchedFiles: $searchMatchedFiles, sortType: $sortType, isMultiSelectMode: $isMultiSelectMode, selectedItems: $selectedItems)';
}
@@ -51,7 +55,7 @@ abstract mixin class $Unp4kcStateCopyWith<$Res> {
factory $Unp4kcStateCopyWith(Unp4kcState value, $Res Function(Unp4kcState) _then) = _$Unp4kcStateCopyWithImpl;
@useResult
$Res call({
bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage
bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage, String searchQuery, bool isSearching, MemoryFileSystem? searchFs, Set<String>? searchMatchedFiles, Unp4kSortType sortType, bool isMultiSelectMode, Set<String> selectedItems
});
@@ -68,7 +72,7 @@ class _$Unp4kcStateCopyWithImpl<$Res>
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? startUp = null,Object? files = freezed,Object? fs = freezed,Object? curPath = null,Object? endMessage = freezed,Object? tempOpenFile = freezed,Object? errorMessage = null,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? startUp = null,Object? files = freezed,Object? fs = freezed,Object? curPath = null,Object? endMessage = freezed,Object? tempOpenFile = freezed,Object? errorMessage = null,Object? searchQuery = null,Object? isSearching = null,Object? searchFs = freezed,Object? searchMatchedFiles = freezed,Object? sortType = null,Object? isMultiSelectMode = null,Object? selectedItems = null,}) {
return _then(_self.copyWith(
startUp: null == startUp ? _self.startUp : startUp // ignore: cast_nullable_to_non_nullable
as bool,files: freezed == files ? _self.files : files // ignore: cast_nullable_to_non_nullable
@@ -77,7 +81,14 @@ as MemoryFileSystem?,curPath: null == curPath ? _self.curPath : curPath // ignor
as String,endMessage: freezed == endMessage ? _self.endMessage : endMessage // ignore: cast_nullable_to_non_nullable
as String?,tempOpenFile: freezed == tempOpenFile ? _self.tempOpenFile : tempOpenFile // ignore: cast_nullable_to_non_nullable
as MapEntry<String, String>?,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
as String,
as String,searchQuery: null == searchQuery ? _self.searchQuery : searchQuery // ignore: cast_nullable_to_non_nullable
as String,isSearching: null == isSearching ? _self.isSearching : isSearching // ignore: cast_nullable_to_non_nullable
as bool,searchFs: freezed == searchFs ? _self.searchFs : searchFs // ignore: cast_nullable_to_non_nullable
as MemoryFileSystem?,searchMatchedFiles: freezed == searchMatchedFiles ? _self.searchMatchedFiles : searchMatchedFiles // ignore: cast_nullable_to_non_nullable
as Set<String>?,sortType: null == sortType ? _self.sortType : sortType // ignore: cast_nullable_to_non_nullable
as Unp4kSortType,isMultiSelectMode: null == isMultiSelectMode ? _self.isMultiSelectMode : isMultiSelectMode // ignore: cast_nullable_to_non_nullable
as bool,selectedItems: null == selectedItems ? _self.selectedItems : selectedItems // ignore: cast_nullable_to_non_nullable
as Set<String>,
));
}
@@ -162,10 +173,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage, String searchQuery, bool isSearching, MemoryFileSystem? searchFs, Set<String>? searchMatchedFiles, Unp4kSortType sortType, bool isMultiSelectMode, Set<String> selectedItems)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Unp4kcState() when $default != null:
return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessage,_that.tempOpenFile,_that.errorMessage);case _:
return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessage,_that.tempOpenFile,_that.errorMessage,_that.searchQuery,_that.isSearching,_that.searchFs,_that.searchMatchedFiles,_that.sortType,_that.isMultiSelectMode,_that.selectedItems);case _:
return orElse();
}
@@ -183,10 +194,10 @@ return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessag
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage, String searchQuery, bool isSearching, MemoryFileSystem? searchFs, Set<String>? searchMatchedFiles, Unp4kSortType sortType, bool isMultiSelectMode, Set<String> selectedItems) $default,) {final _that = this;
switch (_that) {
case _Unp4kcState():
return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessage,_that.tempOpenFile,_that.errorMessage);case _:
return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessage,_that.tempOpenFile,_that.errorMessage,_that.searchQuery,_that.isSearching,_that.searchFs,_that.searchMatchedFiles,_that.sortType,_that.isMultiSelectMode,_that.selectedItems);case _:
throw StateError('Unexpected subclass');
}
@@ -203,10 +214,10 @@ return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessag
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage, String searchQuery, bool isSearching, MemoryFileSystem? searchFs, Set<String>? searchMatchedFiles, Unp4kSortType sortType, bool isMultiSelectMode, Set<String> selectedItems)? $default,) {final _that = this;
switch (_that) {
case _Unp4kcState() when $default != null:
return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessage,_that.tempOpenFile,_that.errorMessage);case _:
return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessage,_that.tempOpenFile,_that.errorMessage,_that.searchQuery,_that.isSearching,_that.searchFs,_that.searchMatchedFiles,_that.sortType,_that.isMultiSelectMode,_that.selectedItems);case _:
return null;
}
@@ -218,7 +229,7 @@ return $default(_that.startUp,_that.files,_that.fs,_that.curPath,_that.endMessag
class _Unp4kcState with DiagnosticableTreeMixin implements Unp4kcState {
const _Unp4kcState({required this.startUp, final Map<String, AppUnp4kP4kItemData>? files, this.fs, required this.curPath, this.endMessage, this.tempOpenFile, this.errorMessage = ""}): _files = files;
const _Unp4kcState({required this.startUp, final Map<String, AppUnp4kP4kItemData>? files, this.fs, required this.curPath, this.endMessage, this.tempOpenFile, this.errorMessage = "", this.searchQuery = "", this.isSearching = false, this.searchFs, final Set<String>? searchMatchedFiles, this.sortType = Unp4kSortType.defaultSort, this.isMultiSelectMode = false, final Set<String> selectedItems = const {}}): _files = files,_searchMatchedFiles = searchMatchedFiles,_selectedItems = selectedItems;
@override final bool startUp;
@@ -236,6 +247,33 @@ class _Unp4kcState with DiagnosticableTreeMixin implements Unp4kcState {
@override final String? endMessage;
@override final MapEntry<String, String>? tempOpenFile;
@override@JsonKey() final String errorMessage;
@override@JsonKey() final String searchQuery;
@override@JsonKey() final bool isSearching;
/// 搜索结果的虚拟文件系统(支持分级展示)
@override final MemoryFileSystem? searchFs;
/// 搜索匹配的文件路径集合
final Set<String>? _searchMatchedFiles;
/// 搜索匹配的文件路径集合
@override Set<String>? get searchMatchedFiles {
final value = _searchMatchedFiles;
if (value == null) return null;
if (_searchMatchedFiles is EqualUnmodifiableSetView) return _searchMatchedFiles;
// ignore: implicit_dynamic_type
return EqualUnmodifiableSetView(value);
}
@override@JsonKey() final Unp4kSortType sortType;
/// 是否处于多选模式
@override@JsonKey() final bool isMultiSelectMode;
/// 多选模式下选中的文件路径集合
final Set<String> _selectedItems;
/// 多选模式下选中的文件路径集合
@override@JsonKey() Set<String> get selectedItems {
if (_selectedItems is EqualUnmodifiableSetView) return _selectedItems;
// ignore: implicit_dynamic_type
return EqualUnmodifiableSetView(_selectedItems);
}
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@@ -248,21 +286,21 @@ _$Unp4kcStateCopyWith<_Unp4kcState> get copyWith => __$Unp4kcStateCopyWithImpl<_
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
properties
..add(DiagnosticsProperty('type', 'Unp4kcState'))
..add(DiagnosticsProperty('startUp', startUp))..add(DiagnosticsProperty('files', files))..add(DiagnosticsProperty('fs', fs))..add(DiagnosticsProperty('curPath', curPath))..add(DiagnosticsProperty('endMessage', endMessage))..add(DiagnosticsProperty('tempOpenFile', tempOpenFile))..add(DiagnosticsProperty('errorMessage', errorMessage));
..add(DiagnosticsProperty('startUp', startUp))..add(DiagnosticsProperty('files', files))..add(DiagnosticsProperty('fs', fs))..add(DiagnosticsProperty('curPath', curPath))..add(DiagnosticsProperty('endMessage', endMessage))..add(DiagnosticsProperty('tempOpenFile', tempOpenFile))..add(DiagnosticsProperty('errorMessage', errorMessage))..add(DiagnosticsProperty('searchQuery', searchQuery))..add(DiagnosticsProperty('isSearching', isSearching))..add(DiagnosticsProperty('searchFs', searchFs))..add(DiagnosticsProperty('searchMatchedFiles', searchMatchedFiles))..add(DiagnosticsProperty('sortType', sortType))..add(DiagnosticsProperty('isMultiSelectMode', isMultiSelectMode))..add(DiagnosticsProperty('selectedItems', selectedItems));
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Unp4kcState&&(identical(other.startUp, startUp) || other.startUp == startUp)&&const DeepCollectionEquality().equals(other._files, _files)&&(identical(other.fs, fs) || other.fs == fs)&&(identical(other.curPath, curPath) || other.curPath == curPath)&&(identical(other.endMessage, endMessage) || other.endMessage == endMessage)&&(identical(other.tempOpenFile, tempOpenFile) || other.tempOpenFile == tempOpenFile)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Unp4kcState&&(identical(other.startUp, startUp) || other.startUp == startUp)&&const DeepCollectionEquality().equals(other._files, _files)&&(identical(other.fs, fs) || other.fs == fs)&&(identical(other.curPath, curPath) || other.curPath == curPath)&&(identical(other.endMessage, endMessage) || other.endMessage == endMessage)&&(identical(other.tempOpenFile, tempOpenFile) || other.tempOpenFile == tempOpenFile)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.searchQuery, searchQuery) || other.searchQuery == searchQuery)&&(identical(other.isSearching, isSearching) || other.isSearching == isSearching)&&(identical(other.searchFs, searchFs) || other.searchFs == searchFs)&&const DeepCollectionEquality().equals(other._searchMatchedFiles, _searchMatchedFiles)&&(identical(other.sortType, sortType) || other.sortType == sortType)&&(identical(other.isMultiSelectMode, isMultiSelectMode) || other.isMultiSelectMode == isMultiSelectMode)&&const DeepCollectionEquality().equals(other._selectedItems, _selectedItems));
}
@override
int get hashCode => Object.hash(runtimeType,startUp,const DeepCollectionEquality().hash(_files),fs,curPath,endMessage,tempOpenFile,errorMessage);
int get hashCode => Object.hash(runtimeType,startUp,const DeepCollectionEquality().hash(_files),fs,curPath,endMessage,tempOpenFile,errorMessage,searchQuery,isSearching,searchFs,const DeepCollectionEquality().hash(_searchMatchedFiles),sortType,isMultiSelectMode,const DeepCollectionEquality().hash(_selectedItems));
@override
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
return 'Unp4kcState(startUp: $startUp, files: $files, fs: $fs, curPath: $curPath, endMessage: $endMessage, tempOpenFile: $tempOpenFile, errorMessage: $errorMessage)';
return 'Unp4kcState(startUp: $startUp, files: $files, fs: $fs, curPath: $curPath, endMessage: $endMessage, tempOpenFile: $tempOpenFile, errorMessage: $errorMessage, searchQuery: $searchQuery, isSearching: $isSearching, searchFs: $searchFs, searchMatchedFiles: $searchMatchedFiles, sortType: $sortType, isMultiSelectMode: $isMultiSelectMode, selectedItems: $selectedItems)';
}
@@ -273,7 +311,7 @@ abstract mixin class _$Unp4kcStateCopyWith<$Res> implements $Unp4kcStateCopyWith
factory _$Unp4kcStateCopyWith(_Unp4kcState value, $Res Function(_Unp4kcState) _then) = __$Unp4kcStateCopyWithImpl;
@override @useResult
$Res call({
bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage
bool startUp, Map<String, AppUnp4kP4kItemData>? files, MemoryFileSystem? fs, String curPath, String? endMessage, MapEntry<String, String>? tempOpenFile, String errorMessage, String searchQuery, bool isSearching, MemoryFileSystem? searchFs, Set<String>? searchMatchedFiles, Unp4kSortType sortType, bool isMultiSelectMode, Set<String> selectedItems
});
@@ -290,7 +328,7 @@ class __$Unp4kcStateCopyWithImpl<$Res>
/// Create a copy of Unp4kcState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? startUp = null,Object? files = freezed,Object? fs = freezed,Object? curPath = null,Object? endMessage = freezed,Object? tempOpenFile = freezed,Object? errorMessage = null,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? startUp = null,Object? files = freezed,Object? fs = freezed,Object? curPath = null,Object? endMessage = freezed,Object? tempOpenFile = freezed,Object? errorMessage = null,Object? searchQuery = null,Object? isSearching = null,Object? searchFs = freezed,Object? searchMatchedFiles = freezed,Object? sortType = null,Object? isMultiSelectMode = null,Object? selectedItems = null,}) {
return _then(_Unp4kcState(
startUp: null == startUp ? _self.startUp : startUp // ignore: cast_nullable_to_non_nullable
as bool,files: freezed == files ? _self._files : files // ignore: cast_nullable_to_non_nullable
@@ -299,7 +337,14 @@ as MemoryFileSystem?,curPath: null == curPath ? _self.curPath : curPath // ignor
as String,endMessage: freezed == endMessage ? _self.endMessage : endMessage // ignore: cast_nullable_to_non_nullable
as String?,tempOpenFile: freezed == tempOpenFile ? _self.tempOpenFile : tempOpenFile // ignore: cast_nullable_to_non_nullable
as MapEntry<String, String>?,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
as String,
as String,searchQuery: null == searchQuery ? _self.searchQuery : searchQuery // ignore: cast_nullable_to_non_nullable
as String,isSearching: null == isSearching ? _self.isSearching : isSearching // ignore: cast_nullable_to_non_nullable
as bool,searchFs: freezed == searchFs ? _self.searchFs : searchFs // ignore: cast_nullable_to_non_nullable
as MemoryFileSystem?,searchMatchedFiles: freezed == searchMatchedFiles ? _self._searchMatchedFiles : searchMatchedFiles // ignore: cast_nullable_to_non_nullable
as Set<String>?,sortType: null == sortType ? _self.sortType : sortType // ignore: cast_nullable_to_non_nullable
as Unp4kSortType,isMultiSelectMode: null == isMultiSelectMode ? _self.isMultiSelectMode : isMultiSelectMode // ignore: cast_nullable_to_non_nullable
as bool,selectedItems: null == selectedItems ? _self._selectedItems : selectedItems // ignore: cast_nullable_to_non_nullable
as Set<String>,
));
}

View File

@@ -41,7 +41,7 @@ final class Unp4kCModelProvider
}
}
String _$unp4kCModelHash() => r'a296a499158e78848a698c3fda92c4c88ff039be';
String _$unp4kCModelHash() => r'b46274b1409dc904db2d96acf692869edf034b9f';
abstract class _$Unp4kCModel extends $Notifier<Unp4kcState> {
Unp4kcState build();