Live Activity Content Density

Nucleic-Session: B3643133-163C-4C5D-BE20-1A6B7FB83DA9
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-05 00:51:24 -07:00
co-authored by Nucleic
parent 4dbc432d0c
commit 7c542c236a
@@ -834,6 +834,49 @@ final class RemoteStore: ObservableObject {
activeConnection?.send(msg)
}
// MARK: - Live Activity push registration (UX_IOS §5.3)
/// The current Live Activity's APNS update token + id, shipped to every capable Mac so it can
/// refresh the lock-screen glance over APNs while the phone is backgrounded and its socket is
/// suspended. Sent to *all* connected hosts (not just the active one) — while the phone is
/// away, whichever Mac has work to report should be able to push.
private var liveActivityReg: (token: String, activityID: String)?
/// Host ids that already have the current token (re-sent to a host that (re)connects, and
/// re-sent to everyone when the token rotates).
private var liveActivitySentTo: Set<String> = []
private func setupLiveActivityBridge() {
LiveActivityManager.shared.onPushToken = { [weak self] token, activityID in
guard let self, self.liveActivityReg?.token != token else { return }
self.liveActivityReg = (token, activityID)
self.liveActivitySentTo.removeAll() // a fresh token must reach every host again
self.syncLiveActivityRegistration()
}
LiveActivityManager.shared.onActivityEnded = { [weak self] activityID in
guard let self else { return }
self.liveActivityReg = nil
self.liveActivitySentTo.removeAll()
for conn in self.connections.values where conn.capabilities.canPushLiveActivity {
conn.send(.endLiveActivity(activityID))
}
}
}
/// Send the current Live Activity token to every live, capable host that hasn't got it yet.
/// Called when the token changes and on every connection update, so a host that just connected
/// — or reconnected while the phone was away — learns the token it needs to push.
private func syncLiveActivityRegistration() {
guard let reg = liveActivityReg else { return }
// A host that dropped should re-register when it returns.
liveActivitySentTo = liveActivitySentTo.filter { connections[$0]?.connectivity.isLive == true }
for (id, conn) in connections {
guard conn.connectivity.isLive, conn.capabilities.canPushLiveActivity,
!liveActivitySentTo.contains(id) else { continue }
conn.send(.registerLiveActivity(reg.token, reg.activityID))
liveActivitySentTo.insert(id)
}
}
// MARK: - Demo simulator (offline, interactive)
//
// In demo mode there's no host, so writes can't go over the wire. Instead they mutate the