From cc15bd4cba97ef6c4957f13a8db0e610ce50313c Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Wed, 8 Mar 2023 16:50:14 +0100 Subject: [PATCH 01/17] Add new "Primary Color" row to "App Settings" --- .../AppSettingsViewController.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index 78e0c560c4c1..32a30a4929ca 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -250,6 +250,17 @@ class AppSettingsViewController: UITableViewController { } } + func pushPrimaryColorPicker() -> ImmuTableAction { + return { [weak self] row in + let vc = UIColorPickerViewController() + vc.title = "Primary Color" + vc.view.backgroundColor = .listBackground + vc.supportsAlpha = false + + self?.navigationController?.pushViewController(vc, animated: true) + } + } + func pushAppIconSwitcher() -> ImmuTableAction { return { [weak self] row in let controller = AppIconViewController() @@ -501,6 +512,12 @@ private extension AppSettingsViewController { rows.insert(iconRow, at: 0) } + let primaryColorRow = NavigationItemRow( + title: NSLocalizedString("Primary Color", comment: "Navigates to color picker screen to change the app's primary color"), + action: pushPrimaryColorPicker() + ) + rows.insert(primaryColorRow, at: 0) + if JetpackFeaturesRemovalCoordinator.jetpackFeaturesEnabled() { let initialScreen = NavigationItemRow(title: NSLocalizedString("Initial Screen", comment: "Title of the option to change the default initial screen"), detail: MySiteSettings().defaultSection.title, action: pushInitialScreenSettings()) From 385ded03aae6cdf2d55c2026d2d42197a93ac4b5 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Wed, 8 Mar 2023 17:35:11 +0100 Subject: [PATCH 02/17] Create and integrate `SwiftUIRow` (`ImmuTableRow` with SwiftUI content) using native `ColorPicker` --- .../Classes/Utility/WPImmuTableRows.swift | 33 ++++++++++++++++- .../AppSettingsViewController.swift | 37 ++++++++++--------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/WordPress/Classes/Utility/WPImmuTableRows.swift b/WordPress/Classes/Utility/WPImmuTableRows.swift index 25bf3ea1ab98..3e8fc8dc10c7 100644 --- a/WordPress/Classes/Utility/WPImmuTableRows.swift +++ b/WordPress/Classes/Utility/WPImmuTableRows.swift @@ -1,7 +1,7 @@ import Foundation import WordPressShared import Gridicons - +import SwiftUI struct NavigationItemRow: ImmuTableRow { static let cell = ImmuTableCell.class(WPTableViewCellValue1.self) @@ -451,3 +451,34 @@ class ExpandableRow: ImmuTableRow { cell.urlCallback = onLinkTap } } + +struct SwiftUIRow: ImmuTableRow { + static var cell: ImmuTableCell { + .class(WPTableViewCellDefault.self) + } + + var action: ImmuTableAction? + var content: () -> T + + func configureCell(_ cell: UITableViewCell) { + if #available(iOS 16.0, *) { + cell.contentConfiguration = UIHostingConfiguration { + content() + } + } else { + cell.contentView.subviews.forEach { $0.removeFromSuperview() } + + let host = UIHostingController(rootView: content()) + host.view.backgroundColor = .clear + host.view.translatesAutoresizingMaskIntoConstraints = false + + cell.contentView.addSubview(host.view) + NSLayoutConstraint.activate([ + host.view.leadingAnchor.constraint(equalTo: cell.layoutMarginsGuide.leadingAnchor), + host.view.trailingAnchor.constraint(equalTo: cell.layoutMarginsGuide.trailingAnchor), + host.view.topAnchor.constraint(equalTo: cell.layoutMarginsGuide.topAnchor), + host.view.bottomAnchor.constraint(equalTo: cell.layoutMarginsGuide.bottomAnchor) + ]) + } + } +} diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index 32a30a4929ca..aea88c68b8b9 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -4,6 +4,7 @@ import Gridicons import WordPressShared import SVProgressHUD import WordPressFlux +import SwiftUI class AppSettingsViewController: UITableViewController { enum Sections: Int { @@ -250,17 +251,6 @@ class AppSettingsViewController: UITableViewController { } } - func pushPrimaryColorPicker() -> ImmuTableAction { - return { [weak self] row in - let vc = UIColorPickerViewController() - vc.title = "Primary Color" - vc.view.backgroundColor = .listBackground - vc.supportsAlpha = false - - self?.navigationController?.pushViewController(vc, animated: true) - } - } - func pushAppIconSwitcher() -> ImmuTableAction { return { [weak self] row in let controller = AppIconViewController() @@ -507,17 +497,16 @@ private extension AppSettingsViewController { var rows: [ImmuTableRow] = [settingsRow] + let appColorRow = SwiftUIRow { + AppColorPicker() + } + rows.insert(appColorRow, at: 0) + if AppConfiguration.allowsCustomAppIcons && UIApplication.shared.supportsAlternateIcons { // We don't show custom icons for Jetpack rows.insert(iconRow, at: 0) } - let primaryColorRow = NavigationItemRow( - title: NSLocalizedString("Primary Color", comment: "Navigates to color picker screen to change the app's primary color"), - action: pushPrimaryColorPicker() - ) - rows.insert(primaryColorRow, at: 0) - if JetpackFeaturesRemovalCoordinator.jetpackFeaturesEnabled() { let initialScreen = NavigationItemRow(title: NSLocalizedString("Initial Screen", comment: "Title of the option to change the default initial screen"), detail: MySiteSettings().defaultSection.title, action: pushInitialScreenSettings()) @@ -547,6 +536,20 @@ private extension AppSettingsViewController { } } +/// - TODO: move somewhere else later +struct AppColorPicker: View { + @State private var color = Color(.sRGB, red: 0.98, green: 0.9, blue: 0.2) + + var body: some View { + ColorPicker(title, selection: $color, supportsOpacity: false) + .font(.callout) + } + + private var title: String { + NSLocalizedString("App Color", comment: "Navigates to color picker screen to change the app's primary color") + } +} + // MARK: - Jetpack powered badge extension AppSettingsViewController { From 87e7be1531c74daa8038f5d365a29659e414cdc4 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Wed, 8 Mar 2023 21:01:16 +0100 Subject: [PATCH 03/17] Add "Reset" button to `ColorPicker` + selection style to `SwiftUIRow` --- .../Classes/Utility/WPImmuTableRows.swift | 3 +++ .../AppSettingsViewController.swift | 25 +++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/WordPress/Classes/Utility/WPImmuTableRows.swift b/WordPress/Classes/Utility/WPImmuTableRows.swift index 3e8fc8dc10c7..43112782a6fc 100644 --- a/WordPress/Classes/Utility/WPImmuTableRows.swift +++ b/WordPress/Classes/Utility/WPImmuTableRows.swift @@ -457,10 +457,13 @@ struct SwiftUIRow: ImmuTableRow { .class(WPTableViewCellDefault.self) } + var selectionStyle: UITableViewCell.SelectionStyle = .default var action: ImmuTableAction? var content: () -> T func configureCell(_ cell: UITableViewCell) { + cell.selectionStyle = selectionStyle + if #available(iOS 16.0, *) { cell.contentConfiguration = UIHostingConfiguration { content() diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index aea88c68b8b9..b6a653cddee8 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -497,7 +497,7 @@ private extension AppSettingsViewController { var rows: [ImmuTableRow] = [settingsRow] - let appColorRow = SwiftUIRow { + let appColorRow = SwiftUIRow(selectionStyle: .none) { AppColorPicker() } rows.insert(appColorRow, at: 0) @@ -541,12 +541,27 @@ struct AppColorPicker: View { @State private var color = Color(.sRGB, red: 0.98, green: 0.9, blue: 0.2) var body: some View { - ColorPicker(title, selection: $color, supportsOpacity: false) - .font(.callout) + ColorPicker(selection: $color, supportsOpacity: false) { + HStack { + Text(colorPickerTitle) + + Spacer() + Button(action: { + print("reset app color") + }, label: { + Text(resetButtonTitle) + }) + } + } + .font(.callout) + } + + private var colorPickerTitle: String { + NSLocalizedString("App Color", comment: "Navigates to color picker screen to change the app primary color") } - private var title: String { - NSLocalizedString("App Color", comment: "Navigates to color picker screen to change the app's primary color") + private var resetButtonTitle: String { + NSLocalizedString("Reset", comment: "Restores default app primary color") } } From 3d5c0d3a5ece5e82ab8b3072ff0c5c3c48277074 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Thu, 9 Mar 2023 15:12:07 +0100 Subject: [PATCH 04/17] Add initial `AppColor` helper + view model + refactor view into a separate file --- .../Me/App Settings/App Color/AppColor.swift | 53 +++++++++++++++++++ .../App Color/AppColorPickerView.swift | 36 +++++++++++++ .../App Color/AppColorPickerViewModel.swift | 22 ++++++++ .../AppSettingsViewController.swift | 31 +---------- WordPress/WordPress.xcodeproj/project.pbxproj | 20 +++++++ 5 files changed, 132 insertions(+), 30 deletions(-) create mode 100644 WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift create mode 100644 WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift create mode 100644 WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift new file mode 100644 index 000000000000..d7ea0f1e383c --- /dev/null +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -0,0 +1,53 @@ +import SwiftUI + +enum AppColor { + + static private(set) var color: Color = savedColor ?? defaultColor { + didSet { + savedColor = color + } + } + + static var uiColor: UIColor { + .init(color) + } + + static var defaultColor: Color { + if AppConfiguration.isWordPress { + return Color(UIColor.muriel(color: .init(name: .wordPressBlue))) + } else if AppConfiguration.isJetpack { + return Color(UIColor.muriel(color: .init(name: .jetpackGreen))) + } else { + assertionFailure("unsupported configuration") + return .red + } + } + + static func update(with newColor: Color) { + color = newColor + } + + private static var savedColor: Color? { + get { + guard + let components = defaults.array(forKey: defaultsKey) as? [CGFloat], !components.isEmpty, + let cgColorSpace: CGColorSpace = .init(name: CGColorSpace.sRGB), + let cgColor = CGColor(colorSpace: cgColorSpace, components: components) + else { + return nil + } + return Color(cgColor) + } + set { + let components = newValue?.cgColor?.components ?? [] + defaults.set(components, forKey: defaultsKey) + } + } + + private static var defaults: UserDefaults { + .init(suiteName: WPAppGroupName) ?? .standard + } + + private static let defaultsKey = "AppColorComponents" + +} diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift new file mode 100644 index 000000000000..a4b451dff98e --- /dev/null +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift @@ -0,0 +1,36 @@ +import SwiftUI + +struct AppColorPickerView: View { + + @StateObject var vm = AppColorPickerViewModel() + + var body: some View { + ColorPicker(selection: $vm.color, supportsOpacity: false) { + HStack { + Text(colorPickerTitle) + + Spacer() + Button(action: { + vm.restoreDefaultColor() + }, label: { + Text(resetButtonTitle) + }) + } + } + .font(.callout) + } + + private var colorPickerTitle: String { + NSLocalizedString("App Color", comment: "Navigates to color picker screen to change the app primary color") + } + + private var resetButtonTitle: String { + NSLocalizedString("Reset", comment: "Restores default app primary color") + } +} + +struct AppColorPickerView_Previews: PreviewProvider { + static var previews: some View { + AppColorPickerView() + } +} diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift new file mode 100644 index 000000000000..bf8ab4d55ed9 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift @@ -0,0 +1,22 @@ +import SwiftUI + +final class AppColorPickerViewModel: ObservableObject { + + @Published var color = AppColor.color { + didSet { + if color != oldValue { + updateAppColor(color) + } + } + } + + func restoreDefaultColor() { + color = AppColor.defaultColor + } + + private func updateAppColor(_ color: Color) { + AppColor.update(with: color) + /// - TODO: update app ui + } + +} diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index b6a653cddee8..96a82aa60f88 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -498,7 +498,7 @@ private extension AppSettingsViewController { var rows: [ImmuTableRow] = [settingsRow] let appColorRow = SwiftUIRow(selectionStyle: .none) { - AppColorPicker() + AppColorPickerView() } rows.insert(appColorRow, at: 0) @@ -536,35 +536,6 @@ private extension AppSettingsViewController { } } -/// - TODO: move somewhere else later -struct AppColorPicker: View { - @State private var color = Color(.sRGB, red: 0.98, green: 0.9, blue: 0.2) - - var body: some View { - ColorPicker(selection: $color, supportsOpacity: false) { - HStack { - Text(colorPickerTitle) - - Spacer() - Button(action: { - print("reset app color") - }, label: { - Text(resetButtonTitle) - }) - } - } - .font(.callout) - } - - private var colorPickerTitle: String { - NSLocalizedString("App Color", comment: "Navigates to color picker screen to change the app primary color") - } - - private var resetButtonTitle: String { - NSLocalizedString("Reset", comment: "Restores default app primary color") - } -} - // MARK: - Jetpack powered badge extension AppSettingsViewController { diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 505350ebb05e..60359a6e327e 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2055,6 +2055,9 @@ 8B939F4323832E5D00ACCB0F /* PostListViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B939F4223832E5D00ACCB0F /* PostListViewControllerTests.swift */; }; 8BA125EB27D8F5E4008B779F /* UIView+PinSubviewPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA125EA27D8F5E4008B779F /* UIView+PinSubviewPriority.swift */; }; 8BA125EC27D8F5E4008B779F /* UIView+PinSubviewPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA125EA27D8F5E4008B779F /* UIView+PinSubviewPriority.swift */; }; + 8BA6F7BC29B9F8D000026408 /* AppColorPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */; }; + 8BA6F7BE29BA19F200026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; + 8BA6F7C029BA1A0000026408 /* AppColorPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */; }; 8BA77BCB2482C52A00E1EBBF /* ReaderCardDiscoverAttributionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8BA77BCA2482C52A00E1EBBF /* ReaderCardDiscoverAttributionView.xib */; }; 8BA77BCD248340CE00E1EBBF /* ReaderDetailToolbar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8BA77BCC248340CE00E1EBBF /* ReaderDetailToolbar.xib */; }; 8BA77BCF2483415400E1EBBF /* ReaderDetailToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA77BCE2483415400E1EBBF /* ReaderDetailToolbar.swift */; }; @@ -7295,6 +7298,9 @@ 8B93856D22DC08060010BF02 /* PageListSectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageListSectionHeaderView.swift; sourceTree = ""; }; 8B939F4223832E5D00ACCB0F /* PostListViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostListViewControllerTests.swift; sourceTree = ""; }; 8BA125EA27D8F5E4008B779F /* UIView+PinSubviewPriority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+PinSubviewPriority.swift"; sourceTree = ""; }; + 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppColorPickerView.swift; sourceTree = ""; }; + 8BA6F7BD29BA19F200026408 /* AppColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppColor.swift; sourceTree = ""; }; + 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppColorPickerViewModel.swift; sourceTree = ""; }; 8BA77BCA2482C52A00E1EBBF /* ReaderCardDiscoverAttributionView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderCardDiscoverAttributionView.xib; sourceTree = ""; }; 8BA77BCC248340CE00E1EBBF /* ReaderDetailToolbar.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderDetailToolbar.xib; sourceTree = ""; }; 8BA77BCE2483415400E1EBBF /* ReaderDetailToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderDetailToolbar.swift; sourceTree = ""; }; @@ -10748,6 +10754,7 @@ 3F29EB6E240420C3005313DE /* App Settings */ = { isa = PBXGroup; children = ( + 8BA6F7BA29B9F8B400026408 /* App Color */, F44293D428E3B39400D340AF /* App Icons */, 3F29EB6824041F6D005313DE /* About */, FFA162301CB7031A00E2E110 /* AppSettingsViewController.swift */, @@ -13410,6 +13417,16 @@ path = Filter; sourceTree = ""; }; + 8BA6F7BA29B9F8B400026408 /* App Color */ = { + isa = PBXGroup; + children = ( + 8BA6F7BD29BA19F200026408 /* AppColor.swift */, + 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */, + 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */, + ); + path = "App Color"; + sourceTree = ""; + }; 8BADF16324801B4B005AD038 /* Detail */ = { isa = PBXGroup; children = ( @@ -21136,6 +21153,7 @@ 3FB1929526C79EC6000F5AA3 /* Date+TimeStrings.swift in Sources */, 178DDD57266E4165006C68C4 /* CalendarDayToggleButton.swift in Sources */, 73ACDF992114FE4500233AD4 /* NotificationSupportService.swift in Sources */, + 8BA6F7C029BA1A0000026408 /* AppColorPickerViewModel.swift in Sources */, 08D345531CD7F50900358E8C /* MenusSelectionView.m in Sources */, 5D6C4B131B604190005E3C43 /* UITextView+RichTextView.swift in Sources */, E15644E91CE0E47C00D96E64 /* RoundedButton.swift in Sources */, @@ -21506,6 +21524,7 @@ 93C4864F181043D700A24725 /* ActivityLogDetailViewController.m in Sources */, B57B99DE19A2DBF200506504 /* NSObject+Helpers.m in Sources */, E1E49CE41C4902EE002393A4 /* ImmuTableViewController.swift in Sources */, + 8BA6F7BC29B9F8D000026408 /* AppColorPickerView.swift in Sources */, D88A6496208D7B0B008AE9BC /* NullStockPhotosService.swift in Sources */, 9A162F2321C26D7500FDC035 /* RevisionPreviewViewController.swift in Sources */, 467D3DFA25E4436000EB9CB0 /* SitePromptView.swift in Sources */, @@ -21797,6 +21816,7 @@ C81CCD82243BF7A600A83E27 /* TenorResultsPage.swift in Sources */, FACB36F11C5C2BF800C6DF4E /* ThemeWebNavigationDelegate.swift in Sources */, E1F47D4D1FE0290C00C1D44E /* PluginListCell.swift in Sources */, + 8BA6F7BE29BA19F200026408 /* AppColor.swift in Sources */, 3F5C865D25C9EBEF00BABE64 /* HomeWidgetAllTimeData.swift in Sources */, D829C33B21B12EFE00B09F12 /* UIView+Borders.swift in Sources */, F1A75B9B2732EF3700784A70 /* AboutScreenTracker.swift in Sources */, From 807093cc3d96ebbbc2d181b3cc88862c6a8ee922 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Fri, 10 Mar 2023 13:32:20 +0100 Subject: [PATCH 05/17] Add new files to "Jetpack" target + minor fixes and improvements --- .../Me/App Settings/App Color/AppColor.swift | 43 ++++++++++++++++--- WordPress/WordPress.xcodeproj/project.pbxproj | 6 +++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index d7ea0f1e383c..7243720088ba 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -2,6 +2,8 @@ import SwiftUI enum AppColor { + // MARK: API + static private(set) var color: Color = savedColor ?? defaultColor { didSet { savedColor = color @@ -13,12 +15,12 @@ enum AppColor { } static var defaultColor: Color { - if AppConfiguration.isWordPress { - return Color(UIColor.muriel(color: .init(name: .wordPressBlue))) - } else if AppConfiguration.isJetpack { - return Color(UIColor.muriel(color: .init(name: .jetpackGreen))) - } else { - assertionFailure("unsupported configuration") + switch appConfig { + case .wordpress: + return .muriel(.wordPressBlue) + case .jetpack: + return .muriel(.jetpackGreen) + case .unknown: return .red } } @@ -27,6 +29,8 @@ enum AppColor { color = newColor } + // MARK: Helpers + private static var savedColor: Color? { get { guard @@ -48,6 +52,31 @@ enum AppColor { .init(suiteName: WPAppGroupName) ?? .standard } - private static let defaultsKey = "AppColorComponents" + private static var defaultsKey: String { + "\(appConfig.rawValue).AppColorComponents" + } + private static var appConfig: AppConfig { + if AppConfiguration.isWordPress { + return .wordpress + } else if AppConfiguration.isJetpack { + return .jetpack + } else { + assertionFailure("unsupported configuration") + return .unknown + } + } + + private enum AppConfig: String { + case wordpress = "Wordpress" + case jetpack = "Jetpack" + case unknown = "Unknown" + } + +} + +private extension Color { + static func muriel(_ name: MurielColorName) -> Self { + .init(UIColor.muriel(color: .init(name: name))) + } } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 60359a6e327e..eb39961d319c 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2058,6 +2058,9 @@ 8BA6F7BC29B9F8D000026408 /* AppColorPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */; }; 8BA6F7BE29BA19F200026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; 8BA6F7C029BA1A0000026408 /* AppColorPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */; }; + 8BA6F7C429BB54D000026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; + 8BA6F7C529BB54D400026408 /* AppColorPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */; }; + 8BA6F7C629BB54D800026408 /* AppColorPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */; }; 8BA77BCB2482C52A00E1EBBF /* ReaderCardDiscoverAttributionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8BA77BCA2482C52A00E1EBBF /* ReaderCardDiscoverAttributionView.xib */; }; 8BA77BCD248340CE00E1EBBF /* ReaderDetailToolbar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8BA77BCC248340CE00E1EBBF /* ReaderDetailToolbar.xib */; }; 8BA77BCF2483415400E1EBBF /* ReaderDetailToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA77BCE2483415400E1EBBF /* ReaderDetailToolbar.swift */; }; @@ -23531,6 +23534,7 @@ FABB21A32602FC2C00C8785C /* CommentsViewController.m in Sources */, FABB21A42602FC2C00C8785C /* SiteSettingsViewController+SiteManagement.swift in Sources */, FABB21A52602FC2C00C8785C /* Follow.swift in Sources */, + 8BA6F7C529BB54D400026408 /* AppColorPickerView.swift in Sources */, FABB21A62602FC2C00C8785C /* BlogJetpackSettingsService.swift in Sources */, FABB21A72602FC2C00C8785C /* MenuItemTypeViewController.m in Sources */, 80535DC3294BDE2B00873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift in Sources */, @@ -24642,6 +24646,7 @@ FABB24F42602FC2C00C8785C /* NoticePresenter.swift in Sources */, FABB24F52602FC2C00C8785C /* ReaderTagTopic.swift in Sources */, FABB24F62602FC2C00C8785C /* Media.swift in Sources */, + 8BA6F7C629BB54D800026408 /* AppColorPickerViewModel.swift in Sources */, 9839CEBC26FAA0530097406E /* CommentModerationBar.swift in Sources */, 837966A3299E9C85004A92B9 /* JetpackInstallPluginHelper.swift in Sources */, 17039227282E6DF500F602E9 /* ViewsVisitorsChartMarker.swift in Sources */, @@ -24956,6 +24961,7 @@ FABB25DC2602FC2C00C8785C /* ThemeIdHelper.swift in Sources */, FABB25DD2602FC2C00C8785C /* BottomScrollAnalyticsTracker.swift in Sources */, FABB25DE2602FC2C00C8785C /* UserProfile.swift in Sources */, + 8BA6F7C429BB54D000026408 /* AppColor.swift in Sources */, FABB25DF2602FC2C00C8785C /* PickerTableViewCell.swift in Sources */, FABB25E02602FC2C00C8785C /* StoryEditor.swift in Sources */, 2481B180260D4D4E00AE59DB /* WPAccount+Lookup.swift in Sources */, From 73e24aba414ff9b4dba2f58c85c412da5dcfa6ad Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Fri, 10 Mar 2023 15:43:38 +0100 Subject: [PATCH 06/17] Make initial proof of concept for using `AppColor` as `primary` color --- .../Colors and Styles/UIColor+MurielColors.swift | 6 +++++- .../App Color/AppColorPickerViewModel.swift | 7 ++++++- WordPress/WordPress.xcodeproj/project.pbxproj | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift b/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift index e650c89b521a..5add42f04a84 100644 --- a/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift +++ b/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift @@ -55,7 +55,11 @@ extension UIColor { } /// Muriel primary color - static var primary = muriel(color: .primary) + static var primary: UIColor { + AppColor.uiColor + } + /// - TODO: cleanup later +// static var primary = muriel(color: .primary) static var primaryLight = muriel(color: .primary, .shade30) static var primaryDark = muriel(color: .primary, .shade70) class func primary(_ shade: MurielColorShade) -> UIColor { diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift index bf8ab4d55ed9..a5655e47ac8e 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift @@ -16,7 +16,12 @@ final class AppColorPickerViewModel: ObservableObject { private func updateAppColor(_ color: Color) { AppColor.update(with: color) - /// - TODO: update app ui + + let appDelegate = UIApplication.shared.delegate as? WordPressAppDelegate + appDelegate?.customizeAppearance() + + /// - TODO: at this point some parts of the UI still use the previous color + /// find a way to update all UI globally when user changes "App Color" in Settings 🤔 } } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index eb39961d319c..120fb5b8a5ad 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2061,6 +2061,13 @@ 8BA6F7C429BB54D000026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; 8BA6F7C529BB54D400026408 /* AppColorPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */; }; 8BA6F7C629BB54D800026408 /* AppColorPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */; }; + 8BA6F7C729BB6B4900026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; + 8BA6F7C829BB6B4A00026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; + 8BA6F7C929BB6B4A00026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; + 8BA6F7CA29BB6B4B00026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; + 8BA6F7CB29BB6B5300026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; + 8BA6F7CC29BB6B5400026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; + 8BA6F7CD29BB6B5400026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; 8BA77BCB2482C52A00E1EBBF /* ReaderCardDiscoverAttributionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8BA77BCA2482C52A00E1EBBF /* ReaderCardDiscoverAttributionView.xib */; }; 8BA77BCD248340CE00E1EBBF /* ReaderDetailToolbar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8BA77BCC248340CE00E1EBBF /* ReaderDetailToolbar.xib */; }; 8BA77BCF2483415400E1EBBF /* ReaderDetailToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA77BCE2483415400E1EBBF /* ReaderDetailToolbar.swift */; }; @@ -20417,6 +20424,7 @@ 0107E0BF28F97D5000DE87DB /* FeatureFlagOverrideStore.swift in Sources */, 0107E11528FD7FE500DE87DB /* AppConfiguration.swift in Sources */, 0107E0C028F97D5000DE87DB /* WordPressHomeWidgetToday.swift in Sources */, + 8BA6F7CD29BB6B5400026408 /* AppColor.swift in Sources */, 0107E0C128F97D5000DE87DB /* FlexibleCard.swift in Sources */, 0107E0C228F97D5000DE87DB /* VerticalCard.swift in Sources */, 0107E0C328F97D5000DE87DB /* ThisWeekWidgetStats.swift in Sources */, @@ -22274,6 +22282,7 @@ 3F6BC05C25B24773007369D3 /* FeatureFlagOverrideStore.swift in Sources */, 3FD675EA25C87A25009AB3C1 /* WordPressHomeWidgetToday.swift in Sources */, 3F568A2F254216550048A9E4 /* FlexibleCard.swift in Sources */, + 8BA6F7C929BB6B4A00026408 /* AppColor.swift in Sources */, 3F568A1F254213B60048A9E4 /* VerticalCard.swift in Sources */, 3F8B306825D1D4B8005A2903 /* ThisWeekWidgetStats.swift in Sources */, 3F5C861A25C9EA2500BABE64 /* HomeWidgetAllTimeData.swift in Sources */, @@ -22384,6 +22393,7 @@ 433ADC1B223B2A7E00ED9DE1 /* TextBundleWrapper.m in Sources */, 4326191622FCB9F8003C7642 /* MurielColor.swift in Sources */, 73B05D2921374F1E0073ECAA /* Constants.m in Sources */, + 8BA6F7CA29BB6B4B00026408 /* AppColor.swift in Sources */, 736584EB2137533A0029C9A4 /* NotificationContentView.swift in Sources */, 73D5AC63212622B200ADDDD2 /* NotificationViewController.swift in Sources */, 436110DE22C41B02000773AD /* BuildConfiguration.swift in Sources */, @@ -22484,6 +22494,7 @@ 74021A1E202E164D006CC39F /* CocoaLumberjack.swift in Sources */, 74E44AD52031E83C00556205 /* ExtensionNotificationManager.swift in Sources */, 74448F552044BC7600BD4CDA /* CategoryTree.swift in Sources */, + 8BA6F7C829BB6B4A00026408 /* AppColor.swift in Sources */, FAD2539126116A1600EDAF88 /* AppStyleGuide.swift in Sources */, 74021A09202E1323006CC39F /* ShareSegueHandler.swift in Sources */, 74021A01202E12F4006CC39F /* SharedCoreDataStack.swift in Sources */, @@ -22560,6 +22571,7 @@ 809620EF28E540D700940A5D /* ExtensionPresentationAnimator.swift in Sources */, 809620F028E540D700940A5D /* String+RegEx.swift in Sources */, 809620F128E540D700940A5D /* AppStyleGuide.swift in Sources */, + 8BA6F7CB29BB6B5300026408 /* AppColor.swift in Sources */, 809620F228E540D700940A5D /* CocoaLumberjack.swift in Sources */, 809620F328E540D700940A5D /* SharedCoreDataStack.swift in Sources */, 809620F428E540D700940A5D /* ShareExtensionAbstractViewController.swift in Sources */, @@ -22636,6 +22648,7 @@ 8096215028E55C9400940A5D /* ExtensionNotificationManager.swift in Sources */, 8096215128E55C9400940A5D /* CategoryTree.swift in Sources */, 8096215228E55C9400940A5D /* AppStyleGuide.swift in Sources */, + 8BA6F7CC29BB6B5400026408 /* AppColor.swift in Sources */, 8096215328E55C9400940A5D /* ShareSegueHandler.swift in Sources */, 8096215428E55C9400940A5D /* SharedCoreDataStack.swift in Sources */, 8096215528E55C9400940A5D /* FeatureFlagOverrideStore.swift in Sources */, @@ -22776,6 +22789,7 @@ 4020B2BE2007AC850002C963 /* WPStyleGuide+Gridicon.swift in Sources */, 74402F2E2005344700A1D4A2 /* ExtensionPresentationAnimator.swift in Sources */, 74D06FE91FE0782000AF1788 /* String+RegEx.swift in Sources */, + 8BA6F7C729BB6B4900026408 /* AppColor.swift in Sources */, FAD2539026116A1600EDAF88 /* AppStyleGuide.swift in Sources */, 938CF3DD1EF1BE7F00AF838E /* CocoaLumberjack.swift in Sources */, 746D6B251FBF701F003C45BE /* SharedCoreDataStack.swift in Sources */, From 15a20bfcb133a9a9498cc7136bdd84d301691a4d Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Mon, 13 Mar 2023 11:09:45 +0100 Subject: [PATCH 07/17] Reorganize sections & rows in "App Settings" according to the feedback from P2 --- .../App Color/AppColorPickerView.swift | 2 +- .../AppSettingsViewController.swift | 80 +++++++++++-------- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift index a4b451dff98e..9637ff2ca63f 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift @@ -21,7 +21,7 @@ struct AppColorPickerView: View { } private var colorPickerTitle: String { - NSLocalizedString("App Color", comment: "Navigates to color picker screen to change the app primary color") + NSLocalizedString("Accent Color", comment: "Navigates to color picker screen to change the app accent color") } private var resetButtonTitle: String { diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index 96a82aa60f88..9bf040d33a88 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -82,6 +82,7 @@ class AppSettingsViewController: UITableViewController { let tableSections = [ mediaTableSection(), privacyTableSection(), + appearanceTableSection(), otherTableSection() ] return ImmuTable(optionalSections: tableSections) @@ -204,7 +205,7 @@ class AppSettingsViewController: UITableViewController { } } - func pushAppearanceSettings() -> ImmuTableAction { + func pushColorModeSettings() -> ImmuTableAction { return { [weak self] row in let values = UIUserInterfaceStyle.allStyles @@ -476,63 +477,78 @@ private extension AppSettingsViewController { ) } - func otherTableSection() -> ImmuTableSection { - let otherHeader = NSLocalizedString("Other", comment: "Link to About section (contains info about the app)") + func appearanceTableSection() -> ImmuTableSection { + var rows: [ImmuTableRow] = [] - let debugRow = NavigationItemRow( - title: NSLocalizedString("Debug", comment: "Navigates to debug menu only available in development builds"), - icon: .gridicon(.bug), - action: pushDebugMenu() + let colorModeRow = NavigationItemRow( + title: NSLocalizedString("Color Mode", comment: "The title of the app color mode settings screen"), + detail: AppAppearance.current.appearanceDescription, + action: pushColorModeSettings() ) + rows.append(colorModeRow) + + if AppConfiguration.allowsCustomAppIcons && UIApplication.shared.supportsAlternateIcons { + let appIconRow = NavigationItemRow( + title: NSLocalizedString("App Icon", comment: "Navigates to picker screen to change the app's icon"), + action: pushAppIconSwitcher() + ) + rows.append(appIconRow) + } - let iconRow = NavigationItemRow( - title: NSLocalizedString("App Icon", comment: "Navigates to picker screen to change the app's icon"), - action: pushAppIconSwitcher() + let appColorRow = SwiftUIRow(selectionStyle: .none) { + AppColorPickerView() + } + rows.append(appColorRow) + + return ImmuTableSection( + headerText: NSLocalizedString("Appearance", comment: "The title of the app appearance settings section"), + rows: rows, + footerText: nil ) + } + + func otherTableSection() -> ImmuTableSection { + var rows: [ImmuTableRow] = [] let settingsRow = NavigationItemRow( title: NSLocalizedString("Open Device Settings", comment: "Opens iOS's Device Settings for WordPress App"), action: openApplicationSettings() ) - - var rows: [ImmuTableRow] = [settingsRow] - - let appColorRow = SwiftUIRow(selectionStyle: .none) { - AppColorPickerView() - } - rows.insert(appColorRow, at: 0) - - if AppConfiguration.allowsCustomAppIcons && UIApplication.shared.supportsAlternateIcons { - // We don't show custom icons for Jetpack - rows.insert(iconRow, at: 0) - } + rows.append(settingsRow) if JetpackFeaturesRemovalCoordinator.jetpackFeaturesEnabled() { - let initialScreen = NavigationItemRow(title: NSLocalizedString("Initial Screen", comment: "Title of the option to change the default initial screen"), detail: MySiteSettings().defaultSection.title, action: pushInitialScreenSettings()) - + let initialScreen = NavigationItemRow( + title: NSLocalizedString("Initial Screen", comment: "Title of the option to change the default initial screen"), + detail: MySiteSettings().defaultSection.title, + action: pushInitialScreenSettings() + ) rows.append(initialScreen) } if FeatureFlag.debugMenu.enabled { + let debugRow = NavigationItemRow( + title: NSLocalizedString("Debug", comment: "Navigates to debug menu only available in development builds"), + icon: .gridicon(.bug), + action: pushDebugMenu() + ) rows.append(debugRow) } if let presenter = RootViewCoordinator.shared.whatIsNewScenePresenter as? WhatIsNewScenePresenter, presenter.versionHasAnnouncements, AppConfiguration.showsWhatIsNew { - let whatIsNewRow = NavigationItemRow(title: AppConstants.Settings.whatIsNewTitle, - action: presentWhatIsNew()) + let whatIsNewRow = NavigationItemRow( + title: AppConstants.Settings.whatIsNewTitle, + action: presentWhatIsNew() + ) rows.append(whatIsNewRow) } - let appearanceRow = NavigationItemRow(title: NSLocalizedString("Appearance", comment: "The title of the app appearance settings screen"), detail: AppAppearance.current.appearanceDescription, action: pushAppearanceSettings()) - - rows.insert(appearanceRow, at: 0) - return ImmuTableSection( - headerText: otherHeader, + headerText: NSLocalizedString("Other", comment: "Link to About section (contains info about the app)"), rows: rows, - footerText: nil) + footerText: nil + ) } } From 92ae312b6bf28b69fd4b600c22ce5aec30a576fe Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Mon, 13 Mar 2023 14:26:32 +0100 Subject: [PATCH 08/17] Replace custom color picker with predefined colors list (as discussed in P2 feedback) --- .../UIColor+MurielColors.swift | 2 +- .../Me/App Settings/App Color/AppColor.swift | 102 +++++++++++++----- .../App Color/AppColorListView.swift | 68 ++++++++++++ .../App Color/AppColorPickerView.swift | 36 ------- .../App Color/AppColorPickerViewModel.swift | 27 ----- .../AppSettingsViewController.swift | 20 +++- WordPress/WordPress.xcodeproj/project.pbxproj | 18 ++-- 7 files changed, 166 insertions(+), 107 deletions(-) create mode 100644 WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift delete mode 100644 WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift delete mode 100644 WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift diff --git a/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift b/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift index 5add42f04a84..b473674b10dc 100644 --- a/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift +++ b/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift @@ -56,7 +56,7 @@ extension UIColor { /// Muriel primary color static var primary: UIColor { - AppColor.uiColor + UIColor(AppColor.accentColor) } /// - TODO: cleanup later // static var primary = muriel(color: .primary) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index 7243720088ba..d58ece9fa631 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -2,49 +2,44 @@ import SwiftUI enum AppColor { + enum Accent: String, CaseIterable { + case `default` + case green + case blue + case orange + case purple + case pink + } + // MARK: API - static private(set) var color: Color = savedColor ?? defaultColor { + static private(set) var accent: Accent = savedAccent ?? .default { didSet { - savedColor = color + savedAccent = accent } } - static var uiColor: UIColor { - .init(color) - } - - static var defaultColor: Color { - switch appConfig { - case .wordpress: - return .muriel(.wordPressBlue) - case .jetpack: - return .muriel(.jetpackGreen) - case .unknown: - return .red - } + static var accentColor: Color { + accent.color } - static func update(with newColor: Color) { - color = newColor + static func updateAccent(with newAccent: Accent) { + accent = newAccent } // MARK: Helpers - private static var savedColor: Color? { + private static var savedAccent: Accent? { get { - guard - let components = defaults.array(forKey: defaultsKey) as? [CGFloat], !components.isEmpty, - let cgColorSpace: CGColorSpace = .init(name: CGColorSpace.sRGB), - let cgColor = CGColor(colorSpace: cgColorSpace, components: components) - else { + guard let rawValue = defaults.string(forKey: savedAccentKey) else { return nil } - return Color(cgColor) + return Accent(rawValue: rawValue) } set { - let components = newValue?.cgColor?.components ?? [] - defaults.set(components, forKey: defaultsKey) + if let newValue { + defaults.set(newValue.rawValue, forKey: savedAccentKey) + } } } @@ -52,8 +47,8 @@ enum AppColor { .init(suiteName: WPAppGroupName) ?? .standard } - private static var defaultsKey: String { - "\(appConfig.rawValue).AppColorComponents" + private static var savedAccentKey: String { + "\(appConfig.rawValue).AppColor.Accent" } private static var appConfig: AppConfig { @@ -73,6 +68,57 @@ enum AppColor { case unknown = "Unknown" } + private static var defaultAccentColor: Color { + switch appConfig { + case .wordpress: + return .muriel(.wordPressBlue) + case .jetpack: + return .muriel(.jetpackGreen) + case .unknown: + return .red + } + } + +} + +extension AppColor.Accent: Identifiable, CustomStringConvertible { + var id: String { + rawValue + } + + var description: String { + switch self { + case .`default`: + return AppLocalizedString("Default", comment: "Title for the Default app accent color") + case .green: + return AppLocalizedString("Green", comment: "Title for the Green app accent color") + case .blue: + return AppLocalizedString("Blue", comment: "Title for the Blue app accent color") + case .orange: + return AppLocalizedString("Orange", comment: "Title for the Orange app accent color") + case .purple: + return AppLocalizedString("Purple", comment: "Title for the Purple app accent color") + case .pink: + return AppLocalizedString("Pink", comment: "Title for the Pink app accent color") + } + } + + var color: Color { + switch self { + case .`default`: + return AppColor.defaultAccentColor + case .green: + return .muriel(.green) + case .blue: + return .muriel(.blue) + case .orange: + return .muriel(.orange) + case .purple: + return .muriel(.purple) + case .pink: + return .muriel(.pink) + } + } } private extension Color { diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift new file mode 100644 index 000000000000..83de5b5b81fb --- /dev/null +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift @@ -0,0 +1,68 @@ +import SwiftUI + +struct AppColorListView: View { + + @StateObject var vm = AppColorListViewModel() + + var body: some View { + List(vm.allAccents) { accent in + Button(action: { + vm.selectedAccent = accent + }, label: { + makeRow(with: accent) + }) + } + } + + private func makeRow(with accent: AppColor.Accent) -> some View { + HStack(spacing: 0) { + Circle() + .fill(accent.color) + .frame(width: 32, height: 32) + .padding(.horizontal) + .padding(.vertical, 4) + + Text(accent.description) + .foregroundColor(.primary) + + Spacer() + if accent == vm.selectedAccent { + Image(systemName: "checkmark") + .foregroundColor(accent.color) + } + } + } + +} + +final class AppColorListViewModel: ObservableObject { + + var allAccents: [AppColor.Accent] { + AppColor.Accent.allCases + } + + @Published var selectedAccent = AppColor.accent { + didSet { + if selectedAccent != oldValue { + updateAccent(selectedAccent) + } + } + } + + private func updateAccent(_ accent: AppColor.Accent) { + AppColor.updateAccent(with: accent) + + let appDelegate = UIApplication.shared.delegate as? WordPressAppDelegate + appDelegate?.customizeAppearance() + + /// - TODO: at this point some parts of the UI still use the previous color + /// find a way to update all UI globally when user changes "App Color" in Settings 🤔 + } + +} + +struct AppColorListView_Previews: PreviewProvider { + static var previews: some View { + AppColorListView() + } +} diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift deleted file mode 100644 index 9637ff2ca63f..000000000000 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerView.swift +++ /dev/null @@ -1,36 +0,0 @@ -import SwiftUI - -struct AppColorPickerView: View { - - @StateObject var vm = AppColorPickerViewModel() - - var body: some View { - ColorPicker(selection: $vm.color, supportsOpacity: false) { - HStack { - Text(colorPickerTitle) - - Spacer() - Button(action: { - vm.restoreDefaultColor() - }, label: { - Text(resetButtonTitle) - }) - } - } - .font(.callout) - } - - private var colorPickerTitle: String { - NSLocalizedString("Accent Color", comment: "Navigates to color picker screen to change the app accent color") - } - - private var resetButtonTitle: String { - NSLocalizedString("Reset", comment: "Restores default app primary color") - } -} - -struct AppColorPickerView_Previews: PreviewProvider { - static var previews: some View { - AppColorPickerView() - } -} diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift deleted file mode 100644 index a5655e47ac8e..000000000000 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorPickerViewModel.swift +++ /dev/null @@ -1,27 +0,0 @@ -import SwiftUI - -final class AppColorPickerViewModel: ObservableObject { - - @Published var color = AppColor.color { - didSet { - if color != oldValue { - updateAppColor(color) - } - } - } - - func restoreDefaultColor() { - color = AppColor.defaultColor - } - - private func updateAppColor(_ color: Color) { - AppColor.update(with: color) - - let appDelegate = UIApplication.shared.delegate as? WordPressAppDelegate - appDelegate?.customizeAppearance() - - /// - TODO: at this point some parts of the UI still use the previous color - /// find a way to update all UI globally when user changes "App Color" in Settings 🤔 - } - -} diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index 9bf040d33a88..0f497751f67b 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -259,6 +259,14 @@ class AppSettingsViewController: UITableViewController { } } + func pushAppColorList() -> ImmuTableAction { + return { [weak self] row in + let vc = UIHostingController(rootView: AppColorListView()) + vc.title = self?.accentColorTitle + self?.navigationController?.pushViewController(vc, animated: true) + } + } + func openPrivacySettings() -> ImmuTableAction { return { [weak self] _ in WPAnalytics.track(.privacySettingsOpened) @@ -495,9 +503,11 @@ private extension AppSettingsViewController { rows.append(appIconRow) } - let appColorRow = SwiftUIRow(selectionStyle: .none) { - AppColorPickerView() - } + let appColorRow = NavigationItemRow( + title: accentColorTitle, + detail: AppColor.accent.description, + action: pushAppColorList() + ) rows.append(appColorRow) return ImmuTableSection( @@ -507,6 +517,10 @@ private extension AppSettingsViewController { ) } + var accentColorTitle: String { + NSLocalizedString("Accent Color", comment: "The title of the app accent color") + } + func otherTableSection() -> ImmuTableSection { var rows: [ImmuTableRow] = [] diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 120fb5b8a5ad..8f36208ef7fc 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2055,12 +2055,10 @@ 8B939F4323832E5D00ACCB0F /* PostListViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B939F4223832E5D00ACCB0F /* PostListViewControllerTests.swift */; }; 8BA125EB27D8F5E4008B779F /* UIView+PinSubviewPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA125EA27D8F5E4008B779F /* UIView+PinSubviewPriority.swift */; }; 8BA125EC27D8F5E4008B779F /* UIView+PinSubviewPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA125EA27D8F5E4008B779F /* UIView+PinSubviewPriority.swift */; }; - 8BA6F7BC29B9F8D000026408 /* AppColorPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */; }; + 8BA6F7BC29B9F8D000026408 /* AppColorListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BB29B9F8D000026408 /* AppColorListView.swift */; }; 8BA6F7BE29BA19F200026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; - 8BA6F7C029BA1A0000026408 /* AppColorPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */; }; 8BA6F7C429BB54D000026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; - 8BA6F7C529BB54D400026408 /* AppColorPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */; }; - 8BA6F7C629BB54D800026408 /* AppColorPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */; }; + 8BA6F7C529BB54D400026408 /* AppColorListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BB29B9F8D000026408 /* AppColorListView.swift */; }; 8BA6F7C729BB6B4900026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; 8BA6F7C829BB6B4A00026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; 8BA6F7C929BB6B4A00026408 /* AppColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BA6F7BD29BA19F200026408 /* AppColor.swift */; }; @@ -7308,9 +7306,8 @@ 8B93856D22DC08060010BF02 /* PageListSectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageListSectionHeaderView.swift; sourceTree = ""; }; 8B939F4223832E5D00ACCB0F /* PostListViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostListViewControllerTests.swift; sourceTree = ""; }; 8BA125EA27D8F5E4008B779F /* UIView+PinSubviewPriority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+PinSubviewPriority.swift"; sourceTree = ""; }; - 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppColorPickerView.swift; sourceTree = ""; }; + 8BA6F7BB29B9F8D000026408 /* AppColorListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppColorListView.swift; sourceTree = ""; }; 8BA6F7BD29BA19F200026408 /* AppColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppColor.swift; sourceTree = ""; }; - 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppColorPickerViewModel.swift; sourceTree = ""; }; 8BA77BCA2482C52A00E1EBBF /* ReaderCardDiscoverAttributionView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderCardDiscoverAttributionView.xib; sourceTree = ""; }; 8BA77BCC248340CE00E1EBBF /* ReaderDetailToolbar.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderDetailToolbar.xib; sourceTree = ""; }; 8BA77BCE2483415400E1EBBF /* ReaderDetailToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderDetailToolbar.swift; sourceTree = ""; }; @@ -13431,8 +13428,7 @@ isa = PBXGroup; children = ( 8BA6F7BD29BA19F200026408 /* AppColor.swift */, - 8BA6F7BB29B9F8D000026408 /* AppColorPickerView.swift */, - 8BA6F7BF29BA1A0000026408 /* AppColorPickerViewModel.swift */, + 8BA6F7BB29B9F8D000026408 /* AppColorListView.swift */, ); path = "App Color"; sourceTree = ""; @@ -21164,7 +21160,6 @@ 3FB1929526C79EC6000F5AA3 /* Date+TimeStrings.swift in Sources */, 178DDD57266E4165006C68C4 /* CalendarDayToggleButton.swift in Sources */, 73ACDF992114FE4500233AD4 /* NotificationSupportService.swift in Sources */, - 8BA6F7C029BA1A0000026408 /* AppColorPickerViewModel.swift in Sources */, 08D345531CD7F50900358E8C /* MenusSelectionView.m in Sources */, 5D6C4B131B604190005E3C43 /* UITextView+RichTextView.swift in Sources */, E15644E91CE0E47C00D96E64 /* RoundedButton.swift in Sources */, @@ -21535,7 +21530,7 @@ 93C4864F181043D700A24725 /* ActivityLogDetailViewController.m in Sources */, B57B99DE19A2DBF200506504 /* NSObject+Helpers.m in Sources */, E1E49CE41C4902EE002393A4 /* ImmuTableViewController.swift in Sources */, - 8BA6F7BC29B9F8D000026408 /* AppColorPickerView.swift in Sources */, + 8BA6F7BC29B9F8D000026408 /* AppColorListView.swift in Sources */, D88A6496208D7B0B008AE9BC /* NullStockPhotosService.swift in Sources */, 9A162F2321C26D7500FDC035 /* RevisionPreviewViewController.swift in Sources */, 467D3DFA25E4436000EB9CB0 /* SitePromptView.swift in Sources */, @@ -23548,7 +23543,7 @@ FABB21A32602FC2C00C8785C /* CommentsViewController.m in Sources */, FABB21A42602FC2C00C8785C /* SiteSettingsViewController+SiteManagement.swift in Sources */, FABB21A52602FC2C00C8785C /* Follow.swift in Sources */, - 8BA6F7C529BB54D400026408 /* AppColorPickerView.swift in Sources */, + 8BA6F7C529BB54D400026408 /* AppColorListView.swift in Sources */, FABB21A62602FC2C00C8785C /* BlogJetpackSettingsService.swift in Sources */, FABB21A72602FC2C00C8785C /* MenuItemTypeViewController.m in Sources */, 80535DC3294BDE2B00873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift in Sources */, @@ -24660,7 +24655,6 @@ FABB24F42602FC2C00C8785C /* NoticePresenter.swift in Sources */, FABB24F52602FC2C00C8785C /* ReaderTagTopic.swift in Sources */, FABB24F62602FC2C00C8785C /* Media.swift in Sources */, - 8BA6F7C629BB54D800026408 /* AppColorPickerViewModel.swift in Sources */, 9839CEBC26FAA0530097406E /* CommentModerationBar.swift in Sources */, 837966A3299E9C85004A92B9 /* JetpackInstallPluginHelper.swift in Sources */, 17039227282E6DF500F602E9 /* ViewsVisitorsChartMarker.swift in Sources */, From f2ba364ef66822aed857efb135a2e9198b4db86d Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Wed, 15 Mar 2023 15:08:37 +0100 Subject: [PATCH 09/17] Address PR feedback --- .../Classes/Utility/WPImmuTableRows.swift | 35 ------------------- .../Me/App Settings/App Color/AppColor.swift | 12 +++---- .../AppSettingsViewController.swift | 10 +++--- 3 files changed, 11 insertions(+), 46 deletions(-) diff --git a/WordPress/Classes/Utility/WPImmuTableRows.swift b/WordPress/Classes/Utility/WPImmuTableRows.swift index 43112782a6fc..306a2b016304 100644 --- a/WordPress/Classes/Utility/WPImmuTableRows.swift +++ b/WordPress/Classes/Utility/WPImmuTableRows.swift @@ -1,7 +1,6 @@ import Foundation import WordPressShared import Gridicons -import SwiftUI struct NavigationItemRow: ImmuTableRow { static let cell = ImmuTableCell.class(WPTableViewCellValue1.self) @@ -451,37 +450,3 @@ class ExpandableRow: ImmuTableRow { cell.urlCallback = onLinkTap } } - -struct SwiftUIRow: ImmuTableRow { - static var cell: ImmuTableCell { - .class(WPTableViewCellDefault.self) - } - - var selectionStyle: UITableViewCell.SelectionStyle = .default - var action: ImmuTableAction? - var content: () -> T - - func configureCell(_ cell: UITableViewCell) { - cell.selectionStyle = selectionStyle - - if #available(iOS 16.0, *) { - cell.contentConfiguration = UIHostingConfiguration { - content() - } - } else { - cell.contentView.subviews.forEach { $0.removeFromSuperview() } - - let host = UIHostingController(rootView: content()) - host.view.backgroundColor = .clear - host.view.translatesAutoresizingMaskIntoConstraints = false - - cell.contentView.addSubview(host.view) - NSLayoutConstraint.activate([ - host.view.leadingAnchor.constraint(equalTo: cell.layoutMarginsGuide.leadingAnchor), - host.view.trailingAnchor.constraint(equalTo: cell.layoutMarginsGuide.trailingAnchor), - host.view.topAnchor.constraint(equalTo: cell.layoutMarginsGuide.topAnchor), - host.view.bottomAnchor.constraint(equalTo: cell.layoutMarginsGuide.bottomAnchor) - ]) - } - } -} diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index d58ece9fa631..3bf432cf3de3 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -89,17 +89,17 @@ extension AppColor.Accent: Identifiable, CustomStringConvertible { var description: String { switch self { case .`default`: - return AppLocalizedString("Default", comment: "Title for the Default app accent color") + return AppLocalizedString("color.default", comment: "Title for the `Default` app accent color") case .green: - return AppLocalizedString("Green", comment: "Title for the Green app accent color") + return AppLocalizedString("color.green", comment: "Title for the `Green` app accent color") case .blue: - return AppLocalizedString("Blue", comment: "Title for the Blue app accent color") + return AppLocalizedString("color.blue", comment: "Title for the `Blue` app accent color") case .orange: - return AppLocalizedString("Orange", comment: "Title for the Orange app accent color") + return AppLocalizedString("color.orange", comment: "Title for the `Orange` app accent color") case .purple: - return AppLocalizedString("Purple", comment: "Title for the Purple app accent color") + return AppLocalizedString("color.purple", comment: "Title for the `Purple` app accent color") case .pink: - return AppLocalizedString("Pink", comment: "Title for the Pink app accent color") + return AppLocalizedString("color.pink", comment: "Title for the `Pink` app accent color") } } diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index 0f497751f67b..19d4656bc156 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -261,9 +261,9 @@ class AppSettingsViewController: UITableViewController { func pushAppColorList() -> ImmuTableAction { return { [weak self] row in - let vc = UIHostingController(rootView: AppColorListView()) - vc.title = self?.accentColorTitle - self?.navigationController?.pushViewController(vc, animated: true) + let controller = UIHostingController(rootView: AppColorListView()) + controller.title = self?.accentColorTitle + self?.navigationController?.pushViewController(controller, animated: true) } } @@ -489,7 +489,7 @@ private extension AppSettingsViewController { var rows: [ImmuTableRow] = [] let colorModeRow = NavigationItemRow( - title: NSLocalizedString("Color Mode", comment: "The title of the app color mode settings screen"), + title: NSLocalizedString("settings.color.mode.title", comment: "The title for the app 'Color Mode' setting."), detail: AppAppearance.current.appearanceDescription, action: pushColorModeSettings() ) @@ -518,7 +518,7 @@ private extension AppSettingsViewController { } var accentColorTitle: String { - NSLocalizedString("Accent Color", comment: "The title of the app accent color") + NSLocalizedString("settings.accent.color.title", comment: "The title for the app 'Accent Color' setting.") } func otherTableSection() -> ImmuTableSection { From c3eeec361266b568987354927417d77cc302b9c0 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Wed, 15 Mar 2023 15:16:12 +0100 Subject: [PATCH 10/17] Post notification when accent color is changed Assumption is that we'll eventually need to react to this change from a different context. --- .../Me/App Settings/App Color/AppColor.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index 3bf432cf3de3..2813d144b13f 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -15,7 +15,12 @@ enum AppColor { static private(set) var accent: Accent = savedAccent ?? .default { didSet { - savedAccent = accent + if accent != oldValue { + savedAccent = accent + + NotificationCenter.default + .post(name: .appColorDidUpdateAccent, object: accent) + } } } @@ -121,6 +126,10 @@ extension AppColor.Accent: Identifiable, CustomStringConvertible { } } +extension Foundation.Notification.Name { + static let appColorDidUpdateAccent = Self("appColorDidUpdateAccent") +} + private extension Color { static func muriel(_ name: MurielColorName) -> Self { .init(UIColor.muriel(color: .init(name: name))) From c644b006c80b03db68d4780cc60500d101bc46e5 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Wed, 15 Mar 2023 16:06:02 +0100 Subject: [PATCH 11/17] Add possibility for different shades and dynamic colors for light & dark mode --- .../Me/App Settings/App Color/AppColor.swift | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index 2813d144b13f..838fad3651c8 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -113,15 +113,30 @@ extension AppColor.Accent: Identifiable, CustomStringConvertible { case .`default`: return AppColor.defaultAccentColor case .green: - return .muriel(.green) + return .dynamic( + light: .muriel(.green), + dark: .muriel(.green) + ) case .blue: - return .muriel(.blue) + return .dynamic( + light: .muriel(.blue), + dark: .muriel(.blue) + ) case .orange: - return .muriel(.orange) + return .dynamic( + light: .muriel(.orange), + dark: .muriel(.orange) + ) case .purple: - return .muriel(.purple) + return .dynamic( + light: .muriel(.purple), + dark: .muriel(.purple) + ) case .pink: - return .muriel(.pink) + return .dynamic( + light: .muriel(.pink), + dark: .muriel(.pink) + ) } } } @@ -131,7 +146,20 @@ extension Foundation.Notification.Name { } private extension Color { - static func muriel(_ name: MurielColorName) -> Self { - .init(UIColor.muriel(color: .init(name: name))) + static func muriel( + _ name: MurielColorName, + shade: MurielColorShade = .shade50 + ) -> Self { + .init( + UIColor.muriel(color: .init(name: name, shade: shade)) + ) + } + + static func dynamic(light: Color, dark: Color) -> Color { + Color(UIColor( + dynamicProvider: { + $0.userInterfaceStyle == .dark ? UIColor(dark) : UIColor(light) + }) + ) } } From a911ef3bb5a0e9a16fad3a9fd5f33ad03497fd3f Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Thu, 16 Mar 2023 12:07:04 +0100 Subject: [PATCH 12/17] Implement exact colors list and sorting as discussed in P2 --- .../Colors and Styles/MurielColor.swift | 1 + .../Me/App Settings/App Color/AppColor.swift | 109 +++++++++++------- .../App Color/AppColorListView.swift | 2 +- 3 files changed, 70 insertions(+), 42 deletions(-) diff --git a/WordPress/Classes/Extensions/Colors and Styles/MurielColor.swift b/WordPress/Classes/Extensions/Colors and Styles/MurielColor.swift index 9ec538d8ea10..360866ad5927 100644 --- a/WordPress/Classes/Extensions/Colors and Styles/MurielColor.swift +++ b/WordPress/Classes/Extensions/Colors and Styles/MurielColor.swift @@ -12,6 +12,7 @@ enum MurielColorName: String, CustomStringConvertible { case red case yellow case jetpackGreen + case wooCommercePurple var description: String { // can't use .capitalized because it lowercases the P and B in "wordPressBlue" diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index 838fad3651c8..9fae04165154 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -3,17 +3,19 @@ import SwiftUI enum AppColor { enum Accent: String, CaseIterable { - case `default` - case green - case blue - case orange - case purple case pink + case red + case orange + case yellow + case celadon + case wooCommercePurple + case jetpackGreen + case wordPressBlue } // MARK: API - static private(set) var accent: Accent = savedAccent ?? .default { + static private(set) var accent: Accent = savedAccent ?? defaultAccent { didSet { if accent != oldValue { savedAccent = accent @@ -34,6 +36,17 @@ enum AppColor { // MARK: Helpers + private static var defaultAccent: Accent { + switch appConfig { + case .wordpress: + return .wordPressBlue + case .jetpack: + return .jetpackGreen + case .unknown: + return .red + } + } + private static var savedAccent: Accent? { get { guard let rawValue = defaults.string(forKey: savedAccentKey) else { @@ -73,17 +86,6 @@ enum AppColor { case unknown = "Unknown" } - private static var defaultAccentColor: Color { - switch appConfig { - case .wordpress: - return .muriel(.wordPressBlue) - case .jetpack: - return .muriel(.jetpackGreen) - case .unknown: - return .red - } - } - } extension AppColor.Accent: Identifiable, CustomStringConvertible { @@ -93,52 +95,77 @@ extension AppColor.Accent: Identifiable, CustomStringConvertible { var description: String { switch self { - case .`default`: - return AppLocalizedString("color.default", comment: "Title for the `Default` app accent color") - case .green: - return AppLocalizedString("color.green", comment: "Title for the `Green` app accent color") - case .blue: - return AppLocalizedString("color.blue", comment: "Title for the `Blue` app accent color") - case .orange: - return AppLocalizedString("color.orange", comment: "Title for the `Orange` app accent color") - case .purple: - return AppLocalizedString("color.purple", comment: "Title for the `Purple` app accent color") case .pink: return AppLocalizedString("color.pink", comment: "Title for the `Pink` app accent color") + case .red: + return AppLocalizedString("color.red", comment: "Title for the `Red` app accent color") + case .orange: + return AppLocalizedString("color.orange", comment: "Title for the `Orange` app accent color") + case .yellow: + return AppLocalizedString("color.yellow", comment: "Title for the `Yellow` app accent color") + case .celadon: + return AppLocalizedString("color.celadon", comment: "Title for the `Celadon` app accent color") + case .wooCommercePurple: + return AppLocalizedString("color.wooCommercePurple", comment: "Title for the `WooCommerce Purple` app accent color") + case .jetpackGreen: + return AppLocalizedString("color.jetpackGreen", comment: "Title for the `Jetpack Green` app accent color") + case .wordPressBlue: + return AppLocalizedString("color.wordPressBlue", comment: "Title for the `WordPress Blue` app accent color") } } var color: Color { switch self { - case .`default`: - return AppColor.defaultAccentColor - case .green: + case .pink: return .dynamic( - light: .muriel(.green), - dark: .muriel(.green) + light: .muriel(.pink, shade: .shade60), + dark: .muriel(.pink, shade: .shade60) ) - case .blue: + case .red: return .dynamic( - light: .muriel(.blue), - dark: .muriel(.blue) + light: .muriel(.red, shade: .shade60), + dark: .muriel(.red, shade: .shade60) ) case .orange: return .dynamic( light: .muriel(.orange), dark: .muriel(.orange) ) - case .purple: + case .yellow: return .dynamic( - light: .muriel(.purple), - dark: .muriel(.purple) + light: .muriel(.yellow), + dark: .muriel(.yellow) ) - case .pink: + case .celadon: return .dynamic( - light: .muriel(.pink), - dark: .muriel(.pink) + light: .muriel(.celadon, shade: .shade60), + dark: .muriel(.celadon, shade: .shade60) + ) + case .wooCommercePurple: + return .dynamic( + light: .muriel(.wooCommercePurple, shade: .shade60), + dark: .muriel(.wooCommercePurple, shade: .shade60) + ) + case .jetpackGreen: + return .dynamic( + light: .muriel(.jetpackGreen), + dark: .muriel(.jetpackGreen) + ) + case .wordPressBlue: + return .dynamic( + light: .muriel(.wordPressBlue), + dark: .muriel(.wordPressBlue) ) } } + + static var allCasesSorted: [Self] { + var all = allCases + let firstAccent = AppColor.defaultAccent + all.removeAll(where: { $0 == firstAccent }) + all.insert(firstAccent, at: 0) + return all + } } extension Foundation.Notification.Name { diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift index 83de5b5b81fb..23a961123545 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift @@ -38,7 +38,7 @@ struct AppColorListView: View { final class AppColorListViewModel: ObservableObject { var allAccents: [AppColor.Accent] { - AppColor.Accent.allCases + AppColor.Accent.allCasesSorted } @Published var selectedAccent = AppColor.accent { From fd31a6a30c425c60738f5ceb73007d6953fe9f05 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Thu, 16 Mar 2023 12:45:45 +0100 Subject: [PATCH 13/17] Replace existing `primary`, `accent` and `brand` colors to use the new `AppColor.accentColor` --- .../UIColor+MurielColors.swift | 58 ++++++++++++------- .../Me/App Settings/App Color/AppColor.swift | 57 +++++++++++++----- .../People/WPStyleGuide+People.swift | 2 +- 3 files changed, 78 insertions(+), 39 deletions(-) diff --git a/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift b/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift index b473674b10dc..2bbbe7cca635 100644 --- a/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift +++ b/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift @@ -32,19 +32,39 @@ extension UIColor { return muriel(color: newColor) } } + // MARK: - Basic Colors extension UIColor { + + /// - Note: as part of this task: https://jetpackmobile.wordpress.com/2023/03/10/trial-task-user-defined-app-color/ + /// we decided to replace `primary`, `accent` and `brand` colors with user customizable `AppColor.accentColor` + /// long term goal is to unify these 3 colors into a single `accent` color. + + /// Muriel primary color + static var primary: UIColor { + UIColor(AppColor.accentColor) + } + class func primary(_ shade: MurielColorShade) -> UIColor { + UIColor(AppColor.accentColor(shade)) + } + static var primaryLight: UIColor { + primary(.shade30) + } + static var primaryDark: UIColor { + primary(.shade70) + } + /// Muriel accent color - static var accent = muriel(color: .accent) - static var accentDark = muriel(color: .accent, .shade70) + static var accent: UIColor { + UIColor(AppColor.accentColor) + } class func accent(_ shade: MurielColorShade) -> UIColor { - return muriel(color: .accent, shade) + UIColor(AppColor.accentColor(shade)) } /// Muriel brand color - static var brand = muriel(color: .brand) - class func brand(_ shade: MurielColorShade) -> UIColor { - return muriel(color: .brand, shade) + static var brand: UIColor { + UIColor(AppColor.accentColor) } /// Muriel error color @@ -54,18 +74,6 @@ extension UIColor { return muriel(color: .error, shade) } - /// Muriel primary color - static var primary: UIColor { - UIColor(AppColor.accentColor) - } - /// - TODO: cleanup later -// static var primary = muriel(color: .primary) - static var primaryLight = muriel(color: .primary, .shade30) - static var primaryDark = muriel(color: .primary, .shade70) - class func primary(_ shade: MurielColorShade) -> UIColor { - return muriel(color: .primary, shade) - } - /// Muriel editor primary color static var editorPrimary = muriel(color: .editorPrimary) class func editorPrimary(_ shade: MurielColorShade) -> UIColor { @@ -243,12 +251,18 @@ extension UIColor { } static var barButtonItemTitle: UIColor { - return UIColor(light: UIColor.primary(.shade50), dark: UIColor.primary(.shade30)) + return UIColor(light: primary(.shade50), dark: primary(.shade30)) + } + + // MARK: - WP Fancy Buttons + + static var primaryButtonBackground: UIColor { + primary } -// MARK: - WP Fancy Buttons - static var primaryButtonBackground = primary - static var primaryButtonDownBackground = muriel(color: .primary, .shade80) + static var primaryButtonDownBackground: UIColor { + primary(.shade80) + } static var secondaryButtonBackground: UIColor { return UIColor(light: .white, dark: .systemGray5) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index 9fae04165154..35b0ee4e616d 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -30,6 +30,10 @@ enum AppColor { accent.color } + static func accentColor(_ shade: MurielColorShade) -> Color { + .muriel(accent.murielName, shade: shade) + } + static func updateAccent(with newAccent: Accent) { accent = newAccent } @@ -118,47 +122,68 @@ extension AppColor.Accent: Identifiable, CustomStringConvertible { switch self { case .pink: return .dynamic( - light: .muriel(.pink, shade: .shade60), - dark: .muriel(.pink, shade: .shade60) + light: .muriel(murielName, shade: .shade60), + dark: .muriel(murielName, shade: .shade60) ) case .red: return .dynamic( - light: .muriel(.red, shade: .shade60), - dark: .muriel(.red, shade: .shade60) + light: .muriel(murielName, shade: .shade60), + dark: .muriel(murielName, shade: .shade60) ) case .orange: return .dynamic( - light: .muriel(.orange), - dark: .muriel(.orange) + light: .muriel(murielName), + dark: .muriel(murielName) ) case .yellow: return .dynamic( - light: .muriel(.yellow), - dark: .muriel(.yellow) + light: .muriel(murielName), + dark: .muriel(murielName) ) case .celadon: return .dynamic( - light: .muriel(.celadon, shade: .shade60), - dark: .muriel(.celadon, shade: .shade60) + light: .muriel(murielName, shade: .shade60), + dark: .muriel(murielName, shade: .shade60) ) case .wooCommercePurple: return .dynamic( - light: .muriel(.wooCommercePurple, shade: .shade60), - dark: .muriel(.wooCommercePurple, shade: .shade60) + light: .muriel(murielName, shade: .shade60), + dark: .muriel(murielName, shade: .shade60) ) case .jetpackGreen: return .dynamic( - light: .muriel(.jetpackGreen), - dark: .muriel(.jetpackGreen) + light: .muriel(murielName), + dark: .muriel(murielName) ) case .wordPressBlue: return .dynamic( - light: .muriel(.wordPressBlue), - dark: .muriel(.wordPressBlue) + light: .muriel(murielName), + dark: .muriel(murielName) ) } } + fileprivate var murielName: MurielColorName { + switch self { + case .pink: + return .pink + case .red: + return .red + case .orange: + return .orange + case .yellow: + return .yellow + case .celadon: + return .celadon + case .wooCommercePurple: + return .wooCommercePurple + case .jetpackGreen: + return .jetpackGreen + case .wordPressBlue: + return .wordPressBlue + } + } + static var allCasesSorted: [Self] { var all = allCases let firstAccent = AppColor.defaultAccent diff --git a/WordPress/Classes/ViewRelated/People/WPStyleGuide+People.swift b/WordPress/Classes/ViewRelated/People/WPStyleGuide+People.swift index cb4c6ab35b81..157565d6341c 100644 --- a/WordPress/Classes/ViewRelated/People/WPStyleGuide+People.swift +++ b/WordPress/Classes/ViewRelated/People/WPStyleGuide+People.swift @@ -19,7 +19,7 @@ extension WPStyleGuide { } // MARK: Colors - public static let superAdminColor = UIColor.accentDark + public static let superAdminColor = UIColor.accent(.shade70) public static let adminColor = UIColor.neutral(.shade70) public static let editorColor = UIColor.primaryDark public static let otherRoleColor: UIColor = .primary From 1ce1df27016240f245a18165783199cef552fd43 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Thu, 16 Mar 2023 18:55:16 +0100 Subject: [PATCH 14/17] Fix app appearance when `AppColor.accentColor` is changed --- .../Classes/System/WordPressAppDelegate.swift | 2 +- .../Prompts/DashboardPromptsCardCell.swift | 12 ++++++++++ .../Detail Header/BlogDetailHeaderView.swift | 12 ++++++++++ .../Blog/My Site/MySiteViewController.swift | 16 ++++++++++++++ .../Blog/WPStyleGuide+BloggingPrompts.swift | 4 +++- .../Me/App Settings/App Color/AppColor.swift | 6 +++++ .../App Color/AppColorListView.swift | 3 --- .../Me/Me Main/MeViewController.swift | 21 +++++++++++++++++- .../NotificationsViewController.swift | 10 +++++++++ .../Style/WPStyleGuide+Notifications.swift | 4 +++- .../ViewRelated/System/FilterTabBar.swift | 12 ++++++++++ .../FloatingActionButton.swift | 22 +++++++++++++++---- .../System/WPTabBarController+Swift.swift | 1 + .../ViewRelated/System/WPTabBarController.m | 6 +++++ 14 files changed, 120 insertions(+), 11 deletions(-) diff --git a/WordPress/Classes/System/WordPressAppDelegate.swift b/WordPress/Classes/System/WordPressAppDelegate.swift index 22df1d5a5285..0e4f6361ceea 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.swift +++ b/WordPress/Classes/System/WordPressAppDelegate.swift @@ -138,7 +138,6 @@ class WordPressAppDelegate: UIResponder, UIApplicationDelegate { InteractiveNotificationsManager.shared.registerForUserNotifications() setupPingHub() setupBackgroundRefresh(application) - setupComponentsAppearance() disableAnimationsForUITests(application) // This was necessary to properly load fonts for the Stories editor. I believe external libraries may require this call to access fonts. @@ -951,6 +950,7 @@ extension WordPressAppDelegate { /// It's necessary to target `PostCategoriesViewController` a second time to "reset" the UI element's `tintColor` for use in the app's Site Settings screen. UIView.appearance(whenContainedInInstancesOf: [PostCategoriesViewController.self, WPSplitViewController.self]).tintColor = .primary + setupComponentsAppearance() } } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/DashboardPromptsCardCell.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/DashboardPromptsCardCell.swift index 26f1513a987b..f20ea75a95ad 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/DashboardPromptsCardCell.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/DashboardPromptsCardCell.swift @@ -326,12 +326,19 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { super.init(frame: frame) setupViews() observeManagedObjectsChange() + + NotificationCenter.default + .addObserver(self, selector: #selector(updateAppearance), name: .appColorDidUpdateAccent, object: nil) } required init?(coder: NSCoder) { super.init(coder: coder) } + deinit { + NotificationCenter.default.removeObserver(self) + } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { // refresh when the appearance style changed so the placeholder images are correctly recolored. if let previousTraitCollection = previousTraitCollection, @@ -417,6 +424,11 @@ private extension DashboardPromptsCardCell { presenterViewController?.collectionView.collectionViewLayout.invalidateLayout() } + @objc + private func updateAppearance() { + answerButton.setTitleColor(WPStyleGuide.BloggingPrompts.buttonTitleColor, for: .normal) + } + // MARK: - Managed object observer func observeManagedObjectsChange() { diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/Detail Header/BlogDetailHeaderView.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/Detail Header/BlogDetailHeaderView.swift index 9e3592c4e1cb..f214ef6ec2c8 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/Detail Header/BlogDetailHeaderView.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/Detail Header/BlogDetailHeaderView.swift @@ -113,12 +113,19 @@ class BlogDetailHeaderView: UIView { super.init(frame: .zero) setupChildViews(items: items) + + NotificationCenter.default + .addObserver(self, selector: #selector(updateAppearance), name: .appColorDidUpdateAccent, object: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + deinit { + NotificationCenter.default.removeObserver(self) + } + // MARK: - Child View Initialization private func setupChildViews(items: [ActionRow.Item]) { @@ -145,6 +152,11 @@ class BlogDetailHeaderView: UIView { setupConstraintsForChildViews(showsActionRow) } + @objc + private func updateAppearance() { + titleView.subtitleButton.setTitleColor(.primary, for: .normal) + } + // MARK: - Constraints private var topActionRowConstraint: NSLayoutConstraint? diff --git a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift index 071a644c9963..ee6af58e7290 100644 --- a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift @@ -104,6 +104,9 @@ class MySiteViewController: UIViewController, NoResultsViewHost { self.mySiteSettings = mySiteSettings super.init(nibName: nil, bundle: nil) + + NotificationCenter.default + .addObserver(self, selector: #selector(updateAppearance), name: .appColorDidUpdateAccent, object: nil) } required init?(coder: NSCoder) { @@ -281,6 +284,19 @@ class MySiteViewController: UIViewController, NoResultsViewHost { object: nil) } + @objc + func updateAppearance() { + guard AppConfiguration.isWordPress else { + return + } + /// - Note: workaround to update navigation bar tint + navigationController?.isNavigationBarHidden = true + DispatchQueue.main.async { + self.navigationController?.isNavigationBarHidden = false + self.setupNavBarAppearance() + } + } + func updateNavigationTitle(for blog: Blog) { let blogName = blog.settings?.name let title = blogName != nil && blogName?.isEmpty == false diff --git a/WordPress/Classes/ViewRelated/Blog/WPStyleGuide+BloggingPrompts.swift b/WordPress/Classes/ViewRelated/Blog/WPStyleGuide+BloggingPrompts.swift index 98ea3ccca530..2ed2deae6dcd 100644 --- a/WordPress/Classes/ViewRelated/Blog/WPStyleGuide+BloggingPrompts.swift +++ b/WordPress/Classes/ViewRelated/Blog/WPStyleGuide+BloggingPrompts.swift @@ -6,7 +6,9 @@ extension WPStyleGuide { static let answerInfoButtonFont = WPStyleGuide.fontForTextStyle(.caption1) static let answerInfoButtonColor = UIColor.textSubtle static let buttonTitleFont = WPStyleGuide.fontForTextStyle(.subheadline) - static let buttonTitleColor = UIColor.primary + static var buttonTitleColor: UIColor { + .primary + } static let answeredLabelColor = UIColor.muriel(name: .green, .shade50) } } diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index 35b0ee4e616d..71b9565666e9 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -197,6 +197,12 @@ extension Foundation.Notification.Name { static let appColorDidUpdateAccent = Self("appColorDidUpdateAccent") } +@objc extension NSNotification { + static var appColorDidUpdateAccent: NSString { + Foundation.Notification.Name.appColorDidUpdateAccent.rawValue as NSString + } +} + private extension Color { static func muriel( _ name: MurielColorName, diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift index 23a961123545..a9ec39d89d10 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift @@ -54,9 +54,6 @@ final class AppColorListViewModel: ObservableObject { let appDelegate = UIApplication.shared.delegate as? WordPressAppDelegate appDelegate?.customizeAppearance() - - /// - TODO: at this point some parts of the UI still use the previous color - /// find a way to update all UI globally when user changes "App Color" in Settings 🤔 } } diff --git a/WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift b/WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift index 2f3de784edee..3c9b37780dd3 100644 --- a/WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift @@ -28,6 +28,10 @@ class MeViewController: UITableViewController { fatalError("init(coder:) has not been implemented") } + deinit { + NotificationCenter.default.removeObserver(self) + } + override func viewDidLoad() { super.viewDidLoad() @@ -43,7 +47,10 @@ class MeViewController: UITableViewController { handler = ImmuTableViewHandler(takeOver: self) WPStyleGuide.configureAutomaticHeightRows(for: tableView) - NotificationCenter.default.addObserver(self, selector: #selector(MeViewController.accountDidChange), name: NSNotification.Name.WPAccountDefaultWordPressComAccountChanged, object: nil) + NotificationCenter.default + .addObserver(self, selector: #selector(MeViewController.accountDidChange), name: NSNotification.Name.WPAccountDefaultWordPressComAccountChanged, object: nil) + NotificationCenter.default + .addObserver(self, selector: #selector(updateAppearance), name: .appColorDidUpdateAccent, object: nil) WPStyleGuide.configureColors(view: view, tableView: tableView) tableView.accessibilityIdentifier = "Me Table" @@ -72,6 +79,18 @@ class MeViewController: UITableViewController { registerUserActivity() } + @objc + private func updateAppearance() { + guard AppConfiguration.isWordPress else { + return + } + /// - Note: workaround to update navigation bar tint + navigationController?.isNavigationBarHidden = true + DispatchQueue.main.async { + self.navigationController?.isNavigationBarHidden = false + } + } + @objc fileprivate func accountDidChange() { reloadViewModel() } diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift index 3464ac894884..a5c6d559edb0 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift @@ -195,6 +195,7 @@ class NotificationsViewController: UIViewController, UIViewControllerRestoration // While we're onscreen, please, update rows with animations tableViewHandler.updateRowAnimation = .fade + reloadVisibleCells() // Tracking WPAnalytics.track(WPAnalyticsStat.openedNotificationsList) @@ -598,6 +599,15 @@ private extension NotificationsViewController { tableViewHandler = handler } + func reloadVisibleCells() { + guard let visibleIndexPaths = tableView.indexPathsForVisibleRows else { + return + } + tableView.beginUpdates() + tableView.reloadRows(at: visibleIndexPaths, with: .none) + tableView.endUpdates() + } + func setupInlinePrompt() { precondition(inlinePromptView != nil) diff --git a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift index 6e9e198f5733..5ce7a00c93e1 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift @@ -19,7 +19,9 @@ extension WPStyleGuide { } // ListTableViewCell - public static let unreadIndicatorColor = UIColor.primaryLight + public static var unreadIndicatorColor: UIColor { + .primaryLight + } // Notification cells public static let noticonFont = UIFont(name: "Noticons", size: 16) diff --git a/WordPress/Classes/ViewRelated/System/FilterTabBar.swift b/WordPress/Classes/ViewRelated/System/FilterTabBar.swift index 7cd9dd8b8253..1e79591dbedd 100644 --- a/WordPress/Classes/ViewRelated/System/FilterTabBar.swift +++ b/WordPress/Classes/ViewRelated/System/FilterTabBar.swift @@ -216,6 +216,9 @@ class FilterTabBar: UIControl { } private func commonInit() { + NotificationCenter.default + .addObserver(self, selector: #selector(updateAppearance), name: .appColorDidUpdateAccent, object: nil) + tabBarHeightConstraint = heightAnchor.constraint(equalToConstant: tabBarHeight) tabBarHeightConstraint?.isActive = true @@ -260,10 +263,19 @@ class FilterTabBar: UIControl { ]) } + deinit { + NotificationCenter.default.removeObserver(self) + } + // MARK: - Tabs private var tabs: [UIButton] = [] + @objc + private func updateAppearance() { + WPStyleGuide.configureFilterTabBar(self) + } + private func refreshTabs() { tabs.forEach({ $0.removeFromSuperview() }) tabs = items.map(makeTab) diff --git a/WordPress/Classes/ViewRelated/System/Floating Create Button/FloatingActionButton.swift b/WordPress/Classes/ViewRelated/System/Floating Create Button/FloatingActionButton.swift index f3e8af77c2e2..3a23f9836a86 100644 --- a/WordPress/Classes/ViewRelated/System/Floating Create Button/FloatingActionButton.swift +++ b/WordPress/Classes/ViewRelated/System/Floating Create Button/FloatingActionButton.swift @@ -17,21 +17,34 @@ class FloatingActionButton: UIButton { override init(frame: CGRect) { super.init(frame: frame) - layer.backgroundColor = UIColor.primary.cgColor - tintColor = .white - refreshShadow() + updateAppearance() + + NotificationCenter.default + .addObserver(self, selector: #selector(updateAppearance), name: .appColorDidUpdateAccent, object: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + deinit { + NotificationCenter.default.removeObserver(self) + } + override func draw(_ rect: CGRect) { super.draw(rect) layer.cornerRadius = rect.size.width / 2 } + @objc + private func updateAppearance() { + layer.backgroundColor = UIColor.primary.cgColor + tintColor = .white + + refreshShadow() + } + private func refreshShadow() { layer.shadowColor = Constants.shadowColor.cgColor layer.shadowOffset = .zero @@ -41,6 +54,7 @@ class FloatingActionButton: UIButton { override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - refreshShadow() + + updateAppearance() } } diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift b/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift index 5a83bfb9aae6..97efe97739f9 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift @@ -92,5 +92,6 @@ extension WPTabBarController { /// Set up the tab bar's colors @objc func setupColors() { tabBar.isTranslucent = false + tabBar.tintColor = .tabSelected } } diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.m b/WordPress/Classes/ViewRelated/System/WPTabBarController.m index a79be8cb8c63..b85c08829058 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.m +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.m @@ -116,6 +116,11 @@ - (instancetype)init name:WordPressAuthenticator.WPSigninDidFinishNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(setupColors) + name:NSNotification.appColorDidUpdateAccent + object:nil]; + // Watch for application badge number changes [[UIApplication sharedApplication] addObserver:self forKeyPath:WPApplicationIconBadgeNumberKeyPath @@ -132,6 +137,7 @@ - (instancetype)init - (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; [self.tabBar removeObserver:self forKeyPath:WPTabBarFrameKeyPath]; [self stopWatchingQuickTours]; [[UIApplication sharedApplication] removeObserver:self forKeyPath:WPApplicationIconBadgeNumberKeyPath]; From a47bc7fe73a6c5fac439348f2a93fd68f5a60a8a Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Mon, 20 Mar 2023 12:46:01 +0100 Subject: [PATCH 15/17] Address PR feedback - add `value` parameter to the new localizable strings - remove internal link from the code - fix accent color in a few places --- .../UIColor+MurielColors.swift | 5 ++- .../Cards/Stats/DashboardStatsNudgeView.swift | 33 ++++++++++++++----- .../CollapsableHeaderViewController.swift | 12 +------ .../Me/App Settings/App Color/AppColor.swift | 16 ++++----- .../AppSettingsViewController.swift | 4 +-- 5 files changed, 38 insertions(+), 32 deletions(-) diff --git a/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift b/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift index 2bbbe7cca635..4bfc6ec4ee66 100644 --- a/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift +++ b/WordPress/Classes/Extensions/Colors and Styles/UIColor+MurielColors.swift @@ -36,9 +36,8 @@ extension UIColor { // MARK: - Basic Colors extension UIColor { - /// - Note: as part of this task: https://jetpackmobile.wordpress.com/2023/03/10/trial-task-user-defined-app-color/ - /// we decided to replace `primary`, `accent` and `brand` colors with user customizable `AppColor.accentColor` - /// long term goal is to unify these 3 colors into a single `accent` color. + /// - Note: We decided to replace `primary`, `accent` and `brand` colors with user customizable `AppColor.accentColor`, + /// however long term goal here is also to unify these 3 colors into a single `appAccent` color. /// Muriel primary color static var primary: UIColor { diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Stats/DashboardStatsNudgeView.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Stats/DashboardStatsNudgeView.swift index a9e40200d3f4..ddabae8e0a31 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Stats/DashboardStatsNudgeView.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Stats/DashboardStatsNudgeView.swift @@ -19,13 +19,30 @@ final class DashboardStatsNudgeView: UIView { return label }() + private let title: String + private let hint: String? + // MARK: - Init - convenience init(title: String, hint: String?, insets: UIEdgeInsets = Constants.margins) { - self.init(frame: .zero) + init(title: String, hint: String?, insets: UIEdgeInsets = Constants.margins) { + self.title = title + self.hint = hint + + super.init(frame: .zero) setup(insets: insets) - setTitle(title: title, hint: hint) + updateTitleLabel() + + NotificationCenter.default + .addObserver(self, selector: #selector(updateTitleLabel), name: .appColorDidUpdateAccent, object: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + NotificationCenter.default.removeObserver(self) } // MARK: - View setup @@ -37,11 +54,7 @@ final class DashboardStatsNudgeView: UIView { prepareForVoiceOver() } - @objc private func buttonTapped() { - onTap?() - } - - private func setTitle(title: String, hint: String?) { + @objc private func updateTitleLabel() { let externalAttachment = NSTextAttachment(image: UIImage.gridicon(.external, size: Constants.iconSize).withTintColor(.primary)) externalAttachment.bounds = Constants.iconBounds @@ -61,6 +74,10 @@ final class DashboardStatsNudgeView: UIView { titleLabel.attributedText = titleString } + @objc private func buttonTapped() { + onTap?() + } + private enum Constants { static let iconSize = CGSize(width: 16, height: 16) static let iconBounds = CGRect(x: 0, y: -2, width: 16, height: 16) diff --git a/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/CollapsableHeaderViewController.swift b/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/CollapsableHeaderViewController.swift index d63f085bf29a..8fffc5503e27 100644 --- a/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/CollapsableHeaderViewController.swift +++ b/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/CollapsableHeaderViewController.swift @@ -154,16 +154,6 @@ class CollapsableHeaderViewController: UIViewController, NoResultsViewHost { } private var minHeaderHeight: CGFloat = 0 - private var accentColor: UIColor { - return UIColor { (traitCollection: UITraitCollection) -> UIColor in - if traitCollection.userInterfaceStyle == .dark { - return UIColor.muriel(color: .primary, .shade40) - } else { - return UIColor.muriel(color: .primary, .shade50) - } - } - } - // MARK: - Static Helpers public static func closeButton(target: Any?, action: Selector) -> UIBarButtonItem { let closeButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) @@ -422,7 +412,7 @@ class CollapsableHeaderViewController: UIViewController, NoResultsViewHost { primaryActionButton.titleLabel?.font = WPStyleGuide.fontForTextStyle(.body, fontWeight: .medium) primaryActionButton.titleLabel?.adjustsFontSizeToFitWidth = true primaryActionButton.titleLabel?.adjustsFontForContentSizeCategory = true - primaryActionButton.backgroundColor = accentColor + primaryActionButton.backgroundColor = .primary primaryActionButton.layer.cornerRadius = 8 } diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index 71b9565666e9..2ee39cd7782f 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -100,21 +100,21 @@ extension AppColor.Accent: Identifiable, CustomStringConvertible { var description: String { switch self { case .pink: - return AppLocalizedString("color.pink", comment: "Title for the `Pink` app accent color") + return AppLocalizedString("color.pink", value: "Pink", comment: "Title for the `Pink` app accent color") case .red: - return AppLocalizedString("color.red", comment: "Title for the `Red` app accent color") + return AppLocalizedString("color.red", value: "Red", comment: "Title for the `Red` app accent color") case .orange: - return AppLocalizedString("color.orange", comment: "Title for the `Orange` app accent color") + return AppLocalizedString("color.orange", value: "Orange", comment: "Title for the `Orange` app accent color") case .yellow: - return AppLocalizedString("color.yellow", comment: "Title for the `Yellow` app accent color") + return AppLocalizedString("color.yellow", value: "Yellow", comment: "Title for the `Yellow` app accent color") case .celadon: - return AppLocalizedString("color.celadon", comment: "Title for the `Celadon` app accent color") + return AppLocalizedString("color.celadon", value: "Celadon", comment: "Title for the `Celadon` app accent color") case .wooCommercePurple: - return AppLocalizedString("color.wooCommercePurple", comment: "Title for the `WooCommerce Purple` app accent color") + return AppLocalizedString("color.wooCommercePurple", value: "WooCommerce Purple", comment: "Title for the `WooCommerce Purple` app accent color") case .jetpackGreen: - return AppLocalizedString("color.jetpackGreen", comment: "Title for the `Jetpack Green` app accent color") + return AppLocalizedString("color.jetpackGreen", value: "Jetpack Green", comment: "Title for the `Jetpack Green` app accent color") case .wordPressBlue: - return AppLocalizedString("color.wordPressBlue", comment: "Title for the `WordPress Blue` app accent color") + return AppLocalizedString("color.wordPressBlue", value: "WordPress Blue", comment: "Title for the `WordPress Blue` app accent color") } } diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index 19d4656bc156..f0ea646415dc 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -489,7 +489,7 @@ private extension AppSettingsViewController { var rows: [ImmuTableRow] = [] let colorModeRow = NavigationItemRow( - title: NSLocalizedString("settings.color.mode.title", comment: "The title for the app 'Color Mode' setting."), + title: NSLocalizedString("settings.color.mode.title", value: "Color Mode", comment: "The title for the app 'Color Mode' setting."), detail: AppAppearance.current.appearanceDescription, action: pushColorModeSettings() ) @@ -518,7 +518,7 @@ private extension AppSettingsViewController { } var accentColorTitle: String { - NSLocalizedString("settings.accent.color.title", comment: "The title for the app 'Accent Color' setting.") + NSLocalizedString("settings.accent.color.title", value: "Accent Color", comment: "The title for the app 'Accent Color' setting.") } func otherTableSection() -> ImmuTableSection { From 6cb41990d880cb490e89b088e9002a05fb1018b1 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Mon, 20 Mar 2023 13:03:37 +0100 Subject: [PATCH 16/17] Centralize usage of the app's new "Accent Color" --- .../Extensions/Colors and Styles/MurielColor.swift | 3 --- .../Utility/App Configuration/AppStyleGuide.swift | 3 --- .../Domains/Views/ShapeWithTextView.swift | 4 +++- .../CollapsableHeaderCollectionViewCell.swift | 14 ++------------ .../ViewRelated/NUX/SplashPrologueStyleGuide.swift | 8 ++++++-- .../ReaderInterestsStyleGuide.swift | 2 +- .../Preview/TemplatePreviewViewController.swift | 12 +----------- WordPress/Jetpack/AppStyleGuide.swift | 3 --- 8 files changed, 13 insertions(+), 36 deletions(-) diff --git a/WordPress/Classes/Extensions/Colors and Styles/MurielColor.swift b/WordPress/Classes/Extensions/Colors and Styles/MurielColor.swift index 360866ad5927..7bfc3b35c5a0 100644 --- a/WordPress/Classes/Extensions/Colors and Styles/MurielColor.swift +++ b/WordPress/Classes/Extensions/Colors and Styles/MurielColor.swift @@ -59,12 +59,9 @@ struct MurielColor { } // MARK: - Muriel's semantic colors - static let accent = AppStyleGuide.accent - static let brand = AppStyleGuide.brand static let divider = AppStyleGuide.divider static let error = AppStyleGuide.error static let gray = AppStyleGuide.gray - static let primary = AppStyleGuide.primary static let success = AppStyleGuide.success static let text = AppStyleGuide.text static let textSubtle = AppStyleGuide.textSubtle diff --git a/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift b/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift index a52e9f8c6760..b832d3de3f92 100644 --- a/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift +++ b/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift @@ -13,12 +13,9 @@ struct AppStyleGuide { // MARK: - Colors extension AppStyleGuide { - static let accent = MurielColor(name: .pink) - static let brand = MurielColor(name: .wordPressBlue) static let divider = MurielColor(name: .gray, shade: .shade10) static let error = MurielColor(name: .red) static let gray = MurielColor(name: .gray) - static let primary = MurielColor(name: .blue) static let success = MurielColor(name: .green) static let text = MurielColor(name: .gray, shade: .shade80) static let textSubtle = MurielColor(name: .gray, shade: .shade50) diff --git a/WordPress/Classes/ViewRelated/Domains/Views/ShapeWithTextView.swift b/WordPress/Classes/ViewRelated/Domains/Views/ShapeWithTextView.swift index 9ef91e9fb407..7a4b42958e6d 100644 --- a/WordPress/Classes/ViewRelated/Domains/Views/ShapeWithTextView.swift +++ b/WordPress/Classes/ViewRelated/Domains/Views/ShapeWithTextView.swift @@ -35,7 +35,9 @@ struct ShapeWithTextView: View { // large rounded rectangle static let largeRoundedRectangleCornerRadius: CGFloat = 8.0 static let largeRoundedRectangleTextPadding: CGFloat = 12.0 - static let largeRoundedRectangleDefaultTextColor = Color(UIColor.muriel(color: .primary)) + static var largeRoundedRectangleDefaultTextColor: Color { + .init(UIColor.primary) + } // small rounded rectangle static let smallRoundedRectangleCornerRadius: CGFloat = 4.0 static let smallRoundedRectangleInsets = EdgeInsets(top: 4.0, leading: 8.0, bottom: 4.0, trailing: 8.0) diff --git a/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/Collapsable Header Collection View Cell/CollapsableHeaderCollectionViewCell.swift b/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/Collapsable Header Collection View Cell/CollapsableHeaderCollectionViewCell.swift index 3316164a7442..3827b1dbd39f 100644 --- a/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/Collapsable Header Collection View Cell/CollapsableHeaderCollectionViewCell.swift +++ b/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/Collapsable Header Collection View Cell/CollapsableHeaderCollectionViewCell.swift @@ -12,7 +12,7 @@ class CollapsableHeaderCollectionViewCell: UICollectionViewCell { @IBOutlet weak var checkmarkImageView: UIImageView! { didSet { checkmarkImageView.image = UIImage(systemName: "checkmark.circle.fill") - checkmarkImageView.tintColor = accentColor + checkmarkImageView.tintColor = .primary } } @@ -34,16 +34,6 @@ class CollapsableHeaderCollectionViewCell: UICollectionViewCell { stopGhostAnimation() } - var accentColor: UIColor { - return UIColor { (traitCollection: UITraitCollection) -> UIColor in - if traitCollection.userInterfaceStyle == .dark { - return UIColor.muriel(color: .primary, .shade40) - } else { - return UIColor.muriel(color: .primary, .shade50) - } - } - } - var borderColor: UIColor { return UIColor.black.withAlphaComponent(0.08) } @@ -94,7 +84,7 @@ class CollapsableHeaderCollectionViewCell: UICollectionViewCell { } private func styleSelectedBorder(animated: Bool = false) { - let imageBorderColor = isSelected ? accentColor.cgColor : borderColor.cgColor + let imageBorderColor = isSelected ? UIColor.primary.cgColor : borderColor.cgColor let imageBorderWidth = isSelected ? 2 : borderWith guard animated else { imageView.layer.borderColor = imageBorderColor diff --git a/WordPress/Classes/ViewRelated/NUX/SplashPrologueStyleGuide.swift b/WordPress/Classes/ViewRelated/NUX/SplashPrologueStyleGuide.swift index c571837503df..1d78f337f447 100644 --- a/WordPress/Classes/ViewRelated/NUX/SplashPrologueStyleGuide.swift +++ b/WordPress/Classes/ViewRelated/NUX/SplashPrologueStyleGuide.swift @@ -15,10 +15,14 @@ struct SplashPrologueStyleGuide { } /// Use the same shade for light and dark modes - private static let primaryButtonColor: UIColor = .muriel(color: .primary) + private static var primaryButtonColor: UIColor { + .primary .resolvedColor(with: UITraitCollection(userInterfaceStyle: .light)) - private static let primaryButtonHighlightedColor: UIColor = .muriel(color: .primary, .shade60) + } + private static var primaryButtonHighlightedColor: UIColor { + .primary(.shade60) .resolvedColor(with: UITraitCollection(userInterfaceStyle: .light)) + } private static let secondaryButtonColor: UIColor = .white private static let secondaryButtonHighlightedColor: UIColor = .muriel(color: .gray, .shade5) diff --git a/WordPress/Classes/ViewRelated/Reader/Select Interests/ReaderInterestsStyleGuide.swift b/WordPress/Classes/ViewRelated/Reader/Select Interests/ReaderInterestsStyleGuide.swift index 1382017aa3a8..4c405885de02 100644 --- a/WordPress/Classes/ViewRelated/Reader/Select Interests/ReaderInterestsStyleGuide.swift +++ b/WordPress/Classes/ViewRelated/Reader/Select Interests/ReaderInterestsStyleGuide.swift @@ -21,7 +21,7 @@ class ReaderInterestsStyleGuide { public class func applyCellLabelStyle(label: UILabel, isSelected: Bool) { label.font = WPStyleGuide.fontForTextStyle(.body) label.textColor = isSelected ? .white : .text - label.backgroundColor = isSelected ? .muriel(color: .primary, .shade40) : .quaternaryBackground + label.backgroundColor = isSelected ? .primary(.shade40) : .quaternaryBackground } // MARK: - Compact Collection View Cell Styles diff --git a/WordPress/Classes/ViewRelated/Site Creation/Design Selection/Preview/TemplatePreviewViewController.swift b/WordPress/Classes/ViewRelated/Site Creation/Design Selection/Preview/TemplatePreviewViewController.swift index ce751926e2f5..ce4faa2c567b 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Design Selection/Preview/TemplatePreviewViewController.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Design Selection/Preview/TemplatePreviewViewController.swift @@ -44,16 +44,6 @@ class TemplatePreviewViewController: UIViewController, NoResultsViewHost, UIPopo return ghost }() - private var accentColor: UIColor { - return UIColor { (traitCollection: UITraitCollection) -> UIColor in - if traitCollection.userInterfaceStyle == .dark { - return UIColor.muriel(color: .primary, .shade40) - } else { - return UIColor.muriel(color: .primary, .shade50) - } - } - } - init(demoURL: String, selectedPreviewDevice: PreviewDevice?, onDismissWithDeviceSelected: ((PreviewDevice) -> ())?) { self.demoURL = demoURL self.selectedPreviewDevice = selectedPreviewDevice ?? PreviewDevice.default @@ -101,7 +91,7 @@ class TemplatePreviewViewController: UIViewController, NoResultsViewHost, UIPopo private func styleButtons() { primaryActionButton.titleLabel?.font = WPStyleGuide.fontForTextStyle(.body, fontWeight: .medium) - primaryActionButton.backgroundColor = accentColor + primaryActionButton.backgroundColor = .primary primaryActionButton.layer.cornerRadius = 8 primaryActionButton.setTitle(NSLocalizedString("Choose", comment: "Title for the button to progress with the selected site homepage design"), for: .normal) } diff --git a/WordPress/Jetpack/AppStyleGuide.swift b/WordPress/Jetpack/AppStyleGuide.swift index 0f9343cc21ca..efab86bdad22 100644 --- a/WordPress/Jetpack/AppStyleGuide.swift +++ b/WordPress/Jetpack/AppStyleGuide.swift @@ -14,12 +14,9 @@ struct AppStyleGuide { // MARK: - Colors extension AppStyleGuide { - static let accent = MurielColor(name: .jetpackGreen) - static let brand = MurielColor(name: .jetpackGreen) static let divider = MurielColor(name: .gray, shade: .shade10) static let error = MurielColor(name: .red) static let gray = MurielColor(name: .gray) - static let primary = MurielColor(name: .jetpackGreen) static let success = MurielColor(name: .green) static let text = MurielColor(name: .gray, shade: .shade80) static let textSubtle = MurielColor(name: .gray, shade: .shade50) From bb4ba66dcb4bf074ed4495fa73e549a1850832b8 Mon Sep 17 00:00:00 2001 From: Marko Tadic Date: Tue, 21 Mar 2023 14:30:58 +0100 Subject: [PATCH 17/17] Configure exact color names & shades for the dark mode --- .../Me/App Settings/App Color/AppColor.swift | 53 ++++++++++--------- .../App Color/AppColorListView.swift | 1 + 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift index 2ee39cd7782f..5b857cdefd89 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColor.swift @@ -40,6 +40,10 @@ enum AppColor { // MARK: Helpers + fileprivate static var isDarkMode: Bool { + UITraitCollection.current.userInterfaceStyle == .dark + } + private static var defaultAccent: Accent { switch appConfig { case .wordpress: @@ -93,6 +97,15 @@ enum AppColor { } extension AppColor.Accent: Identifiable, CustomStringConvertible { + + static var allCasesSorted: [Self] { + var all = allCases + let firstAccent = AppColor.defaultAccent + all.removeAll(where: { $0 == firstAccent }) + all.insert(firstAccent, at: 0) + return all + } + var id: String { rawValue } @@ -123,42 +136,42 @@ extension AppColor.Accent: Identifiable, CustomStringConvertible { case .pink: return .dynamic( light: .muriel(murielName, shade: .shade60), - dark: .muriel(murielName, shade: .shade60) + dark: .muriel(murielName, shade: .shade30) ) case .red: return .dynamic( light: .muriel(murielName, shade: .shade60), - dark: .muriel(murielName, shade: .shade60) + dark: .muriel(murielName, shade: .shade30) ) case .orange: return .dynamic( - light: .muriel(murielName), - dark: .muriel(murielName) + light: .muriel(murielName, shade: .shade50), + dark: .muriel(murielName, shade: .shade30) ) case .yellow: return .dynamic( - light: .muriel(murielName), - dark: .muriel(murielName) + light: .muriel(murielName, shade: .shade50), + dark: .muriel(murielName, shade: .shade20) ) case .celadon: return .dynamic( light: .muriel(murielName, shade: .shade60), - dark: .muriel(murielName, shade: .shade60) + dark: .muriel(murielName, shade: .shade20) ) case .wooCommercePurple: return .dynamic( light: .muriel(murielName, shade: .shade60), - dark: .muriel(murielName, shade: .shade60) + dark: .muriel(murielName, shade: .shade20) ) case .jetpackGreen: return .dynamic( - light: .muriel(murielName), - dark: .muriel(murielName) + light: .muriel(murielName, shade: .shade50), + dark: .muriel(murielName, shade: .shade30) ) case .wordPressBlue: return .dynamic( - light: .muriel(murielName), - dark: .muriel(murielName) + light: .muriel(murielName, shade: .shade50), + dark: .muriel(murielName, shade: .shade50) ) } } @@ -178,19 +191,12 @@ extension AppColor.Accent: Identifiable, CustomStringConvertible { case .wooCommercePurple: return .wooCommercePurple case .jetpackGreen: - return .jetpackGreen + return AppColor.isDarkMode ? .green : .jetpackGreen case .wordPressBlue: - return .wordPressBlue + return AppColor.isDarkMode ? .blue : .wordPressBlue } } - static var allCasesSorted: [Self] { - var all = allCases - let firstAccent = AppColor.defaultAccent - all.removeAll(where: { $0 == firstAccent }) - all.insert(firstAccent, at: 0) - return all - } } extension Foundation.Notification.Name { @@ -204,10 +210,7 @@ extension Foundation.Notification.Name { } private extension Color { - static func muriel( - _ name: MurielColorName, - shade: MurielColorShade = .shade50 - ) -> Self { + static func muriel(_ name: MurielColorName, shade: MurielColorShade) -> Self { .init( UIColor.muriel(color: .init(name: name, shade: shade)) ) diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift index a9ec39d89d10..012ce89547d5 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/App Color/AppColorListView.swift @@ -1,6 +1,7 @@ import SwiftUI struct AppColorListView: View { + @SwiftUI.Environment(\.colorScheme) var colorScheme @StateObject var vm = AppColorListViewModel()