show upload progress from toolbar popover

This commit is contained in:
ngfchl
2026-07-19 05:02:46 +08:00
parent 716237ef80
commit b88a2eeb01
5 changed files with 392 additions and 126 deletions
+126 -9
View File
@@ -60,6 +60,36 @@ extension FileSortExt on FileSort {
enum SortDirection { ascending, descending }
class UploadProgress {
final int totalFiles;
final int completedFiles;
final int failedFiles;
final int totalBytes;
final int transferredBytes;
final String currentFileName;
final bool isActive;
const UploadProgress({
required this.totalFiles,
required this.completedFiles,
required this.failedFiles,
required this.totalBytes,
required this.transferredBytes,
required this.currentFileName,
required this.isActive,
});
int get processedFiles => completedFiles + failedFiles;
double get fraction {
if (totalBytes > 0) {
return (transferredBytes / totalBytes).clamp(0.0, 1.0);
}
if (totalFiles == 0) return 0;
return (processedFiles / totalFiles).clamp(0.0, 1.0);
}
}
enum WorkspaceSection {
files('全部', 'folder'),
recentViewed('最近查看', 'clock'),
@@ -93,6 +123,7 @@ class FileState {
final Set<String> selectedIDs;
final List<CloudFile>? clipboard;
final bool clipboardIsMove;
final UploadProgress? uploadProgress;
const FileState({
this.section = WorkspaceSection.files,
@@ -109,6 +140,7 @@ class FileState {
this.selectedIDs = const {},
this.clipboard,
this.clipboardIsMove = false,
this.uploadProgress,
});
bool get hasSelection => selectedIDs.isNotEmpty;
@@ -132,6 +164,8 @@ class FileState {
List<CloudFile>? clipboard,
bool clearClipboard = false,
bool? clipboardIsMove,
UploadProgress? uploadProgress,
bool clearUploadProgress = false,
}) {
return FileState(
section: section ?? this.section,
@@ -148,6 +182,9 @@ class FileState {
selectedIDs: selectedIDs ?? this.selectedIDs,
clipboard: clearClipboard ? null : (clipboard ?? this.clipboard),
clipboardIsMove: clipboardIsMove ?? this.clipboardIsMove,
uploadProgress: clearUploadProgress
? null
: (uploadProgress ?? this.uploadProgress),
);
}
}
@@ -1048,19 +1085,99 @@ class FileNotifier extends StateNotifier<FileState> {
Future<void> uploadLocalFiles(List<File> files, {String? parentID}) async {
if (_api == null || files.isEmpty) return;
final targetParentID = parentID ?? _currentParentID;
state = state.copyWith(statusMessage: '正在上传 ${files.length} 个文件…');
final uploadFiles = <File>[];
var totalBytes = 0;
for (final file in files) {
if (!await file.exists()) continue;
uploadFiles.add(file);
totalBytes += await file.length();
}
if (uploadFiles.isEmpty) {
state = state.copyWith(errorMessage: '没有可上传的本地文件');
return;
}
UploadProgress progress({
required int completed,
required int failed,
required int transferred,
required String currentName,
required bool active,
}) => UploadProgress(
totalFiles: uploadFiles.length,
completedFiles: completed,
failedFiles: failed,
totalBytes: totalBytes,
transferredBytes: transferred,
currentFileName: currentName,
isActive: active,
);
state = state.copyWith(
statusMessage: '正在上传 ${uploadFiles.length} 个文件…',
uploadProgress: progress(
completed: 0,
failed: 0,
transferred: 0,
currentName: uploadFiles.first.uri.pathSegments.last,
active: true,
),
);
var completed = 0;
try {
for (final file in files) {
if (!await file.exists()) continue;
state = state.copyWith(
statusMessage:
'正在上传 ${completed + 1}/${files.length}${file.uri.pathSegments.last}',
var failed = 0;
var completedBytes = 0;
for (final file in uploadFiles) {
final fileSize = await file.length();
final fileName = file.uri.pathSegments.last;
state = state.copyWith(
statusMessage:
'正在上传 ${completed + failed + 1}/${uploadFiles.length}$fileName',
uploadProgress: progress(
completed: completed,
failed: failed,
transferred: completedBytes,
currentName: fileName,
active: true,
),
);
try {
await _api!.fileUpload(
file,
parentID: targetParentID,
onProgress: (sent, total) {
final currentTransferred =
completedBytes + sent.clamp(0, total == 0 ? 0 : total).toInt();
state = state.copyWith(
uploadProgress: progress(
completed: completed,
failed: failed,
transferred: currentTransferred,
currentName: fileName,
active: true,
),
);
},
);
await _api!.fileUpload(file, parentID: targetParentID);
completed += 1;
completedBytes += fileSize;
} catch (_) {
failed += 1;
completedBytes += fileSize;
}
state = state.copyWith(statusMessage: '已上传 $completed 个文件');
}
state = state.copyWith(
statusMessage: failed == 0
? '已上传 $completed 个文件'
: '已上传 $completed 个文件,失败 $failed',
uploadProgress: progress(
completed: completed,
failed: failed,
transferred: completedBytes,
currentName: '',
active: false,
),
);
try {
await _invalidateFolderCaches(targetParentID);
await loadFiles(parentID: _currentParentID);
} catch (e) {