From 37890e0c88f0cd5337b1c64db102ba205e7e00dc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 14:55:29 -0500 Subject: [PATCH 001/167] updated icon to statusIcon and iconColorConfiguration Signed-off-by: Matt Bruce --- .../DropdownSelect/DropdownSelect.swift | 14 +++----- .../TextFields/EntryFieldBase.swift | 34 +++++++++++-------- .../TextFields/TextArea/TextArea.swift | 12 ++----- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index 11550937..f1b7fd13 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -89,12 +89,6 @@ open class DropdownSelect: EntryFieldBase { // MARK: - Configuration Properties //-------------------------------------------------- internal override var containerSize: CGSize { CGSize(width: showInlineLabel ? minWidthInlineLabel : width ?? minWidthDefault, height: 44) } - - internal let iconColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .error) - } //-------------------------------------------------- // MARK: - Overrides @@ -240,11 +234,11 @@ open class DropdownSelect: EntryFieldBase { open override func updateErrorLabel() { super.updateErrorLabel() if !showError && !hasInternalError { - icon.name = .downCaret + statusIcon.name = .downCaret } - icon.surface = surface - icon.isHidden = readOnly ? true : false - icon.color = iconColorConfiguration.getColor(self) + statusIcon.surface = surface + statusIcon.isHidden = readOnly ? true : false + statusIcon.color = iconColorConfiguration.getColor(self) } @objc open func pickerDoneClicked() { diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 7ce12d75..7d78cf11 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -112,6 +112,12 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled,.error]) } + internal let iconColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .error) + } + internal var readOnlyBorderColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.borderReadonlyOnlight, VDSFormControlsColor.borderReadonlyOndark, forState: .normal) } @@ -142,7 +148,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { $0.textStyle = .bodySmall } - open var icon: Icon = Icon().with { + open var statusIcon: Icon = Icon().with { $0.size = .medium } @@ -248,7 +254,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //add the view to add input fields containerStackView.addArrangedSubview(controlContainerView) - containerStackView.addArrangedSubview(icon) + containerStackView.addArrangedSubview(statusIcon) containerStackView.setCustomSpacing(VDSLayout.space3X, after: controlContainerView) //get the container this is what show helper text, error text @@ -379,32 +385,30 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { errorLabel.surface = surface errorLabel.isEnabled = isEnabled errorLabel.isHidden = false - icon.name = .error - icon.color = VDSColor.paletteBlack - icon.surface = surface - icon.isHidden = !isEnabled + statusIcon.name = .error + statusIcon.surface = surface + statusIcon.isHidden = !isEnabled } else if showError, let errorText { errorLabel.text = errorText errorLabel.surface = surface errorLabel.isEnabled = isEnabled errorLabel.isHidden = false - icon.name = .error - icon.color = VDSColor.paletteBlack - icon.surface = surface - icon.isHidden = !isEnabled + statusIcon.name = .error + statusIcon.surface = surface + statusIcon.isHidden = !isEnabled } else if hasInternalError, let internalErrorText { errorLabel.text = internalErrorText errorLabel.surface = surface errorLabel.isEnabled = isEnabled errorLabel.isHidden = false - icon.name = .error - icon.color = VDSColor.paletteBlack - icon.surface = surface - icon.isHidden = !isEnabled + statusIcon.name = .error + statusIcon.surface = surface + statusIcon.isHidden = !isEnabled } else { - icon.isHidden = true + statusIcon.isHidden = true errorLabel.isHidden = true } + statusIcon.color = iconColorConfiguration.getColor(self) } open func updateHelperLabel(){ diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index b8f0e009..797e7e74 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -138,12 +138,7 @@ open class TextArea: EntryFieldBase { setNeedsUpdate() } } - - /// Color configuration for error icon. - internal var iconColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) - } - + /// Color configuration for character counter's highlight background color internal var highlightBackgroundColor = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .normal) @@ -219,8 +214,7 @@ open class TextArea: EntryFieldBase { characterCounterLabel.text = getCharacterCounterText() - icon.size = .medium - icon.color = iconColorConfiguration.getColor(self) + statusIcon.color = iconColorConfiguration.getColor(self) containerView.layer.borderColor = readOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor textView.isEditable = readOnly ? false : true textView.backgroundColor = backgroundColorConfiguration.getColor(self) @@ -240,7 +234,7 @@ open class TextArea: EntryFieldBase { open override func updateAccessibility() { super.updateAccessibility() if showError { - accessibilityElements = [titleLabel, textView, icon, errorLabel, helperLabel] + accessibilityElements = [titleLabel, textView, statusIcon, errorLabel, helperLabel] } else { accessibilityElements = [titleLabel, textView, helperLabel] } From ca1e7e2b8751b836d8ce01f39c8cd594b3550989 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 14:55:41 -0500 Subject: [PATCH 002/167] added accessibleText Signed-off-by: Matt Bruce --- VDS/Components/TextFields/InputField/TextLinkModel.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/InputField/TextLinkModel.swift b/VDS/Components/TextFields/InputField/TextLinkModel.swift index d5d8c7ba..09abc023 100644 --- a/VDS/Components/TextFields/InputField/TextLinkModel.swift +++ b/VDS/Components/TextFields/InputField/TextLinkModel.swift @@ -12,12 +12,16 @@ extension InputField { ///Text that goes in the Tab public var text: String - + + ///Text that goes in the Tab + public var accessibleText: String? + ///Click event when you click on a tab public var onClick: ((TextLink) -> Void)? - public init(text: String, onClick: ((TextLink) -> Void)? = nil) { + public init(text: String, accessibleText: String? = nil, onClick: ((TextLink) -> Void)? = nil) { self.text = text + self.accessibleText = accessibleText self.onClick = onClick } } From 87389d02cc80183bad477e1538dc78030da8c5e2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 14:56:25 -0500 Subject: [PATCH 003/167] accessibleText update Signed-off-by: Matt Bruce --- VDS/Components/Notification/Notification.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index f91d45ef..be05bbf2 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -52,7 +52,7 @@ open class Notification: View { } } - var accessibilityText: String { + var accessibleText: String { switch self { case .info: "Information Message" @@ -325,7 +325,7 @@ open class Notification: View { let iconColor = surface == .dark ? VDSColor.paletteWhite : VDSColor.paletteBlack typeIcon.name = style.iconName typeIcon.color = iconColor - typeIcon.accessibilityLabel = style.accessibilityText + typeIcon.accessibilityLabel = style.accessibleText closeButton.color = iconColor closeButton.isHidden = hideCloseButton } From 63de916555f32de159dca447acdda3ea30af79dc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 14:56:53 -0500 Subject: [PATCH 004/167] initial rework for inputField Signed-off-by: Matt Bruce --- .../TextFields/InputField/InputField.swift | 134 +++++++++++------- 1 file changed, 86 insertions(+), 48 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 004b33ae..bb1831cf 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -42,7 +42,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var inputFieldStackView: UIStackView = { + internal var inputFieldStackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal @@ -77,9 +77,11 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { /// Representing the type of input. open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } } - internal var actionTextLink = TextLink().with { $0.contentEdgeInsets = .top(-2) } + open var leftIcon: Icon = Icon().with { $0.size = .medium } - internal var actionTextLinkModel: TextLinkModel? { didSet { setNeedsUpdate() } } + open var actionTextLink = TextLink().with { $0.contentEdgeInsets = .top(-2) } + + open var actionTextLinkModel: TextLinkModel? { didSet { setNeedsUpdate() } } /// The text of this TextField. private var _text: String? @@ -155,13 +157,18 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0) minWidthConstraint?.isActive = true - controlContainerView.addSubview(textField) - textField - .pinTop() - .pinLeading() - .pinTrailingLessThanOrEqualTo(nil, 0, .defaultHigh) - .pinBottom(0, .defaultHigh) + // stackview for controls in EntryFieldBase.controlContainerView + let controlStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .horizontal + $0.spacing = VDSLayout.space3X + } + controlContainerView.addSubview(controlStackView) + controlStackView.pinToSuperView() + controlStackView.addArrangedSubview(leftIcon) + controlStackView.addArrangedSubview(textField) + textField.heightAnchor.constraint(equalToConstant: 20).isActive = true textField .textPublisher @@ -210,16 +217,8 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { textField.isEnabled = isEnabled textField.textColor = textFieldTextColorConfiguration.getColor(self) - - if let actionTextLinkModel { - actionTextLink.text = actionTextLinkModel.text - actionTextLink.onClick = actionTextLinkModel.onClick - actionTextLink.isHidden = false - containerStackView.setCustomSpacing(VDSLayout.space2X, after: icon) - } else { - actionTextLink.isHidden = true - containerStackView.setCustomSpacing(0, after: icon) - } + + updateFieldType() //show error or success if showError, let _ = errorText { @@ -231,25 +230,14 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { successLabel.isEnabled = isEnabled successLabel.isHidden = false errorLabel.isHidden = true - icon.name = .checkmarkAlt - icon.color = VDSColor.paletteBlack - icon.surface = surface - icon.isHidden = !isEnabled + statusIcon.name = .checkmarkAlt + statusIcon.color = VDSColor.paletteBlack + statusIcon.surface = surface + statusIcon.isHidden = !isEnabled } else { - icon.isHidden = true + statusIcon.isHidden = true successLabel.isHidden = true } - - //set the width constraints - if let width, width > fieldType.width { - widthConstraint?.constant = width - widthConstraint?.isActive = true - minWidthConstraint?.isActive = false - } else { - minWidthConstraint?.constant = fieldType.width - widthConstraint?.isActive = false - minWidthConstraint?.isActive = true - } } open override func updateHelperLabel(){ @@ -272,25 +260,75 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } } -} - -extension InputField.FieldType { - var width: CGFloat { - switch self { + open func updateFieldType() { + textField.isSecureTextEntry = false + + var minWidth: CGFloat = 40.0 + var iconName: Icon.Name? + var actionLinkModel: InputField.TextLinkModel? + var toolTipModel: Tooltip.TooltipModel? + + switch fieldType { + case .text: + break + + case .number: + break + + case .calendar: + break + case .inlineAction: - return 102 + minWidth = 102.0 + case .password: - return 62.0 + textField.isSecureTextEntry = true + minWidth = 62.0 + case .creditCard: - return 288.0 + minWidth = 288.0 + case .tel: - return 176.0 + minWidth = 176.0 + case .date: - return 114.0 + minWidth = 114.0 + case .securityCode: - return 88.0 - default: - return 40.0 + minWidth = 88.0 + } + + //leftIcon + leftIcon.surface = surface + leftIcon.color = iconColorConfiguration.getColor(self) + leftIcon.name = iconName + leftIcon.isHidden = iconName == nil + + //actionLink + actionTextLink.surface = surface + if let actionTextLinkModel = actionLinkModel { + actionTextLink.text = actionTextLinkModel.text + actionTextLink.accessibilityLabel = actionTextLinkModel.accessibleText + actionTextLink.isHidden = false + containerStackView.setCustomSpacing(VDSLayout.space2X, after: statusIcon) + } else { + actionTextLink.isHidden = true + containerStackView.setCustomSpacing(0, after: statusIcon) + } + + //set the width constraints + if let width, width > minWidth { + widthConstraint?.constant = width + widthConstraint?.isActive = true + minWidthConstraint?.isActive = false + } else { + minWidthConstraint?.constant = minWidth + widthConstraint?.isActive = false + minWidthConstraint?.isActive = true + } + + //tooltip + self.tooltipModel = toolTipModel } } From 7e2fdb30e3d1c0e433ec96f29432b8b5d3562f70 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 19 Apr 2024 15:03:08 -0500 Subject: [PATCH 005/167] removed accessibleText Signed-off-by: Matt Bruce --- VDS/Components/TextFields/InputField/InputField.swift | 1 - VDS/Components/TextFields/InputField/TextLinkModel.swift | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index bb1831cf..cb013856 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -309,7 +309,6 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { actionTextLink.surface = surface if let actionTextLinkModel = actionLinkModel { actionTextLink.text = actionTextLinkModel.text - actionTextLink.accessibilityLabel = actionTextLinkModel.accessibleText actionTextLink.isHidden = false containerStackView.setCustomSpacing(VDSLayout.space2X, after: statusIcon) } else { diff --git a/VDS/Components/TextFields/InputField/TextLinkModel.swift b/VDS/Components/TextFields/InputField/TextLinkModel.swift index 09abc023..89235e5e 100644 --- a/VDS/Components/TextFields/InputField/TextLinkModel.swift +++ b/VDS/Components/TextFields/InputField/TextLinkModel.swift @@ -13,15 +13,11 @@ extension InputField { ///Text that goes in the Tab public var text: String - ///Text that goes in the Tab - public var accessibleText: String? - ///Click event when you click on a tab public var onClick: ((TextLink) -> Void)? - public init(text: String, accessibleText: String? = nil, onClick: ((TextLink) -> Void)? = nil) { + public init(text: String, onClick: ((TextLink) -> Void)? = nil) { self.text = text - self.accessibleText = accessibleText self.onClick = onClick } } From bb705d8155e3197eef335b8a7e1b6aa426881014 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 23 Apr 2024 16:39:50 -0500 Subject: [PATCH 006/167] refactored value to be readOnly Signed-off-by: Matt Bruce --- .../DropdownSelect/DropdownSelect.swift | 7 +- .../TextFields/EntryFieldBase.swift | 10 +-- .../TextFields/InputField/InputField.swift | 90 +++++++++++-------- .../TextFields/TextArea/TextArea.swift | 14 +-- VDS/Protocols/FormFieldable.swift | 2 +- 5 files changed, 64 insertions(+), 59 deletions(-) diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index f1b7fd13..860b4db0 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -37,6 +37,11 @@ open class DropdownSelect: EntryFieldBase { /// Allows unique ID to be passed to the element. open var selectId: Int? { didSet { setNeedsUpdate() }} + /// Current SelectedItem Value + open override var value: String? { + selectedItem?.value + } + /// Current SelectedItem open var selectedItem: DropdownOptionModel? { guard let selectId else { return nil } @@ -228,7 +233,6 @@ open class DropdownSelect: EntryFieldBase { open func updateSelectedOptionLabel(option: DropdownOptionModel? = nil) { selectedOptionLabel.text = option?.text ?? "" - value = option?.value } open override func updateErrorLabel() { @@ -278,6 +282,7 @@ extension DropdownSelect: UIPickerViewDelegate, UIPickerViewDataSource { guard options.count > row else { return } selectId = row updateSelectedOptionLabel(option: options[row]) + sendActions(for: .valueChanged) self.onItemSelected?(row, options[row]) } } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 7d78cf11..ddbd0016 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -201,15 +201,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open var inputId: String? { didSet { setNeedsUpdate() } } /// The text of this textField. - internal var _value: String? open var value: String? { - get { _value } - set { - if let newValue, newValue != _value { - _value = newValue - sendActions(for: .valueChanged) - } - } + get { fatalError("must be read from subclass")} } open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } @@ -306,7 +299,6 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { transparentBackground = false width = nil inputId = nil - value = nil defaultValue = nil required = false readOnly = false diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index cb013856..f43fc951 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -30,15 +30,15 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { public required init?(coder: NSCoder) { super.init(coder: coder) } - + //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- /// Enum used to describe the input type. public enum FieldType: String, CaseIterable { - case text, number, calendar, inlineAction, password, creditCard, tel, date, securityCode + case text, number, inlineAction, password, creditCard, tel, date, securityCode } - + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -50,9 +50,9 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { $0.spacing = 12 } }() - + internal var minWidthConstraint: NSLayoutConstraint? - + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -73,39 +73,29 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) }.eraseToAnyColorable() - + /// Representing the type of input. open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } } - + open var leftIcon: Icon = Icon().with { $0.size = .medium } open var actionTextLink = TextLink().with { $0.contentEdgeInsets = .top(-2) } open var actionTextLinkModel: TextLinkModel? { didSet { setNeedsUpdate() } } - + /// The text of this TextField. - private var _text: String? open var text: String? { - get { _text } + get { textField.text } set { - if let newValue, newValue != _text { - _text = newValue - textField.text = newValue - value = newValue - } - setNeedsUpdate() + textField.text = newValue } } - /// The value of this textField. + /// Value for the textField open override var value: String? { - didSet { - if text != value { - text = value - } - } + textField.text } - + var _showError: Bool = false /// Whether not to show the error. open override var showError: Bool { @@ -172,10 +162,10 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { textField.heightAnchor.constraint(equalToConstant: 20).isActive = true textField .textPublisher - .sink { [weak self] text in - self?.value = text + .sink { [weak self] newText in + self?.text = newText self?.sendActions(for: .valueChanged) - + if newText.isEmpty { self?.passwordActionType = .show } }.store(in: &subscribers) stackView.addArrangedSubview(successLabel) @@ -259,13 +249,13 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } } } - + open func updateFieldType() { textField.isSecureTextEntry = false var minWidth: CGFloat = 40.0 - var iconName: Icon.Name? - var actionLinkModel: InputField.TextLinkModel? + var leftIconName: Icon.Name? + var actionModel: InputField.TextLinkModel? var toolTipModel: Tooltip.TooltipModel? switch fieldType { @@ -275,14 +265,22 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { case .number: break - case .calendar: - break - case .inlineAction: minWidth = 102.0 case .password: - textField.isSecureTextEntry = true + let isHide = passwordActionType == .hide + let buttonText = isHide ? hidePasswordButtonText : showPasswordButtonText + let isSecureTextEntry = !isHide + let nextPasswordActionType = passwordActionType.toggle() + if let text, !text.isEmpty { + actionModel = .init(text: buttonText, + onClick: { [weak self] _ in + guard let self else { return } + self.passwordActionType = nextPasswordActionType + }) + textField.isSecureTextEntry = isSecureTextEntry + } minWidth = 62.0 case .creditCard: @@ -302,13 +300,14 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { //leftIcon leftIcon.surface = surface leftIcon.color = iconColorConfiguration.getColor(self) - leftIcon.name = iconName - leftIcon.isHidden = iconName == nil + leftIcon.name = leftIconName + leftIcon.isHidden = leftIconName == nil //actionLink actionTextLink.surface = surface - if let actionTextLinkModel = actionLinkModel { - actionTextLink.text = actionTextLinkModel.text + if let actionModel { + actionTextLink.text = actionModel.text + actionTextLink.onClick = actionModel.onClick actionTextLink.isHidden = false containerStackView.setCustomSpacing(VDSLayout.space2X, after: statusIcon) } else { @@ -330,4 +329,21 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { //tooltip self.tooltipModel = toolTipModel } + + //-------------------------------------------------- + // MARK: - Password + //-------------------------------------------------- + enum PasswordAction { + case show, hide + + func toggle() -> PasswordAction { + self == .hide ? .show : .hide + } + } + + internal var passwordActionType: PasswordAction = .show { didSet { setNeedsUpdate() } } + + open var hidePasswordButtonText: String = "Hide" { didSet { setNeedsUpdate() } } + open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } } } + diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 797e7e74..1de4c1aa 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -102,24 +102,16 @@ open class TextArea: EntryFieldBase { /// The text of this TextArea. private var _text: String? open var text: String? { - get { _text } + get { textView.text } set { - if let newValue, newValue != _text { - _text = newValue - textView.text = newValue - value = newValue - } + textView.text = newValue setNeedsUpdate() } } /// The value of this textField. open override var value: String? { - didSet { - if text != value { - text = value - } - } + return textView.text } /// UITextView shown in the TextArea. diff --git a/VDS/Protocols/FormFieldable.swift b/VDS/Protocols/FormFieldable.swift index 70a69ee5..83638cf4 100644 --- a/VDS/Protocols/FormFieldable.swift +++ b/VDS/Protocols/FormFieldable.swift @@ -15,7 +15,7 @@ public protocol FormFieldable { var inputId: String? { get set } /// Value for the Form Field. - var value: ValueType? { get set } + var value: ValueType? { get } } /// Protocol for FormFieldable that require internal validation. From 2e99210dfe6481974b75f6d562028915ea10dda8 Mon Sep 17 00:00:00 2001 From: vasavk Date: Wed, 24 Apr 2024 18:06:21 +0530 Subject: [PATCH 007/167] Digital ACT-191 ONEAPP-7016 story: added new page --- VDS.xcodeproj/project.pbxproj | 12 ++++++ VDS/Components/Calendar/Calendar.swift | 56 ++++++++++++++++++++++++++ VDS/VDS.docc/VDS.md | 1 + 3 files changed, 69 insertions(+) create mode 100644 VDS/Components/Calendar/Calendar.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index f805c10f..35f61ed9 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 186D13CB2BBA8B1500986B53 /* DropdownSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */; }; 186D13CF2BBC36EF00986B53 /* DropdownSelectChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */; }; 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; + 18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1292BD9298900498E4A /* Calendar.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; }; @@ -205,6 +206,7 @@ 186D13CA2BBA8B1500986B53 /* DropdownSelect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownSelect.swift; sourceTree = ""; }; 186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = DropdownSelectChangeLog.txt; sourceTree = ""; }; 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; + 18A3F1292BD9298900498E4A /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = ""; }; 18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; 18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = ""; }; 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = ""; }; @@ -415,6 +417,14 @@ path = DropdownSelect; sourceTree = ""; }; + 18A3F1202BD8F5DE00498E4A /* Calendar */ = { + isa = PBXGroup; + children = ( + 18A3F1292BD9298900498E4A /* Calendar.swift */, + ); + path = Calendar; + sourceTree = ""; + }; 18A65A002B96E7E1006602CC /* Breadcrumbs */ = { isa = PBXGroup; children = ( @@ -573,6 +583,7 @@ EAD062AE2A3B87210015965D /* BadgeIndicator */, 18A65A002B96E7E1006602CC /* Breadcrumbs */, EA0FC2BE2912D18200DF80B4 /* Buttons */, + 18A3F1202BD8F5DE00498E4A /* Calendar */, 1808BEBA2BA41B1D00129230 /* CarouselScrollbar */, EAF7F092289985E200B287F5 /* Checkbox */, 186D13C92BBA8A3500986B53 /* DropdownSelect */, @@ -1106,6 +1117,7 @@ EAB2376229E9880400AABE9A /* TrailingTooltipLabel.swift in Sources */, EAACB8982B92706F006A3869 /* DefaultValuing.swift in Sources */, EAB2376A29E9E59100AABE9A /* TooltipLaunchable.swift in Sources */, + 18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */, 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */, EAB2375D29E8789100AABE9A /* Tooltip.swift in Sources */, 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */, diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift new file mode 100644 index 00000000..b6aa9ecf --- /dev/null +++ b/VDS/Components/Calendar/Calendar.swift @@ -0,0 +1,56 @@ +// +// Calendar.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 19/04/24. +// + +import Foundation +import UIKit +import VDSTokens +import Combine + +/// A calendar is a monthly view that lets customers select a single date. +@objc(VDSCalendar) +open class CalendarBase: View { + + //-------------------------------------------------- + // 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) + } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + internal var containerSize: CGSize { CGSize(width: 290, height: 300) } + + internal var containerView = View().with { + $0.clipsToBounds = true + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func initialSetup() { + super.initialSetup() + } + + open override func setup() { + super.setup() + isAccessibilityElement = false + } + + open override func reset() { + super.reset() + } +} diff --git a/VDS/VDS.docc/VDS.md b/VDS/VDS.docc/VDS.md index 607e09f5..d145ea0a 100755 --- a/VDS/VDS.docc/VDS.md +++ b/VDS/VDS.docc/VDS.md @@ -25,6 +25,7 @@ Using the system allows designers and developers to collaborate more easily and - ``Button`` - ``ButtonIcon`` - ``ButtonGroup`` +- ``CalendarBase`` - ``CarouselScrollbar`` - ``Checkbox`` - ``CheckboxItem`` From 440f516522551cac8d1942cfc627db5e17cb16a5 Mon Sep 17 00:00:00 2001 From: vasavk Date: Fri, 26 Apr 2024 17:02:18 +0530 Subject: [PATCH 008/167] Digital ACT-191 ONEAPP-7016 story: changes for calendar base view with header and footer. --- VDS.xcodeproj/project.pbxproj | 8 ++ VDS/Components/Calendar/Calendar.swift | 100 +++++++++++++++++- .../CalendarDateCollectionViewCell.swift | 54 ++++++++++ .../Calendar/CalendarHeaderReusableView.swift | 57 ++++++++++ 4 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 VDS/Components/Calendar/CalendarDateCollectionViewCell.swift create mode 100644 VDS/Components/Calendar/CalendarHeaderReusableView.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 35f61ed9..5a2e0c91 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -17,6 +17,8 @@ 186D13CF2BBC36EF00986B53 /* DropdownSelectChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */; }; 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; 18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1292BD9298900498E4A /* Calendar.swift */; }; + 18A3F1322BD944E800498E4A /* CalendarDateCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */; }; + 18A3F1382BDA693000498E4A /* CalendarHeaderReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; }; @@ -207,6 +209,8 @@ 186D13CE2BBC36EE00986B53 /* DropdownSelectChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = DropdownSelectChangeLog.txt; sourceTree = ""; }; 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; 18A3F1292BD9298900498E4A /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = ""; }; + 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarDateCollectionViewCell.swift; sourceTree = ""; }; + 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarHeaderReusableView.swift; sourceTree = ""; }; 18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; 18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = ""; }; 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = ""; }; @@ -421,6 +425,8 @@ isa = PBXGroup; children = ( 18A3F1292BD9298900498E4A /* Calendar.swift */, + 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */, + 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */, ); path = Calendar; sourceTree = ""; @@ -1144,6 +1150,7 @@ 71ACE89C2BA0451200FB6ADC /* PaginationContainer.swift in Sources */, EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */, EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */, + 18A3F1322BD944E800498E4A /* CalendarDateCollectionViewCell.swift in Sources */, EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */, 71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */, EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */, @@ -1153,6 +1160,7 @@ 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */, EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */, EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */, + 18A3F1382BDA693000498E4A /* CalendarHeaderReusableView.swift in Sources */, EA985BE82968951C00F2FF2E /* TileletTitleModel.swift in Sources */, 71FC86DE2B9738B900700965 /* SurfaceConfigurationValue.swift in Sources */, EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */, diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index b6aa9ecf..641aee5d 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -32,12 +32,35 @@ open class CalendarBase: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var containerSize: CGSize { CGSize(width: 290, height: 300) } + internal var containerSize: CGSize { CGSize(width: 320, height: 376) } //width:320/328 + private let cellItemSize = CGSize(width: 40, height: 40) + private let headerHeight = 104.0 + private let footerHeight = 56.0 + private let items = 35 internal var containerView = View().with { $0.clipsToBounds = true } + ///Collectionview to render Breadcrumb Items + private lazy var collectionView: UICollectionView = { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + collectionView.isScrollEnabled = false + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.delegate = self + collectionView.dataSource = self + collectionView.showsHorizontalScrollIndicator = false + collectionView.showsVerticalScrollIndicator = false + collectionView.register(CalendarDateCollectionViewCell.self, forCellWithReuseIdentifier: CalendarDateCollectionViewCell.identifier) + collectionView.register(CalendarHeaderReusableView.self, + forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, + withReuseIdentifier: CalendarHeaderReusableView.identifier) + collectionView.register(CalendarFooterReusableView.self, + forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, + withReuseIdentifier: CalendarFooterReusableView.identifier) + return collectionView + }() + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -48,9 +71,84 @@ open class CalendarBase: View { open override func setup() { super.setup() isAccessibilityElement = false + + addSubview(containerView) + containerView + .pinTop() + .pinBottom() + .pinLeadingGreaterThanOrEqualTo() + .pinTrailingLessThanOrEqualTo() + .height(containerSize.height) + .width(containerSize.width) + + containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + + // Calendar View + containerView.addSubview(collectionView) + collectionView.pinToSuperView() } + override open func layoutSubviews() { + super.layoutSubviews() + } + open override func reset() { super.reset() } } + +extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + //-------------------------------------------------- + // MARK: - UICollectionView Delegate & Datasource + //-------------------------------------------------- + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + items + } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CalendarDateCollectionViewCell.identifier, for: indexPath) as? CalendarDateCollectionViewCell else { return UICollectionViewCell() } + return cell + } + + public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + if kind == UICollectionView.elementKindSectionHeader { + // Header + guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarHeaderReusableView.identifier, for: indexPath) as? CalendarHeaderReusableView else { + return UICollectionReusableView() + } + header.configure(with: true) + return header + } else { + // Footer + if kind == UICollectionView.elementKindSectionFooter { + guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarFooterReusableView.identifier, for: indexPath) as? CalendarFooterReusableView else { + return UICollectionReusableView() + } + footer.configure(with: true) + return footer + } + } + return UICollectionReusableView() + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + return CGSize(width: collectionView.frame.size.width, height: headerHeight) + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { + return CGSize(width: collectionView.frame.size.width, height: footerHeight) + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return VDSLayout.space1X + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return VDSLayout.space1X + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return cellItemSize + } + +} diff --git a/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift b/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift new file mode 100644 index 00000000..156cce04 --- /dev/null +++ b/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift @@ -0,0 +1,54 @@ +// +// CalendarDateCollectionViewCell.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 24/04/24. +// + +import Foundation +import UIKit +import VDSTokens + +///This is customised view for Calendar cell item +final class CalendarDateCollectionViewCell: UICollectionViewCell { + + ///Identifier for the Calendar Date Cell + static let identifier: String = String(describing: CalendarDateCollectionViewCell.self) + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- +// internal var stackView: UIStackView = { +// return UIStackView().with { +// $0.translatesAutoresizingMaskIntoConstraints = false +// $0.axis = .horizontal +// $0.distribution = .fill +// $0.alignment = .center +// $0.spacing = VDSLayout.space2X +// $0.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) +// $0.setContentHuggingPriority(.defaultHigh, for: .horizontal) +// } +// }() +// +// private lazy var selectionBackgroundView = View().with { +// $0.translatesAutoresizingMaskIntoConstraints = false +// $0.clipsToBounds = true +// $0.backgroundColor = .systemRed +// } +// +// private lazy var numberLabel = Label().with { +// $0.translatesAutoresizingMaskIntoConstraints = false +// $0.textAlignment = .center +// // $0.font +// // $0.textColor +// } + + override init(frame:CGRect) { + super.init(frame: frame) + contentView.backgroundColor = .link + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/VDS/Components/Calendar/CalendarHeaderReusableView.swift b/VDS/Components/Calendar/CalendarHeaderReusableView.swift new file mode 100644 index 00000000..3f139a10 --- /dev/null +++ b/VDS/Components/Calendar/CalendarHeaderReusableView.swift @@ -0,0 +1,57 @@ +// +// CalendarHeaderReusableView.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 24/04/24. +// + +import UIKit + +/// Custom header view +class CalendarHeaderReusableView: UICollectionReusableView { + + ///Identifier for the Calendar Header Reusable View + static let identifier: String = String(describing: CalendarHeaderReusableView.self) + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configure(with color: Bool) { + // Make a view and make in generic and dynamic + self.backgroundColor = .orange + } + + override func layoutSubviews() { + super.layoutSubviews() + } +} + +/// Custom footer view +class CalendarFooterReusableView: UICollectionReusableView { + + ///Identifier for the Calendar Footer Reusable View + static let identifier: String = String(describing: CalendarFooterReusableView.self) + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configure(with color: Bool) { + // Make a view and make in generic and dynamic + self.backgroundColor = .green + } + + override func layoutSubviews() { + super.layoutSubviews() + } +} + From 2b16fecdc353020b3dadc998913042413072c1e4 Mon Sep 17 00:00:00 2001 From: vasavk Date: Mon, 29 Apr 2024 10:10:26 +0530 Subject: [PATCH 009/167] Digital ACT-191 ONEAPP-7016 story: added calendar indicator model --- VDS.xcodeproj/project.pbxproj | 4 +++ .../Calendar/CalendarIndicatorModel.swift | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 VDS/Components/Calendar/CalendarIndicatorModel.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 5a2e0c91..1890cb34 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; }; 18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; }; + 18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; @@ -215,6 +216,7 @@ 18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = ""; }; 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = ""; }; 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = ""; }; + 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarIndicatorModel.swift; sourceTree = ""; }; 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; @@ -427,6 +429,7 @@ 18A3F1292BD9298900498E4A /* Calendar.swift */, 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */, 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */, + 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */, ); path = Calendar; sourceTree = ""; @@ -1247,6 +1250,7 @@ EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */, EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */, EAD068942A560C13002E3A2D /* LoaderLaunchable.swift in Sources */, + 18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */, EA985BEC2968A91200F2FF2E /* TitleLockupTitleModel.swift in Sources */, 5FC35BE328D51405004EBEAC /* Button.swift in Sources */, ); diff --git a/VDS/Components/Calendar/CalendarIndicatorModel.swift b/VDS/Components/Calendar/CalendarIndicatorModel.swift new file mode 100644 index 00000000..04ad9714 --- /dev/null +++ b/VDS/Components/Calendar/CalendarIndicatorModel.swift @@ -0,0 +1,25 @@ +// +// CalendarIndicatorModel.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 26/04/24. +// + +import Foundation + +/// Custom data type for indicators prop +extension CalendarBase { + public struct CalendarIndicatorModel { + + /// Text that shown to an indicator for legend + public var label: String + + /// Date to an indicator + public var date: Date + + public init(label: String, date: Date) { + self.label = label + self.date = date + } + } +} From 58ceee5d47f8f9f006609a51b1e6a3410679cddf Mon Sep 17 00:00:00 2001 From: vasavk Date: Mon, 29 Apr 2024 10:13:58 +0530 Subject: [PATCH 010/167] Digital ACT-191 ONEAPP-7016 story: added properties --- VDS/Components/Calendar/Calendar.swift | 58 +++++++++++++++++++++----- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index 641aee5d..cb938dde 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -29,6 +29,45 @@ open class CalendarBase: View { super.init(coder: coder) } + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + /// If set to true, the calendar will not have a border. + open var hideContainerBorder: Bool = false + + /// If set to true, the calendar will not have current date indication. + open var hideCurrentDateIndicator: Bool = false + + /// Enable specific days. Pass an array of string value in date format e.g. ['07/21/2024', '07/24/2024', 07/28/2024']. + /// All other dates will be inactive + open var activeDates: [Date] = [] + + /// Disable specific days. Pass an array of string value in date format e.g. ['07/21/2024', '07/24/2024', 07/28/2024']. + /// All other dates will be active. + open var inactiveDates: [Date] = [] + + /// If provided, the calendar will allow a selection to be made from this date forward. Defaults to today. + open var minDate: Date? + + /// If provided, the calendar will allow a selection to be made up to this date. + open var maxDate: Date? + + /// If provided, this is the date that will show as selected by the Calendar. + /// If no value is provided, the current date will be used. If null is provided, no date will be selected. + open var selectedDate: Date? + + /// If provided, the calendar will be rendered with transparent background. + open var transparentBackground: Bool = false + + /// Array of ``CalendarIndicatorModel`` you are wanting to show on legend. + open var indicators: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } + + /// Array of indicators for the legend. + open var indicatorData: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } + + /// A callback when the selected date changes.. + open var onChangeSelectedDate: ((Date) -> String)? + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -37,12 +76,12 @@ open class CalendarBase: View { private let headerHeight = 104.0 private let footerHeight = 56.0 private let items = 35 - + internal var containerView = View().with { $0.clipsToBounds = true } - ///Collectionview to render Breadcrumb Items + /// Collectionview to load calendar month view private lazy var collectionView: UICollectionView = { let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) collectionView.isScrollEnabled = false @@ -53,11 +92,11 @@ open class CalendarBase: View { collectionView.showsVerticalScrollIndicator = false collectionView.register(CalendarDateCollectionViewCell.self, forCellWithReuseIdentifier: CalendarDateCollectionViewCell.identifier) collectionView.register(CalendarHeaderReusableView.self, - forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, - withReuseIdentifier: CalendarHeaderReusableView.identifier) + forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, + withReuseIdentifier: CalendarHeaderReusableView.identifier) collectionView.register(CalendarFooterReusableView.self, - forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, - withReuseIdentifier: CalendarFooterReusableView.identifier) + forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, + withReuseIdentifier: CalendarFooterReusableView.identifier) return collectionView }() @@ -85,9 +124,9 @@ open class CalendarBase: View { // Calendar View containerView.addSubview(collectionView) - collectionView.pinToSuperView() + collectionView.pinToSuperView() } - + override open func layoutSubviews() { super.layoutSubviews() } @@ -146,9 +185,8 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return VDSLayout.space1X } - + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return cellItemSize } - } From 68d21296a7a76f588b76ff1b9f640c74dcfe8972 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 29 Apr 2024 15:16:56 -0500 Subject: [PATCH 011/167] Signed-off-by: Matt Bruce --- VDS/BaseClasses/Selector/SelectorGroupBase.swift | 6 +++--- VDS/BaseClasses/Selector/SelectorItemBase.swift | 7 ++++--- VDS/Components/Checkbox/CheckboxGroup.swift | 9 +++++++-- VDS/Components/Icon/ButtonIcon/ButtonIcon.swift | 6 +----- VDS/Components/RadioBox/RadioBoxGroup.swift | 5 +++++ VDS/Components/RadioBox/RadioBoxItem.swift | 6 ++++-- VDS/Components/RadioButton/RadioButtonGroup.swift | 8 ++++++-- VDS/Components/Toggle/Toggle.swift | 3 +-- VDS/Components/Toggle/ToggleView.swift | 3 +-- 9 files changed, 32 insertions(+), 21 deletions(-) diff --git a/VDS/BaseClasses/Selector/SelectorGroupBase.swift b/VDS/BaseClasses/Selector/SelectorGroupBase.swift index 997a71b2..1639ab86 100644 --- a/VDS/BaseClasses/Selector/SelectorGroupBase.swift +++ b/VDS/BaseClasses/Selector/SelectorGroupBase.swift @@ -20,7 +20,7 @@ extension SelectorGroup { public var hasSelectedItem: Bool { items.filter { $0.isSelected == true }.count > 0 } } -public protocol SelectorGroupMultiSelect: SelectorGroup {} +public protocol SelectorGroupMultiSelect: SelectorGroup, FormFieldable {} extension SelectorGroupMultiSelect { /// Current Selected Control for this group. public var selectedItems: [SelectorItemType]? { @@ -30,7 +30,7 @@ extension SelectorGroupMultiSelect { } } -public protocol SelectorGroupSingleSelect: SelectorGroup {} +public protocol SelectorGroupSingleSelect: SelectorGroup, FormFieldable {} extension SelectorGroupSingleSelect { /// Current Selected Control for this group. public var selectedItem: SelectorItemType? { @@ -39,7 +39,7 @@ extension SelectorGroupSingleSelect { } /// Base Class used for any Grouped Form Control of a Selector Type. -open class SelectorGroupBase: Control, SelectorGroup, Changeable { +open class SelectorGroupBase: Control, SelectorGroup, Changeable { //-------------------------------------------------- // MARK: - Private Properties diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index 9eee8f29..6a45e5e8 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -11,7 +11,7 @@ import Combine import VDSTokens /// Base Class used to build out a SelectorControlable control. -open class SelectorItemBase: Control, Errorable, Changeable, FormFieldable { +open class SelectorItemBase: Control, Errorable, Changeable { //-------------------------------------------------- // MARK: - Initializers @@ -141,8 +141,10 @@ open class SelectorItemBase: Control, Errorable, open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: AnyHashable? { hiddenValue } + open var hiddenValue: AnyHashable? { didSet { setNeedsUpdate() } } + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -214,7 +216,6 @@ open class SelectorItemBase: Control, Errorable, showError = false errorText = nil inputId = nil - value = nil isSelected = false onChange = nil diff --git a/VDS/Components/Checkbox/CheckboxGroup.swift b/VDS/Components/Checkbox/CheckboxGroup.swift index c7e424a1..1df8d9cd 100644 --- a/VDS/Components/Checkbox/CheckboxGroup.swift +++ b/VDS/Components/Checkbox/CheckboxGroup.swift @@ -14,6 +14,7 @@ import VDSTokens /// to allow user selection. @objc(VDSCheckboxGroup) open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSelect { + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -32,6 +33,10 @@ open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSel //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + public var inputId: String? + + public var value: [SelectorItemType]? { selectedItems } + /// Array of ``CheckboxItemModel`` that will be used to build the selectorViews of type ``CheckboxItem``. open var selectorModels: [CheckboxItemModel]? { didSet { @@ -41,7 +46,7 @@ open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSel $0.isEnabled = !model.disabled $0.surface = model.surface $0.inputId = model.inputId - $0.value = model.value + $0.hiddenValue = model.value $0.accessibilityLabel = model.accessibileText $0.accessibilityValue = "item \(index+1) of \(selectorModels.count)" $0.labelText = model.labelText @@ -97,7 +102,7 @@ open class CheckboxGroup: SelectorGroupBase, SelectorGroupMultiSel } extension CheckboxGroup { - public struct CheckboxItemModel : Surfaceable, Initable, FormFieldable, Errorable { + public struct CheckboxItemModel : Surfaceable, Initable, Errorable { /// Whether this object is disabled or not public var disabled: Bool diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 658cb05e..b97a1fac 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -14,7 +14,7 @@ import Combine /// It usually represents a supplementary or utilitarian action. A button icon can stand alone, but often /// exists in a group when there are several actions that can be performed. @objc(VDSButtonIcon) -open class ButtonIcon: Control, Changeable, FormFieldable { +open class ButtonIcon: Control, Changeable { //-------------------------------------------------- // MARK: - Initializers @@ -173,10 +173,6 @@ open class ButtonIcon: Control, Changeable, FormFieldable { /// Used to move the icon inside the button in both x and y axis. open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } } - open var inputId: String? { didSet { setNeedsUpdate() } } - - open var value: AnyHashable? { didSet { setNeedsUpdate() } } - //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index b31bcb0e..22e43426 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -32,6 +32,10 @@ open class RadioBoxGroup: SelectorGroupBase, SelectorGroupSingleSe //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + public var inputId: String? + + public var value: SelectorItemType? { selectedItem } + /// Array of ``RadioBoxItemModel`` that will be used to build the selectorViews of type ``RadioBoxItem``. open var selectorModels: [RadioBoxItemModel]? { didSet { @@ -48,6 +52,7 @@ open class RadioBoxGroup: SelectorGroupBase, SelectorGroupSingleSe $0.subTextRightAttributes = model.subTextRightAttributes $0.isEnabled = !model.disabled $0.inputId = model.inputId + $0.hiddenValue = model.value $0.isSelected = model.selected } } diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index 17d509c2..7828ed3c 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -125,7 +125,9 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: AnyHashable? { hiddenValue } + + open var hiddenValue: AnyHashable? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Configuration Properties @@ -209,7 +211,7 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { subTextRightAttributedText = nil strikethrough = false inputId = nil - value = nil + hiddenValue = nil isSelected = false onChange = nil diff --git a/VDS/Components/RadioButton/RadioButtonGroup.swift b/VDS/Components/RadioButton/RadioButtonGroup.swift index 6b12f60a..aecb8034 100644 --- a/VDS/Components/RadioButton/RadioButtonGroup.swift +++ b/VDS/Components/RadioButton/RadioButtonGroup.swift @@ -32,6 +32,10 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + public var inputId: String? + + public var value: SelectorItemType? { selectedItem } + /// Array of ``RadioButtonItemModel`` that will be used to build the selectorViews of type ``RadioButtonItem``. open var selectorModels: [RadioButtonItemModel]? { didSet { @@ -41,7 +45,7 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi $0.isEnabled = !model.disabled $0.surface = model.surface $0.inputId = model.inputId - $0.value = model.value + $0.hiddenValue = model.value $0.accessibilityLabel = model.accessibileText $0.accessibilityValue = "item \(index+1) of \(selectorModels.count)" $0.labelText = model.labelText @@ -57,7 +61,7 @@ open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSi setNeedsUpdate() } } - + private var _showError: Bool = false /// Whether not to show the error. diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index b73630d6..812d47d0 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -145,7 +145,7 @@ open class Toggle: Control, Changeable, FormFieldable { open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: AnyHashable? { isOn } /// The natural size for the receiving view, considering only properties of the view itself. open override var intrinsicContentSize: CGSize { @@ -224,7 +224,6 @@ open class Toggle: Control, Changeable, FormFieldable { textWeight = .regular textPosition = .left inputId = nil - value = nil onChange = nil shouldUpdateView = true setNeedsUpdate() diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index 16b8307e..8faf4def 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -68,7 +68,7 @@ open class ToggleView: Control, Changeable, FormFieldable { open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: AnyHashable? { isOn } /// The natural size for the receiving view, considering only properties of the view itself. open override var intrinsicContentSize: CGSize { toggleSize } @@ -163,7 +163,6 @@ open class ToggleView: Control, Changeable, FormFieldable { isOn = false isAnimated = true inputId = nil - value = nil toggleView.backgroundColor = toggleColorConfiguration.getColor(self) knobView.backgroundColor = knobColorConfiguration.getColor(self) onChange = nil From 39107082e7b6e8501d6def6cd2335a72e85a2814 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 29 Apr 2024 16:25:55 -0500 Subject: [PATCH 012/167] fixed bug with isSecureTextEntry Signed-off-by: Matt Bruce --- .../TextFields/InputField/InputField.swift | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index f43fc951..db722165 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -63,7 +63,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } /// UITextField shown in the InputField. - open var textField = UITextField().with { + open var textField = TextField().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.font = TextStyle.bodyLarge.font } @@ -88,6 +88,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { get { textField.text } set { textField.text = newValue + setNeedsUpdate() } } @@ -163,9 +164,9 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { textField .textPublisher .sink { [weak self] newText in + print("textPublisher newText: \(newText)") self?.text = newText self?.sendActions(for: .valueChanged) - if newText.isEmpty { self?.passwordActionType = .show } }.store(in: &subscribers) stackView.addArrangedSubview(successLabel) @@ -251,13 +252,13 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } open func updateFieldType() { - textField.isSecureTextEntry = false var minWidth: CGFloat = 40.0 var leftIconName: Icon.Name? var actionModel: InputField.TextLinkModel? var toolTipModel: Tooltip.TooltipModel? - + var isSecureTextEntry = false + switch fieldType { case .text: break @@ -271,7 +272,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { case .password: let isHide = passwordActionType == .hide let buttonText = isHide ? hidePasswordButtonText : showPasswordButtonText - let isSecureTextEntry = !isHide + isSecureTextEntry = !isHide let nextPasswordActionType = passwordActionType.toggle() if let text, !text.isEmpty { actionModel = .init(text: buttonText, @@ -279,7 +280,8 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { guard let self else { return } self.passwordActionType = nextPasswordActionType }) - textField.isSecureTextEntry = isSecureTextEntry + } else { + passwordActionType = .show } minWidth = 62.0 @@ -297,6 +299,9 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } + //textField + textField.isSecureTextEntry = isSecureTextEntry + //leftIcon leftIcon.surface = surface leftIcon.color = iconColorConfiguration.getColor(self) @@ -327,7 +332,7 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { } //tooltip - self.tooltipModel = toolTipModel + tooltipModel = toolTipModel } //-------------------------------------------------- @@ -347,3 +352,22 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } } } +public class TextField: UITextField { + + open override var isSecureTextEntry: Bool { + didSet { + if isFirstResponder { + _ = becomeFirstResponder() + } + } + } + + public override func becomeFirstResponder() -> Bool { + let success = super.becomeFirstResponder() + if isSecureTextEntry, let text { + self.text?.removeAll() + insertText(text) + } + return success + } +} From 7438d65fe53d2a46959c26be258eab2945cbf346 Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 30 Apr 2024 11:17:14 +0530 Subject: [PATCH 013/167] Digital ACT-191 ONEAPP-7016 story: updating footer with indicators data --- VDS.xcodeproj/project.pbxproj | 12 +- VDS/Components/Calendar/Calendar.swift | 13 +- .../Calendar/CalendarIndicatorModel.swift | 4 +- .../Calendar/CalendarLegendView.swift | 204 ++++++++++++++++++ ...eView.swift => CalendarReusableView.swift} | 13 +- 5 files changed, 230 insertions(+), 16 deletions(-) create mode 100644 VDS/Components/Calendar/CalendarLegendView.swift rename VDS/Components/Calendar/{CalendarHeaderReusableView.swift => CalendarReusableView.swift} (83%) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 1890cb34..354969af 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -18,12 +18,13 @@ 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; 18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1292BD9298900498E4A /* Calendar.swift */; }; 18A3F1322BD944E800498E4A /* CalendarDateCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */; }; - 18A3F1382BDA693000498E4A /* CalendarHeaderReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; }; 18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; }; 18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; }; + 18FEA1B12BE0B69300A56439 /* CalendarLegendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */; }; + 18FEA1B32BE0BC8700A56439 /* CalendarReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; @@ -211,12 +212,13 @@ 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; 18A3F1292BD9298900498E4A /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = ""; }; 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarDateCollectionViewCell.swift; sourceTree = ""; }; - 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarHeaderReusableView.swift; sourceTree = ""; }; 18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; 18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = ""; }; 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = ""; }; 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = ""; }; 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarIndicatorModel.swift; sourceTree = ""; }; + 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarLegendView.swift; sourceTree = ""; }; + 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarReusableView.swift; sourceTree = ""; }; 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; @@ -428,8 +430,9 @@ children = ( 18A3F1292BD9298900498E4A /* Calendar.swift */, 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */, - 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */, 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */, + 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */, + 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */, ); path = Calendar; sourceTree = ""; @@ -1163,7 +1166,6 @@ 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */, EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */, EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */, - 18A3F1382BDA693000498E4A /* CalendarHeaderReusableView.swift in Sources */, EA985BE82968951C00F2FF2E /* TileletTitleModel.swift in Sources */, 71FC86DE2B9738B900700965 /* SurfaceConfigurationValue.swift in Sources */, EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */, @@ -1216,7 +1218,9 @@ EA0B180A2AA78F9000F2D0CD /* UIEdgeInsets.swift in Sources */, EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */, EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */, + 18FEA1B12BE0B69300A56439 /* CalendarLegendView.swift in Sources */, EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */, + 18FEA1B32BE0BC8700A56439 /* CalendarReusableView.swift in Sources */, EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */, EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */, EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */, diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index cb938dde..c9312c4e 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -62,8 +62,8 @@ open class CalendarBase: View { /// Array of ``CalendarIndicatorModel`` you are wanting to show on legend. open var indicators: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } - /// Array of indicators for the legend. - open var indicatorData: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } +// /// Array of indicators for the legend. +// open var indicatorData: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } /// A callback when the selected date changes.. open var onChangeSelectedDate: ((Date) -> String)? @@ -76,7 +76,7 @@ open class CalendarBase: View { private let headerHeight = 104.0 private let footerHeight = 56.0 private let items = 35 - + internal var containerView = View().with { $0.clipsToBounds = true } @@ -127,6 +127,11 @@ open class CalendarBase: View { collectionView.pinToSuperView() } + open override func updateView() { + super.updateView() + collectionView.reloadData() + } + override open func layoutSubviews() { super.layoutSubviews() } @@ -163,7 +168,7 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarFooterReusableView.identifier, for: indexPath) as? CalendarFooterReusableView else { return UICollectionReusableView() } - footer.configure(with: true) + footer.configure(with: indicators) return footer } } diff --git a/VDS/Components/Calendar/CalendarIndicatorModel.swift b/VDS/Components/Calendar/CalendarIndicatorModel.swift index 04ad9714..911afe36 100644 --- a/VDS/Components/Calendar/CalendarIndicatorModel.swift +++ b/VDS/Components/Calendar/CalendarIndicatorModel.swift @@ -8,7 +8,7 @@ import Foundation /// Custom data type for indicators prop -extension CalendarBase { +//extension CalendarBase { public struct CalendarIndicatorModel { /// Text that shown to an indicator for legend @@ -22,4 +22,4 @@ extension CalendarBase { self.date = date } } -} +//} diff --git a/VDS/Components/Calendar/CalendarLegendView.swift b/VDS/Components/Calendar/CalendarLegendView.swift new file mode 100644 index 00000000..df1bbdf6 --- /dev/null +++ b/VDS/Components/Calendar/CalendarLegendView.swift @@ -0,0 +1,204 @@ +// +// CalendarLegendView.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 29/04/24. +// + +import Foundation +import UIKit +import VDSTokens +import Combine + +/// Legend view to show array of indicators as calendar footer view. +open class CalendarLegendView: View { + //-------------------------------------------------- + // 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) + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + open var items: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + internal var containerSize: CGSize { CGSize(width: 320, height: 56) } //width:320/328 + + internal var containerView = View().with { + $0.clipsToBounds = true + } + + private let flowLayout = UICollectionViewFlowLayout().with { + $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize + $0.minimumLineSpacing = VDSLayout.space1X + $0.minimumInteritemSpacing = VDSLayout.space4X + $0.scrollDirection = .vertical + } + open lazy var legendCollectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout).with { + $0.isScrollEnabled = false + $0.translatesAutoresizingMaskIntoConstraints = false + $0.showsVerticalScrollIndicator = false + $0.showsHorizontalScrollIndicator = false + $0.isAccessibilityElement = true + $0.backgroundColor = .clear + $0.delegate = self + $0.dataSource = self + $0.register(LegendCollectionViewCell.self, forCellWithReuseIdentifier: LegendCollectionViewCell.identifier) + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func initialSetup() { + super.initialSetup() + } + + open override func setup() { + super.setup() + isAccessibilityElement = false + + addSubview(containerView) + containerView + .pinTop(VDSLayout.space6X) + .pinBottom(VDSLayout.space4X) + .pinLeadingGreaterThanOrEqualTo(leadingAnchor, VDSLayout.space5X, .defaultLow) + .pinTrailingLessThanOrEqualTo(trailingAnchor, VDSLayout.space5X, .defaultHigh) + .height(containerSize.height) + .width(containerSize.width) + + containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + + // legend Collection View + containerView.addSubview(legendCollectionView) + legendCollectionView.pinToSuperView() + + } + + open override func updateView() { + super.updateView() + legendCollectionView.reloadData() + } + + override open func layoutSubviews() { + super.layoutSubviews() + } + + open override func reset() { + super.reset() + } +} + +extension CalendarLegendView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return items.count + } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard collectionView == legendCollectionView, + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LegendCollectionViewCell.identifier, for: indexPath) as? LegendCollectionViewCell, + indexPath.row <= items.count else { return UICollectionViewCell() } + let text = items[indexPath.row].label + cell.updateTitle(text: text, color: VDSColor.elementsSecondaryOnlight, surface: surface, clearFullcircle: indexPath.row == 1, drawSemiCircle: indexPath.row == 2) + return cell + } +} + +private class LegendCollectionViewCell: UICollectionViewCell { + + static let identifier: String = String(describing: LegendCollectionViewCell.self) + + private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + + private let indicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark) + + private var title = Label().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.textAlignment = .left + $0.numberOfLines = 1 + $0.textStyle = .bodySmall + $0.backgroundColor = .clear + $0.isAccessibilityElement = false + } + private var legendIndicatorWrapper: View = View().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.backgroundColor = .clear + } + private var legendIndicator: View = View().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.backgroundColor = .clear + $0.layer.borderWidth = 1.0 + } + + private lazy var stackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.distribution = .equalSpacing + $0.spacing = VDSLayout.space2X + $0.axis = .horizontal + $0.backgroundColor = .clear + } + + private lazy var shapeLayer = CAShapeLayer() + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + override init(frame: CGRect) { + super.init(frame: frame) + setupCell() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupCell() + } + + func setupCell() { + addSubview(stackView) + stackView.pinToSuperView() + + legendIndicatorWrapper.addSubview(legendIndicator) + legendIndicator.pinLeading().pinTrailing().width(8).height(8).pinCenterY() + + stackView.addArrangedSubview(legendIndicatorWrapper) + stackView.addArrangedSubview(title) + } + + func updateTitle(text: String, color: UIColor, surface: Surface, clearFullcircle: Bool, drawSemiCircle: Bool) { + title.text = text + title.textColor = textColorConfiguration.getColor(surface) + + legendIndicator.backgroundColor = drawSemiCircle ? .clear : (clearFullcircle ? .clear : color) + legendIndicator.layer.borderColor = indicatorColorConfiguration.getColor(surface).cgColor + + self.layoutIfNeeded() + + legendIndicator.layer.cornerRadius = legendIndicator.frame.size.height / 2.0 + + guard drawSemiCircle else { return } + + let center = CGPoint(x: legendIndicator.frame.size.width/2, y: legendIndicator.frame.size.height/2) + let path = UIBezierPath() + path.move(to: center) + path.addArc(withCenter: center, radius: center.x, startAngle: 2 * .pi, endAngle: .pi, clockwise: true) + path.close() + shapeLayer.path = path.cgPath + shapeLayer.fillColor = color.cgColor + + guard legendIndicator.layer.sublayers?.contains(shapeLayer) ?? true else { return } + legendIndicator.layer.addSublayer(shapeLayer) + } +} diff --git a/VDS/Components/Calendar/CalendarHeaderReusableView.swift b/VDS/Components/Calendar/CalendarReusableView.swift similarity index 83% rename from VDS/Components/Calendar/CalendarHeaderReusableView.swift rename to VDS/Components/Calendar/CalendarReusableView.swift index 3f139a10..8131ce33 100644 --- a/VDS/Components/Calendar/CalendarHeaderReusableView.swift +++ b/VDS/Components/Calendar/CalendarReusableView.swift @@ -1,11 +1,12 @@ // -// CalendarHeaderReusableView.swift +// CalendarReusableView.swift // VDS // // Created by Kanamarlapudi, Vasavi on 24/04/24. // import UIKit +import VDSTokens /// Custom header view class CalendarHeaderReusableView: UICollectionReusableView { @@ -23,7 +24,6 @@ class CalendarHeaderReusableView: UICollectionReusableView { func configure(with color: Bool) { // Make a view and make in generic and dynamic - self.backgroundColor = .orange } override func layoutSubviews() { @@ -37,6 +37,8 @@ class CalendarFooterReusableView: UICollectionReusableView { ///Identifier for the Calendar Footer Reusable View static let identifier: String = String(describing: CalendarFooterReusableView.self) + private lazy var footerView = CalendarLegendView() + override init(frame: CGRect) { super.init(frame: frame) } @@ -45,13 +47,12 @@ class CalendarFooterReusableView: UICollectionReusableView { fatalError("init(coder:) has not been implemented") } - func configure(with color: Bool) { - // Make a view and make in generic and dynamic - self.backgroundColor = .green + func configure(with indicators: [CalendarIndicatorModel]) { + footerView.items = indicators + addSubview(footerView) } override func layoutSubviews() { super.layoutSubviews() } } - From ef80db9e73c22888208b3c607784c364abc86175 Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 30 Apr 2024 14:21:43 +0530 Subject: [PATCH 014/167] Digital ACT-191 ONEAPP-7016 story: minor changes --- VDS/Components/Calendar/Calendar.swift | 1 + VDS/Components/Calendar/CalendarIndicatorModel.swift | 4 ++-- VDS/Components/Calendar/CalendarLegendView.swift | 4 +++- VDS/Components/Calendar/CalendarReusableView.swift | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index c9312c4e..a7ed560a 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -90,6 +90,7 @@ open class CalendarBase: View { collectionView.dataSource = self collectionView.showsHorizontalScrollIndicator = false collectionView.showsVerticalScrollIndicator = false + collectionView.backgroundColor = .clear collectionView.register(CalendarDateCollectionViewCell.self, forCellWithReuseIdentifier: CalendarDateCollectionViewCell.identifier) collectionView.register(CalendarHeaderReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, diff --git a/VDS/Components/Calendar/CalendarIndicatorModel.swift b/VDS/Components/Calendar/CalendarIndicatorModel.swift index 911afe36..04ad9714 100644 --- a/VDS/Components/Calendar/CalendarIndicatorModel.swift +++ b/VDS/Components/Calendar/CalendarIndicatorModel.swift @@ -8,7 +8,7 @@ import Foundation /// Custom data type for indicators prop -//extension CalendarBase { +extension CalendarBase { public struct CalendarIndicatorModel { /// Text that shown to an indicator for legend @@ -22,4 +22,4 @@ import Foundation self.date = date } } -//} +} diff --git a/VDS/Components/Calendar/CalendarLegendView.swift b/VDS/Components/Calendar/CalendarLegendView.swift index df1bbdf6..78826ffd 100644 --- a/VDS/Components/Calendar/CalendarLegendView.swift +++ b/VDS/Components/Calendar/CalendarLegendView.swift @@ -30,7 +30,7 @@ open class CalendarLegendView: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var items: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } + open var items: [CalendarBase.CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Private Properties @@ -90,6 +90,8 @@ open class CalendarLegendView: View { open override func updateView() { super.updateView() legendCollectionView.reloadData() + setNeedsLayout() + layoutIfNeeded() } override open func layoutSubviews() { diff --git a/VDS/Components/Calendar/CalendarReusableView.swift b/VDS/Components/Calendar/CalendarReusableView.swift index 8131ce33..96995006 100644 --- a/VDS/Components/Calendar/CalendarReusableView.swift +++ b/VDS/Components/Calendar/CalendarReusableView.swift @@ -47,7 +47,7 @@ class CalendarFooterReusableView: UICollectionReusableView { fatalError("init(coder:) has not been implemented") } - func configure(with indicators: [CalendarIndicatorModel]) { + func configure(with indicators: [CalendarBase.CalendarIndicatorModel]) { footerView.items = indicators addSubview(footerView) } From 23831589f0dba211193205d47b51a43424f0e6be Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 30 Apr 2024 19:19:28 +0530 Subject: [PATCH 015/167] Digital ACT-191 ONEAPP-7016 story: added header view and updated with week days --- VDS.xcodeproj/project.pbxproj | 8 + VDS/Components/Calendar/Calendar.swift | 13 +- .../Calendar/CalendarHeaderView.swift | 195 ++++++++++++++++++ .../Calendar/CalendarReusableView.swift | 4 +- VDS/Components/Calendar/Date+Extension.swift | 20 ++ 5 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 VDS/Components/Calendar/CalendarHeaderView.swift create mode 100644 VDS/Components/Calendar/Date+Extension.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 514e3fa0..33835770 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -25,6 +25,8 @@ 18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; }; 18FEA1B12BE0B69300A56439 /* CalendarLegendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */; }; 18FEA1B32BE0BC8700A56439 /* CalendarReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */; }; + 18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */; }; + 18FEA1B72BE0EBFE00A56439 /* CalendarHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B62BE0EBFE00A56439 /* CalendarHeaderView.swift */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; @@ -219,6 +221,8 @@ 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarIndicatorModel.swift; sourceTree = ""; }; 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarLegendView.swift; sourceTree = ""; }; 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarReusableView.swift; sourceTree = ""; }; + 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = ""; }; + 18FEA1B62BE0EBFE00A56439 /* CalendarHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarHeaderView.swift; sourceTree = ""; }; 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; @@ -433,6 +437,8 @@ 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */, 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */, 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */, + 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */, + 18FEA1B62BE0EBFE00A56439 /* CalendarHeaderView.swift */, ); path = Calendar; sourceTree = ""; @@ -1170,6 +1176,7 @@ 71FC86DE2B9738B900700965 /* SurfaceConfigurationValue.swift in Sources */, EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */, EA985BEA29689B6D00F2FF2E /* TileletSubTitleModel.swift in Sources */, + 18FEA1B72BE0EBFE00A56439 /* CalendarHeaderView.swift in Sources */, EA3361C9289054C50071C351 /* Surfaceable.swift in Sources */, EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */, EA4DB30228DCBCA500103EE3 /* Badge.swift in Sources */, @@ -1239,6 +1246,7 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */, EAF7F0B7289C12A600B287F5 /* UITapGestureRecognizer.swift in Sources */, EA0D1C392A6AD4DF00E5C127 /* Typography+SpacingConfig.swift in Sources */, + 18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */, EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */, EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */, EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */, diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index a7ed560a..0700bb55 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -101,6 +101,15 @@ open class CalendarBase: View { return collectionView }() + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + internal var containerBorderColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight , VDSColor.elementsPrimaryOndark) + internal var backgroundColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .normal) + $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .disabled) + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -122,7 +131,8 @@ open class CalendarBase: View { .width(containerSize.width) containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() - + containerView.layer.borderWidth = VDSFormControls.borderWidth + // Calendar View containerView.addSubview(collectionView) collectionView.pinToSuperView() @@ -131,6 +141,7 @@ open class CalendarBase: View { open override func updateView() { super.updateView() collectionView.reloadData() + containerView.layer.borderColor = containerBorderColorConfiguration.getColor(self).cgColor } override open func layoutSubviews() { diff --git a/VDS/Components/Calendar/CalendarHeaderView.swift b/VDS/Components/Calendar/CalendarHeaderView.swift new file mode 100644 index 00000000..2e591b94 --- /dev/null +++ b/VDS/Components/Calendar/CalendarHeaderView.swift @@ -0,0 +1,195 @@ +// +// CalendarHeaderView.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 30/04/24. +// + +import Foundation +import UIKit +import VDSTokens + +/// Header view to display month and year along with days of week +open class CalendarHeaderView: View { + //-------------------------------------------------- + // 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) + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + internal var containerSize: CGSize { CGSize(width: 320, height: 104) } //width:320/328 + + private lazy var stackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.distribution = .fill + $0.spacing = VDSLayout.space1X + $0.axis = .vertical + $0.backgroundColor = .clear + } + + private lazy var monthHeaderStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.distribution = .fill + $0.spacing = VDSLayout.space1X + $0.axis = .horizontal + $0.backgroundColor = .clear + } + + internal var containerView = View().with { + $0.clipsToBounds = true + $0.backgroundColor = .clear + } + internal var monthView = View() + internal var daysView = View() + internal let daysOfWeek = Date.capitalizedFirstLettersOfWeekdays + + private lazy var daysCollectionView: UICollectionView = { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + collectionView.isScrollEnabled = false + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.delegate = self + collectionView.dataSource = self + collectionView.showsHorizontalScrollIndicator = false + collectionView.showsVerticalScrollIndicator = false + collectionView.backgroundColor = .clear + collectionView.register(collectionViewCell.self, forCellWithReuseIdentifier: collectionViewCell.identifier) + return collectionView + }() + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func initialSetup() { + super.initialSetup() + } + + open override func setup() { + super.setup() + isAccessibilityElement = false + + // stackView + addSubview(containerView) + containerView + .pinTop() + .pinBottom() + .pinLeadingGreaterThanOrEqualTo() + .pinTrailingLessThanOrEqualTo() + .height(containerSize.height) + .width(containerSize.width) + containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + + // stackview + containerView.addSubview(stackView) + stackView + .pinTop(VDSLayout.space4X) + .pinLeading() + .pinTrailing() + .pinBottom(VDSLayout.space1X) + + // month label view, previous and next buttons + stackView.addArrangedSubview(monthView) + monthView.backgroundColor = .orange + monthView.heightAnchor.constraint(equalToConstant: 40).isActive = true + + // days Collection View + stackView.addArrangedSubview(daysCollectionView) + daysCollectionView.widthAnchor.constraint(equalTo: widthAnchor).activate() + daysCollectionView.heightAnchor.constraint(equalTo: monthView.heightAnchor).activate() + print("daysOfWeek: \(daysOfWeek)") + } + + open override func updateView() { + super.updateView() + daysCollectionView.reloadData() + } + + override open func layoutSubviews() { + super.layoutSubviews() + } + + open override func reset() { + super.reset() + } +} + +extension CalendarHeaderView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return daysOfWeek.count + } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCell.identifier, for: indexPath) as? collectionViewCell else { return UICollectionViewCell() } + cell.updateTitle(text: daysOfWeek[indexPath.row], surface: surface) + return cell + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: 40, height: 40) + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return VDSLayout.space1X + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return VDSLayout.space1X + } +} + +private class collectionViewCell: UICollectionViewCell { + + static let identifier: String = String(describing: collectionViewCell.self) + + private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark) + + private var title = Label().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.textAlignment = .center + $0.numberOfLines = 1 + $0.textStyle = .bodySmall + $0.backgroundColor = .clear + $0.isAccessibilityElement = false + } + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + override init(frame: CGRect) { + super.init(frame: frame) + setupCell() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupCell() + } + + func setupCell() { + addSubview(title) + title.pinToSuperView() + } + + func updateTitle(text: String, surface: Surface) { + title.surface = surface + title.text = text + title.textColor = textColorConfiguration.getColor(surface) + title.backgroundColor = .clear + } +} diff --git a/VDS/Components/Calendar/CalendarReusableView.swift b/VDS/Components/Calendar/CalendarReusableView.swift index 96995006..b348cc30 100644 --- a/VDS/Components/Calendar/CalendarReusableView.swift +++ b/VDS/Components/Calendar/CalendarReusableView.swift @@ -14,6 +14,8 @@ class CalendarHeaderReusableView: UICollectionReusableView { ///Identifier for the Calendar Header Reusable View static let identifier: String = String(describing: CalendarHeaderReusableView.self) + private lazy var headerView = CalendarHeaderView() + override init(frame: CGRect) { super.init(frame: frame) } @@ -23,7 +25,7 @@ class CalendarHeaderReusableView: UICollectionReusableView { } func configure(with color: Bool) { - // Make a view and make in generic and dynamic + addSubview(headerView) } override func layoutSubviews() { diff --git a/VDS/Components/Calendar/Date+Extension.swift b/VDS/Components/Calendar/Date+Extension.swift new file mode 100644 index 00000000..60036ee2 --- /dev/null +++ b/VDS/Components/Calendar/Date+Extension.swift @@ -0,0 +1,20 @@ +// +// Date+Extension.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 26/04/24. +// + +import Foundation + +extension Date { + static var capitalizedFirstLettersOfWeekdays: [String] { + let calendar = Calendar.current + let weekdays = calendar.shortWeekdaySymbols + + return weekdays.map { weekday in + guard let firstLetter = weekday.first else { return "" } + return String(firstLetter).capitalized + } + } +} From 36238890c79cf227ebfebb3d473a2f40614616bf Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 30 Apr 2024 19:39:50 +0530 Subject: [PATCH 016/167] Digital ACT-191 ONEAPP-7016 story: added change log --- VDS.xcodeproj/project.pbxproj | 4 + VDS/Components/Calendar/CalendarChangeLog.txt | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 VDS/Components/Calendar/CalendarChangeLog.txt diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 33835770..e75dc4c1 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 18FEA1B32BE0BC8700A56439 /* CalendarReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */; }; 18FEA1B52BE0E63600A56439 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */; }; 18FEA1B72BE0EBFE00A56439 /* CalendarHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B62BE0EBFE00A56439 /* CalendarHeaderView.swift */; }; + 18FEA1B92BE1301700A56439 /* CalendarChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18FEA1B82BE1301700A56439 /* CalendarChangeLog.txt */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; @@ -223,6 +224,7 @@ 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarReusableView.swift; sourceTree = ""; }; 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = ""; }; 18FEA1B62BE0EBFE00A56439 /* CalendarHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarHeaderView.swift; sourceTree = ""; }; + 18FEA1B82BE1301700A56439 /* CalendarChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CalendarChangeLog.txt; sourceTree = ""; }; 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; @@ -439,6 +441,7 @@ 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */, 18FEA1B42BE0E63600A56439 /* Date+Extension.swift */, 18FEA1B62BE0EBFE00A56439 /* CalendarHeaderView.swift */, + 18FEA1B82BE1301700A56439 /* CalendarChangeLog.txt */, ); path = Calendar; sourceTree = ""; @@ -1094,6 +1097,7 @@ EAA5EEB928ECD24B003B3210 /* Icons.xcassets in Resources */, EAEEECA92B1F969700531FC2 /* TooltipChangeLog.txt in Resources */, 186D13CF2BBC36EF00986B53 /* DropdownSelectChangeLog.txt in Resources */, + 18FEA1B92BE1301700A56439 /* CalendarChangeLog.txt in Resources */, EAEEEC9C2B1F8F0700531FC2 /* TextLinkCaretChangeLog.txt in Resources */, EAA5EEE428F5B855003B3210 /* VerizonNHGDS-Light.otf in Resources */, 71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */, diff --git a/VDS/Components/Calendar/CalendarChangeLog.txt b/VDS/Components/Calendar/CalendarChangeLog.txt new file mode 100644 index 00000000..ee6928a3 --- /dev/null +++ b/VDS/Components/Calendar/CalendarChangeLog.txt @@ -0,0 +1,84 @@ +MM/DD/YYYY +---------------- +- Initial Brand 3.0 handoff + +12/24/2021 +---------------- +- Replaced focusring colors (previously interactive/onlight/ondark) with accessibility/onlight/ondark colors +- Updated focus border name (previously interactive.focusring.onlight) with focusring.onlight/ondark +- Updated the SPECS with FormControl tokens and corner radius tokens + +02/24/2022 +---------------- +- Replaced Caret Left and Right icons with bold assets. + +02/28/2022 +---------------- +- Removed dev note from Hover state and added a dev note to Active state. + +03/11/2022 +---------------- +- Update Hover and Active states triggers for carets. Icon swap and color change for mouse-only, and color change for touch. + +05/25/2022 +---------------- +- Added date indicator feature (including legend), today’s date indicator, and size/spacing adjustments to support this. + +07/20/2022 +---------------- +- Added configuration page. +- To configuration added transparent background and border suppression. + +08/10/2022 +---------------- +- Updated inverted and default to light and dark surface. Also, updated dark to selected. + +08/16/2022 +---------------- +- Updated default date background to be transparent. Updated border configuration prop name to hideContainerBorder. +- Moved Width from Configurations to Layout and Spacing, and Calendar Indicator specs under Elements. + +11/30/2022 +---------------- +- Added "(web only)" to any instance of "keyboard focus" + +12/13/2022 +---------------- +- Replaced form border and focus border pixel values, styles & spacing with tokens. + +01/09/2023 +---------------- +- Updated Specs to use new SPEC Templates and SPEC DOC Components. + +01/10/2023 +---------------- +- Updated Anatomy item #8 to “Current Date” to match design doc (originally “Today’s Date) + +04/12/2023 +---------------- +- Updated palette colors for Current date. + +05/01/2023 +---------------- +- Updated Day Header Text Style from Bold to Regular +- Updated Date Disabled Text Style from Bold to Regular +- Updated Date Text Style from Bold to Regular +- Updated Current Date font color from blue to black on light and white on dark. +- Updated all frames to reflect new designs. + +05/09/2023 +---------------- +- Replaced Previous and Next carets with Button Icon in: +Anatomy +Configurations +States + +11/09/2023 +---------------- +- Added component tokens +- Applied component tokens to selected states on light and dark surfaces +- Removed redundant color specifications from other sections + +11/30/2023 +---------------- +- Revised selected container background inverse tokens from onlight/ondark to light/dark From 5a0018319fb20cef51f117f09d26250971899ea2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 11:54:12 -0500 Subject: [PATCH 017/167] CXTDT-552068 - Text Area - Text padding Signed-off-by: Matt Bruce --- VDS/Components/TextFields/TextArea/TextArea.swift | 2 ++ VDS/SupportingFiles/ReleaseNotes.txt | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index d057333b..732ac7ac 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -127,6 +127,8 @@ open class TextArea: EntryFieldBase { $0.translatesAutoresizingMaskIntoConstraints = false $0.sizeToFit() $0.isScrollEnabled = false + $0.textContainerInset = .zero + $0.textContainer.lineFragmentPadding = 0 } open var maxLength: Int? { diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 855ef058..3e3f0258 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,3 +1,7 @@ +1.0.61 +---------------- +- CXTDT-552068 - Text Area - Text padding + 1.0.60 ---------------- - CXTDT-544442 - Button Icon - Selected state needs to allow custom color From 000e4cdefae703a5e03df87975788b188f8f0357 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 12:15:43 -0500 Subject: [PATCH 018/167] CXTDT-552074 - Text Area - Tooltip Signed-off-by: Matt Bruce --- .../Label/Attributes/TooltipLabelAttribute.swift | 8 +++++--- VDS/SupportingFiles/ReleaseNotes.txt | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift index 187d4eda..20666b10 100644 --- a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -37,17 +37,19 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable } var frame = CGRect.zero + let ratio: Double = 1.0 //0.80 + let yPosition: Double = -3 if let font = attributedString.attribute(.font, at: 0, effectiveRange: &originalRange) as? UIFont { switch font.pointSize { case 15..<25: size = .medium - frame = CGRect(x: 0, y: -1, width: size.value.dimensions.width * 0.80, height: size.value.dimensions.height * 0.80) + frame = CGRect(x: 0, y: yPosition, width: size.value.dimensions.width * ratio, height: size.value.dimensions.height * ratio) case 0..<14: size = .small - frame = CGRect(x: 0, y: -1, width: size.value.dimensions.width * 0.80 , height: size.value.dimensions.height * 0.80) + frame = CGRect(x: 0, y: yPosition, width: size.value.dimensions.width * ratio , height: size.value.dimensions.height * ratio) default: size = .medium - frame = CGRect(x: 0, y: -1, width: size.value.dimensions.width, height: size.value.dimensions.height) + frame = CGRect(x: 0, y: yPosition, width: size.value.dimensions.width, height: size.value.dimensions.height) } } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 3e3f0258..e09e37c0 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,6 +1,7 @@ 1.0.61 ---------------- - CXTDT-552068 - Text Area - Text padding +- CXTDT-552074 - Text Area - Tooltip 1.0.60 ---------------- From b80dcda680264d0b71f5c4c2e109d2e6975ca70e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 12:31:55 -0500 Subject: [PATCH 019/167] CXTDT-552070 - Text Area - Container heights Signed-off-by: Matt Bruce --- VDS/Components/TextFields/EntryFieldBase.swift | 2 +- VDS/Components/TextFields/TextArea/TextArea.swift | 9 +++++---- VDS/SupportingFiles/ReleaseNotes.txt | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index a8ad917a..2fae06c0 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -239,7 +239,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { //this is the horizontal stack that contains //the left, InputContainer, Icons, Buttons container.addSubview(containerStackView) - containerStackView.pinToSuperView(.uniform(12)) + containerStackView.pinToSuperView(.uniform(VDSLayout.space3X)) //add the view to add input fields containerStackView.addArrangedSubview(controlContainerView) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 732ac7ac..83f940bb 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -86,15 +86,16 @@ open class TextArea: EntryFieldBase { case twoX = "2X" case fourX = "4X" case eightX = "8X" + var containerVerticalPadding: CGFloat { VDSLayout.space3X * 2 } var value: CGFloat { switch self { case .twoX: - 88 + 88 - containerVerticalPadding case .fourX: - 176 + 176 - containerVerticalPadding case .eightX: - 352 + 352 - containerVerticalPadding } } } @@ -176,7 +177,7 @@ open class TextArea: EntryFieldBase { .pinBottom(0, .defaultHigh) textView.isScrollEnabled = true textView.autocorrectionType = .no - textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: containerSize.height) + textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: Height.twoX.value) textViewHeightConstraint?.isActive = true backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index e09e37c0..1df8f3a6 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -2,7 +2,7 @@ ---------------- - CXTDT-552068 - Text Area - Text padding - CXTDT-552074 - Text Area - Tooltip - +- CXTDT-552070 - Text Area - Container heights 1.0.60 ---------------- - CXTDT-544442 - Button Icon - Selected state needs to allow custom color From 83e0c4ab53fe249ea7e0a8cb28ea23cc9f562c82 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 13:15:31 -0500 Subject: [PATCH 020/167] CXTDT-552071 - Text Area - Entering text Signed-off-by: Matt Bruce --- .../TextFields/EntryFieldBase.swift | 1 + .../TextFields/TextArea/TextArea.swift | 23 +++++++++++++++++-- VDS/SupportingFiles/ReleaseNotes.txt | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 2fae06c0..2f776ab8 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -107,6 +107,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { internal var borderColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forState: .focused) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled,.error]) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 83f940bb..ad76b0f2 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -79,7 +79,18 @@ open class TextArea: EntryFieldBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - override var containerSize: CGSize { CGSize(width: 182, height: 88) } + /// Override UIControl state to add the .error state if showSuccess is true and if showError is true. + open override var state: UIControl.State { + get { + var state = super.state + if textView.isFirstResponder && !showError && !hasInternalError { + state.insert(.focused) + } + return state + } + } + + override var containerSize: CGSize { CGSize(width: 182, height: Height.twoX.value) } /// Enum used to describe the the height of TextArea. public enum Height: String, CaseIterable { @@ -177,7 +188,7 @@ open class TextArea: EntryFieldBase { .pinBottom(0, .defaultHigh) textView.isScrollEnabled = true textView.autocorrectionType = .no - textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: Height.twoX.value) + textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: containerSize.height) textViewHeightConstraint?.isActive = true backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) @@ -309,6 +320,14 @@ open class TextArea: EntryFieldBase { } extension TextArea: UITextViewDelegate { + public func textViewDidBeginEditing(_ textView: UITextView) { + setNeedsUpdate() + } + + public func textViewDidEndEditing(_ textView: UITextView) { + setNeedsUpdate() + } + //-------------------------------------------------- // MARK: - UITextViewDelegate //-------------------------------------------------- diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 1df8f3a6..8ffb31cb 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -3,6 +3,8 @@ - CXTDT-552068 - Text Area - Text padding - CXTDT-552074 - Text Area - Tooltip - CXTDT-552070 - Text Area - Container heights +- CXTDT-552071 - Text Area - Entering text + 1.0.60 ---------------- - CXTDT-544442 - Button Icon - Selected state needs to allow custom color From 896d393d7a4dd7ba53e33760610a123036414573 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 13:24:37 -0500 Subject: [PATCH 021/167] updated for focused Signed-off-by: Matt Bruce --- .../TextFields/InputField/InputField.swift | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 62b361c6..f18a6224 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -14,7 +14,7 @@ import Combine /// Specialized input fields capture credit card numbers, inline actions, passwords, phone numbers, /// dates and security codes in their correct formats. @objc(VDSInputField) -open class InputField: EntryFieldBase, UITextFieldDelegate { +open class InputField: EntryFieldBase { //-------------------------------------------------- // MARK: - Initializers @@ -127,7 +127,11 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { var state = super.state if showSuccess { state.insert(.success) + + } else if textField.isFirstResponder && !showError && !hasInternalError { + state.insert(.focused) } + return state } } @@ -160,7 +164,8 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { controlStackView.addArrangedSubview(leftIcon) controlStackView.addArrangedSubview(textField) - + + textField.delegate = self textField.heightAnchor.constraint(equalToConstant: 20).isActive = true textField .textPublisher @@ -373,6 +378,16 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { open var showPasswordButtonText: String = "Show" { didSet { setNeedsUpdate() } } } +extension InputField: UITextFieldDelegate { + public func textFieldDidBeginEditing(_ textField: UITextField) { + setNeedsUpdate() + } + + public func textFieldDidEndEditing(_ textField: UITextField) { + setNeedsUpdate() + } +} + public class TextField: UITextField { open override var isSecureTextEntry: Bool { From aa4dc91afabc0c7e2e575ecbaaca2a67fec53fc1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 13:51:13 -0500 Subject: [PATCH 022/167] updated for password field Signed-off-by: Matt Bruce --- VDS/Components/TextFields/InputField/InputField.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index f18a6224..9200a5f7 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -262,7 +262,7 @@ open class InputField: EntryFieldBase { var minWidth: CGFloat = 40.0 var leftIconName: Icon.Name? var actionModel: InputField.TextLinkModel? - var toolTipModel: Tooltip.TooltipModel? + var toolTipModel: Tooltip.TooltipModel? = tooltipModel var isSecureTextEntry = false switch fieldType { @@ -277,7 +277,10 @@ open class InputField: EntryFieldBase { case .password: let isHide = passwordActionType == .hide - let buttonText = isHide ? hidePasswordButtonText : showPasswordButtonText + let buttonText = isHide ? + hidePasswordButtonText.isEmpty ? "Hide" : hidePasswordButtonText : + showPasswordButtonText.isEmpty ? "Show" : showPasswordButtonText + isSecureTextEntry = !isHide let nextPasswordActionType = passwordActionType.toggle() if let text, !text.isEmpty { From cfc21c2727b31f35cfbd892960501a751a7a8703 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 14:10:36 -0500 Subject: [PATCH 023/167] added internal rules Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 16 ++++++++++++++++ .../TextFields/Rules/CharacterCountRule.swift | 18 ++++++++++++++++++ .../TextFields/Rules/RequiredRule.swift | 19 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 VDS/Components/TextFields/Rules/CharacterCountRule.swift create mode 100644 VDS/Components/TextFields/Rules/RequiredRule.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 308c7f47..ccc8e61d 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -54,6 +54,8 @@ EA21C5DB2B600EDE00CFC139 /* VDSTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA21C5DA2B600EDD00CFC139 /* VDSTokens.xcframework */; }; EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */; }; EA297A5729FB0A360031ED56 /* AppleGuidelinesTouchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */; }; + EA2DC9B02BE175BA004F58C5 /* RequiredRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */; }; + EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9B12BE175E6004F58C5 /* CharacterCountRule.swift */; }; EA336171288B19200071C351 /* VDS.docc in Sources */ = {isa = PBXBuildFile; fileRef = EA336170288B19200071C351 /* VDS.docc */; }; EA336177288B19210071C351 /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA33616C288B19200071C351 /* VDS.framework */; }; EA33617C288B19210071C351 /* VDSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33617B288B19210071C351 /* VDSTests.swift */; }; @@ -243,6 +245,8 @@ EA21C5DA2B600EDD00CFC139 /* VDSTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTokens.xcframework; path = ../SharedFrameworks/VDSTokens.xcframework; sourceTree = ""; }; EA297A5429FB07760031ED56 /* TooltipLabelAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipLabelAttribute.swift; sourceTree = ""; }; EA297A5629FB0A360031ED56 /* AppleGuidelinesTouchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesTouchable.swift; sourceTree = ""; }; + EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequiredRule.swift; sourceTree = ""; }; + EA2DC9B12BE175E6004F58C5 /* CharacterCountRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCountRule.swift; sourceTree = ""; }; EA33616C288B19200071C351 /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA33616F288B19200071C351 /* VDS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VDS.h; sourceTree = ""; }; EA336170288B19200071C351 /* VDS.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = VDS.docc; sourceTree = ""; }; @@ -512,6 +516,15 @@ path = ButtonGroup; sourceTree = ""; }; + EA2DC9AE2BE175A6004F58C5 /* Rules */ = { + isa = PBXGroup; + children = ( + EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */, + EA2DC9B12BE175E6004F58C5 /* CharacterCountRule.swift */, + ); + path = Rules; + sourceTree = ""; + }; EA336162288B19200071C351 = { isa = PBXGroup; children = ( @@ -875,6 +888,7 @@ EAC925852911C9DE00091998 /* TextFields */ = { isa = PBXGroup; children = ( + EA2DC9AE2BE175A6004F58C5 /* Rules */, EAC9258B2911C9DE00091998 /* EntryFieldBase.swift */, EAC925862911C9DE00091998 /* InputField */, EA985C21296E032000F2FF2E /* TextArea */, @@ -1136,6 +1150,7 @@ 71ACE89E2BA1CC1700FB6ADC /* TiletEyebrowModel.swift in Sources */, EAF7F11728A1475A00B287F5 /* RadioButtonItem.swift in Sources */, EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */, + EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */, EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */, EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */, 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */, @@ -1145,6 +1160,7 @@ 71FC86DE2B9738B900700965 /* SurfaceConfigurationValue.swift in Sources */, EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */, EA985BEA29689B6D00F2FF2E /* TileletSubTitleModel.swift in Sources */, + EA2DC9B02BE175BA004F58C5 /* RequiredRule.swift in Sources */, EA3361C9289054C50071C351 /* Surfaceable.swift in Sources */, EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */, EA4DB30228DCBCA500103EE3 /* Badge.swift in Sources */, diff --git a/VDS/Components/TextFields/Rules/CharacterCountRule.swift b/VDS/Components/TextFields/Rules/CharacterCountRule.swift new file mode 100644 index 00000000..f26ccafc --- /dev/null +++ b/VDS/Components/TextFields/Rules/CharacterCountRule.swift @@ -0,0 +1,18 @@ +// +// CharacterCountRule.swift +// VDS +// +// Created by Matt Bruce on 4/30/24. +// + +import Foundation + +class CharacterCountRule: Rule { + var maxLength: Int? + var errorMessage: String = "You have exceeded the character limit." + + func isValid(value: String?) -> Bool { + guard let text = value, let maxLength, maxLength > 0 else { return true } + return text.count <= maxLength + } +} diff --git a/VDS/Components/TextFields/Rules/RequiredRule.swift b/VDS/Components/TextFields/Rules/RequiredRule.swift new file mode 100644 index 00000000..df00bc59 --- /dev/null +++ b/VDS/Components/TextFields/Rules/RequiredRule.swift @@ -0,0 +1,19 @@ +// +// RequiredRule.swift +// VDS +// +// Created by Matt Bruce on 4/30/24. +// + +import Foundation + +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 } + return true + } +} + From 1813661f7d7c4674f934926138edad2f7b3310ab Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 Apr 2024 15:48:29 -0500 Subject: [PATCH 024/167] updated states Signed-off-by: Matt Bruce --- .../TextFields/EntryFieldBase.swift | 59 ++++++++++++++----- .../TextFields/InputField/InputField.swift | 19 ++++-- .../TextFields/TextArea/TextArea.swift | 20 +++---- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 63f0ca69..390c2b9a 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -83,6 +83,8 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } }() + open var rules = [AnyRule]() + //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- @@ -103,11 +105,13 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .normal) $0.setSurfaceColors(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + $0.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: [.error, .focused]) } internal var borderColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forState: .focused) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forState: [.focused, .error]) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.disabled,.error]) @@ -159,7 +163,10 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { internal var validator: (any FormFieldValidatorable)? /// Whether or not to show the internal error - open var hasInternalError: Bool { !(validator?.isValid ?? true) } + open var hasInternalError: Bool { + guard let validator, !showError else { return false } + return !validator.isValid + } /// Override UIControl state to add the .error state if showError is true. open override var state: UIControl.State { @@ -304,15 +311,30 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - + updateRules() + validator = FormFieldValidator(field: self, rules: rules) + updateContainerView() updateTitleLabel() updateErrorLabel() updateHelperLabel() backgroundColor = surface.color - validator?.validate() - internalErrorText = validator?.errorMessage + + if let validator { + validator.validate() + if validator.isValid { + internalErrorText = nil + } else { + if let errorText, errorText.isEmpty { + internalErrorText = errorText + } else { + internalErrorText = validator.errorMessage + } + } + } else { + internalErrorText = nil + } } //-------------------------------------------------- @@ -338,6 +360,21 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { return bottomContainerView } + internal func updateRules() { + rules.removeAll() + if self.required { + let rule = RequiredRule() + if let errorText { + rule.errorMessage = errorText + } else if let labelText{ + rule.errorMessage = "You must enter a \(labelText)" + } else { + rule.errorMessage = "You must enter a value" + } + rules.append(.init(rule)) + } + } + open func updateTitleLabel() { //update the local vars for the label since we no @@ -369,22 +406,14 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { } open func updateErrorLabel(){ - if showError, hasInternalError, let errorText, let internalErrorText { - errorLabel.text = [internalErrorText, errorText].joined(separator: "\n") - errorLabel.surface = surface - errorLabel.isEnabled = isEnabled - errorLabel.isHidden = false - statusIcon.name = .error - statusIcon.surface = surface - statusIcon.isHidden = !isEnabled - } else if showError, let errorText { + if showError, let errorText { errorLabel.text = errorText errorLabel.surface = surface errorLabel.isEnabled = isEnabled errorLabel.isHidden = false statusIcon.name = .error statusIcon.surface = surface - statusIcon.isHidden = !isEnabled + statusIcon.isHidden = !isEnabled || state.contains(.focused) } else if hasInternalError, let internalErrorText { errorLabel.text = internalErrorText errorLabel.surface = surface @@ -392,7 +421,7 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { errorLabel.isHidden = false statusIcon.name = .error statusIcon.surface = surface - statusIcon.isHidden = !isEnabled + statusIcon.isHidden = !isEnabled || state.contains(.focused) } else { statusIcon.isHidden = true errorLabel.isHidden = true diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 9200a5f7..071790c5 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -210,13 +210,15 @@ open class InputField: EntryFieldBase { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { + + //update fieldType first + updateFieldType() + super.updateView() textField.isEnabled = isEnabled textField.textColor = textFieldTextColorConfiguration.getColor(self) - - updateFieldType() - + //show error or success if showError, let _ = errorText { successLabel.isHidden = true @@ -264,7 +266,16 @@ open class InputField: EntryFieldBase { var actionModel: InputField.TextLinkModel? var toolTipModel: Tooltip.TooltipModel? = tooltipModel var isSecureTextEntry = false - + var rules = [AnyRule]() + + if self.required { + let rule = RequiredRule() + if let errorText { + rule.errorMessage = errorText + } + rules.append(.init(rule)) + } + switch fieldType { case .text: break diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 796fe6cd..8dd9485a 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -83,7 +83,7 @@ open class TextArea: EntryFieldBase { open override var state: UIControl.State { get { var state = super.state - if textView.isFirstResponder && !showError && !hasInternalError { + if textView.isFirstResponder { state.insert(.focused) } return state @@ -162,8 +162,6 @@ open class TextArea: EntryFieldBase { open override func setup() { super.setup() isAccessibilityElement = false - validator = FormFieldValidator