Add CoreData-based workout tracking app with iOS and watchOS targets

- Migrate from SwiftData to CoreData with CloudKit sync
- Add core models: Split, Exercise, Workout, WorkoutLog
- Implement tab-based UI: Workout Logs, Splits, Settings
- Add SF Symbols picker for split icons
- Add exercise picker filtered by split with exclusion of added exercises
- Integrate IndieAbout for settings/about section
- Add Yams for YAML exercise definition parsing
- Include starter exercise libraries (bodyweight, Planet Fitness)
- Add Date extensions for formatting (formattedTime, isSameDay)
- Format workout date ranges to show time-only for same-day end dates
- Add build number update script
- Add app icons
This commit is contained in:
2026-01-19 06:42:15 -05:00
parent 2bfeb6a165
commit 13313a32d3
77 changed files with 3876 additions and 48 deletions

View File

@@ -0,0 +1,43 @@
import Foundation
import CoreData
@objc(WorkoutLog)
public class WorkoutLog: NSManagedObject, Identifiable {
@NSManaged public var date: Date
@NSManaged public var sets: Int32
@NSManaged public var reps: Int32
@NSManaged public var weight: Int32
@NSManaged private var statusRaw: String?
@NSManaged public var order: Int32
@NSManaged public var exerciseName: String
@NSManaged public var currentStateIndex: Int32
@NSManaged public var elapsedSeconds: Int32
@NSManaged public var completed: Bool
@NSManaged public var workout: Workout?
public var id: NSManagedObjectID { objectID }
var status: WorkoutStatus? {
get {
guard let raw = statusRaw else { return nil }
return WorkoutStatus(rawValue: raw)
}
set { statusRaw = newValue?.rawValue }
}
}
// MARK: - Fetch Request
extension WorkoutLog {
@nonobjc public class func fetchRequest() -> NSFetchRequest<WorkoutLog> {
return NSFetchRequest<WorkoutLog>(entityName: "WorkoutLog")
}
static func orderedFetchRequest(for workout: Workout) -> NSFetchRequest<WorkoutLog> {
let request = fetchRequest()
request.predicate = NSPredicate(format: "workout == %@", workout)
request.sortDescriptors = [NSSortDescriptor(keyPath: \WorkoutLog.order, ascending: true)]
return request
}
}