feat: 单选多选

This commit is contained in:
jinyaqiu 2025-08-21 11:33:25 +08:00
parent 06f7c1e367
commit d27f665009
2 changed files with 52 additions and 18 deletions

View File

@ -56,23 +56,39 @@ struct MediaPicker: UIViewControllerRepresentable {
let videoSelectionLimit: Int
let onDismiss: (() -> Void)?
let allowedMediaTypes: MediaTypeFilter
let selectionMode: SelectionMode
///
enum SelectionMode {
case single //
case multiple //
var selectionLimit: Int {
switch self {
case .single: return 1
case .multiple: return 0 // 0 imageSelectionLimit videoSelectionLimit
}
}
}
init(selectedMedia: Binding<[MediaType]>,
imageSelectionLimit: Int = 10,
videoSelectionLimit: Int = 10,
allowedMediaTypes: MediaTypeFilter = .all,
selectionMode: SelectionMode = .multiple,
onDismiss: (() -> Void)? = nil) {
self._selectedMedia = selectedMedia
self.imageSelectionLimit = imageSelectionLimit
self.videoSelectionLimit = videoSelectionLimit
self.allowedMediaTypes = allowedMediaTypes
self.selectionMode = selectionMode
self.onDismiss = onDismiss
}
func makeUIViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.filter = allowedMediaTypes.pickerFilter
configuration.selectionLimit = 0 // 0
configuration.selectionLimit = selectionMode.selectionLimit
configuration.preferredAssetRepresentationMode = .current
let picker = PHPickerViewController(configuration: configuration)
@ -105,11 +121,14 @@ struct MediaPicker: UIViewControllerRepresentable {
return
}
//
var processedMedia = parent.selectionMode == .single ? [] : parent.selectedMedia
//
var currentImageCount = 0
var currentVideoCount = 0
for media in parent.selectedMedia {
for media in processedMedia {
switch media {
case .image: currentImageCount += 1
case .video: currentVideoCount += 1
@ -123,11 +142,9 @@ struct MediaPicker: UIViewControllerRepresentable {
for result in results {
let itemProvider = result.itemProvider
if itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
//
guard parent.allowedMediaTypes != .videosOnly else { continue }
newImages += 1
} else if itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
//
guard parent.allowedMediaTypes != .imagesOnly else { continue }
newVideos += 1
}
@ -166,49 +183,49 @@ struct MediaPicker: UIViewControllerRepresentable {
}
//
processSelectedMedia(results: results, picker: picker)
processSelectedMedia(results: results, picker: picker, processedMedia: &processedMedia)
}
private func processSelectedMedia(results: [PHPickerResult], picker: PHPickerViewController) {
var processedMedia = parent.selectedMedia
private func processSelectedMedia(results: [PHPickerResult],
picker: PHPickerViewController,
processedMedia: inout [MediaType]) {
let group = DispatchGroup()
let mediaCollector = MediaCollector()
for result in results {
let itemProvider = result.itemProvider
if itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
//
guard parent.allowedMediaTypes != .videosOnly else { continue }
group.enter()
processImage(itemProvider: itemProvider) { media in
if let media = media {
DispatchQueue.main.async {
processedMedia.append(media)
}
mediaCollector.add(media: media)
}
group.leave()
}
} else if itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
//
guard parent.allowedMediaTypes != .imagesOnly else { continue }
group.enter()
processVideo(itemProvider: itemProvider) { media in
if let media = media {
DispatchQueue.main.async {
processedMedia.append(media)
}
mediaCollector.add(media: media)
}
group.leave()
}
}
}
// Create a local copy of the parent reference
let parent = self.parent
group.notify(queue: .main) {
self.parent.selectedMedia = processedMedia
let finalMedia = mediaCollector.mediaItems
parent.selectedMedia = finalMedia
picker.dismiss(animated: true) {
self.parent.onDismiss?()
parent.onDismiss?()
}
}
}
@ -268,3 +285,19 @@ struct MediaPicker: UIViewControllerRepresentable {
}
}
}
// Helper class to collect media items in a thread-safe way
private class MediaCollector {
private let queue = DispatchQueue(label: "com.example.MediaCollector", attributes: .concurrent)
private var _mediaItems: [MediaType] = []
var mediaItems: [MediaType] {
queue.sync { _mediaItems }
}
func add(media: MediaType) {
queue.async(flags: .barrier) { [weak self] in
self?._mediaItems.append(media)
}
}
}

View File

@ -27,7 +27,8 @@ struct MediaUploadDemo: View {
selectedMedia: $uploadManager.selectedMedia,
imageSelectionLimit: 1,
videoSelectionLimit: 0,
allowedMediaTypes: .imagesOnly,
allowedMediaTypes: .imagesOnly, // This needs to come before selectionMode
selectionMode: .single, // This was moved after allowedMediaTypes
onDismiss: {
showMediaPicker = false
//