diff --git a/ElementX/Sources/Screens/MediaPickerScreen/MediaPickerScreenCoordinator.swift b/ElementX/Sources/Screens/MediaPickerScreen/MediaPickerScreenCoordinator.swift index 2a357f0a5..6eee6a8cf 100644 --- a/ElementX/Sources/Screens/MediaPickerScreen/MediaPickerScreenCoordinator.swift +++ b/ElementX/Sources/Screens/MediaPickerScreen/MediaPickerScreenCoordinator.swift @@ -20,9 +20,21 @@ enum MediaPickerScreenSource: Hashable { case documents(types: [UTType] = [.data]) } -enum MediaPickerScreenSelectionType { +enum MediaPickerScreenSelectionType: Hashable { case single - case multiple + /// Multiple items, up to the given limit. + case multiple(limit: Int) + + /// The number of attachments a gallery may contain, as recommended by + /// [MSC4274](https://github.com/matrix-org/matrix-spec-proposals/pull/4274). + static let galleryLimit = 60 + /// The number of items to allow when each is sent as an individual message. + static let individualUploadLimit = 10 + + /// Multiple items, capped for a gallery when they're sent as one, or for individual uploads when not. + static func multiple(galleryEnabled: Bool) -> Self { + .multiple(limit: galleryEnabled ? galleryLimit : individualUploadLimit) + } } enum MediaPickerScreenCoordinatorAction { diff --git a/ElementX/Sources/Screens/MediaPickerScreen/PhotoLibraryPicker.swift b/ElementX/Sources/Screens/MediaPickerScreen/PhotoLibraryPicker.swift index 96e32afd1..d414bd7a9 100644 --- a/ElementX/Sources/Screens/MediaPickerScreen/PhotoLibraryPicker.swift +++ b/ElementX/Sources/Screens/MediaPickerScreen/PhotoLibraryPicker.swift @@ -39,8 +39,8 @@ struct PhotoLibraryPicker: UIViewControllerRepresentable { configuration.selectionLimit = switch selectionType { case .single: 1 - case .multiple: - 10 + case .multiple(let limit): + limit } let pickerViewController = PHPickerViewController(configuration: configuration) diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift index 1eeaa45bd..2ad2cee5c 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift @@ -57,6 +57,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol { private var roomViewModel: RoomScreenViewModelProtocol private var timelineViewModel: TimelineViewModelProtocol private var composerViewModel: ComposerToolbarViewModelProtocol + private let appSettings: AppSettings private var cancellables = Set() @@ -66,6 +67,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol { } init(parameters: RoomScreenCoordinatorParameters) { + appSettings = parameters.appSettings + var selectedPinnedEventID: String? if let focussedEvent = parameters.focussedEvent { selectedPinnedEventID = focussedEvent.shouldSetPin ? focussedEvent.eventID : nil @@ -122,13 +125,13 @@ final class RoomScreenCoordinator: CoordinatorProtocol { case .displayReportContent(let itemID, let senderID): actionsSubject.send(.presentReportContent(itemID: itemID, senderID: senderID)) case .displayCameraPicker: - actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .camera, selectionType: .multiple), + actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .camera, selectionType: .multiple(galleryEnabled: appSettings.galleryEnabled)), caption: composerViewModel.context.plainComposerText)) case .displayMediaPicker: - actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .photoLibrary, selectionType: .multiple), + actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .photoLibrary, selectionType: .multiple(galleryEnabled: appSettings.galleryEnabled)), caption: composerViewModel.context.plainComposerText)) case .displayDocumentPicker: - actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .documents(), selectionType: .multiple), + actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .documents(), selectionType: .multiple(galleryEnabled: appSettings.galleryEnabled)), caption: composerViewModel.context.plainComposerText)) case .displayMediaPreview(let mediaPreviewViewModel): roomViewModel.displayMediaPreview(mediaPreviewViewModel) diff --git a/ElementX/Sources/Screens/ThreadTimelineScreen/ThreadTimelineScreenCoordinator.swift b/ElementX/Sources/Screens/ThreadTimelineScreen/ThreadTimelineScreenCoordinator.swift index b3b256461..4423be4d7 100644 --- a/ElementX/Sources/Screens/ThreadTimelineScreen/ThreadTimelineScreenCoordinator.swift +++ b/ElementX/Sources/Screens/ThreadTimelineScreen/ThreadTimelineScreenCoordinator.swift @@ -46,6 +46,7 @@ final class ThreadTimelineScreenCoordinator: CoordinatorProtocol { private let viewModel: ThreadTimelineScreenViewModelProtocol private let timelineViewModel: TimelineViewModelProtocol private var composerViewModel: ComposerToolbarViewModelProtocol + private let appSettings: AppSettings private var cancellables = Set() @@ -55,6 +56,8 @@ final class ThreadTimelineScreenCoordinator: CoordinatorProtocol { } init(parameters: ThreadTimelineScreenCoordinatorParameters) { + appSettings = parameters.appSettings + viewModel = ThreadTimelineScreenViewModel(roomProxy: parameters.roomProxy, userSession: parameters.userSession) timelineViewModel = TimelineViewModel(roomProxy: parameters.roomProxy, @@ -107,13 +110,13 @@ final class ThreadTimelineScreenCoordinator: CoordinatorProtocol { case .displayReportContent(let itemID, let senderID): actionsSubject.send(.presentReportContent(itemID: itemID, senderID: senderID)) case .displayCameraPicker: - actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .camera, selectionType: .multiple), + actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .camera, selectionType: .multiple(galleryEnabled: appSettings.galleryEnabled)), caption: composerViewModel.context.plainComposerText)) case .displayMediaPicker: - actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .photoLibrary, selectionType: .multiple), + actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .photoLibrary, selectionType: .multiple(galleryEnabled: appSettings.galleryEnabled)), caption: composerViewModel.context.plainComposerText)) case .displayDocumentPicker: - actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .documents(), selectionType: .multiple), + actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .documents(), selectionType: .multiple(galleryEnabled: appSettings.galleryEnabled)), caption: composerViewModel.context.plainComposerText)) case .displayMediaPreview(let mediaPreviewViewModel): viewModel.displayMediaPreview(mediaPreviewViewModel) diff --git a/ShareExtension/SupportingFiles/Info.plist b/ShareExtension/SupportingFiles/Info.plist index 6af769e45..50d2dbbe2 100644 --- a/ShareExtension/SupportingFiles/Info.plist +++ b/ShareExtension/SupportingFiles/Info.plist @@ -31,11 +31,11 @@ NSExtensionActivationRule NSExtensionActivationSupportsFileWithMaxCount - 10 + 60 NSExtensionActivationSupportsImageWithMaxCount - 10 + 60 NSExtensionActivationSupportsMovieWithMaxCount - 10 + 60 NSExtensionActivationSupportsText NSExtensionActivationSupportsWebURLWithMaxCount