iOS Live Activity Updates

Nucleic-Session: 665980BA-E8A5-4E84-9DF4-1757CF792353
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-06 12:45:31 -07:00
co-authored by Nucleic
parent ecfec2690f
commit 41f0f62beb
@@ -87,6 +87,41 @@ final class LiveActivityManager {
push(state, hostName: hostName)
}
/// Nothing is running or waiting. If the glance was showing active work, flash a brief "Done"
/// summary of the just-completed sessions and then dismiss (UX_IOS §5.3 — a run should read as
/// *finished*, not just vanish). If nothing was on screen, there's nothing to close.
private func finishWithDoneGlance(hostName: String, live: [WireSessionSummary]) {
// Already flashing "Done" and scheduled to dismiss — let that run rather than restart it.
guard dismissTask == nil else { return }
// Nothing tracked on screen: only reach into ActivityKit if an untracked orphan is lingering.
guard activity != nil else {
if !Activity<NucleicSessionAttributes>.activities.isEmpty { end() }
return
}
// The sessions that just finished — completed conversational turns and finished runs. These
// are exactly the ones the active-work filter above drops, surfaced now as `.done` rows.
let done = live
.filter {
$0.status == .finished
|| ($0.status == .awaitingInput && $0.disposition == .completed)
}
.sorted(by: StatusStyle.attentionThenRecency)
.prefix(Self.maxLines)
.map(Self.line(for:))
// Nothing to celebrate (e.g. the work was discarded/deleted) → just dismiss.
guard !done.isEmpty else { end(); return }
let state = NucleicSessionAttributes.ContentState(
runningCount: 0, needsYouCount: 0, approvalCount: 0,
filesChanged: 0, linesAdded: 0, linesRemoved: 0, lines: Array(done))
push(state, hostName: hostName)
dismissTask = Task { [weak self] in
try? await Task.sleep(for: Self.doneLinger)
guard !Task.isCancelled else { return }
self?.end()
}
}
/// Apply `state` to the Activity — deduped against the last push and coalesced through one
/// serial task so the newest state always wins.
private func push(_ state: NucleicSessionAttributes.ContentState, hostName: String) {