Add machine comfort settings and tighten the document schemas
Machine-based exercises now carry ordered name/value comfort settings (seat height, back-rest position, ...) on both ExerciseDocument and, as a plan-time snapshot, WorkoutLogDocument — the optional array doubles as the machine flag. Editable from the exercise editor's new Machine section and from the workout row's settings sheet, whose mid-workout edits write back to the originating split (workout saved first, so seed clone-on-edit repointing can't clobber the log edit). Schema tightening rides the same rev: splits bump to v2 (weight-reminder fields and the unused exercise category removed), workouts to v3 (the derived `completed` flag removed; status is the single source). Starter seeds regenerated at v2 with unchanged ULIDs; SwiftData cache schema bumped to rebuild. SCHEMA.md documents the shapes. Claude-Session: https://claude.ai/code/session_01LEoff8bXGBS83tK1c55Mf7
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// MachineSettingsEditor.swift
|
||||
// Workouts
|
||||
//
|
||||
// Copyright 2025 Rouslan Zenetl. All Rights Reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// Reusable editor for an ordered list of machine comfort settings (seat height,
|
||||
/// back-rest incline, pin position…). Drop it into a `Form`/`List` `Section`: it
|
||||
/// renders one `name`/`value` row per setting with swipe-to-delete and
|
||||
/// drag-to-reorder, plus an "Add Setting" row. Shared by the exercise add/edit
|
||||
/// screen (Surface 1) and the in-workout settings sheet (Surface 2).
|
||||
///
|
||||
/// `MachineSetting` is a plain Codable wire type with no identity, so the editor
|
||||
/// keeps a per-row `UUID` internally (stable across edits/reorders, unlike an
|
||||
/// index) and mirrors changes back into the `settings` binding. The editor is the
|
||||
/// sole mutator of `settings` while it's on screen, so a one-way seed at init is
|
||||
/// enough — there's no external write to reconcile.
|
||||
struct MachineSettingsEditor: View {
|
||||
@Binding var settings: [MachineSetting]
|
||||
@State private var rows: [Row]
|
||||
|
||||
init(settings: Binding<[MachineSetting]>) {
|
||||
_settings = settings
|
||||
_rows = State(initialValue: settings.wrappedValue.map(Row.init))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ForEach($rows) { $row in
|
||||
HStack {
|
||||
TextField("Setting", text: $row.name)
|
||||
.textInputAutocapitalization(.words)
|
||||
TextField("Value", text: $row.value)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.foregroundStyle(.secondary)
|
||||
.frame(maxWidth: 120)
|
||||
}
|
||||
}
|
||||
.onDelete { rows.remove(atOffsets: $0) }
|
||||
.onMove { rows.move(fromOffsets: $0, toOffset: $1) }
|
||||
|
||||
Button {
|
||||
withAnimation { rows.append(Row(MachineSetting(name: "", value: ""))) }
|
||||
} label: {
|
||||
Label("Add Setting", systemImage: "plus.circle.fill")
|
||||
}
|
||||
// Mirror the identified rows back into the plain wire-type binding on every
|
||||
// edit/add/delete/reorder.
|
||||
.onChange(of: rows) { _, newRows in
|
||||
settings = newRows.map(\.setting)
|
||||
}
|
||||
}
|
||||
|
||||
/// Session-only identified wrapper so `ForEach` and reordering have a stable
|
||||
/// identity that survives text edits.
|
||||
fileprivate struct Row: Identifiable, Equatable {
|
||||
let id = UUID()
|
||||
var name: String
|
||||
var value: String
|
||||
|
||||
init(_ setting: MachineSetting) {
|
||||
name = setting.name
|
||||
value = setting.value
|
||||
}
|
||||
|
||||
var setting: MachineSetting { MachineSetting(name: name, value: value) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user