From 417cddb382b187083e37c3b69346819fa39fd097 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 2 Aug 2024 16:38:31 -0500 Subject: [PATCH] refactored code Signed-off-by: Matt Bruce --- .../InputStepper/InputStepper.swift | 134 ++++++++++-------- 1 file changed, 76 insertions(+), 58 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 37c82a88..e8980f0f 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -10,9 +10,10 @@ import UIKit import VDSCoreTokens 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) -open class InputStepper: EntryFieldBase { +open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers @@ -35,6 +36,29 @@ open class InputStepper: EntryFieldBase { /// Enum used to describe the size of Input Stepper. public enum Size: String, CaseIterable { 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. @@ -81,21 +105,36 @@ open class InputStepper: EntryFieldBase { /// Allows an id to be passed to input stepper. 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'. - open var maxValue: Int? = 99 { + lazy open var maxValue: Int = { _defaultMaxValue }() { didSet { - if let value = maxValue, value > 99 || value < 0 { - maxValue = 99 + if maxValue > _defaultMaxValue || maxValue < _defaultMinValue && maxValue > minValue { + maxValue = _defaultMaxValue } setNeedsUpdate() } } /// Minimum value of the input stepper, defaults to '0'. - open var minValue: Int? = 0 { + lazy open var minValue: Int = { _defaultMinValue }() { didSet { - if let value = minValue, value < 0 && value >= 99 { - minValue = 0 + if minValue < _defaultMinValue && minValue >= _defaultMaxValue && minValue < maxValue { + minValue = _defaultMinValue } setNeedsUpdate() } @@ -112,21 +151,12 @@ open class InputStepper: EntryFieldBase { /// Accepts any text or character to appear next to input stepper value. open var trailingText: String? { didSet { setNeedsUpdate() } } - /// Value for the textField - open override var value: String? { - return nil - } - //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var _controlWidth: ControlWidth? = nil - - /// Default Int value of the input stepper, defaults to '0'. - internal var defaultIntValue: Int { - guard let intValue = defaultValue as? Int else { return 0 } - return intValue - } + private var _defaultMinValue: Int = 0 + private var _defaultMaxValue: Int = 99 /// This is the view that will be wrapped with the border for userInteraction. /// The only subview of this view is the stepperStackView. @@ -177,28 +207,21 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- - internal override var containerSize: CGSize { CGSize(width: size == .large ? largeMinWidth : smallMinWidth, height: size == .large ? largeMinHeight : smallMinHeight) } - - internal var largeMinWidth = 121 - internal var smallMinWidth = 90 - internal var largeMinHeight = 44 - internal var smallMinHeight = 32 - + internal override var containerSize: CGSize { CGSize(width: size.minWidth, height: size.minHeight) } + internal let labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) internal let labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark) //-------------------------------------------------- // 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. open override func setup() { super.setup() - + // Set initial states + defaultValue = 0 containerView.isEnabled = false statusIcon.isHidden = true @@ -216,12 +239,11 @@ open class InputStepper: EntryFieldBase { stepperStackView.addArrangedSubview(incrementButton) // Set space between decrement button, label, and increment button relative to input Stepper size. - let space = size == .large ? VDSLayout.space3X : VDSLayout.space2X - stepperStackView.setCustomSpacing(space, after: decrementButton) - stepperStackView.setCustomSpacing(space, after: textLabel) + stepperStackView.setCustomSpacing(size.space, after: decrementButton) + stepperStackView.setCustomSpacing(size.space, after: textLabel) // 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.addSubview(stepperStackView) @@ -240,8 +262,8 @@ open class InputStepper: EntryFieldBase { statusIcon.isHidden = true // Update label text, style, color, ande surface. - textLabel.text = String(defaultIntValue) + " " + (trailingText ?? "") - textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall + textLabel.text = "\(_defaultValue) " + (trailingText ?? "") + textLabel.textStyle = size.textStyle textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() textLabel.surface = surface @@ -287,8 +309,9 @@ open class InputStepper: EntryFieldBase { controlWidth = nil widthPercentage = nil id = nil - minValue = 0 - maxValue = 99 + defaultValue = 0 + minValue = _defaultMinValue + maxValue = _defaultMaxValue trailingText = nil size = .large helperTextPlacement = .bottom @@ -325,27 +348,23 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- - internal func checkDefaultValue() { - if let minValue, let maxValue { - defaultValue = defaultIntValue > maxValue ? maxValue : defaultIntValue < minValue ? minValue : defaultIntValue + internal func decrementButtonClick() { + if _defaultValue > minValue { + defaultValue = _defaultValue - 1 + sendActions(for: .valueChanged) } } - internal func decrementButtonClick() { - defaultValue = defaultIntValue - 1 - checkDefaultValue() - updateButtonStates() - } - internal func incrementButtonClick() { - defaultValue = defaultIntValue + 1 - checkDefaultValue() - updateButtonStates() + if _defaultValue < maxValue { + defaultValue = _defaultValue + 1 + sendActions(for: .valueChanged) + } } internal func updateButtonStates() { - decrementButton.customContainerSize = size == .large ? 32 : 24 - incrementButton.customContainerSize = size == .large ? 32 : 24 + decrementButton.customContainerSize = size.buttonContainerSize + incrementButton.customContainerSize = size.buttonContainerSize decrementButton.surface = surface incrementButton.surface = surface @@ -353,8 +372,8 @@ open class InputStepper: EntryFieldBase { decrementButton.isEnabled = false incrementButton.isEnabled = false } else { - decrementButton.isEnabled = defaultIntValue > minValue ?? 0 ? true : false - incrementButton.isEnabled = defaultIntValue < maxValue ?? 99 ? true : false + decrementButton.isEnabled = (defaultValue ?? _defaultMaxValue ) > minValue ? true : false + incrementButton.isEnabled = (defaultValue ?? _defaultMinValue) < maxValue ? true : false } } @@ -365,7 +384,7 @@ open class InputStepper: EntryFieldBase { // Update Edge insets if size changes applied. stepperStackView.removeFromSuperview() stepperContainerView.addSubview(stepperStackView) - stepperStackView.pinToSuperView(.uniform(size == .large ? 6.0 : VDSLayout.space1X)) + stepperStackView.pinToSuperView(.uniform(size.padding)) // Update height if size changes applied. stepperHeightConstraint?.deactivate() @@ -407,7 +426,7 @@ open class InputStepper: EntryFieldBase { // Update the container view width based on the percentage received. private func updateContainerWidthWithPercentage() { - guard let superWidth = superview?.frame.width else { + guard let superWidth = horizontalPinnedWidth() else { return } @@ -415,7 +434,6 @@ open class InputStepper: EntryFieldBase { if let widthPercentage { // test value vs minimum width and take the greater value width = max(superWidth * (widthPercentage / 100), minWidth) - updateContainerWidth() } }