Skip to content

Instantly share code, notes, and snippets.

@frboulais
Created March 16, 2022 14:03
Show Gist options
  • Save frboulais/c47cc0519fe4ce768199cb4297ea25e0 to your computer and use it in GitHub Desktop.
Save frboulais/c47cc0519fe4ce768199cb4297ea25e0 to your computer and use it in GitHub Desktop.
Help Drylendar - Manager
//
// NotificationManager.swift
// Drylendar
//
// Created by François Boulais on 14/03/2022.
// Copyright © 2022 App Craft Studio. All rights reserved.
//
import Foundation
import Resolver
import UserNotifications
final class NotificationManager: NSObject, ObservableObject {
@Published private(set) var notifications = [UNNotificationRequest]()
@Published private(set) var authorizationStatus: UNAuthorizationStatus?
@LazyInjected private var databaseManager: DatabaseManager
@LazyInjected private var authenticationManager: AuthenticationManager
private let center = UNUserNotificationCenter.current()
private let encoder = JSONEncoder()
private let decoder = JSONDecoder()
override init() {
super.init()
registerCategories()
}
// MARK: - NotificationManager
func reloadAuthorizationStatus() {
center.getNotificationSettings { [weak self] settings in
DispatchQueue.main.async {
self?.authorizationStatus = settings.authorizationStatus
}
}
}
func requestAuthorization() {
center.requestAuthorization(options: [.alert, .sound]) { [weak self] granted, error in
self?.reloadAuthorizationStatus()
}
}
func removeScheduledNotifications() {
center.removeAllPendingNotificationRequests()
}
func removeNotification(for item: CalendarItem) {
center.removeDeliveredNotifications(withIdentifiers: [item.notificationIdentifier])
center.removePendingNotificationRequests(withIdentifiers: [item.notificationIdentifier])
}
func reloadScheduledNotifications() {
center.getPendingNotificationRequests { [weak self] notifications in
DispatchQueue.main.async {
self?.notifications = notifications
}
}
}
func scheduleNotifications(for date: Date) {
removeScheduledNotifications()
guard let user = authenticationManager.currentUser else {
return
}
let matchComponents = Calendar.autoupdatingCurrent.dateComponents([.hour, .minute], from: date)
let items = Calendar.autoupdatingCurrent.upcomingItems(count: 20, matching: matchComponents)
databaseManager.entries(for: user) { [weak self] entries in
for item in items {
guard entries.contains(where: { item.matches(entry: $0) }) else {
return
}
var dateComponents = item.dateComponents
dateComponents.hour = matchComponents.hour
dateComponents.minute = matchComponents.minute
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let content = UNMutableNotificationContent()
content.title = "Drylendar"
content.body = "How many drinks today?"
content.sound = .default
content.categoryIdentifier = NotificationCategory.dailyReminder.identifier
if let data = try? self?.encoder.encode(item),
let jsonObject = try? JSONSerialization.jsonObject(with: data),
let userInfo = jsonObject as? [AnyHashable : Any] {
content.userInfo = userInfo
}
let request = UNNotificationRequest(identifier: item.notificationIdentifier, content: content, trigger: trigger)
self?.center.add(request)
}
}
}
func rescheduleNotifications() {
center.getPendingNotificationRequests { [weak self] requests in
if let trigger = requests.first?.trigger as? UNTimeIntervalNotificationTrigger,
let date = trigger.nextTriggerDate() {
self?.scheduleNotifications(for: date)
}
}
}
// MARK: - Private functions
private func registerCategories() {
let actions = CalendarState.allCases.map { state in
UNNotificationAction(
identifier: state.actionIdentifier,
title: state.actionTitle
)
}
let category = UNNotificationCategory(
identifier: NotificationCategory.dailyReminder.identifier,
actions: actions,
intentIdentifiers: []
)
center.setNotificationCategories([category])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment