// // BatteryCheckpointEditorSheetView.swift // USB Meter // // Created by Codex on 10/04/2026. // import SwiftUI struct BatteryCheckpointEditorSheetView: View { @EnvironmentObject private var appData: AppData @EnvironmentObject private var meter: Meter @Environment(\.dismiss) private var dismiss @State private var batteryPercent = "" @State private var label = "" @State private var confirmationWarning: BatteryCheckpointPlausibilityWarning? private var activeSession: ChargeSessionSummary? { appData.activeChargeSessionSummary(for: meter.btSerial.macAddress.description) } private var plausibilityWarning: BatteryCheckpointPlausibilityWarning? { guard let percent = Double(batteryPercent), let activeSession else { return nil } return appData.batteryCheckpointPlausibilityWarning(percent: percent, for: activeSession.id) } var body: some View { NavigationView { Form { Section( header: ContextInfoHeader( title: "Checkpoint", message: "The checkpoint is stored on the active charge session and later used for capacity estimation and the typical charge curve." ) ) { TextField("Battery %", text: $batteryPercent) .keyboardType(.decimalPad) TextField("Label (optional)", text: $label) } if let plausibilityWarning { Section(header: Text(plausibilityWarning.title)) { Text(plausibilityWarning.message) .font(.footnote) .foregroundColor(.orange) } } } .navigationTitle("Battery Checkpoint") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { dismiss() } } ToolbarItem(placement: .confirmationAction) { Button("Save") { saveCheckpoint() } .disabled( (Double(batteryPercent) ?? -1) < 0 || (Double(batteryPercent) ?? 101) > 100 || appData.activeChargeSessionSummary(for: meter.btSerial.macAddress.description) == nil ) } } } .navigationViewStyle(StackNavigationViewStyle()) .alert(item: $confirmationWarning) { warning in Alert( title: Text(warning.title), message: Text(warning.message), primaryButton: .destructive(Text("Save Anyway")) { saveCheckpoint(forceOverride: true) }, secondaryButton: .cancel() ) } } private func saveCheckpoint(forceOverride: Bool = false) { guard let percent = Double(batteryPercent) else { return } if !forceOverride, let plausibilityWarning { confirmationWarning = plausibilityWarning return } let didSave = appData.addBatteryCheckpoint( percent: percent, label: label, for: meter ) if didSave { dismiss() } } }