forked from shadowfacts/Tusker
Start account-specific push subscriptions
This commit is contained in:
parent
9fad2a882a
commit
f98589b419
|
@ -12,13 +12,82 @@ public struct PushSubscription: Decodable, Sendable {
|
||||||
public let id: String
|
public let id: String
|
||||||
public let endpoint: URL
|
public let endpoint: URL
|
||||||
public let serverKey: String
|
public let serverKey: String
|
||||||
// TODO: WTF is this?
|
public let alerts: Alerts
|
||||||
// public let alerts
|
public let policy: Policy
|
||||||
|
|
||||||
|
public static func create(endpoint: URL, publicKey: Data, authSecret: Data, alerts: Alerts, policy: Policy) -> Request<PushSubscription> {
|
||||||
|
return Request(method: .post, path: "/api/v1/push/subscription", body: ParametersBody([
|
||||||
|
"subscription[endpoint]" => endpoint.absoluteString,
|
||||||
|
"subscription[keys][p256dh]" => publicKey.base64EncodedString(),
|
||||||
|
"subscription[keys][auth]" => authSecret.base64EncodedString(),
|
||||||
|
"data[alerts][mention]" => alerts.mention,
|
||||||
|
"data[alerts][status]" => alerts.status,
|
||||||
|
"data[alerts][reblog]" => alerts.reblog,
|
||||||
|
"data[alerts][follow]" => alerts.follow,
|
||||||
|
"data[alerts][follow_request]" => alerts.followRequest,
|
||||||
|
"data[alerts][favourite]" => alerts.favourite,
|
||||||
|
"data[alerts][poll]" => alerts.poll,
|
||||||
|
"data[alerts][update]" => alerts.update,
|
||||||
|
"data[policy]" => policy.rawValue,
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func update(alerts: Alerts, policy: Policy) -> Request<PushSubscription> {
|
||||||
|
return Request(method: .put, path: "/api/v1/push/subscription", body: ParametersBody([
|
||||||
|
"data[alerts][mention]" => alerts.mention,
|
||||||
|
"data[alerts][status]" => alerts.status,
|
||||||
|
"data[alerts][reblog]" => alerts.reblog,
|
||||||
|
"data[alerts][follow]" => alerts.follow,
|
||||||
|
"data[alerts][follow_request]" => alerts.followRequest,
|
||||||
|
"data[alerts][favourite]" => alerts.favourite,
|
||||||
|
"data[alerts][poll]" => alerts.poll,
|
||||||
|
"data[alerts][update]" => alerts.update,
|
||||||
|
"data[policy]" => policy.rawValue,
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func delete() -> Request<Empty> {
|
||||||
|
return Request(method: .delete, path: "/api/v1/push/subscription")
|
||||||
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case id
|
case id
|
||||||
case endpoint
|
case endpoint
|
||||||
case serverKey = "server_key"
|
case serverKey = "server_key"
|
||||||
// case alerts
|
case alerts
|
||||||
|
case policy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PushSubscription {
|
||||||
|
public struct Alerts: Decodable, Sendable {
|
||||||
|
public let mention: Bool
|
||||||
|
public let status: Bool
|
||||||
|
public let reblog: Bool
|
||||||
|
public let follow: Bool
|
||||||
|
public let followRequest: Bool
|
||||||
|
public let favourite: Bool
|
||||||
|
public let poll: Bool
|
||||||
|
public let update: Bool
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case mention
|
||||||
|
case status
|
||||||
|
case reblog
|
||||||
|
case follow
|
||||||
|
case followRequest = "follow_request"
|
||||||
|
case favourite
|
||||||
|
case poll
|
||||||
|
case update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PushSubscription {
|
||||||
|
public enum Policy: String, Decodable, Sendable {
|
||||||
|
case all
|
||||||
|
case followed
|
||||||
|
case followers
|
||||||
|
case none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,7 @@
|
||||||
D64B967C2BC19C28002C8990 /* NotificationsPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B967B2BC19C28002C8990 /* NotificationsPrefsView.swift */; };
|
D64B967C2BC19C28002C8990 /* NotificationsPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B967B2BC19C28002C8990 /* NotificationsPrefsView.swift */; };
|
||||||
D64B967F2BC1D447002C8990 /* PushManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B967E2BC1D447002C8990 /* PushManager.swift */; };
|
D64B967F2BC1D447002C8990 /* PushManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B967E2BC1D447002C8990 /* PushManager.swift */; };
|
||||||
D64B96812BC3279D002C8990 /* PrefsAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B96802BC3279D002C8990 /* PrefsAccountView.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 */; };
|
D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; };
|
||||||
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */; };
|
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */; };
|
||||||
D651C5B42915B00400236EF6 /* ProfileFieldsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */; };
|
D651C5B42915B00400236EF6 /* ProfileFieldsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */; };
|
||||||
|
@ -132,6 +133,8 @@
|
||||||
D6552367289870790048A653 /* ScreenCorners in Frameworks */ = {isa = PBXBuildFile; platformFilters = (ios, maccatalyst, ); productRef = D6552366289870790048A653 /* ScreenCorners */; };
|
D6552367289870790048A653 /* ScreenCorners in Frameworks */ = {isa = PBXBuildFile; platformFilters = (ios, maccatalyst, ); productRef = D6552366289870790048A653 /* ScreenCorners */; };
|
||||||
D659F35E2953A212002D944A /* TTTKit in Frameworks */ = {isa = PBXBuildFile; productRef = D659F35D2953A212002D944A /* TTTKit */; };
|
D659F35E2953A212002D944A /* TTTKit in Frameworks */ = {isa = PBXBuildFile; productRef = D659F35D2953A212002D944A /* TTTKit */; };
|
||||||
D659F36229541065002D944A /* TTTView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D659F36129541065002D944A /* TTTView.swift */; };
|
D659F36229541065002D944A /* TTTView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D659F36129541065002D944A /* TTTView.swift */; };
|
||||||
|
D65A261B2BC3928A005EB5D8 /* TriStateToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65A261A2BC3928A005EB5D8 /* TriStateToggle.swift */; };
|
||||||
|
D65A261D2BC39399005EB5D8 /* PushInstanceSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65A261C2BC39399005EB5D8 /* PushInstanceSettingsView.swift */; };
|
||||||
D65B4B542971F71D00DABDFB /* EditedReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B532971F71D00DABDFB /* EditedReport.swift */; };
|
D65B4B542971F71D00DABDFB /* EditedReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B532971F71D00DABDFB /* EditedReport.swift */; };
|
||||||
D65B4B562971F98300DABDFB /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B552971F98300DABDFB /* ReportView.swift */; };
|
D65B4B562971F98300DABDFB /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B552971F98300DABDFB /* ReportView.swift */; };
|
||||||
D65B4B58297203A700DABDFB /* ReportSelectRulesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B57297203A700DABDFB /* ReportSelectRulesView.swift */; };
|
D65B4B58297203A700DABDFB /* ReportSelectRulesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B57297203A700DABDFB /* ReportSelectRulesView.swift */; };
|
||||||
|
@ -527,12 +530,15 @@
|
||||||
D64B967B2BC19C28002C8990 /* NotificationsPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsPrefsView.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>"; };
|
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>"; };
|
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>"; };
|
D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; };
|
||||||
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiThreadDictionary.swift; sourceTree = "<group>"; };
|
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiThreadDictionary.swift; sourceTree = "<group>"; };
|
||||||
D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldsView.swift; sourceTree = "<group>"; };
|
D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldsView.swift; sourceTree = "<group>"; };
|
||||||
D6531DED246B81C9000F9538 /* GifvPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvPlayerView.swift; sourceTree = "<group>"; };
|
D6531DED246B81C9000F9538 /* GifvPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvPlayerView.swift; sourceTree = "<group>"; };
|
||||||
D6538944214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewSwipeActionProvider.swift; sourceTree = "<group>"; };
|
D6538944214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewSwipeActionProvider.swift; sourceTree = "<group>"; };
|
||||||
D659F36129541065002D944A /* TTTView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTTView.swift; sourceTree = "<group>"; };
|
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>"; };
|
||||||
D65B4B532971F71D00DABDFB /* EditedReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditedReport.swift; 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>"; };
|
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>"; };
|
D65B4B57297203A700DABDFB /* ReportSelectRulesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportSelectRulesView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1126,7 +1132,7 @@
|
||||||
0427033922B31269000D31B6 /* AdvancedPrefsView.swift */,
|
0427033922B31269000D31B6 /* AdvancedPrefsView.swift */,
|
||||||
D67895BF246870DE00D4CD9E /* LocalAccountAvatarView.swift */,
|
D67895BF246870DE00D4CD9E /* LocalAccountAvatarView.swift */,
|
||||||
D68A76ED295369C7001DA1B3 /* AcknowledgementsView.swift */,
|
D68A76ED295369C7001DA1B3 /* AcknowledgementsView.swift */,
|
||||||
D64B967B2BC19C28002C8990 /* NotificationsPrefsView.swift */,
|
D64B96822BC3892B002C8990 /* Notifications */,
|
||||||
D60089172981FEA4005B4D00 /* Tip Jar */,
|
D60089172981FEA4005B4D00 /* Tip Jar */,
|
||||||
D68A76EF2953910A001DA1B3 /* About */,
|
D68A76EF2953910A001DA1B3 /* About */,
|
||||||
);
|
);
|
||||||
|
@ -1197,6 +1203,17 @@
|
||||||
path = Push;
|
path = Push;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D64B96822BC3892B002C8990 /* Notifications */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D64B967B2BC19C28002C8990 /* NotificationsPrefsView.swift */,
|
||||||
|
D65A261C2BC39399005EB5D8 /* PushInstanceSettingsView.swift */,
|
||||||
|
D64B96832BC3893C002C8990 /* PushSubscriptionView.swift */,
|
||||||
|
D65A261A2BC3928A005EB5D8 /* TriStateToggle.swift */,
|
||||||
|
);
|
||||||
|
path = Notifications;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D65A37F221472F300087646E /* Frameworks */ = {
|
D65A37F221472F300087646E /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -2082,6 +2099,7 @@
|
||||||
D68329EF299540050026EB24 /* MoreTrendsFooterCollectionViewCell.swift in Sources */,
|
D68329EF299540050026EB24 /* MoreTrendsFooterCollectionViewCell.swift in Sources */,
|
||||||
D623A5412635FB3C0095BD04 /* PollOptionView.swift in Sources */,
|
D623A5412635FB3C0095BD04 /* PollOptionView.swift in Sources */,
|
||||||
D61F75B1293BD85300C0B37F /* CreateFilterService.swift in Sources */,
|
D61F75B1293BD85300C0B37F /* CreateFilterService.swift in Sources */,
|
||||||
|
D65A261D2BC39399005EB5D8 /* PushInstanceSettingsView.swift in Sources */,
|
||||||
D65C6BF525478A9C00A6E89C /* BackgroundableViewController.swift in Sources */,
|
D65C6BF525478A9C00A6E89C /* BackgroundableViewController.swift in Sources */,
|
||||||
D61DC84D28F500D200B82C6E /* ProfileViewController.swift in Sources */,
|
D61DC84D28F500D200B82C6E /* ProfileViewController.swift in Sources */,
|
||||||
D600891F29848DE2005B4D00 /* AddInstancePinnedTimelineView.swift in Sources */,
|
D600891F29848DE2005B4D00 /* AddInstancePinnedTimelineView.swift in Sources */,
|
||||||
|
@ -2141,6 +2159,7 @@
|
||||||
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */,
|
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */,
|
||||||
D6D706A029466649000827ED /* ScrollingSegmentedControl.swift in Sources */,
|
D6D706A029466649000827ED /* ScrollingSegmentedControl.swift in Sources */,
|
||||||
D686BBE324FBF8110068E6AA /* WrappedProgressView.swift in Sources */,
|
D686BBE324FBF8110068E6AA /* WrappedProgressView.swift in Sources */,
|
||||||
|
D65A261B2BC3928A005EB5D8 /* TriStateToggle.swift in Sources */,
|
||||||
D620483423D3801D008A63EF /* LinkTextView.swift in Sources */,
|
D620483423D3801D008A63EF /* LinkTextView.swift in Sources */,
|
||||||
D64B967F2BC1D447002C8990 /* PushManager.swift in Sources */,
|
D64B967F2BC1D447002C8990 /* PushManager.swift in Sources */,
|
||||||
D61F75882932DB6000C0B37F /* StatusSwipeActions.swift in Sources */,
|
D61F75882932DB6000C0B37F /* StatusSwipeActions.swift in Sources */,
|
||||||
|
@ -2239,6 +2258,7 @@
|
||||||
D6C3F5172991C1A00009FCFF /* View+AppListStyle.swift in Sources */,
|
D6C3F5172991C1A00009FCFF /* View+AppListStyle.swift in Sources */,
|
||||||
D65B4B6A297777D900DABDFB /* StatusNotFoundView.swift in Sources */,
|
D65B4B6A297777D900DABDFB /* StatusNotFoundView.swift in Sources */,
|
||||||
D6412B0924B0291E00F5412E /* MyProfileViewController.swift in Sources */,
|
D6412B0924B0291E00F5412E /* MyProfileViewController.swift in Sources */,
|
||||||
|
D64B96842BC3893C002C8990 /* PushSubscriptionView.swift in Sources */,
|
||||||
D6CF5B832AC65DDF00F15D83 /* NSCollectionLayoutSection+Readable.swift in Sources */,
|
D6CF5B832AC65DDF00F15D83 /* NSCollectionLayoutSection+Readable.swift in Sources */,
|
||||||
D601FA5D297B2E6F00A8E8B5 /* ConversationCollectionViewController.swift in Sources */,
|
D601FA5D297B2E6F00A8E8B5 /* ConversationCollectionViewController.swift in Sources */,
|
||||||
D6D12B56292D57E800D528E1 /* AccountCollectionViewCell.swift in Sources */,
|
D6D12B56292D57E800D528E1 /* AccountCollectionViewCell.swift in Sources */,
|
||||||
|
|
|
@ -12,6 +12,7 @@ import OSLog
|
||||||
import Sentry
|
import Sentry
|
||||||
#endif
|
#endif
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
|
import UserAccounts
|
||||||
|
|
||||||
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PushManager")
|
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PushManager")
|
||||||
|
|
||||||
|
@ -40,10 +41,12 @@ struct PushManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
protocol _PushManager: ObservableObject {
|
protocol _PushManager {
|
||||||
var enabled: Bool { get }
|
var enabled: Bool { get }
|
||||||
var pushProxyRegistration: PushProxyRegistration? { get }
|
var pushProxyRegistration: PushProxyRegistration? { get }
|
||||||
|
|
||||||
|
func pushSubscription(account: UserAccountInfo) -> PushSubscription?
|
||||||
|
|
||||||
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() async
|
||||||
|
@ -61,6 +64,10 @@ private class DisabledPushManager: _PushManager {
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pushSubscription(account: UserAccountInfo) -> PushSubscription? {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
func register(transactionID: UInt64) async throws -> PushProxyRegistration {
|
func register(transactionID: UInt64) async throws -> PushProxyRegistration {
|
||||||
throw Disabled()
|
throw Disabled()
|
||||||
}
|
}
|
||||||
|
@ -112,7 +119,6 @@ private class PushManagerImpl: _PushManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
objectWillChange.send()
|
|
||||||
defaults.setValue(newValue?.defaultsDict, forKey: "PushProxyRegistration")
|
defaults.setValue(newValue?.defaultsDict, forKey: "PushProxyRegistration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +131,6 @@ private class PushManagerImpl: _PushManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
objectWillChange.send()
|
|
||||||
defaults.setValue(newValue.map(\.defaultsDict), forKey: "PushSubscriptions")
|
defaults.setValue(newValue.map(\.defaultsDict), forKey: "PushSubscriptions")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,6 +139,10 @@ private class PushManagerImpl: _PushManager {
|
||||||
self.endpoint = endpoint
|
self.endpoint = endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pushSubscription(account: UserAccountInfo) -> PushSubscription? {
|
||||||
|
pushSubscriptions.first { $0.accountID == account.id }
|
||||||
|
}
|
||||||
|
|
||||||
func register(transactionID: UInt64) async throws -> PushProxyRegistration {
|
func register(transactionID: UInt64) async throws -> PushProxyRegistration {
|
||||||
guard remoteNotificationsRegistrationContinuation == nil else {
|
guard remoteNotificationsRegistrationContinuation == nil else {
|
||||||
throw PushRegistrationError.alreadyRegistering
|
throw PushRegistrationError.alreadyRegistering
|
||||||
|
|
|
@ -56,7 +56,7 @@ struct NotificationsPrefsView: View {
|
||||||
private var accountsSection: some View {
|
private var accountsSection: some View {
|
||||||
Section {
|
Section {
|
||||||
ForEach(userAccounts.accounts) { account in
|
ForEach(userAccounts.accounts) { account in
|
||||||
PrefsAccountView(account: account)
|
PushInstanceSettingsView(account: account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.appGroupedListRowBackground()
|
.appGroupedListRowBackground()
|
||||||
|
@ -112,52 +112,6 @@ struct NotificationsPrefsView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct TriStateToggle: View {
|
|
||||||
let titleKey: LocalizedStringKey
|
|
||||||
@Binding var mode: Mode
|
|
||||||
let onChange: (Bool) async -> Void
|
|
||||||
@State private var isOn: Bool = false
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
toggleOrSpinner
|
|
||||||
.onChange(of: mode) { newValue in
|
|
||||||
switch newValue {
|
|
||||||
case .off:
|
|
||||||
isOn = false
|
|
||||||
case .loading:
|
|
||||||
break
|
|
||||||
case .on:
|
|
||||||
isOn = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var toggleOrSpinner: some View {
|
|
||||||
if mode == .loading {
|
|
||||||
ProgressView()
|
|
||||||
} else {
|
|
||||||
Toggle(titleKey, isOn: Binding {
|
|
||||||
isOn
|
|
||||||
} set: { newValue in
|
|
||||||
isOn = newValue
|
|
||||||
mode = .loading
|
|
||||||
Task {
|
|
||||||
await onChange(newValue)
|
|
||||||
mode = newValue ? .on : .off
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.labelsHidden()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Mode {
|
|
||||||
case off
|
|
||||||
case loading
|
|
||||||
case on
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum NotificationsSetupError: LocalizedError {
|
private enum NotificationsSetupError: LocalizedError {
|
||||||
case requestingAuthorization(any Error)
|
case requestingAuthorization(any Error)
|
||||||
case registering(any Error)
|
case registering(any Error)
|
|
@ -0,0 +1,82 @@
|
||||||
|
//
|
||||||
|
// PushInstanceSettingsView.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 4/7/24.
|
||||||
|
// Copyright © 2024 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import UserAccounts
|
||||||
|
import Pachyderm
|
||||||
|
|
||||||
|
struct PushInstanceSettingsView: View {
|
||||||
|
let account: UserAccountInfo
|
||||||
|
let pushProxyRegistration: PushProxyRegistration
|
||||||
|
@State private var mode: TriStateToggle.Mode
|
||||||
|
@State private var error: Error?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .prefsAvatar) {
|
||||||
|
HStack {
|
||||||
|
PrefsAccountView(account: account)
|
||||||
|
TriStateToggle(titleKey: "\(account.instanceURL.host!) notifications enabled", mode: $mode, onChange: updateNotificationsEnabled(enabled:))
|
||||||
|
}
|
||||||
|
PushSubscriptionView(account: account)
|
||||||
|
}
|
||||||
|
.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 {
|
||||||
|
self.error = .enabling(error)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
try await disableNotifications()
|
||||||
|
} catch {
|
||||||
|
self.error = .disabling(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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#>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func disableNotifications() async throws {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Error: LocalizedError {
|
||||||
|
case enabling(any Swift.Error)
|
||||||
|
case disabling(any Swift.Error)
|
||||||
|
|
||||||
|
var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .enabling(let error):
|
||||||
|
"Enabling push: \(error.localizedDescription)"
|
||||||
|
case .disabling(let error):
|
||||||
|
"Disabling push: \(error.localizedDescription)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#Preview {
|
||||||
|
// PushInstanceSettingsView()
|
||||||
|
//}
|
|
@ -0,0 +1,33 @@
|
||||||
|
//
|
||||||
|
// PushSubscriptionView.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 4/7/24.
|
||||||
|
// Copyright © 2024 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import UserAccounts
|
||||||
|
|
||||||
|
struct PushSubscriptionView: View {
|
||||||
|
let account: UserAccountInfo
|
||||||
|
@State private var subscription: PushSubscription?
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
init(account: UserAccountInfo) {
|
||||||
|
self.account = account
|
||||||
|
self.subscription = PushManager.shared.pushSubscription(account: account)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if let subscription {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Text("No notifications")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#Preview {
|
||||||
|
// PushSubscriptionView()
|
||||||
|
//}
|
|
@ -0,0 +1,63 @@
|
||||||
|
//
|
||||||
|
// TriStateToggle.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 4/7/24.
|
||||||
|
// Copyright © 2024 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct TriStateToggle: View {
|
||||||
|
let titleKey: LocalizedStringKey
|
||||||
|
@Binding var mode: Mode
|
||||||
|
let onChange: (Bool) async -> Void
|
||||||
|
@State private var isOn: Bool = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
toggleOrSpinner
|
||||||
|
.onChange(of: mode) { newValue in
|
||||||
|
switch newValue {
|
||||||
|
case .off:
|
||||||
|
isOn = false
|
||||||
|
case .loading:
|
||||||
|
break
|
||||||
|
case .on:
|
||||||
|
isOn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var toggleOrSpinner: some View {
|
||||||
|
if mode == .loading {
|
||||||
|
ProgressView()
|
||||||
|
} else {
|
||||||
|
Toggle(titleKey, isOn: Binding {
|
||||||
|
isOn
|
||||||
|
} set: { newValue in
|
||||||
|
isOn = newValue
|
||||||
|
mode = .loading
|
||||||
|
Task {
|
||||||
|
await onChange(newValue)
|
||||||
|
mode = newValue ? .on : .off
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.labelsHidden()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Mode {
|
||||||
|
case off
|
||||||
|
case loading
|
||||||
|
case on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
@State var mode = TriStateToggle.Mode.on
|
||||||
|
return TriStateToggle(titleKey: "", mode: $mode) { _ in
|
||||||
|
try! await Task.sleep(nanoseconds: NSEC_PER_SEC)
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ struct PrefsAccountView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
LocalAccountAvatarView(localAccountInfo: account)
|
LocalAccountAvatarView(localAccountInfo: account)
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .prefsAvatar) {
|
||||||
Text(verbatim: account.username)
|
Text(verbatim: account.username)
|
||||||
.foregroundColor(.primary)
|
.foregroundColor(.primary)
|
||||||
let instance = if let domain = WebURL.Domain(account.instanceURL.host!) {
|
let instance = if let domain = WebURL.Domain(account.instanceURL.host!) {
|
||||||
|
@ -28,10 +28,23 @@ struct PrefsAccountView: View {
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundColor(.primary)
|
.foregroundColor(.primary)
|
||||||
}
|
}
|
||||||
|
.alignmentGuide(.prefsAvatar, computeValue: { dimension in
|
||||||
|
dimension[.leading]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct AvatarAlignment: AlignmentID {
|
||||||
|
static func defaultValue(in context: ViewDimensions) -> CGFloat {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension HorizontalAlignment {
|
||||||
|
static let prefsAvatar = HorizontalAlignment(AvatarAlignment.self)
|
||||||
|
}
|
||||||
|
|
||||||
//#Preview {
|
//#Preview {
|
||||||
// PrefsAccountView()
|
// PrefsAccountView()
|
||||||
//}
|
//}
|
||||||
|
|
Loading…
Reference in New Issue