Files
workouts/Shared/Model/Enums.swift
T
rzen 7274f155e9 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.
2026-07-06 01:15:52 -04:00

136 lines
4.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
/// Completion state of a workout or an individual exercise log. Persisted as its
/// raw string in both the JSON documents and the SwiftData cache.
enum WorkoutStatus: String, CaseIterable, Codable, Sendable {
case notStarted
case inProgress
case completed
case skipped
var displayName: String {
switch self {
case .notStarted: "Not Started"
case .inProgress: "In Progress"
case .completed: "Completed"
case .skipped: "Skipped"
}
}
var name: String { displayName }
}
/// How an exercise's effort is measured. Persisted as its raw `Int` value.
enum LoadType: Int, CaseIterable, Codable, Sendable {
case none = 0
case weight = 1
case duration = 2
var name: String {
switch self {
case .none: "None"
case .weight: "Weight"
case .duration: "Duration"
}
}
}
/// Which segment of a split an exercise belongs to — the split screen groups its
/// exercise list by this. Persisted as its raw `Int` value; `main` is the default
/// (and what older documents without the field decode to).
enum ExerciseCategory: Int, CaseIterable, Codable, Sendable {
case main = 0
case warmup = 1
/// Order the categories appear on screen: warm-up first, then the main circuit.
static let displayOrder: [ExerciseCategory] = [.warmup, .main]
var displayName: String {
switch self {
case .main: "Main Circuit"
case .warmup: "Warm-up"
}
}
}
/// The kind of training a split represents — used to tag the Apple Health workout
/// so it lands in the right category (and credits the rings correctly), and to pick
/// a MET value when the phone has to estimate calories without watch sensor data.
/// Persisted as its raw `Int` on `SplitDocument`; the `HKWorkoutActivityType`
/// mapping lives in `Shared/HealthKit/HealthKitMapping.swift` to keep this enum
/// HealthKit-free.
enum WorkoutActivityType: Int, CaseIterable, Codable, Sendable {
case traditionalStrength = 0 // default
case functionalStrength = 1
case hiit = 2
case coreTraining = 3
case cardio = 4
case cycling = 5
var displayName: String {
switch self {
case .traditionalStrength: "Strength Training"
case .functionalStrength: "Functional Strength"
case .hiit: "HIIT"
case .coreTraining: "Core Training"
case .cardio: "Cardio"
case .cycling: "Cycling"
}
}
var systemImage: String {
switch self {
case .traditionalStrength: "dumbbell.fill"
case .functionalStrength: "figure.strengthtraining.functional"
case .hiit: "figure.highintensity.intervaltraining"
case .coreTraining: "figure.core.training"
case .cardio: "figure.run"
case .cycling: "figure.outdoor.cycle"
}
}
/// Metabolic-equivalent value used only for the phone-side calorie estimate
/// (`kcal ≈ MET × bodyweightKg × hours`) when no watch metrics are available.
var met: Double {
switch self {
case .traditionalStrength: 5.0
case .functionalStrength: 4.0
case .hiit: 8.0
case .coreTraining: 4.0
case .cardio: 7.0
case .cycling: 7.5
}
}
}
/// Where a workout's health metrics came from: real watch sensors, or a phone-side
/// estimate written when no watch session ran. Persisted in `WorkoutMetrics`.
enum MetricSource: String, Codable, Sendable {
case watch
case phoneEstimate
}
/// Display unit for weights. The stored weight values are plain integers and are
/// never rewritten when this changes — switching only relabels what's shown.
enum WeightUnit: String, CaseIterable, Codable, Sendable {
case lb
case kg
var displayName: String {
switch self {
case .lb: "Pounds (lb)"
case .kg: "Kilograms (kg)"
}
}
var abbreviation: String {
switch self {
case .lb: "lb"
case .kg: "kg"
}
}
/// Render a stored weight value with the current unit's label, e.g. "135 lb".
func format(_ value: Int) -> String { "\(value) \(abbreviation)" }
}