Files
Reflect/Shared/LocalNotification.swift
Trey t 0442eab1f8 Rebrand entire project from Feels to Reflect
Complete rename across all bundle IDs, App Groups, CloudKit containers,
StoreKit product IDs, data store filenames, URL schemes, logger subsystems,
Swift identifiers, user-facing strings (7 languages), file names, directory
names, Xcode project, schemes, assets, and documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:47:16 -06:00

174 lines
6.5 KiB
Swift

//
// LocalNotification.swift
// Reflect
//
// Created by Trey Tartt on 1/8/22.
//
import Foundation
import UserNotifications
class LocalNotification {
public enum ActionType: String {
case horrible = "HORRIBLE_ACTION"
case bad = "BAD_ACTION"
case average = "AVERAGE_ACTION"
case good = "GOOD_ACTION"
case great = "GREAT_ACTION"
}
static let categoryName = "MOOD_UPDATE"
public class func testIfEnabled(completion: @escaping (Result<Bool, Error>) -> Void) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
AnalyticsManager.shared.track(.notificationEnabled)
completion(.success(true))
} else if let error = error {
AnalyticsManager.shared.track(.notificationDisabled)
completion(.failure(error))
}
}
}
public class func rescheduleNotifiations() {
if let data = GroupUserDefaults.groupDefaults.object(forKey: UserDefaultsStore.Keys.savedOnboardingData.rawValue) as? Data,
let model = try? JSONDecoder().decode(OnboardingData.self, from: data) {
LocalNotification.scheduleReminder(atTime: model.date)
}
}
public class func scheduleReminder(atTime time: Date) {
self.removeNotificaiton()
LocalNotification.testIfEnabled(completion: { result in
switch result{
case .success(_):
let _ = LocalNotification.createNotificationCategory()
let notificationContent = UNMutableNotificationContent()
let strings = UserDefaultsStore.personalityPackable().randomPushNotificationStrings()
notificationContent.title = strings.title
notificationContent.body = strings.body
notificationContent.badge = NSNumber(value: 1)
notificationContent.sound = .default
notificationContent.categoryIdentifier = LocalNotification.categoryName
let calendar = Calendar.current
let time = calendar.dateComponents([.hour,.minute], from: time)
var datComp = DateComponents()
datComp.hour = time.hour
datComp.minute = time.minute
let trigger = UNCalendarNotificationTrigger(dateMatching: datComp, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
case .failure(let error):
print(error)
// Todo: show enable this
break
}
})
}
private class func createNotificationCategory() -> UNNotificationCategory {
let moodCategory =
UNNotificationCategory(identifier: LocalNotification.categoryName,
actions: [horribleAction, badAction, averageAction, goodAction, greatAction],
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: "",
options: .customDismissAction)
// Register the notification type.
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.setNotificationCategories([moodCategory])
return moodCategory
}
private class var horribleAction: UNNotificationAction {
let acceptAction = UNNotificationAction(identifier: ActionType.horrible.rawValue,
title: "Horrible",
options: [])
return acceptAction
}
private class var badAction: UNNotificationAction {
let acceptAction = UNNotificationAction(identifier: ActionType.bad.rawValue,
title: "Bad",
options: [])
return acceptAction
}
private class var averageAction: UNNotificationAction {
let acceptAction = UNNotificationAction(identifier: ActionType.average.rawValue,
title: "Average",
options: [])
return acceptAction
}
private class var goodAction: UNNotificationAction {
let acceptAction = UNNotificationAction(identifier: ActionType.good.rawValue,
title: "Good",
options: [])
return acceptAction
}
private class var greatAction: UNNotificationAction {
let acceptAction = UNNotificationAction(identifier: ActionType.great.rawValue,
title: "Great",
options: [])
return acceptAction
}
public class func removeNotificaiton() {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
}
// MARK: - Debug: Send All Personality Pack Notifications
#if DEBUG
/// Sends one notification from each personality pack, staggered over 10 seconds for screenshot
public class func sendAllPersonalityNotificationsForScreenshot() {
let _ = createNotificationCategory()
let packs: [(PersonalityPack, Double)] = [
(.Default, 5),
(.MotivationalCoach, 6),
(.ZenMaster, 7),
(.BestFriend, 8),
(.DataAnalyst, 9)
]
for (pack, delay) in packs {
let content = UNMutableNotificationContent()
let strings = pack.randomPushNotificationStrings()
content.title = strings.title
content.body = strings.body
content.sound = .default
content.categoryIdentifier = LocalNotification.categoryName
content.interruptionLevel = .timeSensitive
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: delay, repeats: false)
let request = UNNotificationRequest(
identifier: "debug-\(pack.rawValue)-\(UUID().uuidString)",
content: content,
trigger: trigger
)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("Failed to schedule \(pack) notification: \(error)")
} else {
print("Scheduled \(pack) notification in \(delay)s")
}
}
}
}
#endif
}