Fix 25 audit issues: memory leaks, concurrency, performance, accessibility

Address findings from comprehensive audit across 5 workstreams:

- Memory: Token-based DataController listeners (prevent closure leaks),
  static DateFormatters, ImageCache observer cleanup, MotionManager
  reference counting, FoundationModels dedup guard
- Concurrency: Replace Task.detached with Task in FeelsApp (preserve
  MainActor isolation), wrap WatchConnectivity handler in MainActor
- Performance: Cache sortedGroupedData in DayViewViewModel, cache demo
  data in MonthView/YearView, remove broken ReduceMotionModifier
- Accessibility: VoiceOver support for LockScreen, DemoHeatmapCell
  labels, MonthCard button labels, InsightsView header traits,
  Smart Invert protection on neon headers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-19 09:11:48 -06:00
parent b58dfd5093
commit c22d246865
18 changed files with 175 additions and 73 deletions

View File

@@ -2224,6 +2224,9 @@ struct MotionCardView: View {
.onAppear {
motionManager.startIfNeeded()
}
.onDisappear {
motionManager.stopIfNoConsumers()
}
}
}
@@ -2237,10 +2240,13 @@ class MotionManager: ObservableObject {
@Published var yOffset: CGFloat = 0
private var isRunning = false
private var activeConsumers = 0
private init() {}
func startIfNeeded() {
activeConsumers += 1
guard !isRunning,
motionManager.isDeviceMotionAvailable,
!UIAccessibility.isReduceMotionEnabled else { return }
@@ -2257,8 +2263,18 @@ class MotionManager: ObservableObject {
}
}
func stopIfNoConsumers() {
activeConsumers = max(0, activeConsumers - 1)
guard activeConsumers == 0, isRunning else { return }
isRunning = false
motionManager.stopDeviceMotionUpdates()
xOffset = 0
yOffset = 0
}
func stop() {
guard isRunning else { return }
activeConsumers = 0
isRunning = false
motionManager.stopDeviceMotionUpdates()
}