feat: Working on pressure estimations feature, integrating all views and shared settings
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user