159 lines
5.8 KiB
Swift
159 lines
5.8 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
|
|
|
|
struct PushInstanceSettingsView: View {
|
|
let account: UserAccountInfo
|
|
let pushProxyRegistration: PushProxyRegistration
|
|
@State private var mode: TriStateToggle.Mode
|
|
@State private var error: Error?
|
|
@State private var subscription: PushNotifications.PushSubscription?
|
|
|
|
@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()
|
|
TriStateToggle("\(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)
|
|
}
|
|
}
|
|
|
|
private func updateNotificationsEnabled(enabled: Bool) async {
|
|
if enabled {
|
|
do {
|
|
try await enableNotifications()
|
|
} catch {
|
|
PushManager.logger.error("Error creating instance subscription: \(String(describing: error))")
|
|
self.error = .enabling(error)
|
|
}
|
|
} else {
|
|
do {
|
|
try await disableNotifications()
|
|
} catch {
|
|
PushManager.logger.error("Error removing instance subscription: \(String(describing: error))")
|
|
self.error = .disabling(error)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func enableNotifications() async throws {
|
|
let subscription = try await PushManager.shared.createSubscription(account: account)
|
|
let req = Pachyderm.PushSubscription.create(
|
|
endpoint: pushProxyRegistration.endpoint,
|
|
publicKey: subscription.secretKey.publicKey.rawRepresentation,
|
|
authSecret: subscription.authSecret,
|
|
alerts: .init(subscription.alerts),
|
|
policy: .init(subscription.policy)
|
|
)
|
|
let mastodonController = await MastodonController.getForAccount(account)
|
|
do {
|
|
let (result, _) = try await mastodonController.run(req)
|
|
PushManager.logger.debug("Push subscription \(result.id) created on \(account.instanceURL)")
|
|
self.subscription = subscription
|
|
} catch {
|
|
// if creation failed, remove the subscription locally as well
|
|
await PushManager.shared.removeSubscription(account: account)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
private func disableNotifications() async throws {
|
|
let req = Pachyderm.PushSubscription.delete()
|
|
let mastodonController = await MastodonController.getForAccount(account)
|
|
_ = try await mastodonController.run(req)
|
|
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 {
|
|
try! await Task.sleep(nanoseconds: NSEC_PER_SEC)
|
|
let req = Pachyderm.PushSubscription.update(alerts: .init(alerts), policy: .init(policy))
|
|
let mastodonController = await MastodonController.getForAccount(account)
|
|
do {
|
|
let (result, _) = try await mastodonController.run(req)
|
|
PushManager.logger.debug("Push subscription \(result.id) updated on \(account.instanceURL)")
|
|
subscription?.alerts = alerts
|
|
subscription?.policy = policy
|
|
} catch {
|
|
PushManager.logger.error("Error updating subscription: \(String(describing: error))")
|
|
self.error = .updating(error)
|
|
}
|
|
}
|
|
}
|
|
|
|
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)"
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension Pachyderm.PushSubscription.Alerts {
|
|
init(_ alerts: PushNotifications.PushSubscription.Alerts) {
|
|
self.init(
|
|
mention: alerts.contains(.mention),
|
|
status: alerts.contains(.status),
|
|
reblog: alerts.contains(.reblog),
|
|
follow: alerts.contains(.follow),
|
|
followRequest: alerts.contains(.followRequest),
|
|
favourite: alerts.contains(.favorite),
|
|
poll: alerts.contains(.poll),
|
|
update: alerts.contains(.update)
|
|
)
|
|
}
|
|
}
|
|
|
|
private extension Pachyderm.PushSubscription.Policy {
|
|
init(_ policy: PushNotifications.PushSubscription.Policy) {
|
|
switch policy {
|
|
case .all:
|
|
self = .all
|
|
case .followers:
|
|
self = .followers
|
|
case .followed:
|
|
self = .followed
|
|
}
|
|
}
|
|
}
|
|
|
|
//#Preview {
|
|
// PushInstanceSettingsView()
|
|
//}
|