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>
This commit is contained in:
1 parent
45bc0eefe0
commit
fdf9e970b2
45 files changed
+9822
No files matched your search
@@ -0,0 +1,80 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user