App/Sources/MoonriseApp.swift
68 lines · 3147 bytes
1import SkyRenderer
2import SwiftUI
3import UIKit
4import UserNotifications
5import os
6
7let log = Logger(subsystem: "sh.krz.moonrise", category: "app")
8
9@main
10struct MoonriseApp: App {
11 @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
12 @AppStorage(SettingsKey.onboarded) private var onboarded = false
13 @AppStorage(SettingsKey.nightActive) private var nightActive = false
14 @State private var router = Router.shared
15
16 var body: some Scene {
17 WindowGroup {
18 TabView(selection: $router.tab) {
19 Tab("Sky", systemImage: "sparkles", value: "sky") { SkyScreen() }
20 Tab("System", systemImage: "circle.circle", value: "system") { SystemScreen() }
21 Tab("Sun", systemImage: "sun.max", value: "sun") { SunScreen() }
22 Tab("News & launches", systemImage: "airplane.departure", value: "launches") { LaunchesScreen() }
23 Tab("Library", systemImage: "books.vertical", value: "library") { LibraryScreen() }
24 }
25 .tabViewStyle(.sidebarAdaptable)
26 // Red tab highlight while the Sky tab is in night mode.
27 .tint(router.tab == "sky" && nightActive ? SkyStyle.nightRed : nil)
28 .preferredColorScheme(.dark)
29 .environment(\.openURL, InAppBrowser.action)
30 .fullScreenCover(isPresented: .constant(!onboarded)) {
31 OnboardingScreen().preferredColorScheme(.dark)
32 }
33 }
34 }
35}
36
37final class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
38 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
39 ImageLoader.configureURLCache()
40 UNUserNotificationCenter.current().delegate = self
41 application.registerForRemoteNotifications()
42 return true
43 }
44
45 func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
46 let token = deviceToken.map { String(format: "%02x", $0) }.joined()
47 log.info("APNs device token: \(token, privacy: .public)")
48 Task { @MainActor in AuroraAlerts.shared.receivedToken(token) }
49 }
50
51 /// A news digest opens News & launches on the News switch.
52 nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
53 guard response.notification.request.content.userInfo["tab"] as? String == "news" else { return }
54 await MainActor.run {
55 Router.shared.tab = "launches"
56 Router.shared.showNews = true
57 }
58 }
59
60 /// Show alerts as banners while the app is open.
61 nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
62 [.banner, .sound]
63 }
64
65 func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
66 log.error("APNs registration failed: \(error.localizedDescription, privacy: .public)")
67 }
68}