feat: Styles views for macos

This commit is contained in:
2024-06-17 09:30:47 -04:00
parent 50e80d39eb
commit bd758fac90
7 changed files with 115 additions and 16 deletions

View File

@@ -284,9 +284,10 @@ public struct EquipmentMeasurementFormView: View {
if store.allowEquipmentTypeSelection { if store.allowEquipmentTypeSelection {
Section { Section {
} header: { } header: {
Text("Equipment Type") SectionHeaderLabel("Equipment Type")
} footer: { } footer: {
EquipmentTypePicker(selection: $store.equipmentType) EquipmentTypePicker(selection: $store.equipmentType)
.dynamicBottomPadding()
.pickerStyle(.segmented) .pickerStyle(.segmented)
.labelsHidden() .labelsHidden()
} }
@@ -295,9 +296,10 @@ public struct EquipmentMeasurementFormView: View {
Grid(alignment: .leading, horizontalSpacing: 40) { Grid(alignment: .leading, horizontalSpacing: 40) {
ForEach(store.pressureFields, content: gridRow(for:)) ForEach(store.pressureFields, content: gridRow(for:))
} }
.dynamicBottomPadding()
} header: { } header: {
HStack { HStack {
Text("Static Measurements") SectionHeaderLabel("Static Measurements")
Spacer() Spacer()
InfoButton { send(.infoButtonTapped) } InfoButton { send(.infoButtonTapped) }
} }
@@ -310,7 +312,7 @@ public struct EquipmentMeasurementFormView: View {
} header: { } header: {
HStack { HStack {
Spacer() Spacer()
Text(store.sharedSettings.equipmentMetadata.coolingCapacity.description) SectionHeaderLabel(store.sharedSettings.equipmentMetadata.coolingCapacity.description)
} }
} footer: { } footer: {
HStack { HStack {
@@ -348,7 +350,8 @@ public struct EquipmentMeasurementFormView: View {
} }
private func gridRow(for field: EquipmentMeasurementForm.State.Field) -> some 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) textField(for: field)
} }
} }

View File

@@ -133,18 +133,19 @@ public struct EquipmentSettingsFormView: View {
Form { Form {
Section { Section {
EquipmentTypePicker(selection: $store.equipmentType) EquipmentTypePicker(selection: $store.equipmentType)
.dynamicBottomPadding()
.pickerStyle(.segmented) .pickerStyle(.segmented)
EmptyView()
} header: { } header: {
Text("Equipment Type") SectionHeaderLabel("Equipment Type")
} }
.listRowBackground(Color.clear) .listRowBackground(Color.clear)
Section { Section {
FanTypePicker(selection: $store.sharedSettings.fanType) FanTypePicker(selection: $store.sharedSettings.fanType)
.dynamicBottomPadding()
.pickerStyle(.segmented) .pickerStyle(.segmented)
} header: { } header: {
Text("Fan Type") SectionHeaderLabel("Fan Type")
} }
.listRowBackground(Color.clear) .listRowBackground(Color.clear)
@@ -175,11 +176,13 @@ public struct EquipmentSettingsFormView: View {
} }
} }
} }
.dynamicBottomPadding()
// .applyPadding()
} header: { } header: {
if store.equipmentType == .airHandler { if store.equipmentType == .airHandler {
EmptyView() EmptyView()
} else { } else {
Text("Capacities") SectionHeaderLabel("Capacities")
} }
} }
@@ -187,6 +190,7 @@ public struct EquipmentSettingsFormView: View {
Grid(alignment: .leading, horizontalSpacing: 40) { Grid(alignment: .leading, horizontalSpacing: 40) {
ForEach(RatingsField.allCases, content: ratingsRow(for:)) ForEach(RatingsField.allCases, content: ratingsRow(for:))
} }
.dynamicBottomPadding()
.labeledContentStyle(.gridRow) .labeledContentStyle(.gridRow)
} header: { } header: {
header("Rated Static Pressure", infoView: .ratedStaticPressures) header("Rated Static Pressure", infoView: .ratedStaticPressures)
@@ -262,7 +266,7 @@ public struct EquipmentSettingsFormView: View {
label: @escaping () -> Label label: @escaping () -> Label
) -> some View { ) -> some View {
HStack { HStack {
label() SectionHeaderLabel { label() }
Spacer() Spacer()
InfoButton { send(.infoButtonTapped(infoView)) } 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 { fileprivate struct BudgetFlagViewStyle: FlaggedViewStyle {
func makeBody(configuration: Configuration) -> some View { func makeBody(configuration: Configuration) -> some View {

View File

@@ -108,9 +108,11 @@ public struct PressureEstimationsView: View {
} }
public var body: some View { public var body: some View {
EquipmentSettingsFormView( ScrollView {
store: store.scope(state: \.equipmentSettings, action: \.equipmentSettings) EquipmentSettingsFormView(
) store: store.scope(state: \.equipmentSettings, action: \.equipmentSettings)
)
}
.navigationTitle("Equipment Settings") .navigationTitle("Equipment Settings")
.toolbar { .toolbar {
NextButton { send(.nextButtonTapped) } NextButton { send(.nextButtonTapped) }
@@ -123,10 +125,11 @@ public struct PressureEstimationsView: View {
action: \.destination.equipmentMeasurements action: \.destination.equipmentMeasurements
) )
) { measurementStore in ) { measurementStore in
EquipmentMeasurementFormView(store: measurementStore) ScrollView {
.navigationTitle("Existing Measurements") EquipmentMeasurementFormView(store: measurementStore)
.navigationTitle("Existing Measurements")
}
} }
} }
} }

View File

@@ -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
}
}

View File

@@ -0,0 +1,50 @@
import SwiftUI
public struct SectionHeaderLabel<Content: View>: 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<S>(_ 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
}

View File

@@ -6,6 +6,7 @@ extension View {
public func applyFormStyle() -> some View { public func applyFormStyle() -> some View {
self self
.labelsHidden() .labelsHidden()
// .formStyle(.grouped)
.textLabelStyle(.boldSecondary) .textLabelStyle(.boldSecondary)
.textFieldStyle(.roundedBorder) .textFieldStyle(.roundedBorder)
#if os(macOS) #if os(macOS)

View File

@@ -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 { private struct TextLabelStyleKey: EnvironmentKey {
static let defaultValue = MainActor.assumeIsolated { static let defaultValue = MainActor.assumeIsolated {
AnyTextLabelStyle(style: AutomaticTextLabelStyle()) AnyTextLabelStyle(style: AutomaticTextLabelStyle())
@@ -75,7 +84,7 @@ private struct TextLabelStyleKey: EnvironmentKey {
private struct SectionHeaderLabelStyleKey: EnvironmentKey { private struct SectionHeaderLabelStyleKey: EnvironmentKey {
static let defaultValue = MainActor.assumeIsolated { static let defaultValue = MainActor.assumeIsolated {
AnyTextLabelStyle(style: AutomaticTextLabelStyle()) AnyTextLabelStyle(style: DefaultSectionHeaderLabelStyle())
} }
} }