feat: Adding improvements to pressure estimations feature.
This commit is contained in:
@@ -304,9 +304,14 @@ public struct EquipmentMeasurementFormView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
Grid(alignment: .leading, horizontalSpacing: 60) {
|
Grid(alignment: .leading, horizontalSpacing: 80) {
|
||||||
gridRow(for: .airflow)
|
gridRow(for: .airflow)
|
||||||
}
|
}
|
||||||
|
} header: {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Text(store.sharedSettings.equipmentMetadata.coolingCapacity.description)
|
||||||
|
}
|
||||||
} footer: {
|
} footer: {
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|||||||
@@ -355,45 +355,6 @@ fileprivate enum RatingsField: String, Hashable, CaseIterable, Identifiable {
|
|||||||
var prompt: String { "\(label) Pressure" }
|
var prompt: String { "\(label) Pressure" }
|
||||||
}
|
}
|
||||||
|
|
||||||
//fileprivate extension Store where State == EquipmentSettingsForm.State {
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// func label(for ratingsField: RatingsField) -> String {
|
|
||||||
// self.label(for: ratingsField.field)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func prompt(for ratingsField: RatingsField) -> String {
|
|
||||||
// self.prompt(for: ratingsField.field)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func label(for field: EquipmentSettingsForm.State.Field) -> String {
|
|
||||||
// switch field {
|
|
||||||
// case .heatingCapacity:
|
|
||||||
// return "Heating"
|
|
||||||
// case .minimumStaticPressure:
|
|
||||||
// return "Minimum"
|
|
||||||
// case .maximumStaticPressure:
|
|
||||||
// return "Maximum"
|
|
||||||
// case .ratedStaticPressure:
|
|
||||||
// return "Rated"
|
|
||||||
// case .manufacturersIncludedFilterPressureDrop:
|
|
||||||
// return "Filter Drop"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// func prompt(for field: EquipmentSettingsForm.State.Field) -> String {
|
|
||||||
// switch field {
|
|
||||||
// case .heatingCapacity:
|
|
||||||
// return "Heating Capacity"
|
|
||||||
// case .minimumStaticPressure, .maximumStaticPressure, .ratedStaticPressure:
|
|
||||||
// return "\(label(for: field)) Pressure"
|
|
||||||
// case .manufacturersIncludedFilterPressureDrop:
|
|
||||||
// return label(for: field)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
EquipmentSettingsFormView(
|
EquipmentSettingsFormView(
|
||||||
|
|||||||
@@ -3,35 +3,82 @@ import SharedModels
|
|||||||
import Styleguide
|
import Styleguide
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
#warning("Use shared settings, don't display filter pressure drop if current flagged measurement pressure drop is not set.")
|
|
||||||
@Reducer
|
@Reducer
|
||||||
public struct EstimationForm {
|
public struct EstimationForm {
|
||||||
public init() { }
|
public init() { }
|
||||||
|
|
||||||
@ObservableState
|
@ObservableState
|
||||||
public struct State: Equatable, Sendable {
|
public struct State: Equatable, Sendable {
|
||||||
public var cfmPerTon: Int
|
@SharedReader public var existingMeasurement: EquipmentMeasurement?
|
||||||
|
|
||||||
|
public let id: SharedPressureEstimationState.FlaggedEstimationContainer.ID?
|
||||||
|
public var airflowSelection: AirflowSelection
|
||||||
|
public var cfmTextField: Int?
|
||||||
public var coolingCapacity: EquipmentMetadata.CoolingCapacity
|
public var coolingCapacity: EquipmentMetadata.CoolingCapacity
|
||||||
public var filterPressureDrop: Double?
|
public var filterPressureDrop: Double?
|
||||||
public var name: String
|
public var name: String
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
cfmPerTon: Int = 350,
|
id: SharedPressureEstimationState.FlaggedEstimationContainer.ID? = nil,
|
||||||
|
existingMeasurement: SharedReader<EquipmentMeasurement?>,
|
||||||
|
airflowSelection: AirflowSelection = .cfmPerTon,
|
||||||
|
cfmTextField: Int? = nil,
|
||||||
coolingCapacity: EquipmentMetadata.CoolingCapacity = .default,
|
coolingCapacity: EquipmentMetadata.CoolingCapacity = .default,
|
||||||
filterPressureDrop: Double? = nil,
|
filterPressureDrop: Double? = nil,
|
||||||
name: String = ""
|
name: String = ""
|
||||||
) {
|
) {
|
||||||
self.cfmPerTon = cfmPerTon
|
self.id = id
|
||||||
|
self._existingMeasurement = existingMeasurement
|
||||||
|
self.airflowSelection = airflowSelection
|
||||||
|
self.cfmTextField = cfmTextField
|
||||||
self.filterPressureDrop = filterPressureDrop
|
self.filterPressureDrop = filterPressureDrop
|
||||||
self.coolingCapacity = coolingCapacity
|
self.coolingCapacity = coolingCapacity
|
||||||
self.name = name
|
self.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
public var airflow: Double {
|
public var airflow: Double {
|
||||||
Double(cfmPerTon) * coolingCapacity.rawValue
|
let cfmTextField = Double(self.cfmTextField ?? 0)
|
||||||
|
switch airflowSelection {
|
||||||
|
case .cfmPerTon:
|
||||||
|
return Double(cfmTextField) * coolingCapacity.rawValue
|
||||||
|
case .cfm:
|
||||||
|
return Double(cfmTextField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var isValid: Bool {
|
||||||
|
!name.isEmpty
|
||||||
|
&& cfmTextField != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: Keep in display order of the picker.
|
||||||
|
public enum AirflowSelection: Hashable, CaseIterable, Identifiable, CustomStringConvertible {
|
||||||
|
case cfmPerTon
|
||||||
|
case cfm
|
||||||
|
|
||||||
|
init(
|
||||||
|
_ container: SharedPressureEstimationState.FlaggedEstimationContainer.EstimationState.CFMContainer
|
||||||
|
) {
|
||||||
|
switch container {
|
||||||
|
case .cfm:
|
||||||
|
self = .cfm
|
||||||
|
case .cfmPerTon:
|
||||||
|
self = .cfmPerTon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var id: Self { self }
|
||||||
|
|
||||||
|
public var description: String {
|
||||||
|
switch self {
|
||||||
|
case .cfm:
|
||||||
|
return "CFM"
|
||||||
|
case .cfmPerTon:
|
||||||
|
return "CFM / Ton"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var isValid: Bool { !name.isEmpty }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Action: BindableAction {
|
public enum Action: BindableAction {
|
||||||
@@ -68,7 +115,15 @@ public struct EstimationFormView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Section("Airflow") {
|
Section("Airflow") {
|
||||||
|
VStack {
|
||||||
|
CaseIterablePicker(
|
||||||
|
"Airflow Type",
|
||||||
|
selection: $store.airflowSelection
|
||||||
|
)
|
||||||
|
.pickerStyle(.segmented)
|
||||||
|
|
||||||
Grid(alignment: .leading, horizontalSpacing: 40) {
|
Grid(alignment: .leading, horizontalSpacing: 40) {
|
||||||
|
if store.airflowSelection == .cfmPerTon {
|
||||||
GridRow {
|
GridRow {
|
||||||
HStack {
|
HStack {
|
||||||
TextLabel("Capacity")
|
TextLabel("Capacity")
|
||||||
@@ -79,13 +134,14 @@ public struct EstimationFormView: View {
|
|||||||
}
|
}
|
||||||
.gridCellColumns(2)
|
.gridCellColumns(2)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
GridRow {
|
GridRow {
|
||||||
HStack {
|
HStack {
|
||||||
TextLabel("CFM / Ton")
|
TextLabel(store.airflowSelection.description)
|
||||||
Spacer()
|
Spacer()
|
||||||
TextField(
|
TextField(
|
||||||
"CFM / Ton",
|
"CFM / Ton",
|
||||||
value: $store.cfmPerTon,
|
value: $store.cfmTextField,
|
||||||
format: .number,
|
format: .number,
|
||||||
prompt: Text("CFM")
|
prompt: Text("CFM")
|
||||||
)
|
)
|
||||||
@@ -96,7 +152,11 @@ public struct EstimationFormView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let existingsMeasurement = store.existingMeasurement,
|
||||||
|
existingsMeasurement.hasFilterDrop
|
||||||
|
{
|
||||||
Section("Filter Pressure Drop") {
|
Section("Filter Pressure Drop") {
|
||||||
HStack {
|
HStack {
|
||||||
TextLabel("Pressure Drop")
|
TextLabel("Pressure Drop")
|
||||||
@@ -112,15 +172,34 @@ public struct EstimationFormView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.textLabelStyle(.boldSecondary)
|
.textLabelStyle(.boldSecondary)
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileprivate extension EquipmentMeasurement {
|
||||||
|
|
||||||
|
var hasFilterDrop: Bool {
|
||||||
|
switch self {
|
||||||
|
case let .airHandler(airHandler):
|
||||||
|
return airHandler.postFilterPressure > 0
|
||||||
|
case let .furnaceAndCoil(furnace):
|
||||||
|
return furnace.postFilterPressure > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
EstimationFormView(
|
EstimationFormView(
|
||||||
store: Store(initialState: EstimationForm.State()) {
|
store: Store(
|
||||||
|
initialState: EstimationForm.State(
|
||||||
|
existingMeasurement: SharedReader(
|
||||||
|
Shared(EquipmentMeasurement.mock(type: .airHandler))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
EstimationForm()
|
EstimationForm()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -57,8 +57,9 @@ public struct FlaggedMeasurementsList: Sendable {
|
|||||||
@CasePathable
|
@CasePathable
|
||||||
public enum View {
|
public enum View {
|
||||||
case addButtonTapped
|
case addButtonTapped
|
||||||
|
case deleteEstimationButtonTapped(id: SharedPressureEstimationState.FlaggedEstimationContainer.ID)
|
||||||
case destination(DestinationAction)
|
case destination(DestinationAction)
|
||||||
case editButtonTapped(id: SharedPressureEstimationState.FlaggedMeasurementContainer.ID)
|
case editButtonTapped(id: SharedPressureEstimationState.FlaggedEstimationContainer.ID)
|
||||||
case onAppear
|
case onAppear
|
||||||
|
|
||||||
@CasePathable
|
@CasePathable
|
||||||
@@ -107,10 +108,15 @@ public struct FlaggedMeasurementsList: Sendable {
|
|||||||
|
|
||||||
case .addButtonTapped:
|
case .addButtonTapped:
|
||||||
state.destination = .estimationForm(.init(
|
state.destination = .estimationForm(.init(
|
||||||
|
existingMeasurement: state.$sharedSettings.equipmentMeasurement,
|
||||||
coolingCapacity: state.sharedSettings.equipmentMetadata.coolingCapacity
|
coolingCapacity: state.sharedSettings.equipmentMetadata.coolingCapacity
|
||||||
))
|
))
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
|
case let .deleteEstimationButtonTapped(id: id):
|
||||||
|
state.sharedSettings.flaggedEstimations.remove(id: id)
|
||||||
|
return .none
|
||||||
|
|
||||||
case let .destination(action):
|
case let .destination(action):
|
||||||
switch action {
|
switch action {
|
||||||
case .cancelButtonTapped:
|
case .cancelButtonTapped:
|
||||||
@@ -237,7 +243,16 @@ public struct FlaggedMeasurementListView: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Text(measurement.name)
|
Text(measurement.name)
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("Edit") { send(.editButtonTapped(id: measurement.id)) }
|
Menu {
|
||||||
|
EditButton { send(.editButtonTapped(id: measurement.id)) }
|
||||||
|
DeleteButton { send(.deleteEstimationButtonTapped(id: measurement.id)) }
|
||||||
|
} label: {
|
||||||
|
Label("Actions", systemImage: "list.dash")
|
||||||
|
} primaryAction: {
|
||||||
|
send(.editButtonTapped(id: measurement.id))
|
||||||
|
}
|
||||||
|
.labelStyle(.iconOnly)
|
||||||
|
.menuStyle(ButtonMenuStyle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,7 +297,7 @@ public struct FlaggedMeasurementListView: View {
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|
||||||
private let budgets = BudgetedPercentEnvelope(equipmentType: .airHandler, fanType: .constantSpeed)
|
private let budgets = BudgetedPercentEnvelope(equipmentType: .airHandler, fanType: .constantSpeed)
|
||||||
private let flaggedMeasurements = IdentifiedArrayOf<SharedPressureEstimationState.FlaggedMeasurementContainer>(
|
private let flaggedMeasurements = IdentifiedArrayOf<SharedPressureEstimationState.FlaggedEstimationContainer>(
|
||||||
uniqueElements: [
|
uniqueElements: [
|
||||||
.init(
|
.init(
|
||||||
id: UUID(0),
|
id: UUID(0),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public struct SharedPressureEstimationState: Equatable, Sendable {
|
|||||||
public var equipmentMeasurement: EquipmentMeasurement?
|
public var equipmentMeasurement: EquipmentMeasurement?
|
||||||
public var equipmentMetadata: EquipmentMetadata
|
public var equipmentMetadata: EquipmentMetadata
|
||||||
public var flaggedEquipmentMeasurement: EquipmentMeasurement.FlaggedMeasurement?
|
public var flaggedEquipmentMeasurement: EquipmentMeasurement.FlaggedMeasurement?
|
||||||
public var flaggedEstimations: IdentifiedArrayOf<FlaggedMeasurementContainer>
|
public var flaggedEstimations: IdentifiedArrayOf<FlaggedEstimationContainer>
|
||||||
public var heatingCapacity: Double?
|
public var heatingCapacity: Double?
|
||||||
public var manufacturersIncludedFilterPressureDrop: Double?
|
public var manufacturersIncludedFilterPressureDrop: Double?
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ public struct SharedPressureEstimationState: Equatable, Sendable {
|
|||||||
equipmentMeasurement: EquipmentMeasurement? = nil,
|
equipmentMeasurement: EquipmentMeasurement? = nil,
|
||||||
equipmentMetadata: EquipmentMetadata = .init(),
|
equipmentMetadata: EquipmentMetadata = .init(),
|
||||||
flaggedEquipmentMeasurement: EquipmentMeasurement.FlaggedMeasurement? = nil,
|
flaggedEquipmentMeasurement: EquipmentMeasurement.FlaggedMeasurement? = nil,
|
||||||
flaggedEstimations: IdentifiedArrayOf<FlaggedMeasurementContainer> = [],
|
flaggedEstimations: IdentifiedArrayOf<FlaggedEstimationContainer> = [],
|
||||||
heatingCapacity: Double? = nil,
|
heatingCapacity: Double? = nil,
|
||||||
manufacturersIncludedFilterPressureDrop: Double? = nil
|
manufacturersIncludedFilterPressureDrop: Double? = nil
|
||||||
) {
|
) {
|
||||||
@@ -36,7 +36,8 @@ public struct SharedPressureEstimationState: Equatable, Sendable {
|
|||||||
set { equipmentMetadata[keyPath: keyPath] = newValue }
|
set { equipmentMetadata[keyPath: keyPath] = newValue }
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct FlaggedMeasurementContainer: Equatable, Identifiable, Sendable {
|
#warning("Needs to hold onto estimation state, so it can be editable")
|
||||||
|
public struct FlaggedEstimationContainer: Equatable, Identifiable, Sendable {
|
||||||
public let id: UUID
|
public let id: UUID
|
||||||
public var flaggedMeasurement: EquipmentMeasurement.FlaggedMeasurement
|
public var flaggedMeasurement: EquipmentMeasurement.FlaggedMeasurement
|
||||||
public var name: String
|
public var name: String
|
||||||
@@ -50,6 +51,44 @@ public struct SharedPressureEstimationState: Equatable, Sendable {
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.flaggedMeasurement = flaggedMeasurement
|
self.flaggedMeasurement = flaggedMeasurement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct EstimationState: Equatable, Sendable {
|
||||||
|
public var cfm: CFMContainer
|
||||||
|
public var filterPressureDrop: Double?
|
||||||
|
public var name: String?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
cfm: CFMContainer,
|
||||||
|
filterPressureDrop: Double? = nil,
|
||||||
|
name: String? = nil
|
||||||
|
) {
|
||||||
|
self.cfm = cfm
|
||||||
|
self.filterPressureDrop = filterPressureDrop
|
||||||
|
self.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayName: String {
|
||||||
|
guard let name else {
|
||||||
|
return "@\(Int(cfm.airflow)) CFM"
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CFMContainer: Equatable, Sendable {
|
||||||
|
case cfm(Int)
|
||||||
|
case cfmPerTon(Int, EquipmentMetadata.CoolingCapacity)
|
||||||
|
|
||||||
|
var airflow: Double {
|
||||||
|
switch self {
|
||||||
|
case let .cfm(cfm):
|
||||||
|
return Double(cfm)
|
||||||
|
case let .cfmPerTon(cfmPerTon, capacity):
|
||||||
|
return Double(cfmPerTon) * capacity.rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
public struct DeleteButton: View {
|
||||||
|
let action: () -> Void
|
||||||
|
|
||||||
|
public init(action: @escaping () -> Void) {
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some View {
|
||||||
|
Button(role: .destructive, action: action) {
|
||||||
|
Label("Delete", systemImage: "trash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct DoneButton: View {
|
public struct DoneButton: View {
|
||||||
|
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
@@ -15,6 +29,24 @@ public struct DoneButton: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct EditButton: View {
|
||||||
|
|
||||||
|
@Environment(\.editButtonStyle) private var style
|
||||||
|
|
||||||
|
let action: () -> Void
|
||||||
|
|
||||||
|
public init(action: @escaping () -> Void) {
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some View {
|
||||||
|
Button(action: action) {
|
||||||
|
Label("Edit", systemImage: "square.and.pencil")
|
||||||
|
}
|
||||||
|
.buttonStyle(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct InfoButton: View {
|
public struct InfoButton: View {
|
||||||
|
|
||||||
@Environment(\.infoButtonStyle) private var infoButtonStyle
|
@Environment(\.infoButtonStyle) private var infoButtonStyle
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
#warning("Remove button types and just make styles stand-alone")
|
||||||
|
|
||||||
|
/// A name space for edit button styles.
|
||||||
|
public enum EditButtonType { }
|
||||||
|
|
||||||
/// A name space for info button styles.
|
/// A name space for info button styles.
|
||||||
public enum InfoButtonType { }
|
public enum InfoButtonType { }
|
||||||
|
|
||||||
@@ -119,6 +124,10 @@ private struct ResetButtonStyleKey: EnvironmentKey {
|
|||||||
extension EnvironmentValues {
|
extension EnvironmentValues {
|
||||||
// @Entry var infoButtonStyle: AnyButtonStyle<InfoButtonType> = AnyButtonStyle.default
|
// @Entry var infoButtonStyle: AnyButtonStyle<InfoButtonType> = AnyButtonStyle.default
|
||||||
|
|
||||||
|
@Entry var editButtonStyle = MainActor.assumeIsolated {
|
||||||
|
AnyPrimitiveButtonStyle<EditButtonType>(DefaultInfoButtonStyle(labelStyle: .automatic))
|
||||||
|
}
|
||||||
|
|
||||||
var infoButtonStyle: AnyPrimitiveButtonStyle<InfoButtonType> {
|
var infoButtonStyle: AnyPrimitiveButtonStyle<InfoButtonType> {
|
||||||
get { self[InfoButtonStyleKey.self] }
|
get { self[InfoButtonStyleKey.self] }
|
||||||
set { self[InfoButtonStyleKey.self] = newValue }
|
set { self[InfoButtonStyleKey.self] = newValue }
|
||||||
@@ -137,6 +146,16 @@ extension EnvironmentValues {
|
|||||||
|
|
||||||
extension View {
|
extension View {
|
||||||
|
|
||||||
|
/// Sets the button style for the ``EditButton`` type.
|
||||||
|
public func editButtonStyle(_ style: AnyPrimitiveButtonStyle<EditButtonType>) -> some View {
|
||||||
|
environment(\.editButtonStyle, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the button style for the ``EditButton`` type.
|
||||||
|
public func editButtonStyle<S: PrimitiveButtonStyle>(_ style: S) -> some View {
|
||||||
|
editButtonStyle(AnyPrimitiveButtonStyle(style))
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the button style for the ``InfoButton`` type.
|
/// Sets the button style for the ``InfoButton`` type.
|
||||||
public func infoButtonStyle(_ style: AnyPrimitiveButtonStyle<InfoButtonType>) -> some View {
|
public func infoButtonStyle(_ style: AnyPrimitiveButtonStyle<InfoButtonType>) -> some View {
|
||||||
environment(\.infoButtonStyle, style)
|
environment(\.infoButtonStyle, style)
|
||||||
|
|||||||
Reference in New Issue
Block a user