import SwiftUI extension Color { init(hex: UInt32, alpha: Double = 1) { self.init(.sRGB, red: Double((hex >> 16) & 0xFF) / 255, green: Double((hex >> 8) & 0xFF) / 255, blue: Double(hex & 0xFF) / 255, opacity: alpha) } } /// The three themes' colours. Black is true black for OLED; no gradients anywhere. struct Palette { var dark: Bool var bg: Color var groupedBg: Color var cell: Color var fill: Color var fillStrong: Color var label: Color var label2: Color var label3: Color var separator: Color var placeholder: Color var accent: Color var red: Color static func of(_ mode: ThemeMode, _ accent: Accent) -> Palette { switch mode { case .Black: Palette(dark: true, bg: Color(hex: 0x000000), groupedBg: Color(hex: 0x000000), cell: Color(hex: 0x1C1C1E), fill: Color(hex: 0x1C1C1E), fillStrong: Color(hex: 0x3A3A3C), label: .white, label2: Color(hex: 0x8D8D93), label3: Color(hex: 0x48484A), separator: Color(hex: 0x2C2C2E), placeholder: Color(hex: 0x1C1C1E), accent: Color(hex: accent.dark), red: Color(hex: 0xFF453A)) case .Dark: Palette(dark: true, bg: Color(hex: 0x1C1C1E), groupedBg: Color(hex: 0x1C1C1E), cell: Color(hex: 0x2C2C2E), fill: Color(hex: 0x2C2C2E), fillStrong: Color(hex: 0x48484A), label: .white, label2: Color(hex: 0x98989D), label3: Color(hex: 0x5A5A5E), separator: Color(hex: 0x3D3D40), placeholder: Color(hex: 0x3A3A3C), accent: Color(hex: accent.dark), red: Color(hex: 0xFF453A)) case .White: Palette(dark: false, bg: Color(hex: 0xFFFFFF), groupedBg: Color(hex: 0xF2F2F7), cell: Color(hex: 0xFFFFFF), fill: Color(hex: 0xEFEFF0), fillStrong: Color(hex: 0xE3E3E8), label: .black, label2: Color(hex: 0x8A8A8E), label3: Color(hex: 0xC4C4C7), separator: Color(hex: 0xD8D8DC), placeholder: Color(hex: 0xE5E5EA), accent: Color(hex: accent.light), red: Color(hex: 0xFF3B30)) } } } private struct PaletteKey: EnvironmentKey { static let defaultValue = Palette.of(.Black, .Music) } extension EnvironmentValues { var palette: Palette { get { self[PaletteKey.self] } set { self[PaletteKey.self] = newValue } } } extension View { /// A list on the theme's background instead of the system one. func themedList(grouped: Bool = true) -> some View { modifier(ThemedList(grouped: grouped)) } /// Rows on the theme's cell colour. func themedRow(grouped: Bool = true) -> some View { modifier(ThemedRow(grouped: grouped)) } } private struct ThemedList: ViewModifier { @Environment(\.palette) private var p let grouped: Bool func body(content: Content) -> some View { content.scrollContentBackground(.hidden).background(grouped ? p.groupedBg : p.bg) } } private struct ThemedRow: ViewModifier { @Environment(\.palette) private var p let grouped: Bool func body(content: Content) -> some View { content.listRowBackground(grouped ? p.cell : p.bg).listRowSeparatorTint(p.separator) } }