mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
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:
+41
-8
@@ -5,6 +5,7 @@
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Compound
|
||||
import GameController
|
||||
import QuickLook
|
||||
@@ -16,6 +17,7 @@ struct MediaUploadPreviewScreen: View {
|
||||
@Bindable var context: MediaUploadPreviewScreenViewModel.Context
|
||||
|
||||
@State private var captionWarningFrame: CGRect = .zero
|
||||
@State private var currentIndex = 0
|
||||
@FocusState private var isComposerFocussed
|
||||
|
||||
private var title: String { ProcessInfo.processInfo.isiOSAppOnMac ? context.viewState.title ?? "" : "" }
|
||||
@@ -23,8 +25,15 @@ struct MediaUploadPreviewScreen: View {
|
||||
|
||||
var body: some View {
|
||||
mainContent
|
||||
.id(context.viewState.url)
|
||||
.id(context.viewState.mediaURLs)
|
||||
.ignoresSafeArea(edges: [.horizontal])
|
||||
.safeAreaInset(edge: .top) {
|
||||
if context.viewState.mediaURLs.count > 1 {
|
||||
Text("\(currentIndex + 1) / \(context.viewState.mediaURLs.count)")
|
||||
.font(.compound.bodySM)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
}
|
||||
}
|
||||
.safeAreaInset(edge: .bottom, spacing: 0) {
|
||||
composer
|
||||
.padding(.horizontal, 12)
|
||||
@@ -50,8 +59,9 @@ struct MediaUploadPreviewScreen: View {
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
} else {
|
||||
PreviewView(fileURL: context.viewState.url,
|
||||
title: context.viewState.title)
|
||||
PreviewView(mediaURLs: context.viewState.mediaURLs,
|
||||
title: context.viewState.title,
|
||||
currentIndex: $currentIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,11 +164,12 @@ struct MediaUploadPreviewScreen: View {
|
||||
}
|
||||
|
||||
private struct PreviewView: UIViewControllerRepresentable {
|
||||
let fileURL: URL
|
||||
let mediaURLs: [URL]
|
||||
let title: String?
|
||||
@Binding var currentIndex: Int
|
||||
|
||||
func makeUIViewController(context: Context) -> UIViewController {
|
||||
let previewController = PreviewViewController()
|
||||
let previewController = PreviewViewController(currentIndex: $currentIndex)
|
||||
previewController.dataSource = context.coordinator
|
||||
previewController.delegate = context.coordinator
|
||||
|
||||
@@ -185,11 +196,11 @@ private struct PreviewView: UIViewControllerRepresentable {
|
||||
// MARK: - QLPreviewControllerDataSource
|
||||
|
||||
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
|
||||
1
|
||||
view.mediaURLs.count
|
||||
}
|
||||
|
||||
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
|
||||
PreviewItem(previewItemURL: view.fileURL, previewItemTitle: view.title)
|
||||
PreviewItem(previewItemURL: view.mediaURLs[index], previewItemTitle: view.title)
|
||||
}
|
||||
|
||||
// MARK: - QLPreviewControllerDelegate
|
||||
@@ -211,6 +222,28 @@ private class PreviewItem: NSObject, QLPreviewItem {
|
||||
}
|
||||
|
||||
private class PreviewViewController: QLPreviewController {
|
||||
private var cancellables: Set<AnyCancellable> = []
|
||||
|
||||
init(currentIndex: Binding<Int>) {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
// Observation of currentPreviewItem doesn't work, so use the index instead.
|
||||
publisher(for: \.currentPreviewItemIndex)
|
||||
.sink { index in
|
||||
DispatchQueue.main.async {
|
||||
if index != Int.max { // Because reasons
|
||||
currentIndex.wrappedValue = index
|
||||
}
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
override func viewWillLayoutSubviews() {
|
||||
super.viewWillLayoutSubviews()
|
||||
|
||||
@@ -228,7 +261,7 @@ struct MediaUploadPreviewScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let snapshotURL = URL.picturesDirectory
|
||||
static let testURL = Bundle.main.url(forResource: "AppIcon60x60@2x", withExtension: "png")
|
||||
|
||||
static let viewModel = MediaUploadPreviewScreenViewModel(url: snapshotURL,
|
||||
static let viewModel = MediaUploadPreviewScreenViewModel(mediaURLs: [snapshotURL],
|
||||
title: "App Icon.png",
|
||||
isRoomEncrypted: true,
|
||||
shouldShowCaptionWarning: true,
|
||||
|
||||
Reference in New Issue
Block a user