Migrate from Core Data to SwiftData

- Replace Core Data with SwiftData for iOS 18+
- Create MoodEntryModel as @Model class replacing MoodEntry entity
- Create SharedModelContainer for App Group container sharing
- Create DataController with CRUD extensions replacing PersistenceController
- Update all views and view models to use MoodEntryModel
- Update widget extension to use SwiftData
- Remove old Core Data files (Persistence*.swift, .xcdatamodeld)
- Add EntryType enum with all entry type cases
- Fix widget label truncation with proper spacing and text scaling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-10 15:08:05 -06:00
parent 443f4dfc55
commit aaaf04f05e
51 changed files with 926 additions and 962 deletions

View File

@@ -0,0 +1,85 @@
//
// DataControllerGET.swift
// Feels
//
// SwiftData READ operations.
//
import SwiftData
import Foundation
extension DataController {
func getEntry(byDate date: Date) -> MoodEntryModel? {
let startDate = Calendar.current.startOfDay(for: date)
let endDate = Calendar.current.date(byAdding: .day, value: 1, to: startDate)!
var descriptor = FetchDescriptor<MoodEntryModel>(
predicate: #Predicate { entry in
entry.forDate >= startDate && entry.forDate <= endDate
},
sortBy: [SortDescriptor(\.forDate, order: .forward)]
)
descriptor.fetchLimit = 1
return try? modelContext.fetch(descriptor).first
}
func getData(startDate: Date, endDate: Date, includedDays: [Int]) -> [MoodEntryModel] {
let weekDays = includedDays.isEmpty ? [1, 2, 3, 4, 5, 6, 7] : includedDays
let descriptor = FetchDescriptor<MoodEntryModel>(
predicate: #Predicate { entry in
entry.forDate >= startDate &&
entry.forDate <= endDate &&
weekDays.contains(entry.weekDay)
},
sortBy: [SortDescriptor(\.forDate, order: .forward)]
)
return (try? modelContext.fetch(descriptor)) ?? []
}
func splitIntoYearMonth(includedDays: [Int]) -> [Int: [Int: [MoodEntryModel]]] {
let data = getData(
startDate: Date(timeIntervalSince1970: 0),
endDate: Date(),
includedDays: includedDays
).sorted { $0.forDate < $1.forDate }
guard let earliest = data.first,
let latest = data.last else { return [:] }
let calendar = Calendar.current
let earliestYear = calendar.component(.year, from: earliest.forDate)
let latestYear = calendar.component(.year, from: latest.forDate)
var result = [Int: [Int: [MoodEntryModel]]]()
for year in earliestYear...latestYear {
var monthData = [Int: [MoodEntryModel]]()
for month in 1...12 {
var components = DateComponents()
components.year = year
components.month = month
components.day = 1
guard let startOfMonth = calendar.date(from: components) else { continue }
let items = getData(
startDate: startOfMonth,
endDate: startOfMonth.endOfMonth,
includedDays: [1, 2, 3, 4, 5, 6, 7]
)
if !items.isEmpty {
monthData[month] = items
}
}
result[year] = monthData
}
return result
}
}