refactor: rename internal notification ID prefix from predictive_ to api_

This commit is contained in:
Jose Olarte III
2026-06-09 17:27:15 +08:00
parent eca2bbf947
commit ceaa4ada66
5 changed files with 69 additions and 69 deletions

View File

@@ -32,9 +32,9 @@ public class DailyNotificationPlugin: CAPPlugin {
// Background task identifiers
private let fetchTaskIdentifier = "org.timesafari.dailynotification.fetch"
private let notifyTaskIdentifier = "org.timesafari.dailynotification.notify"
/// Prefix for deterministic UNNotificationRequest identifiers: `predictive_\(Int(timestamp))` with `timestamp` in epoch milliseconds.
private let predictiveNotificationPrefix = "predictive_"
/// Stable identifier for the dual (New Activity) user notification. Used for replace and cancelDualSchedule; must not conflict with Daily Reminder (`predictive_*`).
/// Prefix for deterministic UNNotificationRequest identifiers: `api_\(Int(timestamp))` with `timestamp` in epoch milliseconds.
private let apiNotificationPrefix = "api_"
/// Stable identifier for the dual (New Activity) user notification. Used for replace and cancelDualSchedule; must not conflict with Daily Reminder (`api_*`).
private let dualNotificationRequestIdentifier = "org.timesafari.dailynotification.dual"
/// UserDefaults key for persisted dual schedule config (userNotification + relationship) for relationship resolution when fetch completes.
private let dualScheduleConfigKey = "dual_schedule_config"
@@ -430,7 +430,7 @@ public class DailyNotificationPlugin: CAPPlugin {
}
}
/// Cancel the dual (New Activity) schedule only. Does not affect Daily Reminder (`predictive_*`).
/// Cancel the dual (New Activity) schedule only. Does not affect Daily Reminder (`api_*`).
@objc func cancelDualSchedule(_ call: CAPPluginCall) {
do {
performCancelDualSchedule()
@@ -1085,7 +1085,7 @@ public class DailyNotificationPlugin: CAPPlugin {
return interval > 0 ? interval : (24 * 60 * 60)
}
/// Epoch milliseconds for the next local occurrence of `hour`:`minute` (used only to build predictive IDs from HH:mm schedules).
/// Epoch milliseconds for the next local occurrence of `hour`:`minute` (used only to build API notification IDs from HH:mm schedules).
private func epochMillisNextDailyOccurrence(hour: Int, minute: Int) -> Int64 {
var comp = DateComponents()
comp.hour = hour
@@ -1097,12 +1097,12 @@ public class DailyNotificationPlugin: CAPPlugin {
return Int64(next.timeIntervalSince1970 * 1000)
}
private func predictiveNotificationId(epochMillis: Int64) -> String {
"\(predictiveNotificationPrefix)\(epochMillis)"
private func apiNotificationId(epochMillis: Int64) -> String {
"\(apiNotificationPrefix)\(epochMillis)"
}
/// Reads persisted millis for a reminder, or derives from stored `time` (HH:mm) for legacy rows.
private func predictiveEpochMillis(from reminder: [String: Any]) -> Int64? {
private func apiEpochMillis(from reminder: [String: Any]) -> Int64? {
if let n = reminder["predictiveEpochMillis"] as? NSNumber {
return n.int64Value
}
@@ -1118,22 +1118,22 @@ public class DailyNotificationPlugin: CAPPlugin {
return epochMillisNextDailyOccurrence(hour: hour, minute: minute)
}
// MARK: - Predictive batch API (replace-all UNUserNotificationCenter)
// MARK: - API batch notifications (replace-all UNUserNotificationCenter)
/// Removes only pending and delivered notifications whose identifiers begin with `predictive_`. Does not touch dual/org IDs or other stacks.
/// Removes only pending and delivered notifications whose identifiers begin with `api_`. Does not touch dual/org IDs or other stacks.
@objc func clearAllNotifications(_ call: CAPPluginCall) {
NSLog("DNP-BATCH: clearAllNotifications — removing predictive_* pending and delivered only")
print("DNP-BATCH: clearAllNotifications — removing predictive_* pending and delivered only")
NSLog("DNP-BATCH: clearAllNotifications — removing api_* pending and delivered only")
print("DNP-BATCH: clearAllNotifications — removing api_* pending and delivered only")
let center = notificationCenter
let prefix = predictiveNotificationPrefix
let prefix = apiNotificationPrefix
let group = DispatchGroup()
group.enter()
center.getPendingNotificationRequests { requests in
let ids = requests.map { $0.identifier }.filter { $0.hasPrefix(prefix) }
center.removePendingNotificationRequests(withIdentifiers: ids)
NSLog("DNP-BATCH: cleared \(ids.count) pending predictive id(s)")
print("DNP-BATCH: cleared \(ids.count) pending predictive id(s)")
NSLog("DNP-BATCH: cleared \(ids.count) pending API notification id(s)")
print("DNP-BATCH: cleared \(ids.count) pending API notification id(s)")
group.leave()
}
@@ -1141,8 +1141,8 @@ public class DailyNotificationPlugin: CAPPlugin {
center.getDeliveredNotifications { notifications in
let ids = notifications.map { $0.request.identifier }.filter { $0.hasPrefix(prefix) }
center.removeDeliveredNotifications(withIdentifiers: ids)
NSLog("DNP-BATCH: cleared \(ids.count) delivered predictive id(s)")
print("DNP-BATCH: cleared \(ids.count) delivered predictive id(s)")
NSLog("DNP-BATCH: cleared \(ids.count) delivered API notification id(s)")
print("DNP-BATCH: cleared \(ids.count) delivered API notification id(s)")
group.leave()
}
@@ -1152,7 +1152,7 @@ public class DailyNotificationPlugin: CAPPlugin {
}
/// Add one-shot reminders at epoch-ms timestamps. Does not remove other requests; identical IDs replace pending entries. Caller should clear first if needed.
/// Adds/overwrites predictive notifications using deterministic IDs.
/// Adds/overwrites API-managed notifications using deterministic IDs.
/// Does NOT clear existing notifications. Caller is responsible for lifecycle.
@objc func scheduleNotifications(_ call: CAPPluginCall) {
guard let timestamps = call.getArray("timestamps", Double.self) else {
@@ -1182,7 +1182,7 @@ public class DailyNotificationPlugin: CAPPlugin {
content.title = "Reminder"
content.body = "You have a scheduled notification"
let id = "\(predictiveNotificationPrefix)\(Int(ts))"
let id = "\(apiNotificationPrefix)\(Int(ts))"
NSLog("DNP-BATCH: scheduling ts=\(ts) interval=\(interval)s id=\(id)")
print("DNP-BATCH: scheduling ts=\(ts) interval=\(interval)s id=\(id)")
@@ -1262,7 +1262,7 @@ public class DailyNotificationPlugin: CAPPlugin {
)
let epochMillis = epochMillisNextDailyOccurrence(hour: hour, minute: minute)
let requestId = predictiveNotificationId(epochMillis: epochMillis)
let requestId = apiNotificationId(epochMillis: epochMillis)
let request = UNNotificationRequest(
identifier: requestId,
@@ -1305,8 +1305,8 @@ public class DailyNotificationPlugin: CAPPlugin {
// Cancel the notification (ID from stored epoch millis)
let reminders = getRemindersFromUserDefaults()
if let stored = reminders.first(where: { ($0["id"] as? String) == reminderId }),
let epochMillis = predictiveEpochMillis(from: stored) {
let requestId = predictiveNotificationId(epochMillis: epochMillis)
let epochMillis = apiEpochMillis(from: stored) {
let requestId = apiNotificationId(epochMillis: epochMillis)
notificationCenter.removePendingNotificationRequests(withIdentifiers: [requestId])
}
@@ -1321,15 +1321,15 @@ public class DailyNotificationPlugin: CAPPlugin {
// Get pending notifications
notificationCenter.getPendingNotificationRequests { requests in
let reminderRequests = requests.filter { $0.identifier.hasPrefix(self.predictiveNotificationPrefix) }
let reminderRequests = requests.filter { $0.identifier.hasPrefix(self.apiNotificationPrefix) }
// Get stored reminder data from UserDefaults
let reminders = self.getRemindersFromUserDefaults()
var result: [[String: Any]] = []
for reminder in reminders {
let expectedId: String? = self.predictiveEpochMillis(from: reminder).map {
self.predictiveNotificationId(epochMillis: $0)
let expectedId: String? = self.apiEpochMillis(from: reminder).map {
self.apiNotificationId(epochMillis: $0)
}
let isScheduled = reminderRequests.contains { expectedId != nil && $0.identifier == expectedId }
var reminderInfo = reminder
@@ -1352,8 +1352,8 @@ public class DailyNotificationPlugin: CAPPlugin {
// Cancel existing reminder (before UserDefaults update)
let remindersBeforeUpdate = getRemindersFromUserDefaults()
if let stored = remindersBeforeUpdate.first(where: { ($0["id"] as? String) == reminderId }),
let epochMillis = predictiveEpochMillis(from: stored) {
let oldRequestId = predictiveNotificationId(epochMillis: epochMillis)
let epochMillis = apiEpochMillis(from: stored) {
let oldRequestId = apiNotificationId(epochMillis: epochMillis)
notificationCenter.removePendingNotificationRequests(withIdentifiers: [oldRequestId])
}
@@ -1421,7 +1421,7 @@ public class DailyNotificationPlugin: CAPPlugin {
)
let epochMillis = epochMillisNextDailyOccurrence(hour: hour, minute: minute)
let requestId = predictiveNotificationId(epochMillis: epochMillis)
let requestId = apiNotificationId(epochMillis: epochMillis)
let request = UNNotificationRequest(
identifier: requestId,
@@ -1701,7 +1701,7 @@ public class DailyNotificationPlugin: CAPPlugin {
let fireDate = Date().addingTimeInterval(TimeInterval(validSeconds))
let epochMillis = Int64(fireDate.timeIntervalSince1970 * 1000)
let requestId = predictiveNotificationId(epochMillis: epochMillis)
let requestId = apiNotificationId(epochMillis: epochMillis)
let request = UNNotificationRequest(
identifier: requestId,
content: notificationContent,
@@ -2792,7 +2792,7 @@ extension DailyNotificationPlugin {
methods.append(CAPPluginMethod(name: "getScheduledReminders", returnType: CAPPluginReturnPromise))
methods.append(CAPPluginMethod(name: "updateDailyReminder", returnType: CAPPluginReturnPromise))
// Predictive batch API (replace-all UNUserNotificationCenter)
// API batch notifications (replace-all UNUserNotificationCenter)
methods.append(CAPPluginMethod(name: "clearAllNotifications", returnType: CAPPluginReturnPromise))
methods.append(CAPPluginMethod(name: "scheduleNotifications", returnType: CAPPluginReturnPromise))