Feat: Working on pressure estimations feature

This commit is contained in:
2024-06-04 15:16:12 -04:00
parent e70f554b07
commit aa40985486
5 changed files with 153 additions and 52 deletions

View File

@@ -59,7 +59,8 @@ let package = Package(
.target( .target(
name: "Styleguide", name: "Styleguide",
dependencies: [ dependencies: [
"SharedModels" "SharedModels",
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
] ]
), ),
.testTarget( .testTarget(

View File

@@ -6,22 +6,39 @@ import SwiftUI
@Reducer @Reducer
public struct EstimateSettingsForm { public struct EstimateSettingsForm {
@CasePathable
public enum InfoView {
case budgets
case updatedAirflow
}
@Reducer(state: .equatable)
public enum Destination {
case infoView(InfoViewFeature)
}
@ObservableState @ObservableState
public struct State: Equatable { public struct State: Equatable {
@Presents public var destination: Destination.State?
public var budgets: BudgetedPercentEnvelope public var budgets: BudgetedPercentEnvelope
public let equipmentType: EquipmentType public let equipmentMeasurement: EquipmentMeasurement
public var fanType: FanType public var fanType: FanType
public var focusedField: Field? = nil public var focusedField: Field? = nil
public var updatedAirflow: Double? public var updatedAirflow: Double?
public init( public init(
equipmentType: EquipmentType, destination: Destination.State? = nil,
equipmentMeasurement: EquipmentMeasurement,
fanType: FanType = .constantSpeed, fanType: FanType = .constantSpeed,
updatedAirflow: Double? = nil updatedAirflow: Double? = nil
) { ) {
self.budgets = .init(equipmentType: equipmentType, fanType: fanType) self.destination = destination
self.equipmentType = equipmentType self.equipmentMeasurement = equipmentMeasurement
self.budgets = .init(
equipmentType: equipmentMeasurement.equipmentType,
fanType: fanType
)
self.fanType = fanType self.fanType = fanType
self.updatedAirflow = updatedAirflow self.updatedAirflow = updatedAirflow
} }
@@ -42,19 +59,15 @@ public struct EstimateSettingsForm {
public enum Action: BindableAction, ViewAction { public enum Action: BindableAction, ViewAction {
case binding(BindingAction<State>) case binding(BindingAction<State>)
case destination(PresentationAction<Destination.Action>)
case view(View) case view(View)
@CasePathable @CasePathable
public enum View { public enum View {
case infoButtonTapped(InfoButton) case infoButtonTapped(InfoView)
case nextButtonTapped
case resetButtonTapped case resetButtonTapped
case submitField case submitField
@CasePathable
public enum InfoButton {
case budgets
case updatedAirflow
}
} }
} }
@@ -62,9 +75,10 @@ public struct EstimateSettingsForm {
BindingReducer() BindingReducer()
Reduce<State, Action> { state, action in Reduce<State, Action> { state, action in
switch action { switch action {
case .binding(\.fanType): case .binding(\.fanType):
state.budgets = .init( state.budgets = .init(
equipmentType: state.equipmentType, equipmentType: state.equipmentMeasurement.equipmentType,
fanType: state.fanType fanType: state.fanType
) )
return .none return .none
@@ -72,15 +86,29 @@ public struct EstimateSettingsForm {
case .binding: case .binding:
return .none return .none
case .destination(.dismiss):
state.destination = nil
return .none
case .destination:
return .none
case let .view(action): case let .view(action):
switch action { switch action {
case .infoButtonTapped: case let .infoButtonTapped(infoView):
state.destination = .infoView(.init(view: infoView))
return .none
case .nextButtonTapped:
#warning("Fix me.") #warning("Fix me.")
return .none return .none
case .resetButtonTapped: case .resetButtonTapped:
state.budgets = .init(equipmentType: state.equipmentType, fanType: state.fanType) state.budgets = .init(
equipmentType: state.equipmentMeasurement.equipmentType,
fanType: state.fanType
)
state.updatedAirflow = nil state.updatedAirflow = nil
return .none return .none
@@ -91,6 +119,7 @@ public struct EstimateSettingsForm {
} }
} }
} }
.ifLet(\.$destination, action: \.destination)
} }
} }
@@ -121,7 +150,7 @@ public struct EstimateSettingsFormView: View {
Section { Section {
Grid(alignment: .leading, horizontalSpacing: 40) { Grid(alignment: .leading, horizontalSpacing: 40) {
if store.equipmentType == .furnaceAndCoil { if store.equipmentMeasurement.equipmentType == .furnaceAndCoil {
GridRow { GridRow {
TextLabel("Coil") TextLabel("Coil")
percentField("Coil Budget", value: $store.budgets.coilBudget.fraction) percentField("Coil Budget", value: $store.budgets.coilBudget.fraction)
@@ -177,7 +206,11 @@ public struct EstimateSettingsFormView: View {
} }
Section { Section {
TextField(
"Airflow",
value: $store.updatedAirflow,
fractionLength: 0
)
} header: { } header: {
HStack { HStack {
Text("Updated Airflow") Text("Updated Airflow")
@@ -189,8 +222,9 @@ public struct EstimateSettingsFormView: View {
ResetButton { send(.resetButtonTapped) } ResetButton { send(.resetButtonTapped) }
Spacer() Spacer()
Button("Next") { Button("Next") {
#warning("Fix me.") send(.nextButtonTapped)
} }
.disabled(!store.isValid)
} }
.padding(.top) .padding(.top)
} }
@@ -198,6 +232,16 @@ public struct EstimateSettingsFormView: View {
.labelsHidden() .labelsHidden()
.bind($focusedField, to: $store.focusedField) .bind($focusedField, to: $store.focusedField)
.navigationTitle("Estimate Settings") .navigationTitle("Estimate Settings")
.sheet(
item: $store.scope(
state: \.destination?.infoView,
action: \.destination.infoView
)
) { store in
NavigationStack {
InfoView(store: store)
}
}
} }
private func percentField( private func percentField(
@@ -219,11 +263,36 @@ fileprivate struct BudgetFlagViewStyle: FlaggedViewStyle {
} }
} }
fileprivate extension InfoViewFeature.State {
init(view: EstimateSettingsForm.InfoView) {
switch view {
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 .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.
"""
)
}
}
}
#Preview { #Preview {
NavigationStack { NavigationStack {
EstimateSettingsFormView( EstimateSettingsFormView(
store: Store( store: Store(
initialState: EstimateSettingsForm.State(equipmentType: .furnaceAndCoil) initialState: EstimateSettingsForm.State(equipmentMeasurement: .furnaceAndCoil(.init()))
) { ) {
EstimateSettingsForm() EstimateSettingsForm()
} }

View File

@@ -14,7 +14,11 @@ public struct InfoButton: View {
Button(action: action) { Button(action: action) {
Label("Info", systemImage: "info.circle") Label("Info", systemImage: "info.circle")
} }
.buttonStyle(infoButtonStyle) .buttonStyle(.plain)
.labelStyle(.iconOnly)
.font(.title2)
.foregroundStyle(Color.accentColor)
// .buttonStyle(infoButtonStyle)
} }
} }

View File

@@ -1,48 +1,74 @@
import ComposableArchitecture
import SwiftUI import SwiftUI
public struct InfoView: View { @Reducer
let headingText: String public struct InfoViewFeature {
public init() { }
@ObservableState
public struct State: Equatable {
let titleText: String
let bodyText: String let bodyText: String
public init(
public init(heading headingText: String, body bodyText: String) { title titleText: String,
self.headingText = headingText body bodyText: String
) {
self.titleText = titleText
self.bodyText = bodyText self.bodyText = bodyText
} }
}
public enum Action {
case dismissButtonTapped
}
@Dependency(\.dismiss) var dismiss
public var body: some ReducerOf<Self> {
Reduce { _, action in
switch action {
case .dismissButtonTapped:
return .run { _ in await self.dismiss() }
}
}
}
}
public struct InfoView: View {
let store: StoreOf<InfoViewFeature>
public init(store: StoreOf<InfoViewFeature>) {
self.store = store
}
public var body: some View { public var body: some View {
VStack(spacing: 40) { VStack(spacing: 40) {
Text(store.bodyText)
ZStack {
Text(headingText)
.font(.headline)
.bold()
.foregroundStyle(Color.white)
.padding()
}
.background {
RoundedRectangle(cornerRadius: 10)
.foregroundStyle(Color.orange.opacity(0.6))
}
ZStack {
Text(bodyText)
.font(.callout) .font(.callout)
.padding() .padding()
}
.background {
RoundedRectangle(cornerRadius: 10)
.foregroundStyle(Color.secondary.opacity(0.3))
}
.padding(.horizontal, 10)
Spacer() Spacer()
} }
.navigationTitle(store.titleText)
.padding(.horizontal) .padding(.horizontal)
.navigationBarBackButtonHidden()
.toolbar {
Button("Done") {
store.send(.dismissButtonTapped)
}
}
} }
} }
#Preview { #Preview {
InfoView(heading: "Generic Info View", body: "Explain what this view does here...") InfoView(
store: Store(
initialState: InfoViewFeature.State(
title: "Generic Info View",
body: "Explain what this view does here..."
),
reducer: InfoViewFeature.init
)
)
} }

View File

@@ -22,6 +22,7 @@ public struct DefaultInfoButtonStyle: PrimitiveButtonStyle {
public func makeBody(configuration: Configuration) -> some View { public func makeBody(configuration: Configuration) -> some View {
configuration.label configuration.label
.buttonStyle(.plain) .buttonStyle(.plain)
.font(.title2)
.foregroundStyle(Color.accentColor) .foregroundStyle(Color.accentColor)
.labelStyle(.iconOnly) .labelStyle(.iconOnly)
} }