From 5e24c1ee5896d65922fc617981a9743044781099 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Sat, 24 Dec 2022 14:55:04 +0100 Subject: [PATCH] Early WIP of theming support --- .../App/AppAccounts/AppAccountsManager.swift | 3 ++ IceCubesApp/App/IceCubesApp.swift | 8 +++- .../App/Tabs/Settings/SettingsTab.swift | 16 ++++++++ .../DesignSystem/Resources/Colors.swift | 35 +++++++++++++++++ .../brand.colorset/Contents.json | 6 +-- .../label.colorset/Contents.json | 28 ++++++++++++++ .../primaryBackground.colorset/Contents.json | 38 +++++++++++++++++++ .../Contents.json | 38 +++++++++++++++++++ .../Sources/DesignSystem/Theme.swift | 14 +++++++ 9 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/label.colorset/Contents.json create mode 100644 Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/primaryBackground.colorset/Contents.json create mode 100644 Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/secondaryBackground.colorset/Contents.json create mode 100644 Packages/DesignSystem/Sources/DesignSystem/Theme.swift diff --git a/IceCubesApp/App/AppAccounts/AppAccountsManager.swift b/IceCubesApp/App/AppAccounts/AppAccountsManager.swift index d0e2b21c..fceed968 100644 --- a/IceCubesApp/App/AppAccounts/AppAccountsManager.swift +++ b/IceCubesApp/App/AppAccounts/AppAccountsManager.swift @@ -8,15 +8,18 @@ class AppAccountsManager: ObservableObject { oauthToken: currentAccount.oauthToken) } } + @Published var availableAccount: [AppAccount] @Published var currentClient: Client init() { var defaultAccount = AppAccount(server: IceCubesApp.defaultServer, oauthToken: nil) do { let keychainAccounts = try AppAccount.retrieveAll() + availableAccount = keychainAccounts defaultAccount = keychainAccounts.last ?? defaultAccount } catch {} currentAccount = defaultAccount + availableAccount = [defaultAccount] currentClient = .init(server: defaultAccount.server, oauthToken: defaultAccount.oauthToken) } diff --git a/IceCubesApp/App/IceCubesApp.swift b/IceCubesApp/App/IceCubesApp.swift index a355f3dc..1205fc1b 100644 --- a/IceCubesApp/App/IceCubesApp.swift +++ b/IceCubesApp/App/IceCubesApp.swift @@ -3,6 +3,7 @@ import Timeline import Network import KeychainSwift import Env +import DesignSystem @main struct IceCubesApp: App { @@ -11,10 +12,12 @@ struct IceCubesApp: App { } public static let defaultServer = "mastodon.social" - + @StateObject private var appAccountsManager = AppAccountsManager() @StateObject private var currentAccount = CurrentAccount() @StateObject private var quickLook = QuickLook() + @StateObject private var theme = Theme() + @State private var selectedTab: Tab = .timeline @State private var popToRootTab: Tab = .other @@ -60,7 +63,7 @@ struct IceCubesApp: App { } .tag(Tab.settings) } - .tint(.brand) + .tint(theme.tintColor) .onChange(of: appAccountsManager.currentClient) { newClient in currentAccount.setClient(client: newClient) } @@ -71,6 +74,7 @@ struct IceCubesApp: App { .environmentObject(appAccountsManager.currentClient) .environmentObject(quickLook) .environmentObject(currentAccount) + .environmentObject(theme) .quickLookPreview($quickLook.url, in: quickLook.urls) } } diff --git a/IceCubesApp/App/Tabs/Settings/SettingsTab.swift b/IceCubesApp/App/Tabs/Settings/SettingsTab.swift index cbba3ec2..27bc488b 100644 --- a/IceCubesApp/App/Tabs/Settings/SettingsTab.swift +++ b/IceCubesApp/App/Tabs/Settings/SettingsTab.swift @@ -4,11 +4,13 @@ import Env import Network import Account import Models +import DesignSystem struct SettingsTabs: View { @Environment(\.openURL) private var openURL @EnvironmentObject private var client: Client @EnvironmentObject private var appAccountsManager: AppAccountsManager + @EnvironmentObject private var theme: Theme @State private var signInInProgress = false @State private var accountData: Account? @@ -20,6 +22,7 @@ struct SettingsTabs: View { Form { appSection accountSection + themeSection instanceSection } .onOpenURL(perform: { url in @@ -59,6 +62,19 @@ struct SettingsTabs: View { } } + private var themeSection: some View { + Section("Theme") { + ColorPicker("Tint color", selection: $theme.tintColor) + Button { + theme.tintColor = .brand + theme.labelColor = .label + } label: { + Text("Restore default") + } + + } + } + @ViewBuilder private var instanceSection: some View { if let instanceData { diff --git a/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.swift b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.swift index a0ebe209..d4c88685 100644 --- a/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.swift +++ b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.swift @@ -4,4 +4,39 @@ extension Color { public static var brand: Color { Color("brand", bundle: .module) } + + public static var primaryBackground: Color { + Color("primaryBackground", bundle: .module) + } + + public static var secondaryBackground: Color { + Color("secondaryBackground", bundle: .module) + } + + public static var label: Color { + Color("label", bundle: .module) + } +} + +extension Color: RawRepresentable { + public init?(rawValue: Int) { + let red = Double((rawValue & 0xFF0000) >> 16) / 0xFF + let green = Double((rawValue & 0x00FF00) >> 8) / 0xFF + let blue = Double(rawValue & 0x0000FF) / 0xFF + self = Color(red: red, green: green, blue: blue) + } + + public var rawValue: Int { + guard let coreImageColor = coreImageColor else { + return 0 + } + let red = Int(coreImageColor.red * 255 + 0.5) + let green = Int(coreImageColor.green * 255 + 0.5) + let blue = Int(coreImageColor.blue * 255 + 0.5) + return (red << 16) | (green << 8) | blue + } + + private var coreImageColor: CIColor? { + return CIColor(color: .init(self)) + } } diff --git a/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/brand.colorset/Contents.json b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/brand.colorset/Contents.json index 53a10836..6c46e5d4 100644 --- a/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/brand.colorset/Contents.json +++ b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/brand.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "255", - "green" : "90", - "red" : "89" + "blue" : "1.000", + "green" : "0.353", + "red" : "0.349" } }, "idiom" : "universal" diff --git a/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/label.colorset/Contents.json b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/label.colorset/Contents.json new file mode 100644 index 00000000..1effc4f1 --- /dev/null +++ b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/label.colorset/Contents.json @@ -0,0 +1,28 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "universal", + "reference" : "labelColor" + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "platform" : "universal", + "reference" : "labelColor" + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/primaryBackground.colorset/Contents.json b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/primaryBackground.colorset/Contents.json new file mode 100644 index 00000000..22763ba6 --- /dev/null +++ b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/primaryBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x22", + "green" : "0x1B", + "red" : "0x19" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x22", + "green" : "0x1B", + "red" : "0x19" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/secondaryBackground.colorset/Contents.json b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/secondaryBackground.colorset/Contents.json new file mode 100644 index 00000000..73d24611 --- /dev/null +++ b/Packages/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/secondaryBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x37", + "green" : "0x2C", + "red" : "0x28" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x37", + "green" : "0x2C", + "red" : "0x28" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Packages/DesignSystem/Sources/DesignSystem/Theme.swift b/Packages/DesignSystem/Sources/DesignSystem/Theme.swift new file mode 100644 index 00000000..07651713 --- /dev/null +++ b/Packages/DesignSystem/Sources/DesignSystem/Theme.swift @@ -0,0 +1,14 @@ +import SwiftUI + +public class Theme: ObservableObject { + enum ThemeKey: String { + case tint, label, primaryBackground, secondaryBackground + } + + @AppStorage(ThemeKey.tint.rawValue) public var tintColor: Color = .brand + @AppStorage(ThemeKey.primaryBackground.rawValue) public var primaryBackgroundColor: Color = .primaryBackground + @AppStorage(ThemeKey.secondaryBackground.rawValue) public var secondaryBackgroundColor: Color = .secondaryBackground + @AppStorage(ThemeKey.label.rawValue) public var labelColor: Color = .label + + public init() { } +}