diff --git a/core/Sources/Common/Control/PropertyStates/ControlPropertyStates.swift b/core/Sources/Common/Control/PropertyStates/ControlPropertyStates.swift index 89263a818..640543d2b 100644 --- a/core/Sources/Common/Control/PropertyStates/ControlPropertyStates.swift +++ b/core/Sources/Common/Control/PropertyStates/ControlPropertyStates.swift @@ -50,7 +50,7 @@ final class ControlPropertyStates { /// Get the value for a state. /// - Parameters: /// - state: the state of the value - func value(for state: ControlState) -> PropertyType? { + func value(forState state: ControlState) -> PropertyType? { switch state { case .normal: return self.normalState.value case .highlighted: return self.highlightedState.value @@ -61,8 +61,8 @@ final class ControlPropertyStates { /// Get the value for the status of the control. /// - Parameters: - /// - status: the status of the control - func value(for status: ControlStatus) -> PropertyType? { + /// - state: the status of the control + func value(forStatus status: ControlStatus) -> PropertyType? { // isHighlighted has the highest priority, // then isDisabled, // then isSelected, diff --git a/core/Sources/Common/Control/PropertyStates/ControlPropertyStatesTests.swift b/core/Sources/Common/Control/PropertyStates/ControlPropertyStatesTests.swift index 0f2afb91d..56bb4cb57 100644 --- a/core/Sources/Common/Control/PropertyStates/ControlPropertyStatesTests.swift +++ b/core/Sources/Common/Control/PropertyStates/ControlPropertyStatesTests.swift @@ -25,7 +25,7 @@ final class ControlPropertyStatesTests: XCTestCase { states.setValue(expectedValue, for: state) // WHEN - let value = states.value(for: state) + let value = states.value(forState: state) // THEN XCTAssertEqual( @@ -45,7 +45,7 @@ final class ControlPropertyStatesTests: XCTestCase { states.setValue(nil, for: state) // WHEN - let value = states.value(for: state) + let value = states.value(forState: state) // THEN XCTAssertNil( @@ -73,7 +73,7 @@ final class ControlPropertyStatesTests: XCTestCase { var status = ControlStatus(isHighlighted: true) states.setValue(highlightedValue, for: .highlighted) - var value = states.value(for: status) + var value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -89,7 +89,7 @@ final class ControlPropertyStatesTests: XCTestCase { status = ControlStatus(isHighlighted: true) states.setValue(nil, for: .highlighted) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -106,7 +106,7 @@ final class ControlPropertyStatesTests: XCTestCase { status = .init(isHighlighted: false) states.setValue(highlightedValue, for: .highlighted) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -134,7 +134,7 @@ final class ControlPropertyStatesTests: XCTestCase { var status = ControlStatus(isDisabled: true) states.setValue(disabledValue, for: .disabled) - var value = states.value(for: status) + var value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -150,7 +150,7 @@ final class ControlPropertyStatesTests: XCTestCase { status = ControlStatus(isDisabled: true) states.setValue(nil, for: .disabled) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -167,7 +167,7 @@ final class ControlPropertyStatesTests: XCTestCase { status = .init(isDisabled: false) states.setValue(disabledValue, for: .disabled) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -186,7 +186,7 @@ final class ControlPropertyStatesTests: XCTestCase { states.setValue(disabledValue, for: .disabled) states.setValue(highlightedValue, for: .highlighted) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -205,7 +205,7 @@ final class ControlPropertyStatesTests: XCTestCase { states.setValue(disabledValue, for: .disabled) states.setValue(nil, for: .highlighted) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -235,7 +235,7 @@ final class ControlPropertyStatesTests: XCTestCase { // Test with .selected value and true isSelected status. states.setValue(selectedValue, for: .selected) - var value = states.value(for: status) + var value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -250,7 +250,7 @@ final class ControlPropertyStatesTests: XCTestCase { // Test without .selected value and true isSelected status. states.setValue(nil, for: .selected) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -267,7 +267,7 @@ final class ControlPropertyStatesTests: XCTestCase { status = .init(isSelected: false) states.setValue(selectedValue, for: .selected) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -286,7 +286,7 @@ final class ControlPropertyStatesTests: XCTestCase { states.setValue(selectedValue, for: .selected) states.setValue(highlightedValue, for: .highlighted) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -305,7 +305,7 @@ final class ControlPropertyStatesTests: XCTestCase { states.setValue(selectedValue, for: .selected) states.setValue(nil, for: .highlighted) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -324,7 +324,7 @@ final class ControlPropertyStatesTests: XCTestCase { states.setValue(selectedValue, for: .selected) states.setValue(disabledValue, for: .disabled) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -343,7 +343,7 @@ final class ControlPropertyStatesTests: XCTestCase { states.setValue(selectedValue, for: .selected) states.setValue(nil, for: .disabled) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -366,7 +366,7 @@ final class ControlPropertyStatesTests: XCTestCase { var status = ControlStatus() states.setValue(normalStateValue, for: .normal) - var value = states.value(for: status) + var value = states.value(forStatus: status) // THEN XCTAssertEqual( @@ -382,7 +382,7 @@ final class ControlPropertyStatesTests: XCTestCase { status = ControlStatus() states.setValue(nil, for: .normal) - value = states.value(for: status) + value = states.value(forStatus: status) // THEN XCTAssertNil( diff --git a/core/Sources/Common/Control/UIView/UIControlStateImageView.swift b/core/Sources/Common/Control/UIView/UIControlStateImageView.swift index 3f7d744ae..8da3d72e0 100644 --- a/core/Sources/Common/Control/UIView/UIControlStateImageView.swift +++ b/core/Sources/Common/Control/UIView/UIControlStateImageView.swift @@ -16,40 +16,12 @@ final class UIControlStateImageView: UIImageView { private let imageStates = ControlPropertyStates() - /// The image must be stored to lock the posibility to set the image directly like this **self.image = UIImage()**. - /// When the storedImage is set (always from **setImage** function), it set the image. - private var storedImage: UIImage? { - didSet { - self.isImage = self.storedImage != nil - self.image = self.storedImage - } - } - - // MARK: - Published - - @Published var isImage: Bool = false - - // MARK: - Override Properties - - /// It's not possible to set the image outside this class. - /// The only possiblity to change the image is to use the **setImage(_: UIImage?, for: ControlState, on: UIControl)** function. - override var image: UIImage? { - get { - return super.image - } - set { - if newValue == self.storedImage { - super.image = newValue - } - } - } - // MARK: - Setter & Getter /// The image for a state. /// - parameter state: state of the image func image(for state: ControlState) -> UIImage? { - return self.imageStates.value(for: state) + return self.imageStates.value(forState: state) } /// Set the image for a state. @@ -78,6 +50,6 @@ final class UIControlStateImageView: UIImageView { ) // Set the image from states - self.storedImage = self.imageStates.value(for: status) + self.image = self.imageStates.value(forStatus: status) } } diff --git a/core/Sources/Common/Control/UIView/UIControlStateLabel.swift b/core/Sources/Common/Control/UIView/UIControlStateLabel.swift index 6cc425ce8..3310e2934 100644 --- a/core/Sources/Common/Control/UIView/UIControlStateLabel.swift +++ b/core/Sources/Common/Control/UIView/UIControlStateLabel.swift @@ -18,76 +18,11 @@ final class UIControlStateLabel: UILabel { private let attributedTextStates = ControlPropertyStates() private let textTypesStates = ControlPropertyStates() - /// The text must be stored to lock the posibility to set the text directly like this **self.text = "Text"**. - /// When the storedText is set (always from **setText** function), it set the text. - private var storedText: String? { - didSet { - self.isText = self.storedText != nil - self.text = self.storedText - - // Reset styles - if let storedTextFont = self.storedTextFont { - self.font = storedTextFont - } - if let storedTextColor = self.storedTextColor { - self.textColor = storedTextColor - } - } - } - - /// The attributedText must be stored to lock the posibility to set the attributedText directly like this **self.attributedText = NSAttributedString()**. - /// When the storedAttributedText is set (always from **setAttributedText** function), it set the attributedText. - private var storedAttributedText: NSAttributedString? { - didSet { - self.isText = self.storedAttributedText != nil - self.attributedText = self.storedAttributedText - } - } - - /// The storedTextFont is use to reset the font when a new text is set - /// because the previous text can be an attributedText - /// and attributedText has its own styles. private var storedTextFont: UIFont? - - /// The storedTextColor is use to reset the textColor when a new text is set - /// because the previous text can be an attributedText - /// and attributedText has its own styles. private var storedTextColor: UIColor? - // MARK: - Published - - @Published var isText: Bool = false - // MARK: - Override Properties - /// It's not possible to set the text outside this class. - /// The only possiblity to change the text is to use the **setText(_: String?, for: ControlState, on: UIControl)** function. - override var text: String? { - get { - return super.text - } - set { - // Set the attributedText only if the current come from setText - if newValue == self.storedText { - super.text = newValue - } - } - } - - /// It's not possible to set the attributedText outside this class. - /// The only possiblity to change the attributedText is to use the **setAttributedText(_: NSAttributedString?, for: ControlState, on: UIControl)** function. - override var attributedText: NSAttributedString? { - get { - return super.attributedText - } - set { - // Set the attributedText only if the current come from setAttributedText - if newValue == self.storedAttributedText { - super.attributedText = newValue - } - } - } - override var font: UIFont! { get { return super.font @@ -123,7 +58,7 @@ final class UIControlStateLabel: UILabel { /// The text for a state. /// - parameter state: state of the text func text(for state: ControlState) -> String? { - return self.textStates.value(for: state) + return self.textStates.value(forState: state) } /// Set the text for a state. @@ -146,7 +81,7 @@ final class UIControlStateLabel: UILabel { /// The attributedText for a state. /// - parameter state: state of the attributedText func attributedText(for state: ControlState) -> NSAttributedString? { - return self.attributedTextStates.value(for: state) + return self.attributedTextStates.value(forState: state) } /// Set the attributedText of the button for a state. @@ -178,24 +113,26 @@ final class UIControlStateLabel: UILabel { ) // Get the current textType from status - let textType = self.textTypesStates.value(for: status) - let textTypeContainsText = textType?.containsText ?? false + let textType = textTypesStates.value(forStatus: status) // Reset attributedText & text - self.storedAttributedText = nil - self.storedText = nil + self.attributedText = nil + self.text = nil // Set the text or the attributedText from textType and states - if let text = self.textStates.value(for: status), - textType == .text || !textTypeContainsText { - self.storedText = text - - } else if let attributedText = self.attributedTextStates.value(for: status), - textType == .attributedText || !textTypeContainsText { - self.storedAttributedText = attributedText - - } else { // No text to displayed - self.text = nil + switch textType { + case .text: + self.text = self.textStates.value(forStatus: status) + if let storedTextFont = self.storedTextFont { + self.font = storedTextFont + } + if let storedTextColor = self.storedTextColor { + self.textColor = storedTextColor + } + case .attributedText: + self.attributedText = self.attributedTextStates.value(forStatus: status) + default: + break } } @@ -207,7 +144,7 @@ final class UIControlStateLabel: UILabel { guard let attributedText = self.attributedText else { return false } - + // The attributedText contains attributes ? return !attributedText.attributes(at: 0, effectiveRange: nil).isEmpty } diff --git a/core/Sources/Components/Button/View/UIKit/ButtonUIView.swift b/core/Sources/Components/Button/View/UIKit/ButtonUIView.swift index 91c2771b2..cb09385a3 100644 --- a/core/Sources/Components/Button/View/UIKit/ButtonUIView.swift +++ b/core/Sources/Components/Button/View/UIKit/ButtonUIView.swift @@ -10,7 +10,7 @@ import Combine import UIKit /// The UIKit version for the button. -public final class ButtonUIView: UIControl { +public final class ButtonUIView: UIView { // MARK: - Type alias @@ -23,19 +23,18 @@ public final class ButtonUIView: UIControl { let stackView = UIStackView( arrangedSubviews: [ - self.imageContentView, + self.iconView, self.titleLabel ] ) stackView.axis = .horizontal stackView.accessibilityIdentifier = AccessibilityIdentifier.contentStackView - stackView.isUserInteractionEnabled = false return stackView }() - private lazy var imageContentView: UIView = { + private lazy var iconView: UIView = { let view = UIView() - view.addSubview(self.imageView) + view.addSubview(self.iconImageView) view.accessibilityIdentifier = AccessibilityIdentifier.icon view.setContentCompressionResistancePriority(.required, for: .vertical) @@ -44,23 +43,15 @@ public final class ButtonUIView: UIControl { return view }() - public var imageView: UIImageView { - return self.imageStateView - } - - private var imageStateView: UIControlStateImageView = { - let imageView = UIControlStateImageView() + private var iconImageView: UIImageView = { + let imageView = UIImageView() imageView.contentMode = .scaleAspectFit imageView.accessibilityIdentifier = AccessibilityIdentifier.iconImage return imageView }() - public var titleLabel: UILabel { - return self.titleStateLabel - } - - private var titleStateLabel: UIControlStateLabel = { - let label = UIControlStateLabel() + private var titleLabel: UILabel = { + let label = UILabel() label.numberOfLines = 1 label.lineBreakMode = .byWordWrapping label.textAlignment = .left @@ -70,31 +61,41 @@ public final class ButtonUIView: UIControl { return label }() + private lazy var clearButton: UIButton = { + let button = UIButton() + button.isAccessibilityElement = false + button.addTarget(self, action: #selector(self.touchUpInsideAction), for: .touchUpInside) + button.addTarget(self, action: #selector(self.touchDownAction), for: .touchDown) + button.addTarget(self, action: #selector(self.touchUpOutsideAction), for: .touchUpOutside) + button.addTarget(self, action: #selector(self.touchCancelAction), for: .touchCancel) + button.accessibilityIdentifier = AccessibilityIdentifier.clearButton + return button + }() + // MARK: - Public Properties /// The delegate used to notify about some changed on button. - @available(*, deprecated, message: "Use native **action** or **target** on UIControl or publisher instead") public weak var delegate: ButtonUIViewDelegate? - /// The tap publisher. Alternatively, you can use the native **action** (addAction) or **target** (addTarget). + /// The tap publisher. Alternatively, you can set a delegate. public var tapPublisher: UIControl.EventPublisher { - return self.publisher(for: .touchUpInside) + return self.clearButton.publisher(for: .touchUpInside) } /// Publishes when a touch was cancelled (e.g. by the system). public var touchCancelPublisher: UIControl.EventPublisher { - return self.publisher(for: .touchCancel) + return self.clearButton.publisher(for: .touchCancel) } /// Publishes when a touch was started but the touch ended outside of the button view bounds. public var touchUpOutsidePublisher: UIControl.EventPublisher { - return self.publisher(for: .touchUpOutside) + return self.clearButton.publisher(for: .touchUpOutside) } /// Publishes instantly when the button is touched down. /// - warning: This should not trigger a user action and should only be used for things like tracking. public var touchDownPublisher: UIControl.EventPublisher { - return self.publisher(for: .touchDown) + return self.clearButton.publisher(for: .touchDown) } /// The spark theme of the button. @@ -158,13 +159,12 @@ public final class ButtonUIView: UIControl { } /// The icon image of the button. - @available(*, deprecated, message: "Use setImage(_:, for:) and image(for:) instead") public var iconImage: UIImage? { get { - return self.image(for: .normal) + return self.viewModel.iconImage?.leftValue } set { - self.setImage(newValue, for: .normal) + self.viewModel.set(iconImage: newValue.map { .left($0) }) } } @@ -172,10 +172,11 @@ public final class ButtonUIView: UIControl { @available(*, deprecated, message: "Use setTitle(_:, for:) and title(for:) instead") public var text: String? { get { - return self.title(for: .normal) + return self.titleLabel.text } set { - self.setTitle(newValue, for: .normal) + self.titleLabel.text = newValue + self.viewModel.set(title: newValue) } } @@ -183,10 +184,11 @@ public final class ButtonUIView: UIControl { @available(*, deprecated, message: "Use setAttributedTitle(_:, for:) and attributedTitle(for:) instead") public var attributedText: NSAttributedString? { get { - return self.attributedTitle(for: .normal) + return self.titleLabel.attributedText } set { - self.setAttributedTitle(newValue, for: .normal) + self.titleLabel.attributedText = newValue + self.viewModel.set(attributedTitle: newValue.map { .left($0) }) } } @@ -201,38 +203,13 @@ public final class ButtonUIView: UIControl { } } - /// A Boolean value indicating whether the button is in the enabled state. - public override var isEnabled: Bool { + /// The state of the button: enabled or not. + public var isEnabled: Bool { get { return self.viewModel.isEnabled } set { - super.isEnabled = newValue self.viewModel.set(isEnabled: newValue) - self.titleStateLabel.updateContent(from: self) - self.imageStateView.updateContent(from: self) - } - } - - /// A Boolean value indicating whether the button is in the selected state. - public override var isSelected: Bool { - didSet { - self.titleStateLabel.updateContent(from: self) - self.imageStateView.updateContent(from: self) - } - } - - /// A Boolean value indicating whether the button draws a highlight. - public override var isHighlighted: Bool { - didSet { - self.titleStateLabel.updateContent(from: self) - self.imageStateView.updateContent(from: self) - - if self.isHighlighted { - self.viewModel.pressedAction() - } else { - self.viewModel.unpressedAction() - } } } @@ -251,7 +228,7 @@ public final class ButtonUIView: UIControl { private var contentStackViewTopConstraint: NSLayoutConstraint? private var contentStackViewBottomConstraint: NSLayoutConstraint? - private var imageViewHeightConstraint: NSLayoutConstraint? + private var iconImageViewHeightConstraint: NSLayoutConstraint? @ScaledUIMetric private var height: CGFloat = 0 @ScaledUIMetric private var verticalSpacing: CGFloat = 0 @@ -267,38 +244,6 @@ public final class ButtonUIView: UIControl { // MARK: - Initialization - /// Initialize a new button view. - /// - Parameters: - /// - theme: The spark theme of the button. - /// - intent: The intent of the button. - /// - variant: The variant of the button. - /// - size: The size of the button. - /// - shape: The shape of the button. - /// - alignment: The alignment of the button. - /// - isEnabled: The state of the button: enabled or not. - public convenience init( - theme: Theme, - intent: ButtonIntent, - variant: ButtonVariant, - size: ButtonSize, - shape: ButtonShape, - alignment: ButtonAlignment, - isEnabled: Bool - ) { - self.init( - theme, - intent: intent, - variant: variant, - size: size, - shape: shape, - alignment: alignment, - iconImage: nil, - text: nil, - attributedText: nil, - isEnabled: isEnabled - ) - } - /// Initialize a new button view with a text. /// - Parameters: /// - theme: The spark theme of the button. @@ -309,7 +254,6 @@ public final class ButtonUIView: UIControl { /// - alignment: The alignment of the button. /// - text: The text of the button. /// - isEnabled: The state of the button: enabled or not. - @available(*, deprecated, message: "Use init(theme: , intent: , variant: , size: , shape: , alignment: , isEnabled) instead") public convenience init( theme: Theme, intent: ButtonIntent, @@ -344,7 +288,6 @@ public final class ButtonUIView: UIControl { /// - alignment: The alignment of the button. /// - attributedText: The attributed text of the button. /// - isEnabled: The state of the button: enabled or not. - @available(*, deprecated, message: "Use init(theme: , intent: , variant: , size: , shape: , alignment: , isEnabled) instead") public convenience init( theme: Theme, intent: ButtonIntent, @@ -379,7 +322,6 @@ public final class ButtonUIView: UIControl { /// - alignment: The alignment of the button. /// - iconImage: The icon image of the button. /// - isEnabled: The state of the button: enabled or not. - @available(*, deprecated, message: "Use init(theme: , intent: , variant: , size: , shape: , alignment: , isEnabled) instead") public convenience init( theme: Theme, intent: ButtonIntent, @@ -415,7 +357,6 @@ public final class ButtonUIView: UIControl { /// - iconImage: The icon image of the button. /// - text: The text of the button. /// - isEnabled: The state of the button: enabled or not. - @available(*, deprecated, message: "Use init(theme: , intent: , variant: , size: , shape: , alignment: , isEnabled) instead") public convenience init( theme: Theme, intent: ButtonIntent, @@ -452,7 +393,6 @@ public final class ButtonUIView: UIControl { /// - iconImage: The icon image of the button. /// - attributedText: The attributed text of the button. /// - isEnabled: The state of the button: enabled or not. - @available(*, deprecated, message: "Use init(theme: , intent: , variant: , size: , shape: , alignment: , isEnabled) instead") public convenience init( theme: Theme, intent: ButtonIntent, @@ -520,6 +460,7 @@ public final class ButtonUIView: UIControl { self.accessibilityTraits = [.button] // Add subviews self.addSubview(self.contentStackView) + self.addSubview(self.clearButton) // Needed values from viewModel (important for superview) self.height = self.viewModel.sizes?.height ?? 0 @@ -530,9 +471,6 @@ public final class ButtonUIView: UIControl { // Setup publisher subcriptions self.setupSubscriptions() - // Setup actions - self.setupActions() - // Load view model self.viewModel.load() } @@ -568,6 +506,7 @@ public final class ButtonUIView: UIControl { self.setupContentStackViewConstraints() self.setupIconViewConstraints() self.setupIconImageViewConstraints() + self.setupClearButtonConstraints() } private func setupViewConstraints() { @@ -596,74 +535,24 @@ public final class ButtonUIView: UIControl { } private func setupIconViewConstraints() { - self.imageContentView.translatesAutoresizingMaskIntoConstraints = false - self.imageContentView.widthAnchor.constraint(greaterThanOrEqualTo: self.imageView.widthAnchor).isActive = true + self.iconView.translatesAutoresizingMaskIntoConstraints = false + self.iconView.widthAnchor.constraint(greaterThanOrEqualTo: self.iconImageView.widthAnchor).isActive = true } private func setupIconImageViewConstraints() { - self.imageView.translatesAutoresizingMaskIntoConstraints = false - - self.imageViewHeightConstraint = self.imageView.heightAnchor.constraint(equalToConstant: self.iconHeight) - self.imageViewHeightConstraint?.isActive = true - - NSLayoutConstraint.activate([ - self.imageView.widthAnchor.constraint(equalTo: self.imageView.heightAnchor), - self.imageView.centerXAnchor.constraint(equalTo: self.imageContentView.centerXAnchor), - self.imageView.centerYAnchor.constraint(equalTo: self.imageContentView.centerYAnchor) - ]) - } - - // MARK: - Setter & Getter - - /// The image of the button for a state. - /// - parameter state: state of the image - public func image(for state: ControlState) -> UIImage? { - return self.imageStateView.image(for: state) - } + self.iconImageView.translatesAutoresizingMaskIntoConstraints = false - /// Set the image of the button for a state. - /// - parameter image: new image of the button - /// - parameter state: state of the image - public func setImage(_ image: UIImage?, for state: ControlState) { - if state == .normal { - self.viewModel.set(iconImage: image.map { .left($0) }) - } - - self.imageStateView.setImage(image, for: state, on: self) - } + self.iconImageViewHeightConstraint = self.iconImageView.heightAnchor.constraint(equalToConstant: self.iconHeight) + self.iconImageViewHeightConstraint?.isActive = true - /// The title of the button for a state. - /// - parameter state: state of the title - public func title(for state: ControlState) -> String? { - return self.titleStateLabel.text(for: state) + self.iconImageView.widthAnchor.constraint(equalTo: self.iconImageView.heightAnchor).isActive = true + self.iconImageView.centerXAnchor.constraint(equalTo: self.iconView.centerXAnchor).isActive = true + self.iconImageView.centerYAnchor.constraint(equalTo: self.iconView.centerYAnchor).isActive = true } - /// Set the title of the button for a state. - /// - parameter title: new title of the button - /// - parameter state: state of the title - public func setTitle(_ title: String?, for state: ControlState) { - if state == .normal { - self.viewModel.set(title: title) - } - - self.titleStateLabel.setText(title, for: state, on: self) - } - - /// The title of the button for a state. - /// - parameter state: state of the title - public func attributedTitle(for state: ControlState) -> NSAttributedString? { - return self.titleStateLabel.attributedText(for: state) - } - - /// Set the attributedTitle of the button for a state. - /// - parameter attributedTitle: new attributedTitle of the button - /// - parameter state: state of the attributedTitle - public func setAttributedTitle(_ attributedTitle: NSAttributedString?, for state: ControlState) { - if state == .normal { - self.viewModel.set(attributedTitle: attributedTitle.map { .left($0) }) - } - - self.titleStateLabel.setAttributedText(attributedTitle, for: state, on: self) + private func setupClearButtonConstraints() { + self.clearButton.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.stickEdges(from: self.clearButton, to: self) } // MARK: - Update UI @@ -710,9 +599,9 @@ public final class ButtonUIView: UIControl { private func updateIconHeight() { // Reload height only if value changed - if self.imageViewHeightConstraint?.constant != self.iconHeight { - self.imageViewHeightConstraint?.constant = self.iconHeight - self.imageView.updateConstraintsIfNeeded() + if self.iconImageViewHeightConstraint?.constant != self.iconHeight { + self.iconImageViewHeightConstraint?.constant = self.iconHeight + self.iconImageView.updateConstraintsIfNeeded() } } @@ -725,7 +614,7 @@ public final class ButtonUIView: UIControl { guard let self, let state else { return } // Update the user interaction enabled - self.isUserInteractionEnabled = state.isUserInteractionEnabled + self.clearButton.isUserInteractionEnabled = state.isUserInteractionEnabled if !state.isUserInteractionEnabled { self.accessibilityTraits.insert(.notEnabled) } else { @@ -752,7 +641,7 @@ public final class ButtonUIView: UIControl { // Background Color let isAnimated = self.isAnimated && self.backgroundColor != colors.backgroundColor.uiColor let animationType: UIExecuteAnimationType = isAnimated ? .animated(duration: Animation.fastDuration) : .unanimated - + UIView.execute(animationType: animationType) { [weak self] in self?.backgroundColor = colors.backgroundColor.uiColor } @@ -761,7 +650,7 @@ public final class ButtonUIView: UIControl { self.setBorderColor(from: colors.borderColor) // Foreground Color - self.imageView.tintColor = colors.iconTintColor.uiColor + self.iconImageView.tintColor = colors.iconTintColor.uiColor if let titleColor = colors.titleColor { self.titleLabel.textColor = titleColor.uiColor } @@ -822,7 +711,7 @@ public final class ButtonUIView: UIControl { guard let self, let content else { return } // Icon ImageView - self.imageView.image = content.iconImage?.leftValue + self.iconImageView.image = content.iconImage?.leftValue // Subviews positions and visibilities let isAnimated = self.isAnimated && !self.firstContentStackViewSubviewAnimation @@ -833,8 +722,8 @@ public final class ButtonUIView: UIControl { self.firstContentStackViewSubviewAnimation = false - if self.imageContentView.isHidden == content.shouldShowIconImage { - self.imageContentView.isHidden = !content.shouldShowIconImage + if self.iconView.isHidden == content.shouldShowIconImage { + self.iconView.isHidden = !content.shouldShowIconImage } if self.titleLabel.isHidden == content.shouldShowTitle { @@ -856,50 +745,36 @@ public final class ButtonUIView: UIControl { self.titleLabel.font = titleFontToken.uiFont } // ** + } - // ** - // Is Image ? - self.imageStateView.$isImage.subscribe(in: &self.subscriptions) { [weak self] isImage in - guard let self else { return } + // MARK: - Actions - self.imageContentView.isHidden = !isImage - } + @objc private func touchUpInsideAction() { + self.unpressedAction() - // ** - // Is Text ? - self.titleStateLabel.$isText.subscribe(in: &self.subscriptions) { [weak self] isText in - guard let self else { return } - self.titleLabel.isHidden = !isText - } + self.delegate?.button(self, didReceive: .touchUpInside) + self.delegate?.buttonWasTapped(self) } - // MARK: - Actions + @objc private func touchDownAction() { + self.viewModel.pressedAction() + self.delegate?.button(self, didReceive: .touchDown) + } + + @objc private func touchUpOutsideAction() { + self.unpressedAction() + self.delegate?.button(self, didReceive: .touchUpOutside) + } + + @objc private func touchCancelAction() { + self.unpressedAction() + self.delegate?.button(self, didReceive: .touchCancel) + } - private func setupActions() { - // Touch down - self.addAction(.init(handler: { [weak self] _ in - guard let self else { return } - self.delegate?.button(self, didReceive: .touchDown) - }), for: .touchDown) - - // Touch Up Inside - self.addAction(.init(handler: { [weak self] _ in - guard let self else { return } - self.delegate?.button(self, didReceive: .touchUpInside) - self.delegate?.buttonWasTapped(self) - }), for: .touchUpInside) - - // Touch Up Outside - self.addAction(.init(handler: { [weak self] _ in - guard let self else { return } - self.delegate?.button(self, didReceive: .touchUpOutside) - }), for: .touchUpOutside) - - // Touch Cancel - self.addAction(.init(handler: { [weak self] _ in - guard let self else { return } - self.delegate?.button(self, didReceive: .touchCancel) - }), for: .touchCancel) + private func unpressedAction() { + DispatchQueue.main.asyncAfter(deadline: .now() + Animation.fastDuration, execute: { [weak self] in + self?.viewModel.unpressedAction() + }) } // MARK: - Trait Collection diff --git a/core/Sources/Components/Button/View/UIKit/ButtonUIViewDelegate.swift b/core/Sources/Components/Button/View/UIKit/ButtonUIViewDelegate.swift index 394afdd87..5d124e1c4 100644 --- a/core/Sources/Components/Button/View/UIKit/ButtonUIViewDelegate.swift +++ b/core/Sources/Components/Button/View/UIKit/ButtonUIViewDelegate.swift @@ -9,7 +9,6 @@ import Foundation /// Implement the delegate to receive tap and touch events. -@available(*, deprecated, message: "Use native **action** or **target** on UIControl or publisher instead") public protocol ButtonUIViewDelegate: AnyObject { /// Optionally implement this method to receive tap events and perform actions. /// - Parameter button: the button that was tapped diff --git a/core/Sources/Components/Switch/View/SwiftUI/SwitchView.swift b/core/Sources/Components/Switch/View/SwiftUI/SwitchView.swift index bfe46f358..8b3541acd 100644 --- a/core/Sources/Components/Switch/View/SwiftUI/SwitchView.swift +++ b/core/Sources/Components/Switch/View/SwiftUI/SwitchView.swift @@ -31,10 +31,10 @@ public struct SwitchView: View { /// Initialize a new switch view /// - Parameters: + /// - isOn: The Binding value of the switch. /// - theme: The spark theme of the switch. /// - intent: The intent of the switch. /// - alignment: The alignment of the switch. - /// - isOn: The Binding value of the switch. public init( theme: any Theme, intent: SwitchIntent, diff --git a/spark/Demo/Classes/View/Components/Button/ButtonContent.swift b/spark/Demo/Classes/View/Components/Button/ButtonContent.swift index fa120a16d..bd079bbff 100644 --- a/spark/Demo/Classes/View/Components/Button/ButtonContent.swift +++ b/spark/Demo/Classes/View/Components/Button/ButtonContent.swift @@ -12,5 +12,4 @@ enum ButtonContentDefault: CaseIterable { case attributedText case iconAndText case iconAndAttributedText - case none } diff --git a/spark/Demo/Classes/View/Components/Button/SwiftUI/ButtonComponentView.swift b/spark/Demo/Classes/View/Components/Button/SwiftUI/ButtonComponentView.swift index c464b84f8..de7c8f250 100644 --- a/spark/Demo/Classes/View/Components/Button/SwiftUI/ButtonComponentView.swift +++ b/spark/Demo/Classes/View/Components/Button/SwiftUI/ButtonComponentView.swift @@ -26,7 +26,6 @@ struct ButtonComponentView: View { @State private var alignment: ButtonAlignment = .leadingIcon @State private var content: ButtonContentDefault = .text @State private var isEnabled: CheckboxSelectionState = .selected - @State private var isSelected: CheckboxSelectionState = .selected @State private var isAnimated: CheckboxSelectionState = .selected @State private var shouldShowReverseBackgroundColor: Bool = false @@ -92,14 +91,6 @@ struct ButtonComponentView: View { selectionState: self.$isEnabled ) - CheckboxView( - text: "Is selected", - checkedImage: DemoIconography.shared.checkmark, - theme: self.theme, - isEnabled: true, - selectionState: self.$isSelected - ) - CheckboxView( text: "Is animated", checkedImage: DemoIconography.shared.checkmark, @@ -121,7 +112,6 @@ struct ButtonComponentView: View { alignment: self.$alignment.wrappedValue, content: self.$content.wrappedValue, isEnabled: self.$isEnabled.wrappedValue == .selected, - isSelected: self.$isSelected.wrappedValue == .selected, isAnimated: self.$isAnimated.wrappedValue == .selected ) .frame(width: geometry.size.width, height: self.uiKitViewHeight, alignment: .center) diff --git a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentItemsUIView.swift b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentItemsUIView.swift index 02d6cfe4e..ec0874cea 100644 --- a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentItemsUIView.swift +++ b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentItemsUIView.swift @@ -29,7 +29,6 @@ struct ButtonComponentItemsUIView: UIViewRepresentable { private let alignment: ButtonAlignment private let content: ButtonContentDefault private let isEnabled: Bool - private let isSelected: Bool private let isAnimated: Bool // MARK: - Initialization @@ -45,7 +44,6 @@ struct ButtonComponentItemsUIView: UIViewRepresentable { alignment: ButtonAlignment, content: ButtonContentDefault, isEnabled: Bool, - isSelected: Bool, isAnimated: Bool ) { self.viewModel = viewModel @@ -66,7 +64,6 @@ struct ButtonComponentItemsUIView: UIViewRepresentable { self.alignment = alignment self.content = content self.isEnabled = isEnabled - self.isSelected = isSelected self.isAnimated = isAnimated } @@ -137,17 +134,6 @@ struct ButtonComponentItemsUIView: UIViewRepresentable { attributedText: self.attributedText, isEnabled: self.isEnabled ) - - default: - buttonView = ButtonUIView( - theme: SparkTheme.shared, - intent: self.intent, - variant: self.variant, - size: self.size, - shape: self.shape, - alignment: self.alignment, - isEnabled: self.isEnabled - ) } let stackView = UIStackView(arrangedSubviews: [ @@ -209,21 +195,12 @@ struct ButtonComponentItemsUIView: UIViewRepresentable { case .iconAndAttributedText: buttonView.iconImage = self.iconImage buttonView.attributedText = self.attributedText - - default: - buttonView.text = nil - buttonView.attributedText = nil - buttonView.iconImage = nil } if buttonView.isEnabled != self.isEnabled { buttonView.isEnabled = self.isEnabled } - if buttonView.isSelected != self.isSelected { - buttonView.isSelected = self.isSelected - } - if buttonView.isAnimated != self.isAnimated { buttonView.isAnimated = self.isAnimated } diff --git a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentUIView.swift b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentUIView.swift index a025fcd52..e9ea132a1 100644 --- a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentUIView.swift +++ b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentUIView.swift @@ -18,15 +18,69 @@ final class ButtonComponentUIView: ComponentUIView { private let buttonView: ButtonUIView private static func makeButtonView(_ viewModel: ButtonComponentUIViewModel) -> ButtonUIView { - return .init( - theme: viewModel.theme, - intent: viewModel.intent, - variant: viewModel.variant, - size: viewModel.size, - shape: viewModel.shape, - alignment: viewModel.alignment, - isEnabled: viewModel.isEnabled - ) + switch viewModel.content { + case .icon: + return .init( + theme: viewModel.theme, + intent: viewModel.intent, + variant: viewModel.variant, + size: viewModel.size, + shape: viewModel.shape, + alignment: viewModel.alignment, + iconImage: viewModel.iconImage, + isEnabled: viewModel.isEnabled + ) + + case .text: + return .init( + theme: viewModel.theme, + intent: viewModel.intent, + variant: viewModel.variant, + size: viewModel.size, + shape: viewModel.shape, + alignment: viewModel.alignment, + text: viewModel.text, + isEnabled: viewModel.isEnabled + ) + + case .attributedText: + return .init( + theme: viewModel.theme, + intent: viewModel.intent, + variant: viewModel.variant, + size: viewModel.size, + shape: viewModel.shape, + alignment: viewModel.alignment, + attributedText: viewModel.attributedText, + isEnabled: viewModel.isEnabled + ) + + case .iconAndText: + return .init( + theme: viewModel.theme, + intent: viewModel.intent, + variant: viewModel.variant, + size: viewModel.size, + shape: viewModel.shape, + alignment: viewModel.alignment, + iconImage: viewModel.iconImage, + text: viewModel.text, + isEnabled: viewModel.isEnabled + ) + + case .iconAndAttributedText: + return .init( + theme: viewModel.theme, + intent: viewModel.intent, + variant: viewModel.variant, + size: viewModel.size, + shape: viewModel.shape, + alignment: viewModel.alignment, + iconImage: viewModel.iconImage, + attributedText: viewModel.attributedText, + isEnabled: viewModel.isEnabled + ) + } } // MARK: - Properties @@ -34,11 +88,6 @@ final class ButtonComponentUIView: ComponentUIView { private let viewModel: ButtonComponentUIViewModel private var cancellables: Set = [] - private lazy var buttonAction: UIAction = .init { _ in - self.showAlert(for: .action) - } - private var buttonControlCancellable: AnyCancellable? - // MARK: - Initializer init(viewModel: ButtonComponentUIViewModel) { @@ -102,33 +151,34 @@ final class ButtonComponentUIView: ComponentUIView { self.buttonView.alignment = alignment } - self.viewModel.$contentNormal.subscribe(in: &self.cancellables) { [weak self] content in + self.viewModel.$content.subscribe(in: &self.cancellables) { [weak self] content in guard let self = self else { return } - self.viewModel.contentNormalConfigurationItemViewModel.buttonTitle = content.name - self.showRightSpacing = content != .icon - self.setContent(content, for: .normal) - } - - self.viewModel.$contentHighlighted.subscribe(in: &self.cancellables) { [weak self] content in - guard let self = self else { return } - - self.viewModel.contentHighlightedConfigurationItemViewModel.buttonTitle = content.name - self.setContent(content, for: .highlighted) - } - - self.viewModel.$contentDisabled.subscribe(in: &self.cancellables) { [weak self] content in - guard let self = self else { return } - - self.viewModel.contentDisabledConfigurationItemViewModel.buttonTitle = content.name - self.setContent(content, for: .disabled) - } - - self.viewModel.$contentSelected.subscribe(in: &self.cancellables) { [weak self] content in - guard let self = self else { return } + self.viewModel.contentConfigurationItemViewModel.buttonTitle = content.name - self.viewModel.contentSelectedConfigurationItemViewModel.buttonTitle = content.name - self.setContent(content, for: .selected) + self.showRightSpacing = content != .icon + switch content { + case .icon: + self.buttonView.text = nil + self.buttonView.attributedText = nil + self.buttonView.iconImage = self.viewModel.iconImage + + case .text: + self.buttonView.iconImage = nil + self.buttonView.text = self.viewModel.text + + case .attributedText: + self.buttonView.iconImage = nil + self.buttonView.attributedText = self.viewModel.attributedText + + case .iconAndText: + self.buttonView.iconImage = self.viewModel.iconImage + self.buttonView.text = self.viewModel.text + + case .iconAndAttributedText: + self.buttonView.iconImage = self.viewModel.iconImage + self.buttonView.attributedText = self.viewModel.attributedText + } } self.viewModel.$isEnabled.subscribe(in: &self.cancellables) { [weak self] isEnabled in @@ -136,156 +186,9 @@ final class ButtonComponentUIView: ComponentUIView { self.buttonView.isEnabled = isEnabled } - self.viewModel.$isSelected.subscribe(in: &self.cancellables) { [weak self] isSelected in - guard let self = self else { return } - self.buttonView.isSelected = isSelected - } - self.viewModel.$isAnimated.subscribe(in: &self.cancellables) { [weak self] isAnimated in guard let self = self else { return } self.buttonView.isAnimated = isAnimated } - - self.viewModel.$controlType.subscribe(in: &self.cancellables) { [weak self] controlType in - guard let self = self else { return } - self.viewModel.controlTypeConfigurationItemViewModel.buttonTitle = controlType.name - self.setControl(from: controlType) - } - } - - // MARK: - Setter - - private func setContent(_ content: ButtonContentDefault, for state: ControlState) { - switch content { - case .icon: - self.buttonView.setTitle(nil, for: state) - self.buttonView.setAttributedTitle(nil, for: state) - self.buttonView.setImage(self.image(for: state), for: state) - - case .text: - self.buttonView.setImage(nil, for: state) - self.buttonView.setAttributedTitle(nil, for: state) - self.buttonView.setTitle(self.title(for: state), for: state) - - case .attributedText: - self.buttonView.setImage(nil, for: state) - self.buttonView.setTitle(nil, for: state) - self.buttonView.setAttributedTitle(self.attributedTitle(for: state), for: state) - - case .iconAndText: - self.buttonView.setImage(self.image(for: state), for: state) - self.buttonView.setAttributedTitle(nil, for: state) - self.buttonView.setTitle(self.title(for: state), for: state) - - case .iconAndAttributedText: - self.buttonView.setImage(self.image(for: state), for: state) - self.buttonView.setTitle(nil, for: state) - self.buttonView.setAttributedTitle(self.attributedTitle(for: state), for: state) - - case .none: - self.buttonView.setTitle(nil, for: state) - self.buttonView.setAttributedTitle(nil, for: state) - self.buttonView.setImage(nil, for: state) - } - } - - private func setControl(from controlType: ButtonControlType) { - // Delegate ? - self.buttonView.delegate = controlType == .delegate ? self : nil - - // Publisher ? - if controlType == .publisher { - self.buttonControlCancellable = self.buttonView.tapPublisher.sink { _ in - self.showAlert(for: .publisher) - } - } else { - self.buttonControlCancellable?.cancel() - self.buttonControlCancellable = nil - } - - // Action ? - if controlType == .action { - self.buttonView.addAction(self.buttonAction, for: .touchUpInside) - } else { - self.buttonView.removeAction(self.buttonAction, for: .touchUpInside) - } - - // Target ? - if controlType == .target { - self.buttonView.addTarget(self, action: #selector(self.touchUpInsideTarget), for: .touchUpInside) - } else { - self.buttonView.removeTarget(self, action: #selector(self.touchUpInsideTarget), for: .touchUpInside) - } - } - - // MARK: - Getter - - private func image(for state: ControlState) -> UIImage? { - switch state { - case .normal: return UIImage(named: "arrow") - case .highlighted: return UIImage(named: "close") - case .disabled: return UIImage(named: "check") - case .selected: return UIImage(named: "alert") - @unknown default: return nil - } - } - - private func title(for state: ControlState) -> String? { - switch state { - case .normal: return "My Title" - case .highlighted: return "My Highlighted" - case .disabled: return "My Disabled" - case .selected: return "My Selected" - @unknown default: return nil - } - } - - private func attributedTitle(for state: ControlState) -> NSAttributedString? { - - func attributedText(_ text: String) -> NSAttributedString { - return .init( - string: text, - attributes: [ - .foregroundColor: UIColor.purple, - .font: UIFont.italicSystemFont(ofSize: 20), - .underlineStyle: NSUnderlineStyle.single.rawValue - ] - ) - } - - switch state { - case .normal: return attributedText("My A_Title") - case .highlighted: return attributedText("My A_Highlighted") - case .disabled: return attributedText("My A_Disabled") - case .selected: return attributedText("My A_Selected") - @unknown default: return nil - } - } - - // MARK: - Action - - @objc func touchUpInsideTarget() { - self.showAlert(for: .target) - } - - // MARK: - Alert - - func showAlert(for controlType: ButtonControlType) { - let alertController = UIAlertController( - title: "Button tap from " + controlType.name, - message: nil, - preferredStyle: .alert - ) - alertController.addAction(.init(title: "Ok", style: .default)) - self.viewController?.present(alertController, animated: true) - } -} - -// MARK: - ButtonUIViewDelegate - -extension ButtonComponentUIView: ButtonUIViewDelegate { - - func buttonWasTapped(_ button: ButtonUIView) { - self.showAlert(for: .delegate) } } diff --git a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentUIViewModel.swift b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentUIViewModel.swift index ebd06f55a..7ba87b7f2 100644 --- a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentUIViewModel.swift +++ b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentUIViewModel.swift @@ -45,28 +45,8 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { .eraseToAnyPublisher() } - var showContentNormalSheet: AnyPublisher<[ButtonContentDefault], Never> { - showContentNormalSheetSubject - .eraseToAnyPublisher() - } - - var showContentHighlightedSheet: AnyPublisher<[ButtonContentDefault], Never> { - showContentHighlightedSheetSubject - .eraseToAnyPublisher() - } - - var showContentDisabledSheet: AnyPublisher<[ButtonContentDefault], Never> { - showContentDisabledSheetSubject - .eraseToAnyPublisher() - } - - var showContentSelectedSheet: AnyPublisher<[ButtonContentDefault], Never> { - showContentSelectedSheetSubject - .eraseToAnyPublisher() - } - - var showControlType: AnyPublisher<[ButtonControlType], Never> { - showControlTypeSheetSubject + var showContentSheet: AnyPublisher<[ButtonContentDefault], Never> { + showContentSheetSubject .eraseToAnyPublisher() } @@ -78,14 +58,9 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { @Published var size: ButtonSize @Published var shape: ButtonShape @Published var alignment: ButtonAlignment - @Published var contentNormal: ButtonContentDefault - @Published var contentHighlighted: ButtonContentDefault - @Published var contentDisabled: ButtonContentDefault - @Published var contentSelected: ButtonContentDefault + @Published var content: ButtonContentDefault @Published var isEnabled: Bool - @Published var isSelected: Bool @Published var isAnimated: Bool - @Published var controlType: ButtonControlType // MARK: - Items Properties @@ -137,35 +112,11 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { ) }() - lazy var contentNormalConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { - return .init( - name: "Content (normal state)", - type: .button, - target: (source: self, action: #selector(self.presentContentNormalSheet)) - ) - }() - - lazy var contentHighlightedConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { - return .init( - name: "Content (highlighted state)", - type: .button, - target: (source: self, action: #selector(self.presentContentHighlightedCSheet)) - ) - }() - - lazy var contentDisabledConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { - return .init( - name: "Content (disabled state)", - type: .button, - target: (source: self, action: #selector(self.presentContentDisabledSheet)) - ) - }() - - lazy var contentSelectedConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { + lazy var contentConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { return .init( - name: "Content (selected state)", + name: "Content", type: .button, - target: (source: self, action: #selector(self.presentContentSelectedSheet)) + target: (source: self, action: #selector(self.presentContentSheet)) ) }() @@ -177,14 +128,6 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { ) }() - lazy var isSelectedConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { - return .init( - name: "Is Selected", - type: .toggle(isOn: self.isSelected), - target: (source: self, action: #selector(self.isSelectedChanged)) - ) - }() - lazy var isAnimatedConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { return .init( name: "Is Animated", @@ -193,14 +136,6 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { ) }() - lazy var controlTypeConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { - return .init( - name: "Control Type", - type: .button, - target: (source: self, action: #selector(self.presentControlTypeSheet)) - ) - }() - // MARK: - Properties let text: String @@ -217,14 +152,9 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { self.sizeConfigurationItemViewModel, self.shapeConfigurationItemViewModel, self.alignmentConfigurationItemViewModel, - self.contentNormalConfigurationItemViewModel, - self.contentHighlightedConfigurationItemViewModel, - self.contentDisabledConfigurationItemViewModel, - self.contentSelectedConfigurationItemViewModel, + self.contentConfigurationItemViewModel, self.isEnabledConfigurationItemViewModel, - self.isSelectedConfigurationItemViewModel, - self.isAnimatedConfigurationItemViewModel, - self.controlTypeConfigurationItemViewModel + self.isAnimatedConfigurationItemViewModel ] } @@ -236,11 +166,7 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { private var showSizeSheetSubject: PassthroughSubject<[ButtonSize], Never> = .init() private var showShapeSheetSubject: PassthroughSubject<[ButtonShape], Never> = .init() private var showAlignmentSheetSubject: PassthroughSubject<[ButtonAlignment], Never> = .init() - private var showContentNormalSheetSubject: PassthroughSubject<[ButtonContentDefault], Never> = .init() - private var showContentHighlightedSheetSubject: PassthroughSubject<[ButtonContentDefault], Never> = .init() - private var showContentDisabledSheetSubject: PassthroughSubject<[ButtonContentDefault], Never> = .init() - private var showContentSelectedSheetSubject: PassthroughSubject<[ButtonContentDefault], Never> = .init() - private var showControlTypeSheetSubject: PassthroughSubject<[ButtonControlType], Never> = .init() + private var showContentSheetSubject: PassthroughSubject<[ButtonContentDefault], Never> = .init() // MARK: - Initialization @@ -253,14 +179,9 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { size: ButtonSize = .medium, shape: ButtonShape = .rounded, alignment: ButtonAlignment = .leadingIcon, - contentNormal: ButtonContentDefault = .text, - contentHighlighted: ButtonContentDefault = .text, - contentDisabled: ButtonContentDefault = .text, - contentSelected: ButtonContentDefault = .text, + content: ButtonContentDefault = .text, isEnabled: Bool = true, - isSelected: Bool = false, - isAnimated: Bool = true, - controlType: ButtonControlType = .action + isAnimated: Bool = true ) { self.text = text self.iconImage = .init(named: iconImageNamed) ?? UIImage() @@ -277,14 +198,9 @@ final class ButtonComponentUIViewModel: ComponentUIViewModel { self.size = size self.shape = shape self.alignment = alignment - self.contentNormal = contentNormal - self.contentHighlighted = contentHighlighted - self.contentDisabled = contentDisabled - self.contentSelected = contentSelected + self.content = content self.isEnabled = isEnabled - self.isSelected = isSelected self.isAnimated = isAnimated - self.controlType = controlType super.init(identifier: "Button") } @@ -318,35 +234,15 @@ extension ButtonComponentUIViewModel { self.showAlignmentSheetSubject.send(ButtonAlignment.allCases) } - @objc func presentContentNormalSheet() { - self.showContentNormalSheetSubject.send(ButtonContentDefault.allCases) - } - - @objc func presentContentHighlightedCSheet() { - self.showContentHighlightedSheetSubject.send(ButtonContentDefault.allCases) - } - - @objc func presentContentDisabledSheet() { - self.showContentDisabledSheetSubject.send(ButtonContentDefault.allCases) - } - - @objc func presentContentSelectedSheet() { - self.showContentSelectedSheetSubject.send(ButtonContentDefault.allCases) + @objc func presentContentSheet() { + self.showContentSheetSubject.send(ButtonContentDefault.allCases) } @objc func isEnabledChanged() { self.isEnabled.toggle() } - @objc func isSelectedChanged() { - self.isSelected.toggle() - } - @objc func isAnimatedChanged() { self.isAnimated.toggle() } - - @objc func presentControlTypeSheet() { - self.showControlTypeSheetSubject.send(ButtonControlType.allCases) - } } diff --git a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentViewController.swift b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentViewController.swift index ff6989af4..aba85c867 100644 --- a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentViewController.swift +++ b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonComponentViewController.swift @@ -84,24 +84,8 @@ final class ButtonComponentViewController: UIViewController { self.presentAlignmentActionSheet(alignments) } - self.viewModel.showContentNormalSheet.subscribe(in: &self.cancellables) { contents in - self.presentContentNormalActionSheet(contents) - } - - self.viewModel.showContentHighlightedSheet.subscribe(in: &self.cancellables) { contents in - self.presentContentHighlightedActionSheet(contents) - } - - self.viewModel.showContentDisabledSheet.subscribe(in: &self.cancellables) { contents in - self.presentContentDisabledActionSheet(contents) - } - - self.viewModel.showContentSelectedSheet.subscribe(in: &self.cancellables) { contents in - self.presentContentSelectedActionSheet(contents) - } - - self.viewModel.showControlType.subscribe(in: &self.cancellables) { types in - self.presentControlTypeActionSheet(types) + self.viewModel.showContentSheet.subscribe(in: &self.cancellables) { contents in + self.presentContentActionSheet(contents) } } } @@ -173,48 +157,13 @@ extension ButtonComponentViewController { self.present(actionSheet, animated: true) } - private func presentContentNormalActionSheet(_ contents: [ButtonContentDefault]) { - let actionSheet = SparkActionSheet.init( - values: contents, - texts: contents.map { $0.name }) { content in - self.viewModel.contentNormal = content - } - self.present(actionSheet, animated: true) - } - - private func presentContentHighlightedActionSheet(_ contents: [ButtonContentDefault]) { - let actionSheet = SparkActionSheet.init( - values: contents, - texts: contents.map { $0.name }) { content in - self.viewModel.contentHighlighted = content - } - self.present(actionSheet, animated: true) - } - - private func presentContentDisabledActionSheet(_ contents: [ButtonContentDefault]) { + private func presentContentActionSheet(_ contents: [ButtonContentDefault]) { let actionSheet = SparkActionSheet.init( values: contents, texts: contents.map { $0.name }) { content in - self.viewModel.contentDisabled = content + self.viewModel.content = content } self.present(actionSheet, animated: true) } - private func presentContentSelectedActionSheet(_ contents: [ButtonContentDefault]) { - let actionSheet = SparkActionSheet.init( - values: contents, - texts: contents.map { $0.name }) { content in - self.viewModel.contentSelected = content - } - self.present(actionSheet, animated: true) - } - - private func presentControlTypeActionSheet(_ contents: [ButtonControlType]) { - let actionSheet = SparkActionSheet.init( - values: contents, - texts: contents.map { $0.name }) { content in - self.viewModel.controlType = content - } - self.present(actionSheet, animated: true) - } } diff --git a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonControlType.swift b/spark/Demo/Classes/View/Components/Button/UIKit/ButtonControlType.swift deleted file mode 100644 index 4e91103c2..000000000 --- a/spark/Demo/Classes/View/Components/Button/UIKit/ButtonControlType.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// ButtonActionType.swift -// SparkCore -// -// Created by robin.lemaire on 06/11/2023. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import Foundation - -enum ButtonControlType: CaseIterable { - case delegate - case publisher - case action - case target -}