Tusker/Tusker/Screens/Preferences/NotificationsPrefsView.swift

130 lines
3.8 KiB
Swift

//
// NotificationsPrefsView.swift
// Tusker
//
// Created by Shadowfacts on 4/6/24.
// Copyright © 2024 Shadowfacts. All rights reserved.
//
import SwiftUI
import UserNotifications
struct NotificationsPrefsView: View {
@State private var error: NotificationsSetupError?
@State private var isSetup = false
@State private var working = false
@State private var pushProxyRegistration: PushProxyRegistration?
var body: some View {
List {
enableSection
}
.listStyle(.insetGrouped)
.appGroupedListBackground(container: PreferencesNavigationController.self)
.navigationTitle("Notifications")
}
private var enableSection: some View {
Section {
HStack {
Text("Push Notifications")
Spacer()
if working {
ProgressView()
} else {
Toggle("Push Notifications Enabled", isOn: Binding(get: {
isSetup
}, set: { newValue in
isSetup = newValue
isSetupChanged(newValue: newValue)
}))
.labelsHidden()
}
}
}
.alertWithData("An Error Occurred", data: $error) { error in
Button("OK") {}
} message: { error in
Text(error.localizedDescription)
}
.task { @MainActor in
pushProxyRegistration = PushManager.shared.pushProxyRegistration
isSetup = pushProxyRegistration != nil
if !UIApplication.shared.isRegisteredForRemoteNotifications {
_ = await registerForRemoteNotifications()
}
}
}
private func isSetupChanged(newValue: Bool) {
working = true
Task {
defer {
working = false
}
let success = if newValue {
await startRegistration()
} else {
await unregister()
}
if !success {
isSetup = !newValue
}
}
}
private func startRegistration() async -> Bool {
let authorized: Bool
do {
authorized = try await UNUserNotificationCenter.current().requestAuthorization(options: [.alert])
} catch {
self.error = .requestingAuthorization(error)
return false
}
guard authorized else {
return false
}
return await registerForRemoteNotifications()
}
private func registerForRemoteNotifications() async -> Bool {
do {
pushProxyRegistration = try await PushManager.shared.register(transactionID: 0)
return true
} catch {
self.error = .registering(error)
return false
}
}
private func unregister() async -> Bool {
do {
try await PushManager.shared.unregister()
pushProxyRegistration = nil
return true
} catch {
self.error = .unregistering(error)
return false
}
}
}
private enum NotificationsSetupError: LocalizedError {
case requestingAuthorization(any Error)
case registering(any Error)
case unregistering(any Error)
var errorDescription: String? {
switch self {
case .requestingAuthorization(let error):
"Notifications authorization request failed: \(error.localizedDescription)"
case .registering(let error):
"Registration failed: \(error.localizedDescription)"
case .unregistering(let error):
"Deactivation failed: \(error.localizedDescription)"
}
}
}