From e5bee3fac5867898374b38859aeda7123a049964 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 17 Nov 2023 10:14:34 -0500 Subject: [PATCH 1/9] Integrate SiteMediaPickerViewController in Aztec --- .../AztecPostViewController.swift | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift index f19cd09fbbc3..6483b2057459 100644 --- a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift +++ b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift @@ -1586,13 +1586,13 @@ extension AztecPostViewController { switch mediaIdentifier { case .deviceLibrary: trackFormatBarAnalytics(stat: .editorMediaPickerTappedDevicePhotos) - presentMediaPickerFullScreen(animated: true, dataSourceType: .device) + presentDeviceMediaPickerFullScreen(animated: true) case .camera: trackFormatBarAnalytics(stat: .editorMediaPickerTappedCamera) mediaPickerInputViewController?.showCapture() case .mediaLibrary: trackFormatBarAnalytics(stat: .editorMediaPickerTappedMediaLibrary) - presentMediaPickerFullScreen(animated: true, dataSourceType: .mediaLibrary) + presentSiteMediaPicker() case .otherApplications: trackFormatBarAnalytics(stat: .editorMediaPickerTappedOtherApps) showMore(from: barItem) @@ -1833,7 +1833,7 @@ extension AztecPostViewController { /// - Parameter sender: the button that was pressed. /// @objc func mediaAddShowFullScreen(_ sender: UIBarButtonItem) { - presentMediaPickerFullScreen(animated: true) + presentDeviceMediaPickerFullScreen(animated: true) restoreInputAssistantItems() } @@ -1891,8 +1891,7 @@ extension AztecPostViewController { } } - fileprivate func presentMediaPickerFullScreen(animated: Bool, dataSourceType: MediaPickerDataSourceType = .device) { - + fileprivate func presentDeviceMediaPickerFullScreen(animated: Bool) { let options = WPMediaPickerOptions() options.showMostRecentFirst = true options.filter = [.all] @@ -1902,18 +1901,7 @@ extension AztecPostViewController { options.preferredStatusBarStyle = WPStyleGuide.preferredStatusBarStyle let picker = WPNavigationMediaPickerViewController() - - switch dataSourceType { - case .device: - picker.dataSource = devicePhotoLibraryDataSource - case .mediaLibrary: - picker.startOnGroupSelector = false - picker.showGroupSelector = false - picker.dataSource = mediaLibraryDataSource - registerChangeObserver(forPicker: picker.mediaPicker) - @unknown default: - fatalError() - } + picker.dataSource = devicePhotoLibraryDataSource picker.selectionActionTitle = Constants.mediaPickerInsertText picker.mediaPicker.options = options @@ -1927,6 +1915,11 @@ extension AztecPostViewController { present(picker, animated: true) } + private func presentSiteMediaPicker() { + MediaPickerMenu(viewController: self, isMultipleSelectionEnabled: true) + .showSiteMediaPicker(blog: post.blog, delegate: self) + } + private func toggleMediaPicker(fromButton button: UIButton) { if mediaPickerInputViewController != nil { closeMediaPickerInputViewController() @@ -3210,6 +3203,16 @@ extension AztecPostViewController: TextViewAttachmentDelegate { } } +extension AztecPostViewController: SiteMediaPickerViewControllerDelegate { + func siteMediaPickerViewController(_ viewController: SiteMediaPickerViewController, didFinishWithSelection selection: [Media]) { + dismiss(animated: true) + mediaSelectionMethod = .fullScreenPicker + for media in selection { + insertSiteMediaLibrary(media: media) + } + } +} + // MARK: - MediaPickerViewController Delegate Conformance // From 9c4077913c030b553b0257a5b14a1c45a0e4aa9b Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 17 Nov 2023 10:28:52 -0500 Subject: [PATCH 2/9] Integrate PHPickerViewController in Aztec (button press) --- .../AztecPostViewController.swift | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift index 6483b2057459..64e9be3835fb 100644 --- a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift +++ b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift @@ -13,6 +13,8 @@ import MobileCoreServices import AutomatticTracks import MediaEditor import UniformTypeIdentifiers +import Photos +import PhotosUI // MARK: - Aztec's Native Editor! // @@ -377,10 +379,6 @@ class AztecPostViewController: UIViewController, PostEditor { return dataSource }() - /// Device Photo Library Data Source - /// - fileprivate lazy var devicePhotoLibraryDataSource = WPPHAssetDataSource() - fileprivate let mediaCoordinator = MediaCoordinator.shared /// Media Progress View @@ -1586,7 +1584,7 @@ extension AztecPostViewController { switch mediaIdentifier { case .deviceLibrary: trackFormatBarAnalytics(stat: .editorMediaPickerTappedDevicePhotos) - presentDeviceMediaPickerFullScreen(animated: true) + presentDeviceMediaPicker(animated: true) case .camera: trackFormatBarAnalytics(stat: .editorMediaPickerTappedCamera) mediaPickerInputViewController?.showCapture() @@ -1833,7 +1831,7 @@ extension AztecPostViewController { /// - Parameter sender: the button that was pressed. /// @objc func mediaAddShowFullScreen(_ sender: UIBarButtonItem) { - presentDeviceMediaPickerFullScreen(animated: true) + presentDeviceMediaPicker(animated: true) restoreInputAssistantItems() } @@ -1891,28 +1889,9 @@ extension AztecPostViewController { } } - fileprivate func presentDeviceMediaPickerFullScreen(animated: Bool) { - let options = WPMediaPickerOptions() - options.showMostRecentFirst = true - options.filter = [.all] - options.allowCaptureOfMedia = false - options.showSearchBar = true - options.badgedUTTypes = [UTType.gif.identifier] - options.preferredStatusBarStyle = WPStyleGuide.preferredStatusBarStyle - - let picker = WPNavigationMediaPickerViewController() - picker.dataSource = devicePhotoLibraryDataSource - - picker.selectionActionTitle = Constants.mediaPickerInsertText - picker.mediaPicker.options = options - picker.delegate = self - picker.previewActionTitle = NSLocalizedString("Edit %@", comment: "Button that displays the media editor to the user") - picker.modalPresentationStyle = .currentContext - if let previousPicker = mediaPickerInputViewController?.mediaPicker { - picker.mediaPicker.selectedAssets = previousPicker.selectedAssets - } - - present(picker, animated: true) + fileprivate func presentDeviceMediaPicker(animated: Bool) { + MediaPickerMenu(viewController: self, isMultipleSelectionEnabled: true) + .showPhotosPicker(delegate: self) } private func presentSiteMediaPicker() { @@ -3203,6 +3182,8 @@ extension AztecPostViewController: TextViewAttachmentDelegate { } } +// MARK: - MediaPickerViewController (SiteMediaPickerViewControllerDelegate) + extension AztecPostViewController: SiteMediaPickerViewControllerDelegate { func siteMediaPickerViewController(_ viewController: SiteMediaPickerViewController, didFinishWithSelection selection: [Media]) { dismiss(animated: true) @@ -3213,6 +3194,16 @@ extension AztecPostViewController: SiteMediaPickerViewControllerDelegate { } } +// MARK: - MediaPickerViewController (PHPickerViewControllerDelegate) + +extension AztecPostViewController: PHPickerViewControllerDelegate { + func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { + dismiss(animated: true) + for result in results { + insert(exportableAsset: result.itemProvider, source: .deviceLibrary) + } + } +} // MARK: - MediaPickerViewController Delegate Conformance // From 0f8d10305b8bbac1fa973a70ff264b07fa6233e6 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 17 Nov 2023 12:39:08 -0500 Subject: [PATCH 3/9] Show camera directly without WPMediaPicker --- .../AztecPostViewController.swift | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift index 64e9be3835fb..3cf479fd635e 100644 --- a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift +++ b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift @@ -1587,7 +1587,7 @@ extension AztecPostViewController { presentDeviceMediaPicker(animated: true) case .camera: trackFormatBarAnalytics(stat: .editorMediaPickerTappedCamera) - mediaPickerInputViewController?.showCapture() + MediaPickerMenu(viewController: self).showCamera(delegate: self) case .mediaLibrary: trackFormatBarAnalytics(stat: .editorMediaPickerTappedMediaLibrary) presentSiteMediaPicker() @@ -3194,6 +3194,37 @@ extension AztecPostViewController: SiteMediaPickerViewControllerDelegate { } } +// MARK: - AztecPostViewController (ImagePickerControllerDelegate) + +extension AztecPostViewController: ImagePickerControllerDelegate { + func imagePicker(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { + dismiss(animated: true) { + guard let mediaType = info[.mediaType] as? String else { + return + } + switch mediaType { + case UTType.image.identifier: + if let image = info[.originalImage] as? UIImage { + self.insertImage(image: image, source: .camera) + } + case UTType.movie.identifier: + guard let videoURL = info[.mediaURL] as? URL else { + return + } + guard self.post.blog.canUploadVideo(from: videoURL) else { + self.presentVideoLimitExceededAfterCapture(on: self) + return + } + self.insert(exportableAsset: videoURL as NSURL, source: .camera) + default: + break + } + } + } +} + +extension AztecPostViewController: VideoLimitsAlertPresenter {} + // MARK: - MediaPickerViewController (PHPickerViewControllerDelegate) extension AztecPostViewController: PHPickerViewControllerDelegate { From fe1e0e322decb12907b2a255d67bf80003919364 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 17 Nov 2023 15:22:39 -0500 Subject: [PATCH 4/9] Use PHPicker as an embedded media picker --- .../AztecPostViewController.swift | 153 ++++++------------ 1 file changed, 48 insertions(+), 105 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift index 3cf479fd635e..27e8b6a0152a 100644 --- a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift +++ b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift @@ -440,7 +440,8 @@ class AztecPostViewController: UIViewController, PostEditor { UIAccessibility.isVoiceOverRunning } - fileprivate var mediaPickerInputViewController: WPInputMediaPickerViewController? + private var mediaPickerInputViewController: PHPickerViewController? + private var selectedPickerResults: [PHPickerResult] = [] fileprivate var originalLeadingBarButtonGroup = [UIBarButtonItemGroup]() @@ -452,7 +453,6 @@ class AztecPostViewController: UIViewController, PostEditor { fileprivate var mediaLibraryChangeObserverKey: NSObjectProtocol? = nil - /// Presents whatever happens when FormatBar's more button is selected /// fileprivate lazy var moreCoordinator: AztecMediaPickingCoordinator = { @@ -1603,11 +1603,7 @@ extension AztecPostViewController { } func handleFormatBarTrailingItem(_ item: UIButton) { - guard let mediaPicker = mediaPickerInputViewController else { - return - } - - mediaPickerController(mediaPicker.mediaPicker, didFinishPicking: mediaPicker.mediaPicker.selectedAssets) + insertPickerResults() } @objc func toggleBold() { @@ -1801,68 +1797,7 @@ extension AztecPostViewController { richTextView.removeLink(inRange: range) } - private var mediaInputToolbar: UIToolbar { - let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: Constants.toolbarHeight)) - toolbar.barTintColor = WPStyleGuide.aztecFormatBarBackgroundColor - toolbar.tintColor = WPStyleGuide.aztecFormatBarActiveColor - let gridButton = UIBarButtonItem(image: .gridicon(.grid), style: .plain, target: self, action: #selector(mediaAddShowFullScreen)) - gridButton.accessibilityLabel = NSLocalizedString("Open full media picker", comment: "Editor button to swich the media picker from quick mode to full picker") - toolbar.items = [ - UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(mediaAddInputCancelled)), - UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil), - gridButton, - UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil), - UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(mediaAddInputDone)) - ] - - for item in toolbar.items! { - item.tintColor = WPStyleGuide.aztecFormatBarActiveColor - item.setTitleTextAttributes([.foregroundColor: WPStyleGuide.aztecFormatBarActiveColor], for: .normal) - } - - return toolbar - - } - - // MARK: - Media Input toolbar button actions - - /// Method to be called when the grid icon is pressed on the media input toolbar. - /// - /// - Parameter sender: the button that was pressed. - /// - @objc func mediaAddShowFullScreen(_ sender: UIBarButtonItem) { - presentDeviceMediaPicker(animated: true) - restoreInputAssistantItems() - } - - /// Method to be called when canceled is pressed. - /// - /// - Parameter sender: the button that was pressed. - @objc func mediaAddInputCancelled(_ sender: UIBarButtonItem) { - - guard let mediaPicker = mediaPickerInputViewController?.mediaPicker else { - return - } - mediaPickerControllerDidCancel(mediaPicker) - restoreInputAssistantItems() - } - - /// Method to be called when done is pressed on the media input toolbar. - /// - /// - Parameter sender: the button that was pressed. - @objc func mediaAddInputDone(_ sender: UIBarButtonItem) { - - guard let mediaPicker = mediaPickerInputViewController?.mediaPicker - else { - return - } - let selectedAssets = mediaPicker.selectedAssets - mediaPickerController(mediaPicker, didFinishPicking: selectedAssets) - restoreInputAssistantItems() - } - func restoreInputAssistantItems() { - richTextView.inputAssistantItem.leadingBarButtonGroups = originalLeadingBarButtonGroup richTextView.inputAssistantItem.trailingBarButtonGroups = originalTrailingBarButtonGroup richTextView.autocorrectionType = .yes @@ -1885,7 +1820,7 @@ extension AztecPostViewController { @IBAction @objc func presentMediaPickerWasPressed() { if let item = formatBar.leadingItem { - presentMediaPicker(fromButton: item, animated: true) + presentEmbeddedMediaPicker(fromButton: item, animated: true) } } @@ -1904,23 +1839,30 @@ extension AztecPostViewController { closeMediaPickerInputViewController() trackFormatBarAnalytics(stat: .editorMediaPickerTappedDismiss) } else { - presentMediaPicker(fromButton: button, animated: true) + presentEmbeddedMediaPicker(fromButton: button, animated: true) } } - private func presentMediaPicker(fromButton button: UIButton, animated: Bool = true) { + private func presentEmbeddedMediaPicker(fromButton button: UIButton, animated: Bool = true) { + guard #available(iOS 17, *) else { return } + trackFormatBarAnalytics(stat: .editorTappedImage) - let options = WPMediaPickerOptions() - options.showMostRecentFirst = true - options.filter = [WPMediaType.image, WPMediaType.video] - options.allowMultipleSelection = true - options.allowCaptureOfMedia = false - options.scrollVertically = true - options.badgedUTTypes = [UTType.gif.identifier] - options.preferredStatusBarStyle = WPStyleGuide.preferredStatusBarStyle + var configuration = PHPickerConfiguration() + configuration.filter = .any(of: [.images, .videos]) + configuration.preferredAssetRepresentationMode = .current + configuration.selectionLimit = 0 + configuration.mode = .compact + configuration.disabledCapabilities = [ + .collectionNavigation, .collectionNavigation, .search, .stagingArea + ] + configuration.edgesWithoutContentMargins = .all + configuration.selection = .continuousAndOrdered + + let picker = PHPickerViewController(configuration: configuration) + picker.delegate = self + picker.zoomOut() - let picker = WPInputMediaPickerViewController(options: options) mediaPickerInputViewController = picker updateToolbar(formatBar, forMode: .media) @@ -1932,10 +1874,6 @@ extension AztecPostViewController { richTextView.autocorrectionType = .no - picker.mediaPicker.viewControllerToUseToPresent = self - picker.dataSource = WPPHAssetDataSource.sharedInstance() - picker.mediaPicker.mediaPickerDelegate = self - if currentKeyboardFrame != .zero { // iOS is not adjusting the media picker's height to match the default keyboard's height when autoresizingMask // is set to UIViewAutoresizingFlexibleHeight (even though the docs claim it should). Need to manually @@ -3056,6 +2994,7 @@ extension AztecPostViewController { guard mediaPickerInputViewController != nil else { return } + selectedPickerResults = [] mediaPickerInputViewController = nil changeRichTextInputView(to: nil) updateToolbar(formatBar, forMode: .text) @@ -3229,10 +3168,25 @@ extension AztecPostViewController: VideoLimitsAlertPresenter {} extension AztecPostViewController: PHPickerViewControllerDelegate { func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { - dismiss(animated: true) - for result in results { + selectedPickerResults = results + + // The delegate is configured to get called continuously + if picker == mediaPickerInputViewController { + updateFormatBarInsertAssetCount() + } else { + dismiss(animated: true) + insertPickerResults() + } + } + + private func insertPickerResults() { + guard !selectedPickerResults.isEmpty else { + return + } + for result in selectedPickerResults { insert(exportableAsset: result.itemProvider, source: .deviceLibrary) } + closeMediaPickerInputViewController() } } @@ -3241,9 +3195,6 @@ extension AztecPostViewController: PHPickerViewControllerDelegate { extension AztecPostViewController: WPMediaPickerViewControllerDelegate { func emptyViewController(forMediaPickerController picker: WPMediaPickerViewController) -> UIViewController? { - if picker != mediaPickerInputViewController?.mediaPicker { - return noResultsView - } return nil } @@ -3267,22 +3218,16 @@ extension AztecPostViewController: WPMediaPickerViewControllerDelegate { } func mediaPickerControllerDidCancel(_ picker: WPMediaPickerViewController) { - if picker != mediaPickerInputViewController?.mediaPicker { - unregisterChangeObserver() - mediaLibraryDataSource.searchCancelled() - dismiss(animated: true) - } + unregisterChangeObserver() + mediaLibraryDataSource.searchCancelled() + dismiss(animated: true) } func mediaPickerController(_ picker: WPMediaPickerViewController, didFinishPicking assets: [WPMediaAsset]) { - if picker != mediaPickerInputViewController?.mediaPicker { - unregisterChangeObserver() - mediaLibraryDataSource.searchCancelled() - dismiss(animated: true) - mediaSelectionMethod = .fullScreenPicker - } else { - mediaSelectionMethod = .inlinePicker - } + unregisterChangeObserver() + mediaLibraryDataSource.searchCancelled() + dismiss(animated: true) + mediaSelectionMethod = .fullScreenPicker closeMediaPickerInputViewController() @@ -3332,9 +3277,7 @@ extension AztecPostViewController: WPMediaPickerViewControllerDelegate { } private func updateFormatBarInsertAssetCount() { - guard let assetCount = mediaPickerInputViewController?.mediaPicker.selectedAssets.count else { - return - } + let assetCount = selectedPickerResults.count if assetCount == 0 { insertToolbarItem.isEnabled = false From 25dd04240be3e427df7913f91af42176f3d93d8c Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 17 Nov 2023 15:37:43 -0500 Subject: [PATCH 5/9] Revert (+1 squashed commit) Squashed commits: [0989edba27] Remove deprecated code --- .../AztecPostViewController.swift | 192 +----------------- 1 file changed, 3 insertions(+), 189 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift index 27e8b6a0152a..d2a104872680 100644 --- a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift +++ b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift @@ -7,7 +7,6 @@ import Gridicons import WordPressShared import MobileCoreServices import WordPressEditor -import WPMediaPicker import AVKit import MobileCoreServices import AutomatticTracks @@ -371,14 +370,6 @@ class AztecPostViewController: UIViewController, PostEditor { /// fileprivate var activeMediaRequests = [ImageDownloaderTask]() - /// Media Library Data Source - /// - lazy var mediaLibraryDataSource: MediaLibraryPickerDataSource = { - let dataSource = MediaLibraryPickerDataSource(post: self.post) - dataSource.ignoreSyncErrors = true - return dataSource - }() - fileprivate let mediaCoordinator = MediaCoordinator.shared /// Media Progress View @@ -447,23 +438,12 @@ class AztecPostViewController: UIViewController, PostEditor { fileprivate var originalTrailingBarButtonGroup = [UIBarButtonItemGroup]() - /// The view to show when media picker has no assets to show. - /// - fileprivate let noResultsView = NoResultsViewController.controller() - - fileprivate var mediaLibraryChangeObserverKey: NSObjectProtocol? = nil - /// Presents whatever happens when FormatBar's more button is selected /// fileprivate lazy var moreCoordinator: AztecMediaPickingCoordinator = { return AztecMediaPickingCoordinator(delegate: self) }() - - /// Helps choosing the correct view controller for previewing a media asset - /// - private var mediaPreviewHelper: MediaPreviewHelper? = nil - private let database: KeyValueDatabase = UserDefaults.standard private enum Key { static let classicDeprecationNoticeHasBeenShown = "kClassicDeprecationNoticeHasBeenShown" @@ -534,7 +514,6 @@ class AztecPostViewController: UIViewController, PostEditor { configureNavigationBar() configureView() configureSubviews() - noResultsView.configureForNoAssets(userCanUploadMedia: false) // UI elements might get their properties reset when the view is effectively loaded. Refresh it all! refreshInterface() @@ -910,44 +889,6 @@ class AztecPostViewController: UIViewController, PostEditor { navigationBarManager.reloadPublishButton() } - fileprivate func updateSearchBar(mediaPicker: WPMediaPickerViewController) { - let isSearching = mediaLibraryDataSource.searchQuery?.count ?? 0 != 0 - let hasAssets = mediaLibraryDataSource.totalAssetCount > 0 - - if isSearching || hasAssets { - mediaPicker.showSearchBar() - if let searchBar = mediaPicker.searchBar { - WPStyleGuide.configureSearchBar(searchBar) - } - } else { - mediaPicker.hideSearchBar() - } - } - - fileprivate func registerChangeObserver(forPicker picker: WPMediaPickerViewController) { - assert(mediaLibraryChangeObserverKey == nil) - mediaLibraryChangeObserverKey = mediaLibraryDataSource.registerChangeObserverBlock({ [weak self] _, _, _, _, _ in - - self?.updateSearchBar(mediaPicker: picker) - - let isNotSearching = self?.mediaLibraryDataSource.searchQuery?.count ?? 0 == 0 - let hasNoAssets = self?.mediaLibraryDataSource.numberOfAssets() == 0 - - if isNotSearching && hasNoAssets { - self?.noResultsView.removeFromView() - self?.noResultsView.configureForNoAssets(userCanUploadMedia: false) - } - }) - } - - fileprivate func unregisterChangeObserver() { - if let mediaLibraryChangeObserverKey = mediaLibraryChangeObserverKey { - mediaLibraryDataSource.unregisterChangeObserver(mediaLibraryChangeObserverKey) - } - mediaLibraryChangeObserverKey = nil - } - - // MARK: - Keyboard Handling override var keyCommands: [UIKeyCommand] { @@ -2361,13 +2302,12 @@ extension AztecPostViewController { attachment?.uploadID = media.uploadID } - /// Sets the badge title of `attachment` to "GIF" if either the media is being imported from Tenor, - /// or if it's a PHAsset with an animated playback style. + /// Sets the badge title of `attachment` to "GIF". private func setGifBadgeIfNecessary(for attachment: MediaAttachment, asset: ExportableAsset, source: MediaSource) { var isGif = source == .tenor - if let asset = asset as? PHAsset, - asset.playbackStyle == .imageAnimated { + if let asset = (asset as? NSItemProvider), + asset.hasItemConformingToTypeIdentifier(UTType.gif.identifier) { isGif = true } @@ -2384,10 +2324,6 @@ extension AztecPostViewController { insert(exportableAsset: image, source: source) } - fileprivate func insertDeviceMedia(phAsset: PHAsset, source: MediaSource = .deviceLibrary) { - insert(exportableAsset: phAsset, source: source) - } - private func insertStockPhotosMedia(_ media: StockPhotosMedia) { insert(exportableAsset: media, source: .stockPhotos) } @@ -3188,93 +3124,6 @@ extension AztecPostViewController: PHPickerViewControllerDelegate { } closeMediaPickerInputViewController() } -} - -// MARK: - MediaPickerViewController Delegate Conformance -// -extension AztecPostViewController: WPMediaPickerViewControllerDelegate { - - func emptyViewController(forMediaPickerController picker: WPMediaPickerViewController) -> UIViewController? { - return nil - } - - func mediaPickerController(_ picker: WPMediaPickerViewController, didUpdateSearchWithAssetCount assetCount: Int) { - noResultsView.removeFromView() - - if (mediaLibraryDataSource.searchQuery?.count ?? 0) > 0 { - noResultsView.configureForNoSearchResult() - } - } - - func mediaPickerControllerWillBeginLoadingData(_ picker: WPMediaPickerViewController) { - updateSearchBar(mediaPicker: picker) - noResultsView.configureForFetching() - } - - func mediaPickerControllerDidEndLoadingData(_ picker: WPMediaPickerViewController) { - updateSearchBar(mediaPicker: picker) - noResultsView.removeFromView() - noResultsView.configureForNoAssets(userCanUploadMedia: false) - } - - func mediaPickerControllerDidCancel(_ picker: WPMediaPickerViewController) { - unregisterChangeObserver() - mediaLibraryDataSource.searchCancelled() - dismiss(animated: true) - } - - func mediaPickerController(_ picker: WPMediaPickerViewController, didFinishPicking assets: [WPMediaAsset]) { - unregisterChangeObserver() - mediaLibraryDataSource.searchCancelled() - dismiss(animated: true) - mediaSelectionMethod = .fullScreenPicker - - closeMediaPickerInputViewController() - - if assets.isEmpty { - return - } - - for asset in assets { - switch asset { - case let phAsset as PHAsset: - insertDeviceMedia(phAsset: phAsset) - case let media as Media: - insertSiteMediaLibrary(media: media) - default: - continue - } - } - } - - - func mediaPickerController(_ picker: WPMediaPickerViewController, selectionChanged assets: [WPMediaAsset]) { - updateFormatBarInsertAssetCount() - } - - func mediaPickerController(_ picker: WPMediaPickerViewController, didSelect asset: WPMediaAsset) { - updateFormatBarInsertAssetCount() - } - - func mediaPickerController(_ picker: WPMediaPickerViewController, didDeselect asset: WPMediaAsset) { - updateFormatBarInsertAssetCount() - } - - func mediaPickerController(_ picker: WPMediaPickerViewController, handleError error: Error) -> Bool { - let alert = WPMediaPickerAlertHelper.buildAlertControllerWithError(error) - present(alert, animated: true) - return true - } - - func mediaPickerController(_ picker: WPMediaPickerViewController, previewViewControllerFor assets: [WPMediaAsset], selectedIndex selected: Int) -> UIViewController? { - if let phAssets = assets as? [PHAsset], phAssets.allSatisfy({ $0.mediaType == .image }) { - edit(fromMediaPicker: picker, assets: phAssets) - return nil - } else { - mediaPreviewHelper = MediaPreviewHelper(assets: assets) - return mediaPreviewHelper?.previewViewController(selectedIndex: selected) - } - } private func updateFormatBarInsertAssetCount() { let assetCount = selectedPickerResults.count @@ -3560,41 +3409,6 @@ extension AztecPostViewController { // MARK: - Media Editing // extension AztecPostViewController { - private func edit(fromMediaPicker picker: WPMediaPickerViewController, assets: [PHAsset]) { - let mediaEditor = WPMediaEditor(assets) - - // When the photo's library is updated (eg.: a new photo is added) - // the actionBar is appearing and conflicting with Media Editor. - // We hide it to prevent that issue - picker.actionBar?.isHidden = true - - mediaEditor.edit(from: picker, - onFinishEditing: { [weak self] images, actions in - images.forEach { mediaEditorImage in - if let image = mediaEditorImage.editedImage { - self?.insertImage(image: image) - } else if let phAsset = mediaEditorImage as? PHAsset { - self?.insertDeviceMedia(phAsset: phAsset) - } - } - - self?.dismissMediaPicker() - }, onCancel: { - // Dismiss the Preview screen in Media Picker - picker.navigationController?.popViewController(animated: false) - - // Show picker actionBar again - picker.actionBar?.isHidden = false - }) - } - - private func dismissMediaPicker() { - unregisterChangeObserver() - mediaLibraryDataSource.searchCancelled() - closeMediaPickerInputViewController() - dismiss(animated: false) - } - private func edit(_ imageAttachment: ImageAttachment) { guard imageAttachment.mediaURL?.isGif == false else { From f9693b4b45b6a7d005e6e8c666e439c936956f78 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 17 Nov 2023 16:05:52 -0500 Subject: [PATCH 6/9] Fix support for earlier iOS versions --- .../AztecPostViewController.swift | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift index d2a104872680..f0a2f273997e 100644 --- a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift +++ b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift @@ -110,6 +110,8 @@ class AztecPostViewController: UIViewController, PostEditor { case expectedSecondaryAction = 1 } + private var toolbarMode: FormatBarMode = .text + /// The editor view. /// fileprivate(set) lazy var editorView: Aztec.EditorView = { @@ -1776,35 +1778,18 @@ extension AztecPostViewController { } private func toggleMediaPicker(fromButton button: UIButton) { - if mediaPickerInputViewController != nil { + switch toolbarMode { + case .media: closeMediaPickerInputViewController() trackFormatBarAnalytics(stat: .editorMediaPickerTappedDismiss) - } else { + case .text: presentEmbeddedMediaPicker(fromButton: button, animated: true) } } private func presentEmbeddedMediaPicker(fromButton button: UIButton, animated: Bool = true) { - guard #available(iOS 17, *) else { return } - trackFormatBarAnalytics(stat: .editorTappedImage) - var configuration = PHPickerConfiguration() - configuration.filter = .any(of: [.images, .videos]) - configuration.preferredAssetRepresentationMode = .current - configuration.selectionLimit = 0 - configuration.mode = .compact - configuration.disabledCapabilities = [ - .collectionNavigation, .collectionNavigation, .search, .stagingArea - ] - configuration.edgesWithoutContentMargins = .all - configuration.selection = .continuousAndOrdered - - let picker = PHPickerViewController(configuration: configuration) - picker.delegate = self - picker.zoomOut() - - mediaPickerInputViewController = picker updateToolbar(formatBar, forMode: .media) originalLeadingBarButtonGroup = richTextView.inputAssistantItem.leadingBarButtonGroups @@ -1815,15 +1800,31 @@ extension AztecPostViewController { richTextView.autocorrectionType = .no - if currentKeyboardFrame != .zero { - // iOS is not adjusting the media picker's height to match the default keyboard's height when autoresizingMask - // is set to UIViewAutoresizingFlexibleHeight (even though the docs claim it should). Need to manually - // set the picker's frame to the current keyboard's frame. - picker.view.autoresizingMask = [] - picker.view.frame = CGRect(x: 0, y: 0, width: currentKeyboardFrame.width, height: mediaKeyboardHeight) - } + if #available(iOS 17, *) { + var configuration = PHPickerConfiguration() + configuration.filter = .any(of: [.images, .videos]) + configuration.preferredAssetRepresentationMode = .current + configuration.selectionLimit = 0 + configuration.disabledCapabilities = [ + .collectionNavigation, .collectionNavigation, .search, .stagingArea + ] + configuration.edgesWithoutContentMargins = .all + configuration.selection = .continuousAndOrdered + + let picker = PHPickerViewController(configuration: configuration) + picker.delegate = self + mediaPickerInputViewController = picker + + if currentKeyboardFrame != .zero { + // iOS is not adjusting the media picker's height to match the default keyboard's height when autoresizingMask + // is set to UIViewAutoresizingFlexibleHeight (even though the docs claim it should). Need to manually + // set the picker's frame to the current keyboard's frame. + picker.view.autoresizingMask = [] + picker.view.frame = CGRect(x: 0, y: 0, width: currentKeyboardFrame.width, height: mediaKeyboardHeight) + } - presentToolbarViewControllerAsInputView(picker) + presentToolbarViewControllerAsInputView(picker) + } } @objc func toggleEditingMode() { @@ -1957,6 +1958,8 @@ extension AztecPostViewController { } fileprivate func updateToolbar(_ toolbar: Aztec.FormatBar, forMode mode: FormatBarMode) { + self.toolbarMode = mode + if let leadingItem = toolbar.leadingItem { rotateMediaToolbarItem(leadingItem, forMode: mode) } @@ -2927,9 +2930,6 @@ extension AztecPostViewController { } func closeMediaPickerInputViewController() { - guard mediaPickerInputViewController != nil else { - return - } selectedPickerResults = [] mediaPickerInputViewController = nil changeRichTextInputView(to: nil) From 1099db6e29eda2115c725f2fde77f940eb77a3a9 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 17 Nov 2023 16:08:50 -0500 Subject: [PATCH 7/9] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 99e252fd48f0..bc8b4cf39152 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -17,6 +17,7 @@ * [*] Block Editor: Ensure uploaded audio is always visible within Audio block [https://github.com/WordPress/gutenberg/pull/55627] * [*] Block Editor: In the deeply nested block warning, only display the ungroup option for blocks that support it [https://github.com/WordPress/gutenberg/pull/56445] * [**] Refactor deleting media [#21748] +* [*] Update the classic editor to use the new Photos and Site Media pickers [#22060] 23.7 ----- From 9cb520ff9949a2572be01a866eae7be3e8ebe1a0 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 27 Nov 2023 09:13:25 -0500 Subject: [PATCH 8/9] Add compatibility with Xcode 14.3 --- .../Aztec/ViewControllers/AztecPostViewController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift index f0a2f273997e..4c969fbef1dd 100644 --- a/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift +++ b/WordPress/Classes/ViewRelated/Aztec/ViewControllers/AztecPostViewController.swift @@ -1800,6 +1800,7 @@ extension AztecPostViewController { richTextView.autocorrectionType = .no +#if swift(>=5.9) // Requires Xcode 15 if #available(iOS 17, *) { var configuration = PHPickerConfiguration() configuration.filter = .any(of: [.images, .videos]) @@ -1825,6 +1826,7 @@ extension AztecPostViewController { presentToolbarViewControllerAsInputView(picker) } +#endif } @objc func toggleEditingMode() { From dc03e76dbdcc08c2ba456bf764f13ba8372fb7ca Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 27 Nov 2023 09:13:43 -0500 Subject: [PATCH 9/9] Update release notes --- RELEASE-NOTES.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index bc8b4cf39152..a802a2e313c2 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,3 +1,7 @@ +23.9 +---- +* [*] Update the classic editor to use the new Photos and Site Media pickers [#22060] + 23.8 ----- * [**] Add Optimize Images setting for image uploads and enable it by default [#21981] @@ -17,7 +21,6 @@ * [*] Block Editor: Ensure uploaded audio is always visible within Audio block [https://github.com/WordPress/gutenberg/pull/55627] * [*] Block Editor: In the deeply nested block warning, only display the ungroup option for blocks that support it [https://github.com/WordPress/gutenberg/pull/56445] * [**] Refactor deleting media [#21748] -* [*] Update the classic editor to use the new Photos and Site Media pickers [#22060] 23.7 -----