Remove the buried Start This Split button from the exercise editor

ExerciseListView is reached only via Settings > Splits > split > Edit >
Exercises, so its toolbar start button was effectively undiscoverable and
duplicated the home-screen split picker (the sole remaining start path).
Strip the button and its now-dead start flow: the active-workout prompt,
end-and-restart handling, started-workout navigation, and the AppServices
dependency. Also drop the changelog entry for the watch-launch wiring of
that button (f01e149) since the button no longer exists and never shipped.

Claude-Session: https://claude.ai/code/session_01PVNBVKp5bcq52X722uMjwT
This commit is contained in:
2026-07-09 22:51:10 -04:00
parent ae3aa15019
commit c885d37d44
2 changed files with 0 additions and 97 deletions
-2
View File
@@ -2,8 +2,6 @@
A new Cardio exercise and matching starter split let you log aerobic sessions, tracked on your Apple Watch as a cardio workout.
Starting a workout with a split's Start This Split button now brings it up on your Apple Watch too, matching how starting one from the main list already worked.
A new Auto-Advance option lets a split flow hands-free from one exercise to the next, resting automatically between them.
Each split can now set its own rest time, overriding the app-wide default in Settings.
@@ -13,7 +13,6 @@ import SwiftData
struct ExerciseListView: View {
@Environment(SyncEngine.self) private var sync
@Environment(AppServices.self) private var services
@Environment(\.dismiss) private var dismiss
// Resolve the split by id, not a captured entity: editing a seed's exercise from
@@ -25,15 +24,6 @@ struct ExerciseListView: View {
@State private var showingAddSheet: Bool = false
@State private var itemToEdit: Exercise? = nil
@State private var itemToDelete: Exercise? = nil
/// ID of the just-created workout; drives programmatic navigation once the
/// cache observer delivers the entity a beat after the file write (see
/// `navigatesToStartedWorkout`).
@State private var pendingWorkoutID: String? = nil
@Query(sort: \Workout.start, order: .reverse)
private var workouts: [Workout]
@State private var showingActivePrompt = false
@AppStorage("weightUnit") private var weightUnit: WeightUnit = .lb
init(split: Split) {
@@ -45,10 +35,6 @@ struct ExerciseListView: View {
return splits.first { $0.id == id }
}
private var activeWorkouts: [Workout] {
workouts.filter { $0.status == .inProgress || $0.status == .notStarted }
}
var body: some View {
Group {
if let split {
@@ -58,8 +44,6 @@ struct ExerciseListView: View {
.task { dismiss() }
}
}
// Navigate into the workout's log screen once the entity appears in the cache.
.navigatesToStartedWorkout(pendingWorkoutID: $pendingWorkoutID)
}
@ViewBuilder
@@ -103,14 +87,6 @@ struct ExerciseListView: View {
}
}
.navigationTitle(split.name)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Start This Split") {
confirmAndStart()
}
.disabled(split.exercisesArray.isEmpty)
}
}
.sheet(isPresented: $showingAddSheet) {
ExercisePickerView(onExerciseSelected: { exerciseNames in
addExercises(names: exerciseNames)
@@ -138,53 +114,10 @@ struct ExerciseListView: View {
} message: { item in
Text("Remove \"\(item.name)\" from this split?")
}
.confirmationDialog(
activePromptTitle,
isPresented: $showingActivePrompt,
titleVisibility: .visible
) {
Button("End Current & Start New") { endActiveThenStart() }
Button("Start in Parallel") { start() }
Button("Cancel", role: .cancel) { showingActivePrompt = false }
} message: {
Text(activePromptMessage)
}
}
// MARK: - Helpers
private var activePromptTitle: String {
activeWorkouts.count == 1 ? "Workout in Progress" : "\(activeWorkouts.count) Workouts in Progress"
}
private var activePromptMessage: String {
let n = activeWorkouts.count
let those = n == 1 ? "it" : "them"
return "You already have \(n == 1 ? "a workout" : "\(n) workouts") going. End \(those) first, or run this one alongside."
}
/// Prompt before starting if other workouts are still going; otherwise start straight away.
private func confirmAndStart() {
if activeWorkouts.isEmpty {
start()
} else {
showingActivePrompt = true
}
}
/// End every in-flight workout (keeping its progress), then start this split.
private func endActiveThenStart() {
let toEnd = activeWorkouts.map { WorkoutDocument(from: $0) }
showingActivePrompt = false
Task {
for var doc in toEnd {
doc.endKeepingProgress()
await sync.save(workout: doc)
}
}
start()
}
private func moveExercises(from source: IndexSet, to destination: Int) {
guard let split else { return }
var exercises = split.exercisesArray
@@ -199,34 +132,6 @@ struct ExerciseListView: View {
Task { await sync.save(split: doc) }
}
private func start() {
guard let split else { return }
let startDate = Date()
let logs = split.exercisesArray.enumerated().map { i, ex in
WorkoutLogDocument(planFrom: ExerciseDocument(from: ex), order: i, date: startDate)
}
let doc = WorkoutDocument(
schemaVersion: WorkoutDocument.currentSchemaVersion,
id: ULID.make(),
splitID: split.id,
splitName: split.name,
start: startDate,
end: nil,
status: WorkoutStatus.notStarted.rawValue,
createdAt: startDate,
updatedAt: startDate,
logs: logs,
restSeconds: split.restSeconds, autoAdvance: split.autoAdvance
)
Task {
await sync.save(workout: doc)
pendingWorkoutID = doc.id
}
// Bring the Apple Watch up into the session so the user can run it from the wrist,
// tagged with the split's activity type mirroring the split-picker start path.
services.workoutLauncher.launchWatchWorkout(activityType: split.activityTypeEnum.hkActivityType)
}
private func addExercises(names: [String]) {
guard let split else { return }
var doc = SplitDocument(from: split)