From 02dbc2d93177b94867a3fe75c52e6e71ad914ee7 Mon Sep 17 00:00:00 2001 From: ykisana Date: Wed, 14 Oct 2026 18:11:45 -0600 Subject: [PATCH] fix/live-activity-end-state --- Normal/Services/LiveActivityManager.swift | 15 ++++++++++++++- NormalTests/Services/LiveActivityPlanTests.swift | 8 ++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Normal/Services/LiveActivityManager.swift b/Normal/Services/LiveActivityManager.swift index 483c170..3644faa 100644 --- a/Normal/Services/LiveActivityManager.swift +++ b/Normal/Services/LiveActivityManager.swift @@ -31,7 +31,11 @@ enum LiveActivityManager { static func reconcile(active: [String: Date], titles: [String: String], startDates: [String: Date] = [:]) { guard ActivityAuthorizationInfo().areActivitiesEnabled else { return } - let running = Activity.activities + let all = Activity.activities + for activity in all where !isRunning(activity.activityState) { + Task { await activity.end(nil, dismissalPolicy: .immediate) } + } + let running = all.filter { isRunning($0.activityState) } let runningByID = Dictionary( running.map { ($0.attributes.unblockID, $0) }, uniquingKeysWith: { first, _ in first } @@ -59,6 +63,15 @@ enum LiveActivityManager { } } + static func isRunning(_ state: ActivityState) -> Bool { + switch state { + case .ended, .dismissed: + false + default: + true + } + } + private static func content( endingAt endDate: Date ) -> ActivityContent { diff --git a/NormalTests/Services/LiveActivityPlanTests.swift b/NormalTests/Services/LiveActivityPlanTests.swift index 1ed0005..eec638c 100644 --- a/NormalTests/Services/LiveActivityPlanTests.swift +++ b/NormalTests/Services/LiveActivityPlanTests.swift @@ -1,3 +1,4 @@ +import ActivityKit @testable import Normal import Testing @@ -47,4 +48,11 @@ struct LiveActivityPlanTests { let plan = LiveActivityPlan(activeIDs: [], runningIDs: []) #expect(plan.toStart.isEmpty && plan.toUpdate.isEmpty && plan.toEnd.isEmpty) } + + @Test func systemEndedActivitiesAreNotTreatedAsRunning() { + #expect(LiveActivityManager.isRunning(.active)) + #expect(LiveActivityManager.isRunning(.stale)) + #expect(!LiveActivityManager.isRunning(.ended)) + #expect(!LiveActivityManager.isRunning(.dismissed)) + } }