Add the exercise reference library, animated exercise figures, and exercise categories
Exercise Library/ holds per-exercise reference docs (setup, cues, mistakes, progressions) with SVG visuals and a Python-rendered motion pipeline; Workouts/ExerciseFigure renders the bundled *.motion.json rigs as animated stick figures on the exercise screen. Exercises gain a warm-up/main-circuit category, timed exercises display hold time via planSummary, and a completed exercise reopens to a check screen instead of its timers.
This commit is contained in:
@@ -64,12 +64,13 @@ final class Exercise {
|
||||
var durationTotalSeconds: Int = 0
|
||||
var weightLastUpdated: Date?
|
||||
var weightReminderTimeIntervalWeeks: Int = 2
|
||||
var categoryRaw: Int = ExerciseCategory.main.rawValue
|
||||
|
||||
var split: Split?
|
||||
|
||||
init(id: String, name: String, order: Int, sets: Int, reps: Int, weight: Int,
|
||||
loadType: Int, durationTotalSeconds: Int, weightLastUpdated: Date?,
|
||||
weightReminderTimeIntervalWeeks: Int) {
|
||||
weightReminderTimeIntervalWeeks: Int, categoryRaw: Int = ExerciseCategory.main.rawValue) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.order = order
|
||||
@@ -80,6 +81,7 @@ final class Exercise {
|
||||
self.durationTotalSeconds = durationTotalSeconds
|
||||
self.weightLastUpdated = weightLastUpdated
|
||||
self.weightReminderTimeIntervalWeeks = weightReminderTimeIntervalWeeks
|
||||
self.categoryRaw = categoryRaw
|
||||
}
|
||||
|
||||
var loadTypeEnum: LoadType {
|
||||
@@ -87,6 +89,27 @@ final class Exercise {
|
||||
set { loadType = newValue.rawValue }
|
||||
}
|
||||
|
||||
var categoryEnum: ExerciseCategory {
|
||||
get { ExerciseCategory(rawValue: categoryRaw) ?? .main }
|
||||
set { categoryRaw = newValue.rawValue }
|
||||
}
|
||||
|
||||
/// One-line plan summary for list rows — duration exercises show their hold time
|
||||
/// ("3 × 45 sec"), unloaded ones drop the weight ("3 × 12 reps"), weighted ones
|
||||
/// keep the full "3 × 10 × 40 lb".
|
||||
func planSummary(weightUnit: WeightUnit) -> String {
|
||||
switch loadTypeEnum {
|
||||
case .duration:
|
||||
let m = durationMinutes, s = durationSeconds
|
||||
let hold = m > 0 && s > 0 ? "\(m)m \(s)s" : (m > 0 ? "\(m) min" : "\(s) sec")
|
||||
return "\(sets) × \(hold)"
|
||||
case .none:
|
||||
return "\(sets) × \(reps) reps"
|
||||
case .weight:
|
||||
return "\(sets) × \(reps) × \(weightUnit.format(weight))"
|
||||
}
|
||||
}
|
||||
|
||||
/// Minutes component of the total duration (for min:sec pickers).
|
||||
var durationMinutes: Int {
|
||||
get { durationTotalSeconds / 60 }
|
||||
|
||||
Reference in New Issue
Block a user