Skip to content

Commit 8a517d9

Browse files
committed
Move AppColor to DesignSystem
1 parent 5965024 commit 8a517d9

File tree

223 files changed

+593
-310
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

223 files changed

+593
-310
lines changed

Modules/Package.swift

+10-4
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,15 @@ let package = Package(
6060
.product(name: "Gifu", package: "Gifu"),
6161
]),
6262
.target(name: "BuildSettingsKit"),
63-
.target(name: "DesignSystem", swiftSettings: [.swiftLanguageMode(.v5)]),
63+
.target(
64+
name: "DesignSystem",
65+
dependencies: [
66+
"BuildSettingsKit",
67+
.product(name: "ColorStudio", package: "color-studio"),
68+
],
69+
resources: [.process("Resources")],
70+
swiftSettings: [.swiftLanguageMode(.v5)]
71+
),
6472
.target(name: "JetpackStatsWidgetsCore", swiftSettings: [.swiftLanguageMode(.v5)]),
6573
// SFHFKeychainUtils is an old Objective-C keychain wrapper.
6674
// The implementatoin predates ARC, hence the dedicated target with ARC disabled, for the time being.
@@ -96,7 +104,7 @@ let package = Package(
96104
.target(name: "WordPressTesting", resources: [.process("Resources")]),
97105
.target(
98106
name: "WordPressUI",
99-
dependencies: ["AsyncImageKit", "WordPressShared"],
107+
dependencies: ["AsyncImageKit", "DesignSystem", "WordPressShared"],
100108
resources: [.process("Resources")],
101109
swiftSettings: [.swiftLanguageMode(.v5)]
102110
),
@@ -175,7 +183,6 @@ enum XcodeSupport {
175183
.product(name: "Reachability", package: "Reachability"),
176184
.product(name: "SVProgressHUD", package: "SVProgressHUD"),
177185
.product(name: "ZIPFoundation", package: "ZIPFoundation"),
178-
.product(name: "ColorStudio", package: "color-studio"),
179186
.product(name: "Aztec", package: "AztecEditor-iOS"),
180187
.product(name: "WordPressEditor", package: "AztecEditor-iOS"),
181188
]
@@ -252,7 +259,6 @@ enum XcodeSupport {
252259
"WordPressUI",
253260
.product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack"),
254261
.product(name: "WordPressAPI", package: "wordpress-rs"),
255-
.product(name: "ColorStudio", package: "color-studio"),
256262
]),
257263
.xcodeTarget("XcodeTarget_Intents", dependencies: [
258264
"BuildSettingsKit",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import Foundation
2+
3+
/// The live container for running the app with settings defined in the Info.plist file.
4+
struct BuildSettingsLiveContainer: BuildSettingsContainer {
5+
static let shared = BuildSettingsLiveContainer()
6+
7+
var brand: AppBrand {
8+
AppBrand(rawValue: infoPlistValue(forKey: "WPAppBrand"))!
9+
}
10+
11+
var appGroupName: String {
12+
infoPlistValue(forKey: "WPAppGroupName")
13+
}
14+
15+
var appKeychainAccessGroup: String {
16+
infoPlistValue(forKey: "WPAppKeychainAccessGroup")
17+
}
18+
}
19+
20+
private func infoPlistValue<T>(forKey key: String) -> T where T: LosslessStringConvertible {
21+
guard let object = Bundle.main.object(forInfoDictionaryKey: key) else {
22+
fatalError("missing value for key: \(key)")
23+
}
24+
switch object {
25+
case let value as T:
26+
return value
27+
case let string as String:
28+
guard let value = T(string) else { fallthrough }
29+
return value
30+
default:
31+
fatalError("unexpected value: \(object) for key: \(key)")
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import Foundation
2+
3+
/// The container for Xcode previews.
4+
public struct BuildSettingsPreviewContainer: BuildSettingsContainer {
5+
public var brand: AppBrand = .jetpack
6+
public var appGroupName = "xcode_preview_group_name"
7+
public var appKeychainAccessGroup = "xcode_preview_app_keychain_access_group"
8+
9+
nonisolated(unsafe) static var shared = BuildSettingsPreviewContainer()
10+
}
11+
12+
extension BuildSettings {
13+
/// Updates the preview settings for the lifetime of the given closure.
14+
/// Reverts to the original settings when done.
15+
@MainActor
16+
public static func withSettings<T>(_ configure: (inout BuildSettingsPreviewContainer) -> Void, perform closure: () -> T) -> T {
17+
var container = BuildSettingsPreviewContainer.shared
18+
let original = container
19+
configure(&container)
20+
BuildSettingsPreviewContainer.shared = container
21+
let value = closure()
22+
BuildSettingsPreviewContainer.shared = original
23+
return value
24+
}
25+
26+
/// Runs the closure with given brand.
27+
@MainActor
28+
public static func withBrand<T>(_ brand: AppBrand, perform closure: () -> T) -> T {
29+
withSettings {
30+
$0.brand = brand
31+
} perform: {
32+
closure()
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,53 @@
11
import Foundation
22

3-
/// Provides convenient access for values defined in Info.plist files for
4-
/// apps and app extensions.
3+
public protocol BuildSettingsContainer: Sendable {
4+
var brand: AppBrand { get }
5+
var appGroupName: String { get }
6+
var appKeychainAccessGroup: String { get }
7+
}
8+
9+
public enum AppBrand: String, Sendable {
10+
case wordpress
11+
case jetpack
12+
}
13+
14+
/// Manages global build settings.
15+
///
16+
/// The build settings work differently depending on the environment:
17+
///
18+
/// - **Live** – the code runs as part of an app or app extensions with build
19+
/// settings configured using the `Info.plist` file.
20+
/// - **Preview** – the code runs as part of the SwiftPM or Xcode target. In this
21+
/// environment, the build settings have predefined values that can also be
22+
/// changed at runtime.
23+
/// - **Test** – `BuildSettings` are not available when running unit tests as
24+
/// they are incompatible with parallelized tests and are generally not recommended.
525
///
626
/// - warning: Most of these values exist only in Info.plist files for apps as
7-
/// app extensions only need a tiny subset of these settings.
27+
/// app extensions only need a tiny subset of the settings.
828
public enum BuildSettings {
9-
public static var appGroupName: String {
10-
infoPlistValue(forKey: "WPAppGroupName")
11-
}
12-
13-
public static var appKeychainAccessGroup: String {
14-
infoPlistValue(forKey: "WPAppKeychainAccessGroup")
29+
public static var current: BuildSettingsContainer {
30+
switch BuildSettingsEnvironment.current {
31+
case .live: BuildSettingsLiveContainer.shared
32+
case .preview: BuildSettingsPreviewContainer.shared
33+
}
1534
}
1635
}
1736

18-
private func infoPlistValue<T>(forKey key: String) -> T where T: LosslessStringConvertible {
19-
guard let object = Bundle.main.object(forInfoDictionaryKey: key) else {
20-
fatalError("missing value for key: \(key)")
21-
}
22-
switch object {
23-
case let value as T:
24-
return value
25-
case let string as String:
26-
guard let value = T(string) else { fallthrough }
27-
return value
28-
default:
29-
fatalError("unexpected value: \(object) for key: \(key)")
30-
}
37+
private enum BuildSettingsEnvironment {
38+
case live
39+
case preview
40+
41+
static let current: BuildSettingsEnvironment = {
42+
#if DEBUG
43+
let environment = ProcessInfo.processInfo.environment
44+
if environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
45+
return .preview
46+
}
47+
if NSClassFromString("XCTestCase") != nil {
48+
fatalError("BuildSettings are unavailable when running unit tests. Make sure to inject the values manually in system under test.")
49+
}
50+
#endif
51+
return .live
52+
}()
3153
}

Modules/Sources/DesignSystem/Components/DSButtonStyle.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import SwiftUI
2+
import BuildSettingsKit
23

34
public struct DSButtonStyle {
45
public enum Emphasis: CaseIterable {
@@ -17,7 +18,11 @@ public struct DSButtonStyle {
1718
public let size: Size
1819
public let isJetpack: Bool
1920

20-
public init(emphasis: Emphasis, size: Size, isJetpack: Bool) {
21+
public init(
22+
emphasis: Emphasis,
23+
size: Size,
24+
isJetpack: Bool = BuildSettings.current.brand == .jetpack
25+
) {
2126
self.emphasis = emphasis
2227
self.size = size
2328
self.isJetpack = isJetpack
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import UIKit
2+
import SwiftUI
3+
import ColorStudio
4+
import BuildSettingsKit
5+
6+
public enum UIAppColor {
7+
/// A tint color used in places like navigation bars.
8+
///
9+
/// - note: The Jetpack app uses
10+
public static var tint: UIColor {
11+
switch BuildSettings.current.brand {
12+
case .wordpress: primary
13+
case .jetpack: UIColor.label
14+
}
15+
}
16+
17+
public static var primary: UIColor {
18+
switch BuildSettings.current.brand {
19+
case .wordpress: UIColor(light: CSColor.Blue.base, dark: primary(.shade40))
20+
case .jetpack: UIColor(light: CSColor.JetpackGreen.shade(.shade40), dark: CSColor.JetpackGreen.shade(.shade30))
21+
}
22+
}
23+
24+
public static func primary(_ shade: ColorStudioShade) -> UIColor {
25+
switch BuildSettings.current.brand {
26+
case .wordpress: CSColor.Blue.shade(shade)
27+
case .jetpack: CSColor.JetpackGreen.shade(shade)
28+
}
29+
}
30+
}
31+
32+
extension UIAppColor {
33+
public static func accent(_ shade: ColorStudioShade) -> UIColor {
34+
CSColor.Pink.shade(shade)
35+
}
36+
37+
public static func error(_ shade: ColorStudioShade) -> UIColor {
38+
CSColor.Red.shade(shade)
39+
}
40+
41+
public static func warning(_ shade: ColorStudioShade) -> UIColor {
42+
CSColor.Yellow.shade(shade)
43+
}
44+
45+
public static func success(_ shade: ColorStudioShade) -> UIColor {
46+
CSColor.Green.shade(shade)
47+
}
48+
49+
public static func gray(_ shade: ColorStudioShade) -> UIColor {
50+
CSColor.Gray.shade(shade)
51+
}
52+
53+
public static func blue(_ shade: ColorStudioShade) -> UIColor {
54+
CSColor.Blue.shade(shade)
55+
}
56+
57+
public static func green(_ shade: ColorStudioShade) -> UIColor {
58+
CSColor.Green.shade(shade)
59+
}
60+
61+
public static func red(_ shade: ColorStudioShade) -> UIColor {
62+
CSColor.Red.shade(shade)
63+
}
64+
65+
public static func pink(_ shade: ColorStudioShade) -> UIColor {
66+
CSColor.Pink.shade(shade)
67+
}
68+
69+
public static func yellow(_ shade: ColorStudioShade) -> UIColor {
70+
CSColor.Yellow.shade(shade)
71+
}
72+
73+
public static func purple(_ shade: ColorStudioShade) -> UIColor {
74+
CSColor.Purple.shade(shade)
75+
}
76+
77+
public static func orange(_ shade: ColorStudioShade) -> UIColor {
78+
CSColor.Orange.shade(shade)
79+
}
80+
81+
public static func celadon(_ shade: ColorStudioShade) -> UIColor {
82+
CSColor.Celadon.shade(shade)
83+
}
84+
85+
public static func wordPressBlue(_ shade: ColorStudioShade) -> UIColor {
86+
CSColor.WordPressBlue.shade(shade)
87+
}
88+
89+
public static func jetpackGreen(_ shade: ColorStudioShade) -> UIColor {
90+
CSColor.JetpackGreen.shade(shade)
91+
}
92+
93+
public static let primaryLight: UIColor = primary(.shade30)
94+
public static let primaryDark: UIColor = primary(.shade70)
95+
96+
public static func neutral(_ shade: ColorStudioShade) -> UIColor {
97+
return switch shade {
98+
case .shade0: UIColor(light: gray(.shade0), dark: gray(.shade100))
99+
case .shade5: UIColor(light: gray(.shade5), dark: gray(.shade90))
100+
case .shade10: UIColor(light: gray(.shade10), dark: gray(.shade80))
101+
case .shade20: UIColor(light: gray(.shade20), dark: gray(.shade70))
102+
case .shade30: UIColor(light: gray(.shade30), dark: gray(.shade60))
103+
case .shade40: UIColor(light: gray(.shade40), dark: gray(.shade50))
104+
case .shade50: UIColor(light: gray(.shade50), dark: gray(.shade40))
105+
case .shade60: UIColor(light: gray(.shade60), dark: gray(.shade30))
106+
case .shade70: UIColor(light: gray(.shade70), dark: gray(.shade20))
107+
case .shade80: UIColor(light: gray(.shade80), dark: gray(.shade10))
108+
case .shade90: UIColor(light: gray(.shade90), dark: gray(.shade5))
109+
case .shade100: UIColor(light: gray(.shade100), dark: gray(.shade0))
110+
}
111+
}
112+
113+
public static let accent = CSColor.Pink.base
114+
public static let divider = CSColor.Gray.shade(.shade10)
115+
public static let error = CSColor.Red.base
116+
public static let gray = CSColor.Gray.base
117+
public static let blue = CSColor.Blue.base
118+
119+
public static let success = CSColor.Green.base
120+
public static let text = CSColor.Gray.shade(.shade80)
121+
public static let textSubtle = CSColor.Gray.shade(.shade50)
122+
public static let warning = CSColor.Yellow.base
123+
public static let jetpackGreen = CSColor.JetpackGreen.base
124+
public static let editorPrimary = CSColor.Blue.base
125+
public static let neutral = CSColor.Gray.base
126+
127+
public static let statsPrimaryHighlight = UIColor(light: accent(.shade30), dark: accent(.shade60))
128+
public static let statsSecondaryHighlight = UIColor(light: accent(.shade60), dark: accent(.shade30))
129+
130+
// TODO : These should be customized for WP and JP
131+
public static let appBarTint = UIColor.systemOrange
132+
public static let appBarText = UIColor.systemOrange
133+
134+
public static let placeholderElement = UIColor(light: .systemGray5, dark: .systemGray4)
135+
public static let placeholderElementFaded: UIColor = UIColor(light: .systemGray6, dark: .systemGray5)
136+
137+
public static let prologueBackground = UIColor(light: blue(.shade0), dark: .systemBackground)
138+
139+
public static let switchStyle: SwitchToggleStyle = SwitchToggleStyle(tint: Color(UIAppColor.primary))
140+
}
141+
142+
public enum AppColor {
143+
public static var tint: Color { Color(UIAppColor.tint) }
144+
public static var primary: Color { Color(UIAppColor.primary) }
145+
}
146+
147+
private extension UIColor {
148+
convenience init(light: UIColor, dark: UIColor) {
149+
self.init { traitCollection in
150+
if traitCollection.userInterfaceStyle == .dark {
151+
return dark
152+
} else {
153+
return light
154+
}
155+
}
156+
}
157+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@_exported import DesignSystem
2+
@_exported import AsyncImageKit
3+
@_exported import WordPressShared

WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColorsObjC.swift

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import UIKit
2+
import WordPressUI
3+
14
/// Objective-C *only* API for the Muriel colors
25
@objc extension UIColor {
36

WordPress/Classes/Extensions/Colors and Styles/UIColor+Notice.swift

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import UIKit
2+
import WordPressUI
3+
14
extension UIColor {
25

36
static var invertedSystem5: UIColor {

WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+Aztec.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import UIKit
2-
import Gridicons
32
import WordPressShared
3+
import WordPressUI
44

55
extension WPStyleGuide {
66
static let aztecFormatBarInactiveColor: UIColor = .secondaryLabel

WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+FilterTabBar.swift

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import UIKit
2+
import WordPressUI
23

34
extension WPStyleGuide {
45
@objc class func configureFilterTabBar(_ filterTabBar: FilterTabBar) {

0 commit comments

Comments
 (0)