5bc81d5b3b
iOS SwiftUI app with Supabase auth/realtime, Node.js backend, Docker/Supabase self-hosted infrastructure, and APNs scheduler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
68 lines
2.2 KiB
Swift
68 lines
2.2 KiB
Swift
import SwiftUI
|
|
|
|
@main
|
|
struct NightlyApp: App {
|
|
@StateObject private var appState = AppState()
|
|
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
|
|
|
var body: some Scene {
|
|
WindowGroup {
|
|
RootView()
|
|
.environmentObject(appState)
|
|
.preferredColorScheme(.dark)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - App Delegate
|
|
|
|
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
|
|
|
|
func application(
|
|
_ application: UIApplication,
|
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
) -> Bool {
|
|
UNUserNotificationCenter.current().delegate = self
|
|
return true
|
|
}
|
|
|
|
// ⚠️ Push Notifications: erfordert bezahlten Apple Developer Account ($99/Jahr)
|
|
// Ohne Developer-Account kann dieser Code nicht getestet werden (nur Simulator ohne Pushs)
|
|
func application(
|
|
_ application: UIApplication,
|
|
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
|
|
) {
|
|
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
|
|
Task { try? await supabase.savePushToken(token) }
|
|
}
|
|
|
|
func application(
|
|
_ application: UIApplication,
|
|
didFailToRegisterForRemoteNotificationsWithError error: Error
|
|
) {
|
|
print("APNs Registrierung fehlgeschlagen:", error.localizedDescription)
|
|
// Häufige Ursache: kein bezahlter Developer Account
|
|
}
|
|
|
|
func userNotificationCenter(
|
|
_ center: UNUserNotificationCenter,
|
|
willPresent notification: UNNotification,
|
|
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
|
|
) {
|
|
completionHandler([.banner, .sound, .badge])
|
|
}
|
|
|
|
func userNotificationCenter(
|
|
_ center: UNUserNotificationCenter,
|
|
didReceive response: UNNotificationResponse,
|
|
withCompletionHandler completionHandler: @escaping () -> Void
|
|
) {
|
|
NotificationCenter.default.post(name: .nightlyPingReceived, object: nil)
|
|
completionHandler()
|
|
}
|
|
}
|
|
|
|
extension Notification.Name {
|
|
static let nightlyPingReceived = Notification.Name("nightlyPingReceived")
|
|
}
|