Skip to content

Commit

Permalink
Merge pull request #14085 from wordpress-mobile/rnmobile/issue/1744-t…
Browse files Browse the repository at this point in the history
…hemeColor

[RNMobile] Support Theme Colors and Gradients
  • Loading branch information
Chip authored Jun 3, 2020
2 parents 57da3c2 + 06352af commit 8056b01
Show file tree
Hide file tree
Showing 8 changed files with 299 additions and 76 deletions.
2 changes: 1 addition & 1 deletion Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ target 'WordPress' do
## Gutenberg (React Native)
## =====================
##
gutenberg :tag => '1.29.0'
gutenberg :commit => 'a3a155d0053c75985960ae7ac8ecfaa2e3732efa'

## Third party libraries
## =====================
Expand Down
138 changes: 69 additions & 69 deletions Podfile.lock

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
15.1
-----

* [**] Block editor: Adds support for theme colors and gradients.

15.0
-----
* [**] Block editor: Fix media upload progress when there's no connection.
Expand Down Expand Up @@ -38,7 +39,7 @@
* Support the superscript and subscript HTML formatting on the Block Editor and Classic Editor.
* [***] You can now draw on images to annotate them using the Edit image feature in the post editor.
* [*] Fixed a bug on the editors where changing a featured image didn't trigger that the post/page changed.

14.8.1
-----
* Fix adding and removing of featured images to posts.
Expand All @@ -59,7 +60,7 @@
* [internal] the "send magic link" screen has navigation changes that can cause regressions. See https://git.io/Jfqiz for testing details.
* Updated UI for Login and Signup epilogues.
* Fixes delayed split view resizing while rotating your device.

14.7
-----
* Classic Editor: Fixed action sheet position for additional Media sources picker on iPad
Expand All @@ -78,9 +79,9 @@
* Updated site details screen title to My Site, to avoid duplicating the title of the current site which is displayed in the screen's header area.
* You can now schedule your post, add tags or change the visibility before hitting "Publish Now" — and you don't have to go to the Post Settings for this!

* Login Epilogue: fixed issue where account information never stopped loading for some self-hosted sites.
* Updated site details screen title to My Site, to avoid duplicating the title of the current site which is displayed in the screen's header area.
* Login Epilogue: fixed issue where account information never stopped loading for some self-hosted sites.
* Updated site details screen title to My Site, to avoid duplicating the title of the current site which is displayed in the screen's header area.

14.6
-----
* [internal] the login flow with 2-factor authentication enabled has code changes that can cause regressions. See https://git.io/Jvdil for testing details.
Expand Down
46 changes: 46 additions & 0 deletions WordPress/Classes/Models/EditorTheme.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Foundation
import Gutenberg

struct EditorTheme: Codable, Equatable {
static func == (lhs: EditorTheme, rhs: EditorTheme) -> Bool {
return lhs.description == rhs.description
}

enum CodingKeys: String, CodingKey {
case themeSupport = "theme_supports"
case version
case stylesheet
}

let themeSupport: EditorThemeSupport?
let version: String?
let stylesheet: String?

var description: String {
return "\(stylesheet ?? "")-\(version ?? "")"
}

init(from decoder: Decoder) throws {
let map = try decoder.container(keyedBy: CodingKeys.self)
self.themeSupport = try? map.decode(EditorThemeSupport.self, forKey: .themeSupport)
self.version = try? map.decode(String.self, forKey: .version)
self.stylesheet = try? map.decode(String.self, forKey: .stylesheet)
}
}

struct EditorThemeSupport: Codable, GutenbergEditorTheme {

enum CodingKeys: String, CodingKey {
case colors = "editor-color-palette"
case gradients = "editor-gradient-presets"
}

let colors: [[String: String]]?
let gradients: [[String: String]]?

init(from decoder: Decoder) throws {
let map = try decoder.container(keyedBy: CodingKeys.self)
self.colors = try? map.decode([[String: String]].self, forKey: .colors)
self.gradients = try? map.decode([[String: String]].self, forKey: .gradients)
}
}
126 changes: 126 additions & 0 deletions WordPress/Classes/Stores/EditorThemeStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import WordPressFlux

