Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Button-367] Refactoring #701

Merged
merged 6 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//

/// Contains the dynamic property for a ControlState.
final class ControlPropertyState<T> {
final class ControlPropertyState<T: Equatable> {

// MARK: - Properties

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation

/// Manage all the states for a dynamic property.
final class ControlPropertyStates<PropertyType> {
final class ControlPropertyStates<PropertyType: Equatable> {

// MARK: - Type Alias

Expand Down Expand Up @@ -70,7 +70,7 @@ final class ControlPropertyStates<PropertyType> {

if status.isHighlighted, let value = self.highlightedState.value {
return value
} else if status.isDisabled, let value = self.disabledState.value {
} else if !status.isEnabled, let value = self.disabledState.value {
return value
} else if status.isSelected, let value = self.selectedState.value {
return value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ final class ControlPropertyStatesTests: XCTestCase {

// **
// WHEN
// Test with .disabled value and true isDisabled status.
// Test with .disabled value and false isEnabled status.

var status = ControlStatus(isDisabled: true)
var status = ControlStatus(isEnabled: false)
states.setValue(disabledValue, for: .disabled)
var value = states.value(for: status)

Expand All @@ -146,9 +146,9 @@ final class ControlPropertyStatesTests: XCTestCase {

// **
// WHEN
// Test without .disabled value and true isDisabled status.
// Test without .disabled value and false isEnabled status.

status = ControlStatus(isDisabled: true)
status = ControlStatus(isEnabled: false)
states.setValue(nil, for: .disabled)
value = states.value(for: status)

Expand All @@ -164,7 +164,7 @@ final class ControlPropertyStatesTests: XCTestCase {
// WHEN
// Test with .disabled value and false isDisabled status.

status = .init(isDisabled: false)
status = .init(isEnabled: true)

states.setValue(disabledValue, for: .disabled)
value = states.value(for: status)
Expand All @@ -179,10 +179,10 @@ final class ControlPropertyStatesTests: XCTestCase {

// **
// WHEN
// Test with .disabled value and true isDisabled status.
// Test with .disabled value and false isEnabled status.
// AND with value for .highlighted and isHighlighted status is true

status = .init(isHighlighted: true, isDisabled: true)
status = .init(isHighlighted: true, isEnabled: false)

states.setValue(disabledValue, for: .disabled)
states.setValue(highlightedValue, for: .highlighted)
Expand All @@ -198,10 +198,10 @@ final class ControlPropertyStatesTests: XCTestCase {

// **
// WHEN
// Test with .disabled value and true isDisabled status.
// Test with .disabled value and false isEnabled status.
// AND without value for .highlighted and isHighlighted status is true

status = .init(isHighlighted: true, isDisabled: true)
status = .init(isHighlighted: true, isEnabled: false)

states.setValue(disabledValue, for: .disabled)
states.setValue(nil, for: .highlighted)
Expand Down Expand Up @@ -318,9 +318,9 @@ final class ControlPropertyStatesTests: XCTestCase {
// **
// WHEN
// Test with .selected value and true isSelected status.
// AND with value for .disabled and isDisabled status is true
// AND with value for .disabled and isEnabled status is false.

status = .init(isDisabled: true, isSelected: true)
status = .init(isEnabled: false, isSelected: true)

states.setValue(selectedValue, for: .selected)
states.setValue(disabledValue, for: .disabled)
Expand All @@ -337,9 +337,9 @@ final class ControlPropertyStatesTests: XCTestCase {
// **
// WHEN
// Test with .selected value and true isSelected status.
// AND without value for .disabled and isDisabled status is true
// AND without value for .disabled and isEnabled status is false.

status = .init(isDisabled: true, isSelected: true)
status = .init(isEnabled: false, isSelected: true)

states.setValue(selectedValue, for: .selected)
states.setValue(nil, for: .disabled)
Expand Down Expand Up @@ -392,16 +392,3 @@ final class ControlPropertyStatesTests: XCTestCase {
// **
}
}

// MARK: - Extension

private extension ControlStatus {

init(isHighlighted: Bool = false, isDisabled: Bool = false, isSelected: Bool = false) {
self.init(
isHighlighted: isHighlighted,
isEnabled: !isDisabled,
isSelected: isSelected
)
}
}
2 changes: 1 addition & 1 deletion core/Sources/Common/Control/State/ControlState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation

/// Constants describing the state of a Spark control.
public enum ControlState: CaseIterable {
public enum ControlState: CaseIterable, Equatable {
/// The normal, or default, state of a control where the control is enabled but neither selected nor highlighted.
case normal
/// The highlighted state of a control.
Expand Down
26 changes: 19 additions & 7 deletions core/Sources/Common/Control/Status/ControlStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,34 @@
//

/// The current status of the control: highlighted or not, disabled or not and selected or not.
struct ControlStatus {
final class ControlStatus: Equatable {
robergro marked this conversation as resolved.
Show resolved Hide resolved

// MARK: - Properties

/// A Boolean value indicating whether the control draws a highlight.
let isHighlighted: Bool
/// A Boolean value indicating whether the control is in the disabled state.
let isDisabled: Bool
var isHighlighted: Bool
/// A Boolean value indicating whether the control is in the enabled state.
var isEnabled: Bool
/// A Boolean value indicating whether the control is in the selected state.
let isSelected: Bool
var isSelected: Bool

// MARK: - Initialization

init(isHighlighted: Bool, isEnabled: Bool, isSelected: Bool) {
init(
isHighlighted: Bool = false,
isEnabled: Bool = true,
isSelected: Bool = false
) {
self.isHighlighted = isHighlighted
self.isDisabled = !isEnabled
self.isEnabled = isEnabled
self.isSelected = isSelected
}

// MARK: - Equatable

static func == (lhs: ControlStatus, rhs: ControlStatus) -> Bool {
return lhs.isHighlighted == rhs.isHighlighted &&
lhs.isEnabled == rhs.isEnabled &&
lhs.isSelected == rhs.isSelected
}
}
16 changes: 13 additions & 3 deletions core/Sources/Common/Control/Status/ControlStatusTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ final class ControlStatusTests: XCTestCase {

// MARK: - Tests

func test_init_with_default_values() {
// GIVEN / WHEN
let status = ControlStatus()

// THEN
XCTAssertFalse(status.isHighlighted, "Wrong isHighlighted value")
XCTAssertTrue(status.isEnabled, "Wrong isSelected value")
XCTAssertFalse(status.isSelected, "Wrong isSelected value")
}

func test_init() {
// GIVEN
let givenIsHighlighted = true
Expand All @@ -35,9 +45,9 @@ final class ControlStatusTests: XCTestCase {
)

XCTAssertEqual(
status.isDisabled,
!givenIsEnabled,
"Wrong isDisabled"
status.isEnabled,
givenIsEnabled,
"Wrong isEnabled"
)

XCTAssertEqual(
Expand Down
16 changes: 0 additions & 16 deletions core/Sources/Common/Control/SwiftUI/Control.swift

This file was deleted.

21 changes: 7 additions & 14 deletions core/Sources/Common/Control/SwiftUI/ControlStateImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,23 @@ final class ControlStateImage: ObservableObject {
// MARK: - Setter

/// Set the image for a state.
/// - parameter image: new image
/// - parameter state: state of the image
/// - parameter control: the parent control
/// - parameter image: the new image
/// - parameter state: the state of the image
/// - parameter status: the status of the parent control
func setImage(
_ image: Image?,
for state: ControlState,
on control: Control
on status: ControlStatus
) {
self.imageStates.setValue(image, for: state)
self.updateContent(from: control)
self.updateContent(from: status)
}

// MARK: - Update UI

/// Update the label (image or attributed) for a parent control state.
/// - parameter control: the parent control
func updateContent(from control: Control) {
// Create the status from the control
let status = ControlStatus(
isHighlighted: control.isPressed,
isEnabled: !control.isDisabled,
isSelected: control.isSelected
)

/// - parameter status: the status of the parent control
func updateContent(from status: ControlStatus) {
self.image = self.imageStates.value(for: status)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ final class ControlStateImageTests: XCTestCase {
// GIVEN
let givenDisabledImage = Image("switchOff")

let control = Control(isDisabled: true)
let control = ControlStatus(isEnabled: false)

let controlStateImage = ControlStateImage()

Expand Down
28 changes: 11 additions & 17 deletions core/Sources/Common/Control/SwiftUI/ControlStateText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,60 +26,54 @@ final class ControlStateText: ObservableObject {
/// Set the text for a state.
/// - parameter text: new text
/// - parameter state: state of the text
/// - parameter control: the parent control
/// - parameter status: the status of the parent control
func setText(
_ text: String?,
for state: ControlState,
on control: Control
on status: ControlStatus
) {
self.textStates.setValue(text, for: state)
self.textTypesStates.setValue(
text != nil ? .text : DisplayedTextType.none,
for: state
)
self.updateContent(from: control)
self.updateContent(from: status)
}

/// Set the attributed text for a state.
/// - parameter text: new attributed text
/// - parameter state: state of the attributed text
/// - parameter control: the parent control
/// - parameter status: the status of the parent control
func setAttributedText(
_ attributedText: AttributedString?,
for state: ControlState,
on control: Control
on status: ControlStatus
) {
self.attributedTextStates.setValue(attributedText, for: state)
self.textTypesStates.setValue(
attributedText != nil ? .attributedText : DisplayedTextType.none,
for: state
)
self.updateContent(from: control)
self.updateContent(from: status)
}

// MARK: - Update UI

/// Update the label (text or attributed) for a parent control state.
/// - parameter control: the parent control
func updateContent(from control: Control) {
// Create the status from the control
let status = ControlStatus(
isHighlighted: control.isPressed,
isEnabled: !control.isDisabled,
isSelected: control.isSelected
)

/// - parameter status: the status of the parent control
func updateContent(from status: ControlStatus) {
// Get the current textType from status
let textType = self.textTypesStates.value(for: status)
let textTypeContainsText = textType?.containsText ?? false

// Set the text or the attributedText from textType and states
if let text = self.textStates.value(for: status),
textType == .text {
textType == .text || !textTypeContainsText {
self.attributedText = nil
self.text = text

} else if let attributedText = self.attributedTextStates.value(for: status),
textType == .attributedText {
textType == .attributedText || !textTypeContainsText {
self.text = nil
self.attributedText = attributedText

Expand Down
Loading
Loading