diff --git a/lib/upload_video/video_batch_upload_panel.dart b/lib/upload_video/video_batch_upload_panel.dart index 3304458..ca7293d 100644 --- a/lib/upload_video/video_batch_upload_panel.dart +++ b/lib/upload_video/video_batch_upload_panel.dart @@ -67,7 +67,7 @@ class _CollapsedUploadBar extends StatelessWidget { SizedBox(width: 12.w), Expanded( child: Text( - '正在上传 ${queue.finishedCount}/${queue.totalCount}', + '正在上传${queue.assetType.label} ${queue.finishedCount}/${queue.totalCount}', style: TextStyle( fontSize: 24.sp, color: const Color(0xFF1F2937), @@ -117,7 +117,7 @@ class _ExpandedUploadPanel extends StatelessWidget { children: [ Expanded( child: Text( - '上传视频', + '上传${queue.assetType.label}', style: TextStyle( fontSize: 30.sp, color: const Color(0xFF111827), @@ -201,7 +201,9 @@ class _UploadTaskCell extends StatelessWidget { color: const Color(0xFFEDEFF3), alignment: Alignment.center, child: Icon( - Icons.videocam_outlined, + task.assetType == VideoBatchUploadAssetType.video + ? Icons.videocam_outlined + : Icons.image_outlined, size: 46.sp, color: const Color(0xFF98A2B3), ), @@ -292,7 +294,7 @@ class _UploadTaskCell extends StatelessWidget { if (task.durationText.isNotEmpty) task.durationText, if (task.fileSizeText.isNotEmpty) task.fileSizeText, ]; - return parts.isEmpty ? '本地视频' : parts.join(' · '); + return parts.isEmpty ? task.assetType.localLabel : parts.join(' · '); } } diff --git a/lib/upload_video/video_batch_upload_queue.dart b/lib/upload_video/video_batch_upload_queue.dart index 1cb2983..fa4d237 100644 --- a/lib/upload_video/video_batch_upload_queue.dart +++ b/lib/upload_video/video_batch_upload_queue.dart @@ -14,6 +14,7 @@ class VideoBatchUploadQueue { required this.uploadTask, required this.saveTask, required this.onChanged, + this.assetType = VideoBatchUploadAssetType.video, this.onCompleted, this.maxAssets = VideoBatchUploadConfig.maxAssets, this.maxConcurrent = VideoBatchUploadConfig.maxConcurrent, @@ -23,6 +24,7 @@ class VideoBatchUploadQueue { final VideoBatchUploadUploadTask uploadTask; final VideoBatchUploadSaveTask saveTask; final VoidCallback onChanged; + final VideoBatchUploadAssetType assetType; final FutureOr Function()? onCompleted; final int maxAssets; final int maxConcurrent; @@ -60,7 +62,7 @@ class VideoBatchUploadQueue { if (hasActiveUploads) { isExpanded = true; _notifyChanged(); - ToastUtils.showToast(msg: '视频正在上传中'); + ToastUtils.showToast(msg: '${assetType.label}正在上传中'); return; } @@ -70,9 +72,10 @@ class VideoBatchUploadQueue { } final List pickedTasks = - await VideoBatchUploadPicker.pickVideos( + await VideoBatchUploadPicker.pickMedia( context, maxAssets: maxAssets, + assetType: assetType, ); if (pickedTasks.isEmpty) { return; @@ -157,7 +160,7 @@ class VideoBatchUploadQueue { return; } ToastUtils.showAlterDialog( - titleText: '视频还在上传', + titleText: '${assetType.label}还在上传', contentText: '离开会中断本次上传,确定要离开吗?', confirmText: '离开', confirmCallback: () { @@ -315,11 +318,13 @@ class VideoBatchUploadQueue { await onCompleted?.call(); if (failedCount > 0) { ToastUtils.showToast( - msg: '已上传 $_completedRemovedCount 个,失败 $failedCount 个'); + msg: + '已上传 $_completedRemovedCount ${assetType.unit},失败 $failedCount ${assetType.unit}'); return; } final int completed = _completedRemovedCount; - ToastUtils.showToast(msg: '已上传 $completed 个视频'); + ToastUtils.showToast( + msg: '已上传 $completed ${assetType.unit}${assetType.label}'); tasks.clear(); isExpanded = false; _resetBatchProgress(); diff --git a/lib/upload_video/video_batch_upload_service.dart b/lib/upload_video/video_batch_upload_service.dart index 6c2aa4c..2d0cf39 100644 --- a/lib/upload_video/video_batch_upload_service.dart +++ b/lib/upload_video/video_batch_upload_service.dart @@ -13,12 +13,35 @@ class VideoBatchUploadPicker { static Future> pickVideos( BuildContext context, { int maxAssets = VideoBatchUploadConfig.maxAssets, + }) async { + return pickMedia( + context, + maxAssets: maxAssets, + assetType: VideoBatchUploadAssetType.video, + ); + } + + static Future> pickImages( + BuildContext context, { + int maxAssets = VideoBatchUploadConfig.maxAssets, + }) async { + return pickMedia( + context, + maxAssets: maxAssets, + assetType: VideoBatchUploadAssetType.image, + ); + } + + static Future> pickMedia( + BuildContext context, { + int maxAssets = VideoBatchUploadConfig.maxAssets, + VideoBatchUploadAssetType assetType = VideoBatchUploadAssetType.video, }) async { final List? assets = await AssetPicker.pickAssets( context, pickerConfig: AssetPickerConfig( maxAssets: maxAssets, - requestType: RequestType.video, + requestType: _requestType(assetType), ), ); if (assets == null || assets.isEmpty) { @@ -39,10 +62,12 @@ class VideoBatchUploadPicker { tasks.add( VideoBatchUploadTask( id: '${asset.id}_${DateTime.now().microsecondsSinceEpoch}', + assetType: assetType, file: file, - fileName: _normalizeFileName(asset.title, file.path), + fileName: _normalizeFileName(asset.title, file.path, assetType), fileSize: fileSize, - duration: asset.duration, + duration: + assetType == VideoBatchUploadAssetType.video ? asset.duration : 0, thumbnail: thumbnail, ), ); @@ -50,13 +75,26 @@ class VideoBatchUploadPicker { return tasks; } - static String _normalizeFileName(String? assetTitle, String path) { + static RequestType _requestType(VideoBatchUploadAssetType assetType) { + switch (assetType) { + case VideoBatchUploadAssetType.image: + return RequestType.image; + case VideoBatchUploadAssetType.video: + return RequestType.video; + } + } + + static String _normalizeFileName( + String? assetTitle, + String path, + VideoBatchUploadAssetType assetType, + ) { final String title = (assetTitle ?? '').trim(); if (title.isNotEmpty) { return title; } final List segments = path.split(Platform.pathSeparator); final String fileName = segments.isEmpty ? '' : segments.last.trim(); - return fileName.isEmpty ? 'video.mp4' : fileName; + return fileName.isEmpty ? assetType.defaultFileName : fileName; } } diff --git a/lib/upload_video/video_batch_upload_task.dart b/lib/upload_video/video_batch_upload_task.dart index 9e6357b..ddaa60d 100644 --- a/lib/upload_video/video_batch_upload_task.dart +++ b/lib/upload_video/video_batch_upload_task.dart @@ -14,6 +14,49 @@ typedef VideoBatchUploadSaveTask = Future Function( VideoBatchUploadTask task, ); +enum VideoBatchUploadAssetType { + image, + video, +} + +extension VideoBatchUploadAssetTypeText on VideoBatchUploadAssetType { + String get label { + switch (this) { + case VideoBatchUploadAssetType.image: + return '图片'; + case VideoBatchUploadAssetType.video: + return '视频'; + } + } + + String get unit { + switch (this) { + case VideoBatchUploadAssetType.image: + return '张'; + case VideoBatchUploadAssetType.video: + return '个'; + } + } + + String get localLabel { + switch (this) { + case VideoBatchUploadAssetType.image: + return '本地图片'; + case VideoBatchUploadAssetType.video: + return '本地视频'; + } + } + + String get defaultFileName { + switch (this) { + case VideoBatchUploadAssetType.image: + return 'image.jpg'; + case VideoBatchUploadAssetType.video: + return 'video.mp4'; + } + } +} + enum VideoBatchUploadStatus { waiting, uploading, @@ -45,6 +88,7 @@ extension VideoBatchUploadStatusText on VideoBatchUploadStatus { class VideoBatchUploadTask { VideoBatchUploadTask({ required this.id, + this.assetType = VideoBatchUploadAssetType.video, required this.file, required this.fileName, required this.fileSize, @@ -53,6 +97,7 @@ class VideoBatchUploadTask { }); final String id; + final VideoBatchUploadAssetType assetType; final File file; final String fileName; final int fileSize; @@ -120,4 +165,8 @@ class VideoBatchUploadTask { Map toLibraryVideoPayload() { return toVideoPayload(); } + + String toLibraryImageURL() { + return uploadUrl; + } } diff --git a/lib/upload_video/video_batch_upload_widgets.dart b/lib/upload_video/video_batch_upload_widgets.dart index 0d40476..e678db3 100644 --- a/lib/upload_video/video_batch_upload_widgets.dart +++ b/lib/upload_video/video_batch_upload_widgets.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'video_batch_upload_task.dart'; + class VideoBatchUploadBackButton extends StatelessWidget { const VideoBatchUploadBackButton({ super.key, @@ -28,11 +30,13 @@ class VideoBatchUploadIconButton extends StatelessWidget { const VideoBatchUploadIconButton({ super.key, required this.onTap, + this.assetType = VideoBatchUploadAssetType.video, this.iconSize, this.rightPadding, }); final VoidCallback onTap; + final VideoBatchUploadAssetType assetType; final double? iconSize; final double? rightPadding; @@ -43,7 +47,9 @@ class VideoBatchUploadIconButton extends StatelessWidget { child: Padding( padding: EdgeInsets.only(right: rightPadding ?? 30.w), child: Icon( - Icons.video_call_outlined, + assetType == VideoBatchUploadAssetType.video + ? Icons.video_call_outlined + : Icons.add_photo_alternate_outlined, size: iconSize ?? 50.sp, color: const Color(0xFF1D1D21), ), diff --git a/lib/upload_video/video_batch_uploader.dart b/lib/upload_video/video_batch_uploader.dart index cdc16f9..10964f9 100644 --- a/lib/upload_video/video_batch_uploader.dart +++ b/lib/upload_video/video_batch_uploader.dart @@ -14,6 +14,7 @@ class VideoBatchUploader { required BuildContext? Function() contextProvider, required VideoBatchUploadUploadTask uploadTask, required VideoBatchUploadSaveTask saveTask, + VideoBatchUploadAssetType assetType = VideoBatchUploadAssetType.video, VoidCallback? onChanged, VideoBatchUploadCallback? onCompleted, int? maxAssets, @@ -25,6 +26,7 @@ class VideoBatchUploader { uploadTask: uploadTask, saveTask: saveTask, onChanged: _handleChanged, + assetType: assetType, onCompleted: onCompleted, maxAssets: maxAssets ?? VideoBatchUploadConfig.maxAssets, maxConcurrent: maxConcurrent ?? VideoBatchUploadConfig.maxConcurrent,