struct EditorThemeQuery {
let blog: Blog
}

enum EditorThemeStoreState {
typealias StoredThemes = [String: EditorTheme]
case empty
case loaded(StoredThemes)

static func key(forBlog blog: Blog) -> String? {
return blog.hostname as String?
}

func editorTheme(forBlog blog: Blog) -> EditorTheme? {
guard let themeKey = EditorThemeStoreState.key(forBlog: blog) else {
return nil
}

switch self {
case .loaded(let themes):
return themes[themeKey]
default:
return nil
}
}

func storedThemes() -> StoredThemes {
switch self {
case .loaded(let themes):
return themes
default:
return [:]
}
}
}

extension EditorThemeStoreState: Codable {

enum Key: CodingKey {
case rawValue
case associatedValue
}

enum CodingError: Error {
case unknownValue
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self)
let rawValue = try container.decode(Int.self, forKey: .rawValue)
switch rawValue {
case 0:
self = .empty
case 1:
let themes = try container.decode(StoredThemes.self, forKey: .associatedValue)
self = .loaded(themes)
default:
throw CodingError.unknownValue
}
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: Key.self)
switch self {
case .empty:
try container.encode(0, forKey: .rawValue)
case .loaded(let themes):
try container.encode(1, forKey: .rawValue)
try container.encode(themes, forKey: .associatedValue)
}
}
}

class EditorThemeStore: QueryStore<EditorThemeStoreState, EditorThemeQuery> {

private enum ErrorCode: Int {
case processingError
}

init(dispatcher: ActionDispatcher = .global) {
super.init(initialState: .empty, dispatcher: dispatcher)
}

override func queriesChanged() {

activeQueries.forEach { (query) in
fetchTheme(for: query.blog)
}
}

override func logError(_ error: String) {
DDLogError("Error loading active theme: \(error)")
}
}

