IceCubesApp/Packages/DesignSystem/Sources/DesignSystem/ThemeApplier.swift

103 lines
3.2 KiB
Swift
Raw Normal View History

import SwiftUI
#if canImport(UIKit)
2023-01-17 10:36:01 +00:00
import UIKit
#endif
public extension View {
2023-01-17 10:36:01 +00:00
func applyTheme(_ theme: Theme) -> some View {
modifier(ThemeApplier(theme: theme))
}
}
2023-09-18 19:03:52 +00:00
@MainActor
struct ThemeApplier: ViewModifier {
@Environment(\EnvironmentValues.colorScheme) var colorScheme
2023-01-22 05:38:30 +00:00
2023-09-18 19:03:52 +00:00
var theme: Theme
2023-01-22 05:38:30 +00:00
var actualColorScheme: SwiftUI.ColorScheme? {
if theme.followSystemColorScheme {
return nil
}
return theme.selectedScheme == ColorScheme.dark ? .dark : .light
}
2023-01-17 10:36:01 +00:00
func body(content: Content) -> some View {
content
.tint(theme.tintColor)
.preferredColorScheme(actualColorScheme)
#if canImport(UIKit)
2023-01-17 10:36:01 +00:00
.onAppear {
// If theme is never set before set the default store. This should only execute once after install.
if !theme.isThemePreviouslySet {
2023-09-20 06:20:01 +00:00
theme.applySet(set: colorScheme == .dark ? .iceCubeDark : .iceCubeLight)
theme.isThemePreviouslySet = true
2023-01-22 05:38:30 +00:00
} else if theme.followSystemColorScheme, theme.isThemePreviouslySet,
let sets = availableColorsSets
2023-01-22 05:38:30 +00:00
.first(where: { $0.light.name == theme.selectedSet || $0.dark.name == theme.selectedSet })
{
2023-09-20 06:20:01 +00:00
theme.applySet(set: colorScheme == .dark ? sets.dark.name : sets.light.name)
}
2023-01-17 10:36:01 +00:00
setWindowTint(theme.tintColor)
setWindowUserInterfaceStyle(from: theme.selectedScheme)
2023-01-17 10:36:01 +00:00
setBarsColor(theme.primaryBackgroundColor)
}
.onChange(of: theme.tintColor) { _, newValue in
2023-01-17 10:36:01 +00:00
setWindowTint(newValue)
}
.onChange(of: theme.primaryBackgroundColor) { _, newValue in
2023-01-17 10:36:01 +00:00
setBarsColor(newValue)
}
.onChange(of: theme.selectedScheme) { _, newValue in
2023-01-30 06:27:06 +00:00
setWindowUserInterfaceStyle(from: newValue)
}
.onChange(of: colorScheme) { _, newColorScheme in
if theme.followSystemColorScheme,
let sets = availableColorsSets
2023-01-22 05:38:30 +00:00
.first(where: { $0.light.name == theme.selectedSet || $0.dark.name == theme.selectedSet })
{
2023-09-20 06:20:01 +00:00
theme.applySet(set: newColorScheme == .dark ? sets.dark.name : sets.light.name)
}
}
2023-01-17 10:36:01 +00:00
#endif
}
#if canImport(UIKit)
private func setWindowUserInterfaceStyle(from colorScheme: ColorScheme) {
guard !theme.followSystemColorScheme else {
2023-01-30 06:27:06 +00:00
setWindowUserInterfaceStyle(.unspecified)
return
}
switch colorScheme {
case .dark:
setWindowUserInterfaceStyle(.dark)
case .light:
setWindowUserInterfaceStyle(.light)
}
}
2023-01-30 06:27:06 +00:00
private func setWindowUserInterfaceStyle(_ userInterfaceStyle: UIUserInterfaceStyle) {
2024-02-14 11:48:14 +00:00
for window in allWindows() {
window.overrideUserInterfaceStyle = userInterfaceStyle
}
}
2023-01-30 06:27:06 +00:00
private func setWindowTint(_ color: Color) {
2024-02-14 11:48:14 +00:00
for window in allWindows() {
window.tintColor = UIColor(color)
}
}
2023-01-17 10:36:01 +00:00
private func setBarsColor(_ color: Color) {
2023-01-17 10:36:01 +00:00
UINavigationBar.appearance().isTranslucent = true
UINavigationBar.appearance().barTintColor = UIColor(color)
}
2023-01-17 10:36:01 +00:00
private func allWindows() -> [UIWindow] {
2023-01-17 10:36:01 +00:00
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
2023-09-16 12:15:03 +00:00
.flatMap(\.windows)
}
2023-01-17 10:36:01 +00:00
#endif
}