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>
95 lines
2.7 KiB
Swift
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 {}
|