feat: Working on pressure estimations feature, integrating all views and shared settings

This commit is contained in:
2024-06-10 13:34:38 -04:00
parent 51f7a30701
commit a6bfbd6877
15 changed files with 447 additions and 348 deletions

View File

@@ -4,13 +4,13 @@ import SharedModels
import Styleguide
import SwiftUI
@Reducer
public struct EquipmentSettingsForm {
@CasePathable
public enum InfoView {
case capacities
case manufacturersIncludedFilterPressureDrop
case ratedStaticPressures
}
@@ -21,34 +21,27 @@ public struct EquipmentSettingsForm {
@ObservableState
public struct State: Equatable {
@Presents public var destination: Destination.State?
public var coolingCapacity: EquipmentMetadata.CoolingCapacity
public var includesFilterDrop: Bool
public var equipmentType: EquipmentMeasurement.EquipmentType
public var fanType: EquipmentMetadata.FanType
public var focusedField: Field? = nil
public var heatingCapacity: Double?
public var ratedStaticPressures: RatedStaticPressures
@Shared public var sharedSettings: SharedPressureEstimationSettings
public init(
coolingCapacity: EquipmentMetadata.CoolingCapacity = .default,
destination: Destination.State? = nil,
includesFilterDrop: Bool = false,
equipmentType: EquipmentMeasurement.EquipmentType = .airHandler,
fanType: EquipmentMetadata.FanType = .constantSpeed,
heatingCapacity: Double? = nil,
ratedStaticPressures: RatedStaticPressures = .init()
sharedSettings: Shared<SharedPressureEstimationSettings>
) {
self.coolingCapacity = coolingCapacity
self.destination = destination
self.includesFilterDrop = includesFilterDrop
self.equipmentType = equipmentType
self.fanType = fanType
self.heatingCapacity = heatingCapacity
self.ratedStaticPressures = ratedStaticPressures
self._sharedSettings = sharedSettings
}
public var isValid: Bool {
guard equipmentType == .furnaceAndCoil else { return true }
return heatingCapacity != nil
return sharedSettings.heatingCapacity != nil
}
// Note: These need to be in display order.
@@ -57,6 +50,7 @@ public struct EquipmentSettingsForm {
case minimumStaticPressure
case maximumStaticPressure
case ratedStaticPressure
case manufacturersIncludedFilterPressureDrop
}
}
@@ -68,7 +62,6 @@ public struct EquipmentSettingsForm {
@CasePathable
public enum View {
case infoButtonTapped(InfoView)
case nextButtonTapped
case resetButtonTapped
case submitField
}
@@ -79,6 +72,17 @@ public struct EquipmentSettingsForm {
Reduce<State, Action> { state, action in
switch action {
case .binding(\.includesFilterDrop):
guard state.includesFilterDrop else {
state.sharedSettings.manufacturersIncludedFilterPressureDrop = nil
return .none
}
guard state.sharedSettings.manufacturersIncludedFilterPressureDrop != nil else {
return .none
}
state.sharedSettings.manufacturersIncludedFilterPressureDrop = 0.1
return .none
case .binding:
return .none
@@ -96,12 +100,8 @@ public struct EquipmentSettingsForm {
state.destination = .infoView(.init(view: infoView))
return .none
case .nextButtonTapped:
#warning("Fix me.")
return .none
case .resetButtonTapped:
state.heatingCapacity = nil
state.sharedSettings.heatingCapacity = nil
return .none
case .submitField:
@@ -138,7 +138,7 @@ public struct EquipmentSettingsFormView: View {
.listRowBackground(Color.clear)
Section {
FanTypePicker(selection: $store.fanType)
FanTypePicker(selection: $store.sharedSettings.fanType)
.pickerStyle(.segmented)
} header: {
Text("Fan Type")
@@ -154,20 +154,16 @@ public struct EquipmentSettingsFormView: View {
: "Capacity"
)
Spacer()
CoolingCapacityPicker(selection: $store.coolingCapacity)
// Picker("Cooling Capcity", selection: $store.coolingCapacity) {
// ForEach(CoolingCapacity.allCases) {
// Text($0.description)
// .tag($0)
// }
// }
CoolingCapacityPicker(
selection: $store.sharedSettings.coolingCapacity
)
}
if store.equipmentType == .furnaceAndCoil {
GridRow {
TextLabel("Heating")
textField(
"Heating Capacity",
value: $store.heatingCapacity,
value: $store.sharedSettings.heatingCapacity,
fractionLength: 0
)
.focused($focusedField, equals: .heatingCapacity)
@@ -190,7 +186,7 @@ public struct EquipmentSettingsFormView: View {
TextLabel("Minimum")
textField(
"Minimum Pressure",
value: $store.ratedStaticPressures.minimum,
value: $store.sharedSettings.ratedStaticPressures.minimum,
fractionLength: 2
)
.focused($focusedField, equals: .minimumStaticPressure)
@@ -200,7 +196,7 @@ public struct EquipmentSettingsFormView: View {
TextLabel("Maximum")
textField(
"Maximum Pressure",
value: $store.ratedStaticPressures.maximum,
value: $store.sharedSettings.ratedStaticPressures.maximum,
fractionLength: 2
)
.focused($focusedField, equals: .maximumStaticPressure)
@@ -210,7 +206,7 @@ public struct EquipmentSettingsFormView: View {
TextLabel("Rated")
textField(
"Rated Pressure",
value: $store.ratedStaticPressures.rated,
value: $store.sharedSettings.ratedStaticPressures.rated,
fractionLength: 2
)
.focused($focusedField, equals: .ratedStaticPressure)
@@ -221,74 +217,36 @@ public struct EquipmentSettingsFormView: View {
header("Rated Static Pressure", infoView: .ratedStaticPressures)
}
// Section {
// Grid(alignment: .leading, horizontalSpacing: 40) {
// if store.equipmentMeasurement.equipmentType == .furnaceAndCoil {
// GridRow {
// TextLabel("Coil")
// percentField("Coil Budget", value: $store.budgets.coilBudget.fraction)
// .focused($focusedField, equals: .coilBudget)
// .onSubmit { send(.submitField) }
// .numberPad()
// }
// }
//
// GridRow {
// TextLabel("Filter")
// percentField("Filter Budget", value: $store.budgets.filterBudget.fraction)
// .focused($focusedField, equals: .filterBudget)
// .onSubmit { send(.submitField) }
// .numberPad()
// }
//
// GridRow {
// TextLabel("Return")
// percentField("Return Plenum Budget", value: $store.budgets.returnPlenumBudget.fraction)
// .focused($focusedField, equals: .returnPlenumBudget)
// .onSubmit { send(.submitField) }
// .numberPad()
// }
//
// GridRow {
// TextLabel("Supply")
// percentField("Supply Plenum Budget", value: $store.budgets.supplyPlenumBudget.fraction)
// .focused($focusedField, equals: .supplyPlenumBudget)
// .onSubmit { send(.submitField) }
// .numberPad()
// }
// }
//
// } header: {
// VStack {
// header("Budgets", infoView: .budgets)
// #if os(macOS)
// .font(.title2)
// .padding(.top, 20)
// #endif
// FlaggedView(
// flagged: Flagged(wrappedValue: store.budgets.total.rawValue, .percent())
// )
// .flaggedViewStyle(BudgetFlagViewStyle())
// }
// }
// Section {
// TextField(
// "Airflow",
// value: $store.updatedAirflow,
// fractionLength: 0
// )
// } header: {
// header("Updated Airflow", infoView: .updatedAirflow)
// } footer: {
// HStack {
// ResetButton { send(.resetButtonTapped) }
// Spacer()
// NextButton { send(.nextButtonTapped) }
// .disabled(!store.isValid)
// }
// .padding(.top)
// }
Section {
VStack(alignment: .leading) {
HStack {
TextLabel("Includes Filter Drop")
Spacer()
Toggle("Includes Filter Drop", isOn: $store.includesFilterDrop)
}
if store.includesFilterDrop {
HStack {
TextLabel("Filter Drop")
Spacer()
textField(
"Filter Drop",
value: $store.sharedSettings.manufacturersIncludedFilterPressureDrop,
fractionLength: 2
)
.focused($focusedField, equals: .manufacturersIncludedFilterPressureDrop)
.decimalPad()
.padding(.leading, 40)
}
}
}
} header: {
header(infoView: .manufacturersIncludedFilterPressureDrop) {
VStack(alignment: .leading) {
Text("Manufacturer's")
Text("Filter Pressure Drop")
}
}
}
}
.labelsHidden()
.bind($focusedField, to: $store.focusedField)
@@ -306,23 +264,23 @@ public struct EquipmentSettingsFormView: View {
}
}
private func header(
_ title: String,
infoView: EquipmentSettingsForm.InfoView
private func header<Label: View>(
infoView: EquipmentSettingsForm.InfoView,
label: @escaping () -> Label
) -> some View {
HStack {
Text(title)
label()
Spacer()
InfoButton { send(.infoButtonTapped(infoView)) }
}
}
// private func percentField(
// _ title: LocalizedStringKey,
// value: Binding<Double>
// ) -> some View {
// TextField(title, value: value, format: .percent, prompt: Text(title))
// }
private func header(
_ title: String,
infoView: EquipmentSettingsForm.InfoView
) -> some View {
header(infoView: infoView) { Text(title) }
}
private func textField(
_ title: String,
@@ -362,37 +320,29 @@ fileprivate extension InfoViewFeature.State {
Record the cooling and heating capacities of the system.
"""
)
// case .budgets:
// self.init(
// title: "Budgets",
// body: """
// Budgeted percentages for static pressure estimations, these generally are set to
// reasonable defaults, however you can change them if desired.
//
// Note: These must total up to 100%.
// """
// )
case .manufacturersIncludedFilterPressureDrop:
self.init(
title: "Filter Pressure Drop",
body: """
Record the filter pressure drop that the manufacturer includes in their blower performance table, if applicable.
Sometimes this information is not listed, therefore it may be reasonable to use a sensible default value of '0.1'.
Note: The value that is set get's deducted from the filter pressure drop when determining the external static pressure of a system.
"""
)
case .ratedStaticPressures:
self.init(
title: "Rated Static",
body: """
Record the rated static pressures of the system.
These are generally found on the nameplate of the equipment or in the installation
manual.
These are generally found on the nameplate of the equipment or in the installation manual.
The defaults are generally acceptable for most unitary equipment.
"""
)
// case .updatedAirflow:
// self.init(
// title: "Updated Airflow",
// body: """
// This is used to generated estimated static pressures at the updated airflow
// compared to the existing airflow of the system.
// """
// )
}
}
}
@@ -401,9 +351,11 @@ fileprivate extension InfoViewFeature.State {
NavigationStack {
EquipmentSettingsFormView(
store: Store(
initialState: EquipmentSettingsForm.State()
initialState: EquipmentSettingsForm.State(
sharedSettings: Shared(SharedPressureEstimationSettings())
)
) {
EquipmentSettingsForm()
EquipmentSettingsForm()._printChanges()
}
)
#if os(macOS)