@@ -135,7 +135,14 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor
135135 private var suggestionViewBottomConstraint : NSLayoutConstraint ?
136136 private var currentSuggestionsController : GutenbergSuggestionsViewController ?
137137
138- private var editorState : EditorLoadingState = . uninitialized
138+ private var editorState : EditorLoadingState = . uninitialized {
139+ willSet {
140+ // TODO: Cancel tasks
141+ }
142+ didSet {
143+ self . evaluateEditorState ( )
144+ }
145+ }
139146 private var dependencyLoadingError : Error ?
140147 private var editorLoadingTask : Task < Void , Error > ?
141148
@@ -156,6 +163,7 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor
156163 func getHTML( ) -> String { post. content ?? " " }
157164
158165 private let blockEditorSettingsService : RawBlockEditorSettingsService
166+ private let pluginRecommendationService = PluginRecommendationService ( )
159167
160168 // MARK: - Initializers
161169 required convenience init (
@@ -275,7 +283,7 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor
275283 case . loadingCancelled: preconditionFailure ( " Dependency loading should not be cancelled " )
276284 case . suggestingPlugin( let plugin) : self . recommendPlugin ( plugin)
277285 case . dependencyError( let error) : self . showEditorError ( error)
278- case . dependenciesReady( let dependencies) : try await self . startEditor ( settings: dependencies. settings)
286+ case . dependenciesReady( let dependencies) : self . startEditor ( settings: dependencies. settings)
279287 case . started: preconditionFailure ( " The editor should not already be started " )
280288 }
281289 } catch {
@@ -361,7 +369,15 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor
361369 }
362370
363371 func showEditorError( _ error: Error ) {
364- // TODO: We should have a unified way to do this
372+ let controller = UIAlertController (
373+ title: " Error loading editor " ,
374+ message: error. localizedDescription,
375+ preferredStyle: . actionSheet
376+ )
377+
378+ controller. addAction ( UIAlertAction ( title: " Dismiss " , style: . cancel) )
379+
380+ self . present ( controller, animated: true )
365381 }
366382
367383 func showFeedbackView( ) {
@@ -374,6 +390,18 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor
374390 }
375391 }
376392
393+ func evaluateEditorState( ) {
394+ switch self . editorState {
395+ case . uninitialized: break
396+ case . loadingDependencies: break
397+ case . loadingCancelled: break
398+ case . suggestingPlugin( let plugin) : self . recommendPlugin ( plugin)
399+ case . dependencyError( let error) : self . showEditorError ( error)
400+ case . dependenciesReady( let dependencies) : self . startEditor ( settings: dependencies. settings)
401+ case . started: break
402+ }
403+ }
404+
377405 func startLoadingDependencies( ) {
378406 switch self . editorState {
379407 case . uninitialized:
@@ -396,7 +424,9 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor
396424 do {
397425 try await fetchEditorDependencies ( )
398426 } catch {
399- self . editorState = . dependencyError( error)
427+ await MainActor . run {
428+ self . editorState = . dependencyError( error)
429+ }
400430 }
401431 } )
402432 }
@@ -422,7 +452,7 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor
422452 }
423453
424454 @MainActor
425- func startEditor( settings: String ? ) async throws {
455+ func startEditor( settings: String ? ) {
426456 guard case . dependenciesReady = self . editorState else {
427457 preconditionFailure ( " `startEditor` should only be called when the editor is in the `.dependenciesReady` state. " )
428458 }
@@ -508,39 +538,60 @@ class NewGutenbergViewController: UIViewController, PostEditor, PublishingEditor
508538
509539 // MARK: - Editor Setup
510540 private func fetchEditorDependencies( ) async throws {
511- let site = try await ContextManager . shared. performQuery { context in
541+ let ( site, dotComID ) = try await ContextManager . shared. performQuery { context in
512542 let blog = try context. existingObject ( with: self . blogID)
513- return try WordPressSite ( blog: blog)
543+ return ( try WordPressSite ( blog: blog) , blog . dotComID ? . intValue )
514544 }
515545
516546 let client = WordPressClient ( site: site)
517- let pluginService = PluginService ( client: client, wordpressCoreVersion: nil )
518- let pluginRecommendationService = PluginRecommendationService ( )
519547
520- let features : [ PluginRecommendationService . Feature ] = [ . themeStyles, . editorCompatibility]
548+ if let plugin = try await self . fetchPluginRecommendation ( client: client) {
549+ self . editorState = . suggestingPlugin( plugin)
550+ return
551+ }
521552
522- // Don't make plugin recommendations for WordPress
523- if AppConfiguration . isJetpack {
524- for feature in features {
525- if pluginRecommendationService. shouldRecommendPlugin ( for: feature, frequency: . weekly) {
526- let plugin = try await pluginRecommendationService. recommendPlugin ( for: feature)
527-
528- guard try await pluginService. hasInstalledPlugin ( slug: plugin. pluginSlug) else {
529- pluginRecommendationService. didRecommendPlugin ( for: feature)
530- self . editorState = . suggestingPlugin( plugin)
531- return
532- }
533- }
534- }
553+ let settings: String?
554+
555+ if try await client. supports ( . themeStyles, forSiteId: dotComID) {
556+ settings = try await blockEditorSettingsService. getSettingsString ( allowingCachedResponse: true )
535557 }
536558
537- let settings = try await blockEditorSettingsService. getSettingsString ( allowingCachedResponse: true )
538559 let loaded = await loadAuthenticationCookiesAsync ( )
539560
540561 let dependencies = EditorDependencies ( settings: settings, didLoadCookies: loaded)
541562 self. editorState = . dependenciesReady( dependencies)
542563 }
543564
565+ private func fetchPluginRecommendation( client: WordPressClient ) async throws -> RecommendedPlugin ? {
566+
567+ guard try await client. supports ( . managePlugins) else {
568+ return nil
569+ }
570+
571+ let pluginService = PluginService ( client: client, wordpressCoreVersion: nil )
572+ try await pluginService. fetchInstalledPlugins ( )
573+
574+ // Don't make plugin recommendations for WordPress – that app only supports features available in Core
575+ guard AppConfiguration . isJetpack else {
576+ return nil
577+ }
578+
579+ let features : [ PluginRecommendationService . Feature ] = [ . themeStyles, . editorCompatibility]
580+
581+ for feature in features {
582+ if await pluginRecommendationService. shouldRecommendPlugin ( for: feature, frequency: . weekly) {
583+ let plugin = try await pluginRecommendationService. recommendPlugin ( for: feature)
584+
585+ guard try await pluginService. hasInstalledPlugin ( slug: plugin. pluginSlug) else {
586+ await pluginRecommendationService. displayedRecommendation ( for: feature)
587+ return plugin
588+ }
589+ }
590+ }
591+
592+ return nil
593+ }
594+
544595 private func loadAuthenticationCookiesAsync( ) async -> Bool {
545596 guard post. blog. isPrivate ( ) else {
546597 return true
0 commit comments