diff --git a/lib/upload_video/video_batch_upload_queue.dart b/lib/upload_video/video_batch_upload_queue.dart index fa4d237..74b1d2b 100644 --- a/lib/upload_video/video_batch_upload_queue.dart +++ b/lib/upload_video/video_batch_upload_queue.dart @@ -12,7 +12,8 @@ class VideoBatchUploadQueue { VideoBatchUploadQueue({ required this.contextProvider, required this.uploadTask, - required this.saveTask, + this.saveTask, + this.batchSaveTask, required this.onChanged, this.assetType = VideoBatchUploadAssetType.video, this.onCompleted, @@ -22,7 +23,8 @@ class VideoBatchUploadQueue { final BuildContext? Function() contextProvider; final VideoBatchUploadUploadTask uploadTask; - final VideoBatchUploadSaveTask saveTask; + final VideoBatchUploadSaveTask? saveTask; + final VideoBatchUploadBatchSaveTask? batchSaveTask; final VoidCallback onChanged; final VideoBatchUploadAssetType assetType; final FutureOr Function()? onCompleted; @@ -58,6 +60,8 @@ class VideoBatchUploadQueue { int get finishedCount => _completedRemovedCount + completedCount + failedCount; + bool get _usesBatchSave => batchSaveTask != null; + Future pickAndStart() async { if (hasActiveUploads) { isExpanded = true; @@ -195,6 +199,7 @@ class VideoBatchUploadQueue { ); await Future.wait(workers); _isRunning = false; + await _saveUploadedBatchIfNeeded(); await _notifyCompletedIfNeeded(); } @@ -251,9 +256,13 @@ class VideoBatchUploadQueue { ..status = VideoBatchUploadStatus.uploaded; _notifyChanged(); + if (_usesBatchSave) { + return; + } + task.status = VideoBatchUploadStatus.saving; _notifyChanged(); - final bool saved = await saveTask(task); + final bool saved = await saveTask!(task); if (!tasks.contains(task)) { return; } @@ -290,6 +299,62 @@ class VideoBatchUploadQueue { } } + Future _saveUploadedBatchIfNeeded() async { + if (!_usesBatchSave || _isDisposed) { + return; + } + final List successfulUploadTasks = tasks + .where((VideoBatchUploadTask task) => + task.status == VideoBatchUploadStatus.uploaded) + .toList(); + if (successfulUploadTasks.isEmpty) { + return; + } + + for (final VideoBatchUploadTask task in successfulUploadTasks) { + task.status = VideoBatchUploadStatus.saving; + } + _notifyChanged(); + + try { + final bool saved = await batchSaveTask!(List.of( + successfulUploadTasks, + growable: false, + )); + if (_isDisposed) { + return; + } + if (saved) { + _completedRemovedCount += successfulUploadTasks.length; + tasks.removeWhere(successfulUploadTasks.contains); + if (tasks.isEmpty) { + isExpanded = false; + } + return; + } + for (final VideoBatchUploadTask task in successfulUploadTasks) { + if (tasks.contains(task)) { + task + ..status = VideoBatchUploadStatus.failed + ..errorMessage = '入库失败'; + } + } + } catch (_) { + if (_isDisposed) { + return; + } + for (final VideoBatchUploadTask task in successfulUploadTasks) { + if (tasks.contains(task)) { + task + ..status = VideoBatchUploadStatus.failed + ..errorMessage = '入库失败'; + } + } + } finally { + _notifyChanged(); + } + } + String _networkErrorText(DioException error) { switch (error.type) { case DioExceptionType.connectionTimeout: diff --git a/lib/upload_video/video_batch_upload_task.dart b/lib/upload_video/video_batch_upload_task.dart index ddaa60d..35267ef 100644 --- a/lib/upload_video/video_batch_upload_task.dart +++ b/lib/upload_video/video_batch_upload_task.dart @@ -14,6 +14,10 @@ typedef VideoBatchUploadSaveTask = Future Function( VideoBatchUploadTask task, ); +typedef VideoBatchUploadBatchSaveTask = Future Function( + List tasks, +); + enum VideoBatchUploadAssetType { image, video, diff --git a/lib/upload_video/video_batch_uploader.dart b/lib/upload_video/video_batch_uploader.dart index 10964f9..d7c5c5c 100644 --- a/lib/upload_video/video_batch_uploader.dart +++ b/lib/upload_video/video_batch_uploader.dart @@ -13,18 +13,21 @@ class VideoBatchUploader { VideoBatchUploader({ required BuildContext? Function() contextProvider, required VideoBatchUploadUploadTask uploadTask, - required VideoBatchUploadSaveTask saveTask, + VideoBatchUploadSaveTask? saveTask, + VideoBatchUploadBatchSaveTask? batchSaveTask, VideoBatchUploadAssetType assetType = VideoBatchUploadAssetType.video, VoidCallback? onChanged, VideoBatchUploadCallback? onCompleted, int? maxAssets, int? maxConcurrent, - }) : _contextProvider = contextProvider, + }) : assert(saveTask != null || batchSaveTask != null), + _contextProvider = contextProvider, _onChanged = onChanged { queue = VideoBatchUploadQueue( contextProvider: contextProvider, uploadTask: uploadTask, saveTask: saveTask, + batchSaveTask: batchSaveTask, onChanged: _handleChanged, assetType: assetType, onCompleted: onCompleted,