Files
stemify/ios/Stemify/UI/Theme.swift
T
cdnutterandClaude Opus 5.5 fdf9e970b2 Add iOS app with CarPlay and Siri
SwiftUI port of the Android app under ios/, with CarPlay browse and
Now Playing, Siri play-media intents, and a build-ipa.sh script that
makes an unsigned IPA for sideloading. README gets an iOS section and
the vibecoded disclaimer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:15:47 -07:00

81 lines
3.2 KiB
Swift

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)
}
}