Added the "invertStyle" flag to the RecordingButtonStyle button style in the Recording package target.

This commit is contained in:
2026-07-03 20:01:06 +02:00
parent a9dd4c9abe
commit f97dac8371
2 changed files with 58 additions and 14 deletions
@@ -2,8 +2,11 @@ import SwiftUI
/// The button style for the controls of a ``RecordingView``. /// The button style for the controls of a ``RecordingView``.
/// ///
/// The style renders the button's label, filled with the background color of the inverted color scheme, over a padded, circular red background, shrinks it /// The style renders the button's label, filled with the background color of the label's color scheme, over a padded, circular red background, shrinks it
/// slightly while pressed, and dims it while disabled. Both the label and its padding scale relative to the current dynamic type size. /// slightly while pressed, and dims it while disabled. Both the label and its padding scale relative to the current dynamic type size.
///
/// By default, the label's color scheme is inverted from the environment's, so its fill contrasts with the surroundings; this behavior can be turned off
/// through the ``init(invertStyle:)`` initializer.
struct RecordingButtonStyle: ButtonStyle { struct RecordingButtonStyle: ButtonStyle {
// MARK: Properties // MARK: Properties
@@ -17,9 +20,23 @@ struct RecordingButtonStyle: ButtonStyle {
/// The padding between the button's label and its background, scaled relative to the current dynamic type size. /// The padding between the button's label and its background, scaled relative to the current dynamic type size.
@ScaledMetric private var padding = Constant.Padding.button @ScaledMetric private var padding = Constant.Padding.button
/// Whether the color scheme of the button's label should be inverted from the environment's.
private let invertStyle: Bool
/// The width and height of the button's label, scaled relative to the current dynamic type size. /// The width and height of the button's label, scaled relative to the current dynamic type size.
@ScaledMetric private var size = Constant.Size.button @ScaledMetric private var size = Constant.Size.button
// MARK: Initializers
/// Creates a recording button style.
///
/// - Parameter invertStyle: Whether the foreground style of the button's label should be inverted from the environment's.
init(
invertStyle: Bool = false
) {
self.invertStyle = invertStyle
}
// MARK: Methods // MARK: Methods
/// Creates the styled body of the button. /// Creates the styled body of the button.
@@ -38,7 +55,7 @@ struct RecordingButtonStyle: ButtonStyle {
.foregroundStyle(.background) .foregroundStyle(.background)
.environment( .environment(
\.colorScheme, \.colorScheme,
colorSchemeInverted colorSchemeLabel
) )
.background( .background(
Circle() Circle()
@@ -60,9 +77,13 @@ private extension RecordingButtonStyle {
// MARK: Computed // MARK: Computed
/// The color scheme opposite to the environment's, under which the label's background fill resolves to the inverted background color. /// The color scheme for the button's label: the opposite of the environment's when ``invertStyle`` is set, the environment's otherwise.
var colorSchemeInverted: ColorScheme { var colorSchemeLabel: ColorScheme {
colorScheme == .dark guard invertStyle else {
return colorScheme
}
return colorScheme == .dark
? .light ? .light
: .dark : .dark
} }
@@ -94,11 +115,21 @@ private extension RecordingButtonStyle {
extension ButtonStyle where Self == RecordingButtonStyle { extension ButtonStyle where Self == RecordingButtonStyle {
/// The button style for the controls of a ``RecordingView``. /// The button style for the controls of a ``RecordingView``, inverting the color scheme of the button's label.
static var recording: RecordingButtonStyle { static var recording: RecordingButtonStyle {
.init() .init()
} }
/// The button style for the controls of a ``RecordingView``.
///
/// - Parameter invertStyle: Whether the color scheme of the button's label should be inverted from the environment's.
/// - Returns: A recording button style with the given color scheme behavior.
static func recording(
invertStyle: Bool
) -> RecordingButtonStyle {
.init(invertStyle: invertStyle)
}
} }
// MARK: - Constants // MARK: - Constants
@@ -146,18 +177,30 @@ private enum Constant {
"Recording button style" "Recording button style"
) { ) {
@Previewable @State var isDisabled: Bool = false @Previewable @State var isDisabled: Bool = false
@Previewable @State var isStyleInverted: Bool = false
Button {} label: { Button {
// Button action closure.
} label: {
Image(.Icon.record) Image(.Icon.record)
.resizable() .resizable()
} }
.buttonStyle(.recording) .buttonStyle(.recording(
invertStyle: isStyleInverted
))
.disabled(isDisabled) .disabled(isDisabled)
.safeAreaInset(edge: .bottom) { .safeAreaInset(edge: .bottom) {
Toggle( VStack {
"Button disabled", Toggle(
isOn: $isDisabled "Style inverted",
) isOn: $isStyleInverted
)
Toggle(
"Button disabled",
isOn: $isDisabled
)
}
.fontWeight(.semibold) .fontWeight(.semibold)
.dynamicTypeSize(.large) .dynamicTypeSize(.large)
.padding() .padding()
@@ -61,13 +61,14 @@ public struct RecordingView: View {
.resizable() .resizable()
} else { } else {
ProgressView() ProgressView()
.dynamicTypeSize(.small)
} }
} }
.disabled(model.isProcessing) .disabled(model.isProcessing)
} }
} }
.buttonStyle(.recording) .buttonStyle(.recording(
invertStyle: !model.isProcessing
))
} }
.onChange( .onChange(
of: model.state, of: model.state,