Let routines rename exercises and repeat them for interval segments

An exercise's name is now a per-routine display name: a new optional
libraryName on ExerciseDocument (snapshotted onto WorkoutLogDocument at
plan time) keeps the link to the bundled library exercise, and every
figure/info/cue lookup resolves libraryName ?? name. Deliberately not
schema-bumped — an older app dropping the key only strands the
figure link, same rationale as activityType. Cache schema bumped to 9
for the new columns.

The picker no longer filters out exercises already in the routine
(an "×N" badge marks them instead), exercise rows gain a leading
Duplicate swipe that clones an entry in place, and the edit sheet gets
a Name field with the library exercise shown read-only above it.

Claude-Session: https://claude.ai/code/session_01H8VxUX4ckjU3vRF5M4L5FV
This commit is contained in:
2026-07-12 18:38:14 -04:00
parent d04526826c
commit df5c77eee1
15 changed files with 203 additions and 38 deletions
@@ -15,10 +15,17 @@ struct ExercisePickerView: View {
var onExerciseSelected: ([String]) -> Void
var allowMultiSelect: Bool = false
/// How many times each exercise already appears in the routine being edited
/// shown as a "×N" badge so picking it again (for interval-style segments like
/// a treadmill's warmup/brisk/cooldown) doesn't read as a mistake. Keyed by
/// library name. Empty for callers with no notion of "already in this routine".
var inRoutineCounts: [String: Int] = [:]
init(onExerciseSelected: @escaping ([String]) -> Void, allowMultiSelect: Bool = false) {
init(onExerciseSelected: @escaping ([String]) -> Void, allowMultiSelect: Bool = false,
inRoutineCounts: [String: Int] = [:]) {
self.onExerciseSelected = onExerciseSelected
self.allowMultiSelect = allowMultiSelect
self.inRoutineCounts = inRoutineCounts
}
var body: some View {
@@ -35,6 +42,10 @@ struct ExercisePickerView: View {
HStack {
Text(exerciseName)
Spacer()
if let count = inRoutineCounts[exerciseName], count > 0 {
Text("×\(count)")
.foregroundStyle(.secondary)
}
if selectedExercises.contains(exerciseName) {
Image(systemName: "checkmark")
.foregroundColor(.accentColor)
@@ -46,7 +57,14 @@ struct ExercisePickerView: View {
onExerciseSelected([exerciseName])
dismiss()
}) {
Text(exerciseName)
HStack {
Text(exerciseName)
Spacer()
if let count = inRoutineCounts[exerciseName], count > 0 {
Text("×\(count)")
.foregroundStyle(.secondary)
}
}
}
}
}