import SwiftUI struct PhView: View { @Bindable var state: AppState var body: some View { VStack(spacing: 0) { controlsRow Divider() phBody .frame(maxWidth: .infinity, maxHeight: .infinity) .padding() } } // MARK: - Controls private var controlsRow: some View { HStack(spacing: 10) { LabeledField("Stabilize s", text: $state.phStabilize, width: 80) Button("Measure pH") { state.startPh() } .buttonStyle(ActionButtonStyle(color: .green)) Spacer() } .padding(.horizontal) .padding(.vertical, 8) } // MARK: - Result body @ViewBuilder private var phBody: some View { if let r = state.phResult { VStack(alignment: .leading, spacing: 8) { Text(String(format: "pH: %.2f", r.ph)) .font(.system(size: 48, weight: .bold, design: .rounded)) .foregroundStyle(.primary) let nernstSlope = 0.1984 * (Double(r.tempC) + 273.15) Text(String(format: "OCP: %.1f mV | Nernst slope: %.2f mV/pH | Temp: %.1f\u{00B0}C", r.vOcpMv, nernstSlope, r.tempC)) .font(.subheadline) .foregroundStyle(.secondary) if let refR = state.phRef { let dPh = r.ph - refR.ph let dV = r.vOcpMv - refR.vOcpMv Text(String(format: "vs Ref: dpH=%+.3f dOCP=%+.1f mV (ref pH=%.2f)", dPh, dV, refR.ph)) .font(.subheadline) .foregroundStyle(.secondary) } } } else { VStack(alignment: .leading, spacing: 8) { Text("No measurement yet") .font(.title3) .foregroundStyle(.secondary) Text("OCP method: V(SE0) - V(RE0) with Nernst correction") .font(.caption) .foregroundStyle(Color(white: 0.4)) } } } }