Move push notifications stuff to separate package

This commit is contained in:
Shadowfacts 2024-04-08 09:48:40 -04:00
parent f98589b419
commit b03991ae1d
14 changed files with 348 additions and 196 deletions

8
Packages/PushNotifications/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PushNotifications"
BuildableName = "PushNotifications"
BlueprintName = "PushNotifications"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PushNotifications"
BuildableName = "PushNotifications"
BlueprintName = "PushNotifications"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,26 @@
// swift-tools-version: 5.10
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "PushNotifications",
platforms: [
.iOS(.v15),
],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "PushNotifications",
targets: ["PushNotifications"]),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "PushNotifications"),
.testTarget(
name: "PushNotificationsTests",
dependencies: ["PushNotifications"]),
]
)

View File

@ -0,0 +1,45 @@
//
// DisabledPushManager.swift
// PushNotifications
//
// Created by Shadowfacts on 4/7/24.
//
import Foundation
import UserAccounts
class DisabledPushManager: _PushManager {
var enabled: Bool {
false
}
var pushProxyRegistration: PushProxyRegistration? {
nil
}
func pushSubscription(account: UserAccountInfo) -> PushSubscription? {
nil
}
func register(transactionID: UInt64) async throws -> PushProxyRegistration {
throw Disabled()
}
func unregister() async throws {
throw Disabled()
}
func updateIfNecessary() async {
}
func didRegisterForRemoteNotifications(deviceToken: Data) {
}
func didFailToRegisterForRemoteNotifications(error: any Error) {
}
struct Disabled: LocalizedError {
var errorDescription: String? {
"Push notifications disabled"
}
}
}

View File

@ -0,0 +1,56 @@
//
// PushManager.swift
// PushNotifications
//
// Created by Shadowfacts on 4/7/24.
//
import Foundation
import OSLog
#if canImport(Sentry)
import Sentry
#endif
import Pachyderm
import UserAccounts
public struct PushManager {
@MainActor
public static let shared = createPushManager()
static let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PushManager")
private init() {}
@MainActor
private static func createPushManager() -> any _PushManager {
guard let info = Bundle.main.object(forInfoDictionaryKey: "TuskerInfo") as? [String: Any],
let scheme = info["PushProxyScheme"] as? String,
let host = info["PushProxyHost"] as? String,
!scheme.isEmpty,
!host.isEmpty else {
logger.debug("Missing proxy info, push disabled")
return DisabledPushManager()
}
var endpoint = URLComponents()
endpoint.scheme = scheme
endpoint.host = host
let url = endpoint.url!
logger.debug("Push notifications enabled with proxy \(url.absoluteString, privacy: .public)")
return PushManagerImpl(endpoint: url)
}
}
@MainActor
public protocol _PushManager {
var enabled: Bool { get }
var pushProxyRegistration: PushProxyRegistration? { get }
func pushSubscription(account: UserAccountInfo) -> PushSubscription?
func register(transactionID: UInt64) async throws -> PushProxyRegistration
func unregister() async throws
func updateIfNecessary() async
func didRegisterForRemoteNotifications(deviceToken: Data)
func didFailToRegisterForRemoteNotifications(error: any Error)
}

View File

