Files
Reflect/Shared/Persisence/DataControllerProtocol.swift
Trey t c22d246865 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>
2026-02-19 09:11:48 -06:00

95 lines
2.7 KiB
Swift

//
// DataControllerProtocol.swift
// Feels
//
// Protocol defining the data access interface for mood entries.
// Enables dependency injection and testability.
//
import Foundation
import SwiftData
// MARK: - Data Controller Protocol
/// Protocol defining read-only data access for mood entries
/// Used by widgets and other components that only need to read data
@MainActor
protocol MoodDataReading {
/// Get a single entry for a specific date
func getEntry(byDate date: Date) -> MoodEntryModel?
/// Get entries within a date range, filtered by weekdays
func getData(startDate: Date, endDate: Date, includedDays: [Int]) -> [MoodEntryModel]
/// Get all data organized by year and month
func splitIntoYearMonth(includedDays: [Int]) -> [Int: [Int: [MoodEntryModel]]]
/// The earliest entry in the database
var earliestEntry: MoodEntryModel? { get }
/// The latest entry in the database
var latestEntry: MoodEntryModel? { get }
}
/// Protocol defining write operations for mood entries
@MainActor
protocol MoodDataWriting {
/// Add a new mood entry
func add(mood: Mood, forDate date: Date, entryType: EntryType)
/// Update the mood for an existing entry
@discardableResult
func update(entryDate: Date, withMood mood: Mood) -> Bool
/// Update notes for an entry
@discardableResult
func updateNotes(forDate date: Date, notes: String?) -> Bool
/// Update photo for an entry
@discardableResult
func updatePhoto(forDate date: Date, photoID: UUID?) -> Bool
/// Fill in missing dates with placeholder entries
func fillInMissingDates()
/// Fix incorrect weekday values
func fixWrongWeekdays()
}
/// Protocol for data deletion operations
@MainActor
protocol MoodDataDeleting {
/// Clear all entries from the database
func clearDB()
/// Delete entries from the last N days
func deleteLast(numberOfEntries: Int)
}
/// Protocol for persistence operations
@MainActor
protocol MoodDataPersisting {
/// Save pending changes
@discardableResult
func save() -> Bool
/// Save and notify listeners
@discardableResult
func saveAndRunDataListeners() -> Bool
/// Add a listener for data changes, returns a token for removal
@discardableResult
func addNewDataListener(closure: @escaping (() -> Void)) -> DataController.DataListenerToken
/// Remove a previously registered data listener
func removeDataListener(token: DataController.DataListenerToken)
}
/// Combined protocol for full data controller functionality
@MainActor
protocol DataControlling: MoodDataReading, MoodDataWriting, MoodDataDeleting, MoodDataPersisting {}
// MARK: - DataController Conformance
extension DataController: DataControlling {}