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,79 @@
//
// SharedModelContainer.swift
// Feels
//
// Factory for creating ModelContainer shared between main app and widget extension.
//
import Foundation
import SwiftData
enum SharedModelContainer {
/// Creates a ModelContainer with the appropriate configuration for app group sharing
/// - Parameter useCloudKit: Whether to enable CloudKit sync
/// - Returns: Configured ModelContainer
static func create(useCloudKit: Bool = false) -> ModelContainer {
let schema = Schema([MoodEntryModel.self])
let storeURL = Self.storeURL
let configuration: ModelConfiguration
if useCloudKit {
// CloudKit-enabled configuration
configuration = ModelConfiguration(
schema: schema,
url: storeURL,
cloudKitDatabase: .private(cloudKitContainerID)
)
} else {
// Local-only configuration
configuration = ModelConfiguration(
schema: schema,
url: storeURL,
cloudKitDatabase: .none
)
}
do {
return try ModelContainer(for: schema, configurations: [configuration])
} catch {
fatalError("Failed to create ModelContainer: \(error)")
}
}
/// The URL for the SwiftData store in the shared app group container
static var storeURL: URL {
guard let containerURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: appGroupID
) else {
fatalError("App Group container not available for: \(appGroupID)")
}
return containerURL.appendingPathComponent(storeFileName)
}
/// App Group identifier based on build configuration
static var appGroupID: String {
#if DEBUG
return Constants.groupShareIdDebug
#else
return Constants.groupShareId
#endif
}
/// CloudKit container identifier based on build configuration
static var cloudKitContainerID: String {
#if DEBUG
return "iCloud.com.tt.ifeelDebug"
#else
return "iCloud.com.tt.ifeel"
#endif
}
/// Store file name based on build configuration
static var storeFileName: String {
#if DEBUG
return "Feels-Debug.store"
#else
return "Feels.store"
#endif
}
}