@ -1,97 +1,17 @@
//
// PushManager.swift
// Tusker
// PushManagerImpl.swift
// PushNotifications
//
// Created by Shadowfacts on 4/6/24.
// Copyright © 2024 Shadowfacts. All rights reserved.
// Created by Shadowfacts on 4/7/24.
//
import Foundation
import OSLog
import UIKit
import UserAccounts
#if canImport(Sentry)
import Sentry
#endif
import Pachyderm
import UserAccounts
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PushManager")
@MainActor
struct PushManager {
static let shared = createPushManager()
private init() {}
private static func createPushManager() -> any _PushManager {
guard let info = Bundle.main.object(forInfoDictionaryKey: "TuskerInfo") as? [String: Any],
let scheme = info["PushProxyScheme"] as? String,
let host = info["PushProxyHost"] as? String,
!scheme.isEmpty,
!host.isEmpty else {
logger.debug("Missing proxy info, push disabled")
return DisabledPushManager()
}
var endpoint = URLComponents()
endpoint.scheme = scheme
endpoint.host = host
let url = endpoint.url!
logger.debug("Push notifications enabled with proxy \(url.absoluteString, privacy: .public)")
return PushManagerImpl(endpoint: url)
}
}
@MainActor
protocol _PushManager {
var enabled: Bool { get }
var pushProxyRegistration: PushProxyRegistration? { get }
func pushSubscription(account: UserAccountInfo) -> PushSubscription?
func register(transactionID: UInt64) async throws -> PushProxyRegistration
func unregister() async throws
func updateIfNecessary() async
func didRegisterForRemoteNotifications(deviceToken: Data)
func didFailToRegisterForRemoteNotifications(error: any Error)
}
private class DisabledPushManager: _PushManager {
var enabled: Bool {
false
}
var pushProxyRegistration: PushProxyRegistration? {
nil
}
func pushSubscription(account: UserAccountInfo) -> PushSubscription? {
nil
}
func register(transactionID: UInt64) async throws -> PushProxyRegistration {
throw Disabled()
}
func unregister() async throws {
throw Disabled()
}
func updateIfNecessary() async {
}
func didRegisterForRemoteNotifications(deviceToken: Data) {
}
func didFailToRegisterForRemoteNotifications(error: any Error) {
}
struct Disabled: LocalizedError {
var errorDescription: String? {
"Push notifications disabled"
}
}
}
private class PushManagerImpl: _PushManager {
class PushManagerImpl: _PushManager {
private let endpoint: URL
var enabled: Bool {
@ -148,13 +68,13 @@ private class PushManagerImpl: _PushManager {
throw PushRegistrationError.alreadyRegistering
}
let deviceToken = try await getDeviceToken().hexEncodedString()
logger.debug("Got device token: \(deviceToken)")
PushManager.logger.debug("Got device token: \(deviceToken)")
let registration: PushProxyRegistration
do {
registration = try await register(deviceToken: deviceToken)
logger.debug("Got endpoint: \(registration.endpoint)")
PushManager.logger.debug("Got endpoint: \(registration.endpoint)")
} catch {
logger.error("Proxy registration failed: \(String(describing: error))")
PushManager.logger.error("Proxy registration failed: \(String(describing: error))")
throw PushRegistrationError.registeringWithProxy(error)
}
pushProxyRegistration = registration
@ -173,9 +93,9 @@ private class PushManagerImpl: _PushManager {
let status = (resp as! HTTPURLResponse).statusCode
if (200...299).contains(status) {
self.pushProxyRegistration = nil
logger.debug("Unregistered from proxy")
PushManager.logger.debug("Unregistered from proxy")
} else {
logger.error("Unregistering: unexpected status \(status)")
PushManager.logger.error("Unregistering: unexpected status \(status)")
let error = (try? JSONDecoder().decode(ProxyRegistrationError.self, from: data)) ?? ProxyRegistrationError(error: "Unknown error", fields: nil)
throw PushRegistrationError.unregistering(error)
}
@ -185,7 +105,7 @@ private class PushManagerImpl: _PushManager {
guard let pushProxyRegistration else {
return
}
logger.debug("Push proxy registration: \(pushProxyRegistration.id, privacy: .public)")
PushManager.logger.debug("Push proxy registration: \(pushProxyRegistration.id, privacy: .public)")
do {
let token = try await getDeviceToken().hexEncodedString()
guard token != pushProxyRegistration.deviceToken else {
@ -197,7 +117,7 @@ private class PushManagerImpl: _PushManager {
// TODO: update subscriptions if the endpoint's changed
}
} catch {
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)")
#if canImport(Sentry)
SentrySDK.capture(error: error)
#endif
@ -232,7 +152,7 @@ private class PushManagerImpl: _PushManager {
let (data, resp) = try await URLSession.shared.data(for: request)
let status = (resp as! HTTPURLResponse).statusCode
guard (200...299).contains(status) else {
logger.error("Registering: unexpected status \(status)")
PushManager.logger.error("Registering: unexpected status \(status)")
let error = (try? JSONDecoder().decode(ProxyRegistrationError.self, from: data)) ?? ProxyRegistrationError(error: "Unknown error", fields: [])
throw error
}
@ -249,7 +169,7 @@ private class PushManagerImpl: _PushManager {
let (data, resp) = try await URLSession.shared.data(for: request)
let status = (resp as! HTTPURLResponse).statusCode
guard (200...299).contains(status) else {
logger.error("Updating: unexpected status \(status)")
PushManager.logger.error("Updating: unexpected status \(status)")
let error = (try? JSONDecoder().decode(ProxyRegistrationError.self, from: data)) ?? ProxyRegistrationError(error: "Unknown error", fields: [])
throw error
}
@ -322,37 +242,6 @@ private struct PushUpdateParams: Encodable {
}
}
struct PushProxyRegistration: Decodable {
let id: String
let endpoint: URL
let deviceToken: String
fileprivate var defaultsDict: [String: String] {
[
"id": id,
"endpoint": endpoint.absoluteString,
"deviceToken": deviceToken,
]
}
fileprivate init?(defaultsDict: [String: String]) {
guard let id = defaultsDict["id"],
let endpoint = defaultsDict["endpoint"].flatMap(URL.init(string:)),
let deviceToken = defaultsDict["deviceToken"] else {
return nil
}
self.id = id
self.endpoint = endpoint
self.deviceToken = deviceToken
}
private enum CodingKeys: String, CodingKey {
case id
case endpoint
case deviceToken = "device_token"
}
}
private extension Data {
func hexEncodedString() -> String {
String(unsafeUninitializedCapacity: count * 2) { buffer in
@ -366,49 +255,3 @@ private extension Data {
}
}
}
struct PushSubscription {
let accountID: String
let endpoint: URL
let alerts: Alerts
let policy: Policy
fileprivate var defaultsDict: [String: Any] {
[
"accountID": accountID,
"endpoint": endpoint.absoluteString,
"alerts": alerts.rawValue,
"policy": policy.rawValue
]
}
init?(defaultsDict: [String: Any]) {
guard let accountID = defaultsDict["accountID"] as? String,
let endpoint = (defaultsDict["endpoint"] as? String).flatMap(URL.init(string:)),
let alerts = defaultsDict["alerts"] as? Int,
let policy = (defaultsDict["policy"] as? String).flatMap(Policy.init(rawValue:)) else {
return nil
}
self.accountID = accountID
self.endpoint = endpoint
self.alerts = Alerts(rawValue: alerts)
self.policy = policy
}
enum Policy: String {
case all, followed, followers
}
struct Alerts: OptionSet {
static let mention = Alerts(rawValue: 1 << 0)
static let status = Alerts(rawValue: 1 << 1)
static let reblog = Alerts(rawValue: 1 << 2)
static let follow = Alerts(rawValue: 1 << 3)
static let followRequest = Alerts(rawValue: 1 << 4)
static let favorite = Alerts(rawValue: 1 << 5)
static let poll = Alerts(rawValue: 1 << 6)
static let update = Alerts(rawValue: 1 << 7)
let rawValue: Int
}
}

View File

@ -0,0 +1,39 @@
//
// PushProxyRegistration.swift
// PushNotifications
//
// Created by Shadowfacts on 4/7/24.
//
import Foundation
public struct PushProxyRegistration: Decodable {
let id: String
let endpoint: URL
let deviceToken: String
var defaultsDict: [String: String] {
[
"id": id,
"endpoint": endpoint.absoluteString,
"deviceToken": deviceToken,
]
}
init?(defaultsDict: [String: String]) {
guard let id = defaultsDict["id"],
let endpoint = defaultsDict["endpoint"].flatMap(URL.init(string:)),
let deviceToken = defaultsDict["deviceToken"] else {
return nil
}
self.id = id
self.endpoint = endpoint
self.deviceToken = deviceToken
}
private enum CodingKeys: String, CodingKey {
case id
case endpoint
case deviceToken = "device_token"
}
}

View File

@ -0,0 +1,54 @@
//
// PushSubscription.swift
// PushNotifications
//
// Created by Shadowfacts on 4/7/24.
//
import Foundation
public struct PushSubscription {
let accountID: String
let endpoint: URL
let alerts: Alerts
let policy: Policy
var defaultsDict: [String: Any] {
[
"accountID": accountID,
"endpoint": endpoint.absoluteString,
"alerts": alerts.rawValue,
"policy": policy.rawValue
]
}
init?(defaultsDict: [String: Any]) {
guard let accountID = defaultsDict["accountID"] as? String,
let endpoint = (defaultsDict["endpoint"] as? String).flatMap(URL.init(string:)),
let alerts = defaultsDict["alerts"] as? Int,
let policy = (defaultsDict["policy"] as? String).flatMap(Policy.init(rawValue:)) else {
return nil
}
self.accountID = accountID
self.endpoint = endpoint
self.alerts = Alerts(rawValue: alerts)
self.policy = policy
}
enum Policy: String {
case all, followed, followers
}
struct Alerts: OptionSet {
static let mention = Alerts(rawValue: 1 << 0)
static let status = Alerts(rawValue: 1 << 1)
static let reblog = Alerts(rawValue: 1 << 2)
static let follow = Alerts(rawValue: 1 << 3)
static let followRequest = Alerts(rawValue: 1 << 4)
static let favorite = Alerts(rawValue: 1 << 5)
static let poll = Alerts(rawValue: 1 << 6)
static let update = Alerts(rawValue: 1 << 7)
let rawValue: Int
}
}

View File

@ -0,0 +1,12 @@
import XCTest
@testable import PushNotifications
final class PushNotificationsTests: XCTestCase {
func testExample() throws {
// XCTest Documentation
// https://developer.apple.com/documentation/xctest
// Defining Test Cases and Test Methods
// https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods
}
}

View File

@ -92,6 +92,7 @@
D62E9985279CA23900C26176 /* URLSession+Development.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62E9984279CA23900C26176 /* URLSession+Development.swift */; };
D62E9987279D094F00C26176 /* StatusMetaIndicatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62E9986279D094F00C26176 /* StatusMetaIndicatorsView.swift */; };
D62FF04823D7CDD700909D6E /* AttributedStringHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */; };
D630C3C82BC43AFD00208903 /* PushNotifications in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3C72BC43AFD00208903 /* PushNotifications */; };
D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6311C4F25B3765B00B27539 /* ImageDataCache.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 */; };
@ -122,7 +123,6 @@
D64AAE9526C88C5000FC57FB /* ToastableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64AAE9426C88C5000FC57FB /* ToastableViewController.swift */; };
D64AAE9726C88DC400FC57FB /* ToastConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64AAE9626C88DC400FC57FB /* ToastConfiguration.swift */; };
D64B967C2BC19C28002C8990 /* NotificationsPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B967B2BC19C28002C8990 /* NotificationsPrefsView.swift */; };
D64B967F2BC1D447002C8990 /* PushManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B967E2BC1D447002C8990 /* PushManager.swift */; };
D64B96812BC3279D002C8990 /* PrefsAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B96802BC3279D002C8990 /* PrefsAccountView.swift */; };
D64B96842BC3893C002C8990 /* PushSubscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B96832BC3893C002C8990 /* PushSubscriptionView.swift */; };
D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; };
@ -528,7 +528,6 @@
D64AAE9426C88C5000FC57FB /* ToastableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastableViewController.swift; sourceTree = "<group>"; };
D64AAE9626C88DC400FC57FB /* ToastConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastConfiguration.swift; sourceTree = "<group>"; };
D64B967B2BC19C28002C8990 /* NotificationsPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsPrefsView.swift; sourceTree = "<group>"; };
D64B967E2BC1D447002C8990 /* PushManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushManager.swift; sourceTree = "<group>"; };
D64B96802BC3279D002C8990 /* PrefsAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsAccountView.swift; sourceTree = "<group>"; };
D64B96832BC3893C002C8990 /* PushSubscriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushSubscriptionView.swift; sourceTree = "<group>"; };
D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; };
@ -539,6 +538,7 @@
D659F36129541065002D944A /* TTTView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTTView.swift; sourceTree = "<group>"; };
D65A261A2BC3928A005EB5D8 /* TriStateToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TriStateToggle.swift; sourceTree = "<group>"; };
D65A261C2BC39399005EB5D8 /* PushInstanceSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushInstanceSettingsView.swift; sourceTree = "<group>"; };
D65A26242BC39A02005EB5D8 /* PushNotifications */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = PushNotifications; sourceTree = "<group>"; };
D65B4B532971F71D00DABDFB /* EditedReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditedReport.swift; sourceTree = "<group>"; };
D65B4B552971F98300DABDFB /* ReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportView.swift; sourceTree = "<group>"; };
D65B4B57297203A700DABDFB /* ReportSelectRulesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportSelectRulesView.swift; sourceTree = "<group>"; };
@ -793,6 +793,7 @@
buildActionMask = 2147483647;
files = (
D6BD395929B64426005FFD2B /* ComposeUI in Frameworks */,
D630C3C82BC43AFD00208903 /* PushNotifications in Frameworks */,
D6FA94E129B52898006AAC51 /* InstanceFeatures in Frameworks */,
D635237129B78A7D009ED5E7 /* TuskerComponents in Frameworks */,
D674A50927F9128D00BA03AC /* Pachyderm in Frameworks */,
@ -1181,6 +1182,7 @@
D6CA6ED029EF6060003EC5DF /* TuskerPreferences */,
D6A9E04F29F8917500BEDC7E /* MatchedGeometryPresentation */,
D642E83D2BA7AD0F004BFD6A /* GalleryVC */,
D65A26242BC39A02005EB5D8 /* PushNotifications */,
);
path = Packages;
sourceTree = "<group>";
@ -1195,14 +1197,6 @@
path = Toast;
sourceTree = "<group>";
};
D64B967D2BC1D43A002C8990 /* Push */ = {
isa = PBXGroup;
children = (
D64B967E2BC1D447002C8990 /* PushManager.swift */,
);
path = Push;
sourceTree = "<group>";
};
D64B96822BC3892B002C8990 /* Notifications */ = {
isa = PBXGroup;
children = (
@ -1551,7 +1545,6 @@
D6E57FA525C26FAB00341037 /* Localizable.stringsdict */,
D61959D2241E846D00A37B8E /* Models */,
D663626021360A9600C9CBA2 /* Preferences */,
D64B967D2BC1D43A002C8990 /* Push */,
D63CC70A2910AAC6000E19DE /* Scenes */,
D641C780213DD7C4004B4513 /* Screens */,
D62D241E217AA46B005076CC /* Shortcuts */,
@ -1739,6 +1732,7 @@
D6CA6ED129EF6091003EC5DF /* TuskerPreferences */,
D60BB3932B30076F00DAEA65 /* HTMLStreamer */,
D6934F2B2BA7AD32002B1C8D /* GalleryVC */,
D630C3C72BC43AFD00208903 /* PushNotifications */,
);
productName = Tusker;
productReference = D6D4DDCC212518A000E1C4BB /* Tusker.app */;
@ -2161,7 +2155,6 @@
D686BBE324FBF8110068E6AA /* WrappedProgressView.swift in Sources */,
D65A261B2BC3928A005EB5D8 /* TriStateToggle.swift in Sources */,
D620483423D3801D008A63EF /* LinkTextView.swift in Sources */,
D64B967F2BC1D447002C8990 /* PushManager.swift in Sources */,
D61F75882932DB6000C0B37F /* StatusSwipeActions.swift in Sources */,
D68A76EA295285D0001DA1B3 /* AddHashtagPinnedTimelineView.swift in Sources */,
D6F253CF2AC9F86300806D83 /* SearchTokenSuggestionCollectionViewCell.swift in Sources */,
@ -3044,6 +3037,10 @@
isa = XCSwiftPackageProductDependency;
productName = Pachyderm;
};
D630C3C72BC43AFD00208903 /* PushNotifications */ = {
isa = XCSwiftPackageProductDependency;
productName = PushNotifications;
};
D635237029B78A7D009ED5E7 /* TuskerComponents */ = {
isa = XCSwiftPackageProductDependency;
productName = TuskerComponents;

View File

@ -15,6 +15,7 @@ import Sentry
import UserAccounts
import ComposeUI
import TuskerPreferences
import PushNotifications
typealias Preferences = TuskerPreferences.Preferences

View File

@ -9,6 +9,7 @@
import SwiftUI
import UserNotifications
import UserAccounts
import PushNotifications
struct NotificationsPrefsView: View {
@State private var error: NotificationsSetupError?
@ -19,8 +20,9 @@ struct NotificationsPrefsView: View {
var body: some View {
List {
enableSection
if isSetup == .on {
accountsSection
if isSetup == .on,
let pushProxyRegistration {
accountsSection(pushProxyRegistration: pushProxyRegistration)
}
}
.listStyle(.insetGrouped)
@ -53,10 +55,10 @@ struct NotificationsPrefsView: View {
}
}
private var accountsSection: some View {
private func accountsSection(pushProxyRegistration: PushProxyRegistration) -> some View {
Section {
ForEach(userAccounts.accounts) { account in
PushInstanceSettingsView(account: account)
PushInstanceSettingsView(account: account, pushProxyRegistration: pushProxyRegistration)
}
}
.appGroupedListRowBackground()

View File

@ -9,11 +9,12 @@
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 mode: TriStateToggle.Mode = .off
@State private var error: Error?
var body: some View {
@ -49,13 +50,13 @@ struct PushInstanceSettingsView: View {
}
private func enableNotifications() async throws {
let req = Pachyderm.PushSubscription.create(
endpoint: pushProxyRegistration.endpoint,
publicKey: <#T##Data#>,
authSecret: <#T##Data#>,
alerts: <#T##PushSubscription.Alerts#>,
policy: <#T##PushSubscription.Policy#>
)
// let req = Pachyderm.PushSubscription.create(
// endpoint: pushProxyRegistration.endpoint,
// publicKey: <#T##Data#>,
// authSecret: <#T##Data#>,
// alerts: <#T##PushSubscription.Alerts#>,
// policy: <#T##PushSubscription.Policy#>
// )
}
private func disableNotifications() async throws {

View File

@ -8,6 +8,7 @@
import SwiftUI
import UserAccounts
import PushNotifications
struct PushSubscriptionView: View {
let account: UserAccountInfo