diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 57cdf756..cc55048c 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -42,9 +42,31 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- /// Accepts a string or number value to control the width of input stepper. /// auto(default) - The control's width is determined by the combined width of the value, trailing text and padding - /// Value - The control's width can be set to a fixed pixel or percentage value. + /// Value - The control's width can be set to a fixed pixel. open var controlWidth: String? = "auto" { didSet { setNeedsUpdate() } } + /// Accepts percentage value to controlWidth of input stepper. + open var controlWidthPercentage: CGFloat? { + didSet { + if let percentage = controlWidthPercentage, percentage > 100 { + controlWidthPercentage = 100 + } + updateControlWidthPercentage() + setNeedsUpdate() + } + } + + /// Accepts percentage value to width of parent container. + open var widthPercentage: CGFloat? { + didSet { + if let percentage = widthPercentage, percentage > 100 { + widthPercentage = 100 + } + updatePercentageWidth() + setNeedsUpdate() + } + } + /// Default value of the input stepper, defaults to '0'. open var defaultValue:Int = 0 { didSet { setNeedsUpdate() } } @@ -52,26 +74,20 @@ open class InputStepper: EntryFieldBase { open var id: Int? { didSet { setNeedsUpdate() } } /// Maximum value of the input stepper, defaults to '99'. - open var maxValue: Int? { - get { return _maxValue } - set { - if let newValue, newValue <= 99 && newValue > 0 { - _maxValue = newValue - } else { - _maxValue = 99 + open var maxValue: Int? = 99 { + didSet { + if let value = maxValue, value > 99 || value < 0 { + maxValue = 99 } setNeedsUpdate() } } /// Minimum value of the input stepper, defaults to '0'. - open var minValue: Int? { - get { return _minValue } - set { - if let newValue, newValue >= 0 && newValue < 99 { - _minValue = newValue - } else { - _minValue = 0 + open var minValue: Int? = 0 { + didSet { + if let value = minValue, value < 0 && value >= 99 { + minValue = 0 } setNeedsUpdate() } @@ -91,9 +107,6 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var _maxValue: Int = 99 - internal var _minValue: Int = 0 - /// This is the view that will be wrapped with the border for userInteraction. /// The only subview of this view is the stepperStackView. internal var stepperContainerView = View().with { @@ -148,8 +161,8 @@ open class InputStepper: EntryFieldBase { internal var largeMinHeight = 44 internal var smallMinHeight = 32 - internal let labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight , VDSColor.elementsPrimaryOndark) - internal let labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight , VDSColor.interactiveDisabledOndark) + internal let labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + internal let labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark) //-------------------------------------------------- // MARK: - Lifecycle @@ -207,6 +220,7 @@ open class InputStepper: EntryFieldBase { super.updateView() statusIcon.isHidden = true updateConstraintsToFieldStackView(flag: false) + updateContainerView(flag: false) // Update label text, style, color, ande surface. textLabel.text = String(defaultValue) + " " + (trailingText ?? "") @@ -219,7 +233,9 @@ open class InputStepper: EntryFieldBase { // Update stepper container border and corner radius. setControlWidth(controlWidth) - updateContainerView(flag: false) + updateControlWidthPercentage() + + setNeedsLayout() } /// Resets to default settings. @@ -227,19 +243,52 @@ open class InputStepper: EntryFieldBase { super.reset() textLabel.reset() textLabel.textStyle = .boldBodyLarge - textLabel.text = "" - controlWidth = nil - minValue = nil - maxValue = nil + controlWidth = "auto" + controlWidthPercentage = nil + widthPercentage = nil + defaultValue = 0 + id = nil + minValue = 0 + maxValue = 99 trailingText = nil + size = .large helperTextPlacement = .bottom } + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + internal override func updateContainerWidth() { + widthConstraint?.deactivate() + trailingLessThanEqualsConstraint?.deactivate() + trailingEqualsConstraint?.deactivate() + + if let width, width >= minWidth, width <= maxWidth { + widthConstraint?.constant = width + widthConstraint?.activate() + trailingLessThanEqualsConstraint?.activate() + } else if let parentWidth = width, parentWidth >= maxWidth { + width = maxWidth + widthConstraint?.constant = maxWidth + widthConstraint?.activate() + trailingLessThanEqualsConstraint?.activate() + } else if let parentWidth = width, parentWidth <= minWidth { + width = minWidth + widthConstraint?.constant = minWidth + widthConstraint?.activate() + trailingLessThanEqualsConstraint?.activate() + } else { + trailingEqualsConstraint?.activate() + } + } + //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- internal func checkDefaultValue() { - defaultValue = defaultValue > _maxValue ? _maxValue : defaultValue < _minValue ? _minValue : defaultValue + if let _minValue = minValue, let _maxValue = maxValue { + defaultValue = defaultValue > _maxValue ? _maxValue : defaultValue < _minValue ? _minValue : defaultValue + } } internal func decrementButtonClick() { @@ -264,8 +313,8 @@ open class InputStepper: EntryFieldBase { decrementButton.isEnabled = false incrementButton.isEnabled = false } else { - decrementButton.isEnabled = defaultValue > _minValue ? true : false - incrementButton.isEnabled = defaultValue < _maxValue ? true : false + decrementButton.isEnabled = defaultValue > minValue ?? 0 ? true : false + incrementButton.isEnabled = defaultValue < maxValue ?? 99 ? true : false } } @@ -307,4 +356,29 @@ open class InputStepper: EntryFieldBase { stepperWidthConstraint?.activate() } } + + private func updateControlWidthPercentage() { + let superWidth = width ?? CGFloat(containerView.frame.size.width) + + // Set the inputStepper's controlWidth based on the controlWidth percentage received relative to its parentView's frame. + if let controlWidthPercentage { + controlWidth = String( Int( max(superWidth * ((controlWidthPercentage) / 100), minWidth))) + setControlWidth(controlWidth) + } + } + + private func updatePercentageWidth() { + guard let superWidth = superview?.frame.width else { + return + } + + // Set width of Parent container based on width perecentage received relative to its superview frame. + if let widthPercentage { + width = max(superWidth * ((widthPercentage) / 100), minWidth) + if controlWidthPercentage != nil { + updateControlWidthPercentage() + } + } + + } }