Closer/iphone/Closer/Core/Notifications/NotificationService.swift

103 lines
3.8 KiB
Swift

import Foundation
import FirebaseMessaging
import UserNotifications
// MARK: - Notification Service
final class NotificationService: NSObject, @unchecked Sendable {
static let shared = NotificationService()
private override init() {
super.init()
}
func configure() {
UNUserNotificationCenter.current().delegate = self
registerForPushNotifications()
}
private func registerForPushNotifications() {
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
guard granted else { return }
Task { @MainActor in
UIApplication.shared.registerForRemoteNotifications()
}
}
}
func updateFCMToken() {
if let token = Messaging.messaging().fcmToken {
Task {
await saveTokenToFirestore(token)
}
}
}
private func saveTokenToFirestore(_ token: String) async {
guard let userId = try? FirestoreService.shared.userId() else { return }
let tokenRef = FirestoreService.shared.fcmTokensRef(userId).document(token)
try? await tokenRef.setData([
"token": token,
"updatedAt": FieldValue.serverTimestamp()
], merge: true)
}
}
// MARK: - UNUserNotificationCenterDelegate
extension NotificationService: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([.banner, .sound])
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
// Handle notification tap deep link to relevant screen
let userInfo = response.notification.request.content.userInfo
handleDeepLink(userInfo)
completionHandler()
}
private func handleDeepLink(_ userInfo: [AnyHashable: Any]) {
guard let type = userInfo["type"] as? String else { return }
switch type {
case "daily_question", "gentle_reminder", "daily_question_reminder":
NotificationCenter.default.post(name: .navigateToDailyQuestion, object: nil)
case "partner_answered":
NotificationCenter.default.post(name: .navigateToReveal, object: userInfo["questionId"])
case "streak":
NotificationCenter.default.post(name: .navigateToHome, object: nil)
case "partner_started_game", "partner_completed_part", "partner_finished_game":
NotificationCenter.default.post(name: .navigateToPlay, object: nil)
case "memory_capsule_unlocked":
NotificationCenter.default.post(name: .navigateToMemoryLane, object: nil)
case "challenge_day_ready", "challenge_waiting":
NotificationCenter.default.post(name: .navigateToConnectionChallenges, object: nil)
default:
break
}
}
}
// MARK: - Notification Names
extension Notification.Name {
static let navigateToDailyQuestion = Notification.Name("navigateToDailyQuestion")
static let navigateToReveal = Notification.Name("navigateToReveal")
static let navigateToHome = Notification.Name("navigateToHome")
static let navigateToPlay = Notification.Name("navigateToPlay")
static let navigateToMemoryLane = Notification.Name("navigateToMemoryLane")
static let navigateToConnectionChallenges = Notification.Name("navigateToConnectionChallenges")
}
typealias FieldValue = FirebaseFirestore.FieldValue