feat: Adds more buttons and reverse label style

This commit is contained in:
2024-06-04 19:38:40 -04:00
parent dd8f360417
commit a65ac76dde
5 changed files with 130 additions and 16 deletions

View File

@@ -221,9 +221,7 @@ public struct EstimateSettingsFormView: View {
HStack { HStack {
ResetButton { send(.resetButtonTapped) } ResetButton { send(.resetButtonTapped) }
Spacer() Spacer()
Button("Next") { NextButton { send(.nextButtonTapped) }
send(.nextButtonTapped)
}
.disabled(!store.isValid) .disabled(!store.isValid)
} }
.padding(.top) .padding(.top)

View File

@@ -1,5 +1,20 @@
import SwiftUI import SwiftUI
public struct DoneButton: View {
let action: () -> Void
public init(action: @escaping () -> Void) {
self.action = action
}
public var body: some View {
Button(action: action) {
Text("Done")
}
}
}
public struct InfoButton: View { public struct InfoButton: View {
@Environment(\.infoButtonStyle) private var infoButtonStyle @Environment(\.infoButtonStyle) private var infoButtonStyle
@@ -18,6 +33,26 @@ public struct InfoButton: View {
} }
} }
public struct NextButton: View {
@Environment(\.nextButtonStyle) private var nextButtonStyle
let action: () -> Void
public init(action: @escaping () -> Void) {
self.action = action
}
public var body: some View {
Button {
action()
} label: {
Label("Next", systemImage: "chevron.right")
}
.buttonStyle(nextButtonStyle)
}
}
public struct ResetButton: View { public struct ResetButton: View {
@Environment(\.resetButtonStyle) private var resetButtonStyle @Environment(\.resetButtonStyle) private var resetButtonStyle
@@ -48,6 +83,9 @@ struct ButtonPreview: View {
InfoButton { InfoButton {
lastButtonPressed = "Info button pressed." lastButtonPressed = "Info button pressed."
} }
NextButton {
lastButtonPressed = "Next button pressed."
}
ResetButton { ResetButton {
lastButtonPressed = "Reset button pressed." lastButtonPressed = "Reset button pressed."
} }

View File

@@ -54,9 +54,7 @@ public struct InfoView: View {
.padding(.horizontal) .padding(.horizontal)
.navigationBarBackButtonHidden() .navigationBarBackButtonHidden()
.toolbar { .toolbar {
Button("Done") { DoneButton { store.send(.dismissButtonTapped) }
store.send(.dismissButtonTapped)
}
} }
} }
} }

View File

