This commit moves the device token logic to a new
PushNotificationClient, to move complexity from this specific feature
away from damusApp.swift
This commit also slightly improves the handling of device tokens, by
caching it on the client struct even if the user is using local
notifications, so that the device token can be sent to the server immediately after
switching to push notifications mode.
damus.xcodeproj/project.pbxproj | 4 ++
damus/ContentView.swift | 2 +-
damus/Models/DamusState.swift | 2 +
damus/Models/PushNotificationClient.swift | 62 +++++++++++++++++++++++
damus/damusApp.swift | 48 ++----------------
5 files changed, 73 insertions(+), 45 deletions(-)
create mode 100644 damus/Models/PushNotificationClient.swift
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
index 8386ebe7..09103f60 100644
--- a/damus.xcodeproj/project.pbxproj
+++ b/damus.xcodeproj/project.pbxproj
@@ -615,6 +615,7 @@
D7CE1B472B0BE719002EDAD4 /* NativeObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C32B9462A9AD44700DC3548 /* NativeObject.swift */; };
D7CE1B482B0BE719002EDAD4 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C32B93D2A9AD44700DC3548 /* Message.swift */; };
D7CE1B492B0BE729002EDAD4 /* DisplayName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9BB83029C0ED4F00FC4E37 /* DisplayName.swift */; };
+ D7D2A3812BF815D000E4B42B /* PushNotificationClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D2A3802BF815D000E4B42B /* PushNotificationClient.swift */; };
D7DBD41F2B02F15E002A6197 /* NostrKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD32819DE8F00B3DE84 /* NostrKind.swift */; };
D7DEEF2F2A8C021E00E0C99F /* NostrEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DEEF2E2A8C021E00E0C99F /* NostrEventTests.swift */; };
D7EDED152B11776B0018B19C /* LibreTranslateServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */; };
@@ -1437,6 +1438,7 @@
D7CB5D5E2B11770C00AD4105 /* FollowState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowState.swift; sourceTree = "<group>"; };
D7CBD1D32B8D21DC00BFD889 /* DamusPurpleNotificationManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleNotificationManagement.swift; sourceTree = "<group>"; };
D7CBD1D52B8D509800BFD889 /* DamusPurpleImpendingExpirationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleImpendingExpirationTests.swift; sourceTree = "<group>"; };
+ D7D2A3802BF815D000E4B42B /* PushNotificationClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotificationClient.swift; sourceTree = "<group>"; };
D7DEEF2E2A8C021E00E0C99F /* NostrEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrEventTests.swift; sourceTree = "<group>"; };
D7EDED1B2B1178FE0018B19C /* NoteContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteContent.swift; sourceTree = "<group>"; };
D7EDED1D2B11797D0018B19C /* LongformEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongformEvent.swift; sourceTree = "<group>"; };
@@ -1663,6 +1665,7 @@
D74AAFC12B153395006CF0F4 /* HeadlessDamusState.swift */,
B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */,
B533694D2B66D791008A805E /* MutelistManager.swift */,
+ D7D2A3802BF815D000E4B42B /* PushNotificationClient.swift */,
);
path = Models;
sourceTree = "<group>";
@@ -3291,6 +3294,7 @@
5CF2DCCC2AA3AF0B00984B8D /* RelayPicView.swift in Sources */,
4C687C242A5FA86D0092C550 /* SearchHeaderView.swift in Sources */,
64FBD06F296255C400D9D3B2 /* Theme.swift in Sources */,
+ D7D2A3812BF815D000E4B42B /* PushNotificationClient.swift in Sources */,
4C1A9A2329DDDB8100516EAC /* IconLabel.swift in Sources */,
4CA352AC2A76C07F003BB08B /* NewUnmutesNotify.swift in Sources */,
4C3EA64928FF597700C48A62 /* bech32.c in Sources */,
diff --git a/damus/ContentView.swift b/damus/ContentView.swift
index b3846a57..a3bc5bd1 100644
--- a/damus/ContentView.swift
+++ b/damus/ContentView.swift
@@ -308,7 +308,7 @@ struct ContentView: View {
active_sheet = .onboardingSuggestions
hasSeenOnboardingSuggestions = true
}
- self.appDelegate?.settings = damus_state?.settings
+ self.appDelegate?.state = damus_state
}
.sheet(item: $active_sheet) { item in
switch item {
diff --git a/damus/Models/DamusState.swift b/damus/Models/DamusState.swift
index 13679e45..2d42463a 100644
--- a/damus/Models/DamusState.swift
+++ b/damus/Models/DamusState.swift
@@ -36,6 +36,7 @@ class DamusState: HeadlessDamusState {
let video: VideoController
let ndb: Ndb
var purple: DamusPurple
+ var push_notification_client: PushNotificationClient
init(pool: RelayPool, keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, postbox: PostBox, bootstrap_relays: [RelayURL], replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: VideoController, ndb: Ndb, purple: DamusPurple? = nil, quote_reposts: EventCounter) {
self.pool = pool
@@ -68,6 +69,7 @@ class DamusState: HeadlessDamusState {
keypair: keypair
)
self.quote_reposts = quote_reposts
+ self.push_notification_client = PushNotificationClient(keypair: keypair, settings: settings)
}
@discardableResult
diff --git a/damus/Models/PushNotificationClient.swift b/damus/Models/PushNotificationClient.swift
new file mode 100644
index 00000000..9f862896
--- /dev/null
+++ b/damus/Models/PushNotificationClient.swift
@@ -0,0 +1,62 @@
+//
+// PushNotificationClient.swift
+// damus
+//
+// Created by Daniel D’Aquino on 2024-05-17.
+//
+
+import Foundation
+
+struct PushNotificationClient {
+ let keypair: Keypair
+ let settings: UserSettingsStore
+ private(set) var device_token: Data? = nil
+
+ mutating func set_device_token(new_device_token: Data) async throws {
+ self.device_token = new_device_token
+ if settings.enable_experimental_push_notifications && settings.notifications_mode == .push {
+ try await self.send_token()
+ }
+ }
+
+ func send_token() async throws {
+ guard let device_token else { return }
+ // Send the device token and pubkey to the server
+ let token = device_token.map { String(format: "%02.2hhx", $0) }.joined()
+
+ Log.info("Sending device token to server: %s", for: .push_notifications, token)
+
+ let pubkey = self.keypair.pubkey
+
+ // Send those as JSON to the server
+ let json: [String: Any] = ["deviceToken": token, "pubkey": pubkey.hex()]
+
+ // create post request
+ let url = self.settings.send_device_token_to_localhost ? Constants.DEVICE_TOKEN_RECEIVER_TEST_URL : Constants.DEVICE_TOKEN_RECEIVER_PRODUCTION_URL
+ var request = URLRequest(url: url)
+ request.httpMethod = "POST"
+
+ // insert json data to the request
+ request.httpBody = try? JSONSerialization.data(withJSONObject: json, options: [])
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+
+ let task = URLSession.shared.dataTask(with: request) { data, response, error in
+ guard let data = data, error == nil else {
+ print(error?.localizedDescription ?? "No data")
+ return
+ }
+
+ if let response = response as? HTTPURLResponse, !(200...299).contains(response.statusCode) {
+ print("Unexpected status code: \(response.statusCode)")
+ return
+ }
+
+ let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
+ if let responseJSON = responseJSON as? [String: Any] {
+ print(responseJSON)
+ }
+ }
+
+ task.resume()
+ }
+}
diff --git a/damus/damusApp.swift b/damus/damusApp.swift
index ebd4c72c..eedd7b52 100644
--- a/damus/damusApp.swift
+++ b/damus/damusApp.swift
@@ -54,14 +54,12 @@ struct MainView: View {
.onAppear {
orientationTracker.setDeviceMajorAxis()
keypair = get_saved_keypair()
- appDelegate.keypair = keypair
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
- var keypair: Keypair? = nil
- var settings: UserSettingsStore? = nil
+ var state: DamusState? = nil
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UNUserNotificationCenter.current().delegate = self
@@ -71,51 +69,13 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
- // Return if this feature is disabled
- guard let settings = self.settings else { return }
- if !settings.enable_experimental_push_notifications || settings.notifications_mode == .local {
+ guard let state else {
return
}
- // Send the device token and pubkey to the server
- let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
-
- print("Received device token: \(token)")
-
- guard let pubkey = keypair?.pubkey else {
- return
- }
-
- // Send those as JSON to the server
- let json: [String: Any] = ["deviceToken": token, "pubkey": pubkey.hex()]
-
- // create post request
- let url = settings.send_device_token_to_localhost ? Constants.DEVICE_TOKEN_RECEIVER_TEST_URL : Constants.DEVICE_TOKEN_RECEIVER_PRODUCTION_URL
- var request = URLRequest(url: url)
- request.httpMethod = "POST"
-
- // insert json data to the request
- request.httpBody = try? JSONSerialization.data(withJSONObject: json, options: [])
- request.setValue("application/json", forHTTPHeaderField: "Content-Type")
-
- let task = URLSession.shared.dataTask(with: request) { data, response, error in
- guard let data = data, error == nil else {
- print(error?.localizedDescription ?? "No data")
- return
- }
-
- if let response = response as? HTTPURLResponse, !(200...299).contains(response.statusCode) {
- print("Unexpected status code: \(response.statusCode)")
- return
- }
-
- let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
- if let responseJSON = responseJSON as? [String: Any] {
- print(responseJSON)
- }
+ Task {
+ try await state.push_notification_client.set_device_token(new_device_token: deviceToken)
}
-
- task.resume()
}
// Handle the notification in the foreground state
--
2.44.0