Feat: Working on pressure estimations feature
This commit is contained in:
@@ -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(
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user