diff --git a/Packages/Features/Sources/Recording/RecordingButtonStyle.swift b/Packages/Features/Sources/Recording/RecordingButtonStyle.swift index 060100e..bd63662 100644 --- a/Packages/Features/Sources/Recording/RecordingButtonStyle.swift +++ b/Packages/Features/Sources/Recording/RecordingButtonStyle.swift @@ -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() diff --git a/Packages/Features/Sources/Recording/RecordingView.swift b/Packages/Features/Sources/Recording/RecordingView.swift index 8aa5839..46a50c2 100644 --- a/Packages/Features/Sources/Recording/RecordingView.swift +++ b/Packages/Features/Sources/Recording/RecordingView.swift @@ -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,