diff --git a/Sources/PressureEstimationsFeature/EquipmentMeasurementForm.swift b/Sources/PressureEstimationsFeature/EquipmentMeasurementForm.swift index 81c67ac..cee0b5f 100644 --- a/Sources/PressureEstimationsFeature/EquipmentMeasurementForm.swift +++ b/Sources/PressureEstimationsFeature/EquipmentMeasurementForm.swift @@ -284,9 +284,10 @@ public struct EquipmentMeasurementFormView: View { if store.allowEquipmentTypeSelection { Section { } header: { - Text("Equipment Type") + SectionHeaderLabel("Equipment Type") } footer: { EquipmentTypePicker(selection: $store.equipmentType) + .dynamicBottomPadding() .pickerStyle(.segmented) .labelsHidden() } @@ -295,9 +296,10 @@ public struct EquipmentMeasurementFormView: View { Grid(alignment: .leading, horizontalSpacing: 40) { ForEach(store.pressureFields, content: gridRow(for:)) } + .dynamicBottomPadding() } header: { HStack { - Text("Static Measurements") + SectionHeaderLabel("Static Measurements") Spacer() InfoButton { send(.infoButtonTapped) } } @@ -310,7 +312,7 @@ public struct EquipmentMeasurementFormView: View { } header: { HStack { Spacer() - Text(store.sharedSettings.equipmentMetadata.coolingCapacity.description) + SectionHeaderLabel(store.sharedSettings.equipmentMetadata.coolingCapacity.description) } } footer: { HStack { @@ -348,7 +350,8 @@ public struct EquipmentMeasurementFormView: View { } private func gridRow(for field: EquipmentMeasurementForm.State.Field) -> some View { - TextLabeledContent(store.label(field: field)) { + GridRow { + TextLabel(store.label(field: field)) textField(for: field) } } diff --git a/Sources/PressureEstimationsFeature/EquipmentSettingsForm.swift b/Sources/PressureEstimationsFeature/EquipmentSettingsForm.swift index 1316261..690bac2 100644 --- a/Sources/PressureEstimationsFeature/EquipmentSettingsForm.swift +++ b/Sources/PressureEstimationsFeature/EquipmentSettingsForm.swift @@ -133,18 +133,19 @@ public struct EquipmentSettingsFormView: View { Form { Section { EquipmentTypePicker(selection: $store.equipmentType) + .dynamicBottomPadding() .pickerStyle(.segmented) - EmptyView() } header: { - Text("Equipment Type") + SectionHeaderLabel("Equipment Type") } .listRowBackground(Color.clear) Section { FanTypePicker(selection: $store.sharedSettings.fanType) + .dynamicBottomPadding() .pickerStyle(.segmented) } header: { - Text("Fan Type") + SectionHeaderLabel("Fan Type") } .listRowBackground(Color.clear) @@ -175,11 +176,13 @@ public struct EquipmentSettingsFormView: View { } } } + .dynamicBottomPadding() +// .applyPadding() } header: { if store.equipmentType == .airHandler { EmptyView() } else { - Text("Capacities") + SectionHeaderLabel("Capacities") } } @@ -187,6 +190,7 @@ public struct EquipmentSettingsFormView: View { Grid(alignment: .leading, horizontalSpacing: 40) { ForEach(RatingsField.allCases, content: ratingsRow(for:)) } + .dynamicBottomPadding() .labeledContentStyle(.gridRow) } header: { header("Rated Static Pressure", infoView: .ratedStaticPressures) @@ -262,7 +266,7 @@ public struct EquipmentSettingsFormView: View { label: @escaping () -> Label ) -> some View { HStack { - label() + SectionHeaderLabel { label() } Spacer() InfoButton { send(.infoButtonTapped(infoView)) } } @@ -285,6 +289,17 @@ public struct EquipmentSettingsFormView: View { } } +fileprivate extension View { + @ViewBuilder + func applyPadding() -> some View { + #if os(macOS) + self.padding(.bottom, 20) + #else + self + #endif + } +} + fileprivate struct BudgetFlagViewStyle: FlaggedViewStyle { func makeBody(configuration: Configuration) -> some View { diff --git a/Sources/PressureEstimationsFeature/PressureEstimations.swift b/Sources/PressureEstimationsFeature/PressureEstimations.swift index d91c8e3..6035480 100644 --- a/Sources/PressureEstimationsFeature/PressureEstimations.swift +++ b/Sources/PressureEstimationsFeature/PressureEstimations.swift @@ -108,9 +108,11 @@ public struct PressureEstimationsView: View { } public var body: some View { - EquipmentSettingsFormView( - store: store.scope(state: \.equipmentSettings, action: \.equipmentSettings) - ) + ScrollView { + EquipmentSettingsFormView( + store: store.scope(state: \.equipmentSettings, action: \.equipmentSettings) + ) + } .navigationTitle("Equipment Settings") .toolbar { NextButton { send(.nextButtonTapped) } @@ -123,10 +125,11 @@ public struct PressureEstimationsView: View { action: \.destination.equipmentMeasurements ) ) { measurementStore in - EquipmentMeasurementFormView(store: measurementStore) - .navigationTitle("Existing Measurements") + ScrollView { + EquipmentMeasurementFormView(store: measurementStore) + .navigationTitle("Existing Measurements") + } } - } } diff --git a/Sources/Styleguide/Modifiers/DynamicPaddingModifier.swift b/Sources/Styleguide/Modifiers/DynamicPaddingModifier.swift new file mode 100644 index 0000000..6486100 --- /dev/null +++ b/Sources/Styleguide/Modifiers/DynamicPaddingModifier.swift @@ -0,0 +1,18 @@ +import SharedModels +import SwiftUI + +extension View { + + public func dynamicBottomPadding( + iOS iOSPadding: CGFloat? = nil, + macOS macOSPadding: CGFloat? = 40 + ) -> some View { + self + #if os(macOS) + .padding(.bottom, macOSPadding) + #elseif os(iOS) + .padding(.bottom, iOSPadding) + #endif + } +} + diff --git a/Sources/Styleguide/SectionHeaderLabel.swift b/Sources/Styleguide/SectionHeaderLabel.swift new file mode 100644 index 0000000..c59f668 --- /dev/null +++ b/Sources/Styleguide/SectionHeaderLabel.swift @@ -0,0 +1,50 @@ +import SwiftUI + +public struct SectionHeaderLabel: View { + @Environment(\.sectionHeaderLabelStyle) var style + + let content: () -> Content + + public init(@ViewBuilder _ content: @escaping () -> Content) { + self.content = content + } + + public var body: some View { + style.makeBody( + configuration: TextLabelConfiguration( + label: TextLabelConfiguration.Label(content: content()) + ) + ) + } +} + +extension SectionHeaderLabel where Content == Text { + + public init(_ text: LocalizedStringKey) { + self.init { Text(text) } + } + + public init(_ text: S) where S: StringProtocol { + self.init { Text(text) } + } +} + +#Preview { + Form { + Section { + Text("Content") + } header: { + SectionHeaderLabel("One") + } + + Section { + Text("Content") + } header: { + SectionHeaderLabel("Two") + } + } + .formStyle(.grouped) + #if os(macOS) + .frame(width: 400, height: 400) + #endif +} diff --git a/Sources/Styleguide/Styles/FormStyle.swift b/Sources/Styleguide/Styles/FormStyle.swift index dab21a3..b81f8fc 100644 --- a/Sources/Styleguide/Styles/FormStyle.swift +++ b/Sources/Styleguide/Styles/FormStyle.swift @@ -6,6 +6,7 @@ extension View { public func applyFormStyle() -> some View { self .labelsHidden() +// .formStyle(.grouped) .textLabelStyle(.boldSecondary) .textFieldStyle(.roundedBorder) #if os(macOS) diff --git a/Sources/Styleguide/Styles/TextLabelStyle.swift b/Sources/Styleguide/Styles/TextLabelStyle.swift index 4d837c0..5d44c72 100644 --- a/Sources/Styleguide/Styles/TextLabelStyle.swift +++ b/Sources/Styleguide/Styles/TextLabelStyle.swift @@ -67,6 +67,15 @@ public struct AutomaticTextLabelStyle: TextLabelStyle { } } +public struct DefaultSectionHeaderLabelStyle: TextLabelStyle { + public func makeBody(configuration: Configuration) -> some View { + configuration.label + #if os(macOS) + .font(.headline) + #endif + } +} + private struct TextLabelStyleKey: EnvironmentKey { static let defaultValue = MainActor.assumeIsolated { AnyTextLabelStyle(style: AutomaticTextLabelStyle()) @@ -75,7 +84,7 @@ private struct TextLabelStyleKey: EnvironmentKey { private struct SectionHeaderLabelStyleKey: EnvironmentKey { static let defaultValue = MainActor.assumeIsolated { - AnyTextLabelStyle(style: AutomaticTextLabelStyle()) + AnyTextLabelStyle(style: DefaultSectionHeaderLabelStyle()) } }