Add a debug figure-review pager under Settings > Developer
Swipe through every bundled exercise rig, toggling between the looping figure and its authored reference page, to QA the library on device. Claude-Session: https://claude.ai/code/session_01PKptrgbx74peTwHGRxBojv
This commit is contained in:
@@ -261,8 +261,9 @@ private struct MachineSettingsCard: View {
|
||||
}
|
||||
|
||||
/// Renders a parsed `ExerciseInfo`: summary, target chips, then each authored
|
||||
/// section with its numbered steps or bullets.
|
||||
private struct ExerciseInfoContent: View {
|
||||
/// section with its numbered steps or bullets. Internal so the debug figure-review
|
||||
/// screen can reuse it.
|
||||
struct ExerciseInfoContent: View {
|
||||
let info: ExerciseInfo
|
||||
|
||||
var body: some View {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// ExerciseFigureReviewView.swift
|
||||
// Workouts
|
||||
//
|
||||
// Copyright 2026 Rouslan Zenetl. All Rights Reserved.
|
||||
//
|
||||
|
||||
#if DEBUG
|
||||
import SwiftUI
|
||||
|
||||
/// Debug-only QA screen (Settings → Developer): swipe through every bundled
|
||||
/// exercise to eyeball its stick-figure rig for glitches, flipping between the
|
||||
/// looping figure and the authored reference copy with a segmented picker. The
|
||||
/// picker state is shared across pages so a figure-only sweep stays in figure mode.
|
||||
struct ExerciseFigureReviewView: View {
|
||||
private enum Pane: String, CaseIterable, Identifiable {
|
||||
case figure = "Figure"
|
||||
case info = "Info"
|
||||
var id: String { rawValue }
|
||||
}
|
||||
|
||||
private let names = ExerciseMotionLibrary.exerciseNames
|
||||
|
||||
@State private var index = 0
|
||||
@State private var pane: Pane = .figure
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Picker("Pane", selection: $pane) {
|
||||
ForEach(Pane.allCases) { pane in
|
||||
Text(pane.rawValue).tag(pane)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 8)
|
||||
|
||||
TabView(selection: $index) {
|
||||
ForEach(Array(names.enumerated()), id: \.offset) { i, name in
|
||||
page(for: name)
|
||||
.tag(i)
|
||||
}
|
||||
}
|
||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||
}
|
||||
.navigationTitle(names.indices.contains(index) ? names[index] : "Exercises")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Text("\(index + 1) / \(names.count)")
|
||||
.font(.subheadline)
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func page(for name: String) -> some View {
|
||||
switch pane {
|
||||
case .figure:
|
||||
ExerciseFigureSlot(exerciseName: name)
|
||||
case .info:
|
||||
ScrollView {
|
||||
Group {
|
||||
if let info = ExerciseInfoLibrary.info(for: name) {
|
||||
ExerciseInfoContent(info: info)
|
||||
} else {
|
||||
Text("No reference copy for this exercise.")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -181,6 +181,11 @@ struct SettingsView: View {
|
||||
} label: {
|
||||
Label("Clean Up Duplicates", systemImage: "wrench.and.screwdriver")
|
||||
}
|
||||
NavigationLink {
|
||||
ExerciseFigureReviewView()
|
||||
} label: {
|
||||
Label("Review Exercise Figures", systemImage: "figure.strengthtraining.traditional")
|
||||
}
|
||||
} header: {
|
||||
Text("Developer")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user