diff --git a/WordPress/Classes/Utility/Editor/EditorConfigurationBuilder+Blog.swift b/WordPress/Classes/Utility/Editor/EditorConfigurationBuilder+Blog.swift new file mode 100644 index 000000000000..022feec25992 --- /dev/null +++ b/WordPress/Classes/Utility/Editor/EditorConfigurationBuilder+Blog.swift @@ -0,0 +1,71 @@ +import Foundation +import GutenbergKit +import WordPressData +import WordPressShared + +extension EditorConfigurationBuilder { + init(blog: Blog) { + let selfHostedApiUrl = blog.url(withPath: "wp-json/") + let isWPComSite = blog.isHostedAtWPcom || blog.isAtomic() + let siteApiRoot = blog.isAccessibleThroughWPCom() && isWPComSite ? blog.wordPressComRestApi?.baseURL.absoluteString : selfHostedApiUrl + let siteId = blog.dotComID?.stringValue + let siteDomain = blog.primaryDomainAddress + let authToken = blog.authToken ?? "" + var authHeader = "Bearer \(authToken)" + + let applicationPassword = try? blog.getApplicationToken() + + if let appPassword = applicationPassword, let username = blog.username { + let credentials = "\(username):\(appPassword)" + if let credentialsData = credentials.data(using: .utf8) { + let base64Credentials = credentialsData.base64EncodedString() + authHeader = "Basic \(base64Credentials)" + } + } + + // Must provide both namespace forms to detect usages of both forms in third-party code + var siteApiNamespace: [String] = [] + if isWPComSite { + if let siteId { + siteApiNamespace.append("sites/\(siteId)") + } + siteApiNamespace.append("sites/\(siteDomain)") + } + + self = EditorConfigurationBuilder() + .setSiteUrl(blog.url ?? "") + .setSiteApiRoot(siteApiRoot ?? "") + .setSiteApiNamespace(siteApiNamespace) + .setNamespaceExcludedPaths(["/wpcom/v2/following/recommendations", "/wpcom/v2/following/mine"]) + .setAuthHeader(authHeader) + .setShouldUseThemeStyles(FeatureFlag.newGutenbergThemeStyles.enabled) + + // Limited to Simple sites until application password auth is supported + if RemoteFeatureFlag.newGutenbergPlugins.enabled() && blog.isHostedAtWPcom { + self = self.setShouldUsePlugins(true) + if var editorAssetsEndpoint = blog.wordPressComRestApi?.baseURL { + editorAssetsEndpoint.appendPathComponent("wpcom/v2/sites") + if let siteId { + editorAssetsEndpoint.appendPathComponent(siteId) + } else { + editorAssetsEndpoint.appendPathComponent(siteDomain) + } + editorAssetsEndpoint.appendPathComponent("editor-assets") + self = self.setEditorAssetsEndpoint(editorAssetsEndpoint) + } + } + self = self.setLocale(WordPressComLanguageDatabase().deviceLanguage.slug) + + if !blog.isSelfHosted { + let siteType: String = blog.isHostedAtWPcom ? "simple" : "atomic" + do { + self = self.setWebViewGlobals([ + try WebViewGlobal(name: "_currentSiteType", value: .string(siteType)) + ]) + } catch { + wpAssertionFailure("Failed to create WebViewGlobal", userInfo: ["error": "\(error)"]) + self = self.setWebViewGlobals([]) + } + } + } +} diff --git a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift index 36d642ef787d..770baf806798 100644 --- a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift @@ -172,7 +172,7 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite if RemoteFeatureFlag.newGutenberg.enabled() { GutenbergKit.EditorViewController.warmup( - configuration: blog.flatMap(EditorConfiguration.init(blog:)) ?? .default + configuration: blog.flatMap { EditorConfigurationBuilder(blog: $0).build() } ?? .default ) } } diff --git a/WordPress/Classes/ViewRelated/Comments/Controllers/Editor/CommentGutenbergEditorViewController.swift b/WordPress/Classes/ViewRelated/Comments/Controllers/Editor/CommentGutenbergEditorViewController.swift index 53e7e4df9f4a..7fd86eb68a7b 100644 --- a/WordPress/Classes/ViewRelated/Comments/Controllers/Editor/CommentGutenbergEditorViewController.swift +++ b/WordPress/Classes/ViewRelated/Comments/Controllers/Editor/CommentGutenbergEditorViewController.swift @@ -35,8 +35,9 @@ final class CommentGutenbergEditorViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - var configuration = EditorConfiguration(content: initialContent ?? "") - configuration.hideTitle = true + let configuration = EditorConfigurationBuilder(content: initialContent ?? "") + .setShouldHideTitle(true) + .build() let editorVC = GutenbergKit.EditorViewController(configuration: configuration) editorVC.delegate = self diff --git a/WordPress/Classes/ViewRelated/NewGutenberg/NewGutenbergViewController.swift b/WordPress/Classes/ViewRelated/NewGutenberg/NewGutenbergViewController.swift index 2db3e626077e..07f6ca5acdda 100644 --- a/WordPress/Classes/ViewRelated/NewGutenberg/NewGutenbergViewController.swift +++ b/WordPress/Classes/ViewRelated/NewGutenberg/NewGutenbergViewController.swift @@ -127,13 +127,14 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor self.editorSession = PostEditorAnalyticsSession(editor: .gutenbergKit, post: post) self.navigationBarManager = navigationBarManager ?? PostEditorNavigationBarManager() - var conf = EditorConfiguration(blog: post.blog) - conf.title = post.postTitle ?? "" - conf.content = post.content ?? "" - conf.postID = post.postID?.intValue != -1 ? post.postID?.intValue : nil - conf.postType = post is Page ? "page" : "post" + let configuration = EditorConfigurationBuilder(blog: post.blog) + .setTitle(post.postTitle ?? "") + .setContent(post.content ?? "") + .setPostID(post.postID?.intValue != -1 ? post.postID?.intValue : nil) + .setPostType(post is Page ? "page" : "post") + .build() - self.editorViewController = GutenbergKit.EditorViewController(configuration: conf) + self.editorViewController = GutenbergKit.EditorViewController(configuration: configuration) super.init(nibName: nil, bundle: nil) @@ -331,8 +332,12 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor hasEditorStarted = true if let settings { - var updatedConfig = self.editorViewController.configuration - updatedConfig.updateEditorSettings(settings) + // TODO: `setEditorSettings` throws due to incompatibility between `[String: Any]` + // and `[String: Encodable]`. The latter is now expected by + // `GutenbergKitConfiguration.EditorSettings`. How should we reconcile this? + let updatedConfig = self.editorViewController.configuration.toBuilder() + .setEditorSettings(settings) + .build() self.editorViewController.updateConfiguration(updatedConfig) } self.editorViewController.startEditorSetup() @@ -840,74 +845,6 @@ extension NewGutenbergViewController { } } -extension EditorConfiguration { - init(blog: Blog) { - let selfHostedApiUrl = blog.url(withPath: "wp-json/") - let isWPComSite = blog.isHostedAtWPcom || blog.isAtomic() - let siteApiRoot = blog.isAccessibleThroughWPCom() && isWPComSite ? blog.wordPressComRestApi?.baseURL.absoluteString : selfHostedApiUrl - let siteId = blog.dotComID?.stringValue - let siteDomain = blog.primaryDomainAddress - let authToken = blog.authToken ?? "" - var authHeader = "Bearer \(authToken)" - - let applicationPassword = try? blog.getApplicationToken() - - if let appPassword = applicationPassword, let username = blog.username { - let credentials = "\(username):\(appPassword)" - if let credentialsData = credentials.data(using: .utf8) { - let base64Credentials = credentialsData.base64EncodedString() - authHeader = "Basic \(base64Credentials)" - } - } - - // Must provide both namespace forms to detect usages of both forms in third-party code - var siteApiNamespace: [String] = [] - if isWPComSite { - if let siteId { - siteApiNamespace.append("sites/\(siteId)") - } - siteApiNamespace.append("sites/\(siteDomain)") - } - - self = EditorConfiguration() - - self.siteURL = blog.url ?? "" - self.siteApiRoot = siteApiRoot ?? "" - self.siteApiNamespace = siteApiNamespace - self.namespaceExcludedPaths = ["/wpcom/v2/following/recommendations", "/wpcom/v2/following/mine"] - self.authHeader = authHeader - - self.themeStyles = FeatureFlag.newGutenbergThemeStyles.enabled - // Limited to Simple sites until application password auth is supported - if RemoteFeatureFlag.newGutenbergPlugins.enabled() && blog.isHostedAtWPcom { - self.plugins = true - if var editorAssetsEndpoint = blog.wordPressComRestApi?.baseURL { - editorAssetsEndpoint.appendPathComponent("wpcom/v2/sites") - if let siteId { - editorAssetsEndpoint.appendPathComponent(siteId) - } else { - editorAssetsEndpoint.appendPathComponent(siteDomain) - } - editorAssetsEndpoint.appendPathComponent("editor-assets") - self.editorAssetsEndpoint = editorAssetsEndpoint - } - } - self.locale = WordPressComLanguageDatabase().deviceLanguage.slug - - if !blog.isSelfHosted { - let siteType: String = blog.isHostedAtWPcom ? "simple" : "atomic" - do { - self.webViewGlobals = [ - try WebViewGlobal(name: "_currentSiteType", value: .string(siteType)) - ] - } catch { - wpAssertionFailure("Failed to create WebViewGlobal", userInfo: ["error": "\(error)"]) - self.webViewGlobals = [] - } - } - } -} - // Extend Gutenberg JavaScript exception struct to conform the protocol defined in the Crash Logging service extension GutenbergJSException.StacktraceLine: @retroactive AutomatticTracks.JSStacktraceLine {} extension GutenbergJSException: @retroactive AutomatticTracks.JSException {}