From 9efd50a0fab9b2f1b2727534061537c5a80283ed Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Mon, 24 Jun 2024 19:57:15 +0530 Subject: [PATCH 01/41] Digital ACT-191 ONEAPP-9311 story: added new page for Input Stepper --- VDS.xcodeproj/project.pbxproj | 16 +++++++ .../InputStepper/InputStepper.swift | 31 +++++++++++++ .../InputStepper/InputStepperLog.txt | 44 +++++++++++++++++++ VDS/VDS.docc/VDS.md | 1 + 4 files changed, 92 insertions(+) create mode 100644 VDS/Components/InputStepper/InputStepper.swift create mode 100644 VDS/Components/InputStepper/InputStepperLog.txt diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index ff8a6735..f1912a04 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 180636C72C29B0A400C92D86 /* InputStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 180636C62C29B0A400C92D86 /* InputStepper.swift */; }; + 180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */; }; 1808BEBC2BA41C3200129230 /* CarouselScrollbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */; }; 1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; }; 1842B1DF2BECE28B0021AFCA /* CalendarDateViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1842B1DE2BECE28B0021AFCA /* CalendarDateViewCell.swift */; }; @@ -203,6 +205,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 180636C62C29B0A400C92D86 /* InputStepper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputStepper.swift; sourceTree = ""; }; + 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = InputStepperLog.txt; sourceTree = ""; }; 1808BEBB2BA41C3200129230 /* CarouselScrollbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselScrollbar.swift; sourceTree = ""; }; 1808BEBF2BA456B700129230 /* CarouselScrollbarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CarouselScrollbarChangeLog.txt; sourceTree = ""; }; 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = ""; }; @@ -440,6 +444,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 180636C52C29B06200C92D86 /* InputStepper */ = { + isa = PBXGroup; + children = ( + 180636C62C29B0A400C92D86 /* InputStepper.swift */, + 180636C82C29B0DF00C92D86 /* InputStepperLog.txt */, + ); + path = InputStepper; + sourceTree = ""; + }; 1808BEBA2BA41B1D00129230 /* CarouselScrollbar */ = { isa = PBXGroup; children = ( @@ -660,6 +673,7 @@ EAC58C1F2BF127F000BA39FA /* DatePicker */, 186D13C92BBA8A3500986B53 /* DropdownSelect */, EA985BF3296C609E00F2FF2E /* Icon */, + 180636C52C29B06200C92D86 /* InputStepper */, EA3362412892EF700071C351 /* Label */, 44604AD529CE195300E62B51 /* Line */, EAD0688C2A55F801002E3A2D /* Loader */, @@ -1166,6 +1180,7 @@ EA3362072891E14D0071C351 /* VerizonNHGeDS-Regular.otf in Resources */, EA3362062891E14D0071C351 /* VerizonNHGeTX-Regular.otf in Resources */, EA3362052891E14D0071C351 /* VerizonNHGeDS-Bold.otf in Resources */, + 180636C92C29B0DF00C92D86 /* InputStepperLog.txt in Resources */, EAA5EEB928ECD24B003B3210 /* Icons.xcassets in Resources */, EAA5EEE428F5B855003B3210 /* VerizonNHGDS-Light.otf in Resources */, ); @@ -1209,6 +1224,7 @@ files = ( 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */, EA5E304C294CBDD00082B959 /* TileContainer.swift in Sources */, + 180636C72C29B0A400C92D86 /* InputStepper.swift in Sources */, EAF7F0A6289B0CE000B287F5 /* Resetable.swift in Sources */, EA985C2D296F03FE00F2FF2E /* TileletIconModels.swift in Sources */, EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */, diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift new file mode 100644 index 00000000..84651c85 --- /dev/null +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -0,0 +1,31 @@ +// +// InputStepper.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 24/06/24. +// + +import Foundation +import UIKit +import VDSCoreTokens +import Combine + +@objc(VDSInputStepper) +open class InputStepper: EntryFieldBase { + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + +} diff --git a/VDS/Components/InputStepper/InputStepperLog.txt b/VDS/Components/InputStepper/InputStepperLog.txt new file mode 100644 index 00000000..e8cd816b --- /dev/null +++ b/VDS/Components/InputStepper/InputStepperLog.txt @@ -0,0 +1,44 @@ + +MM/DD/YYYY +---------------- + +02/2024 +---------------- +- New component + +02/15/2024 +---------------- +- Added Border align: Inside to Anatomy +- Removed leadingText property values from States. +- Added Read-only to States. +- Created a section for Minimum width in Layout and spacing and updated the minWidth to 145px. +- Added trailingText spacing to Layout and spacing. +- Reduced space between Button Icons and text to 12px in Layout and spacing. +- Added top/bottom padding values to Layout and spacing. + +03/01/2024 +---------------- +- Removed Leading Text from “Content and other properties” section. + +03/20/2024 +---------------- +- Updated Anatomy artwork and items +- Added width and controlWidth to Configurations +- Updated Width under Layout and spacing to show layout examples + +04/12/2024 +---------------- +- Added a new configuration property (size) that includes large and small +- Reduced details from Anatomy page and added them to Configurations/Size +- Added Hit area, Small Input Stepper spacing properties to Layout and spacing +- Updated the Behavior page to display disabled button icon when value is at max and min + +04/29/2024 +---------------- +- Updated the Behavior page to display disabled button icon when value is at max and min + +05/10/2024 +---------------- +- Added helperTextPlacement property to Configurations +- Added Layout examples for right Helper Text placement in Layout and Spacing +- Added overflow examples in Overflow section of Layout and Spacing diff --git a/VDS/VDS.docc/VDS.md b/VDS/VDS.docc/VDS.md index d145ea0a..3cfe568d 100755 --- a/VDS/VDS.docc/VDS.md +++ b/VDS/VDS.docc/VDS.md @@ -32,6 +32,7 @@ Using the system allows designers and developers to collaborate more easily and - ``CheckboxGroup`` - ``DropdownSelect`` - ``Icon`` +- ``InputStepper`` - ``InputField`` - ``Label`` - ``Line`` From 548984d499d943c439fb36b2c2665b1e6759c9b4 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Fri, 12 Jul 2024 13:43:26 +0530 Subject: [PATCH 02/41] Digital ACT-191 ONEAPP-9311 story: added properites --- .../InputStepper/InputStepper.swift | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 84651c85..d9b4b6b8 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -10,6 +10,7 @@ import UIKit import VDSCoreTokens import Combine +/// A stepper is a two-segment control that people use to increase or decrease an incremental value. @objc(VDSInputStepper) open class InputStepper: EntryFieldBase { @@ -28,4 +29,141 @@ open class InputStepper: EntryFieldBase { super.init(coder: coder) } + //-------------------------------------------------- + // MARK: - Enums + //-------------------------------------------------- + + /// Enum used to describe the control width of Input Stepper. + public enum controlWidth: String, CaseIterable { + case auto, value + } + + /// Enum used to describe the size of Input Stepper. + public enum Size: String, CaseIterable { + case large, small + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + /// Accepts a string or number value to control the width of input stepper to a fixed pixel or percentage value. + open var controlWidth: CGFloat? { didSet { setNeedsUpdate() } } + + /// Maximum value of the input stepper, defaults to '99'. + open var maxValue: Int? { + get { return _maxValue } + set { + if let newValue, newValue < 100 && newValue > 0 { + _maxValue = newValue + } else { + _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 + } + setNeedsUpdate() + } + } + + /// The size of the input stepper. Defaults to 'large'. + open var size: Size { + get { return _size } + set { + _size = newValue + setNeedsUpdate() + } + } + + /// Accepts any text or character to appear next to input stepper value. + open var trailingText: String? { didSet { setNeedsUpdate() } } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + internal var _maxValue: Int = 99 + internal var _minValue: Int = 0 + internal var _size: Size = .large + + private var stepperWidthConstraint: NSLayoutConstraint? + private var stepperHeightConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func initialSetup() { + super.initialSetup() + } + + open override func setup() { + super.setup() + isAccessibilityElement = false + accessibilityLabel = "Input Stepper" + + containerView.isEnabled = false + } + + open override func getFieldContainer() -> UIView { + // stackview for controls in EntryFieldBase.controlContainerView + let controlStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .horizontal + $0.spacing = VDSLayout.space3X + $0.backgroundColor = .clear + } + let view = View().with { + $0.clipsToBounds = true + $0.backgroundColor = .clear + } + + let controlView = View().with { + $0.clipsToBounds = true + $0.backgroundColor = .clear + } + + let label = Label().with { + $0.text = "Label" + } + + let minusButton = ButtonIcon().with { + $0.kind = .ghost + $0.iconName = .leftCaret + $0.iconOffset = .init(x: -2, y: 0) + $0.customContainerSize = 40 + $0.icon.customSize = 16 + } + + let plusButton = ButtonIcon().with { + $0.kind = .ghost + $0.iconName = .rightCaret + $0.iconOffset = .init(x: 2, y: 0) + $0.customContainerSize = 40 + $0.icon.customSize = 16 + } + + controlStackView.addArrangedSubview(minusButton) + controlStackView.addArrangedSubview(label) + controlStackView.addArrangedSubview(plusButton) + controlView.addSubview(controlStackView) + controlStackView.pinToSuperView() + + view.addSubview(controlView) + controlView.pinToSuperView() + view.pinToSuperView() + return view + } + + open override func updateView() { + super.updateView() + updateContainerView(flag: false) + } } From 17f9240c7e9c8f200c9b5953b877e84d8a74db8a Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Mon, 15 Jul 2024 15:05:57 +0530 Subject: [PATCH 03/41] Digital ACT-191 ONEAPP-9311 story: added size configuration property that includes large and small --- .../InputStepper/InputStepper.swift | 146 +++++++++++------- 1 file changed, 91 insertions(+), 55 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index d9b4b6b8..71a3c766 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -32,28 +32,30 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- - - /// Enum used to describe the control width of Input Stepper. - public enum controlWidth: String, CaseIterable { - case auto, value - } - /// Enum used to describe the size of Input Stepper. public enum Size: String, CaseIterable { case large, small } - + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - /// Accepts a string or number value to control the width of input stepper to a fixed pixel or percentage value. - open var controlWidth: CGFloat? { didSet { setNeedsUpdate() } } + open var controlWidth: String? { + get { _controlWidth } + set { + setControlWidth(newValue) + setNeedsUpdate() + } + } + + /// Default value of the input stepper, defaults to '0'. + open var defaultValue:Int = 0 { didSet { setNeedsUpdate() } } /// Maximum value of the input stepper, defaults to '99'. open var maxValue: Int? { get { return _maxValue } set { - if let newValue, newValue < 100 && newValue > 0 { + if let newValue, newValue <= 99 && newValue > 0 { _maxValue = newValue } else { _maxValue = 99 @@ -80,7 +82,7 @@ open class InputStepper: EntryFieldBase { get { return _size } set { _size = newValue - setNeedsUpdate() + updateSize() } } @@ -90,13 +92,38 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + internal var _controlWidth = "auto" internal var _maxValue: Int = 99 internal var _minValue: Int = 0 internal var _size: Size = .large - - private var stepperWidthConstraint: NSLayoutConstraint? - private var stepperHeightConstraint: NSLayoutConstraint? + private var largeMinWidth = 121 + private var smallMinWidth = 90 + + let decrementButton = ButtonIcon().with { + $0.kind = .ghost + $0.iconName = Icon.Name(name: "minus") + $0.iconOffset = .init(x: -2, y: 0) + $0.customContainerSize = 32 + $0.icon.customSize = 16 + $0.backgroundColor = .clear + } + + let incrementButton = ButtonIcon().with { + $0.kind = .ghost + $0.iconName = Icon.Name(name: "plus") + $0.iconOffset = .init(x: 2, y: 0) + $0.customContainerSize = 32 + $0.icon.customSize = 16 + $0.backgroundColor = .clear + } + + let textLabel = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.textStyle = .boldBodyLarge + $0.backgroundColor = .clear + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -108,8 +135,7 @@ open class InputStepper: EntryFieldBase { super.setup() isAccessibilityElement = false accessibilityLabel = "Input Stepper" - - containerView.isEnabled = false + containerView.isEnabled = false } open override func getFieldContainer() -> UIView { @@ -120,50 +146,60 @@ open class InputStepper: EntryFieldBase { $0.spacing = VDSLayout.space3X $0.backgroundColor = .clear } - let view = View().with { - $0.clipsToBounds = true - $0.backgroundColor = .clear - } - let controlView = View().with { - $0.clipsToBounds = true - $0.backgroundColor = .clear - } - - let label = Label().with { - $0.text = "Label" - } - - let minusButton = ButtonIcon().with { - $0.kind = .ghost - $0.iconName = .leftCaret - $0.iconOffset = .init(x: -2, y: 0) - $0.customContainerSize = 40 - $0.icon.customSize = 16 - } - - let plusButton = ButtonIcon().with { - $0.kind = .ghost - $0.iconName = .rightCaret - $0.iconOffset = .init(x: 2, y: 0) - $0.customContainerSize = 40 - $0.icon.customSize = 16 - } - - controlStackView.addArrangedSubview(minusButton) - controlStackView.addArrangedSubview(label) - controlStackView.addArrangedSubview(plusButton) - controlView.addSubview(controlStackView) - controlStackView.pinToSuperView() - - view.addSubview(controlView) - controlView.pinToSuperView() - view.pinToSuperView() - return view + controlStackView.addArrangedSubview(decrementButton) + controlStackView.addArrangedSubview(textLabel) + controlStackView.addArrangedSubview(incrementButton) + return controlStackView } open override func updateView() { super.updateView() updateContainerView(flag: false) + textLabel.text = String(defaultValue) + " " + (trailingText ?? "") + decrementButton.surface = surface + incrementButton.surface = surface + textLabel.surface = surface + statusIcon.isHidden = true } + + /// Resets to default settings. + open override func reset() { + super.reset() + textLabel.reset() + textLabel.textStyle = .boldBodyLarge + textLabel.text = "" + controlWidth = nil + minValue = nil + maxValue = nil + trailingText = nil + helperTextPlacement = .bottom + } + + //-------------------------------------------------- + // MARK: - Private Methods + //-------------------------------------------------- + internal func updateSize() { + let value = size == .large ? 6.0 : VDSLayout.space1X + updateConstraintsToFieldStackView(value: value) + +// textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall +// textLabel.heightAnchor.constraint(equalToConstant: size == .large ? 44 : 32).activate() + +// decrementButton.customContainerSize = size == .large ? 32 : 24 +// incrementButton.customContainerSize = size == .large ? 32 : 24 + + } + + internal func setControlWidth(_ text: String?) { + if let text, text == "auto" { + // Set fixed width relative to default value, trailing text label + } else if let controlWidth = Int(text ?? "") { + // Use provided new width either pixel or percentage + width = CGFloat(controlWidth) + } else { + // Use EntryFieldBase width + } + } + } From 6c26655cbb45d4c15db3ef389466137ff8f569d1 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Mon, 15 Jul 2024 15:06:57 +0530 Subject: [PATCH 04/41] Digital ACT-191 ONEAPP-9311 story: added actions to decrement and increment buttons. --- .../InputStepper/InputStepper.swift | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 71a3c766..8cfe49a4 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -135,7 +135,10 @@ open class InputStepper: EntryFieldBase { super.setup() isAccessibilityElement = false accessibilityLabel = "Input Stepper" - containerView.isEnabled = false + containerView.isEnabled = false + + decrementButton.onClick = { _ in self.decrementButtonClick() } + incrementButton.onClick = { _ in self.incrementButtonClick() } } open override func getFieldContainer() -> UIView { @@ -160,6 +163,7 @@ open class InputStepper: EntryFieldBase { decrementButton.surface = surface incrementButton.surface = surface textLabel.surface = surface + updateButtonStates() statusIcon.isHidden = true } @@ -179,6 +183,27 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- + + internal func decrementButtonClick() { + defaultValue = defaultValue - 1 + updateButtonStates() + } + + internal func incrementButtonClick() { + defaultValue = defaultValue + 1 + updateButtonStates() + } + + internal func updateButtonStates() { + if isReadOnly || !isEnabled { + decrementButton.isEnabled = false + incrementButton.isEnabled = false + } else { + decrementButton.isEnabled = defaultValue > _minValue ? true : false + incrementButton.isEnabled = defaultValue < _maxValue ? true : false + } + } + internal func updateSize() { let value = size == .large ? 6.0 : VDSLayout.space1X updateConstraintsToFieldStackView(value: value) From 29d00ec352e99b8f149109a1944aa68ee8330c3e Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Mon, 15 Jul 2024 15:08:32 +0530 Subject: [PATCH 05/41] Digital ACT-191 ONEAPP-9311 story: update color configurations to stepper text for default and disabled states --- VDS/Components/InputStepper/InputStepper.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 8cfe49a4..752937ba 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -123,7 +123,13 @@ open class InputStepper: EntryFieldBase { $0.textStyle = .boldBodyLarge $0.backgroundColor = .clear } - + + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + private var labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight , VDSColor.elementsPrimaryOndark) + private var labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight , VDSColor.interactiveDisabledOndark) + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -195,6 +201,7 @@ open class InputStepper: EntryFieldBase { } internal func updateButtonStates() { + textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() if isReadOnly || !isEnabled { decrementButton.isEnabled = false incrementButton.isEnabled = false From 161f690488085e8187e9e4782a141b21b83ffe27 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Mon, 15 Jul 2024 15:37:26 +0530 Subject: [PATCH 06/41] Digital ACT-191 ONEAPP-9311 story: Check the default value and update it to max or min on button icon presses. --- .../InputStepper/InputStepper.swift | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 752937ba..d630d1d1 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -47,7 +47,7 @@ open class InputStepper: EntryFieldBase { setNeedsUpdate() } } - + /// Default value of the input stepper, defaults to '0'. open var defaultValue:Int = 0 { didSet { setNeedsUpdate() } } @@ -76,7 +76,7 @@ open class InputStepper: EntryFieldBase { setNeedsUpdate() } } - + /// The size of the input stepper. Defaults to 'large'. open var size: Size { get { return _size } @@ -88,7 +88,7 @@ open class InputStepper: EntryFieldBase { /// Accepts any text or character to appear next to input stepper value. open var trailingText: String? { didSet { setNeedsUpdate() } } - + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -142,7 +142,6 @@ open class InputStepper: EntryFieldBase { isAccessibilityElement = false accessibilityLabel = "Input Stepper" containerView.isEnabled = false - decrementButton.onClick = { _ in self.decrementButtonClick() } incrementButton.onClick = { _ in self.incrementButtonClick() } } @@ -155,7 +154,6 @@ open class InputStepper: EntryFieldBase { $0.spacing = VDSLayout.space3X $0.backgroundColor = .clear } - controlStackView.addArrangedSubview(decrementButton) controlStackView.addArrangedSubview(textLabel) controlStackView.addArrangedSubview(incrementButton) @@ -169,8 +167,8 @@ open class InputStepper: EntryFieldBase { decrementButton.surface = surface incrementButton.surface = surface textLabel.surface = surface - updateButtonStates() statusIcon.isHidden = true + updateButtonStates() } /// Resets to default settings. @@ -189,14 +187,19 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- + internal func checkDefaultValue() { + defaultValue = defaultValue > _maxValue ? _maxValue : defaultValue < _minValue ? _minValue : defaultValue + } internal func decrementButtonClick() { defaultValue = defaultValue - 1 + checkDefaultValue() updateButtonStates() } internal func incrementButtonClick() { defaultValue = defaultValue + 1 + checkDefaultValue() updateButtonStates() } @@ -215,12 +218,12 @@ open class InputStepper: EntryFieldBase { let value = size == .large ? 6.0 : VDSLayout.space1X updateConstraintsToFieldStackView(value: value) -// textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall -// textLabel.heightAnchor.constraint(equalToConstant: size == .large ? 44 : 32).activate() - -// decrementButton.customContainerSize = size == .large ? 32 : 24 -// incrementButton.customContainerSize = size == .large ? 32 : 24 - + // textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall + // textLabel.heightAnchor.constraint(equalToConstant: size == .large ? 44 : 32).activate() + + // decrementButton.customContainerSize = size == .large ? 32 : 24 + // incrementButton.customContainerSize = size == .large ? 32 : 24 + } internal func setControlWidth(_ text: String?) { @@ -233,5 +236,5 @@ open class InputStepper: EntryFieldBase { // Use EntryFieldBase width } } - + } From 0210e0d1280f35a2a31844bdf07881440b5653f6 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Wed, 24 Jul 2024 20:40:16 +0530 Subject: [PATCH 07/41] Digital ACT-191 ONEAPP-9311 story: control width can be set to auto (default) or value (pixel) , updating stepper view when size changes. --- .../DropdownSelect/DropdownSelect.swift | 2 +- .../InputStepper/InputStepper.swift | 184 ++++++++++++------ .../TextFields/EntryFieldBase.swift | 42 +++- .../TextFields/InputField/InputField.swift | 2 +- 4 files changed, 161 insertions(+), 69 deletions(-) diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 7fc52808..59b48ac9 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -299,7 +299,7 @@ extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource { dropdownField.resignFirstResponder() } optionsPicker.isHidden = !optionsPicker.isHidden - updateContainerView() + updateContainerView(flag: true) updateErrorLabel() } diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index d630d1d1..57cdf756 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -40,17 +40,17 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var controlWidth: String? { - get { _controlWidth } - set { - setControlWidth(newValue) - setNeedsUpdate() - } - } - + /// 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. + open var controlWidth: String? = "auto" { didSet { setNeedsUpdate() } } + /// Default value of the input stepper, defaults to '0'. open var defaultValue:Int = 0 { didSet { setNeedsUpdate() } } + /// Allows an id to be passed to input stepper. + open var id: Int? { didSet { setNeedsUpdate() } } + /// Maximum value of the input stepper, defaults to '99'. open var maxValue: Int? { get { return _maxValue } @@ -63,7 +63,7 @@ open class InputStepper: EntryFieldBase { setNeedsUpdate() } } - + /// Minimum value of the input stepper, defaults to '0'. open var minValue: Int? { get { return _minValue } @@ -78,11 +78,10 @@ open class InputStepper: EntryFieldBase { } /// The size of the input stepper. Defaults to 'large'. - open var size: Size { - get { return _size } - set { - _size = newValue - updateSize() + open var size: Size = .large { + didSet { + updateStepperContainerViewSize() + setNeedsUpdate() } } @@ -92,15 +91,23 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var _controlWidth = "auto" internal var _maxValue: Int = 99 internal var _minValue: Int = 0 - internal var _size: Size = .large - private var largeMinWidth = 121 - private var smallMinWidth = 90 + /// 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 { + $0.isAccessibilityElement = true + } - let decrementButton = ButtonIcon().with { + internal var stepperStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .horizontal + $0.distribution = .fill + $0.alignment = .fill + } + + internal var decrementButton = ButtonIcon().with { $0.kind = .ghost $0.iconName = Icon.Name(name: "minus") $0.iconOffset = .init(x: -2, y: 0) @@ -109,7 +116,7 @@ open class InputStepper: EntryFieldBase { $0.backgroundColor = .clear } - let incrementButton = ButtonIcon().with { + internal var incrementButton = ButtonIcon().with { $0.kind = .ghost $0.iconName = Icon.Name(name: "plus") $0.iconOffset = .init(x: 2, y: 0) @@ -118,17 +125,31 @@ open class InputStepper: EntryFieldBase { $0.backgroundColor = .clear } - let textLabel = Label().with { + internal var textLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textStyle = .boldBodyLarge - $0.backgroundColor = .clear + $0.numberOfLines = 1 + $0.lineBreakMode = .byTruncatingTail } - + //-------------------------------------------------- - // MARK: - Configuration + // MARK: - Constraints //-------------------------------------------------- - private var labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight , VDSColor.elementsPrimaryOndark) - private var labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight , VDSColor.interactiveDisabledOndark) + internal var stepperWidthConstraint: NSLayoutConstraint? + internal var stepperHeightConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // 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 let labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight , VDSColor.elementsPrimaryOndark) + internal let labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight , VDSColor.interactiveDisabledOndark) //-------------------------------------------------- // MARK: - Lifecycle @@ -137,38 +158,68 @@ open class InputStepper: EntryFieldBase { 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() + + // accessibility isAccessibilityElement = false accessibilityLabel = "Input Stepper" + + // Set initial states containerView.isEnabled = false + statusIcon.isHidden = true + + // Add listeners decrementButton.onClick = { _ in self.decrementButtonClick() } incrementButton.onClick = { _ in self.incrementButtonClick() } + + // setting color config + textLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() } open override func getFieldContainer() -> UIView { - // stackview for controls in EntryFieldBase.controlContainerView - let controlStackView = UIStackView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.axis = .horizontal - $0.spacing = VDSLayout.space3X - $0.backgroundColor = .clear - } - controlStackView.addArrangedSubview(decrementButton) - controlStackView.addArrangedSubview(textLabel) - controlStackView.addArrangedSubview(incrementButton) - return controlStackView + stepperStackView.addArrangedSubview(decrementButton) + stepperStackView.addArrangedSubview(textLabel) + 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) + + // Update Edge insets relative to input Stepper size. + stepperStackView.pinToSuperView(.uniform(size == .large ? 6.0 : VDSLayout.space1X)) + + // stepperContainerView for controls in EntryFieldBase.controlContainerView + stepperContainerView.addSubview(stepperStackView) + + stepperWidthConstraint = stepperContainerView.widthAnchor.constraint(equalToConstant: containerSize.width) + stepperWidthConstraint?.deactivate() + stepperHeightConstraint = stepperContainerView.heightAnchor.constraint(equalToConstant: containerSize.height) + stepperHeightConstraint?.deactivate() + + return stepperContainerView } + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - updateContainerView(flag: false) - textLabel.text = String(defaultValue) + " " + (trailingText ?? "") - decrementButton.surface = surface - incrementButton.surface = surface - textLabel.surface = surface statusIcon.isHidden = true + updateConstraintsToFieldStackView(flag: false) + + // Update label text, style, color, ande surface. + textLabel.text = String(defaultValue) + " " + (trailingText ?? "") + textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall + textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() + textLabel.surface = surface + + // Update increment and decrement button. updateButtonStates() + + // Update stepper container border and corner radius. + setControlWidth(controlWidth) + updateContainerView(flag: false) } /// Resets to default settings. @@ -204,7 +255,11 @@ open class InputStepper: EntryFieldBase { } internal func updateButtonStates() { - textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() + decrementButton.customContainerSize = size == .large ? 32 : 24 + incrementButton.customContainerSize = size == .large ? 32 : 24 + decrementButton.surface = surface + incrementButton.surface = surface + if isReadOnly || !isEnabled { decrementButton.isEnabled = false incrementButton.isEnabled = false @@ -214,27 +269,42 @@ open class InputStepper: EntryFieldBase { } } - internal func updateSize() { - let value = size == .large ? 6.0 : VDSLayout.space1X - updateConstraintsToFieldStackView(value: value) + // Update edge insets and height when size changes. + internal func updateStepperContainerViewSize() { + updateButtonStates() - // textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall - // textLabel.heightAnchor.constraint(equalToConstant: size == .large ? 44 : 32).activate() - - // decrementButton.customContainerSize = size == .large ? 32 : 24 - // incrementButton.customContainerSize = size == .large ? 32 : 24 + // Update Edge insets if size changes applied. + stepperStackView.removeFromSuperview() + stepperContainerView.addSubview(stepperStackView) + stepperStackView.pinToSuperView(.uniform(size == .large ? 6.0 : VDSLayout.space1X)) + // Update height if size changes applied. + stepperHeightConstraint?.deactivate() + stepperHeightConstraint = stepperContainerView.heightAnchor.constraint(equalToConstant: containerSize.height) + stepperHeightConstraint?.activate() } + // Set control width to input stepper. internal func setControlWidth(_ text: String?) { if let text, text == "auto" { - // Set fixed width relative to default value, trailing text label + stepperWidthConstraint?.deactivate() } else if let controlWidth = Int(text ?? "") { - // Use provided new width either pixel or percentage - width = CGFloat(controlWidth) - } else { - // Use EntryFieldBase width - } + // Set controlWidth provided which is either pixel or percentage + let width = width ?? CGFloat(containerView.frame.size.width) + updateStepperContainerWidth(controlWidth: CGFloat(controlWidth), width: width) + } } + // Handling the controlwidth without going beyond the width of the parent container. + internal func updateStepperContainerWidth(controlWidth: CGFloat, width: CGFloat) { + if controlWidth >= containerSize.width && controlWidth <= width { + stepperWidthConstraint?.deactivate() + stepperWidthConstraint?.constant = controlWidth + stepperWidthConstraint?.activate() + } else if controlWidth >= width { + stepperWidthConstraint?.deactivate() + stepperWidthConstraint?.constant = width + stepperWidthConstraint?.activate() + } + } } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 2ef89480..bf75d747 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -227,7 +227,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { get { fatalError("must be read from subclass")} } - open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } +// open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } open var isRequired: Bool = false { didSet { setNeedsUpdate() } } @@ -346,7 +346,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { /// Updates the UI open override func updateView() { super.updateView() - updateContainerView() + updateContainerView(flag: true) updateContainerWidth() updateTitleLabel() updateErrorLabel() @@ -372,7 +372,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { transparentBackground = false width = nil inputId = nil - defaultValue = nil +// defaultValue = nil isRequired = false isReadOnly = false onChange = nil @@ -401,7 +401,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open func getFieldContainer() -> UIView { fatalError("Subclass must return the view that contains the field/view the user will interact with.") } - + /// Container for the area in which helper or error text presents. open func getBottomContainer() -> UIView { return bottomContainerStackView @@ -520,13 +520,35 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } } - internal func updateContainerView() { - containerView.backgroundColor = containerBackgroundColor - containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor - containerView.layer.borderWidth = VDSFormControls.borderWidth - containerView.layer.cornerRadius = VDSFormControls.borderRadius + internal func updateContainerView(flag: Bool) { + if flag { + containerView.backgroundColor = containerBackgroundColor + containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor + containerView.layer.borderWidth = VDSFormControls.borderWidth + containerView.layer.cornerRadius = VDSFormControls.borderRadius + } else { + containerView.backgroundColor = .clear + containerView.layer.borderColor = nil + containerView.layer.borderWidth = 0 + containerView.layer.cornerRadius = 0 + fieldStackView.backgroundColor = containerBackgroundColor + fieldStackView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor + fieldStackView.layer.borderWidth = VDSFormControls.borderWidth + fieldStackView.layer.cornerRadius = containerView.frame.size.height / 2 + } } - + + /// Update constraints to containerStackView which has horizontal stack in which user interacts. + internal func updateConstraintsToFieldStackView(flag: Bool) { + fieldStackView.removeFromSuperview() + containerView.addSubview(fieldStackView) + if flag { + fieldStackView.pinToSuperView(.uniform(VDSLayout.space3X)) + } else { + fieldStackView.pinTop().pinLeading().pinBottom().pinTrailingLessThanOrEqualTo() + } + } + internal func updateContainerWidth() { widthConstraint?.deactivate() trailingLessThanEqualsConstraint?.deactivate() diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index c2f779d4..39074cf1 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -287,7 +287,7 @@ open class InputField: EntryFieldBase { extension InputField: UITextFieldDelegate { public func textFieldDidBeginEditing(_ textField: UITextField) { fieldType.handler().textFieldDidBeginEditing(self, textField: textField) - updateContainerView() + updateContainerView(flag: true) updateErrorLabel() } From 4e88ee936a231b3e05d9fcd5c5bb39d07a13fcc6 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Fri, 26 Jul 2024 20:48:45 +0530 Subject: [PATCH 08/41] Digital ACT-191 ONEAPP-9311 story: parent container width can be set to value (percentage), controlWidth of input stepper can be set to value - percentage --- .../InputStepper/InputStepper.swift | 130 ++++++++++++++---- 1 file changed, 102 insertions(+), 28 deletions(-) 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() + } + } + + } } From 90eb01cb2459917ce33af04780df196a0a9ee2b0 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Fri, 26 Jul 2024 21:24:15 +0530 Subject: [PATCH 09/41] Digital ACT-191 ONEAPP-9311 story: aligning text to center --- .../InputStepper/InputStepper.swift | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index cc55048c..5abf8724 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -44,7 +44,7 @@ open class InputStepper: EntryFieldBase { /// 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. open var controlWidth: String? = "auto" { didSet { setNeedsUpdate() } } - + /// Accepts percentage value to controlWidth of input stepper. open var controlWidthPercentage: CGFloat? { didSet { @@ -72,7 +72,7 @@ open class InputStepper: EntryFieldBase { /// Allows an id to be passed to input stepper. open var id: Int? { didSet { setNeedsUpdate() } } - + /// Maximum value of the input stepper, defaults to '99'. open var maxValue: Int? = 99 { didSet { @@ -82,7 +82,7 @@ open class InputStepper: EntryFieldBase { setNeedsUpdate() } } - + /// Minimum value of the input stepper, defaults to '0'. open var minValue: Int? = 0 { didSet { @@ -94,7 +94,7 @@ open class InputStepper: EntryFieldBase { } /// The size of the input stepper. Defaults to 'large'. - open var size: Size = .large { + open var size: Size = .large { didSet { updateStepperContainerViewSize() setNeedsUpdate() @@ -143,24 +143,25 @@ open class InputStepper: EntryFieldBase { $0.textStyle = .boldBodyLarge $0.numberOfLines = 1 $0.lineBreakMode = .byTruncatingTail + $0.textAlignment = .center } - + //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- internal var stepperWidthConstraint: NSLayoutConstraint? internal var stepperHeightConstraint: NSLayoutConstraint? - + //-------------------------------------------------- // 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 let labelColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) internal let labelDisabledColorConfiguration = SurfaceColorConfiguration(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark) @@ -182,11 +183,11 @@ open class InputStepper: EntryFieldBase { // Set initial states containerView.isEnabled = false statusIcon.isHidden = true - + // Add listeners decrementButton.onClick = { _ in self.decrementButtonClick() } incrementButton.onClick = { _ in self.incrementButtonClick() } - + // setting color config textLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() } @@ -195,12 +196,12 @@ open class InputStepper: EntryFieldBase { stepperStackView.addArrangedSubview(decrementButton) stepperStackView.addArrangedSubview(textLabel) 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) - + // Update Edge insets relative to input Stepper size. stepperStackView.pinToSuperView(.uniform(size == .large ? 6.0 : VDSLayout.space1X)) @@ -221,20 +222,19 @@ open class InputStepper: EntryFieldBase { statusIcon.isHidden = true updateConstraintsToFieldStackView(flag: false) updateContainerView(flag: false) - + // Update label text, style, color, ande surface. textLabel.text = String(defaultValue) + " " + (trailingText ?? "") textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() textLabel.surface = surface - + // Update increment and decrement button. updateButtonStates() // Update stepper container border and corner radius. setControlWidth(controlWidth) updateControlWidthPercentage() - setNeedsLayout() } @@ -262,7 +262,7 @@ open class InputStepper: EntryFieldBase { widthConstraint?.deactivate() trailingLessThanEqualsConstraint?.deactivate() trailingEqualsConstraint?.deactivate() - + if let width, width >= minWidth, width <= maxWidth { widthConstraint?.constant = width widthConstraint?.activate() @@ -286,7 +286,7 @@ open class InputStepper: EntryFieldBase { // MARK: - Private Methods //-------------------------------------------------- internal func checkDefaultValue() { - if let _minValue = minValue, let _maxValue = maxValue { + if let _minValue = minValue, let _maxValue = maxValue { defaultValue = defaultValue > _maxValue ? _maxValue : defaultValue < _minValue ? _minValue : defaultValue } } @@ -308,7 +308,7 @@ open class InputStepper: EntryFieldBase { incrementButton.customContainerSize = size == .large ? 32 : 24 decrementButton.surface = surface incrementButton.surface = surface - + if isReadOnly || !isEnabled { decrementButton.isEnabled = false incrementButton.isEnabled = false @@ -341,7 +341,7 @@ open class InputStepper: EntryFieldBase { // Set controlWidth provided which is either pixel or percentage let width = width ?? CGFloat(containerView.frame.size.width) updateStepperContainerWidth(controlWidth: CGFloat(controlWidth), width: width) - } + } } // Handling the controlwidth without going beyond the width of the parent container. @@ -359,7 +359,7 @@ open class InputStepper: EntryFieldBase { 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))) @@ -379,6 +379,5 @@ open class InputStepper: EntryFieldBase { updateControlWidthPercentage() } } - } } From 3ea4b74af2fa1ba35b098e9dce483339bbdc236e Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Mon, 29 Jul 2024 16:17:52 +0530 Subject: [PATCH 10/41] Digital ACT-191 ONEAPP-9311 story: added accessibility changes --- .../InputStepper/InputStepper.swift | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 5abf8724..b9139b5a 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -104,6 +104,11 @@ 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 //-------------------------------------------------- @@ -111,6 +116,7 @@ open class InputStepper: EntryFieldBase { /// The only subview of this view is the stepperStackView. internal var stepperContainerView = View().with { $0.isAccessibilityElement = true + $0.accessibilityLabel = "Input Stepper" } internal var stepperStackView = UIStackView().with { @@ -145,7 +151,7 @@ open class InputStepper: EntryFieldBase { $0.lineBreakMode = .byTruncatingTail $0.textAlignment = .center } - + //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- @@ -175,11 +181,7 @@ open class InputStepper: EntryFieldBase { /// 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() - - // accessibility - isAccessibilityElement = false - accessibilityLabel = "Input Stepper" - + // Set initial states containerView.isEnabled = false statusIcon.isHidden = true @@ -238,6 +240,30 @@ open class InputStepper: EntryFieldBase { setNeedsLayout() } + open override var accessibilityElements: [Any]? { + get { + var elements = [Any]() + + if !isReadOnly || isEnabled { + elements.append(contentsOf: [titleLabel, containerView, decrementButton, textLabel, incrementButton]) + } else { + elements.append(contentsOf: [titleLabel, containerView, textLabel]) + } + + if showError { + if let errorText, !errorText.isEmpty { + elements.append(errorLabel) + } + } + if let helperText, !helperText.isEmpty { + elements.append(helperLabel) + } + return elements + } + + set { super.accessibilityElements = newValue } + } + /// Resets to default settings. open override func reset() { super.reset() From 06b0c80a58da380e6793e2529b0ccc0109374b6f Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Tue, 30 Jul 2024 14:54:42 +0530 Subject: [PATCH 11/41] Digital ACT-191 ONEAPP-9311 story: changes as per review notes --- VDS/Components/DatePicker/DatePicker.swift | 2 +- .../DropdownSelect/DropdownSelect.swift | 2 +- .../InputStepper/InputStepper.swift | 40 +++++++++++++------ .../TextFields/EntryFieldBase.swift | 40 +++++-------------- .../TextFields/InputField/InputField.swift | 2 +- 5 files changed, 39 insertions(+), 47 deletions(-) diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index db4807b4..df7cc7c9 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -286,7 +286,7 @@ extension DatePicker { // update containerview _ = responder?.becomeFirstResponder() - updateContainerView(flag: true) + updateContainerView() // animate the calendar to show UIView.animate(withDuration: 0.5, diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 8aa36272..947210f4 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -288,7 +288,7 @@ extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource { dropdownField.resignFirstResponder() } optionsPicker.isHidden = !optionsPicker.isHidden - updateContainerView(flag: true) + updateContainerView() updateErrorLabel() } diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 251df4b2..63288e96 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -67,9 +67,6 @@ open class InputStepper: EntryFieldBase { } } - /// Default value of the input stepper, defaults to '0'. - open var defaultValue:Int = 0 { didSet { setNeedsUpdate() } } - /// Allows an id to be passed to input stepper. open var id: Int? { didSet { setNeedsUpdate() } } @@ -112,6 +109,12 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + /// 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 + } + /// 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 { @@ -222,11 +225,9 @@ open class InputStepper: EntryFieldBase { open override func updateView() { super.updateView() statusIcon.isHidden = true - updateConstraintsToFieldStackView(flag: false) - updateContainerView(flag: false) // Update label text, style, color, ande surface. - textLabel.text = String(defaultValue) + " " + (trailingText ?? "") + textLabel.text = String(defaultIntValue) + " " + (trailingText ?? "") textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() textLabel.surface = surface @@ -237,6 +238,7 @@ open class InputStepper: EntryFieldBase { // Update stepper container border and corner radius. setControlWidth(controlWidth) updateControlWidthPercentage() + updateStepperView() setNeedsLayout() } @@ -272,7 +274,6 @@ open class InputStepper: EntryFieldBase { controlWidth = "auto" controlWidthPercentage = nil widthPercentage = nil - defaultValue = 0 id = nil minValue = 0 maxValue = 99 @@ -312,19 +313,19 @@ open class InputStepper: EntryFieldBase { // MARK: - Private Methods //-------------------------------------------------- internal func checkDefaultValue() { - if let _minValue = minValue, let _maxValue = maxValue { - defaultValue = defaultValue > _maxValue ? _maxValue : defaultValue < _minValue ? _minValue : defaultValue + if let minValue, let maxValue { + defaultValue = defaultIntValue > maxValue ? maxValue : defaultIntValue < minValue ? minValue : defaultIntValue } } internal func decrementButtonClick() { - defaultValue = defaultValue - 1 + defaultValue = defaultIntValue - 1 checkDefaultValue() updateButtonStates() } internal func incrementButtonClick() { - defaultValue = defaultValue + 1 + defaultValue = defaultIntValue + 1 checkDefaultValue() updateButtonStates() } @@ -339,8 +340,8 @@ open class InputStepper: EntryFieldBase { decrementButton.isEnabled = false incrementButton.isEnabled = false } else { - decrementButton.isEnabled = defaultValue > minValue ?? 0 ? true : false - incrementButton.isEnabled = defaultValue < maxValue ?? 99 ? true : false + decrementButton.isEnabled = defaultIntValue > minValue ?? 0 ? true : false + incrementButton.isEnabled = defaultIntValue < maxValue ?? 99 ? true : false } } @@ -406,4 +407,17 @@ open class InputStepper: EntryFieldBase { } } } + + private func updateStepperView() { + fieldStackView.removeConstraints() + fieldStackView.pinTop().pinLeading().pinBottom().pinTrailingLessThanOrEqualTo() + containerView.backgroundColor = .clear + containerView.layer.borderColor = nil + containerView.layer.borderWidth = 0 + containerView.layer.cornerRadius = 0 + fieldStackView.backgroundColor = containerBackgroundColor + fieldStackView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor + fieldStackView.layer.borderWidth = VDSFormControls.borderWidth + fieldStackView.layer.cornerRadius = containerView.frame.size.height / 2 + } } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 755b7ffa..6b30c169 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -233,7 +233,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { get { fatalError("must be read from subclass")} } -// open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } + open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } open var isRequired: Bool = false { didSet { setNeedsUpdate() } } @@ -356,7 +356,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open override func updateView() { super.updateView() updateRules() - updateContainerView(flag: true) + updateContainerView() updateContainerWidth() updateTitleLabel() updateErrorLabel() @@ -382,7 +382,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { transparentBackground = false width = nil inputId = nil -// defaultValue = nil + defaultValue = nil isRequired = false isReadOnly = false onChange = nil @@ -536,35 +536,13 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } } - internal func updateContainerView(flag: Bool) { - if flag { - containerView.backgroundColor = containerBackgroundColor - containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor - containerView.layer.borderWidth = VDSFormControls.borderWidth - containerView.layer.cornerRadius = VDSFormControls.borderRadius - } else { - containerView.backgroundColor = .clear - containerView.layer.borderColor = nil - containerView.layer.borderWidth = 0 - containerView.layer.cornerRadius = 0 - fieldStackView.backgroundColor = containerBackgroundColor - fieldStackView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor - fieldStackView.layer.borderWidth = VDSFormControls.borderWidth - fieldStackView.layer.cornerRadius = containerView.frame.size.height / 2 - } + internal func updateContainerView() { + containerView.backgroundColor = containerBackgroundColor + containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor + containerView.layer.borderWidth = VDSFormControls.borderWidth + containerView.layer.cornerRadius = VDSFormControls.borderRadius } - - /// Update constraints to containerStackView which has horizontal stack in which user interacts. - internal func updateConstraintsToFieldStackView(flag: Bool) { - fieldStackView.removeFromSuperview() - containerView.addSubview(fieldStackView) - if flag { - fieldStackView.pinToSuperView(.uniform(VDSLayout.space3X)) - } else { - fieldStackView.pinTop().pinLeading().pinBottom().pinTrailingLessThanOrEqualTo() - } - } - + internal func updateContainerWidth() { widthConstraint?.deactivate() trailingLessThanEqualsConstraint?.deactivate() diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 6f09f12a..a65df78e 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -371,7 +371,7 @@ open class InputField: EntryFieldBase { extension InputField: UITextFieldDelegate { open func textFieldDidBeginEditing(_ textField: UITextField) { fieldType.handler().textFieldDidBeginEditing(self, textField: textField) - updateContainerView(flag: true) + updateContainerView() updateErrorLabel() } From c32621330276a6b50b9c21e23bb3a868377474b9 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Jul 2024 12:24:14 -0500 Subject: [PATCH 12/41] initial generic entryfield Signed-off-by: Matt Bruce --- VDS/Components/DatePicker/DatePicker.swift | 2 +- .../DropdownSelect/DropdownSelect.swift | 2 +- .../InputStepper/InputStepper.swift | 32 ++++++++----------- .../TextFields/EntryFieldBase.swift | 19 +++++------ .../TextFields/InputField/InputField.swift | 2 +- .../TextFields/Rules/RequiredRule.swift | 8 +++-- .../TextFields/TextArea/TextArea.swift | 2 +- VDS/Protocols/FormFieldable.swift | 4 +-- 8 files changed, 32 insertions(+), 39 deletions(-) diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index df7cc7c9..06381fab 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -6,7 +6,7 @@ import Combine /// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection. @objcMembers @objc(VDSDatePicker) -open class DatePicker: EntryFieldBase { +open class DatePicker: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 947210f4..d0ef7275 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -13,7 +13,7 @@ import Combine /// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection. @objcMembers @objc(VDSDropdownSelect) -open class DropdownSelect: EntryFieldBase { +open class DropdownSelect: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 63288e96..afb93dcb 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 @@ -70,6 +71,8 @@ open class InputStepper: EntryFieldBase { /// Allows an id to be passed to input stepper. open var id: Int? { didSet { setNeedsUpdate() } } + open override var value: Int? { return defaultValue } + /// Maximum value of the input stepper, defaults to '99'. open var maxValue: Int? = 99 { didSet { @@ -101,20 +104,9 @@ 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 //-------------------------------------------------- - /// 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 - } - /// 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 { @@ -186,6 +178,7 @@ open class InputStepper: EntryFieldBase { super.setup() // Set initial states + defaultValue = 0 containerView.isEnabled = false statusIcon.isHidden = true @@ -227,7 +220,7 @@ open class InputStepper: EntryFieldBase { statusIcon.isHidden = true // Update label text, style, color, ande surface. - textLabel.text = String(defaultIntValue) + " " + (trailingText ?? "") + textLabel.text = "\(value ?? 0) " + (trailingText ?? "") textLabel.textStyle = size == .large ? .boldBodyLarge : .boldBodySmall textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() textLabel.surface = surface @@ -275,6 +268,7 @@ open class InputStepper: EntryFieldBase { controlWidthPercentage = nil widthPercentage = nil id = nil + defaultValue = 0 minValue = 0 maxValue = 99 trailingText = nil @@ -314,18 +308,18 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- internal func checkDefaultValue() { if let minValue, let maxValue { - defaultValue = defaultIntValue > maxValue ? maxValue : defaultIntValue < minValue ? minValue : defaultIntValue + defaultValue = defaultValue! > maxValue ? maxValue : defaultValue! < minValue ? minValue : defaultValue! } } internal func decrementButtonClick() { - defaultValue = defaultIntValue - 1 + defaultValue = defaultValue! - 1 checkDefaultValue() updateButtonStates() } internal func incrementButtonClick() { - defaultValue = defaultIntValue + 1 + defaultValue = defaultValue! + 1 checkDefaultValue() updateButtonStates() } @@ -340,8 +334,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! > minValue ?? 0 ? true : false + incrementButton.isEnabled = defaultValue! < maxValue ?? 99 ? true : false } } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 6b30c169..e492d6fa 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -11,10 +11,7 @@ import VDSCoreTokens import Combine /// Base Class used to build out a Input controls. -@objcMembers -@objc(VDSEntryField) -open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { - +open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -229,11 +226,11 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open var inputId: String? { didSet { setNeedsUpdate() } } /// The text of this textField. - open var value: String? { + open var value: ValueType? { get { fatalError("must be read from subclass")} } - open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } + open var defaultValue: ValueType? { didSet { setNeedsUpdate() } } open var isRequired: Bool = false { didSet { setNeedsUpdate() } } @@ -245,7 +242,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } } - open var rules = [AnyRule]() + open var rules = [AnyRule]() open var accessibilityHintText: String = "Double tap to open" @@ -342,8 +339,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } containerView.bridge_accessibilityValueBlock = { [weak self] in - guard let self else { return "" } - return value + guard let self, let value else { return "" } + return "\(value)" } statusIcon.bridge_accessibilityLabelBlock = { [weak self] in @@ -523,8 +520,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //-------------------------------------------------- internal func updateRules() { rules.removeAll() - if isRequired && useRequiredRule { - let rule = RequiredRule() + if isRequired && useRequiredRule && ValueType.self == String.self { + let rule = RequiredRule() if let errorText, !errorText.isEmpty { rule.errorMessage = errorText } else if let labelText{ diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index a65df78e..675fc6ac 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -15,7 +15,7 @@ import Combine /// dates and security codes in their correct formats. @objcMembers @objc(VDSInputField) -open class InputField: EntryFieldBase { +open class InputField: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers diff --git a/VDS/Components/TextFields/Rules/RequiredRule.swift b/VDS/Components/TextFields/Rules/RequiredRule.swift index df00bc59..d4296036 100644 --- a/VDS/Components/TextFields/Rules/RequiredRule.swift +++ b/VDS/Components/TextFields/Rules/RequiredRule.swift @@ -7,12 +7,14 @@ import Foundation -class RequiredRule: Rule { +class RequiredRule: Rule { var maxLength: Int? var errorMessage: String = "This field is required." - func isValid(value: String?) -> Bool { - guard let value, !value.isEmpty, value.count > 0 else { return false } + func isValid(value: ValueType?) -> Bool { + guard let value, + !"\(value)".isEmpty, + "\(value)".count > 0 else { return false } return true } } diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 07c79ca6..e9a714be 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -14,7 +14,7 @@ import Combine /// Use a text area when you want customers to enter text that’s longer than a single line. @objcMembers @objc(VDSTextArea) -open class TextArea: EntryFieldBase { +open class TextArea: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- diff --git a/VDS/Protocols/FormFieldable.swift b/VDS/Protocols/FormFieldable.swift index 82666772..98aa6ae8 100644 --- a/VDS/Protocols/FormFieldable.swift +++ b/VDS/Protocols/FormFieldable.swift @@ -8,7 +8,7 @@ import Foundation /// Protocol used for a FormField object. -public protocol FormFieldable { +public protocol FormFieldable { associatedtype ValueType = AnyHashable /// Unique Id for the Form Field object within a Form. @@ -19,7 +19,7 @@ public protocol FormFieldable { } /// Protocol for FormFieldable that require internal validation. -public protocol FormFieldInternalValidatable: FormFieldable, Errorable { +public protocol FormFieldInternalValidatable: FormFieldable, Errorable { /// Rules that drive the validator var rules: [AnyRule] { get set } From 46b11c2585ac1abe4df7c17f35390f845c359c00 Mon Sep 17 00:00:00 2001 From: Vasavi Kanamarlapudi Date: Wed, 31 Jul 2024 14:52:02 +0530 Subject: [PATCH 13/41] Digital ACT-191 ONEAPP-9311 story: refactored code and resolved constraint issues --- .../InputStepper/InputStepper.swift | 90 +++++++++++-------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 63288e96..37c82a88 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -37,21 +37,33 @@ open class InputStepper: EntryFieldBase { case large, small } + /// Enum used to describe the width of a fixed value or percentage of the input stepper control. + public enum ControlWidth { + case percentage(CGFloat) + case value(CGFloat) + } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - /// 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. - 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 + /// If there is a width that is larger than this size's minimumWidth, the input stepper will resize to this width. + open var controlWidth: ControlWidth? { + get { _controlWidth } + set { + if let newValue { + switch newValue { + case .percentage(let percentage): + if percentage <= 100.0 { + _controlWidth = newValue + } + case .value(let value): + if value > 0 && value > containerSize.width { + _controlWidth = newValue + } + } + } else { + _controlWidth = nil } - updateControlWidthPercentage() setNeedsUpdate() } } @@ -62,7 +74,6 @@ open class InputStepper: EntryFieldBase { if let percentage = widthPercentage, percentage > 100 { widthPercentage = 100 } - updatePercentageWidth() setNeedsUpdate() } } @@ -109,6 +120,8 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // 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 } @@ -236,8 +249,8 @@ open class InputStepper: EntryFieldBase { updateButtonStates() // Update stepper container border and corner radius. - setControlWidth(controlWidth) - updateControlWidthPercentage() + updateContainerWidthWithPercentage() + updateInputStepperWidth() updateStepperView() setNeedsLayout() } @@ -271,8 +284,7 @@ open class InputStepper: EntryFieldBase { super.reset() textLabel.reset() textLabel.textStyle = .boldBodyLarge - controlWidth = "auto" - controlWidthPercentage = nil + controlWidth = nil widthPercentage = nil id = nil minValue = 0 @@ -286,6 +298,7 @@ open class InputStepper: EntryFieldBase { // MARK: - Overrides //-------------------------------------------------- internal override func updateContainerWidth() { + stepperWidthConstraint?.deactivate() widthConstraint?.deactivate() trailingLessThanEqualsConstraint?.deactivate() trailingEqualsConstraint?.deactivate() @@ -361,17 +374,25 @@ open class InputStepper: EntryFieldBase { } // Set control width to input stepper. - private func setControlWidth(_ text: String?) { - if let text, text == "auto" { - stepperWidthConstraint?.deactivate() - } else if let controlWidth = Int(text ?? "") { - // Set controlWidth provided which is either pixel or percentage - let width = width ?? CGFloat(containerView.frame.size.width) - updateStepperContainerWidth(controlWidth: CGFloat(controlWidth), width: width) + private func updateInputStepperWidth() { + guard let controlWidth else { + return + } + + switch controlWidth { + case .percentage(let percentage): + // Set the inputStepper's controlWidth based on percentage received relative to its parentView's frame. + let superWidth = width ?? CGFloat(containerView.frame.size.width) + let value = max(superWidth * ((percentage) / 100), minWidth) + updateStepperContainerWidth(controlWidth: value, width: superWidth) + + case .value(let value): + let superWidth = width ?? CGFloat(containerView.frame.size.width) + updateStepperContainerWidth(controlWidth: value, width: superWidth) } } - // Handling the controlwidth without going beyond the width of the parent container. + // Handling the controlwidth without exceeding the width of the parent container. private func updateStepperContainerWidth(controlWidth: CGFloat, width: CGFloat) { if controlWidth >= containerSize.width && controlWidth <= width { stepperWidthConstraint?.deactivate() @@ -384,30 +405,21 @@ open class InputStepper: EntryFieldBase { } } - 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() { + // Update the container view width based on the percentage received. + private func updateContainerWidthWithPercentage() { 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() - } + // test value vs minimum width and take the greater value + width = max(superWidth * (widthPercentage / 100), minWidth) + updateContainerWidth() } } + // Add border and update constratints to stepper view. private func updateStepperView() { fieldStackView.removeConstraints() fieldStackView.pinTop().pinLeading().pinBottom().pinTrailingLessThanOrEqualTo() From 3ec2c984258b09d1e2552b238fb0323d364f4d58 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 31 Jul 2024 12:26:39 -0500 Subject: [PATCH 14/41] setup contentHugging and added more contraints to toggle when not in label mode Signed-off-by: Matt Bruce --- VDS/Components/Toggle/Toggle.swift | 61 +++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index 7cb4ef71..c147739b 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -55,6 +55,7 @@ open class Toggle: Control, Changeable, FormFieldable { private var leftConstraints: [NSLayoutConstraint] = [] private var rightConstraints: [NSLayoutConstraint] = [] private var labelConstraints: [NSLayoutConstraint] = [] + private var toggleConstraints: [NSLayoutConstraint] = [] //-------------------------------------------------- // MARK: - Configuration @@ -95,7 +96,7 @@ open class Toggle: Control, Changeable, FormFieldable { open var toggleView = ToggleView().with { $0.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) $0.isUserInteractionEnabled = false - $0.isAccessibilityElement = false + $0.isAccessibilityElement = false } /// Used in showing the on/off text. @@ -148,18 +149,6 @@ open class Toggle: Control, Changeable, FormFieldable { open var value: AnyHashable? { isOn } - /// The natural size for the receiving view, considering only properties of the view itself. - open override var intrinsicContentSize: CGSize { - if showLabel { - label.sizeToFit() - let size = CGSize(width: label.frame.width + spacingBetween + toggleContainerSize.width, - height: max(toggleContainerSize.height, label.frame.height)) - return size - } else { - return toggleContainerSize - } - } - open override var shouldHighlight: Bool { false } //-------------------------------------------------- @@ -208,6 +197,49 @@ open class Toggle: Control, Changeable, FormFieldable { label.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor) ] + // Set content hugging priority + setContentHuggingPriority(.required, for: .horizontal) + + isAccessibilityElement = true + if #available(iOS 17.0, *) { + accessibilityTraits = .toggleButton + } else { + accessibilityTraits = .button + } + addSubview(label) + addSubview(toggleView) + + // Set up initial constraints for label and switch + toggleView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + + //toggle + toggleConstraints = [ + toggleView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor), + toggleView.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor) + ] + + //toggle and label variants + labelConstraints = [ + height(constant: toggleContainerSize.height, priority: .defaultLow), + heightGreaterThanEqualTo(constant: toggleContainerSize.height, priority: .defaultHigh), + label.topAnchor.constraint(equalTo: topAnchor), + label.bottomAnchor.constraint(equalTo: bottomAnchor), + ] + + //label-toggle + leftConstraints = [ + label.leadingAnchor.constraint(equalTo: leadingAnchor), + toggleView.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: spacingBetween), + toggleView.trailingAnchor.constraint(equalTo: trailingAnchor) + ] + + //toggle-label + rightConstraints = [ + toggleView.leadingAnchor.constraint(equalTo: leadingAnchor), + label.leadingAnchor.constraint(equalTo: toggleView.trailingAnchor, constant: spacingBetween), + label.trailingAnchor.constraint(equalTo: trailingAnchor) + ] + bridge_accessibilityValueBlock = { [weak self] in guard let self else { return "" } if showText { @@ -261,6 +293,8 @@ open class Toggle: Control, Changeable, FormFieldable { label.isHidden = !showLabel if showLabel { + NSLayoutConstraint.deactivate(toggleConstraints) + label.textAlignment = textPosition == .left ? .right : .left label.textStyle = textStyle label.text = statusText @@ -279,6 +313,7 @@ open class Toggle: Control, Changeable, FormFieldable { NSLayoutConstraint.deactivate(leftConstraints) NSLayoutConstraint.deactivate(rightConstraints) NSLayoutConstraint.deactivate(labelConstraints) + NSLayoutConstraint.activate(toggleConstraints) } } } From 0d38eb495b2134833cb16d6fb21a69348dc481f4 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 1 Aug 2024 08:00:13 -0500 Subject: [PATCH 15/41] ensure that the horizontal plane of a label that has characters doesn't get crushed. Signed-off-by: Matt Bruce --- VDS/BaseClasses/Selector/SelectorItemBase.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index 44ed01b1..a15fbfbd 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -66,18 +66,21 @@ open class SelectorItemBase: Control, Errorable, Changea /// Label used to render labelText. open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.setContentCompressionResistancePriority(.required, for: .horizontal) $0.textStyle = .boldBodyLarge } /// Label used to render childText. open var childLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.setContentCompressionResistancePriority(.required, for: .horizontal) $0.textStyle = .bodyLarge } /// Label used to render errorText. open var errorLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.setContentCompressionResistancePriority(.required, for: .horizontal) $0.textStyle = .bodyMedium } From 417cddb382b187083e37c3b69346819fa39fd097 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 2 Aug 2024 16:38:31 -0500 Subject: [PATCH 16/41] 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() } } From 9fc100d3d6a3736f3a883d2c93992ed0d06eac76 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 2 Aug 2024 16:40:42 -0500 Subject: [PATCH 17/41] updated default Signed-off-by: Matt Bruce --- VDS/Components/TextFields/EntryFieldBase.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index e492d6fa..284a32b3 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -371,6 +371,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalVali errorLabel.textStyle = .bodySmall helperLabel.textStyle = .bodySmall + helperTextPlacement = .bottom labelText = nil helperText = nil showError = false From a024e1d5b32b920840f4fbec2ea5bb855e225727 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 2 Aug 2024 16:40:53 -0500 Subject: [PATCH 18/41] removed property Signed-off-by: Matt Bruce --- VDS/Components/InputStepper/InputStepper.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index e8980f0f..3637723d 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -102,9 +102,6 @@ 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 } @@ -305,16 +302,13 @@ open class InputStepper: EntryFieldBase { open override func reset() { super.reset() textLabel.reset() - textLabel.textStyle = .boldBodyLarge controlWidth = nil widthPercentage = nil - id = nil defaultValue = 0 minValue = _defaultMinValue maxValue = _defaultMaxValue trailingText = nil size = .large - helperTextPlacement = .bottom } //-------------------------------------------------- From 6938d918605b4e6e9c1aaba7f94f91bc7a6860df Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 7 Aug 2024 16:36:30 -0500 Subject: [PATCH 19/41] refactored a ton of code... Signed-off-by: Matt Bruce --- .../InputStepper/InputStepper.swift | 201 ++++++++---------- 1 file changed, 89 insertions(+), 112 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 3637723d..92730f20 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -138,12 +138,7 @@ open class InputStepper: EntryFieldBase { } /// The size of the input stepper. Defaults to 'large'. - open var size: Size = .large { - didSet { - updateStepperContainerViewSize() - setNeedsUpdate() - } - } + open var size: Size = .large { didSet { setNeedsUpdate() } } /// Accepts any text or character to appear next to input stepper value. open var trailingText: String? { didSet { setNeedsUpdate() } } @@ -205,10 +200,7 @@ open class InputStepper: EntryFieldBase { // MARK: - Configuration Properties //-------------------------------------------------- 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 //-------------------------------------------------- @@ -216,12 +208,19 @@ open class InputStepper: EntryFieldBase { /// 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 + //override the default settings since the containerView + //fieldStackView relationShip needs to be updated + //we are not applying spacing either in the edges since this + //is the view that will take place of the containerView for the + //design of the original "containerView". This will get refactored at + //some point. + fieldStackView.applyAlignment(.leading) + // Add listeners decrementButton.onClick = { _ in self.decrementButtonClick() } incrementButton.onClick = { _ in self.incrementButtonClick() } @@ -238,17 +237,15 @@ open class InputStepper: EntryFieldBase { // Set space between decrement button, label, and increment button relative to input Stepper size. stepperStackView.setCustomSpacing(size.space, after: decrementButton) stepperStackView.setCustomSpacing(size.space, after: textLabel) - - // Update Edge insets relative to input Stepper size. - stepperStackView.pinToSuperView(.uniform(size.padding)) - + // stepperContainerView for controls in EntryFieldBase.controlContainerView stepperContainerView.addSubview(stepperStackView) - stepperWidthConstraint = stepperContainerView.widthAnchor.constraint(equalToConstant: containerSize.width) - stepperWidthConstraint?.deactivate() - stepperHeightConstraint = stepperContainerView.heightAnchor.constraint(equalToConstant: containerSize.height) - stepperHeightConstraint?.deactivate() + // Update Edge insets relative to input Stepper size. + stepperStackView.pinToSuperView(.uniform(size.padding)) + + stepperWidthConstraint = stepperContainerView.width(constant: containerSize.width, priority: .required) + stepperHeightConstraint = stepperContainerView.height(constant: containerSize.height, priority: .required) return stepperContainerView } @@ -259,19 +256,12 @@ open class InputStepper: EntryFieldBase { statusIcon.isHidden = true // Update label text, style, color, ande surface. + textLabel.isEnabled = isEnabled + textLabel.surface = surface textLabel.text = "\(_defaultValue) " + (trailingText ?? "") textLabel.textStyle = size.textStyle - textLabel.textColorConfiguration = !isEnabled ? labelDisabledColorConfiguration.eraseToAnyColorable() : labelColorConfiguration.eraseToAnyColorable() - textLabel.surface = surface - // Update increment and decrement button. updateButtonStates() - - // Update stepper container border and corner radius. - updateContainerWidthWithPercentage() - updateInputStepperWidth() - updateStepperView() - setNeedsLayout() } open override var accessibilityElements: [Any]? { @@ -314,29 +304,89 @@ open class InputStepper: EntryFieldBase { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + override func updateContainerView() { + //we are not calling super since we + //are using the fieldStackView as the "containerView" + //which will get the look/feel of the containerView. + //this will get refactored in the future. + fieldStackView.backgroundColor = containerBackgroundColor + fieldStackView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor + fieldStackView.layer.borderWidth = VDSFormControls.borderWidth + } + internal override func updateContainerWidth() { + + defer { + fieldStackView.layer.cornerRadius = containerSize.height / 2 + } + + //we are not calling super here since + //we are changing how the widths are getting calculated + //now by including a percentage. stepperWidthConstraint?.deactivate() widthConstraint?.deactivate() trailingLessThanEqualsConstraint?.deactivate() trailingEqualsConstraint?.deactivate() + + var widthConstraintConstant: CGFloat? - if let width, width >= minWidth, width <= maxWidth { - widthConstraint?.constant = width - widthConstraint?.activate() - trailingLessThanEqualsConstraint?.activate() + if let widthPercentage, let superWidth = horizontalPinnedWidth() { + // test value vs minimum width and take the greater value + widthConstraintConstant = max(superWidth * (widthPercentage / 100), minWidth) + } else if let width, width >= minWidth, width <= maxWidth { + widthConstraintConstant = width } else if let parentWidth = width, parentWidth >= maxWidth { - width = maxWidth - widthConstraint?.constant = maxWidth - widthConstraint?.activate() - trailingLessThanEqualsConstraint?.activate() + widthConstraintConstant = maxWidth } else if let parentWidth = width, parentWidth <= minWidth { - width = minWidth - widthConstraint?.constant = minWidth + widthConstraintConstant = minWidth + } + + if let widthConstraintConstant { + widthConstraint?.constant = widthConstraintConstant widthConstraint?.activate() trailingLessThanEqualsConstraint?.activate() } else { trailingEqualsConstraint?.activate() } + + // Update Edge insets if size changes applied. + stepperStackView.applyAlignment(.fill, edges: .uniform(size.padding)) + + // Update height if size changes applied. + stepperHeightConstraint?.constant = containerSize.height + + //update the stepper's widthConstraint if + //controlWidth was set + guard let controlWidth else { + return + } + + var stepperWidthConstant: CGFloat? + var stepperWidth: CGFloat + var containerWidth: CGFloat + + switch controlWidth { + case .percentage(let percentage): + // Set the inputStepper's controlWidth based on percentage received relative to its parentView's frame. + containerWidth = widthConstraintConstant ?? CGFloat(containerView.frame.size.width) + stepperWidth = max(containerWidth * ((percentage) / 100), minWidth) + + case .value(let value): + containerWidth = widthConstraintConstant ?? CGFloat(containerView.frame.size.width) + stepperWidth = value + } + + //get the value of the stepperWidthConstant + if stepperWidth >= containerSize.width && stepperWidth <= containerWidth { + stepperWidthConstant = stepperWidth + } else if stepperWidth >= containerWidth { + stepperWidthConstant = containerWidth + } + + if let stepperWidthConstant { + stepperWidthConstraint?.constant = stepperWidthConstant + stepperWidthConstraint?.activate() + } } //-------------------------------------------------- @@ -370,78 +420,5 @@ open class InputStepper: EntryFieldBase { incrementButton.isEnabled = (defaultValue ?? _defaultMinValue) < maxValue ? true : false } } - - // Update edge insets and height when size changes. - internal func updateStepperContainerViewSize() { - updateButtonStates() - - // Update Edge insets if size changes applied. - stepperStackView.removeFromSuperview() - stepperContainerView.addSubview(stepperStackView) - stepperStackView.pinToSuperView(.uniform(size.padding)) - - // Update height if size changes applied. - stepperHeightConstraint?.deactivate() - stepperHeightConstraint = stepperContainerView.heightAnchor.constraint(equalToConstant: containerSize.height) - stepperHeightConstraint?.activate() - } - - // Set control width to input stepper. - private func updateInputStepperWidth() { - guard let controlWidth else { - return - } - - switch controlWidth { - case .percentage(let percentage): - // Set the inputStepper's controlWidth based on percentage received relative to its parentView's frame. - let superWidth = width ?? CGFloat(containerView.frame.size.width) - let value = max(superWidth * ((percentage) / 100), minWidth) - updateStepperContainerWidth(controlWidth: value, width: superWidth) - - case .value(let value): - let superWidth = width ?? CGFloat(containerView.frame.size.width) - updateStepperContainerWidth(controlWidth: value, width: superWidth) - } - } - - // Handling the controlwidth without exceeding the width of the parent container. - private func updateStepperContainerWidth(controlWidth: CGFloat, width: CGFloat) { - if controlWidth >= containerSize.width && controlWidth <= width { - stepperWidthConstraint?.deactivate() - stepperWidthConstraint?.constant = controlWidth - stepperWidthConstraint?.activate() - } else if controlWidth >= width { - stepperWidthConstraint?.deactivate() - stepperWidthConstraint?.constant = width - stepperWidthConstraint?.activate() - } - } - - // Update the container view width based on the percentage received. - private func updateContainerWidthWithPercentage() { - guard let superWidth = horizontalPinnedWidth() else { - return - } - - // Set width of Parent container based on width perecentage received relative to its superview frame. - if let widthPercentage { - // test value vs minimum width and take the greater value - width = max(superWidth * (widthPercentage / 100), minWidth) - } - } - - // Add border and update constratints to stepper view. - private func updateStepperView() { - fieldStackView.removeConstraints() - fieldStackView.pinTop().pinLeading().pinBottom().pinTrailingLessThanOrEqualTo() - containerView.backgroundColor = .clear - containerView.layer.borderColor = nil - containerView.layer.borderWidth = 0 - containerView.layer.cornerRadius = 0 - fieldStackView.backgroundColor = containerBackgroundColor - fieldStackView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor - fieldStackView.layer.borderWidth = VDSFormControls.borderWidth - fieldStackView.layer.cornerRadius = containerView.frame.size.height / 2 - } + } From cbdd82ee31a10c6c7e1d8ba0662aa38a49a3518c Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 7 Aug 2024 16:37:38 -0500 Subject: [PATCH 20/41] updated comments Signed-off-by: Matt Bruce --- VDS/Components/InputStepper/InputStepper.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 92730f20..11fde045 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -255,7 +255,7 @@ open class InputStepper: EntryFieldBase { super.updateView() statusIcon.isHidden = true - // Update label text, style, color, ande surface. + // Update label textLabel.isEnabled = isEnabled textLabel.surface = surface textLabel.text = "\(_defaultValue) " + (trailingText ?? "") From 6c4fb1c5ba01ce1475053fdd6d4828ca1a992ff8 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 7 Aug 2024 16:42:19 -0500 Subject: [PATCH 21/41] moved code up to 1 point rather than duplicating Signed-off-by: Matt Bruce --- VDS/Components/InputStepper/InputStepper.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 11fde045..9302d0ec 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -361,18 +361,16 @@ open class InputStepper: EntryFieldBase { return } + // Set the inputStepper's controlWidth based on percentage received relative to its parentView's frame. + let containerWidth: CGFloat = widthConstraintConstant ?? containerView.frame.size.width var stepperWidthConstant: CGFloat? var stepperWidth: CGFloat - var containerWidth: CGFloat switch controlWidth { case .percentage(let percentage): - // Set the inputStepper's controlWidth based on percentage received relative to its parentView's frame. - containerWidth = widthConstraintConstant ?? CGFloat(containerView.frame.size.width) stepperWidth = max(containerWidth * ((percentage) / 100), minWidth) case .value(let value): - containerWidth = widthConstraintConstant ?? CGFloat(containerView.frame.size.width) stepperWidth = value } From d4e7d7476d114fd1ccd64bd5f5b3903e9fa954de Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 7 Aug 2024 16:43:14 -0500 Subject: [PATCH 22/41] rearranged comments Signed-off-by: Matt Bruce --- VDS/Components/InputStepper/InputStepper.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/VDS/Components/InputStepper/InputStepper.swift b/VDS/Components/InputStepper/InputStepper.swift index 9302d0ec..6c44b58f 100644 --- a/VDS/Components/InputStepper/InputStepper.swift +++ b/VDS/Components/InputStepper/InputStepper.swift @@ -315,14 +315,14 @@ open class InputStepper: EntryFieldBase { } internal override func updateContainerWidth() { - + //we are not calling super here since + //we are changing how the widths are getting calculated + //now by including a percentage. + defer { fieldStackView.layer.cornerRadius = containerSize.height / 2 } - //we are not calling super here since - //we are changing how the widths are getting calculated - //now by including a percentage. stepperWidthConstraint?.deactivate() widthConstraint?.deactivate() trailingLessThanEqualsConstraint?.deactivate() From 1e9aa876dbe77b303c6cd5fc8024da5b9a0d1de3 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 8 Aug 2024 10:59:30 -0500 Subject: [PATCH 23/41] refactor for use in both UIControl and UIView Signed-off-by: Matt Bruce --- VDS/Protocols/Clickable.swift | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/VDS/Protocols/Clickable.swift b/VDS/Protocols/Clickable.swift index c2fc9056..fe6ff10d 100644 --- a/VDS/Protocols/Clickable.swift +++ b/VDS/Protocols/Clickable.swift @@ -9,12 +9,12 @@ import Foundation import UIKit import Combine -public protocol Clickable: ViewProtocol where Self: UIControl { +public protocol Clickable: ViewProtocol { /// Sets the primary Subscriber used for the UIControl event .touchUpInside. var onClickSubscriber: AnyCancellable? { get set } } -extension Clickable { +extension Clickable where Self: UIControl { /// Allows the setting of a completion block against the onClickSubscriber cancellable. This will /// completion block will get executed against the UIControl publisher for the 'touchUpInside' action. public var onClick: ((Self) -> ())? { @@ -23,7 +23,7 @@ extension Clickable { onClickSubscriber?.cancel() if let newValue { onClickSubscriber = publisher(for: .touchUpInside) - .sink { [weak self] c in + .sink { [weak self] c in guard let self, self.isEnabled else { return } newValue(c) } @@ -34,3 +34,24 @@ extension Clickable { } } } + +extension Clickable where Self: UIView { + /// Allows the setting of a completion block against the onClickSubscriber cancellable. This will + /// completion block will get executed against the UIControl publisher for the 'touchUpInside' action. + public var onClick: ((Self) -> ())? { + get { return nil } + set { + onClickSubscriber?.cancel() + if let newValue { + onClickSubscriber = publisher(for: UITapGestureRecognizer()) + .sink { [weak self] _ in + guard let self, self.isEnabled else { return } + newValue(self) + } + } else { + onClickSubscriber = nil + } + setNeedsUpdate() + } + } +} From 7e36bc074a04235f3c67f6b5955b828a0b941e2e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 8 Aug 2024 10:59:45 -0500 Subject: [PATCH 24/41] added clickable Signed-off-by: Matt Bruce --- VDS/BaseClasses/View.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/VDS/BaseClasses/View.swift b/VDS/BaseClasses/View.swift index 88996ba6..8012c5aa 100644 --- a/VDS/BaseClasses/View.swift +++ b/VDS/BaseClasses/View.swift @@ -12,7 +12,7 @@ import Combine /// Base Class used to build Views. @objcMembers @objc(VDSView) -open class View: UIView, ViewProtocol, UserInfoable { +open class View: UIView, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Initializers @@ -37,6 +37,7 @@ open class View: UIView, ViewProtocol, UserInfoable { //-------------------------------------------------- open var subscribers = Set() + open var onClickSubscriber: AnyCancellable? //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- From e0d769ccf3cb332c821fec3c9ab2deb87906d1f7 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 8 Aug 2024 11:00:02 -0500 Subject: [PATCH 25/41] refactored to now use the onClick Signed-off-by: Matt Bruce --- VDS/Components/DatePicker/DatePicker.swift | 13 +++++-------- VDS/Components/DropdownSelect/DropdownSelect.swift | 9 +++------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index df7cc7c9..d65465b7 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -154,15 +154,12 @@ open class DatePicker: EntryFieldBase { selectedDateLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() // tap gesture - containerView - .publisher(for: UITapGestureRecognizer()) - .sink { [weak self] _ in - guard let self else { return } - if isEnabled && !isReadOnly { - showPopover() - } + containerView.onClick = { [weak self] _ in + guard let self else { return } + if isEnabled && !isReadOnly { + showPopover() } - .store(in: &subscribers) + } NotificationCenter.default .publisher(for: UIDevice.orientationDidChangeNotification).sink { [weak self] _ in diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 947210f4..f0dc8084 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -153,12 +153,9 @@ open class DropdownSelect: EntryFieldBase { }() // tap gesture - containerView - .publisher(for: UITapGestureRecognizer()) - .sink { [weak self] _ in - self?.launchPicker() - } - .store(in: &subscribers) + containerView.onClick = { [weak self] _ in + self?.launchPicker() + } containerView.height(44) } From 0434b3f63ec207f22bfda1369243773acf6fc45a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 8 Aug 2024 11:00:33 -0500 Subject: [PATCH 26/41] refactored to a View instead of Control implemented isHighlighted Signed-off-by: Matt Bruce --- .../TileContainer/TileContainer.swift | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index f35d2614..cdfe675a 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -44,7 +44,7 @@ open class TileContainer: TileContainerBase { } } -open class TileContainerBase: Control where PaddingType.ValueType == CGFloat { +open class TileContainerBase: View where PaddingType.ValueType == CGFloat { //-------------------------------------------------- // MARK: - Initializers @@ -118,6 +118,8 @@ open class TileContainerBase: Control where Padding $0.setContentCompressionResistancePriority(.defaultHigh, for: .vertical) } + private var isHighlighted: Bool = false { didSet { setNeedsUpdate() } } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -337,6 +339,27 @@ open class TileContainerBase: Control where Padding set {} } + open override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + if let onClickSubscriber { + isHighlighted = true + } + } + + open override func touchesEnded(_ touches: Set, with event: UIEvent?) { + super.touchesEnded(touches, with: event) + if let onClickSubscriber { + isHighlighted = false + } + } + + open override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + super.touchesCancelled(touches, with: event) + if let onClickSubscriber { + isHighlighted = false + } + } + //-------------------------------------------------- // MARK: - Public Methods //-------------------------------------------------- From 317cf89fb6b1fcb2ef7827b8c8052653162d0f09 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 11:21:51 -0500 Subject: [PATCH 27/41] ensure updateView() can't be called until setup() is run Signed-off-by: Matt Bruce --- VDS/BaseClasses/Control.swift | 2 ++ VDS/BaseClasses/View.swift | 2 ++ VDS/Components/Buttons/ButtonBase.swift | 2 ++ VDS/Components/Label/Label.swift | 2 ++ VDS/Components/TextFields/InputField/TextField.swift | 2 ++ VDS/Components/TextFields/TextArea/TextView.swift | 2 ++ 6 files changed, 12 insertions(+) diff --git a/VDS/BaseClasses/Control.swift b/VDS/BaseClasses/Control.swift index 472f0635..0dcaa3f1 100644 --- a/VDS/BaseClasses/Control.swift +++ b/VDS/BaseClasses/Control.swift @@ -81,7 +81,9 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { open func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true + shouldUpdateView = false setup() + shouldUpdateView = true setNeedsUpdate() } } diff --git a/VDS/BaseClasses/View.swift b/VDS/BaseClasses/View.swift index 88996ba6..b39afbf2 100644 --- a/VDS/BaseClasses/View.swift +++ b/VDS/BaseClasses/View.swift @@ -60,7 +60,9 @@ open class View: UIView, ViewProtocol, UserInfoable { open func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true + shouldUpdateView = false setup() + shouldUpdateView = true setNeedsUpdate() } } diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index c764b89b..b210560a 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -103,7 +103,9 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false accessibilityCustomActions = [] + shouldUpdateView = false setup() + shouldUpdateView = true setNeedsUpdate() } } diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index f420be7d..3d56470b 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -209,7 +209,9 @@ open class Label: UILabel, ViewProtocol, UserInfoable { isAccessibilityElement = true accessibilityTraits = .staticText textAlignment = .left + shouldUpdateView = false setup() + shouldUpdateView = true setNeedsUpdate() } } diff --git a/VDS/Components/TextFields/InputField/TextField.swift b/VDS/Components/TextFields/InputField/TextField.swift index 3fdf308f..7adf1aa0 100644 --- a/VDS/Components/TextFields/InputField/TextField.swift +++ b/VDS/Components/TextFields/InputField/TextField.swift @@ -105,7 +105,9 @@ open class TextField: UITextField, ViewProtocol, Errorable { translatesAutoresizingMaskIntoConstraints = false setContentCompressionResistancePriority(.defaultLow, for: .horizontal) clipsToBounds = true + shouldUpdateView = false setup() + shouldUpdateView = true setNeedsUpdate() } } diff --git a/VDS/Components/TextFields/TextArea/TextView.swift b/VDS/Components/TextFields/TextArea/TextView.swift index 63356635..526911c4 100644 --- a/VDS/Components/TextFields/TextArea/TextView.swift +++ b/VDS/Components/TextFields/TextArea/TextView.swift @@ -112,7 +112,9 @@ open class TextView: UITextView, ViewProtocol, Errorable { initialSetupPerformed = true backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false + shouldUpdateView = false setup() + shouldUpdateView = true setNeedsUpdate() } } From f713cc0659c1d6330ff67847ba1779bdcc443c77 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 11:22:26 -0500 Subject: [PATCH 28/41] CXTDT-599736 - Unable to turn off the Toggles for Privacy preferences Signed-off-by: Matt Bruce --- VDS/Components/Toggle/Toggle.swift | 19 +++++++++---------- VDS/Components/Toggle/ToggleView.swift | 15 +++++++-------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index c147739b..e4390683 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -153,19 +153,18 @@ open class Toggle: Control, Changeable, FormFieldable { //-------------------------------------------------- // MARK: - Overrides - //-------------------------------------------------- - /// Executed on initialization for this View. - open override func initialSetup() { - super.initialSetup() - onClick = { control in - control.toggle() - } - } - + //-------------------------------------------------- /// 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() - + + publisher(for: .touchUpInside) + .sink(receiveValue: { [weak self] _ in + guard let self else { return } + toggle() + }) + .store(in: &subscribers) + isAccessibilityElement = true if #available(iOS 17.0, *) { accessibilityTraits = .toggleButton diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index 9274be1a..a0dbcda4 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -105,17 +105,16 @@ open class ToggleView: Control, Changeable, FormFieldable { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - /// Executed on initialization for this View. - open override func initialSetup() { - super.initialSetup() - onClick = { control in - control.toggle() - } - } - /// 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() + + publisher(for: .touchUpInside) + .sink(receiveValue: { [weak self] _ in + guard let self else { return } + toggle() + }) + .store(in: &subscribers) isAccessibilityElement = true if #available(iOS 17.0, *) { From 9f6a83f8ce6c978900417c11f56b2c90349013ae Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 11:23:53 -0500 Subject: [PATCH 29/41] ensure isEnabled Signed-off-by: Matt Bruce --- VDS/Components/Toggle/Toggle.swift | 2 +- VDS/Components/Toggle/ToggleView.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index e4390683..29f7dd6d 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -160,7 +160,7 @@ open class Toggle: Control, Changeable, FormFieldable { publisher(for: .touchUpInside) .sink(receiveValue: { [weak self] _ in - guard let self else { return } + guard let self, isEnabled else { return } toggle() }) .store(in: &subscribers) diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index a0dbcda4..fb663e99 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -111,7 +111,7 @@ open class ToggleView: Control, Changeable, FormFieldable { publisher(for: .touchUpInside) .sink(receiveValue: { [weak self] _ in - guard let self else { return } + guard let self, isEnabled else { return } toggle() }) .store(in: &subscribers) From eb8edd2acd7b95a4787cb9273e130a0a847b4bca Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 11:51:40 -0500 Subject: [PATCH 30/41] removed initialSetup so as devs won't use this method anymore, this will now be private to the base classes Signed-off-by: Matt Bruce --- VDS/Protocols/ViewProtocol.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/VDS/Protocols/ViewProtocol.swift b/VDS/Protocols/ViewProtocol.swift index c7cba091..695386cb 100644 --- a/VDS/Protocols/ViewProtocol.swift +++ b/VDS/Protocols/ViewProtocol.swift @@ -19,9 +19,6 @@ public protocol ViewProtocol: AnyObject, Initable, Resettable, Enabling, Surface /// Used for setting an implementation for the default Accessible Action var accessibilityAction: ((Self) -> Void)? { get set } - /// Executed on initialization for this View. - func initialSetup() - /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. func setup() From 760433243eb04db671a6488fd81329abaeedec36 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 11:52:25 -0500 Subject: [PATCH 31/41] updated to private methods Signed-off-by: Matt Bruce --- VDS/BaseClasses/Control.swift | 2 +- VDS/BaseClasses/View.swift | 2 +- VDS/Components/Buttons/ButtonBase.swift | 8 ++--- VDS/Components/Label/Label.swift | 30 +++++++++---------- .../TextFields/InputField/TextField.swift | 11 +++---- .../TextFields/TextArea/TextView.swift | 7 +++-- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/VDS/BaseClasses/Control.swift b/VDS/BaseClasses/Control.swift index 0dcaa3f1..ad138db9 100644 --- a/VDS/BaseClasses/Control.swift +++ b/VDS/BaseClasses/Control.swift @@ -78,7 +78,7 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - open func initialSetup() { + private func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true shouldUpdateView = false diff --git a/VDS/BaseClasses/View.swift b/VDS/BaseClasses/View.swift index b39afbf2..b8acb096 100644 --- a/VDS/BaseClasses/View.swift +++ b/VDS/BaseClasses/View.swift @@ -57,7 +57,7 @@ open class View: UIView, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - open func initialSetup() { + private func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true shouldUpdateView = false diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index b210560a..8af0ee68 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -97,12 +97,9 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - open func initialSetup() { + private func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true - backgroundColor = .clear - translatesAutoresizingMaskIntoConstraints = false - accessibilityCustomActions = [] shouldUpdateView = false setup() shouldUpdateView = true @@ -112,8 +109,9 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { open func setup() { + backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false - + accessibilityCustomActions = [] titleLabel?.adjustsFontSizeToFitWidth = false titleLabel?.lineBreakMode = .byTruncatingTail titleLabel?.numberOfLines = 1 diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 3d56470b..5930dea7 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -192,23 +192,9 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - open func initialSetup() { + private func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true - //register for ContentSizeChanges - NotificationCenter - .Publisher(center: .default, name: UIContentSizeCategory.didChangeNotification) - .sink { [weak self] notification in - self?.setNeedsUpdate() - }.store(in: &subscribers) - backgroundColor = .clear - numberOfLines = 0 - lineBreakMode = .byTruncatingTail - translatesAutoresizingMaskIntoConstraints = false - accessibilityCustomActions = [] - isAccessibilityElement = true - accessibilityTraits = .staticText - textAlignment = .left shouldUpdateView = false setup() shouldUpdateView = true @@ -217,6 +203,20 @@ open class Label: UILabel, ViewProtocol, UserInfoable { } open func setup() { + //register for ContentSizeChanges + NotificationCenter + .Publisher(center: .default, name: UIContentSizeCategory.didChangeNotification) + .sink { [weak self] notification in + self?.setNeedsUpdate() + }.store(in: &subscribers) + backgroundColor = .clear + numberOfLines = 0 + lineBreakMode = .byTruncatingTail + translatesAutoresizingMaskIntoConstraints = false + accessibilityCustomActions = [] + isAccessibilityElement = true + accessibilityTraits = .staticText + textAlignment = .left } open func reset() { diff --git a/VDS/Components/TextFields/InputField/TextField.swift b/VDS/Components/TextFields/InputField/TextField.swift index 7adf1aa0..2f6ddb1a 100644 --- a/VDS/Components/TextFields/InputField/TextField.swift +++ b/VDS/Components/TextFields/InputField/TextField.swift @@ -98,13 +98,9 @@ open class TextField: UITextField, ViewProtocol, Errorable { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - open func initialSetup() { + private func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true - backgroundColor = .clear - translatesAutoresizingMaskIntoConstraints = false - setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - clipsToBounds = true shouldUpdateView = false setup() shouldUpdateView = true @@ -113,6 +109,11 @@ open class TextField: UITextField, ViewProtocol, Errorable { } open func setup() { + backgroundColor = .clear + translatesAutoresizingMaskIntoConstraints = false + setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + clipsToBounds = true + let accessView = UIView(frame: .init(origin: .zero, size: .init(width: UIScreen.main.bounds.width, height: 44))) accessView.backgroundColor = .white accessView.addBorder(side: .top, width: 1, color: .lightGray) diff --git a/VDS/Components/TextFields/TextArea/TextView.swift b/VDS/Components/TextFields/TextArea/TextView.swift index 526911c4..575c2da8 100644 --- a/VDS/Components/TextFields/TextArea/TextView.swift +++ b/VDS/Components/TextFields/TextArea/TextView.swift @@ -107,11 +107,9 @@ open class TextView: UITextView, ViewProtocol, Errorable { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - open func initialSetup() { + private func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true - backgroundColor = .clear - translatesAutoresizingMaskIntoConstraints = false shouldUpdateView = false setup() shouldUpdateView = true @@ -120,6 +118,9 @@ open class TextView: UITextView, ViewProtocol, Errorable { } open func setup() { + backgroundColor = .clear + translatesAutoresizingMaskIntoConstraints = false + let accessView = UIView(frame: .init(origin: .zero, size: .init(width: UIScreen.main.bounds.width, height: 44))) accessView.backgroundColor = .white accessView.addBorder(side: .top, width: 1, color: .lightGray) From c2c88c7b90d2bc34780e33383348c3e7d0727887 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 11:57:28 -0500 Subject: [PATCH 32/41] moved to setup Signed-off-by: Matt Bruce --- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 4 ++-- VDS/Components/Calendar/Calendar.swift | 4 ---- VDS/Components/Carousel/Carousel.swift | 5 ----- VDS/Components/CarouselScrollbar/CarouselScrollbar.swift | 4 ---- VDS/Components/Pagination/Pagination.swift | 4 ++-- VDS/Components/Pagination/PaginationButton.swift | 4 ++-- VDS/Components/Table/Table.swift | 4 ++-- 7 files changed, 8 insertions(+), 21 deletions(-) diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index 5a2de7d0..6c45383d 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -109,8 +109,8 @@ open class Breadcrumbs: View { // MARK: - Overrides //-------------------------------------------------- /// Executed on initialization for this View. - open override func initialSetup() { - super.initialSetup() + open override func setup() { + super.setup() containerView.addSubview(collectionView) collectionView.pinToSuperView() addSubview(containerView) diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index bed772d8..e7c2cb20 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -125,10 +125,6 @@ open class CalendarBase: Control, Changeable { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - 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() diff --git a/VDS/Components/Carousel/Carousel.swift b/VDS/Components/Carousel/Carousel.swift index d1624253..766a7a70 100644 --- a/VDS/Components/Carousel/Carousel.swift +++ b/VDS/Components/Carousel/Carousel.swift @@ -196,11 +196,6 @@ open class Carousel: View { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - /// Executed on initialization for this View. - 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() diff --git a/VDS/Components/CarouselScrollbar/CarouselScrollbar.swift b/VDS/Components/CarouselScrollbar/CarouselScrollbar.swift index f171c395..8a4d4a50 100644 --- a/VDS/Components/CarouselScrollbar/CarouselScrollbar.swift +++ b/VDS/Components/CarouselScrollbar/CarouselScrollbar.swift @@ -235,10 +235,6 @@ open class CarouselScrollbar: View { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - open override func initialSetup() { - super.initialSetup() - } - open override func setup() { super.setup() isAccessibilityElement = false diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift index 02c1e85e..6234e155 100644 --- a/VDS/Components/Pagination/Pagination.swift +++ b/VDS/Components/Pagination/Pagination.swift @@ -95,8 +95,8 @@ open class Pagination: View { // MARK: - Overrides //-------------------------------------------------- /// Executed on initialization for this View. - open override func initialSetup() { - super.initialSetup() + open override func setup() { + super.setup() collectionContainerView.addSubview(collectionView) containerView.addSubview(previousButton) diff --git a/VDS/Components/Pagination/PaginationButton.swift b/VDS/Components/Pagination/PaginationButton.swift index d5de6e3f..14f399b9 100644 --- a/VDS/Components/Pagination/PaginationButton.swift +++ b/VDS/Components/Pagination/PaginationButton.swift @@ -60,8 +60,8 @@ open class PaginationButton: ButtonBase { // MARK: - Overrides //-------------------------------------------------- /// Executed on initialization for this View. - open override func initialSetup() { - super.initialSetup() + open override func setup() { + super.setup() if #available(iOS 15.0, *) { configuration = buttonConfiguration } else { diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index bb599545..95873d33 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -92,8 +92,8 @@ open class Table: View { //-------------------------------------------------- ///Called upon initializing the table view - open override func initialSetup() { - super.initialSetup() + open override func setup() { + super.setup() addSubview(matrixView) matrixView.pinToSuperView() } From 0decdb5a1685189f0fc9f5435ebec1015ba2f8b2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 13:19:33 -0500 Subject: [PATCH 33/41] add the touchUpInside since this is the only one using this Signed-off-by: Matt Bruce --- .../Icon/ButtonIcon/ButtonIcon.swift | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index bf8a50f7..95406fb4 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -402,17 +402,15 @@ open class ButtonIcon: Control, Changeable { centerXConstraint?.activate() centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0) centerYConstraint?.activate() - } - - /// Executed on initialization for this View. - open override func initialSetup() { - super.initialSetup() - onClick = { control in - guard control.isEnabled else { return } - if control.selectedIconName != nil && control.selectable { - control.toggle() - } - } + + publisher(for: .touchUpInside) + .sink(receiveValue: { [weak self] _ in + guard let self, isEnabled, + selectedIconName != nil, + selectable else { return } + toggle() + }) + .store(in: &subscribers) } /// This will change the state of the Selector and execute the actionBlock if provided. From 09886ffe26efec41de21a7c76f9cda091820f055 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 14:35:51 -0500 Subject: [PATCH 34/41] added setDefaults() into protocol and implemented Signed-off-by: Matt Bruce --- VDS/BaseClasses/Control.swift | 23 ++++++++++++------- VDS/BaseClasses/View.swift | 16 +++++++++---- VDS/Components/Buttons/ButtonBase.swift | 18 +++++++++------ VDS/Components/Label/Label.swift | 20 ++++++++-------- .../TextFields/InputField/TextField.swift | 16 ++++++++++--- .../TextFields/TextArea/TextView.swift | 14 ++++++++--- VDS/Protocols/ViewProtocol.swift | 5 +++- 7 files changed, 77 insertions(+), 35 deletions(-) diff --git a/VDS/BaseClasses/Control.swift b/VDS/BaseClasses/Control.swift index ad138db9..7ebe3824 100644 --- a/VDS/BaseClasses/Control.swift +++ b/VDS/BaseClasses/Control.swift @@ -83,17 +83,25 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { initialSetupPerformed = true shouldUpdateView = false setup() + setDefaults() shouldUpdateView = true setNeedsUpdate() } } open func setup() { - backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false insetsLayoutMarginsFromSafeArea = false } - + + open func setDefaults() { + backgroundColor = .clear + surface = .light + isEnabled = true + onClick = nil + userInfo.removeAll() + } + open func updateView() { } open func updateAccessibility() { @@ -110,13 +118,12 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { } } - + open func reset() { - backgroundColor = .clear - surface = .light - isEnabled = true - onClick = nil - userInfo.removeAll() + shouldUpdateView = false + setDefaults() + shouldUpdateView = true + setNeedsUpdate() } //-------------------------------------------------- diff --git a/VDS/BaseClasses/View.swift b/VDS/BaseClasses/View.swift index b8acb096..911daa69 100644 --- a/VDS/BaseClasses/View.swift +++ b/VDS/BaseClasses/View.swift @@ -62,17 +62,24 @@ open class View: UIView, ViewProtocol, UserInfoable { initialSetupPerformed = true shouldUpdateView = false setup() + setDefaults() shouldUpdateView = true setNeedsUpdate() } } open func setup() { - backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false insetsLayoutMarginsFromSafeArea = false } + open func setDefaults() { + backgroundColor = .clear + surface = .light + isEnabled = true + userInfo.removeAll() + } + open func updateView() { } open func updateAccessibility() { @@ -84,9 +91,10 @@ open class View: UIView, ViewProtocol, UserInfoable { } open func reset() { - backgroundColor = .clear - surface = .light - isEnabled = true + shouldUpdateView = false + setDefaults() + shouldUpdateView = true + setNeedsUpdate() } open override func layoutSubviews() { diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index 8af0ee68..b555218d 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -102,6 +102,7 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { initialSetupPerformed = true shouldUpdateView = false setup() + setDefaults() shouldUpdateView = true setNeedsUpdate() } @@ -109,12 +110,20 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { open func setup() { - backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false + } + + open func setDefaults() { + backgroundColor = .clear accessibilityCustomActions = [] titleLabel?.adjustsFontSizeToFitWidth = false titleLabel?.lineBreakMode = .byTruncatingTail titleLabel?.numberOfLines = 1 + surface = .light + isEnabled = true + text = nil + onClick = nil + userInfo.removeAll() } open func updateView() { @@ -131,12 +140,7 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { open func reset() { shouldUpdateView = false - surface = .light - isEnabled = true - text = nil - accessibilityCustomActions = [] - onClick = nil - userInfo.removeAll() + setDefaults() shouldUpdateView = true setNeedsUpdate() } diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 5930dea7..245dcf81 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -197,6 +197,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { initialSetupPerformed = true shouldUpdateView = false setup() + setDefaults() shouldUpdateView = true setNeedsUpdate() } @@ -209,27 +210,28 @@ open class Label: UILabel, ViewProtocol, UserInfoable { .sink { [weak self] notification in self?.setNeedsUpdate() }.store(in: &subscribers) - backgroundColor = .clear - numberOfLines = 0 - lineBreakMode = .byTruncatingTail translatesAutoresizingMaskIntoConstraints = false - accessibilityCustomActions = [] isAccessibilityElement = true - accessibilityTraits = .staticText - textAlignment = .left } - open func reset() { - shouldUpdateView = false + open func setDefaults() { + backgroundColor = .clear + accessibilityTraits = .staticText + accessibilityCustomActions = [] surface = .light isEnabled = true attributes = nil textStyle = .defaultStyle + lineBreakMode = .byTruncatingTail textAlignment = .left text = nil attributedText = nil numberOfLines = 0 - backgroundColor = .clear + } + + open func reset() { + shouldUpdateView = false + setDefaults() shouldUpdateView = true setNeedsUpdate() } diff --git a/VDS/Components/TextFields/InputField/TextField.swift b/VDS/Components/TextFields/InputField/TextField.swift index 2f6ddb1a..9fb8d7f6 100644 --- a/VDS/Components/TextFields/InputField/TextField.swift +++ b/VDS/Components/TextFields/InputField/TextField.swift @@ -103,13 +103,13 @@ open class TextField: UITextField, ViewProtocol, Errorable { initialSetupPerformed = true shouldUpdateView = false setup() + setDefaults() shouldUpdateView = true setNeedsUpdate() } } open func setup() { - backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false setContentCompressionResistancePriority(.defaultLow, for: .horizontal) clipsToBounds = true @@ -127,6 +127,17 @@ open class TextField: UITextField, ViewProtocol, Errorable { inputAccessoryView = accessView } + open func setDefaults() { + backgroundColor = .clear + surface = .light + text = nil + formatText = nil + useScaledFont = false + showError = false + errorText = nil + textStyle = .defaultStyle + } + @objc func doneButtonAction() { // Resigns the first responder status when 'Done' is tapped let _ = resignFirstResponder() @@ -177,8 +188,7 @@ open class TextField: UITextField, ViewProtocol, Errorable { open func reset() { shouldUpdateView = false - surface = .light - text = nil + setDefaults() shouldUpdateView = true setNeedsUpdate() } diff --git a/VDS/Components/TextFields/TextArea/TextView.swift b/VDS/Components/TextFields/TextArea/TextView.swift index 575c2da8..b8098a49 100644 --- a/VDS/Components/TextFields/TextArea/TextView.swift +++ b/VDS/Components/TextFields/TextArea/TextView.swift @@ -112,13 +112,13 @@ open class TextView: UITextView, ViewProtocol, Errorable { initialSetupPerformed = true shouldUpdateView = false setup() + setDefaults() shouldUpdateView = true setNeedsUpdate() } } open func setup() { - backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false let accessView = UIView(frame: .init(origin: .zero, size: .init(width: UIScreen.main.bounds.width, height: 44))) @@ -137,6 +137,15 @@ open class TextView: UITextView, ViewProtocol, Errorable { placeholderLabel.pinToSuperView() } + open func setDefaults() { + backgroundColor = .clear + surface = .light + text = nil + placeholder = nil + errorText = nil + showError = false + } + @objc func doneButtonAction() { // Resigns the first responder status when 'Done' is tapped resignFirstResponder() @@ -156,8 +165,7 @@ open class TextView: UITextView, ViewProtocol, Errorable { open func reset() { shouldUpdateView = false - surface = .light - text = nil + setDefaults() shouldUpdateView = true setNeedsUpdate() } diff --git a/VDS/Protocols/ViewProtocol.swift b/VDS/Protocols/ViewProtocol.swift index 695386cb..9a509dc1 100644 --- a/VDS/Protocols/ViewProtocol.swift +++ b/VDS/Protocols/ViewProtocol.swift @@ -21,7 +21,10 @@ public protocol ViewProtocol: AnyObject, Initable, Resettable, Enabling, Surface /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. func setup() - + + /// Default configurations for values and properties. This is called in the setup() and reset(). + func setDefaults() + /// Used to make changes to the View based off a change events or from local properties. func updateView() From 973e25034e1b404e2d0cb72984c73740a6647714 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 14:37:08 -0500 Subject: [PATCH 35/41] reverted back to onClick() since I found the issue in reset() Signed-off-by: Matt Bruce --- VDS/Components/Toggle/Toggle.swift | 12 +++++------- VDS/Components/Toggle/ToggleView.swift | 10 ++++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index 29f7dd6d..260fdc31 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -157,13 +157,11 @@ open class Toggle: Control, Changeable, FormFieldable { /// 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() - - publisher(for: .touchUpInside) - .sink(receiveValue: { [weak self] _ in - guard let self, isEnabled else { return } - toggle() - }) - .store(in: &subscribers) + + onClick = { [weak self] _ in + guard let self else { return } + toggle() + } isAccessibilityElement = true if #available(iOS 17.0, *) { diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index fb663e99..1ba5d605 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -109,12 +109,10 @@ open class ToggleView: Control, Changeable, FormFieldable { open override func setup() { super.setup() - publisher(for: .touchUpInside) - .sink(receiveValue: { [weak self] _ in - guard let self, isEnabled else { return } - toggle() - }) - .store(in: &subscribers) + onClick = { [weak self] _ in + guard let self else { return } + toggle() + } isAccessibilityElement = true if #available(iOS 17.0, *) { From 59294ebd511803b2926dba88223536fde8f76ed8 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 14:37:36 -0500 Subject: [PATCH 36/41] using setup() now Signed-off-by: Matt Bruce --- VDS/BaseClasses/Selector/SelectorBase.swift | 16 +++++++--------- VDS/BaseClasses/Selector/SelectorItemBase.swift | 16 ++++++---------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/VDS/BaseClasses/Selector/SelectorBase.swift b/VDS/BaseClasses/Selector/SelectorBase.swift index 1e2f5fba..fd794479 100644 --- a/VDS/BaseClasses/Selector/SelectorBase.swift +++ b/VDS/BaseClasses/Selector/SelectorBase.swift @@ -100,9 +100,11 @@ open class SelectorBase: Control, SelectorControlable { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - /// Executed on initialization for this View. - 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() + onClick = { control in control.toggle() } @@ -116,14 +118,10 @@ open class SelectorBase: Control, SelectorControlable { guard let self else { return "" } return !isEnabled ? "" : "Double tap to activate." } - } - - /// 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() - + isAccessibilityElement = true accessibilityTraits = .button + } open override func updateView() { diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index 44ed01b1..e27a9f94 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -157,9 +157,11 @@ open class SelectorItemBase: Control, Errorable, Changea //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - /// Executed on initialization for this View. - 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() + onClick = { [weak self] control in guard let self, isEnabled else { return } toggle() @@ -204,13 +206,7 @@ open class SelectorItemBase: Control, Errorable, Changea return !isEnabled ? "" : "Double tap to activate." } - } - - /// 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() - - selectorView.isAccessibilityElement = true + selectorView.isAccessibilityElement = true isAccessibilityElement = false addSubview(mainStackView) From ac1957d1c3ef71f2dc5488cee23e687abcade1f1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 14:38:32 -0500 Subject: [PATCH 37/41] using submit now Signed-off-by: Matt Bruce --- VDS/Components/RadioBox/RadioBoxItem.swift | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index 1da80c0a..4ea010e6 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -165,11 +165,13 @@ open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - /// Executed on initialization for this View. - open override func initialSetup() { - super.initialSetup() - onClick = { control in - control.toggle() + /// 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() + + onClick = { [weak self] _ in + guard let self, isEnabled else { return } + toggle() } selectorView.bridge_accessibilityLabelBlock = { [weak self] in @@ -205,12 +207,6 @@ open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable { return accessibilityLabels.joined(separator: ", ") } - } - - /// 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() - isAccessibilityElement = false selectorView.isAccessibilityElement = true selectorView.accessibilityTraits = .button From fc7650f7d9f08b091d6c8ea7e3a8b7995fecb178 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 16:45:18 -0500 Subject: [PATCH 38/41] refactor toggle with setDefaults Signed-off-by: Matt Bruce --- VDS/Components/Toggle/Toggle.swift | 31 ++++++++++++++------------ VDS/Components/Toggle/ToggleView.swift | 22 ++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index 260fdc31..304b18ce 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -158,11 +158,6 @@ open class Toggle: Control, Changeable, FormFieldable { open override func setup() { super.setup() - onClick = { [weak self] _ in - guard let self else { return } - toggle() - } - isAccessibilityElement = true if #available(iOS 17.0, *) { accessibilityTraits = .toggleButton @@ -237,6 +232,16 @@ open class Toggle: Control, Changeable, FormFieldable { label.trailingAnchor.constraint(equalTo: trailingAnchor) ] + } + + open override func setDefaults() { + super.setDefaults() + + onClick = { [weak self] _ in + guard let self else { return } + toggle() + } + bridge_accessibilityValueBlock = { [weak self] in guard let self else { return "" } if showText { @@ -245,13 +250,7 @@ open class Toggle: Control, Changeable, FormFieldable { return isSelected ? "On" : "Off" } } - } - - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - label.reset() + isEnabled = true isOn = false isAnimated = true @@ -263,8 +262,12 @@ open class Toggle: Control, Changeable, FormFieldable { textPosition = .left inputId = nil onChange = nil - shouldUpdateView = true - setNeedsUpdate() + } + + /// Resets to default settings. + open override func reset() { + label.reset() + super.reset() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index 1ba5d605..2ecfd44a 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -109,11 +109,6 @@ open class ToggleView: Control, Changeable, FormFieldable { open override func setup() { super.setup() - onClick = { [weak self] _ in - guard let self else { return } - toggle() - } - isAccessibilityElement = true if #available(iOS 17.0, *) { accessibilityTraits = .toggleButton @@ -154,20 +149,21 @@ open class ToggleView: Control, Changeable, FormFieldable { accessibilityLabel = "Toggle" } - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false + open override func setDefaults() { + super.setDefaults() isOn = false isAnimated = true inputId = nil toggleView.backgroundColor = toggleColorConfiguration.getColor(self) knobView.backgroundColor = knobColorConfiguration.getColor(self) - onChange = nil - shouldUpdateView = true - setNeedsUpdate() + onChange = nil + + onClick = { [weak self] _ in + guard let self else { return } + toggle() + } } - + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() From bf4ff94933014b3b42e093614f2bdd53dabd87f1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 9 Aug 2024 16:45:35 -0500 Subject: [PATCH 39/41] moved default values into setDefaults() Signed-off-by: Matt Bruce --- VDS/BaseClasses/Selector/SelectorBase.swift | 12 +-- .../Selector/SelectorGroupBase.swift | 36 +++++---- .../Selector/SelectorItemBase.swift | 73 ++++++++++--------- VDS/Components/Badge/Badge.swift | 21 +++--- .../BadgeIndicator/BadgeIndicator.swift | 28 +++++-- .../Breadcrumbs/BreadcrumbItem.swift | 25 ++----- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 5 +- VDS/Components/Buttons/Button/Button.swift | 10 +-- .../Buttons/ButtonGroup/ButtonGroup.swift | 12 +-- .../Buttons/TextLink/TextLink.swift | 33 +++------ .../Buttons/TextLinkCaret/TextLinkCaret.swift | 18 ++--- VDS/Components/Calendar/Calendar.swift | 24 +++--- VDS/Components/Carousel/Carousel.swift | 26 +++---- VDS/Components/DatePicker/DatePicker.swift | 14 ++-- .../DropdownSelect/DropdownSelect.swift | 22 +++--- .../Icon/ButtonIcon/ButtonIcon.swift | 41 ++++++----- VDS/Components/Icon/Icon.swift | 27 +++---- VDS/Components/Line/Line.swift | 9 +-- .../Notification/Notification.swift | 23 +++--- VDS/Components/RadioBox/RadioBoxItem.swift | 66 ++++++++--------- .../RadioButton/RadioButtonGroup.swift | 9 ++- VDS/Components/Table/Table.swift | 8 +- VDS/Components/Tabs/Tabs.swift | 15 ++-- .../TextFields/EntryFieldBase.swift | 66 +++++++++-------- .../TextFields/InputField/InputField.swift | 30 ++++---- .../TextFields/TextArea/TextArea.swift | 13 +++- .../TileContainer/TileContainer.swift | 13 ++-- VDS/Components/Tilelet/Tilelet.swift | 11 ++- VDS/Components/TitleLockup/TitleLockup.swift | 9 +-- VDS/Components/Tooltip/Tooltip.swift | 18 ++--- .../Tooltip/TrailingTooltipLabel.swift | 8 +- 31 files changed, 361 insertions(+), 364 deletions(-) diff --git a/VDS/BaseClasses/Selector/SelectorBase.swift b/VDS/BaseClasses/Selector/SelectorBase.swift index fd794479..05c8a1e8 100644 --- a/VDS/BaseClasses/Selector/SelectorBase.swift +++ b/VDS/BaseClasses/Selector/SelectorBase.swift @@ -104,11 +104,17 @@ open class SelectorBase: Control, SelectorControlable { /// 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() + isAccessibilityElement = true + accessibilityTraits = .button + } + + open override func setDefaults() { + super.setDefaults() onClick = { control in control.toggle() } - + bridge_accessibilityLabelBlock = { [weak self] in guard let self else { return "" } return "\(Self.self)\(showError ? ", error" : "")" @@ -118,10 +124,6 @@ open class SelectorBase: Control, SelectorControlable { guard let self else { return "" } return !isEnabled ? "" : "Double tap to activate." } - - isAccessibilityElement = true - accessibilityTraits = .button - } open override func updateView() { diff --git a/VDS/BaseClasses/Selector/SelectorGroupBase.swift b/VDS/BaseClasses/Selector/SelectorGroupBase.swift index 4df1ca5c..5cda9c82 100644 --- a/VDS/BaseClasses/Selector/SelectorGroupBase.swift +++ b/VDS/BaseClasses/Selector/SelectorGroupBase.swift @@ -65,25 +65,30 @@ open class SelectorGroupBase: Control, SelectorGrou } didSet { + setItemsActions() for selector in items { - selector.onClick = { [weak self] handler in - self?.didSelect(handler) - self?.setNeedsUpdate() - } - - selector.accessibilityAction = { [weak self] handler in - guard let handler = handler as? SelectorItemType else { return } - self?.didSelect(handler) - self?.setNeedsUpdate() - } - mainStackView.addArrangedSubview(selector) } } } open var onChangeSubscriber: AnyCancellable? - + + private func setItemsActions() { + for selector in items { + selector.onClick = { [weak self] handler in + self?.didSelect(handler) + self?.setNeedsUpdate() + } + + selector.accessibilityAction = { [weak self] handler in + guard let handler = handler as? SelectorItemType else { return } + self?.didSelect(handler) + self?.setNeedsUpdate() + } + } + } + /// Whether the Control is enabled or not. override open var isEnabled: Bool { didSet { @@ -115,6 +120,11 @@ open class SelectorGroupBase: Control, SelectorGrou .pinBottom(0, .defaultHigh) } + open override func setDefaults() { + super.setDefaults() + onChange = nil + } + /// Handler for the Group to override on a select event. /// - Parameter selectedControl: Selected Control the user interacted. open func didSelect(_ selectedControl: SelectorItemType) { @@ -131,8 +141,8 @@ open class SelectorGroupBase: Control, SelectorGrou /// Resets to default settings. open override func reset() { super.reset() - onChange = nil items.forEach{ $0.reset() } + setItemsActions() } } diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index e27a9f94..90aaed14 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -161,6 +161,27 @@ open class SelectorItemBase: Control, Errorable, Changea /// 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() + + selectorView.isAccessibilityElement = true + isAccessibilityElement = false + addSubview(mainStackView) + + mainStackView.isUserInteractionEnabled = false + mainStackView.addArrangedSubview(selectorStackView) + mainStackView.addArrangedSubview(errorLabel) + selectorStackView.addArrangedSubview(selectorView) + selectorStackView.addArrangedSubview(selectorLabelStackView) + selectorLabelStackView.addArrangedSubview(label) + selectorLabelStackView.addArrangedSubview(childLabel) + mainStackView + .pinTop() + .pinLeading() + .pinTrailing() + .pinBottom(0, .defaultHigh) + } + + open override func setDefaults() { + super.setDefaults() onClick = { [weak self] control in guard let self, isEnabled else { return } @@ -205,23 +226,23 @@ open class SelectorItemBase: Control, Errorable, Changea guard let self else { return "" } return !isEnabled ? "" : "Double tap to activate." } + + label.textStyle = .boldBodyLarge + childLabel.textStyle = .bodyLarge + errorLabel.textStyle = .bodyMedium - selectorView.isAccessibilityElement = true - isAccessibilityElement = false - addSubview(mainStackView) + labelText = nil + labelTextAttributes = nil + labelAttributedText = nil + childText = nil + childTextAttributes = nil + childAttributedText = nil + showError = false + errorText = nil + inputId = nil + isSelected = false - mainStackView.isUserInteractionEnabled = false - mainStackView.addArrangedSubview(selectorStackView) - mainStackView.addArrangedSubview(errorLabel) - selectorStackView.addArrangedSubview(selectorView) - selectorStackView.addArrangedSubview(selectorLabelStackView) - selectorLabelStackView.addArrangedSubview(label) - selectorLabelStackView.addArrangedSubview(childLabel) - mainStackView - .pinTop() - .pinLeading() - .pinTrailing() - .pinBottom(0, .defaultHigh) + onChange = nil } /// Used to make changes to the View based off a change events or from local properties. @@ -277,30 +298,10 @@ open class SelectorItemBase: Control, Errorable, Changea /// Resets to default settings. open override func reset() { - super.reset() - shouldUpdateView = false label.reset() childLabel.reset() errorLabel.reset() - - label.textStyle = .boldBodyLarge - childLabel.textStyle = .bodyLarge - errorLabel.textStyle = .bodyMedium - - labelText = nil - labelTextAttributes = nil - labelAttributedText = nil - childText = nil - childTextAttributes = nil - childAttributedText = nil - showError = false - errorText = nil - inputId = nil - isSelected = false - - onChange = nil - shouldUpdateView = true - setNeedsUpdate() + super.reset() } //-------------------------------------------------- diff --git a/VDS/Components/Badge/Badge.swift b/VDS/Components/Badge/Badge.swift index 07477f5f..1c47133f 100644 --- a/VDS/Components/Badge/Badge.swift +++ b/VDS/Components/Badge/Badge.swift @@ -149,25 +149,28 @@ open class Badge: View { maxWidthConstraint = label.widthLessThanEqualTo(constant: 0).with { $0.isActive = false } clipsToBounds = true + } + + open override func setDefaults() { + super.setDefaults() + bridge_accessibilityLabelBlock = { [weak self] in guard let self else { return "" } return text } - } - - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - label.reset() + label.lineBreakMode = .byTruncatingTail label.textStyle = .boldBodySmall fillColor = .red text = "" maxWidth = nil numberOfLines = 1 - shouldUpdateView = true - setNeedsUpdate() + } + + /// Resets to default settings. + open override func reset() { + label.reset() + super.reset() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index 13a6cb21..dc200cd8 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -305,17 +305,31 @@ open class BadgeIndicator: View { } } - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - label.reset() + open override func setDefaults() { + super.setDefaults() label.lineBreakMode = .byTruncatingTail label.textAlignment = .center fillColor = .red number = nil - shouldUpdateView = true - setNeedsUpdate() + kind = .simple + leadingCharacter = nil + trailingText = nil + size = .xxlarge + dotSize = nil + verticalPadding = nil + horizontalPadding = nil + hideDot = false + hideBorder = false + width = nil + height = nil + accessibilityText = nil + maximumDigits = .two + } + + /// Resets to default settings. + open override func reset() { + label.reset() + super.reset() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift index 66f62989..cdb6011e 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift @@ -72,17 +72,15 @@ open class BreadcrumbItem: ButtonBase { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - /// 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() - + open override func setDefaults() { + super.setDefaults() + isAccessibilityElement = true + accessibilityTraits = .link + titleLabel?.numberOfLines = 0 titleLabel?.lineBreakMode = .byWordWrapping contentHorizontalAlignment = .left - isAccessibilityElement = true - accessibilityTraits = .link - bridge_accessibilityHintBlock = { [weak self] in guard let self else { return "" } return !isEnabled ? "" : "Double tap to open." @@ -131,17 +129,4 @@ open class BreadcrumbItem: ButtonBase { } } - - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - text = nil - accessibilityCustomActions = [] - isAccessibilityElement = true - accessibilityTraits = .button - shouldUpdateView = true - setNeedsUpdate() - } - } diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index 6c45383d..1179807d 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -116,14 +116,11 @@ open class Breadcrumbs: View { addSubview(containerView) containerView.pinToSuperView() } - + /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false breadcrumbs.forEach { $0.reset() } - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Buttons/Button/Button.swift b/VDS/Components/Buttons/Button/Button.swift index 0b9d13f1..9569e3e7 100644 --- a/VDS/Components/Buttons/Button/Button.swift +++ b/VDS/Components/Buttons/Button/Button.swift @@ -223,16 +223,12 @@ open class Button: ButtonBase, Useable { isAccessibilityElement = true accessibilityTraits = .button } - - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false + + open override func setDefaults() { + super.setDefaults() use = .primary width = nil size = .large - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift index 8b662070..486301c7 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift @@ -167,15 +167,17 @@ open class ButtonGroup: View { collectionView.reloadData() } - open override func reset() { - super.reset() - shouldUpdateView = false + open override func setDefaults() { + super.setDefaults() rowQuantityPhone = 0 rowQuantityTablet = 0 alignment = .center + childWidth = nil + } + + open override func reset() { buttons.forEach { $0.reset() } - shouldUpdateView = true - setNeedsUpdate() + super.reset() } open override func layoutSubviews() { diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index 70f2840b..b002c712 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -91,12 +91,7 @@ open class TextLink: ButtonBase { open override func setup() { super.setup() isAccessibilityElement = true - accessibilityTraits = .link - - //left align titleLabel in case this is pinned leading/trailing - //default is always set to center - contentHorizontalAlignment = .left - + if let titleLabel { addSubview(line) line.pinLeading(titleLabel.leadingAnchor) @@ -106,12 +101,21 @@ open class TextLink: ButtonBase { lineHeightConstraint = line.height(constant: 1) lineHeightConstraint?.isActive = true } + } + + open override func setDefaults() { + super.setDefaults() + size = .large + accessibilityTraits = .link + //left align titleLabel in case this is pinned leading/trailing + //default is always set to center + contentHorizontalAlignment = .left + bridge_accessibilityHintBlock = { [weak self] in guard let self else { return "" } return !isEnabled ? "" : "Double tap to open." } - } /// Used to make changes to the View based off a change events or from local properties. @@ -123,18 +127,5 @@ open class TextLink: ButtonBase { //always call last so the label is rendered super.updateView() } - - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - text = nil - size = .large - accessibilityCustomActions = [] - isAccessibilityElement = true - accessibilityTraits = .link - shouldUpdateView = true - setNeedsUpdate() - } - + } diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index f8c86a44..e8806daa 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -76,10 +76,8 @@ open class TextLinkCaret: ButtonBase { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - /// 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() - + open override func setDefaults() { + super.setDefaults() //left align titleLabel in case this is pinned leading/trailing //default is always set to center contentHorizontalAlignment = .left @@ -88,11 +86,12 @@ open class TextLinkCaret: ButtonBase { titleLabel?.numberOfLines = 0 titleLabel?.lineBreakMode = .byWordWrapping + iconPosition = .right + bridge_accessibilityHintBlock = { [weak self] in guard let self else { return "" } return !isEnabled ? "" : "Double tap to open." } - } /// Used to make changes to the View based off a change events or from local properties. @@ -100,14 +99,7 @@ open class TextLinkCaret: ButtonBase { imageAttribute = CaretLabelAttribute(tintColor: textColor, position: iconPosition) super.updateView() } - - /// Resets to default settings. - open override func reset() { - super.reset() - iconPosition = .right - text = nil - } - + /// The natural size for the receiving view, considering only properties of the view itself. open override var intrinsicContentSize: CGSize { guard let titleLabel else { return super.intrinsicContentSize } diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index e7c2cb20..0a6ba18c 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -150,6 +150,19 @@ open class CalendarBase: Control, Changeable { collectionView.pinCenterX(anchor: containerView.centerXAnchor) } + + open override func setDefaults() { + super.setDefaults() + hideContainerBorder = false + hideCurrentDateIndicator = false + transparentBackground = false + activeDates = [] + inactiveDates = [] + indicators = [] + minDate = Date() + maxDate = Date() + selectedDate = Date() + } open override func updateView() { super.updateView() @@ -170,17 +183,6 @@ open class CalendarBase: Control, Changeable { containerView.layer.borderWidth = VDSFormControls.borderWidth } } - - /// Resets to default settings. - open override func reset() { - super.reset() - hideContainerBorder = false - hideCurrentDateIndicator = false - transparentBackground = false - activeDates = [] - inactiveDates = [] - indicators = [] - } //-------------------------------------------------- // MARK: - Private Methods diff --git a/VDS/Components/Carousel/Carousel.swift b/VDS/Components/Carousel/Carousel.swift index 766a7a70..f8d62520 100644 --- a/VDS/Components/Carousel/Carousel.swift +++ b/VDS/Components/Carousel/Carousel.swift @@ -244,6 +244,18 @@ open class Carousel: View { updatePaginationInset() } + open override func setDefaults() { + super.setDefaults() + gutter = UIDevice.isIPad ? .gutter6X : .gutter3X + layout = UIDevice.isIPad ? .threeUP : .oneUP + onChange = nil + pagination = .init(kind: .lowContrast, floating: true) + paginationDisplay = .none + paginationInset = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space2X + peek = .standard + groupIndex = 0 + } + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -274,19 +286,7 @@ open class Carousel: View { updatePaginationControls() addCarouselSlots() } - - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - layout = UIDevice.isIPad ? .threeUP : .oneUP - pagination = .init(kind: .lowContrast, floating: true) - paginationDisplay = .none - paginationInset = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space2X - gutter = UIDevice.isIPad ? .gutter6X : .gutter3X - peek = .standard - } - + //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index df7cc7c9..9a95124c 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -174,6 +174,14 @@ open class DatePicker: EntryFieldBase { popoverOverlayView.isHidden = true } + open override func setDefaults() { + super.setDefaults() + selectedDate = nil + calendarModel = .init() + dateFormat = .shortNumeric + selectedDateLabel.textStyle = .bodyLarge + } + open override func getFieldContainer() -> UIView { // stackview for controls in EntryFieldBase.controlContainerView let controlStackView = UIStackView().with { @@ -200,12 +208,6 @@ open class DatePicker: EntryFieldBase { calendarIcon.color = iconColorConfiguration.getColor(self) } - /// Resets to default settings. - open override func reset() { - super.reset() - selectedDateLabel.textStyle = .bodyLarge - } - internal func formatDate(_ date: Date) { let formatter = DateFormatter() formatter.dateFormat = dateFormat.format diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 947210f4..ab2c1195 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -162,6 +162,17 @@ open class DropdownSelect: EntryFieldBase { containerView.height(44) } + open override func setDefaults() { + super.setDefaults() + showInlineLabel = false + selectId = nil + inlineDisplayLabel.textStyle = .boldBodyLarge + selectedOptionLabel.textStyle = .bodyLarge + showInlineLabel = false + options = [] + selectId = nil + } + open override func getFieldContainer() -> UIView { let controlStackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -188,17 +199,6 @@ open class DropdownSelect: EntryFieldBase { selectedOptionLabel.surface = surface selectedOptionLabel.isEnabled = isEnabled } - - /// Resets to default settings. - open override func reset() { - super.reset() - - inlineDisplayLabel.textStyle = .boldBodyLarge - selectedOptionLabel.textStyle = .bodyLarge - showInlineLabel = false - options = [] - selectId = nil - } //-------------------------------------------------- // MARK: - Public Methods diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 95406fb4..b6b51601 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -413,6 +413,27 @@ open class ButtonIcon: Control, Changeable { .store(in: &subscribers) } + open override func setDefaults() { + super.setDefaults() + badgeIndicatorModel = nil + kind = .ghost + surfaceType = .colorFill + iconName = nil + selectedIconName = nil + selectedIconColorConfiguration = nil + size = .large + floating = false + fitToIcon = false + hideBorder = true + showBadgeIndicator = false + selectable = false + iconOffset = .init(x: 0, y: 0) + customContainerSize = nil + customIconSize = nil + customBadgeIndicatorOffset = nil + onChange = nil + } + /// This will change the state of the Selector and execute the actionBlock if provided. open func toggle() { //removed error @@ -420,26 +441,6 @@ open class ButtonIcon: Control, Changeable { sendActions(for: .valueChanged) } - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - kind = .ghost - surfaceType = .colorFill - size = .large - floating = false - hideBorder = true - iconOffset = .init(x: 0, y: 0) - iconName = nil - selectedIconName = nil - showBadgeIndicator = false - selectable = false - badgeIndicatorModel = nil - onChange = nil - shouldUpdateView = true - setNeedsUpdate() - } - /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() diff --git a/VDS/Components/Icon/Icon.swift b/VDS/Components/Icon/Icon.swift index fd5c5fb2..8e19bf5c 100644 --- a/VDS/Components/Icon/Icon.swift +++ b/VDS/Components/Icon/Icon.swift @@ -90,22 +90,29 @@ open class Icon: View { addSubview(imageView) imageView.pinToSuperView() - - backgroundColor = .clear - + isAccessibilityElement = true accessibilityTraits = .none - accessibilityHint = "image" + + } + + open override func setDefaults() { + super.setDefaults() + backgroundColor = .clear + color = VDSColor.paletteBlack + size = .medium + name = nil + customSize = nil + imageView.image = nil + accessibilityHint = "image" bridge_accessibilityLabelBlock = { [weak self] in guard let self else { return "" } return name?.rawValue ?? "icon" } - - - } + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -123,12 +130,6 @@ open class Icon: View { invalidateIntrinsicContentSize() } - /// Resets to default settings. - open override func reset() { - super.reset() - color = VDSColor.paletteBlack - imageView.image = nil - } } extension UIImage { diff --git a/VDS/Components/Line/Line.swift b/VDS/Components/Line/Line.swift index 627210f9..06accf07 100644 --- a/VDS/Components/Line/Line.swift +++ b/VDS/Components/Line/Line.swift @@ -81,11 +81,6 @@ open class Line: View { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- - /// 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() - } - /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() @@ -94,8 +89,8 @@ open class Line: View { } /// Resets to default settings. - open override func reset() { - super.reset() + open override func setDefaults() { + super.setDefaults() style = .primary orientation = .horizontal } diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 6df7da68..e188faf7 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -274,20 +274,13 @@ open class Notification: View { } } - /// Resets to default settings. - open override func reset() { - super.reset() - - shouldUpdateView = false - - titleLabel.reset() + open override func setDefaults() { + super.setDefaults() titleLabel.text = "" titleLabel.textStyle = UIDevice.isIPad ? .boldBodyLarge : .boldBodySmall - subTitleLabel.reset() subTitleLabel.textStyle = UIDevice.isIPad ? .bodyLarge : .bodySmall - buttonGroup.reset() buttonGroup.alignment = .left primaryButtonModel = nil @@ -302,9 +295,15 @@ open class Notification: View { closeButton.name = .close hideCloseButton = false - - shouldUpdateView = true - setNeedsUpdate() + + } + + /// Resets to default settings. + open override func reset() { + titleLabel.reset() + subTitleLabel.reset() + buttonGroup.reset() + super.reset() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index 4ea010e6..a5ca1d8b 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -168,6 +168,31 @@ open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable { /// 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() + + isAccessibilityElement = false + selectorView.isAccessibilityElement = true + selectorView.accessibilityTraits = .button + addSubview(selectorView) + selectorView.isUserInteractionEnabled = false + + selectorView.addSubview(selectorStackView) + + selectorStackView.addArrangedSubview(selectorLeftLabelStackView) + selectorStackView.addArrangedSubview(subTextRightLabel) + selectorLeftLabelStackView.addArrangedSubview(textLabel) + selectorLeftLabelStackView.addArrangedSubview(subTextLabel) + + selectorView + .pinTop() + .pinLeading() + .pinTrailing(0, .defaultHigh) + .pinBottom(0, .defaultHigh) + + selectorStackView.pinToSuperView(.uniform(VDSLayout.space3X)) + } + + open override func setDefaults() { + super.setDefaults() onClick = { [weak self] _ in guard let self, isEnabled else { return } @@ -206,37 +231,7 @@ open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable { return accessibilityLabels.joined(separator: ", ") } - - isAccessibilityElement = false - selectorView.isAccessibilityElement = true - selectorView.accessibilityTraits = .button - addSubview(selectorView) - selectorView.isUserInteractionEnabled = false - - selectorView.addSubview(selectorStackView) - - selectorStackView.addArrangedSubview(selectorLeftLabelStackView) - selectorStackView.addArrangedSubview(subTextRightLabel) - selectorLeftLabelStackView.addArrangedSubview(textLabel) - selectorLeftLabelStackView.addArrangedSubview(subTextLabel) - - selectorView - .pinTop() - .pinLeading() - .pinTrailing(0, .defaultHigh) - .pinBottom(0, .defaultHigh) - - selectorStackView.pinToSuperView(.uniform(VDSLayout.space3X)) - } - - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - textLabel.reset() - subTextLabel.reset() - subTextRightLabel.reset() - + textLabel.textStyle = .boldBodyLarge subTextLabel.textStyle = .bodyLarge subTextRightLabel.textStyle = .bodyLarge @@ -256,9 +251,14 @@ open class RadioBoxItem: Control, Changeable, FormFieldable, Groupable { isSelected = false onChange = nil + } - shouldUpdateView = true - setNeedsUpdate() + /// Resets to default settings. + open override func reset() { + textLabel.reset() + subTextLabel.reset() + subTextRightLabel.reset() + super.reset() } /// This will change the state of the Selector and execute the actionBlock if provided. diff --git a/VDS/Components/RadioButton/RadioButtonGroup.swift b/VDS/Components/RadioButton/RadioButtonGroup.swift index 13adf080..5d323997 100644 --- a/VDS/Components/RadioButton/RadioButtonGroup.swift +++ b/VDS/Components/RadioButton/RadioButtonGroup.swift @@ -77,12 +77,13 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi } } - open override func reset() { - super.reset() + open override func setDefaults() { + super.setDefaults() + inputId = nil showError = false } - - public override func didSelect(_ selectedControl: RadioButtonItem) { + + open override func didSelect(_ selectedControl: RadioButtonItem) { if let selectedItem { updateToggle(selectedItem) } diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index 95873d33..21fe00a4 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -109,18 +109,16 @@ open class Table: View { matrixView.collectionViewLayout.invalidateLayout() } - /// Resets to default settings. - open override func reset() { - super.reset() + open override func setDefaults() { + super.setDefaults() striped = false padding = .standard tableHeader = [] tableRows = [] fillContainer = true columnWidths = nil - setNeedsUpdate() } - + func calculateColumnWidths() -> [CGFloat] { guard let noOfColumns = tableData.first?.columnsCount else { return [] } let itemWidth = floor(matrixView.safeAreaLayoutGuide.layoutFrame.width / CGFloat(noOfColumns)) diff --git a/VDS/Components/Tabs/Tabs.swift b/VDS/Components/Tabs/Tabs.swift index e909d43b..ac9e7269 100644 --- a/VDS/Components/Tabs/Tabs.swift +++ b/VDS/Components/Tabs/Tabs.swift @@ -221,10 +221,11 @@ open class Tabs: View { super.layoutSubviews() updateContentView() } - - open override func reset() { - super.reset() - shouldUpdateView = false + + open override func setDefaults() { + super.setDefaults() + onTabDidSelect = nil + onTabShouldSelect = nil orientation = .horizontal borderLine = true fillContainer = false @@ -235,11 +236,9 @@ open class Tabs: View { selectedIndex = 0 size = .medium sticky = false - tabViews.forEach{ $0.reset() } - shouldUpdateView = true - setNeedsUpdate() + tabModels = [] } - + //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 481318b6..a3a2918e 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -316,6 +316,41 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { errorLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() helperLabel.textColorConfiguration = secondaryColorConfiguration.eraseToAnyColorable() + } + + /// Updates the UI + open override func updateView() { + super.updateView() + updateRules() + updateContainerView() + updateContainerWidth() + updateTitleLabel() + updateErrorLabel() + updateHelperLabel() + } + + open override func setDefaults() { + super.setDefaults() + + titleLabel.textStyle = .bodySmall + errorLabel.textStyle = .bodySmall + helperLabel.textStyle = .bodySmall + + labelText = nil + helperText = nil + showError = false + errorText = nil + tooltipModel = nil + transparentBackground = false + width = nil + inputId = nil + defaultValue = nil + isRequired = false + isReadOnly = false + helperTextPlacement = .bottom + rules = [] + onChange = nil + containerView.bridge_accessibilityLabelBlock = { [weak self] in guard let self else { return "" } var accessibilityLabels = [String]() @@ -350,42 +385,15 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { guard let self else { return "" } return showError || hasInternalError ? "error" : nil } - } - - /// Updates the UI - open override func updateView() { - super.updateView() - updateRules() - updateContainerView() - updateContainerWidth() - updateTitleLabel() - updateErrorLabel() - updateHelperLabel() + } /// Resets to default settings. open override func reset() { - super.reset() titleLabel.reset() errorLabel.reset() helperLabel.reset() - - titleLabel.textStyle = .bodySmall - errorLabel.textStyle = .bodySmall - helperLabel.textStyle = .bodySmall - - labelText = nil - helperText = nil - showError = false - errorText = nil - tooltipModel = nil - transparentBackground = false - width = nil - inputId = nil - defaultValue = nil - isRequired = false - isReadOnly = false - onChange = nil + super.reset() } open override var canBecomeFirstResponder: Bool { diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index a65df78e..92d4c873 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -205,6 +205,22 @@ open class InputField: EntryFieldBase { textField.textColorConfiguration = textFieldTextColorConfiguration + } + + open override func getFieldContainer() -> UIView { + return textField + } + + open override func setDefaults() { + super.setDefaults() + textField.text = "" + + successLabel.textStyle = .bodySmall + + fieldType = .text + showSuccess = false + successText = nil + containerView.bridge_accessibilityLabelBlock = { [weak self] in guard let self else { return "" } var accessibilityLabels = [String]() @@ -259,22 +275,10 @@ open class InputField: EntryFieldBase { } } - open override func getFieldContainer() -> UIView { - return textField - } - /// Resets to default settings. open override func reset() { - super.reset() - textField.text = "" - successLabel.reset() - successLabel.textStyle = .bodySmall - - fieldType = .text - showSuccess = false - successText = nil - helperTextPlacement = .bottom + super.reset() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 07c79ca6..5be37d05 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -166,14 +166,19 @@ open class TextArea: EntryFieldBase { bottomContainerStackView.spacing = VDSLayout.space2X } + + open override func setDefaults() { + super.setDefaults() + minHeight = .twoX + maxLength = nil + textView.text = "" + characterCounterLabel.textStyle = .bodySmall + } /// Resets to default settings. open override func reset() { - super.reset() - textView.text = "" characterCounterLabel.reset() - characterCounterLabel.textStyle = .bodySmall - setNeedsUpdate() + super.reset() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index f35d2614..c2ec56ef 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -279,19 +279,18 @@ open class TileContainerBase: Control where Padding return view } - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false + open override func setDefaults() { + super.setDefaults() + backgroundImage = nil color = .white - aspectRatio = .none + backgroundEffect = .none + padding = .defaultValue + aspectRatio = .ratio1x1 imageFallbackColor = .light width = nil height = nil showBorder = false showDropShadow = false - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 4391bfb3..263d6b77 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -390,20 +390,19 @@ open class Tilelet: TileContainerBase { } } - /// Resets to default settings. - open override func reset() { - shouldUpdateView = false - super.reset() + open override func setDefaults() { + super.setDefaults() aspectRatio = .none color = .black + textWidth = nil + textPostion = .top + //models badgeModel = nil titleModel = nil subTitleModel = nil descriptiveIconModel = nil directionalIconModel = nil - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index 47ae5421..25aaf248 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -280,15 +280,12 @@ open class TitleLockup: View { set {} } - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false + open override func setDefaults() { + super.setDefaults() + textAlignment = .left eyebrowModel = nil titleModel = nil subTitleModel = nil - shouldUpdateView = true - setNeedsUpdate() } var labelViews = [UIView]() diff --git a/VDS/Components/Tooltip/Tooltip.swift b/VDS/Components/Tooltip/Tooltip.swift index 6eaf7ef4..effafa07 100644 --- a/VDS/Components/Tooltip/Tooltip.swift +++ b/VDS/Components/Tooltip/Tooltip.swift @@ -159,18 +159,16 @@ open class Tooltip: Control, TooltipLaunchable { } } - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false - size = .medium - title = "" - content = "" - fillColor = .primary + open override func setDefaults() { + super.setDefaults() closeButtonText = "Close" - shouldUpdateView = true - setNeedsUpdate() + fillColor = .primary + size = .medium + title = nil + content = nil + contentView = nil } + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { diff --git a/VDS/Components/Tooltip/TrailingTooltipLabel.swift b/VDS/Components/Tooltip/TrailingTooltipLabel.swift index f1f26abc..8b5011ef 100644 --- a/VDS/Components/Tooltip/TrailingTooltipLabel.swift +++ b/VDS/Components/Tooltip/TrailingTooltipLabel.swift @@ -84,17 +84,13 @@ open class TrailingTooltipLabel: View, TooltipLaunchable { } } - /// Resets to default settings. - open override func reset() { - super.reset() - shouldUpdateView = false + open override func setDefaults() { + super.setDefaults() labelText = nil labelAttributes = nil labelTextStyle = .defaultStyle labelTextAlignment = .left tooltipModel = nil - shouldUpdateView = true - setNeedsUpdate() } } From 3809e96b1605c10a5189e7d0419b46eaddee05f2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 12 Aug 2024 09:58:06 -0500 Subject: [PATCH 40/41] fixed bug within radiobox Signed-off-by: Matt Bruce --- VDS/Components/RadioBox/RadioBoxGroup.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index b5531e33..8c955999 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -71,13 +71,13 @@ open class RadioBoxGroup: SelectorGroupBase, SelectorGroupSingleSe mainStackView.axis = .horizontal mainStackView.distribution = .fillEqually } else { - if UIDevice.current.orientation.isPortrait || UIDevice.current.orientation == .unknown { - mainStackView.axis = .vertical - mainStackView.distribution = .fill - - } else { + let orientation = UIDevice.current.orientation + if orientation == .landscapeLeft || orientation == .landscapeRight { mainStackView.axis = .horizontal mainStackView.distribution = .fillEqually + } else { + mainStackView.axis = .vertical + mainStackView.distribution = .fill } } } From 3ee592f63814ef4435c672638b1180119a1c36e2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 12 Aug 2024 12:27:49 -0500 Subject: [PATCH 41/41] fixed bug in radiobox Signed-off-by: Matt Bruce --- VDS/Components/RadioBox/RadioBoxGroup.swift | 25 ++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index 8c955999..000e3433 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -67,17 +67,26 @@ open class RadioBoxGroup: SelectorGroupBase, SelectorGroupSingleSe // MARK: - Overrides //-------------------------------------------------- private func ensureDevice() { + var axis: NSLayoutConstraint.Axis = .vertical + var distribution: UIStackView.Distribution = .fill + + defer { + mainStackView.axis = axis + mainStackView.distribution = distribution + } + if UIDevice.isIPad { - mainStackView.axis = .horizontal - mainStackView.distribution = .fillEqually + axis = .horizontal + distribution = .fillEqually } else { + guard let supportedOrientations = UIApplication.shared.windows.first?.rootViewController?.supportedInterfaceOrientations else { + return + } + let orientation = UIDevice.current.orientation - if orientation == .landscapeLeft || orientation == .landscapeRight { - mainStackView.axis = .horizontal - mainStackView.distribution = .fillEqually - } else { - mainStackView.axis = .vertical - mainStackView.distribution = .fill + if supportedOrientations.contains(.landscape) && (orientation == .landscapeLeft || orientation == .landscapeRight) { + axis = .horizontal + distribution = .fillEqually } } }