Surface machine settings in the exercise library and refine machine rigs

Library detail screens now lead with the user's recorded machine settings
(per-split when they disagree, empty-state card for machine-based entries)
and append the weight progression chart. Starter seeds mark machine
exercises with an empty machineSettings list so the settings UI lights up
before first use. The figure rig gains a frontal body profile for face-on
machines, props that can ride mid joints (knees/elbows), and an
alternating four-frame Bird Dog loop.

Claude-Session: https://claude.ai/code/session_01LEoff8bXGBS83tK1c55Mf7
This commit is contained in:
2026-07-06 18:35:15 -04:00
parent ff1ffbb1f6
commit 669ecf1259
76 changed files with 733 additions and 268 deletions
+20 -16
View File
@@ -70,29 +70,32 @@ struct SplitDocument: Codable {
// MARK: - Seed data (canonical source for Workouts/Resources/StarterSplits/*.json)
struct Ex { let name: String; var weight = 0; var sets = 4; var reps = 10; var load = 1; var dur = 0 }
// `machine: true` emits `machineSettings: []` marks the exercise machine-based
// (empty = nothing recorded yet), which lights up the machine-settings UI without
// the user having to flip the editor toggle first.
struct Ex { let name: String; var weight = 0; var sets = 4; var reps = 10; var load = 1; var dur = 0; var machine = false }
struct Sp { let name: String; let color: String; let icon: String; let activity: Int; let ex: [Ex] }
let seeds: [Sp] = [
Sp(name: "Upper Body", color: "blue", icon: "figure.strengthtraining.traditional", activity: 0, ex: [
Ex(name: "Lat Pull Down", weight: 110),
Ex(name: "Seated Row", weight: 90),
Ex(name: "Shoulder Press", weight: 40),
Ex(name: "Chest Press", weight: 40),
Ex(name: "Tricep Press", weight: 100),
Ex(name: "Arm Curl", weight: 40),
Ex(name: "Lat Pull Down", weight: 110, machine: true),
Ex(name: "Seated Row", weight: 90, machine: true),
Ex(name: "Shoulder Press", weight: 40, machine: true),
Ex(name: "Chest Press", weight: 40, machine: true),
Ex(name: "Tricep Press", weight: 100, machine: true),
Ex(name: "Arm Curl", weight: 40, machine: true),
]),
Sp(name: "Core", color: "orange", icon: "figure.core.training", activity: 3, ex: [
Ex(name: "Abdominal", weight: 40),
Ex(name: "Rotary", weight: 40),
Ex(name: "Abdominal", weight: 40, machine: true),
Ex(name: "Rotary", weight: 40, machine: true),
]),
Sp(name: "Lower Body", color: "green", icon: "figure.run", activity: 0, ex: [
Ex(name: "Leg Press", weight: 140),
Ex(name: "Leg Curl", weight: 40),
Ex(name: "Leg Extension", weight: 80),
Ex(name: "Abductor", weight: 130),
Ex(name: "Adductor", weight: 130),
Ex(name: "Calfs", weight: 100),
Ex(name: "Leg Press", weight: 140, machine: true),
Ex(name: "Leg Curl", weight: 40, machine: true),
Ex(name: "Leg Extension", weight: 80, machine: true),
Ex(name: "Abductor", weight: 130, machine: true),
Ex(name: "Adductor", weight: 130, machine: true),
Ex(name: "Calfs", weight: 100, machine: true),
]),
Sp(name: "Bodyweight Core", color: "teal", icon: "figure.core.training", activity: 3, ex: [
Ex(name: "Cat-Cow", sets: 1, reps: 10, load: 0),
@@ -128,7 +131,8 @@ for (order, sp) in seeds.enumerated() {
ExerciseDocument(
id: deterministicULID(label: "starter.\(slug).ex\(idx)"),
name: e.name, order: idx, sets: e.sets, reps: e.reps, weight: e.weight,
loadType: e.load, durationSeconds: e.dur)
loadType: e.load, durationSeconds: e.dur,
machineSettings: e.machine ? [] : nil)
},
activityType: sp.activity)
let data = try encoder.encode(doc)