Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tenor GIF picker for Gutenberg editor #13910

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class GutenbergViewController: UIViewController, PostEditor {
private lazy var filesAppMediaPicker: GutenbergFilesAppMediaSource = {
return GutenbergFilesAppMediaSource(gutenberg: gutenberg, mediaInserter: mediaInserterHelper)
}()
private lazy var tenorMediaPicker: GutenbergTenorMediaPicker = {
return GutenbergTenorMediaPicker(gutenberg: gutenberg, mediaInserter: mediaInserterHelper)
}()

// MARK: - Aztec

Expand Down Expand Up @@ -378,8 +381,14 @@ extension GutenbergViewController: GutenbergBridgeDelegate {
gutenbergDidRequestMediaFromDevicePicker(filter: flags, allowMultipleSelection: allowMultipleSelection, with: callback)
case .deviceCamera:
gutenbergDidRequestMediaFromCameraPicker(filter: flags, with: callback)

case .stockPhotos:
stockPhotos.presentPicker(origin: self, post: post, multipleSelection: allowMultipleSelection, callback: callback)
case .tenor:
tenorMediaPicker.presentPicker(origin: self,
post: post,
multipleSelection: allowMultipleSelection,
callback: callback)
case .filesApp:
filesAppMediaPicker.presentPicker(origin: self, filters: filter, multipleSelection: allowMultipleSelection, callback: callback)
default: break
Expand Down Expand Up @@ -637,6 +646,7 @@ extension GutenbergViewController: GutenbergBridgeDataSource {
func gutenbergMediaSources() -> [Gutenberg.MediaSource] {
return [
post.blog.supports(.stockPhotos) ? .stockPhotos : nil,
FeatureFlag.tenor.enabled ? .tenor : nil,
.filesApp,
].compactMap { $0 }
}
Expand Down Expand Up @@ -738,6 +748,7 @@ extension GutenbergViewController: PostEditorNavigationBarManagerDelegate {
extension Gutenberg.MediaSource {
static let stockPhotos = Gutenberg.MediaSource(id: "wpios-stock-photo-library", label: .freePhotosLibrary, types: [.image])
static let filesApp = Gutenberg.MediaSource(id: "wpios-files-app", label: .files, types: [.image, .video, .audio, .other])
static let tenor = Gutenberg.MediaSource(id: "wpios-tenor", label: .tenor, types: [.image])
}

private extension GutenbergViewController {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import Gutenberg

class GutenbergTenorMediaPicker {
private var tenor: TenorPicker?
private var mediaPickerCallback: MediaPickerDidPickMediaCallback?
private let mediaInserter: GutenbergMediaInserterHelper
private unowned var gutenberg: Gutenberg
private var multipleSelection = false

init(gutenberg: Gutenberg, mediaInserter: GutenbergMediaInserterHelper) {
self.mediaInserter = mediaInserter
self.gutenberg = gutenberg
}

func presentPicker(origin: UIViewController, post: AbstractPost, multipleSelection: Bool, callback: @escaping MediaPickerDidPickMediaCallback) {
let picker = TenorPicker()
tenor = picker
picker.allowMultipleSelection = true
picker.delegate = self
mediaPickerCallback = callback
picker.presentPicker(origin: origin, blog: post.blog)
self.multipleSelection = multipleSelection
}
}

extension GutenbergTenorMediaPicker: TenorPickerDelegate {
func tenorPicker(_ picker: TenorPicker, didFinishPicking assets: [TenorMedia]) {
defer {
mediaPickerCallback = nil
tenor = nil
}
guard assets.isEmpty == false else {
mediaPickerCallback?(nil)
return
}

// For blocks that support multiple uploads this will upload all images.
// If multiple uploads are not supported then it will seperate them out to Image Blocks.
multipleSelection ? insertOnBlock(with: assets) : insertSingleImages(assets)
}

/// Adds the given image object to the requesting block and seperates multiple images to seperate image blocks
/// - Parameter asset: Tenor Media object to add.
func insertSingleImages(_ assets: [TenorMedia]) {
// Append the first item via callback given by Gutenberg.
if let firstItem = assets.first {
insertOnBlock(with: [firstItem])
}
// Append the rest of images via `.appendMedia` event.
// Ideally we would send all picked images via the given callback, but that seems to not be possible yet.
appendOnNewBlocks(assets: assets.dropFirst())
}

/// Adds the given images to the requesting block
/// - Parameter assets: Tenor Media objects to add.
func insertOnBlock(with assets: [TenorMedia]) {
guard let callback = mediaPickerCallback else {
return assertionFailure("Image picked without callback")
}

let mediaInfo = assets.compactMap { (asset) -> MediaInfo? in
guard let media = self.mediaInserter.insert(exportableAsset: asset, source: .giphy) else {
return nil
}
let mediaUploadID = media.gutenbergUploadID
return MediaInfo(id: mediaUploadID, url: asset.URL.absoluteString, type: media.mediaTypeString)
}

callback(mediaInfo)
}

/// Create a new image block for each of the image objects in the slice.
/// - Parameter assets: Tenor Media objects to append.
func appendOnNewBlocks(assets: ArraySlice<TenorMedia>) {
assets.forEach {
if let media = self.mediaInserter.insert(exportableAsset: $0, source: .giphy) {
self.gutenberg.appendMedia(id: media.gutenbergUploadID, url: $0.URL, type: .image)
}
}
}
}
13 changes: 12 additions & 1 deletion WordPress/Classes/ViewRelated/Media/Tenor/TenorPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ protocol TenorPickerDelegate: AnyObject {

/// Presents the Tenor main interface
final class TenorPicker: NSObject {
// MARK: - Public properties

var allowMultipleSelection = true {
didSet {
pickerOptions.allowMultipleSelection = allowMultipleSelection
}
}

// MARK: - Private properties

private lazy var dataSource: TenorDataSource = {
TenorDataSource(service: tenorService)
}()
Expand All @@ -25,14 +35,15 @@ final class TenorPicker: NSObject {

private let searchHint = NoResultsViewController.controller()

private var pickerOptions: WPMediaPickerOptions = {
private lazy var pickerOptions: WPMediaPickerOptions = {
let options = WPMediaPickerOptions()
options.showMostRecentFirst = true
options.filter = [.all]
options.allowCaptureOfMedia = false
options.showSearchBar = true
options.badgedUTTypes = [String(kUTTypeGIF)]
options.preferredStatusBarStyle = .lightContent
options.allowMultipleSelection = allowMultipleSelection
return options
}()

Expand Down
4 changes: 4 additions & 0 deletions WordPress/WordPress.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,7 @@
C8567492243F3751001A995E /* tenor-search-response.json in Resources */ = {isa = PBXBuildFile; fileRef = C8567491243F3751001A995E /* tenor-search-response.json */; };
C8567494243F388F001A995E /* tenor-invalid-search-reponse.json in Resources */ = {isa = PBXBuildFile; fileRef = C8567493243F388F001A995E /* tenor-invalid-search-reponse.json */; };
C8567496243F3D37001A995E /* TenorResultsPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8567495243F3D37001A995E /* TenorResultsPageTests.swift */; };
C856748F243EF177001A995E /* GutenbergTenorMediaPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C856748E243EF177001A995E /* GutenbergTenorMediaPicker.swift */; };
C8567498243F41CA001A995E /* MockTenorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8567497243F41CA001A995E /* MockTenorService.swift */; };
C856749A243F4292001A995E /* TenorMockDataHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8567499243F4292001A995E /* TenorMockDataHelper.swift */; };
CC19BE06223FECAC00CAB3E1 /* EditorPostSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC19BE05223FECAC00CAB3E1 /* EditorPostSettings.swift */; };
Expand Down Expand Up @@ -4047,6 +4048,7 @@
C8567491243F3751001A995E /* tenor-search-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "tenor-search-response.json"; sourceTree = "<group>"; };
C8567493243F388F001A995E /* tenor-invalid-search-reponse.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "tenor-invalid-search-reponse.json"; sourceTree = "<group>"; };
C8567495243F3D37001A995E /* TenorResultsPageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TenorResultsPageTests.swift; sourceTree = "<group>"; };
C856748E243EF177001A995E /* GutenbergTenorMediaPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GutenbergTenorMediaPicker.swift; sourceTree = "<group>"; };
C8567497243F41CA001A995E /* MockTenorService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTenorService.swift; sourceTree = "<group>"; };
C8567499243F4292001A995E /* TenorMockDataHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TenorMockDataHelper.swift; sourceTree = "<group>"; };
C856749B243F462F001A995E /* TenorDataSouceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TenorDataSouceTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -7105,6 +7107,7 @@
8B05D29223AA572A0063B9AA /* GutenbergMediaEditorImage.swift */,
7E407120237163B8003627FA /* GutenbergStockPhotos.swift */,
7E4071392372AD54003627FA /* GutenbergFilesAppMediaSource.swift */,
C856748E243EF177001A995E /* GutenbergTenorMediaPicker.swift */,
);
path = Utils;
sourceTree = "<group>";
Expand Down Expand Up @@ -11957,6 +11960,7 @@
E66969DC1B9E55C300EC9C00 /* ReaderTopicToReaderListTopic37to38.swift in Sources */,
31C9F82E1A2368A2008BB945 /* BlogDetailHeaderView.m in Sources */,
9A2D0B23225CB92B009E585F /* BlogService+JetpackConvenience.swift in Sources */,
C856748F243EF177001A995E /* GutenbergTenorMediaPicker.swift in Sources */,
B50C0C5F1EF42A4A00372C65 /* AztecPostViewController.swift in Sources */,
FF28B3F11AEB251200E11AAE /* InfoPListTranslator.m in Sources */,
086E1FE01BBB35D2002D86CA /* MenusViewController.m in Sources */,
Expand Down