import SwiftUI import SFSafeSymbols import UniformTypeIdentifiers struct ContentView: View { @AppStorage("pushToken") var pushToken: String? var hasPushToken: Bool { pushToken != nil } @State var hasNotificationPermissions: Bool? = nil func statusView(_ state: Bool?) -> some View { let symbol: SFSymbol let color: Color if let state = state { symbol = state ? .checkmarkCircle : .xmarkCircle color = state ? .green : .red } else { symbol = .questionmarkCircle color = .gray } return Image(systemSymbol: symbol) .renderingMode(.template) .foregroundColor(color) } func updateNotificationPermissionState() { Task { let state = await getPushPermissionState() DispatchQueue.main.async { hasNotificationPermissions = state } } } private func getPushPermissionState() async -> Bool? { let settings = await UNUserNotificationCenter.current().notificationSettings() switch settings.authorizationStatus { case .authorized, .provisional, .ephemeral: return true case .denied: return false case .notDetermined: return nil @unknown default: return nil } } @State private var didTapText = false var tapFootnote: String { if didTapText { return "Copied to clipboard" } return "Double tap to copy token" } var body: some View { NavigationView { VStack(spacing: 8) { HStack { statusView(hasPushToken) Text("remote-notifications-title") } HStack { statusView(hasNotificationPermissions) Text("notification-permissions-title") } Spacer() if let token = pushToken { Text("push-token-title") Text(token) .font(.body.monospaced()) .padding() .onTapGesture(count: 2, perform: didDoubleTapToken) Text(tapFootnote) .font(.footnote) } else { Text("register-for-remote-notifications-text") .padding() .multilineTextAlignment(.center) Button("register-for-remote-notifications-button", action: registerForRemoteNotifications) .padding() } if hasNotificationPermissions == nil { Button("request-notification-permission-button", action: requestNotificationPermission) .padding() } else if hasNotificationPermissions == false { Text("no-notification-permissions-text") .padding() .multilineTextAlignment(.center) Button("no-notification-permissions-button", action: openNotificationSettings) .padding() } Spacer() } .navigationTitle("FlurSchnaps") } .onAppear { startPeriodicUpdates() }.onDisappear { stopPeriodicUpdates() } } private func didDoubleTapToken() { UIPasteboard.general .setValue(pushToken!, forPasteboardType: UTType.plainText.identifier) didTapText = true DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { self.didTapText = false } } @State private var timer: Timer? private func startPeriodicUpdates() { guard timer == nil else { return } timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { _ in updateState() } updateState() } private func stopPeriodicUpdates() { timer?.invalidate() timer = nil } private func updateState() { updateNotificationPermissionState() } func registerForRemoteNotifications() { UIApplication.shared.registerForRemoteNotifications() } func requestNotificationPermission() { let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization( options: authOptions, completionHandler: {_, _ in updateNotificationPermissionState() }) } func openNotificationSettings() { if let appSettings = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(appSettings) { UIApplication.shared.open(appSettings) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() .previewDevice("iPhone 8") } }