Files
workouts/Workouts/Views/Settings/ExerciseFigureReviewView.swift
rzen 400601283e 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
2026-07-12 00:37:05 -04:00

80 lines
2.5 KiB
Swift

//
// 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