krz/moonrise

Night-sky companion for iPhone, Apple Watch and Vision Pro: what's up tonight, the Moon, planets, launches and missions, and a Library of the solar system. SwiftUI app with a Cloudflare Workers backend. astronomy cloudflare-workers ios night-sky space swiftui visionos watchos

Commit 906cb6df4f

906cb6df4f93a45c7d9b546cb7db7152eb12d11d

parent: 014330d266

Verified · cmc

cmc <hello@cleberg.net> · 2026-10-18 05:53 UTC

Tint the tab bar red while the Sky tab is in night mode

The Sky tab publishes its night state (nightActive); the root TabView
tints the selected tab red when Sky is selected and night mode is on.

Layout: unified · split

App/Sources/Info.plist −16
@@ -2,22 +2,6 @@
22<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33<plist version="1.0">
44<dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>$(DEVELOPMENT_LANGUAGE)</string>
7 <key>CFBundleExecutable</key>
8 <string>$(EXECUTABLE_NAME)</string>
9 <key>CFBundleIdentifier</key>
10 <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11 <key>CFBundleInfoDictionaryVersion</key>
12 <string>6.0</string>
13 <key>CFBundleName</key>
14 <string>$(PRODUCT_NAME)</string>
15 <key>CFBundlePackageType</key>
16 <string>APPL</string>
17 <key>CFBundleShortVersionString</key>
18 <string>1.0</string>
19 <key>CFBundleVersion</key>
20 <string>1</string>
215 <key>MoonriseAPIURL</key>
226 <string>$(MOONRISE_API_URL)</string>
237 <key>NSAppTransportSecurity</key>
App/Sources/MoonriseApp.swift +10 −6
@@ -8,16 +8,20 @@ let log = Logger(subsystem: "sh.krz.moonrise", category: "app")
88struct MoonriseApp: App {
99 @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
1010 @AppStorage(SettingsKey.onboarded) private var onboarded = false
11 @AppStorage(SettingsKey.nightActive) private var nightActive = false
12 @State private var tab = "sky"
1113
1214 var body: some Scene {
1315 WindowGroup {
14 TabView {
15 Tab("Sky", systemImage: "sparkles") { SkyScreen() }
16 Tab("System", systemImage: "circle.circle") { SystemScreen() }
17 Tab("Sun", systemImage: "sun.max") { SunScreen() }
18 Tab("Launches", systemImage: "airplane.departure") { LaunchesScreen() }
19 Tab("Library", systemImage: "books.vertical") { LibraryScreen() }
16 TabView(selection: $tab) {
17 Tab("Sky", systemImage: "sparkles", value: "sky") { SkyScreen() }
18 Tab("System", systemImage: "circle.circle", value: "system") { SystemScreen() }
19 Tab("Sun", systemImage: "sun.max", value: "sun") { SunScreen() }
20 Tab("Launches", systemImage: "airplane.departure", value: "launches") { LaunchesScreen() }
21 Tab("Library", systemImage: "books.vertical", value: "library") { LibraryScreen() }
2022 }
23 // Red tab highlight while the Sky tab is in night mode.
24 .tint(tab == "sky" && nightActive ? Color(red: 0.85, green: 0.12, blue: 0.08) : nil)
2125 .preferredColorScheme(.dark)
2226 .fullScreenCover(isPresented: .constant(!onboarded)) {
2327 OnboardingScreen().preferredColorScheme(.dark)
App/Sources/SettingsScreen.swift +2
@@ -9,6 +9,8 @@ enum SettingsKey {
99 static let cityLongitude = "cityLongitude"
1010 static let nightMode = "nightMode" // "off", "on" or "auto"
1111 static let onboarded = "onboarded"
12 /// Whether the Sky tab is currently drawn in night mode (written by the Sky tab).
13 static let nightActive = "nightActive"
1214}
1315
1416struct City: Hashable, Identifiable {
App/Sources/SkyScreen.swift +2
@@ -12,6 +12,7 @@ struct SkyScreen: View {
1212 @AppStorage(SettingsKey.nightMode) private var nightMode = "auto"
1313 @State private var showSettings = false
1414 @AppStorage(SettingsKey.onboarded) private var onboarded = false
15 @AppStorage(SettingsKey.nightActive) private var nightActive = false
1516 @State private var showToday = false
1617 @State private var libraryPage: LibraryPage?
1718 @State private var selection: SkyObject?
@@ -68,6 +69,7 @@ struct SkyScreen: View {
6869 }
6970 .onChange(of: model.offsetHours) { select(selection) }
7071 .onChange(of: onboarded) { if onboarded { model.start() } }
72 .onChange(of: night, initial: true) { nightActive = night }
7173 .task {
7274 if onboarded { model.start() }
7375 while !Task.isCancelled {