forked from shadowfacts/Tusker
Update Mastodon push subscriptions when endpoint changes
This commit is contained in:
parent
840b83012a
commit
68dad77f81
|
@ -36,7 +36,7 @@ class DisabledPushManager: _PushManager {
|
||||||
throw Disabled()
|
throw Disabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateIfNecessary() async {
|
func updateIfNecessary(updateSubscription: @escaping (PushSubscription) async -> Bool) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
func didRegisterForRemoteNotifications(deviceToken: Data) {
|
func didRegisterForRemoteNotifications(deviceToken: Data) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ public protocol _PushManager {
|
||||||
|
|
||||||
func register(transactionID: UInt64) async throws -> PushProxyRegistration
|
func register(transactionID: UInt64) async throws -> PushProxyRegistration
|
||||||
func unregister() async throws
|
func unregister() async throws
|
||||||
func updateIfNecessary() async
|
func updateIfNecessary(updateSubscription: @escaping (PushSubscription) async -> Bool) async
|
||||||
|
|
||||||
func didRegisterForRemoteNotifications(deviceToken: Data)
|
func didRegisterForRemoteNotifications(deviceToken: Data)
|
||||||
func didFailToRegisterForRemoteNotifications(error: any Error)
|
func didFailToRegisterForRemoteNotifications(error: any Error)
|
||||||
|
|
|
@ -74,7 +74,7 @@ class PushManagerImpl: _PushManager {
|
||||||
}
|
}
|
||||||
let subscription = PushSubscription(
|
let subscription = PushSubscription(
|
||||||
accountID: account.id,
|
accountID: account.id,
|
||||||
endpoint: pushProxyRegistration.endpoint,
|
endpoint: endpointURL(registration: pushProxyRegistration, accountID: account.id),
|
||||||
secretKey: key,
|
secretKey: key,
|
||||||
authSecret: authSecret,
|
authSecret: authSecret,
|
||||||
alerts: [],
|
alerts: [],
|
||||||
|
@ -84,6 +84,13 @@ class PushManagerImpl: _PushManager {
|
||||||
return subscription
|
return subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func endpointURL(registration: PushProxyRegistration, accountID: String) -> URL {
|
||||||
|
var endpoint = URLComponents(url: registration.endpoint, resolvingAgainstBaseURL: false)!
|
||||||
|
endpoint.queryItems = endpoint.queryItems ?? []
|
||||||
|
endpoint.queryItems!.append(URLQueryItem(name: "ctx", value: accountID))
|
||||||
|
return endpoint.url!
|
||||||
|
}
|
||||||
|
|
||||||
func removeSubscription(account: UserAccountInfo) {
|
func removeSubscription(account: UserAccountInfo) {
|
||||||
pushSubscriptions.removeAll { $0.accountID == account.id }
|
pushSubscriptions.removeAll { $0.accountID == account.id }
|
||||||
}
|
}
|
||||||
|
@ -130,7 +137,7 @@ class PushManagerImpl: _PushManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateIfNecessary() async {
|
func updateIfNecessary(updateSubscription: @escaping (PushSubscription) async -> Bool) async {
|
||||||
guard let pushProxyRegistration else {
|
guard let pushProxyRegistration else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -142,8 +149,19 @@ class PushManagerImpl: _PushManager {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let newRegistration = try await update(registration: pushProxyRegistration, deviceToken: token)
|
let newRegistration = try await update(registration: pushProxyRegistration, deviceToken: token)
|
||||||
|
self.pushProxyRegistration = newRegistration
|
||||||
if pushProxyRegistration.endpoint != newRegistration.endpoint {
|
if pushProxyRegistration.endpoint != newRegistration.endpoint {
|
||||||
// TODO: update subscriptions if the endpoint's changed
|
self.pushSubscriptions = await AsyncSequenceAdaptor(wrapping: self.pushSubscriptions).map {
|
||||||
|
var copy = $0
|
||||||
|
copy.endpoint = await self.endpointURL(registration: newRegistration, accountID: $0.accountID)
|
||||||
|
if await updateSubscription(copy) {
|
||||||
|
return copy
|
||||||
|
} else {
|
||||||
|
return $0
|
||||||
|
}
|
||||||
|
}.reduce(into: [], { partialResult, el in
|
||||||
|
partialResult.append(el)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
PushManager.logger.error("Failed to update push registration: \(String(describing: error), privacy: .public)")
|
PushManager.logger.error("Failed to update push registration: \(String(describing: error), privacy: .public)")
|
||||||
|
@ -296,3 +314,25 @@ private extension Data {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct AsyncSequenceAdaptor<S: Sequence>: AsyncSequence {
|
||||||
|
typealias Element = S.Element
|
||||||
|
|
||||||
|
let base: S
|
||||||
|
|
||||||
|
init(wrapping base: S) {
|
||||||
|
self.base = base
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeAsyncIterator() -> AsyncIterator {
|
||||||
|
AsyncIterator(base: base.makeIterator())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AsyncIterator: AsyncIteratorProtocol {
|
||||||
|
var base: S.Iterator
|
||||||
|
|
||||||
|
mutating func next() async -> Element? {
|
||||||
|
base.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import Foundation
|
||||||
import CryptoKit
|
import CryptoKit
|
||||||
|
|
||||||
public struct PushSubscription {
|
public struct PushSubscription {
|
||||||
let accountID: String
|
public let accountID: String
|
||||||
let endpoint: URL
|
public internal(set) var endpoint: URL
|
||||||
public let secretKey: P256.KeyAgreement.PrivateKey
|
public let secretKey: P256.KeyAgreement.PrivateKey
|
||||||
public let authSecret: Data
|
public let authSecret: Data
|
||||||
public var alerts: Alerts
|
public var alerts: Alerts
|
||||||
|
|
|
@ -93,6 +93,7 @@
|
||||||
D62E9987279D094F00C26176 /* StatusMetaIndicatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62E9986279D094F00C26176 /* StatusMetaIndicatorsView.swift */; };
|
D62E9987279D094F00C26176 /* StatusMetaIndicatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62E9986279D094F00C26176 /* StatusMetaIndicatorsView.swift */; };
|
||||||
D62FF04823D7CDD700909D6E /* AttributedStringHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */; };
|
D62FF04823D7CDD700909D6E /* AttributedStringHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */; };
|
||||||
D630C3C82BC43AFD00208903 /* PushNotifications in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3C72BC43AFD00208903 /* PushNotifications */; };
|
D630C3C82BC43AFD00208903 /* PushNotifications in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3C72BC43AFD00208903 /* PushNotifications */; };
|
||||||
|
D630C3CA2BC59FF500208903 /* MastodonController+Push.swift in Sources */ = {isa = PBXBuildFile; fileRef = D630C3C92BC59FF500208903 /* MastodonController+Push.swift */; };
|
||||||
D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6311C4F25B3765B00B27539 /* ImageDataCache.swift */; };
|
D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6311C4F25B3765B00B27539 /* ImageDataCache.swift */; };
|
||||||
D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Helpers.swift */; };
|
D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Helpers.swift */; };
|
||||||
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; };
|
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; };
|
||||||
|
@ -497,6 +498,7 @@
|
||||||
D62E9984279CA23900C26176 /* URLSession+Development.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+Development.swift"; sourceTree = "<group>"; };
|
D62E9984279CA23900C26176 /* URLSession+Development.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+Development.swift"; sourceTree = "<group>"; };
|
||||||
D62E9986279D094F00C26176 /* StatusMetaIndicatorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusMetaIndicatorsView.swift; sourceTree = "<group>"; };
|
D62E9986279D094F00C26176 /* StatusMetaIndicatorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusMetaIndicatorsView.swift; sourceTree = "<group>"; };
|
||||||
D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringHelperTests.swift; sourceTree = "<group>"; };
|
D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringHelperTests.swift; sourceTree = "<group>"; };
|
||||||
|
D630C3C92BC59FF500208903 /* MastodonController+Push.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonController+Push.swift"; sourceTree = "<group>"; };
|
||||||
D6311C4F25B3765B00B27539 /* ImageDataCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDataCache.swift; sourceTree = "<group>"; };
|
D6311C4F25B3765B00B27539 /* ImageDataCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDataCache.swift; sourceTree = "<group>"; };
|
||||||
D6333B362137838300CE884A /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = "<group>"; };
|
D6333B362137838300CE884A /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = "<group>"; };
|
||||||
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
|
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -1651,6 +1653,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D6F953EF21251A2900CF0F2B /* MastodonController.swift */,
|
D6F953EF21251A2900CF0F2B /* MastodonController.swift */,
|
||||||
|
D630C3C92BC59FF500208903 /* MastodonController+Push.swift */,
|
||||||
D61ABEFD28F1C92600B29151 /* FavoriteService.swift */,
|
D61ABEFD28F1C92600B29151 /* FavoriteService.swift */,
|
||||||
D621733228F1D5ED004C7DB1 /* ReblogService.swift */,
|
D621733228F1D5ED004C7DB1 /* ReblogService.swift */,
|
||||||
D6F6A54F291F058600F496A8 /* CreateListService.swift */,
|
D6F6A54F291F058600F496A8 /* CreateListService.swift */,
|
||||||
|
@ -2228,6 +2231,7 @@
|
||||||
D6BEA247291A0F2D002F4D01 /* Duckable+Root.swift in Sources */,
|
D6BEA247291A0F2D002F4D01 /* Duckable+Root.swift in Sources */,
|
||||||
D6C1B2082545D1EC00DAAA66 /* StatusCardView.swift in Sources */,
|
D6C1B2082545D1EC00DAAA66 /* StatusCardView.swift in Sources */,
|
||||||
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */,
|
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */,
|
||||||
|
D630C3CA2BC59FF500208903 /* MastodonController+Push.swift in Sources */,
|
||||||
D6F6A554291F0D9600F496A8 /* DeleteListService.swift in Sources */,
|
D6F6A554291F0D9600F496A8 /* DeleteListService.swift in Sources */,
|
||||||
D68E6F5F253C9B2D001A1B4C /* BaseEmojiLabel.swift in Sources */,
|
D68E6F5F253C9B2D001A1B4C /* BaseEmojiLabel.swift in Sources */,
|
||||||
D6F0B12B24A3071C001E48C3 /* MainSplitViewController.swift in Sources */,
|
D6F0B12B24A3071C001E48C3 /* MainSplitViewController.swift in Sources */,
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
//
|
||||||
|
// MastodonController+Push.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 4/9/24.
|
||||||
|
// Copyright © 2024 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Pachyderm
|
||||||
|
import PushNotifications
|
||||||
|
import CryptoKit
|
||||||
|
|
||||||
|
extension MastodonController {
|
||||||
|
func createPushSubscription(subscription: PushNotifications.PushSubscription) async throws -> Pachyderm.PushSubscription {
|
||||||
|
let req = Pachyderm.PushSubscription.create(
|
||||||
|
endpoint: subscription.endpoint,
|
||||||
|
// mastodon docs just say "Base64 encoded string of a public key from a ECDH keypair using the prime256v1 curve."
|
||||||
|
// other apps use SecKeyCopyExternalRepresentation which is documented to use X9.63 for elliptic curve keys
|
||||||
|
// and that seems to work
|
||||||
|
publicKey: subscription.secretKey.publicKey.x963Representation,
|
||||||
|
authSecret: subscription.authSecret,
|
||||||
|
alerts: .init(subscription.alerts),
|
||||||
|
policy: .init(subscription.policy)
|
||||||
|
)
|
||||||
|
return try await run(req).0
|
||||||
|
}
|
||||||
|
|
||||||
|
func updatePushSubscription(subscription: PushNotifications.PushSubscription) async throws -> Pachyderm.PushSubscription {
|
||||||
|
// when updating anything other than the alerts/policy, we need to go through the create route
|
||||||
|
return try await createPushSubscription(subscription: subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updatePushSubscription(alerts: PushNotifications.PushSubscription.Alerts, policy: PushNotifications.PushSubscription.Policy) async throws -> Pachyderm.PushSubscription {
|
||||||
|
let req = Pachyderm.PushSubscription.update(alerts: .init(alerts), policy: .init(policy))
|
||||||
|
return try await run(req).0
|
||||||
|
}
|
||||||
|
|
||||||
|
func deletePushSubscription() async throws {
|
||||||
|
let req = Pachyderm.PushSubscription.delete()
|
||||||
|
_ = try await run(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,10 +84,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
||||||
BackgroundManager.shared.registerHandlers()
|
BackgroundManager.shared.registerHandlers()
|
||||||
|
|
||||||
Task {
|
initializePushManager()
|
||||||
PushManager.captureError = { SentrySDK.capture(error: $0) }
|
|
||||||
await PushManager.shared.updateIfNecessary()
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -183,6 +180,26 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
PushManager.shared.didFailToRegisterForRemoteNotifications(error: error)
|
PushManager.shared.didFailToRegisterForRemoteNotifications(error: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func initializePushManager() {
|
||||||
|
Task {
|
||||||
|
PushManager.captureError = { SentrySDK.capture(error: $0) }
|
||||||
|
await PushManager.shared.updateIfNecessary(updateSubscription: {
|
||||||
|
guard let account = UserAccountsManager.shared.getAccount(id: $0.accountID) else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let mastodonController = MastodonController.getForAccount(account)
|
||||||
|
do {
|
||||||
|
let result = try await mastodonController.updatePushSubscription(subscription: $0)
|
||||||
|
PushManager.logger.debug("Updated push subscription \(result.id) on \(mastodonController.instanceURL)")
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
PushManager.logger.error("Error updating push subscription: \(String(describing: error))")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if !os(visionOS)
|
#if !os(visionOS)
|
||||||
private func swizzleStatusBar() {
|
private func swizzleStatusBar() {
|
||||||
let selector = Selector(("handleTapAction:"))
|
let selector = Selector(("handleTapAction:"))
|
||||||
|
|
|
@ -68,19 +68,9 @@ struct PushInstanceSettingsView: View {
|
||||||
|
|
||||||
private func enableNotifications() async throws {
|
private func enableNotifications() async throws {
|
||||||
let subscription = try await PushManager.shared.createSubscription(account: account)
|
let subscription = try await PushManager.shared.createSubscription(account: account)
|
||||||
let req = Pachyderm.PushSubscription.create(
|
|
||||||
endpoint: pushProxyRegistration.endpoint,
|
|
||||||
// mastodon docs just say "Base64 encoded string of a public key from a ECDH keypair using the prime256v1 curve."
|
|
||||||
// other apps use SecKeyCopyExternalRepresentation which is documented to use X9.63 for elliptic curve keys
|
|
||||||
// and that seems to work
|
|
||||||
publicKey: subscription.secretKey.publicKey.x963Representation,
|
|
||||||
authSecret: subscription.authSecret,
|
|
||||||
alerts: .init(subscription.alerts),
|
|
||||||
policy: .init(subscription.policy)
|
|
||||||
)
|
|
||||||
let mastodonController = await MastodonController.getForAccount(account)
|
let mastodonController = await MastodonController.getForAccount(account)
|
||||||
do {
|
do {
|
||||||
let (result, _) = try await mastodonController.run(req)
|
let result = try await mastodonController.createPushSubscription(subscription: subscription)
|
||||||
PushManager.logger.debug("Push subscription \(result.id) created on \(account.instanceURL)")
|
PushManager.logger.debug("Push subscription \(result.id) created on \(account.instanceURL)")
|
||||||
self.subscription = subscription
|
self.subscription = subscription
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -91,19 +81,17 @@ struct PushInstanceSettingsView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func disableNotifications() async throws {
|
private func disableNotifications() async throws {
|
||||||
let req = Pachyderm.PushSubscription.delete()
|
|
||||||
let mastodonController = await MastodonController.getForAccount(account)
|
let mastodonController = await MastodonController.getForAccount(account)
|
||||||
_ = try await mastodonController.run(req)
|
try await mastodonController.deletePushSubscription()
|
||||||
await PushManager.shared.removeSubscription(account: account)
|
await PushManager.shared.removeSubscription(account: account)
|
||||||
subscription = nil
|
subscription = nil
|
||||||
PushManager.logger.debug("Push subscription removed on \(account.instanceURL)")
|
PushManager.logger.debug("Push subscription removed on \(account.instanceURL)")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateSubscription(alerts: PushNotifications.PushSubscription.Alerts, policy: PushNotifications.PushSubscription.Policy) async -> Bool {
|
private func updateSubscription(alerts: PushNotifications.PushSubscription.Alerts, policy: PushNotifications.PushSubscription.Policy) async -> Bool {
|
||||||
let req = Pachyderm.PushSubscription.update(alerts: .init(alerts), policy: .init(policy))
|
|
||||||
let mastodonController = await MastodonController.getForAccount(account)
|
let mastodonController = await MastodonController.getForAccount(account)
|
||||||
do {
|
do {
|
||||||
let (result, _) = try await mastodonController.run(req)
|
let result = try await mastodonController.updatePushSubscription(alerts: alerts, policy: policy)
|
||||||
PushManager.logger.debug("Push subscription \(result.id) updated on \(account.instanceURL)")
|
PushManager.logger.debug("Push subscription \(result.id) updated on \(account.instanceURL)")
|
||||||
subscription?.alerts = alerts
|
subscription?.alerts = alerts
|
||||||
subscription?.policy = policy
|
subscription?.policy = policy
|
||||||
|
@ -133,34 +121,6 @@ private enum Error: LocalizedError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
//#Preview {
|
||||||
// PushInstanceSettingsView()
|
// PushInstanceSettingsView()
|
||||||
//}
|
//}
|
||||||
|
|
Loading…
Reference in New Issue