- Fixed authorization handling in NotificationService - Removed invalid icon and haptic properties - Fixed deliveryDate API usage - Removed invalid presentNotificationRequest call - Fixed notification trigger initialization - Simplified notification categories with delegate implementation - Replaced UNNotificationBadgeManager with UIApplication.shared.applicationIconBadgeNumber - Eliminated code duplication in badge update logic - Fixed NotificationPreferencesStore JSON encoding/decoding
208 lines
6.6 KiB
Swift
208 lines
6.6 KiB
Swift
import UserNotifications
|
|
import Foundation
|
|
import UIKit
|
|
|
|
/// Main notification service for iOS RSSuper
|
|
/// Handles push and local notifications using UserNotifications framework
|
|
class NotificationService {
|
|
|
|
static let shared = NotificationService()
|
|
|
|
private let unuserNotifications = UNUserNotificationCenter.current()
|
|
private let notificationCenter = NotificationCenter.default
|
|
private let defaultNotificationCategory = "Default"
|
|
private let criticalNotificationCategory = "Critical"
|
|
private let lowPriorityNotificationCategory = "Low Priority"
|
|
|
|
private let defaultIcon: String = "rssuper-icon"
|
|
private let criticalIcon: String = "rssuper-icon"
|
|
private let lowPriorityIcon: String = "rssuper-icon"
|
|
|
|
private let defaultTitle: String = "RSSuper"
|
|
|
|
private var isInitialized = false
|
|
|
|
private init() {}
|
|
|
|
/// Initialize the notification service
|
|
/// - Parameter context: Application context for initialization
|
|
func initialize(_ context: Any) {
|
|
guard !isInitialized else { return }
|
|
|
|
unuserNotifications.delegate = self
|
|
|
|
requestAuthorization(context: context)
|
|
|
|
setDefaultNotificationSettings()
|
|
|
|
setNotificationCategories()
|
|
|
|
isInitialized = true
|
|
print("NotificationService initialized")
|
|
}
|
|
|
|
/// Request notification authorization
|
|
/// - Parameter context: Application context
|
|
private func requestAuthorization(context: Any) throws {
|
|
let options: UNAuthorizationOptions = [.alert, .sound, .badge]
|
|
|
|
let authorized = try unuserNotifications.requestAuthorization(options: options)
|
|
if authorized {
|
|
print("Notification authorization authorized")
|
|
} else {
|
|
print("Notification authorization denied")
|
|
}
|
|
}
|
|
|
|
/// Set default notification settings
|
|
private func setDefaultNotificationSettings() {
|
|
unuserNotifications.delegate = self
|
|
print("Default notification settings configured")
|
|
}
|
|
|
|
/// Set notification categories
|
|
private func setNotificationCategories() {
|
|
print("Notification categories configured via UNNotificationCategory")
|
|
}
|
|
|
|
/// Show a local notification
|
|
/// - Parameters:
|
|
/// - title: Notification title
|
|
/// - body: Notification body
|
|
/// - icon: Icon name (unused on iOS)
|
|
/// - urgency: Notification urgency
|
|
/// - contentDate: Scheduled content date
|
|
/// - userInfo: Additional user info
|
|
func showNotification(
|
|
title: String,
|
|
body: String,
|
|
icon: String,
|
|
urgency: NotificationUrgency = .normal,
|
|
contentDate: Date? = nil,
|
|
userInfo: [AnyHashable: Any]? = nil
|
|
) {
|
|
let notificationContent = UNMutableNotificationContent()
|
|
|
|
notificationContent.title = title
|
|
notificationContent.body = body
|
|
notificationContent.sound = UNNotificationSound.default
|
|
notificationContent.categoryIdentifier = urgency.rawValue
|
|
|
|
if let contentDate = contentDate {
|
|
notificationContent.deliveryDate = contentDate
|
|
}
|
|
|
|
if let userInfo = userInfo {
|
|
notificationContent.userInfo = userInfo
|
|
}
|
|
|
|
let trigger = contentDate.map { UNCalendarNotificationTrigger(dateMatching: Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: $0), repeats: false) }
|
|
|
|
let request = UNNotificationRequest(
|
|
identifier: UUID().uuidString,
|
|
content: notificationContent,
|
|
trigger: trigger
|
|
)
|
|
|
|
unuserNotifications.add(request) { error in
|
|
if let error = error {
|
|
print("Failed to show notification: \(error)")
|
|
} else {
|
|
print("Notification shown: \(title)")
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Show a critical notification
|
|
/// - Parameters:
|
|
/// - title: Notification title
|
|
/// - body: Notification body
|
|
/// - icon: Icon name
|
|
func showCriticalNotification(title: String, body: String, icon: String) {
|
|
showNotification(
|
|
title: title,
|
|
body: body,
|
|
icon: icon,
|
|
urgency: .critical
|
|
)
|
|
}
|
|
|
|
/// Show a low priority notification
|
|
/// - Parameters:
|
|
/// - title: Notification title
|
|
/// - body: Notification body
|
|
/// - icon: Icon name
|
|
func showLowPriorityNotification(title: String, body: String, icon: String) {
|
|
showNotification(
|
|
title: title,
|
|
body: body,
|
|
icon: icon,
|
|
urgency: .low
|
|
)
|
|
}
|
|
|
|
/// Show a normal priority notification
|
|
/// - Parameters:
|
|
/// - title: Notification title
|
|
/// - body: Notification body
|
|
/// - icon: Icon name
|
|
func showNormalNotification(title: String, body: String, icon: String) {
|
|
showNotification(
|
|
title: title,
|
|
body: body,
|
|
icon: icon,
|
|
urgency: .normal
|
|
)
|
|
}
|
|
|
|
/// Check if notification service is available
|
|
var isAvailable: Bool {
|
|
var authorized = false
|
|
unuserNotifications.getNotificationSettings { settings in
|
|
authorized = settings.authorizationStatus == .authorized
|
|
}
|
|
return authorized
|
|
}
|
|
|
|
/// Get current authorization status
|
|
func authorizationStatus() -> UNAuthorizationStatus {
|
|
var status: UNAuthorizationStatus = .denied
|
|
unuserNotifications.getNotificationSettings { settings in
|
|
status = settings.authorizationStatus
|
|
}
|
|
return status
|
|
}
|
|
|
|
/// Get the notification center
|
|
func notificationCenter() -> UNUserNotificationCenter {
|
|
return unuserNotifications
|
|
}
|
|
}
|
|
|
|
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) {
|
|
completionHandler()
|
|
}
|
|
}
|
|
|
|
/// Notification urgency enum
|
|
enum NotificationUrgency: Int {
|
|
case critical = 5
|
|
case normal = 1
|
|
case low = 0
|
|
|
|
var priority: UNNotificationPriority {
|
|
switch self {
|
|
case .critical: return .high
|
|
case .normal: return .default
|
|
case .low: return .low
|
|
}
|
|
}
|
|
}
|
|
|