private extension EditorThemeStore {

func fetchTheme(for blog: Blog) {
let requestPath = "/wp/v2/themes?status=active"
GutenbergNetworkRequest(path: requestPath, blog: blog).request { [weak self] result in
switch result {
case .success(let response):
self?.processResponse(response, for: blog)
case .failure(let error):
DDLogError("Error loading active theme: \(error)")
}
}
}

func processResponse(_ response: Any, for blog: Blog) {
guard
let responseData = try? JSONSerialization.data(withJSONObject: response, options: []),
let themeKey = EditorThemeStoreState.key(forBlog: blog),
let themeSupports = try? JSONDecoder().decode([EditorTheme].self, from: responseData),
let newTheme = themeSupports.first
else { return }

var existingThemes = state.storedThemes()
if newTheme != existingThemes[themeKey] {
existingThemes[themeKey] = newTheme
state = .loaded(existingThemes)
}
}
}
1 change: 1 addition & 0 deletions WordPress/Classes/Stores/StoreContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ class StoreContainer {
let statsInsights = StatsInsightsStore()
let statsPeriod = StatsPeriodStore()
let jetpackInstall = JetpackInstallStore()
let editorTheme = EditorThemeStore()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import UIKit
import WPMediaPicker
import Gutenberg
import Aztec
import WordPressFlux

class GutenbergViewController: UIViewController, PostEditor {

Expand Down Expand Up @@ -231,6 +232,9 @@ class GutenbergViewController: UIViewController, PostEditor {
return gutenbergSettings.shouldPresentInformativeDialog(for: post.blog)
}()

private var themeSupportQuery: Receipt? = nil
private var themeSupportReceipt: Receipt? = nil

// MARK: - Initializers
required init(
post: AbstractPost,
Expand Down Expand Up @@ -277,6 +281,7 @@ class GutenbergViewController: UIViewController, PostEditor {

gutenberg.delegate = self
showInformativeDialogIfNecessary()
fetchEditorTheme()
}

override func viewWillAppear(_ animated: Bool) {
Expand Down Expand Up @@ -606,6 +611,7 @@ extension GutenbergViewController: GutenbergBridgeDelegate {
}
focusTitleIfNeeded()
mediaInserterHelper.refreshMediaStatus()
refreshEditorTheme()
}
}

Expand Down Expand Up @@ -878,3 +884,30 @@ private extension GutenbergViewController {
static let retryAllFailedUploadsActionTitle = NSLocalizedString("Retry all", comment: "User action to retry all failed media uploads.")
}
}

// Editor Theme Support
extension GutenbergViewController {

// GutenbergBridgeDataSource
func gutenbergEditorTheme() -> GutenbergEditorTheme? {
return StoreContainer.shared.editorTheme.state.editorTheme(forBlog: post.blog)?.themeSupport
}

private func fetchEditorTheme() {
let themeSupportStore = StoreContainer.shared.editorTheme
themeSupportQuery = themeSupportStore.query(EditorThemeQuery(blog: post.blog))
themeSupportReceipt = themeSupportStore.onStateChange { [weak self] (_, state) in
DispatchQueue.main.async {
if let strongSelf = self, let themeSupport = state.editorTheme(forBlog: strongSelf.post.blog)?.themeSupport {
strongSelf.gutenberg.updateTheme(themeSupport)
}
}
}
}

private func refreshEditorTheme() {
if let themeSupport = StoreContainer.shared.editorTheme.state.editorTheme(forBlog: post.blog)?.themeSupport {
gutenberg.updateTheme(themeSupport)
}
}
}
16 changes: 16 additions & 0 deletions WordPress/WordPress.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -577,10 +577,12 @@
43FB3F411EBD215C00FC8A62 /* LoginEpilogueBlogCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB3F401EBD215C00FC8A62 /* LoginEpilogueBlogCell.swift */; };
43FB3F471EC10F1E00FC8A62 /* LoginEpilogueTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FB3F461EC10F1E00FC8A62 /* LoginEpilogueTableViewController.swift */; };
43FF64EF20DAA0840060A69A /* GravatarUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FF64EE20DAA0840060A69A /* GravatarUploader.swift */; };
4629E41D243D21400002E15C /* EditorThemeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4629E41C243D21400002E15C /* EditorThemeStore.swift */; };
4629E4212440C5B20002E15C /* GutenbergCoverUploadProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4629E4202440C5B20002E15C /* GutenbergCoverUploadProcessor.swift */; };
4629E4232440C8160002E15C /* GutenbergCoverUploadProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4629E4222440C8160002E15C /* GutenbergCoverUploadProcessorTests.swift */; };
462F4E0A18369F0B0028D2F8 /* BlogDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 462F4E0718369F0B0028D2F8 /* BlogDetailsViewController.m */; };
46638DF6244904A3006E8439 /* GutenbergBlockProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46638DF5244904A3006E8439 /* GutenbergBlockProcessor.swift */; };
46963F5924649542000D356D /* EditorTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46963F5824649542000D356D /* EditorTheme.swift */; };
4B2DD0F29CD6AC353C056D41 /* Pods_WordPressUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DCE7542239FBC709B90EA85 /* Pods_WordPressUITests.framework */; };
4C8A715EBCE7E73AEE216293 /* Pods_WordPressShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F47DB4A8EC2E6844E213A3FA /* Pods_WordPressShareExtension.framework */; };
4D520D4F22972BC9002F5924 /* acknowledgements.html in Resources */ = {isa = PBXBuildFile; fileRef = 4D520D4E22972BC9002F5924 /* acknowledgements.html */; };
Expand Down Expand Up @@ -2957,11 +2959,13 @@
43FB3F401EBD215C00FC8A62 /* LoginEpilogueBlogCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginEpilogueBlogCell.swift; sourceTree = "<group>"; };
43FB3F461EC10F1E00FC8A62 /* LoginEpilogueTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginEpilogueTableViewController.swift; sourceTree = "<group>"; };
43FF64EE20DAA0840060A69A /* GravatarUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GravatarUploader.swift; sourceTree = "<group>"; };
4629E41C243D21400002E15C /* EditorThemeStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorThemeStore.swift; sourceTree = "<group>"; };
4629E4202440C5B20002E15C /* GutenbergCoverUploadProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GutenbergCoverUploadProcessor.swift; sourceTree = "<group>"; };
4629E4222440C8160002E15C /* GutenbergCoverUploadProcessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GutenbergCoverUploadProcessorTests.swift; sourceTree = "<group>"; };
462F4E0618369F0B0028D2F8 /* BlogDetailsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlogDetailsViewController.h; sourceTree = "<group>"; };
462F4E0718369F0B0028D2F8 /* BlogDetailsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = BlogDetailsViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
46638DF5244904A3006E8439 /* GutenbergBlockProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GutenbergBlockProcessor.swift; sourceTree = "<group>"; };
46963F5824649542000D356D /* EditorTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorTheme.swift; sourceTree = "<group>"; };
46F84612185A8B7E009D0DA5 /* PostContentProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PostContentProvider.h; sourceTree = "<group>"; };
48690E659987FD4472EEDE5F /* Pods-WordPressNotificationContentExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressNotificationContentExtension.release.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressNotificationContentExtension/Pods-WordPressNotificationContentExtension.release.xcconfig"; sourceTree = "<group>"; };
4D520D4E22972BC9002F5924 /* acknowledgements.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = acknowledgements.html; path = "../Pods/Target Support Files/Pods-WordPress/acknowledgements.html"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5707,6 +5711,7 @@
2F706A870DFB229B00B43086 /* Models */ = {
isa = PBXGroup;
children = (
46963F5724649509000D356D /* Gutenberg */,
40A71C5F220E1941002E3D25 /* Stats */,
9A38DC63218899E4006A409B /* Revisions */,
D8CB56212181A93F00554EAE /* Site Creation */,
Expand Down Expand Up @@ -6387,6 +6392,14 @@
name = "Resources-iPad";
sourceTree = "<group>";
};
46963F5724649509000D356D /* Gutenberg */ = {
isa = PBXGroup;
children = (
46963F5824649542000D356D /* EditorTheme.swift */,
);
name = Gutenberg;
sourceTree = "<group>";
};
5703A4C722C0214C0028A343 /* Style */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -10082,6 +10095,7 @@
9A2D0B24225CB97F009E585F /* JetpackInstallStore.swift */,
9A4E271C22EF33F5001F6A6B /* AccountSettingsStore.swift */,
9A09F914230C3E9700F42AB7 /* StoreFetchingStatus.swift */,
4629E41C243D21400002E15C /* EditorThemeStore.swift */,
);
path = Stores;
sourceTree = "<group>";
Expand Down Expand Up @@ -12018,6 +12032,7 @@
E1222B671F878E4700D23173 /* WebViewControllerFactory.swift in Sources */,
E1D86E691B2B414300DD2192 /* WordPress-32-33.xcmappingmodel in Sources */,
9A2B28E8219046ED00458F2A /* ShowRevisionsListManger.swift in Sources */,
46963F5924649542000D356D /* EditorTheme.swift in Sources */,
985ED0E423C6950600B8D06A /* WidgetStyles.swift in Sources */,
57CCB3812358ED07003ECD0C /* WordPress-91-92.xcmappingmodel in Sources */,
5D2B30B91B7411C700DA15F3 /* ReaderCardDiscoverAttributionView.swift in Sources */,
Expand Down Expand Up @@ -12224,6 +12239,7 @@
E6805D311DCD399600168E4F /* WPRichTextImage.swift in Sources */,
7E4123C120F4097B00DF8486 /* FormattableContentRange.swift in Sources */,
08D978581CD2AF7D0054F19A /* MenuItemSourceHeaderView.m in Sources */,
4629E41D243D21400002E15C /* EditorThemeStore.swift in Sources */,
3FF1A853242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift in Sources */,
BE1071FC1BC75E7400906AFF /* WPStyleGuide+Blog.swift in Sources */,
B56695B01D411EEB007E342F /* KeyboardDismissHelper.swift in Sources */,
Expand Down

0 comments on commit 8056b01

Please sign in to comment.