Schema & Models: - Add notes, loadType, duration fields to WorkoutLog - Align Watch schema with iOS (use duration Date instead of separate mins/secs) - Add duration helper properties to Exercise and WorkoutLog UI Changes: - Remove Splits and Settings tabs, single Workout Logs view - Add gear button in nav bar to access Settings as sheet - Move Splits section into Settings view with inline list - Redesign ExerciseView with read-only Plan/Notes tiles and Edit buttons - Add PlanEditView and NotesEditView with Cancel/Save buttons - Auto-dismiss ExerciseView when completing last set - Navigate to ExerciseView when adding new exercise Data Flow: - Plan edits sync to both WorkoutLog and corresponding Exercise - Changes propagate up navigation chain via CoreData
80 lines
2.5 KiB
Swift
80 lines
2.5 KiB
Swift
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 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 loadType: Int32
|
|
@NSManaged public var duration: Date?
|
|
@NSManaged public var notes: String?
|
|
|
|
@NSManaged public var workout: Workout?
|
|
|
|
public var id: NSManagedObjectID { objectID }
|
|
|
|
var status: WorkoutStatus {
|
|
get {
|
|
willAccessValue(forKey: "status")
|
|
let raw = primitiveValue(forKey: "status") as? String ?? "notStarted"
|
|
didAccessValue(forKey: "status")
|
|
return WorkoutStatus(rawValue: raw) ?? .notStarted
|
|
}
|
|
set {
|
|
willChangeValue(forKey: "status")
|
|
setPrimitiveValue(newValue.rawValue, forKey: "status")
|
|
didChangeValue(forKey: "status")
|
|
}
|
|
}
|
|
|
|
var loadTypeEnum: LoadType {
|
|
get { LoadType(rawValue: Int(loadType)) ?? .weight }
|
|
set { loadType = Int32(newValue.rawValue) }
|
|
}
|
|
|
|
// Duration helpers for minutes/seconds conversion
|
|
var durationMinutes: Int {
|
|
get {
|
|
guard let duration = duration else { return 0 }
|
|
return Int(duration.timeIntervalSince1970) / 60
|
|
}
|
|
set {
|
|
let seconds = durationSeconds
|
|
duration = Date(timeIntervalSince1970: TimeInterval(newValue * 60 + seconds))
|
|
}
|
|
}
|
|
|
|
var durationSeconds: Int {
|
|
get {
|
|
guard let duration = duration else { return 0 }
|
|
return Int(duration.timeIntervalSince1970) % 60
|
|
}
|
|
set {
|
|
let minutes = durationMinutes
|
|
duration = Date(timeIntervalSince1970: TimeInterval(minutes * 60 + newValue))
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|