Multi file uploads (#4358)

* Allow MediaPickerScreen users to select the media selection mode (single or multiple)

* Fix cancellation

* Add support for multiple media URLs on the MediaUploadPreviewScreen.

* Support processing more URLs on the `MediaUploadingPreprocessor` and sending more on the `MediaUploadPreviewScreen`

* Add feature flag for `multipleAttachmentUploadEnabled`

* Add a label showing the current preview item index in the MediaUploadPreviewScreen

* Add support for dragging and dropping or pasting multiple items at the same time.

* Support sharing more than one file through the share extension.

* Limit the number of items that can be shared in one go to 5.

* Fix unit tests

* Fix incorrect fatal error when dealing with single selection media pickers.

* Document the `multipleAttachmentUploadEnabled` usage in the context of the MediaPicker.

* Use a task group for processing selected media in the photo library picker.

* Use a task group for processing multiple selected media in the MediaUploadingPreprocessor

* Switch the maximum number of items that can be shared to 10.

* Allow multiple items to be pasted at the same time.
This commit is contained in:
Stefan Ceriu
2025-07-30 15:44:05 +03:00
committed by GitHub
parent 01033cf53e
commit df335bd2b1
39 changed files with 466 additions and 266 deletions
@@ -63,23 +63,32 @@ class ShareExtensionViewController: UIViewController {
// MARK: - Private
private func prepareSharePayload() async -> ShareExtensionPayload? {
guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem,
let itemProvider = extensionItem.attachments?.first else {
guard let extensionContext,
let extensionItem = extensionContext.inputItems.first as? NSExtensionItem,
let itemProviders = extensionItem.attachments else {
return nil
}
let roomID = (extensionContext?.intent as? INSendMessageIntent)?.conversationIdentifier
let roomID = (extensionContext.intent as? INSendMessageIntent)?.conversationIdentifier
if let fileURL = await itemProvider.storeData(withinAppGroupContainer: true) {
return .mediaFile(roomID: roomID, mediaFile: .init(url: fileURL, suggestedName: fileURL.lastPathComponent))
} else if let url = await itemProvider.loadTransferable(type: URL.self) {
return .text(roomID: roomID, text: url.absoluteString)
} else if let string = await itemProvider.loadString() {
return .text(roomID: roomID, text: string)
} else {
MXLog.error("Failed loading NSItemProvider data: \(itemProvider)")
return nil
var mediaFiles = [ShareExtensionMediaFile]()
for itemProvider in itemProviders {
if let fileURL = await itemProvider.storeData(withinAppGroupContainer: true) {
mediaFiles.append(.init(url: fileURL, suggestedName: fileURL.lastPathComponent))
} else if let url = await itemProvider.loadTransferable(type: URL.self) {
return .text(roomID: roomID, text: url.absoluteString)
} else if let string = await itemProvider.loadString() {
return .text(roomID: roomID, text: string)
} else {
MXLog.error("Failed loading NSItemProvider data: \(itemProvider)")
}
}
if !mediaFiles.isEmpty {
return .mediaFiles(roomID: roomID, mediaFiles: mediaFiles)
}
return nil
}
private func openMainApp(payload: ShareExtensionPayload) async {
+4 -4
View File
@@ -31,15 +31,15 @@
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
<integer>1</integer>
<integer>10</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>1</integer>
<integer>10</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>1</integer>
<integer>10</integer>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<integer>10</integer>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>
+4 -4
View File
@@ -53,11 +53,11 @@ targets:
NSExtensionAttributes:
IntentsSupported: [INSendMessageIntent]
NSExtensionActivationRule:
NSExtensionActivationSupportsFileWithMaxCount: 1
NSExtensionActivationSupportsImageWithMaxCount: 1
NSExtensionActivationSupportsMovieWithMaxCount: 1
NSExtensionActivationSupportsFileWithMaxCount: 10
NSExtensionActivationSupportsImageWithMaxCount: 10
NSExtensionActivationSupportsMovieWithMaxCount: 10
NSExtensionActivationSupportsText: true
NSExtensionActivationSupportsWebURLWithMaxCount: 1
NSExtensionActivationSupportsWebURLWithMaxCount: 10
entitlements:
path: ShareExtension.entitlements