Files
Reflect/Shared/LocalNotification.swift
Trey t e0330dbc8d Replace EventLogger with typed AnalyticsManager using PostHog
Complete analytics overhaul: delete EventLogger.swift, create Analytics.swift
with typed event enum (~45 events), screen tracking, super properties
(theme, icon pack, voting layout, etc.), session replay with kill switch,
autocapture, and network telemetry. Replace all 99 call sites across 38 files
with compiler-enforced typed events in object_action naming convention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 15:12:33 -06:00

174 lines
6.5 KiB
Swift

//
// LocalNotification.swift
// Feels
//
// 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
}