fix(upload_image): 修改媒体上传文件

This commit is contained in:
2026-05-29 17:58:44 +08:00
parent aa89e03bee
commit 037f14b52f
6 changed files with 117 additions and 15 deletions
@@ -67,7 +67,7 @@ class _CollapsedUploadBar extends StatelessWidget {
SizedBox(width: 12.w), SizedBox(width: 12.w),
Expanded( Expanded(
child: Text( child: Text(
'正在上传 ${queue.finishedCount}/${queue.totalCount}', '正在上传${queue.assetType.label} ${queue.finishedCount}/${queue.totalCount}',
style: TextStyle( style: TextStyle(
fontSize: 24.sp, fontSize: 24.sp,
color: const Color(0xFF1F2937), color: const Color(0xFF1F2937),
@@ -117,7 +117,7 @@ class _ExpandedUploadPanel extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: Text( child: Text(
'上传视频', '上传${queue.assetType.label}',
style: TextStyle( style: TextStyle(
fontSize: 30.sp, fontSize: 30.sp,
color: const Color(0xFF111827), color: const Color(0xFF111827),
@@ -201,7 +201,9 @@ class _UploadTaskCell extends StatelessWidget {
color: const Color(0xFFEDEFF3), color: const Color(0xFFEDEFF3),
alignment: Alignment.center, alignment: Alignment.center,
child: Icon( child: Icon(
Icons.videocam_outlined, task.assetType == VideoBatchUploadAssetType.video
? Icons.videocam_outlined
: Icons.image_outlined,
size: 46.sp, size: 46.sp,
color: const Color(0xFF98A2B3), color: const Color(0xFF98A2B3),
), ),
@@ -292,7 +294,7 @@ class _UploadTaskCell extends StatelessWidget {
if (task.durationText.isNotEmpty) task.durationText, if (task.durationText.isNotEmpty) task.durationText,
if (task.fileSizeText.isNotEmpty) task.fileSizeText, if (task.fileSizeText.isNotEmpty) task.fileSizeText,
]; ];
return parts.isEmpty ? '本地视频' : parts.join(' · '); return parts.isEmpty ? task.assetType.localLabel : parts.join(' · ');
} }
} }
+10 -5
View File
@@ -14,6 +14,7 @@ class VideoBatchUploadQueue {
required this.uploadTask, required this.uploadTask,
required this.saveTask, required this.saveTask,
required this.onChanged, required this.onChanged,
this.assetType = VideoBatchUploadAssetType.video,
this.onCompleted, this.onCompleted,
this.maxAssets = VideoBatchUploadConfig.maxAssets, this.maxAssets = VideoBatchUploadConfig.maxAssets,
this.maxConcurrent = VideoBatchUploadConfig.maxConcurrent, this.maxConcurrent = VideoBatchUploadConfig.maxConcurrent,
@@ -23,6 +24,7 @@ class VideoBatchUploadQueue {
final VideoBatchUploadUploadTask uploadTask; final VideoBatchUploadUploadTask uploadTask;
final VideoBatchUploadSaveTask saveTask; final VideoBatchUploadSaveTask saveTask;
final VoidCallback onChanged; final VoidCallback onChanged;
final VideoBatchUploadAssetType assetType;
final FutureOr<void> Function()? onCompleted; final FutureOr<void> Function()? onCompleted;
final int maxAssets; final int maxAssets;
final int maxConcurrent; final int maxConcurrent;
@@ -60,7 +62,7 @@ class VideoBatchUploadQueue {
if (hasActiveUploads) { if (hasActiveUploads) {
isExpanded = true; isExpanded = true;
_notifyChanged(); _notifyChanged();
ToastUtils.showToast(msg: '视频正在上传中'); ToastUtils.showToast(msg: '${assetType.label}正在上传中');
return; return;
} }
@@ -70,9 +72,10 @@ class VideoBatchUploadQueue {
} }
final List<VideoBatchUploadTask> pickedTasks = final List<VideoBatchUploadTask> pickedTasks =
await VideoBatchUploadPicker.pickVideos( await VideoBatchUploadPicker.pickMedia(
context, context,
maxAssets: maxAssets, maxAssets: maxAssets,
assetType: assetType,
); );
if (pickedTasks.isEmpty) { if (pickedTasks.isEmpty) {
return; return;
@@ -157,7 +160,7 @@ class VideoBatchUploadQueue {
return; return;
} }
ToastUtils.showAlterDialog( ToastUtils.showAlterDialog(
titleText: '视频还在上传', titleText: '${assetType.label}还在上传',
contentText: '离开会中断本次上传,确定要离开吗?', contentText: '离开会中断本次上传,确定要离开吗?',
confirmText: '离开', confirmText: '离开',
confirmCallback: () { confirmCallback: () {
@@ -315,11 +318,13 @@ class VideoBatchUploadQueue {
await onCompleted?.call(); await onCompleted?.call();
if (failedCount > 0) { if (failedCount > 0) {
ToastUtils.showToast( ToastUtils.showToast(
msg: '已上传 $_completedRemovedCount 个,失败 $failedCount'); msg:
'已上传 $_completedRemovedCount ${assetType.unit},失败 $failedCount ${assetType.unit}');
return; return;
} }
final int completed = _completedRemovedCount; final int completed = _completedRemovedCount;
ToastUtils.showToast(msg: '已上传 $completed 个视频'); ToastUtils.showToast(
msg: '已上传 $completed ${assetType.unit}${assetType.label}');
tasks.clear(); tasks.clear();
isExpanded = false; isExpanded = false;
_resetBatchProgress(); _resetBatchProgress();
@@ -13,12 +13,35 @@ class VideoBatchUploadPicker {
static Future<List<VideoBatchUploadTask>> pickVideos( static Future<List<VideoBatchUploadTask>> pickVideos(
BuildContext context, { BuildContext context, {
int maxAssets = VideoBatchUploadConfig.maxAssets, int maxAssets = VideoBatchUploadConfig.maxAssets,
}) async {
return pickMedia(
context,
maxAssets: maxAssets,
assetType: VideoBatchUploadAssetType.video,
);
}
static Future<List<VideoBatchUploadTask>> pickImages(
BuildContext context, {
int maxAssets = VideoBatchUploadConfig.maxAssets,
}) async {
return pickMedia(
context,
maxAssets: maxAssets,
assetType: VideoBatchUploadAssetType.image,
);
}
static Future<List<VideoBatchUploadTask>> pickMedia(
BuildContext context, {
int maxAssets = VideoBatchUploadConfig.maxAssets,
VideoBatchUploadAssetType assetType = VideoBatchUploadAssetType.video,
}) async { }) async {
final List<AssetEntity>? assets = await AssetPicker.pickAssets( final List<AssetEntity>? assets = await AssetPicker.pickAssets(
context, context,
pickerConfig: AssetPickerConfig( pickerConfig: AssetPickerConfig(
maxAssets: maxAssets, maxAssets: maxAssets,
requestType: RequestType.video, requestType: _requestType(assetType),
), ),
); );
if (assets == null || assets.isEmpty) { if (assets == null || assets.isEmpty) {
@@ -39,10 +62,12 @@ class VideoBatchUploadPicker {
tasks.add( tasks.add(
VideoBatchUploadTask( VideoBatchUploadTask(
id: '${asset.id}_${DateTime.now().microsecondsSinceEpoch}', id: '${asset.id}_${DateTime.now().microsecondsSinceEpoch}',
assetType: assetType,
file: file, file: file,
fileName: _normalizeFileName(asset.title, file.path), fileName: _normalizeFileName(asset.title, file.path, assetType),
fileSize: fileSize, fileSize: fileSize,
duration: asset.duration, duration:
assetType == VideoBatchUploadAssetType.video ? asset.duration : 0,
thumbnail: thumbnail, thumbnail: thumbnail,
), ),
); );
@@ -50,13 +75,26 @@ class VideoBatchUploadPicker {
return tasks; 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(); final String title = (assetTitle ?? '').trim();
if (title.isNotEmpty) { if (title.isNotEmpty) {
return title; return title;
} }
final List<String> segments = path.split(Platform.pathSeparator); final List<String> segments = path.split(Platform.pathSeparator);
final String fileName = segments.isEmpty ? '' : segments.last.trim(); final String fileName = segments.isEmpty ? '' : segments.last.trim();
return fileName.isEmpty ? 'video.mp4' : fileName; return fileName.isEmpty ? assetType.defaultFileName : fileName;
} }
} }
@@ -14,6 +14,49 @@ typedef VideoBatchUploadSaveTask = Future<bool> Function(
VideoBatchUploadTask task, 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 { enum VideoBatchUploadStatus {
waiting, waiting,
uploading, uploading,
@@ -45,6 +88,7 @@ extension VideoBatchUploadStatusText on VideoBatchUploadStatus {
class VideoBatchUploadTask { class VideoBatchUploadTask {
VideoBatchUploadTask({ VideoBatchUploadTask({
required this.id, required this.id,
this.assetType = VideoBatchUploadAssetType.video,
required this.file, required this.file,
required this.fileName, required this.fileName,
required this.fileSize, required this.fileSize,
@@ -53,6 +97,7 @@ class VideoBatchUploadTask {
}); });
final String id; final String id;
final VideoBatchUploadAssetType assetType;
final File file; final File file;
final String fileName; final String fileName;
final int fileSize; final int fileSize;
@@ -120,4 +165,8 @@ class VideoBatchUploadTask {
Map<String, dynamic> toLibraryVideoPayload() { Map<String, dynamic> toLibraryVideoPayload() {
return toVideoPayload(); return toVideoPayload();
} }
String toLibraryImageURL() {
return uploadUrl;
}
} }
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'video_batch_upload_task.dart';
class VideoBatchUploadBackButton extends StatelessWidget { class VideoBatchUploadBackButton extends StatelessWidget {
const VideoBatchUploadBackButton({ const VideoBatchUploadBackButton({
super.key, super.key,
@@ -28,11 +30,13 @@ class VideoBatchUploadIconButton extends StatelessWidget {
const VideoBatchUploadIconButton({ const VideoBatchUploadIconButton({
super.key, super.key,
required this.onTap, required this.onTap,
this.assetType = VideoBatchUploadAssetType.video,
this.iconSize, this.iconSize,
this.rightPadding, this.rightPadding,
}); });
final VoidCallback onTap; final VoidCallback onTap;
final VideoBatchUploadAssetType assetType;
final double? iconSize; final double? iconSize;
final double? rightPadding; final double? rightPadding;
@@ -43,7 +47,9 @@ class VideoBatchUploadIconButton extends StatelessWidget {
child: Padding( child: Padding(
padding: EdgeInsets.only(right: rightPadding ?? 30.w), padding: EdgeInsets.only(right: rightPadding ?? 30.w),
child: Icon( child: Icon(
Icons.video_call_outlined, assetType == VideoBatchUploadAssetType.video
? Icons.video_call_outlined
: Icons.add_photo_alternate_outlined,
size: iconSize ?? 50.sp, size: iconSize ?? 50.sp,
color: const Color(0xFF1D1D21), color: const Color(0xFF1D1D21),
), ),
@@ -14,6 +14,7 @@ class VideoBatchUploader {
required BuildContext? Function() contextProvider, required BuildContext? Function() contextProvider,
required VideoBatchUploadUploadTask uploadTask, required VideoBatchUploadUploadTask uploadTask,
required VideoBatchUploadSaveTask saveTask, required VideoBatchUploadSaveTask saveTask,
VideoBatchUploadAssetType assetType = VideoBatchUploadAssetType.video,
VoidCallback? onChanged, VoidCallback? onChanged,
VideoBatchUploadCallback? onCompleted, VideoBatchUploadCallback? onCompleted,
int? maxAssets, int? maxAssets,
@@ -25,6 +26,7 @@ class VideoBatchUploader {
uploadTask: uploadTask, uploadTask: uploadTask,
saveTask: saveTask, saveTask: saveTask,
onChanged: _handleChanged, onChanged: _handleChanged,
assetType: assetType,
onCompleted: onCompleted, onCompleted: onCompleted,
maxAssets: maxAssets ?? VideoBatchUploadConfig.maxAssets, maxAssets: maxAssets ?? VideoBatchUploadConfig.maxAssets,
maxConcurrent: maxConcurrent ?? VideoBatchUploadConfig.maxConcurrent, maxConcurrent: maxConcurrent ?? VideoBatchUploadConfig.maxConcurrent,