Tusker/Tusker/Screens/Preferences/Notifications/NotificationsPrefsView.swift

131 lines
3.9 KiB
Swift

//
// NotificationsPrefsView.swift
// Tusker
//
// Created by Shadowfacts on 4/6/24.
// Copyright © 2024 Shadowfacts. All rights reserved.
//
import SwiftUI
import UserNotifications
import UserAccounts
struct NotificationsPrefsView: View {
@State private var error: NotificationsSetupError?
@State private var isSetup = TriStateToggle.Mode.off
@State private var pushProxyRegistration: PushProxyRegistration?
@ObservedObject private var userAccounts = UserAccountsManager.shared
var body: some View {
List {
enableSection
if isSetup == .on {
accountsSection
}
}
.listStyle(.insetGrouped)
.appGroupedListBackground(container: PreferencesNavigationController.self)
.navigationTitle("Notifications")
}
private var enableSection: some View {
Section {
HStack {
Text("Push Notifications")
Spacer()
TriStateToggle(titleKey: "Push Notifications Enabled", mode: $isSetup, onChange: isSetupChanged(newValue:))
}
}
.appGroupedListRowBackground()
.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 ? .on : .off
if !UIApplication.shared.isRegisteredForRemoteNotifications {
_ = await registerForRemoteNotifications()
}
}
}
private var accountsSection: some View {
Section {
ForEach(userAccounts.accounts) { account in
PushInstanceSettingsView(account: account)
}
}
.appGroupedListRowBackground()
}
private func isSetupChanged(newValue: Bool) async {
if newValue {
let success = await startRegistration()
if !success {
isSetup = .off
}
} else {
let success = await unregister()
if !success {
isSetup = .on
}
}
}
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)"
}
}
}