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 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.
///
/// 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 {
// 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.
@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.
@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
/// Creates the styled body of the button.
@@ -38,7 +55,7 @@ struct RecordingButtonStyle: ButtonStyle {
.foregroundStyle(.background)
.environment(
\.colorScheme,
colorSchemeInverted
colorSchemeLabel
)
.background(
Circle()
@@ -60,9 +77,13 @@ private extension RecordingButtonStyle {
// MARK: Computed
/// The color scheme opposite to the environment's, under which the label's background fill resolves to the inverted background color.
var colorSchemeInverted: ColorScheme {
colorScheme == .dark
/// The color scheme for the button's label: the opposite of the environment's when ``invertStyle`` is set, the environment's otherwise.
var colorSchemeLabel: ColorScheme {
guard invertStyle else {
return colorScheme
}
return colorScheme == .dark
? .light
: .dark
}
@@ -94,11 +115,21 @@ private extension 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 {
.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
@@ -146,18 +177,30 @@ private enum Constant {
"Recording button style"
) {
@Previewable @State var isDisabled: Bool = false
@Previewable @State var isStyleInverted: Bool = false
Button {} label: {
Button {
// Button action closure.
} label: {
Image(.Icon.record)
.resizable()
}
.buttonStyle(.recording)
.buttonStyle(.recording(
invertStyle: isStyleInverted
))
.disabled(isDisabled)
.safeAreaInset(edge: .bottom) {
Toggle(
"Button disabled",
isOn: $isDisabled
)
VStack {
Toggle(
"Style inverted",
isOn: $isStyleInverted
)
Toggle(
"Button disabled",
isOn: $isDisabled
)
}
.fontWeight(.semibold)
.dynamicTypeSize(.large)
.padding()
@@ -61,13 +61,14 @@ public struct RecordingView: View {
.resizable()
} else {
ProgressView()
.dynamicTypeSize(.small)
}
}
.disabled(model.isProcessing)
}
}
.buttonStyle(.recording)
.buttonStyle(.recording(
invertStyle: !model.isProcessing
))
}
.onChange(
of: model.state,