Files
swift-estimated-pressures-core/Sources/PressureEstimationsFeature/RatedStaticPressuresSection.swift

142 lines
3.7 KiB
Swift

import ComposableArchitecture
import SharedModels
import Styleguide
import SwiftUI
#warning("Add info view destination??")
/// Allows for rated static pressure fields to be optional values, setting their corresponding shared state values to zero when they're nilled out.
///
@Reducer
public struct RatedStaticPressuresSection {
@ObservableState
public struct State: Equatable {
@Shared public var staticPressures: RatedStaticPressures
public var focusedField: FocusedField?
public var maxPressure: Double?
public var minPressure: Double?
public var ratedPressure: Double?
public init(
staticPressures: Shared<RatedStaticPressures>
) {
self._staticPressures = staticPressures
self.maxPressure = staticPressures.maximum.wrappedValue
self.minPressure = staticPressures.minimum.wrappedValue
self.ratedPressure = staticPressures.rated.wrappedValue
}
public var isValid: Bool {
maxPressure != nil
&& minPressure != nil
&& ratedPressure != nil
}
public enum FocusedField: String, Hashable, CaseIterable, FocusableField {
case maximum
case minimum
case rated
var label: String { rawValue.capitalized }
}
}
public enum Action: BindableAction {
case binding(BindingAction<State>)
case delegate(DelegateAction)
public enum DelegateAction {
case infoButtonTapped
}
}
public var body: some Reducer<State, Action> {
BindingReducer()
Reduce<State, Action> { state, action in
switch action {
case .binding(\.maxPressure):
state.staticPressures.maximum = state.maxPressure ?? 0
return .none
case .binding(\.minPressure):
state.staticPressures.minimum = state.minPressure ?? 0
return .none
case .binding(\.ratedPressure):
state.staticPressures.rated = state.ratedPressure ?? 0
return .none
case .binding:
return .none
case .delegate:
return .none
}
}
}
}
public struct RatedStaticPressuresSectionView: View {
@FocusState private var focusedField: RatedStaticPressuresSection.State.FocusedField?
@Bindable var store: StoreOf<RatedStaticPressuresSection>
public init(store: StoreOf<RatedStaticPressuresSection>) {
self.store = store
}
public var body: some View {
Section {
Grid(alignment: .leading, horizontalSpacing: 40) {
GridRow {
label(for: .maximum)
TextField(
"Maximum",
value: $store.maxPressure,
fractionLength: 2,
prompt: Text("Max Static Pressure")
)
.decimalPad()
.focused($focusedField, equals: .maximum)
}
GridRow {
label(for: .minimum)
TextField(
"Minimum",
value: $store.minPressure,
fractionLength: 2,
prompt: Text("Min Static Pressure")
)
.decimalPad()
.focused($focusedField, equals: .minimum)
}
GridRow {
label(for: .rated)
TextField(
"Rated",
value: $store.ratedPressure,
fractionLength: 2,
prompt: Text("Rated Static Pressure")
)
.decimalPad()
.focused($focusedField, equals: .rated)
}
}
.dynamicBottomPadding()
} header: {
HStack {
SectionHeaderLabel("Rated Static Pressures")
Spacer()
InfoButton { store.send(.delegate(.infoButtonTapped)) }
}
}
.bind($focusedField, to: $store.focusedField)
}
private func label(for field: RatedStaticPressuresSection.State.FocusedField) -> some View {
TextLabel(field.label)
}
}