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

@@ -14,15 +14,15 @@ struct MonthDetailView: View {
@AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor
@StateObject private var shareImage = StupidAssShareObservableObject()
@State private var showingSheet = false
@State private var selectedEntry: MoodEntry?
@State private var selectedEntry: MoodEntryModel?
@State private var showingUpdateEntryAlert = false
@State private var showUpdateEntryAlert = false
let monthInt: Int
let yearInt: Int
@State var entries: [MoodEntry]
@State var entries: [MoodEntryModel]
var parentViewModel: DayViewViewModel
let columns = [
@@ -90,24 +90,24 @@ struct MonthDetailView: View {
ForEach(Mood.allValues) { mood in
Button(mood.strValue, action: {
if let selectedEntry = selectedEntry {
PersistenceController.shared.update(entryDate: selectedEntry.forDate!, withModd: mood)
DataController.shared.update(entryDate: selectedEntry.forDate, withMood: mood)
}
updateEntries()
showUpdateEntryAlert = false
selectedEntry = nil
})
}
if let selectedEntry = selectedEntry,
deleteEnabled,
selectedEntry.mood != .missing {
Button(String(localized: "content_view_delete_entry"), action: {
PersistenceController.shared.update(entryDate: selectedEntry.forDate!, withModd: .missing)
DataController.shared.update(entryDate: selectedEntry.forDate, withMood: .missing)
updateEntries()
showUpdateEntryAlert = false
})
}
Button(String(localized: "content_view_fill_in_missing_entry_cancel"), role: .cancel, action: {
updateEntries()
selectedEntry = nil
@@ -161,13 +161,13 @@ struct MonthDetailView: View {
}
}
private func listViewEntry(forEntry entry: MoodEntry) -> some View {
private func listViewEntry(forEntry entry: MoodEntryModel) -> some View {
VStack {
if entry.mood == .placeholder {
Text(" ")
.font(.title3)
.foregroundColor(Mood.placeholder.color)
Circle()
.frame(minWidth: 5,
maxWidth: 50,
@@ -176,11 +176,11 @@ struct MonthDetailView: View {
alignment: .center)
.foregroundColor(moodTint.color(forMood: entry.mood))
} else {
Text(entry.forDate!,
Text(entry.forDate,
format: Date.FormatStyle().day())
.font(.title3)
.foregroundColor(textColor)
entry.mood.icon
.resizable()
.scaledToFit()
@@ -193,11 +193,11 @@ struct MonthDetailView: View {
}
}
}
private func updateEntries() {
parentViewModel.updateData()
let (startDate, endDate) = Date.dateRange(monthInt: monthInt, yearInt: yearInt)
let updatedEntries = PersistenceController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
let updatedEntries = DataController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
let padded = MoodEntryFunctions.padMoodEntriesMonth(monthEntries: updatedEntries)
entries = padded
}
@@ -221,8 +221,8 @@ struct MonthDetailView: View {
struct MonthDetailView_Previews: PreviewProvider {
static var previews: some View {
MonthDetailView(monthInt: 5, yearInt: 2022, entries:
PersistenceController.shared.randomEntries(count: 30).sorted(by: {
$0.forDate! < $1.forDate!
DataController.shared.randomEntries(count: 30).sorted(by: {
$0.forDate < $1.forDate
}), parentViewModel: DayViewViewModel(addMonthStartWeekdayPadding: true))
}
}

View File

@@ -162,7 +162,7 @@ struct MonthView: View {
struct MonthCard: View {
let month: Int
let year: Int
let entries: [MoodEntry]
let entries: [MoodEntryModel]
let moodTint: MoodTints
let imagePack: MoodImages
let textColor: Color
@@ -177,7 +177,7 @@ struct MonthCard: View {
private var metrics: [MoodMetrics] {
let (startDate, endDate) = Date.dateRange(monthInt: month, yearInt: year)
let monthEntries = PersistenceController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
let monthEntries = DataController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
return Random.createTotalPerc(fromEntries: monthEntries)
}
@@ -250,7 +250,7 @@ struct MonthCard: View {
// MARK: - Heatmap Cell
struct HeatmapCell: View {
let entry: MoodEntry
let entry: MoodEntryModel
let moodTint: MoodTints
let isFiltered: Bool