@@ -3,9 +3,13 @@ import SwiftUI
/// A name space for info button styles. /// A name space for info button styles.
public enum InfoButtonType { } public enum InfoButtonType { }
/// A name space for info button styles.
public enum NextButtonType { }
/// A name space for info button styles. /// A name space for info button styles.
public enum ResetButtonType { } public enum ResetButtonType { }
/// A type erased button style, used to style buttons in a namespace.
public struct AnyButtonStyle<ButtonType>: ButtonStyle { public struct AnyButtonStyle<ButtonType>: ButtonStyle {
private let _makeBody: (Configuration) -> AnyView private let _makeBody: (Configuration) -> AnyView
@@ -20,6 +24,7 @@ public struct AnyButtonStyle<ButtonType>: ButtonStyle {
} }
} }
/// A type erased primitive button style, used to style buttons in a namespace.
public struct AnyPrimitiveButtonStyle<ButtonType>: PrimitiveButtonStyle { public struct AnyPrimitiveButtonStyle<ButtonType>: PrimitiveButtonStyle {
private let _makeBody: (Configuration) -> AnyView private let _makeBody: (Configuration) -> AnyView
@@ -34,36 +39,62 @@ public struct AnyPrimitiveButtonStyle<ButtonType>: PrimitiveButtonStyle {
} }
} }
/// The default info button style.
public struct DefaultInfoButtonStyle<Style: LabelStyle>: ButtonStyle { public struct DefaultInfoButtonStyle<Style: LabelStyle>: ButtonStyle {
let color: Color let color: Color
let font: Font
let labelStyle: Style let labelStyle: Style
init( init(
color: Color = .accentColor, color: Color = .accentColor,
font: Font = .title2,
labelStyle: Style labelStyle: Style
) { ) {
self.color = color self.color = color
self.font = font
self.labelStyle = labelStyle self.labelStyle = labelStyle
} }
public func makeBody(configuration: Configuration) -> some View { public func makeBody(configuration: Configuration) -> some View {
configuration.label configuration.label
.font(.title2) .font(font)
.foregroundStyle(color.opacity(configuration.isPressed ? 0.5 : 1)) .foregroundStyle(color.opacity(configuration.isPressed ? 0.5 : 1))
.labelStyle(labelStyle) .labelStyle(labelStyle)
.scaleEffect(configuration.isPressed ? 0.8 : 1) .scaleEffect(configuration.isPressed ? 0.8 : 1)
} }
} }
public struct DefaultNextButtonStyle<ButtonStyle: PrimitiveButtonStyle, Label: LabelStyle>: PrimitiveButtonStyle {
let buttonStyle: ButtonStyle
let labelStyle: Label
public init(buttonStyle: ButtonStyle, labelStyle: Label) {
self.buttonStyle = buttonStyle
self.labelStyle = labelStyle
}
public func makeBody(configuration: Configuration) -> some View {
Button(role: configuration.role, action: configuration.trigger) {
configuration.label
}
.labelStyle(labelStyle)
.buttonStyle(buttonStyle)
}
}
extension DefaultNextButtonStyle where ButtonStyle == BorderedProminentButtonStyle, Label == ReverseLabelStyle {
init() {
self.init(buttonStyle: .borderedProminent, labelStyle: .reverse())
}
}
extension AnyButtonStyle where ButtonType == InfoButtonType { extension AnyButtonStyle where ButtonType == InfoButtonType {
public static var `default`: Self { public static var `default`: Self {
.init(DefaultInfoButtonStyle<IconOnlyLabelStyle>(labelStyle: .iconOnly)) .init(DefaultInfoButtonStyle<IconOnlyLabelStyle>(labelStyle: .iconOnly))
} }
public static func `default`<S: LabelStyle>(color: Color, labelStyle: S) -> Self { public static func `default`<S: LabelStyle>(color: Color, font: Font, labelStyle: S) -> Self {
.init(DefaultInfoButtonStyle<S>(color: color, labelStyle: labelStyle)) .init(DefaultInfoButtonStyle<S>(color: color, font: font, labelStyle: labelStyle))
} }
} }
@@ -71,17 +102,28 @@ private struct InfoButtonStyleKey: EnvironmentKey {
static var defaultValue = AnyButtonStyle<InfoButtonType>.default static var defaultValue = AnyButtonStyle<InfoButtonType>.default
} }
private struct NextButtonStyleKey: EnvironmentKey {
static var defaultValue = AnyPrimitiveButtonStyle<NextButtonType>(
DefaultNextButtonStyle<BorderedProminentButtonStyle, ReverseLabelStyle>()
)
}
private struct ResetButtonStyleKey: EnvironmentKey { private struct ResetButtonStyleKey: EnvironmentKey {
static var defaultValue = AnyPrimitiveButtonStyle<ResetButtonType>(BorderedProminentButtonStyle()) static var defaultValue = AnyPrimitiveButtonStyle<ResetButtonType>(.borderedProminent)
} }
extension EnvironmentValues { extension EnvironmentValues {
public var infoButtonStyle: AnyButtonStyle<InfoButtonType> { var infoButtonStyle: AnyButtonStyle<InfoButtonType> {
get { self[InfoButtonStyleKey.self] } get { self[InfoButtonStyleKey.self] }
set { self[InfoButtonStyleKey.self] = newValue } set { self[InfoButtonStyleKey.self] = newValue }
} }
public var resetButtonStyle: AnyPrimitiveButtonStyle<ResetButtonType> { var nextButtonStyle: AnyPrimitiveButtonStyle<NextButtonType> {
get { self[NextButtonStyleKey.self] }
set { self[NextButtonStyleKey.self] = newValue }
}
var resetButtonStyle: AnyPrimitiveButtonStyle<ResetButtonType> {
get { self[ResetButtonStyleKey.self] } get { self[ResetButtonStyleKey.self] }
set { self[ResetButtonStyleKey.self] = newValue } set { self[ResetButtonStyleKey.self] = newValue }
} }
@@ -89,18 +131,32 @@ extension EnvironmentValues {
extension View { extension View {
/// Sets the button style for the ``InfoButton`` type.
public func infoButtonStyle(_ style: AnyButtonStyle<InfoButtonType>) -> some View { public func infoButtonStyle(_ style: AnyButtonStyle<InfoButtonType>) -> some View {
environment(\.infoButtonStyle, style) environment(\.infoButtonStyle, style)
} }
/// Sets the button style for the ``InfoButton`` type.
public func infoButtonStyle<S: ButtonStyle>(_ style: S) -> some View { public func infoButtonStyle<S: ButtonStyle>(_ style: S) -> some View {
infoButtonStyle(AnyButtonStyle(style)) infoButtonStyle(AnyButtonStyle(style))
} }
/// Sets the button style for the ``NextButton`` type.
public func nextButtonStyle(_ style: AnyPrimitiveButtonStyle<NextButtonType>) -> some View {
environment(\.nextButtonStyle, style)
}
/// Sets the button style for the ``NextButton`` type.
public func nextButtonStyle<S: PrimitiveButtonStyle>(_ style: S) -> some View {
nextButtonStyle(AnyPrimitiveButtonStyle(style))
}
/// Sets the button style for the ``ResetButton`` type.
public func resetButtonStyle(_ style: AnyPrimitiveButtonStyle<ResetButtonType>) -> some View { public func resetButtonStyle(_ style: AnyPrimitiveButtonStyle<ResetButtonType>) -> some View {
environment(\.resetButtonStyle, style) environment(\.resetButtonStyle, style)
} }
/// Sets the button style for the ``ResetButton`` type.
public func resetButtonStyle<S: PrimitiveButtonStyle>(_ style: S) -> some View { public func resetButtonStyle<S: PrimitiveButtonStyle>(_ style: S) -> some View {
resetButtonStyle(AnyPrimitiveButtonStyle(style)) resetButtonStyle(AnyPrimitiveButtonStyle(style))
} }

View File

@@ -0,0 +1,24 @@
import SwiftUI
/// A label style that puts the title first and icon second.
public struct ReverseLabelStyle: LabelStyle {
let spacing: CGFloat
public init(spacing: CGFloat = 3) {
self.spacing = spacing
}
public func makeBody(configuration: Configuration) -> some View {
HStack(spacing: spacing) {
configuration.title
configuration.icon
}
}
}
extension LabelStyle where Self == ReverseLabelStyle {
public static func reverse(spacing: CGFloat = 3) -> Self {
.init(spacing: spacing)
}
}