refactored code

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-08-02 16:38:31 -05:00
parent ce3d9e6e22
commit 417cddb382

View File

@ -10,9 +10,10 @@ import UIKit
import VDSCoreTokens import VDSCoreTokens
import Combine import Combine
/// A stepper is a two-segment control that people use to increase or decrease an incremental value. /// A stepper is a two-segment control that people use to increase or decrease an incremental value.'
@objcMembers
@objc(VDSInputStepper) @objc(VDSInputStepper)
open class InputStepper: EntryFieldBase { open class InputStepper: EntryFieldBase<Int> {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializers // MARK: - Initializers
@ -35,6 +36,29 @@ open class InputStepper: EntryFieldBase {
/// Enum used to describe the size of Input Stepper. /// Enum used to describe the size of Input Stepper.
public enum Size: String, CaseIterable { public enum Size: String, CaseIterable {
case large, small case large, small
var minWidth: CGFloat {
self == .large ? 121 : 90
}
var minHeight: CGFloat {
self == .large ? 44 : 32
}
var space: CGFloat {
self == .large ? VDSLayout.space3X : VDSLayout.space2X
}
var padding: CGFloat {
self == .large ? 6.0 : VDSLayout.space1X
}
var buttonContainerSize: Int {
self == .large ? 32 : 24
}
var textStyle: TextStyle {
self == .large ? .boldBodyLarge : .boldBodySmall
}
} }
/// Enum used to describe the width of a fixed value or percentage of the input stepper control. /// Enum used to describe the width of a fixed value or percentage of the input stepper control.
@ -81,21 +105,36 @@ open class InputStepper: EntryFieldBase {
/// Allows an id to be passed to input stepper. /// Allows an id to be passed to input stepper.
open var id: Int? { didSet { setNeedsUpdate() } } open var id: Int? { didSet { setNeedsUpdate() } }
private var _defaultValue: Int = 0
open override var defaultValue: Int? {
get { _defaultValue }
set {
if let newValue {
_defaultValue = newValue > maxValue ? maxValue : newValue < minValue ? minValue : newValue
} else {
_defaultValue = 0
}
setNeedsUpdate()
}
}
open override var value: Int? { return defaultValue }
/// Maximum value of the input stepper, defaults to '99'. /// Maximum value of the input stepper, defaults to '99'.
open var maxValue: Int? = 99 { lazy open var maxValue: Int = { _defaultMaxValue }() {
didSet { didSet {
if let value = maxValue, value > 99 || value < 0 { if maxValue > _defaultMaxValue || maxValue < _defaultMinValue && maxValue > minValue {
maxValue = 99 maxValue = _defaultMaxValue
} }
setNeedsUpdate() setNeedsUpdate()
} }
} }
/// Minimum value of the input stepper, defaults to '0'. /// Minimum value of the input stepper, defaults to '0'.
open var minValue: Int? = 0 { lazy open var minValue: Int = { _defaultMinValue }() {
didSet { didSet {
if let value = minValue, value < 0 && value >= 99 { if minValue < _defaultMinValue && minValue >= _defaultMaxValue && minValue < maxValue {
minValue = 0 minValue = _defaultMinValue
} }
setNeedsUpdate() setNeedsUpdate()
} }
@ -112,21 +151,12 @@ open class InputStepper: EntryFieldBase {
/// Accepts any text or character to appear next to input stepper value. /// Accepts any text or character to appear next to input stepper value.
open var trailingText: String? { didSet { setNeedsUpdate() } } open var trailingText: String? { didSet { setNeedsUpdate() } }
/// Value for the textField
open override var value: String? {
return nil
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
private var _controlWidth: ControlWidth? = nil private var _controlWidth: ControlWidth? = nil
private var _defaultMinValue: Int = 0
/// Default Int value of the input stepper, defaults to '0'. private var _defaultMaxValue: Int = 99
internal var defaultIntValue: Int {
guard let intValue = defaultValue as? Int else { return 0 }
return intValue
}
/// This is the view that will be wrapped with the border for userInteraction. /// This is the view that will be wrapped with the border for userInteraction.
/// The only subview of this view is the stepperStackView. /// The only subview of this view is the stepperStackView.
@ -177,28 +207,21 @@ open class InputStepper: EntryFieldBase {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Configuration Properties // MARK: - Configuration Properties
//-------------------------------------------------- //--------------------------------------------------
internal override var containerSize: CGSize { CGSize(width: size == .large ? largeMinWidth : smallMinWidth, height: size == .large ? largeMinHeight : smallMinHeight) } internal override var containerSize: CGSize { CGSize(width: size.minWidth, height: size.minHeight) }
internal var largeMinWidth = 121
internal var smallMinWidth = 90
internal var largeMinHeight = 44
internal var smallMinHeight = 32
internal let labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) internal let labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark)
internal let labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark) internal let labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark)
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
open override func initialSetup() {
super.initialSetup()
}
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
open override func setup() { open override func setup() {
super.setup() super.setup()
// Set initial states // Set initial states
defaultValue = 0
containerView.isEnabled = false containerView.isEnabled = false
statusIcon.isHidden = true statusIcon.isHidden = true
@ -216,12 +239,11 @@ open class InputStepper: EntryFieldBase {
stepperStackView.addArrangedSubview(incrementButton) stepperStackView.addArrangedSubview(incrementButton)
// Set space between decrement button, label, and increment button relative to input Stepper size. // Set space between decrement button, label, and increment button relative to input Stepper size.
let space = size == .large ? VDSLayout.space3X : VDSLayout.space2X stepperStackView.setCustomSpacing(size.space, after: decrementButton)
stepperStackView.setCustomSpacing(space, after: decrementButton) stepperStackView.setCustomSpacing(size.space, after: textLabel)
stepperStackView.setCustomSpacing(space, after: textLabel)
// Update Edge insets relative to input Stepper size. // Update Edge insets relative to input Stepper size.
stepperStackView.pinToSuperView(.uniform(size == .large ? 6.0 : VDSLayout.space1X)) stepperStackView.pinToSuperView(.uniform(size.padding))
// stepperContainerView for controls in EntryFieldBase.controlContainerView // stepperContainerView for controls in EntryFieldBase.controlContainerView
stepperContainerView.addSubview(stepperStackView) stepperContainerView.addSubview(stepperStackView)
@ -240,8 +262,8 @@ open class InputStepper: EntryFieldBase {
statusIcon.isHidden = true statusIcon.isHidden = true
// Update label text, style, color, ande surface. // Update label text, style, color, ande surface.
textLabel.text = String(defaultIntValue) + " " + (trailingText ?? "") textLabel.text = "\(_defaultValue) " + (trailingText ?? "")
textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall textLabel.textStyle = size.textStyle
textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable()
textLabel.surface = surface textLabel.surface = surface
@ -287,8 +309,9 @@ open class InputStepper: EntryFieldBase {
controlWidth = nil controlWidth = nil
widthPercentage = nil widthPercentage = nil
id = nil id = nil
minValue = 0 defaultValue = 0
maxValue = 99 minValue = _defaultMinValue
maxValue = _defaultMaxValue
trailingText = nil trailingText = nil
size = .large size = .large
helperTextPlacement = .bottom helperTextPlacement = .bottom
@ -325,27 +348,23 @@ open class InputStepper: EntryFieldBase {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Methods // MARK: - Private Methods
//-------------------------------------------------- //--------------------------------------------------
internal func checkDefaultValue() { internal func decrementButtonClick() {
if let minValue, let maxValue { if _defaultValue > minValue {
defaultValue = defaultIntValue > maxValue ? maxValue : defaultIntValue < minValue ? minValue : defaultIntValue defaultValue = _defaultValue - 1
sendActions(for: .valueChanged)
} }
} }
internal func decrementButtonClick() {
defaultValue = defaultIntValue - 1
checkDefaultValue()
updateButtonStates()
}
internal func incrementButtonClick() { internal func incrementButtonClick() {
defaultValue = defaultIntValue + 1 if _defaultValue < maxValue {
checkDefaultValue() defaultValue = _defaultValue + 1
updateButtonStates() sendActions(for: .valueChanged)
}
} }
internal func updateButtonStates() { internal func updateButtonStates() {
decrementButton.customContainerSize = size == .large ? 32 : 24 decrementButton.customContainerSize = size.buttonContainerSize
incrementButton.customContainerSize = size == .large ? 32 : 24 incrementButton.customContainerSize = size.buttonContainerSize
decrementButton.surface = surface decrementButton.surface = surface
incrementButton.surface = surface incrementButton.surface = surface
@ -353,8 +372,8 @@ open class InputStepper: EntryFieldBase {
decrementButton.isEnabled = false decrementButton.isEnabled = false
incrementButton.isEnabled = false incrementButton.isEnabled = false
} else { } else {
decrementButton.isEnabled = defaultIntValue > minValue ?? 0 ? true : false decrementButton.isEnabled = (defaultValue ?? _defaultMaxValue ) > minValue ? true : false
incrementButton.isEnabled = defaultIntValue < maxValue ?? 99 ? true : false incrementButton.isEnabled = (defaultValue ?? _defaultMinValue) < maxValue ? true : false
} }
} }
@ -365,7 +384,7 @@ open class InputStepper: EntryFieldBase {
// Update Edge insets if size changes applied. // Update Edge insets if size changes applied.
stepperStackView.removeFromSuperview() stepperStackView.removeFromSuperview()
stepperContainerView.addSubview(stepperStackView) stepperContainerView.addSubview(stepperStackView)
stepperStackView.pinToSuperView(.uniform(size == .large ? 6.0 : VDSLayout.space1X)) stepperStackView.pinToSuperView(.uniform(size.padding))
// Update height if size changes applied. // Update height if size changes applied.
stepperHeightConstraint?.deactivate() stepperHeightConstraint?.deactivate()
@ -407,7 +426,7 @@ open class InputStepper: EntryFieldBase {
// Update the container view width based on the percentage received. // Update the container view width based on the percentage received.
private func updateContainerWidthWithPercentage() { private func updateContainerWidthWithPercentage() {
guard let superWidth = superview?.frame.width else { guard let superWidth = horizontalPinnedWidth() else {
return return
} }
@ -415,7 +434,6 @@ open class InputStepper: EntryFieldBase {
if let widthPercentage { if let widthPercentage {
// test value vs minimum width and take the greater value // test value vs minimum width and take the greater value
width = max(superWidth * (widthPercentage / 100), minWidth) width = max(superWidth * (widthPercentage / 100), minWidth)
updateContainerWidth()
} }
} }