150 lines
5.6 KiB
Swift
150 lines
5.6 KiB
Swift
//
|
|
// PushInstanceSettingsView.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 4/7/24.
|
|
// Copyright © 2024 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import SwiftUI
|
|
import UserAccounts
|
|
import Pachyderm
|
|
import PushNotifications
|
|
import TuskerComponents
|
|
|
|
struct PushInstanceSettingsView: View {
|
|
let account: UserAccountInfo
|
|
let pushProxyRegistration: PushProxyRegistration
|
|
@State private var mode: AsyncToggle.Mode
|
|
@State private var error: Error?
|
|
@State private var subscription: PushNotifications.PushSubscription?
|
|
@State private var showReLoginRequiredAlert = false
|
|
|
|
@MainActor
|
|
init(account: UserAccountInfo, pushProxyRegistration: PushProxyRegistration) {
|
|
self.account = account
|
|
self.pushProxyRegistration = pushProxyRegistration
|
|
let subscription = PushManager.shared.pushSubscription(account: account)
|
|
self.subscription = subscription
|
|
self.mode = subscription == nil ? .off : .on
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(alignment: .prefsAvatar) {
|
|
HStack {
|
|
PrefsAccountView(account: account)
|
|
Spacer()
|
|
AsyncToggle("\(account.instanceURL.host!) notifications enabled", labelHidden: true, mode: $mode, onChange: updateNotificationsEnabled(enabled:))
|
|
.labelsHidden()
|
|
}
|
|
PushSubscriptionView(account: account, subscription: subscription, updateSubscription: updateSubscription)
|
|
}
|
|
.alertWithData("An Error Occurred", data: $error) { data in
|
|
Button("OK") {}
|
|
} message: { data in
|
|
Text(data.localizedDescription)
|
|
}
|
|
.alert("Re-Login Required", isPresented: $showReLoginRequiredAlert) {
|
|
Button("Cancel", role: .cancel) {}
|
|
Button("Login") {
|
|
NotificationCenter.default.post(name: .reLogInRequired, object: account)
|
|
}
|
|
} message: {
|
|
Text("You must grant permission on \(account.instanceURL.host!) to turn on push notifications.")
|
|
}
|
|
.onReceive(NotificationCenter.default
|
|
.publisher(for: .pushSubscriptionRemoved)
|
|
.filter { ($0.object as? String) == account.id }
|
|
) { _ in
|
|
mode = .off
|
|
subscription = nil
|
|
}
|
|
}
|
|
|
|
private func updateNotificationsEnabled(enabled: Bool) async -> Bool {
|
|
if enabled {
|
|
do {
|
|
return try await enableNotifications()
|
|
} catch {
|
|
PushManager.logger.error("Error creating instance subscription: \(String(describing: error))")
|
|
self.error = .enabling(error)
|
|
return false
|
|
}
|
|
} else {
|
|
do {
|
|
try await disableNotifications()
|
|
} catch {
|
|
PushManager.logger.error("Error removing instance subscription: \(String(describing: error))")
|
|
self.error = .disabling(error)
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func enableNotifications() async throws -> Bool {
|
|
guard account.scopes?.contains(Scope.push.rawValue) == true else {
|
|
showReLoginRequiredAlert = true
|
|
return false
|
|
}
|
|
|
|
let subscription = try await PushManager.shared.createSubscription(account: account)
|
|
let mastodonController = await MastodonController.getForAccount(account)
|
|
do {
|
|
let result = try await mastodonController.createPushSubscription(subscription: subscription)
|
|
PushManager.logger.debug("Push subscription \(result.id) created on \(account.instanceURL)")
|
|
self.subscription = subscription
|
|
return true
|
|
} catch {
|
|
// if creation failed, remove the subscription locally as well
|
|
await PushManager.shared.removeSubscription(account: account)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
private func disableNotifications() async throws {
|
|
let mastodonController = await MastodonController.getForAccount(account)
|
|
try await mastodonController.deletePushSubscription()
|
|
await PushManager.shared.removeSubscription(account: account)
|
|
subscription = nil
|
|
PushManager.logger.debug("Push subscription removed on \(account.instanceURL)")
|
|
}
|
|
|
|
private func updateSubscription(alerts: PushNotifications.PushSubscription.Alerts, policy: PushNotifications.PushSubscription.Policy) async -> Bool {
|
|
let mastodonController = await MastodonController.getForAccount(account)
|
|
do {
|
|
let result = try await mastodonController.updatePushSubscription(alerts: alerts, policy: policy)
|
|
PushManager.logger.debug("Push subscription \(result.id) updated on \(account.instanceURL)")
|
|
await PushManager.shared.updateSubscription(account: account, alerts: alerts, policy: policy)
|
|
subscription?.alerts = alerts
|
|
subscription?.policy = policy
|
|
return true
|
|
} catch {
|
|
PushManager.logger.error("Error updating subscription: \(String(describing: error))")
|
|
self.error = .updating(error)
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
private enum Error: LocalizedError {
|
|
case enabling(any Swift.Error)
|
|
case disabling(any Swift.Error)
|
|
case updating(any Swift.Error)
|
|
|
|
var errorDescription: String? {
|
|
switch self {
|
|
case .enabling(let error):
|
|
"Enabling push: \(error.localizedDescription)"
|
|
case .disabling(let error):
|
|
"Disabling push: \(error.localizedDescription)"
|
|
case .updating(let error):
|
|
"Updating settings: \(error.localizedDescription)"
|
|
}
|
|
}
|
|
}
|
|
|
|
//#Preview {
|
|
// PushInstanceSettingsView()
|
|
//}
|