Push Notification Live Activity Redundancy

Nucleic-Session: 73687ED9-C11C-438C-832B-979332B73893
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-06 21:33:26 -07:00
co-authored by Nucleic
parent 4f30e304b0
commit f62840f276
@@ -209,9 +209,35 @@ final class LiveActivityManager {
Date().timeIntervalSince($0) >= Self.churnRefreshInterval
} ?? true
guard signatureChanged || (state != lastState && churnRefreshDue) else { return }
// When a session newly needs the user while we're backgrounded, this update carries the alert
// (sound/haptic) — there's no banner then, we prefer the glance. Foreground, the app UI / a
// banner announces it, so the glance updates silently. Computed against the *previous* state
// before `lastState` is overwritten.
let alert = foreground ? nil : Self.alert(from: lastState, to: state)
lastState = state
lastPushAt = Date()
enqueue(state)
enqueue(state, alert: alert)
}
/// The alert an update should carry when backgrounded: a session newly needs the user. An approval
/// (its Allow/Deny live on the glance) outranks a needs-input for the wording; a rise in neither ⇒
/// nil (silent update). Reuses the same localized keys as the host's pushed alert so a local and a
/// pushed alert read identically. Approvals/inputs that merely persist (or resolve) don't re-alert.
private static func alert(
from previous: NucleicSessionAttributes.ContentState?,
to next: NucleicSessionAttributes.ContentState
) -> AlertConfiguration? {
if next.approvalCount > (previous?.approvalCount ?? 0) {
return AlertConfiguration(
title: LocalizedStringResource("approval.title"),
body: LocalizedStringResource("approval.pending"), sound: .default)
}
if next.needsYouCount > (previous?.needsYouCount ?? 0) {
return AlertConfiguration(
title: LocalizedStringResource("input.title"),
body: LocalizedStringResource("input.pending"), sound: .default)
}
return nil
}
/// Start the process-lived observers that make push-to-start work: the device's push-to-start