Feat: Adds flagged equipment measurement view and style
This commit is contained in:
@@ -97,24 +97,50 @@ public enum EquipmentMeasurement: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension EquipmentMeasurement.AirHandler {
|
//extension EquipmentMeasurement.AirHandler {
|
||||||
|
//
|
||||||
|
// public enum Key: String, Equatable, CaseIterable {
|
||||||
|
// case returnPlenumPressure
|
||||||
|
// case postFilterPressure
|
||||||
|
// case postCoilPressure
|
||||||
|
// case supplyPlenumPressure
|
||||||
|
// case airflow
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//extension EquipmentMeasurement.FurnaceAndCoil {
|
||||||
|
//
|
||||||
|
// public enum Key: String, Equatable, CaseIterable {
|
||||||
|
// case returnPlenumPressure
|
||||||
|
// case postFilterPressure
|
||||||
|
// case preCoilPressure
|
||||||
|
// case supplyPlenumPressure
|
||||||
|
// case airflow
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
public enum Key: String, Equatable, CaseIterable {
|
#if DEBUG
|
||||||
case returnPlenumPressure
|
extension EquipmentMeasurement {
|
||||||
case postFilterPressure
|
public static func mock(type equipmentType: EquipmentType) -> Self {
|
||||||
case postCoilPressure
|
switch equipmentType {
|
||||||
case supplyPlenumPressure
|
case .airHandler:
|
||||||
case airflow
|
return .airHandler(.init(
|
||||||
}
|
airflow: 1200,
|
||||||
}
|
returnPlenumPressure: 0.3,
|
||||||
|
postFilterPressure: 0.6,
|
||||||
extension EquipmentMeasurement.FurnaceAndCoil {
|
postCoilPressure: 0.9,
|
||||||
|
supplyPlenumPressure: 0.2
|
||||||
public enum Key: String, Equatable, CaseIterable {
|
))
|
||||||
case returnPlenumPressure
|
|
||||||
case postFilterPressure
|
case .furnaceAndCoil:
|
||||||
case preCoilPressure
|
return .furnaceAndCoil(.init(
|
||||||
case supplyPlenumPressure
|
airflow: 1200,
|
||||||
case airflow
|
returnPlenumPressure: 0.3,
|
||||||
|
postFilterPressure: 0.6,
|
||||||
|
preCoilPressure: 0.4,
|
||||||
|
supplyPlenumPressure: 0.1
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -120,54 +120,19 @@ public struct FlaggedEquipmentMeasurement: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Key
|
// MARK: - Helpers
|
||||||
|
#if DEBUG
|
||||||
extension FlaggedEquipmentMeasurement {
|
extension FlaggedEquipmentMeasurement {
|
||||||
// NOTE: These need to be kept in display order.
|
public static func mock(type equipmentType: EquipmentType) -> Self {
|
||||||
public enum Key: Equatable, CaseIterable {
|
.init(
|
||||||
case returnPlenum
|
budgets: .init(equipmentType: equipmentType, fanType: .variableSpeed),
|
||||||
case filterDrop
|
measurement: .mock(type: equipmentType),
|
||||||
case coilDrop
|
ratedPressures: .init(),
|
||||||
case supplyPlenum
|
tons: .default
|
||||||
case staticPressure
|
)
|
||||||
case airflow
|
|
||||||
|
|
||||||
public var title: String {
|
|
||||||
switch self {
|
|
||||||
case .returnPlenum:
|
|
||||||
return "Return Plenum"
|
|
||||||
case .filterDrop:
|
|
||||||
return "Filter Pressure Drop"
|
|
||||||
case .coilDrop:
|
|
||||||
return "Coil Pressure Drop"
|
|
||||||
case .supplyPlenum:
|
|
||||||
return "Supply Plenum"
|
|
||||||
case .staticPressure:
|
|
||||||
return "External Static Pressure"
|
|
||||||
case .airflow:
|
|
||||||
return "System Airflow"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var flaggedKeyPath: KeyPath<FlaggedEquipmentMeasurement, Flagged> {
|
|
||||||
switch self {
|
|
||||||
case .returnPlenum:
|
|
||||||
return \.returnPlenumPressure
|
|
||||||
case .filterDrop:
|
|
||||||
return \.filterPressureDrop
|
|
||||||
case .coilDrop:
|
|
||||||
return \.coilPressureDrop
|
|
||||||
case .supplyPlenum:
|
|
||||||
return \.supplyPlenumPressure
|
|
||||||
case .staticPressure:
|
|
||||||
return \.externalStaticPressure
|
|
||||||
case .airflow:
|
|
||||||
return \.airflow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
// MARK: - Helpers
|
|
||||||
fileprivate extension Flagged {
|
fileprivate extension Flagged {
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
|||||||
26
Sources/Styleguide/FlaggedEquipmentMeasurementView.swift
Normal file
26
Sources/Styleguide/FlaggedEquipmentMeasurementView.swift
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import SharedModels
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
public struct FlaggedEquipmentMeasurementView: View {
|
||||||
|
|
||||||
|
@Environment(\.flaggedEquipmentMeasurementStyle) private var style
|
||||||
|
|
||||||
|
let measurement: FlaggedEquipmentMeasurement
|
||||||
|
|
||||||
|
public init(_ measurement: FlaggedEquipmentMeasurement) {
|
||||||
|
self.measurement = measurement
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some View {
|
||||||
|
style.makeBody(
|
||||||
|
configuration: FlaggedEquipmentMeasurementStyleConfiguration(
|
||||||
|
measurement: measurement
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
FlaggedEquipmentMeasurementView(.mock(type: .airHandler))
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ public struct FlaggedView<Label: View>: View {
|
|||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
flaggedViewStyle.makeBody(
|
flaggedViewStyle.makeBody(
|
||||||
configuration: .init(flagged: flagged, label: .init(label()))
|
configuration: FlaggedViewStyleConfiguration(flagged: flagged, label: .init(label()))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,10 @@ extension FlaggedView where Label == Text {
|
|||||||
public init(_ title: LocalizedStringKey, flagged: Flagged) {
|
public init(_ title: LocalizedStringKey, flagged: Flagged) {
|
||||||
self.init(flagged: flagged) { Text(title) }
|
self.init(flagged: flagged) { Text(title) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public init<S: StringProtocol>(_ title: S, flagged: Flagged) {
|
||||||
|
self.init(flagged: flagged) { Text(title) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FlaggedView where Label == EmptyView {
|
extension FlaggedView where Label == EmptyView {
|
||||||
|
|||||||
123
Sources/Styleguide/Styles/FlaggedEquipmentMeasurementStyle.swift
Normal file
123
Sources/Styleguide/Styles/FlaggedEquipmentMeasurementStyle.swift
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import SharedModels
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
public protocol FlaggedEquipmentMeasurementStyle {
|
||||||
|
associatedtype Body: View
|
||||||
|
typealias Configuration = FlaggedEquipmentMeasurementStyleConfiguration
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
func makeBody(configuration: Self.Configuration) -> Self.Body
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct FlaggedEquipmentMeasurementStyleConfiguration {
|
||||||
|
public let measurement: FlaggedEquipmentMeasurement
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AnyFlaggedEquipmentMeasurementStyle: FlaggedEquipmentMeasurementStyle {
|
||||||
|
private var _makeBody: (Configuration) -> AnyView
|
||||||
|
|
||||||
|
internal init(makeBody: @escaping (Configuration) -> AnyView) {
|
||||||
|
self._makeBody = makeBody
|
||||||
|
}
|
||||||
|
|
||||||
|
public init<S: FlaggedEquipmentMeasurementStyle>(_ style: S) {
|
||||||
|
self.init { configuration in
|
||||||
|
AnyView(style.makeBody(configuration: configuration))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeBody(configuration: Configuration) -> some View {
|
||||||
|
_makeBody(configuration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct GridFlaggedEquipmentMeasurementStyle: FlaggedEquipmentMeasurementStyle {
|
||||||
|
|
||||||
|
public func makeBody(configuration: Configuration) -> some View {
|
||||||
|
Grid(alignment: .leading, verticalSpacing: 20) {
|
||||||
|
ForEach(FlaggedEquipmentMeasurement.Key.allCases) { field in
|
||||||
|
FlaggedView(
|
||||||
|
field.title,
|
||||||
|
flagged: configuration.measurement[keyPath: field.flaggedKeyPath]
|
||||||
|
)
|
||||||
|
.flaggedViewStyle(.gridRow(fractionLength: field == .airflow ? 0 : 2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FlaggedEquipmentMeasurementStyle where Self == GridFlaggedEquipmentMeasurementStyle {
|
||||||
|
public static var grid: Self { .init() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct FlaggedEquipmentMeasurementStyleKey: EnvironmentKey {
|
||||||
|
static let defaultValue = AnyFlaggedEquipmentMeasurementStyle(GridFlaggedEquipmentMeasurementStyle())
|
||||||
|
}
|
||||||
|
|
||||||
|
extension EnvironmentValues {
|
||||||
|
public var flaggedEquipmentMeasurementStyle: AnyFlaggedEquipmentMeasurementStyle {
|
||||||
|
get { self[FlaggedEquipmentMeasurementStyleKey.self] }
|
||||||
|
set { self[FlaggedEquipmentMeasurementStyleKey.self] = newValue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
public func flaggedEquipmentMeasurementStyle(_ style: AnyFlaggedEquipmentMeasurementStyle) -> some View {
|
||||||
|
environment(\.flaggedEquipmentMeasurementStyle, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func flaggedEquipmentMeasurementStyle<S: FlaggedEquipmentMeasurementStyle>(
|
||||||
|
_ style: S
|
||||||
|
) -> some View {
|
||||||
|
flaggedEquipmentMeasurementStyle(AnyFlaggedEquipmentMeasurementStyle(style))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Key
|
||||||
|
fileprivate extension FlaggedEquipmentMeasurement {
|
||||||
|
// NOTE: These need to be kept in display order.
|
||||||
|
enum Key: Hashable, CaseIterable, Identifiable {
|
||||||
|
case returnPlenum
|
||||||
|
case filterDrop
|
||||||
|
case coilDrop
|
||||||
|
case supplyPlenum
|
||||||
|
case staticPressure
|
||||||
|
case airflow
|
||||||
|
|
||||||
|
var id: Self { self }
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
switch self {
|
||||||
|
case .returnPlenum:
|
||||||
|
return "Return Plenum"
|
||||||
|
case .filterDrop:
|
||||||
|
return "Filter Pressure Drop"
|
||||||
|
case .coilDrop:
|
||||||
|
return "Coil Pressure Drop"
|
||||||
|
case .supplyPlenum:
|
||||||
|
return "Supply Plenum"
|
||||||
|
case .staticPressure:
|
||||||
|
return "External Static Pressure"
|
||||||
|
case .airflow:
|
||||||
|
return "System Airflow"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var flaggedKeyPath: KeyPath<FlaggedEquipmentMeasurement, Flagged> {
|
||||||
|
switch self {
|
||||||
|
case .returnPlenum:
|
||||||
|
return \.returnPlenumPressure
|
||||||
|
case .filterDrop:
|
||||||
|
return \.filterPressureDrop
|
||||||
|
case .coilDrop:
|
||||||
|
return \.coilPressureDrop
|
||||||
|
case .supplyPlenum:
|
||||||
|
return \.supplyPlenumPressure
|
||||||
|
case .staticPressure:
|
||||||
|
return \.externalStaticPressure
|
||||||
|
case .airflow:
|
||||||
|
return \.airflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,7 +71,6 @@ public struct DefaultFlagViewStyle: FlaggedViewStyle {
|
|||||||
flaggedMessageView(flagged: configuration.flagged)
|
flaggedMessageView(flagged: configuration.flagged)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct FlagAndMessageOnlyStyle: FlaggedViewStyle {
|
public struct FlagAndMessageOnlyStyle: FlaggedViewStyle {
|
||||||
@@ -106,6 +105,33 @@ extension FlaggedViewStyle where Self == FlagAndMessageOnlyStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct FlaggedGridRowStyle: FlaggedViewStyle {
|
||||||
|
|
||||||
|
let fractionLength: Int
|
||||||
|
|
||||||
|
public func makeBody(configuration: Configuration) -> some View {
|
||||||
|
GridRow {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
configuration.label
|
||||||
|
.foregroundStyle(Color.secondary)
|
||||||
|
flaggedMessageView(flagged: configuration.flagged)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
configuration.flagged.wrappedValue,
|
||||||
|
format: .number.precision(.fractionLength(fractionLength))
|
||||||
|
)
|
||||||
|
configuration.flagged.flagImage
|
||||||
|
.gridCellAnchor(.trailing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FlaggedViewStyle where Self == FlaggedGridRowStyle {
|
||||||
|
public static func gridRow(fractionLength: Int = 2) -> Self {
|
||||||
|
.init(fractionLength: fractionLength)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private struct FlaggedViewStyleKey: EnvironmentKey {
|
private struct FlaggedViewStyleKey: EnvironmentKey {
|
||||||
static let defaultValue = AnyFlaggedViewStyle(style: DefaultFlagViewStyle())
|
static let defaultValue = AnyFlaggedViewStyle(style: DefaultFlagViewStyle())
|
||||||
}
|
}
|
||||||
@@ -123,10 +149,9 @@ extension FlaggedViewStyle where Self == DefaultFlagViewStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileprivate extension Flagged.CheckResult.Key {
|
||||||
|
|
||||||
extension Flagged.CheckResult.Key {
|
var flagColor: Color {
|
||||||
|
|
||||||
public var flagColor: Color {
|
|
||||||
switch self {
|
switch self {
|
||||||
case .good:
|
case .good:
|
||||||
return .green
|
return .green
|
||||||
@@ -140,7 +165,7 @@ extension Flagged.CheckResult.Key {
|
|||||||
|
|
||||||
|
|
||||||
extension Flagged {
|
extension Flagged {
|
||||||
public var flagColor: Color { projectedValue.key.flagColor }
|
var flagColor: Color { projectedValue.key.flagColor }
|
||||||
|
|
||||||
public var flagImage: some View {
|
public var flagImage: some View {
|
||||||
Image(systemName: "flag.fill")
|
Image(systemName: "flag.fill")
|
||||||
@@ -151,7 +176,7 @@ extension Flagged {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private func flaggedMessageView(flagged: Flagged) -> some View {
|
fileprivate func flaggedMessageView(flagged: Flagged) -> some View {
|
||||||
if let message = flagged.message {
|
if let message = flagged.message {
|
||||||
HStack {
|
HStack {
|
||||||
Text(flagged.projectedValue.key.title)
|
Text(flagged.projectedValue.key.title)
|
||||||
@@ -171,6 +196,6 @@ extension View {
|
|||||||
public func flaggedViewStyle<S: FlaggedViewStyle>(
|
public func flaggedViewStyle<S: FlaggedViewStyle>(
|
||||||
_ style: S
|
_ style: S
|
||||||
) -> some View {
|
) -> some View {
|
||||||
environment(\.flaggedViewStyle, AnyFlaggedViewStyle(style: style))
|
flaggedViewStyle(AnyFlaggedViewStyle(style: style))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user