Seed machine-based starter routine from screenshots
Replace the bodyweight-catalog-derived seed (hardcoded 3x10, weight 0) with an explicit curated machine-based routine: Upper Body, Core, and Lower Body at 4x10 with starting weights taken from real workout logs. Decoupled from the shared exercise catalog YAML (still used by the exercise picker).
This commit is contained in:
+2
-2
@@ -14,8 +14,8 @@ All notable changes to this project are documented here.
|
|||||||
ULIDs (the phone is the sole writer of iCloud Drive).
|
ULIDs (the phone is the sole writer of iCloud Drive).
|
||||||
- Migrated the project to XcodeGen; iOS 26 / watchOS 26, Swift 6 strict
|
- Migrated the project to XcodeGen; iOS 26 / watchOS 26, Swift 6 strict
|
||||||
concurrency.
|
concurrency.
|
||||||
- Splits ship as on-demand starter data generated from the bundled exercise
|
- Splits ship as an on-demand machine-based starter routine (Upper Body, Core,
|
||||||
catalogs.
|
Lower Body) at 4×10 with sensible starting weights.
|
||||||
- Stored exercise/log durations as integer seconds (was a `Date` epoch hack).
|
- Stored exercise/log durations as integer seconds (was a `Date` epoch hack).
|
||||||
- Fixed: workout marked complete on creation, an undismissable delete dialog,
|
- Fixed: workout marked complete on creation, an undismissable delete dialog,
|
||||||
toolbar buttons hidden by nested navigation stacks, and a placeholder
|
toolbar buttons hidden by nested navigation stacks, and a placeholder
|
||||||
|
|||||||
@@ -1,45 +1,67 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import SwiftData
|
import SwiftData
|
||||||
|
|
||||||
/// Builds starter Splits from the bundled YAML exercise catalog, grouped by the
|
/// Builds the bundled machine-based starter routine (Upper Body / Core / Lower
|
||||||
/// catalog's `split` label (Upper Body / Core / Lower Body). Written on demand
|
/// Body). Written on demand (never auto-seeded) through the SyncEngine — an empty
|
||||||
/// (never auto-seeded) through the SyncEngine — an empty cache at launch can't be
|
/// cache at launch can't be told apart from an iCloud library that simply hasn't
|
||||||
/// told apart from an iCloud library that simply hasn't downloaded yet.
|
/// downloaded yet.
|
||||||
enum SplitSeeder {
|
enum SplitSeeder {
|
||||||
/// Visual theme per starter split group, in display order.
|
/// One starter exercise: name plus its default starting weight (lbs).
|
||||||
private static let groups: [(name: String, color: String, icon: String)] = [
|
private struct SeedExercise {
|
||||||
("Upper Body", "blue", "figure.strengthtraining.traditional"),
|
let name: String
|
||||||
("Core", "orange", "figure.core.training"),
|
let weight: Int
|
||||||
("Lower Body", "green", "figure.run"),
|
}
|
||||||
]
|
|
||||||
|
|
||||||
/// Default split source catalog (most universally applicable).
|
/// One starter split: visual theme plus its ordered exercises.
|
||||||
private static let sourceFile = "bodyweight-starter.exercises.yaml"
|
private struct SeedSplit {
|
||||||
|
let name: String
|
||||||
|
let color: String
|
||||||
|
let icon: String
|
||||||
|
let exercises: [SeedExercise]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets/reps shared by every starter exercise.
|
||||||
|
private static let defaultSets = 4
|
||||||
|
private static let defaultReps = 10
|
||||||
|
|
||||||
|
/// Starter splits in display order, with sensible machine starting weights.
|
||||||
|
/// Users adjust weights from the exercise screen.
|
||||||
|
private static let starterSplits: [SeedSplit] = [
|
||||||
|
SeedSplit(name: "Upper Body", color: "blue", icon: "figure.strengthtraining.traditional", exercises: [
|
||||||
|
SeedExercise(name: "Lat Pull Down", weight: 110),
|
||||||
|
SeedExercise(name: "Tricep Press", weight: 100),
|
||||||
|
SeedExercise(name: "Chest Press", weight: 40),
|
||||||
|
SeedExercise(name: "Seated Row", weight: 90),
|
||||||
|
]),
|
||||||
|
SeedSplit(name: "Core", color: "orange", icon: "figure.core.training", exercises: [
|
||||||
|
SeedExercise(name: "Abdominal", weight: 0),
|
||||||
|
SeedExercise(name: "Rotary", weight: 0),
|
||||||
|
]),
|
||||||
|
SeedSplit(name: "Lower Body", color: "green", icon: "figure.run", exercises: [
|
||||||
|
SeedExercise(name: "Abductor", weight: 140),
|
||||||
|
SeedExercise(name: "Adductor", weight: 140),
|
||||||
|
SeedExercise(name: "Leg Press", weight: 160),
|
||||||
|
SeedExercise(name: "Leg Curl", weight: 70),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
|
||||||
/// Builds the default split documents (fresh ULIDs each call).
|
/// Builds the default split documents (fresh ULIDs each call).
|
||||||
static func defaultSplitDocuments() -> [SplitDocument] {
|
static func defaultSplitDocuments() -> [SplitDocument] {
|
||||||
let lists = ExerciseListLoader.loadExerciseLists()
|
starterSplits.enumerated().map { order, split in
|
||||||
guard let catalog = lists[sourceFile] else { return [] }
|
let exercises = split.exercises.enumerated().map { idx, item in
|
||||||
|
|
||||||
var docs: [SplitDocument] = []
|
|
||||||
for (order, group) in groups.enumerated() {
|
|
||||||
let items = catalog.exercises.filter { $0.split == group.name }
|
|
||||||
guard !items.isEmpty else { continue }
|
|
||||||
|
|
||||||
let exercises = items.enumerated().map { idx, item in
|
|
||||||
ExerciseDocument(
|
ExerciseDocument(
|
||||||
id: ULID.make(), name: item.name, order: idx,
|
id: ULID.make(), name: item.name, order: idx,
|
||||||
sets: 3, reps: 10, weight: 0, loadType: LoadType.weight.rawValue,
|
sets: defaultSets, reps: defaultReps, weight: item.weight,
|
||||||
|
loadType: LoadType.weight.rawValue,
|
||||||
durationSeconds: 0, weightLastUpdated: nil, weightReminderWeeks: 2
|
durationSeconds: 0, weightLastUpdated: nil, weightReminderWeeks: 2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
docs.append(SplitDocument(
|
return SplitDocument(
|
||||||
schemaVersion: SplitDocument.currentSchema, id: ULID.make(),
|
schemaVersion: SplitDocument.currentSchema, id: ULID.make(),
|
||||||
name: group.name, color: group.color, systemImage: group.icon, order: order,
|
name: split.name, color: split.color, systemImage: split.icon, order: order,
|
||||||
createdAt: Date(), updatedAt: Date(), exercises: exercises
|
createdAt: Date(), updatedAt: Date(), exercises: exercises
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
return docs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes any starter splits whose name doesn't already exist, appended after
|
/// Writes any starter splits whose name doesn't already exist, appended after
|
||||||
|
|||||||
Reference in New Issue
Block a user