62 lines
2.6 KiB
Swift
62 lines
2.6 KiB
Swift
import Foundation
|
|
import UserNotifications
|
|
import UIKit
|
|
|
|
enum NotificationService {
|
|
@MainActor
|
|
static func requestPermission() async {
|
|
_ = try? await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge])
|
|
UIApplication.shared.registerForRemoteNotifications()
|
|
}
|
|
|
|
@MainActor private static var deviceToken: String?
|
|
@MainActor private static var registeredSession: String?
|
|
|
|
@MainActor
|
|
static func receivedDeviceToken(_ data: Data) async {
|
|
deviceToken = data.map { String(format: "%02x", $0) }.joined()
|
|
registeredSession = nil
|
|
await syncPushRegistration()
|
|
}
|
|
|
|
@MainActor
|
|
static func syncPushRegistration() async {
|
|
let session = KeychainStore.load()
|
|
guard !session.isEmpty, let deviceToken, registeredSession != session else { return }
|
|
let environment = Bundle.main.object(forInfoDictionaryKey: "KASZTELANPushEnvironment") as? String ?? "production"
|
|
do {
|
|
try await APIClient().registerPush(deviceToken: deviceToken, environment: environment, token: session)
|
|
// The account may have changed while the request was in flight.
|
|
if KeychainStore.load() == session { registeredSession = session }
|
|
} catch {
|
|
// Retry when the app next refreshes; keep account access working offline.
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
static func unregisterPush(session: String) async {
|
|
registeredSession = nil
|
|
guard let deviceToken else { return }
|
|
try? await APIClient().unregisterPush(deviceToken: deviceToken, token: session)
|
|
}
|
|
|
|
static func show(_ message: KasztelanMessage) async {
|
|
let settings = await UNUserNotificationCenter.current().notificationSettings()
|
|
guard settings.authorizationStatus == .authorized || settings.authorizationStatus == .provisional else { return }
|
|
let delivered = await UNUserNotificationCenter.current().deliveredNotifications()
|
|
guard !delivered.contains(where: {
|
|
($0.request.content.userInfo["message_id"] as? Int) == message.id
|
|
}) else { return }
|
|
let content = UNMutableNotificationContent()
|
|
content.title = "KASZTELAN"
|
|
content.subtitle = message.title
|
|
content.body = message.text
|
|
content.sound = .default
|
|
content.threadIdentifier = "kasztelan-messages"
|
|
content.categoryIdentifier = "KASZTELAN_MESSAGE"
|
|
content.userInfo = ["message_id": message.id]
|
|
let request = UNNotificationRequest(identifier: "kasztelan-\(message.id)", content: content, trigger: nil)
|
|
try? await UNUserNotificationCenter.current().add(request)
|
|
}
|
|
}
|