forked from shadowfacts/Tusker
Move push notifications stuff to separate package
This commit is contained in:
parent
f98589b419
commit
b03991ae1d
|
@ -0,0 +1,8 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
|
@ -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>
|
|
@ -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"]),
|
||||
]
|
||||
)
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -15,6 +15,7 @@ import Sentry
|
|||
import UserAccounts
|
||||
import ComposeUI
|
||||
import TuskerPreferences
|
||||
import PushNotifications
|
||||
|
||||
typealias Preferences = TuskerPreferences.Preferences
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import SwiftUI
|
||||
import UserAccounts
|
||||
import PushNotifications
|
||||
|
||||
struct PushSubscriptionView: View {
|
||||
let account: UserAccountInfo
|
||||
|
|
Loading…
Reference in New Issue