From fb623627bf1467f1995bb9e7d12fa4ddde1da9f4 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Feb 2024 15:38:25 -0600 Subject: [PATCH 001/147] fixed bug where someone could nil out attributedText and resetting the text with the same value wouldn't trigger setNeedsUpdate() Signed-off-by: Matt Bruce --- VDS/Components/Label/Label.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 7ecb79cd..67e53abe 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -135,15 +135,15 @@ open class Label: UILabel, ViewProtocol, UserInfoable { override open var text: String? { get { _text } set { - if _text != newValue { + if _text != newValue || newValue != attributedText?.string { _text = newValue useAttributedText = false - attributes = nil + attributes?.removeAll() setNeedsUpdate() } } } - + /// Whether the View is enabled or not. open override var isEnabled: Bool { didSet { setNeedsUpdate() } } From aa30561b298ccfc36bb792702a7bc3e2581c2a2f Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 16 Feb 2024 09:33:39 -0600 Subject: [PATCH 002/147] refactored naming conventions Signed-off-by: Matt Bruce --- VDS/Components/Tilelet/TileletSubTitleModel.swift | 12 ++++++------ VDS/Components/TitleLockup/TitleLockup.swift | 2 +- .../TitleLockup/TitleLockupSubTitleModel.swift | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/VDS/Components/Tilelet/TileletSubTitleModel.swift b/VDS/Components/Tilelet/TileletSubTitleModel.swift index dab4c81c..ae28d958 100644 --- a/VDS/Components/Tilelet/TileletSubTitleModel.swift +++ b/VDS/Components/Tilelet/TileletSubTitleModel.swift @@ -14,7 +14,7 @@ extension Tilelet { // MARK: - Enums //-------------------------------------------------- /// Enum used to describe the textStyle of the subTitle label. - public enum StandardStyle: String, EnumSubset { + public enum OtherStandardStyle: String, EnumSubset { case bodyLarge case bodyMedium case bodySmall @@ -28,7 +28,7 @@ extension Tilelet { public var text: String = "" /// Text style that will be used for the subTitle label. - public var standardStyle: StandardStyle = .bodySmall + public var otherStandardStyle: OtherStandardStyle = .bodySmall /// Text attributes that will be used for the subTitle label. public var textAttributes: [any LabelAttributeModel]? @@ -40,13 +40,13 @@ extension Tilelet { // MARK: - Initializers //-------------------------------------------------- public init(text: String, + otherStandardStyle: OtherStandardStyle = .bodySmall, textColor: Use = .primary, - textAttributes: [any LabelAttributeModel]? = nil, - standardStyle: StandardStyle = .bodySmall) { + textAttributes: [any LabelAttributeModel]? = nil) { self.text = text + self.otherStandardStyle = otherStandardStyle self.textAttributes = textAttributes self.textColor = textColor - self.standardStyle = standardStyle } //-------------------------------------------------- @@ -55,7 +55,7 @@ extension Tilelet { /// Converts this type of model to a TitleLockup.SubTitleModel. public func toTitleLockupSubTitleModel() -> TitleLockup.SubTitleModel { TitleLockup.SubTitleModel(text: text, - standardStyle: standardStyle.value, + otherStandardStyle: otherStandardStyle.value, textColor: textColor, textAttributes: textAttributes) } diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index dbfd8637..e11b674d 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -45,7 +45,7 @@ open class TitleLockup: View { //-------------------------------------------------- private var otherStandardStyle: OtherStandardStyle { if let subTitleModel, !subTitleModel.text.isEmpty { - return subTitleModel.standardStyle + return subTitleModel.otherStandardStyle } else if let eyebrowModel, !eyebrowModel.text.isEmpty { return eyebrowModel.standardStyle } else { diff --git a/VDS/Components/TitleLockup/TitleLockupSubTitleModel.swift b/VDS/Components/TitleLockup/TitleLockupSubTitleModel.swift index 3ba6c7ff..4ac0922c 100644 --- a/VDS/Components/TitleLockup/TitleLockupSubTitleModel.swift +++ b/VDS/Components/TitleLockup/TitleLockupSubTitleModel.swift @@ -14,7 +14,7 @@ extension TitleLockup { public var text: String /// Standard style that will be used for the subTitle label. - public var standardStyle: OtherStandardStyle + public var otherStandardStyle: OtherStandardStyle /// Text color used in the subtitle label. public var textColor: Use @@ -26,19 +26,19 @@ extension TitleLockup { public var numberOfLines: Int public init(text: String, - standardStyle: OtherStandardStyle = .bodyLarge, + otherStandardStyle: OtherStandardStyle = .bodyLarge, textColor: Use = .primary, textAttributes: [any LabelAttributeModel]? = nil, numberOfLines: Int = 0) { self.text = text - self.standardStyle = standardStyle + self.otherStandardStyle = otherStandardStyle self.textColor = textColor self.textAttributes = textAttributes self.numberOfLines = numberOfLines } /// TextStyle used to render the text. - public var textStyle: TextStyle { standardStyle.value.regular } + public var textStyle: TextStyle { otherStandardStyle.value.regular } } From febbd282cefd3528241c27281ad3b72a0bc9c5dc Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Thu, 22 Feb 2024 22:53:19 +0530 Subject: [PATCH 003/147] Updated DropShadowable to multiple configs --- VDS.xcodeproj/project.pbxproj | 8 +- .../Icon/ButtonIcon/ButtonIcon.swift | 75 +++++++----- .../TileContainer/TileContainer.swift | 21 ++-- VDS/Protocols/DropShadowable.swift | 113 ++++++++++++++++++ VDS/Protocols/Dropshadowable.swift | 64 ---------- 5 files changed, 174 insertions(+), 107 deletions(-) create mode 100644 VDS/Protocols/DropShadowable.swift delete mode 100644 VDS/Protocols/Dropshadowable.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index b13f7df5..c7a20041 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -15,7 +15,7 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; - 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */; }; + 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; }; 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; }; EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */; }; EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */; }; @@ -181,7 +181,7 @@ 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; - 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dropshadowable.swift; sourceTree = ""; }; + 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = ""; }; 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = ""; }; EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorGroupBase.swift; sourceTree = ""; }; EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorBase.swift; sourceTree = ""; }; @@ -560,7 +560,7 @@ EA3361B7288B2AAA0071C351 /* ViewProtocol.swift */, EAB1D2CC28ABE76000DAE764 /* Withable.swift */, 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */, - 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */, + 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */, ); path = Protocols; sourceTree = ""; @@ -999,7 +999,7 @@ EAB2376229E9880400AABE9A /* TrailingTooltipLabel.swift in Sources */, EAB2376A29E9E59100AABE9A /* TooltipLaunchable.swift in Sources */, EAB2375D29E8789100AABE9A /* Tooltip.swift in Sources */, - 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */, + 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */, EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */, EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */, EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */, diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 16f0416f..97bbbb77 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -232,19 +232,26 @@ open class ButtonIcon: Control, Changeable, FormFieldable { }() } - private struct LowContrastColorFillFloatingConfiguration: Configuration, Dropshadowable { + private struct LowContrastColorFillFloatingConfiguration: Configuration, DropShadowableConfiguration { var kind: Kind = .lowContrast var surfaceType: SurfaceType = .colorFill var floating: Bool = true var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.paletteWhite, VDSColor.paletteGray20).eraseToAnyColorable() }() - var shadowColorConfiguration: AnyColorable = { - SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() - }() - var shadowOpacity: CGFloat = 0.16 - var shadowOffset: CGSize = .init(width: 0, height: 2) - var shadowRadius: CGFloat = 4 + private let dropshadow1Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.12), CGFloat(0.22)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 1), .init(width: 0, height: 1)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(10), CGFloat(12)) + } + private let dropshadow2Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.15), CGFloat(0.22)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 2), .init(width: 0, height: 2)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(4), CGFloat(6)) + } + var configurations: [DropShadowable] { [dropshadow1Configuration, dropshadow2Configuration] } } private struct LowContrastMediaConfiguration: Configuration, Borderable { @@ -260,19 +267,26 @@ open class ButtonIcon: Control, Changeable, FormFieldable { }() } - private struct LowContrastMediaFloatingConfiguration: Configuration, Dropshadowable { + private struct LowContrastMediaFloatingConfiguration: Configuration, DropShadowableConfiguration { var kind: Kind = .lowContrast var surfaceType: SurfaceType = .media var floating: Bool = true var backgroundColorConfiguration: AnyColorable = { SurfaceColorConfiguration(VDSColor.paletteWhite, VDSColor.paletteGray20).eraseToAnyColorable() }() - var shadowColorConfiguration: AnyColorable = { - SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() - }() - var shadowOpacity: CGFloat = 0.16 - var shadowOffset: CGSize = .init(width: 0, height: 2) - var shadowRadius: CGFloat = 4 + private let dropshadow1Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.12), CGFloat(0.22)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 1), .init(width: 0, height: 1)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(10), CGFloat(12)) + } + private let dropshadow2Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.05), CGFloat(0.15)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 2), .init(width: 0, height: 2)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(4), CGFloat(6)) + } + var configurations: [DropShadowable] { [dropshadow1Configuration, dropshadow2Configuration] } } private struct HighContrastConfiguration: Configuration { @@ -291,7 +305,7 @@ open class ButtonIcon: Control, Changeable, FormFieldable { }() } - private struct HighContrastFloatingConfiguration: Configuration, Dropshadowable { + private struct HighContrastFloatingConfiguration: Configuration, DropShadowableConfiguration { var kind: Kind = .highContrast var surfaceType: SurfaceType = .colorFill var floating: Bool = true @@ -305,12 +319,19 @@ open class ButtonIcon: Control, Changeable, FormFieldable { $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: [.selected, .disabled]) }.eraseToAnyColorable() }() - var shadowColorConfiguration: AnyColorable = { - SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() - }() - var shadowOpacity: CGFloat = 0.16 - var shadowOffset: CGSize = .init(width: 0, height: 2) - var shadowRadius: CGFloat = 6 + private let dropshadow1Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.22), CGFloat(0.12)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 1), .init(width: 0, height: 1)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(12), CGFloat(10)) + } + private let dropshadow2Configuration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteBlack).eraseToAnyColorable() + $0.shadowOpacityConfiguration = AnyConfigurationValue(CGFloat(0.15), CGFloat(0.05)) + $0.shadowOffsetConfiguration = AnyConfigurationValue(.init(width: 0, height: 2), .init(width: 0, height: 2)) + $0.shadowRadiusConfiguration = AnyConfigurationValue(CGFloat(6), CGFloat(4)) + } + var configurations: [DropShadowable] { [dropshadow1Configuration, dropshadow2Configuration] } } private var badgeIndicatorDefaultSize: CGSize = .zero @@ -452,12 +473,6 @@ open class ButtonIcon: Control, Changeable, FormFieldable { layer.borderColor = nil layer.borderWidth = 0 } - - if let dropshadowable = currentConfig as? Dropshadowable { - addDropShadow(dropshadowable) - } else { - removeDropShadows() - } badgeIndicatorCenterXConstraint?.constant = badgeIndicatorOffset.x + badgeIndicatorDefaultSize.width/2 badgeIndicatorCenterYConstraint?.constant = badgeIndicatorOffset.y + badgeIndicatorDefaultSize.height/2 @@ -467,6 +482,12 @@ open class ButtonIcon: Control, Changeable, FormFieldable { if showBadgeIndicator { updateExpandDirectionalConstraints() } + + if let configurations = (currentConfig as? DropShadowableConfiguration)?.configurations { + addDropShadows(configurations) + } else { + removeDropShadows() + } } //-------------------------------------------------- diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index 98090ae4..8dc2d9dd 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -184,9 +184,15 @@ open class TileContainer: Control { // MARK: - Configuration //-------------------------------------------------- private let cornerRadius = VDSFormControls.borderradius * 2 - private var backgroundColorConfiguration = BackgroundColorConfiguration() - private var dropshadowConfiguration = DropshadowConfiguration() + private let dropShadowConfiguration = DropShadowConfiguration().with { + $0.shadowColorConfiguration = SurfaceColorConfiguration().with { + $0.lightColor = VDSColor.elementsPrimaryOnlight + }.eraseToAnyColorable() + $0.shadowOffsetConfiguration = .init(.init(width: 0, height: 6), .zero) + $0.shadowRadiusConfiguration = .init(3.0, 0.0) + $0.shadowOpacityConfiguration = .init(0.01, 0.0) + } private var borderColorConfiguration = SurfaceColorConfiguration().with { $0.lightColor = VDSColor.elementsLowcontrastOnlight @@ -311,7 +317,7 @@ open class TileContainer: Control { heightConstraint?.isActive = false } if showDropShadows, surface == .light { - addDropShadow(dropshadowConfiguration) + addDropShadow(dropShadowConfiguration) } else { removeDropShadows() } @@ -397,15 +403,6 @@ open class TileContainer: Control { extension TileContainer { - struct DropshadowConfiguration: Dropshadowable { - var shadowColorConfiguration: AnyColorable = SurfaceColorConfiguration().with { - $0.lightColor = VDSColor.elementsPrimaryOnlight - }.eraseToAnyColorable() - var shadowOpacity: CGFloat = 0.01 - var shadowOffset: CGSize = .init(width: 0, height: 6) - var shadowRadius: CGFloat = 3 - } - final class BackgroundColorConfiguration: ObjectColorable { typealias ObjectType = TileContainer diff --git a/VDS/Protocols/DropShadowable.swift b/VDS/Protocols/DropShadowable.swift new file mode 100644 index 00000000..57c44036 --- /dev/null +++ b/VDS/Protocols/DropShadowable.swift @@ -0,0 +1,113 @@ +// +// DropShadowable.swift +// VDS +// +// Created by Bandaru, Krishna Kishore on 16/02/24. +// + +import Foundation +import UIKit + +protocol DropShadowable { + + var shadowColorConfiguration: AnyColorable { get set } + var shadowOpacityConfiguration: AnyConfigurationValue { get set } + var shadowOffsetConfiguration: AnyConfigurationValue { get set } + var shadowRadiusConfiguration: AnyConfigurationValue { get set } +} + +protocol DropShadowableConfiguration { + + var configurations: [DropShadowable] { get } +} + +final class DropShadowConfiguration: DropShadowable, ObjectWithable { + + typealias CGFloatConfigurationValue = AnyConfigurationValue + typealias CGSizeConfigurationValue = AnyConfigurationValue + + var shadowColorConfiguration: AnyColorable + var shadowOpacityConfiguration: CGFloatConfigurationValue + var shadowOffsetConfiguration: CGSizeConfigurationValue + var shadowRadiusConfiguration: CGFloatConfigurationValue + + init(shadowColorConfiguration: AnyColorable = SurfaceColorConfiguration().eraseToAnyColorable(), shadowOpacity: CGFloatConfigurationValue = CGFloatConfigurationValue(1.0, 1.0), shadowOffset: CGSizeConfigurationValue = CGSizeConfigurationValue(.zero, .zero), shadowRadius: CGFloatConfigurationValue = CGFloatConfigurationValue(1.0, 1.0)) { + self.shadowColorConfiguration = shadowColorConfiguration + self.shadowOpacityConfiguration = shadowOpacity + self.shadowOffsetConfiguration = shadowOffset + self.shadowRadiusConfiguration = shadowRadius + } +} + +extension ViewProtocol where Self: UIView { + + func addDropShadow(_ config: DropShadowable) { + addDropShadows([config]) + } + + func addDropShadows(_ configs: [DropShadowable]) { + removeDropShadows() + layer.backgroundColor = backgroundColor?.cgColor + layer.masksToBounds = false + for config in configs { + let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius) + let shadowLayer = CALayer() + shadowLayer.shadowPath = shadowPath.cgPath + shadowLayer.frame = bounds + shadowLayer.position = .init(x: bounds.midX, y: bounds.midY) + shadowLayer.backgroundColor = backgroundColor?.cgColor + shadowLayer.cornerRadius = layer.cornerRadius + shadowLayer.shadowColor = config.shadowColorConfiguration.getColor(self).cgColor + shadowLayer.shadowOpacity = Float(config.shadowOpacityConfiguration.getValue(self)) + shadowLayer.shadowOffset = config.shadowOffsetConfiguration.getValue(self) + shadowLayer.shadowRadius = config.shadowRadiusConfiguration.getValue(self) + shadowLayer.name = "dropShadowLayer" + shadowLayer.shouldRasterize = true + shadowLayer.rasterizationScale = UIScreen.main.scale + layer.insertSublayer(shadowLayer, at: 0) + } + } + + func removeDropShadows() { + layer.sublayers?.removeAll { $0.name == "dropShadowLayer" } + } + + func addGradientLayer(with firstColor: UIColor, secondColor: UIColor) { + removeGradientLayer() + let gradientLayer = CAGradientLayer() + gradientLayer.frame = bounds + gradientLayer.startPoint = CGPoint(x: 0, y: 1) + gradientLayer.endPoint = CGPoint(x: 1, y: 0) + gradientLayer.position = center + gradientLayer.shouldRasterize = true + gradientLayer.backgroundColor = UIColor.clear.cgColor + gradientLayer.rasterizationScale = UIScreen.main.scale + gradientLayer.cornerRadius = layer.cornerRadius + gradientLayer.colors = [firstColor.cgColor, secondColor.cgColor] + gradientLayer.name = "gradientLayer" + layer.insertSublayer(gradientLayer, at: 0) + } + + func removeGradientLayer() { + layer.sublayers?.removeAll { $0.name == "gradientLayer" } + } +} + +final class AnyConfigurationValue { + + var lightValue: ValueType + var darkValue: ValueType + + public init(_ lightValue: ValueType = ValueType.self, _ darkValue: ValueType = ValueType.self) { + self.lightValue = lightValue + self.darkValue = darkValue + } + + public func getValue(_ object: Any) -> ValueType { + guard let surfaceable = object as? Surfaceable else { + assertionFailure("Self doesn't confirms to Surfaceable") + return lightValue + } + return surfaceable.surface == .light ? lightValue : darkValue + } +} diff --git a/VDS/Protocols/Dropshadowable.swift b/VDS/Protocols/Dropshadowable.swift deleted file mode 100644 index 77f1a475..00000000 --- a/VDS/Protocols/Dropshadowable.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// Dropshadowable.swift -// VDS -// -// Created by Bandaru, Krishna Kishore on 16/02/24. -// - -import Foundation -import UIKit - -protocol Dropshadowable { - - var shadowColorConfiguration: AnyColorable { get set } - var shadowOpacity: CGFloat { get set } - var shadowOffset: CGSize { get set } - var shadowRadius: CGFloat { get set } -} - -extension ViewProtocol where Self: UIView { - - func addDropShadow(_ config: Dropshadowable) { - removeDropShadows() - layer.backgroundColor = backgroundColor?.cgColor - layer.masksToBounds = false - let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius) - let shadowLayer = CALayer() - shadowLayer.shadowPath = shadowPath.cgPath - shadowLayer.frame = bounds - shadowLayer.position = center - shadowLayer.backgroundColor = UIColor.clear.cgColor - shadowLayer.cornerRadius = layer.cornerRadius - shadowLayer.shadowColor = config.shadowColorConfiguration.getColor(self).cgColor - shadowLayer.shadowOpacity = Float(config.shadowOpacity) - shadowLayer.shadowOffset = .init(width: config.shadowOffset.width, height: config.shadowOffset.height) - shadowLayer.shadowRadius = config.shadowRadius - shadowLayer.name = "dropShadowLayer" - shadowLayer.shouldRasterize = true - shadowLayer.rasterizationScale = UIScreen.main.scale - layer.insertSublayer(shadowLayer, at: 0) - } - - func removeDropShadows() { - layer.sublayers?.removeAll { $0.name == "dropShadowLayer" } - } - - func addGradientLayer(with firstColor: UIColor, secondColor: UIColor) { - removeGradientLayer() - let gradientLayer = CAGradientLayer() - gradientLayer.frame = bounds - gradientLayer.startPoint = CGPoint(x: 0, y: 1) - gradientLayer.endPoint = CGPoint(x: 1, y: 0) - gradientLayer.position = center - gradientLayer.shouldRasterize = true - gradientLayer.rasterizationScale = UIScreen.main.scale - gradientLayer.cornerRadius = layer.cornerRadius - gradientLayer.colors = [firstColor.cgColor, secondColor.cgColor] - gradientLayer.name = "gradientLayer" - layer.insertSublayer(gradientLayer, at: 0) - } - - func removeGradientLayer() { - layer.sublayers?.removeAll { $0.name == "gradientLayer" } - } -} From 9883bd6214df931069fbe5a090bd4fbff461de71 Mon Sep 17 00:00:00 2001 From: vasavk Date: Thu, 22 Feb 2024 23:55:46 +0530 Subject: [PATCH 004/147] Digital ACT191 story ONEAPP-6682 Flex Height as per Layout and spacing --- .../TextFields/TextArea/TextArea.swift | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 7d70cb44..4494f1b7 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -5,7 +5,6 @@ // Created by Matt Bruce on 1/10/23. // -import Foundation import Foundation import UIKit import VDSColorTokens @@ -49,7 +48,7 @@ open class TextArea: EntryFieldBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - override var containerSize: CGSize { CGSize(width: 45, height: 88) } + override var containerSize: CGSize { CGSize(width: 182, height: 88) } /// UITextView shown in the TextArea. open var textView = UITextView().with { @@ -72,7 +71,7 @@ open class TextArea: EntryFieldBase { open override func setup() { super.setup() - minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 0) + minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width) minWidthConstraint?.isActive = true controlContainerView.addSubview(textView) @@ -81,8 +80,8 @@ open class TextArea: EntryFieldBase { .pinLeading() .pinTrailingLessThanOrEqualTo(nil, 0, .defaultHigh) .pinBottom(0, .defaultHigh) - - textViewHeightConstraint = textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 64) + textView.isScrollEnabled = true + 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) @@ -132,17 +131,15 @@ extension TextArea: UITextViewDelegate { //if you want it to work "as-is" delete this code //since it will autogrow with the current settings if let textViewHeightConstraint, textView.isEditable { - let height = textView.frame.size.height - let constraintHeight = textViewHeightConstraint.constant - if height > constraintHeight { - if height > 64 && height < 152 { - textViewHeightConstraint.constant = 152 - } else if height > 152 { - textViewHeightConstraint.constant = 328 + let height = textView.contentSize.height + if height > 88 && height < 176 { + textViewHeightConstraint.constant = 176 + } else if height > 176 { + textViewHeightConstraint.constant = 352 } else { - textViewHeightConstraint.constant = 64 + textViewHeightConstraint.constant = 88 } - } + textViewHeightConstraint.isActive = true } //setting the value and firing control event From 783143717c71d219d725deeef868ea40312a03fd Mon Sep 17 00:00:00 2001 From: vasavk Date: Fri, 23 Feb 2024 12:47:47 +0530 Subject: [PATCH 005/147] Digital ACT191 story ONEAPP-6682 adding character count limit to container --- .../TextFields/EntryFieldBase.swift | 35 ++++++++++++++++-- .../TextFields/TextArea/TextArea.swift | 37 ++++++++++++++++++- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index aaf03256..31529f61 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -70,6 +70,20 @@ open class EntryFieldBase: Control, Changeable { } }() + internal var bottomContainerView: UIView = { + return UIView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + } + }() + + internal var bottomContainerStackView: UIStackView = { + return UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .vertical + $0.distribution = .fill + } + }() + //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- @@ -204,14 +218,24 @@ open class EntryFieldBase: Control, Changeable { containerStackView.addArrangedSubview(controlContainerView) containerStackView.addArrangedSubview(icon) + //get the container this is what show helper text, error text + //can include other for character count, max length + let bottomContainer = getBottomContainer() + + //add bottomContainerStackView + //this is the vertical stack that contains error text, helper text + bottomContainer.addSubview(bottomContainerStackView) + bottomContainerStackView.pinToSuperView() + bottomContainerStackView.addArrangedSubview(errorLabel) + bottomContainerStackView.addArrangedSubview(helperLabel) + stackView.addArrangedSubview(titleLabel) stackView.addArrangedSubview(container) - stackView.addArrangedSubview(errorLabel) - stackView.addArrangedSubview(helperLabel) + stackView.addArrangedSubview(bottomContainer) stackView.setCustomSpacing(4, after: titleLabel) stackView.setCustomSpacing(8, after: container) - stackView.setCustomSpacing(8, after: errorLabel) + stackView.setCustomSpacing(8, after: bottomContainer) stackView .pinTop() @@ -273,6 +297,11 @@ open class EntryFieldBase: Control, Changeable { open func getContainer() -> UIView { return containerView } + + /// Container for the area in which helper or error text presents. + open func getBottomContainer() -> UIView { + return bottomContainerView + } open func updateTitleLabel() { diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 4494f1b7..7cca53da 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -45,6 +45,30 @@ open class TextArea: EntryFieldBase { } }() + internal var bottomView: UIView = { + return UIView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + } + }() + + internal var bottomStackView: UIStackView = { + return UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .horizontal + $0.distribution = .fill + $0.alignment = .top + } + }() + + open var characterCountLabel = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.textStyle = .bodySmall + } + open var maxLengthLabel = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.textStyle = .bodySmall + } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -70,9 +94,10 @@ open class TextArea: EntryFieldBase { /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. open override func setup() { super.setup() - minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width) minWidthConstraint?.isActive = true + characterCountLabel.text = "0" + maxLengthLabel.text = "/200" controlContainerView.addSubview(textView) textView @@ -119,6 +144,16 @@ open class TextArea: EntryFieldBase { minWidthConstraint?.isActive = true } } + + /// Container for the area which shows helper text, error text, character count, max length value. + open override func getBottomContainer() -> UIView { + bottomView.addSubview(bottomStackView) + bottomStackView.pinToSuperView() + bottomStackView.addArrangedSubview(bottomContainerView) + bottomStackView.addArrangedSubview(characterCountLabel) + bottomStackView.addArrangedSubview(maxLengthLabel) + return bottomView + } } extension TextArea: UITextViewDelegate { From e319153ac659f79f581ab4a939848b90f895a8d1 Mon Sep 17 00:00:00 2001 From: vasavk Date: Fri, 23 Feb 2024 16:11:14 +0530 Subject: [PATCH 006/147] Digital ACT191 story ONEAPP-6682 Checking character count overflow --- .../TextFields/TextArea/TextArea.swift | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 7cca53da..105286b5 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -35,7 +35,8 @@ open class TextArea: EntryFieldBase { //-------------------------------------------------- internal var minWidthConstraint: NSLayoutConstraint? internal var textViewHeightConstraint: NSLayoutConstraint? - + internal var allowCharCount: Int = 0 + internal var inputFieldStackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -64,10 +65,6 @@ open class TextArea: EntryFieldBase { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textStyle = .bodySmall } - open var maxLengthLabel = Label().with { - $0.setContentCompressionResistancePriority(.required, for: .vertical) - $0.textStyle = .bodySmall - } //-------------------------------------------------- // MARK: - Public Properties @@ -96,9 +93,6 @@ open class TextArea: EntryFieldBase { super.setup() minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width) minWidthConstraint?.isActive = true - characterCountLabel.text = "0" - maxLengthLabel.text = "/200" - controlContainerView.addSubview(textView) textView .pinTop() @@ -118,6 +112,8 @@ open class TextArea: EntryFieldBase { open override func reset() { super.reset() textView.text = "" + characterCountLabel.reset() + characterCountLabel.textStyle = .bodySmall } /// Container for the area in which the user interacts. @@ -132,7 +128,6 @@ open class TextArea: EntryFieldBase { textView.isEditable = isEnabled textView.textColor = textViewTextColorConfiguration.getColor(self) - //set the width constraints if let width { widthConstraint?.constant = width @@ -143,6 +138,12 @@ open class TextArea: EntryFieldBase { widthConstraint?.isActive = false minWidthConstraint?.isActive = true } + + // allow - 20% of character limit + let overflowLimit = Double(maxLength ?? 0) * 0.20 + allowCharCount = Int(overflowLimit) + (maxLength ?? 0) + characterCountLabel.text = getLimitText() + } /// Container for the area which shows helper text, error text, character count, max length value. @@ -151,9 +152,18 @@ open class TextArea: EntryFieldBase { bottomStackView.pinToSuperView() bottomStackView.addArrangedSubview(bottomContainerView) bottomStackView.addArrangedSubview(characterCountLabel) - bottomStackView.addArrangedSubview(maxLengthLabel) return bottomView } + + //-------------------------------------------------- + // MARK: - Private Methods + //-------------------------------------------------- + private func getLimitText() -> String { + let count = textView.text.count + let countStr = (count > maxLength ?? 0) ? ("-" + "\(count-(maxLength ?? 0))") : "\(count)" + let text = "\(countStr)" + "/" + "\(maxLength ?? 0)" + return text + } } extension TextArea: UITextViewDelegate { @@ -177,9 +187,12 @@ extension TextArea: UITextViewDelegate { textViewHeightConstraint.isActive = true } - //setting the value and firing control event - value = textView.text - sendActions(for: .valueChanged) - + if textView.text.count <= allowCharCount { + //setting the value and firing control event + value = textView.text + sendActions(for: .valueChanged) + } else { + textView.text.removeLast() + } } } From 967eed952266cfe5e8cb7b966bb2ffc5879e4f13 Mon Sep 17 00:00:00 2001 From: vasavk Date: Fri, 23 Feb 2024 19:12:17 +0530 Subject: [PATCH 007/147] Digital ACT191 story ONEAPP-6682 changes for error icon --- VDS/Components/TextFields/EntryFieldBase.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 31529f61..0d6a93e5 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -59,7 +59,7 @@ open class EntryFieldBase: Control, Changeable { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal - $0.distribution = .fillProportionally + $0.distribution = .fill $0.alignment = .top } }() @@ -198,7 +198,7 @@ open class EntryFieldBase: Control, Changeable { //create the wrapping view heightConstraint = containerView.heightAnchor.constraint(greaterThanOrEqualToConstant: containerSize.height) - widthConstraint?.priority = .defaultHigh + heightConstraint?.priority = .defaultHigh heightConstraint?.isActive = true widthConstraint = containerView.widthAnchor.constraint(equalToConstant: 0) @@ -212,11 +212,12 @@ open class EntryFieldBase: Control, Changeable { //this is the horizontal stack that contains //the left, InputContainer, Icons, Buttons container.addSubview(containerStackView) - containerStackView.pinToSuperView(.uniform(12)) + containerStackView.pinToSuperView(.uniform(VDSFormControls.spaceInset)) //add the view to add input fields containerStackView.addArrangedSubview(controlContainerView) containerStackView.addArrangedSubview(icon) + containerStackView.setCustomSpacing(VDSLayout.Spacing.space3X.value, after: controlContainerView) //get the container this is what show helper text, error text //can include other for character count, max length From c2662aaf307023e21e73e50ca7440de5d15a3fa6 Mon Sep 17 00:00:00 2001 From: vasavk Date: Fri, 23 Feb 2024 19:26:41 +0530 Subject: [PATCH 008/147] Digital ACT191 story ONEAPP-6682 added change log --- VDS.xcodeproj/project.pbxproj | 4 ++ .../TextFields/TextArea/TextAreaChangeLog.txt | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 VDS/Components/TextFields/TextArea/TextAreaChangeLog.txt diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index b13f7df5..125d88a8 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 186B2A8A2B88DA7F001AB71F /* TextAreaChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */; }; 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; 18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; @@ -173,6 +174,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextAreaChangeLog.txt; sourceTree = ""; }; 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = ""; }; 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; @@ -715,6 +717,7 @@ isa = PBXGroup; children = ( EA985C22296E033A00F2FF2E /* TextArea.swift */, + 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */, ); path = TextArea; sourceTree = ""; @@ -946,6 +949,7 @@ EA3362042891E14D0071C351 /* VerizonNHGeTX-Bold.otf in Resources */, 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */, EAEEECA72B1F952000531FC2 /* TabsChangeLog.txt in Resources */, + 186B2A8A2B88DA7F001AB71F /* TextAreaChangeLog.txt in Resources */, EAEEEC962B1F893B00531FC2 /* ButtonChangeLog.txt in Resources */, EA5F86CC2A1D28B500BC83E4 /* ReleaseNotes.txt in Resources */, EAEEEC982B1F8DD100531FC2 /* LineChangeLog.txt in Resources */, diff --git a/VDS/Components/TextFields/TextArea/TextAreaChangeLog.txt b/VDS/Components/TextFields/TextArea/TextAreaChangeLog.txt new file mode 100644 index 00000000..555ad730 --- /dev/null +++ b/VDS/Components/TextFields/TextArea/TextAreaChangeLog.txt @@ -0,0 +1,38 @@ +MM/DD/YYYY +---------------- +- Initial Brand 3.0 handoff + +12/27/2021 +---------------- +- Removed Max idth Updated the SPECS with FormControl tokens + +02/25/2022 +---------------- +- Replaced Info and Error Non-Scaling icons with VDS Icon. +- Removed “weight” and “vector effect” from Anatomy and States. + +07/27/2022 +---------------- +- Added Configurations section with transparentBackground principles. + +08/10/2022 +---------------- +- Updated default and inverted prop to light and dark surface. + +11/30/2022 +---------------- +- Added "(web only)" to any instance of "keyboard focus" + +12/13/2022 +---------------- +- Replaced form border and focus border pixel values and style & spacing with tokens. + +01/18/2023 +---------------- +- Updated Anatomy items: +- Added “Highlight” to item #10 +- Changed item #7 to “Tooltip” from “Tooltip Component” + +04/12/2023 +---------------- +- Updated hex colors for updated feedback tokens in error states. From f7134b9b8cd0e763b0a79952974e390b0a7fe2f8 Mon Sep 17 00:00:00 2001 From: vasavk Date: Mon, 26 Feb 2024 11:52:06 +0530 Subject: [PATCH 009/147] Digital ACT191 story ONEAPP-6682 Character limit, error text, and readonly changes. - show error text when exceeds character limit. - No restriction if character counter does not display. - color changes for character counter label, error text, and readonly. - Showing Character count overflow. --- .../TextFields/EntryFieldBase.swift | 42 +++++++++++---- .../TextFields/TextArea/TextArea.swift | 54 +++++++++++++------ 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index 0d6a93e5..dcb16fbf 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -107,11 +107,15 @@ open class EntryFieldBase: Control, Changeable { } internal var borderColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOnlight, forState: .normal) + $0.setSurfaceColors(VDSFormControlsColor.borderOnlight, VDSFormControlsColor.borderOndark, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.feedbackErrorOnlight, VDSColor.feedbackErrorOndark, forState: .error) } + internal var readOnlyBorderColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSFormControlsColor.borderReadonlyOnlight, VDSFormControlsColor.borderReadonlyOndark, forState: .normal) + } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -160,8 +164,22 @@ open class EntryFieldBase: Control, Changeable { } } - open var errorText: String? { didSet { setNeedsUpdate() } } - + private var _errorText: String? + + open var errorText: String? { + get { return _errorText } + set { + if let newValue { + _errorText = newValue + } else { + _errorText = nil + } + updateContainerView() + updateErrorLabel() + setNeedsUpdate() + } + } + open var tooltipModel: Tooltip.TooltipModel? { didSet { setNeedsUpdate() } } open var transparentBackground: Bool = false { didSet { setNeedsUpdate() } } @@ -212,7 +230,7 @@ open class EntryFieldBase: Control, Changeable { //this is the horizontal stack that contains //the left, InputContainer, Icons, Buttons container.addSubview(containerStackView) - containerStackView.pinToSuperView(.uniform(VDSFormControls.spaceInset)) + containerStackView.pinToSuperView(.uniform(12)) //add the view to add input fields containerStackView.addArrangedSubview(controlContainerView) @@ -279,11 +297,7 @@ open class EntryFieldBase: Control, Changeable { open override func updateView() { super.updateView() - containerView.backgroundColor = backgroundColorConfiguration.getColor(self) - containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor - containerView.layer.borderWidth = VDSFormControls.widthBorder - containerView.layer.cornerRadius = VDSFormControls.borderradius - + updateContainerView() updateTitleLabel() updateErrorLabel() updateHelperLabel() @@ -291,6 +305,16 @@ open class EntryFieldBase: Control, Changeable { backgroundColor = surface.color } + //-------------------------------------------------- + // MARK: - Private Methods + //-------------------------------------------------- + private func updateContainerView() { + containerView.backgroundColor = backgroundColorConfiguration.getColor(self) + containerView.layer.borderColor = borderColorConfiguration.getColor(self).cgColor + containerView.layer.borderWidth = VDSFormControls.widthBorder + containerView.layer.cornerRadius = VDSFormControls.borderradius + } + //-------------------------------------------------- // MARK: - Public Methods //-------------------------------------------------- diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 105286b5..1a91a099 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -61,9 +61,11 @@ open class TextArea: EntryFieldBase { } }() - open var characterCountLabel = Label().with { + open var characterCounterLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textStyle = .bodySmall + $0.textAlignment = .right + $0.numberOfLines = 1 } //-------------------------------------------------- @@ -112,8 +114,8 @@ open class TextArea: EntryFieldBase { open override func reset() { super.reset() textView.text = "" - characterCountLabel.reset() - characterCountLabel.textStyle = .bodySmall + characterCounterLabel.reset() + characterCounterLabel.textStyle = .bodySmall } /// Container for the area in which the user interacts. @@ -139,11 +141,20 @@ open class TextArea: EntryFieldBase { minWidthConstraint?.isActive = true } - // allow - 20% of character limit - let overflowLimit = Double(maxLength ?? 0) * 0.20 - allowCharCount = Int(overflowLimit) + (maxLength ?? 0) - characterCountLabel.text = getLimitText() - + if ((maxLength ?? 0) > 0) { + // allow - 20% of character limit + let overflowLimit = Double(maxLength ?? 0) * 0.20 + allowCharCount = Int(overflowLimit) + (maxLength ?? 0) + characterCounterLabel.text = getCharacterCounterText() + } else { + characterCounterLabel.text = "" + } + + icon.size = .medium + containerView.layer.borderColor = readOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor + textView.isEditable = readOnly ? false : true + textView.backgroundColor = backgroundColorConfiguration.getColor(self) + characterCounterLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() } /// Container for the area which shows helper text, error text, character count, max length value. @@ -151,18 +162,25 @@ open class TextArea: EntryFieldBase { bottomView.addSubview(bottomStackView) bottomStackView.pinToSuperView() bottomStackView.addArrangedSubview(bottomContainerView) - bottomStackView.addArrangedSubview(characterCountLabel) + bottomStackView.addArrangedSubview(characterCounterLabel) return bottomView } //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- - private func getLimitText() -> String { + private func getCharacterCounterText() -> String { let count = textView.text.count let countStr = (count > maxLength ?? 0) ? ("-" + "\(count-(maxLength ?? 0))") : "\(count)" - let text = "\(countStr)" + "/" + "\(maxLength ?? 0)" - return text + if count > maxLength ?? 0 { + showError = true + errorText = "You have exceeded the character limit." + return countStr + } else { + showError = false + errorText = "" + return ("\(countStr)" + "/" + "\(maxLength ?? 0)") + } } } @@ -187,12 +205,18 @@ extension TextArea: UITextViewDelegate { textViewHeightConstraint.isActive = true } - if textView.text.count <= allowCharCount { + if ((maxLength ?? 0) > 0) { + if textView.text.count <= allowCharCount { + //setting the value and firing control event + value = textView.text + sendActions(for: .valueChanged) + } else { + textView.text.removeLast() + } + } else { //setting the value and firing control event value = textView.text sendActions(for: .valueChanged) - } else { - textView.text.removeLast() } } } From abb94257da8d8045e1d88f92e10c4195dd43fac1 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Mon, 26 Feb 2024 13:28:24 +0530 Subject: [PATCH 010/147] fixed conflicting constraints --- VDS/Components/Notification/Notification.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 2ed84116..126f83f0 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -398,13 +398,18 @@ open class Notification: View { } private func setConstraints() { + maxWidthConstraint?.deactivate() + labelViewAndButtonViewConstraint?.deactivate() + labelViewBottomConstraint?.deactivate() + buttonGroupCenterYConstraint?.deactivate() + buttonGroupBottomConstraint?.deactivate() maxWidthConstraint?.constant = maxViewWidth maxWidthConstraint?.isActive = UIDevice.isIPad labelViewAndButtonViewConstraint?.isActive = layout == .vertical && !buttonGroup.buttons.isEmpty - typeIconWidthConstraint?.constant = typeIcon.size.dimensions.width - closeIconWidthConstraint?.constant = closeButton.size.dimensions.width labelViewBottomConstraint?.isActive = layout == .horizontal || buttonGroup.buttons.isEmpty buttonGroupCenterYConstraint?.isActive = layout == .horizontal buttonGroupBottomConstraint?.isActive = layout == .vertical + typeIconWidthConstraint?.constant = typeIcon.size.dimensions.width + closeIconWidthConstraint?.constant = closeButton.size.dimensions.width } } From 5b010275546b6428872ce76e894f9a4a74ca71a4 Mon Sep 17 00:00:00 2001 From: vasavk Date: Mon, 26 Feb 2024 14:54:15 +0530 Subject: [PATCH 011/147] Digital ACT191 story ONEAPP-6682 highlight text color, background color for character counter --- .../TextFields/TextArea/TextArea.swift | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 1a91a099..1ac1900d 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -87,6 +87,21 @@ open class TextArea: EntryFieldBase { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) }.eraseToAnyColorable() { didSet { 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) + } + + /// Color configuration for character counter's highlight text color + internal var highlightTextColor = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .normal) + } + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -106,7 +121,6 @@ open class TextArea: EntryFieldBase { textViewHeightConstraint?.isActive = true backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) - textView.delegate = self } @@ -151,13 +165,15 @@ open class TextArea: EntryFieldBase { } icon.size = .medium + icon.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) characterCounterLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() + textView.tintColor = iconColorConfiguration.getColor(self) } - /// Container for the area which shows helper text, error text, character count, max length value. + /// Container for the area showing helper text, error text, character count, maximum length value. open override func getBottomContainer() -> UIView { bottomView.addSubview(bottomStackView) bottomStackView.pinToSuperView() @@ -182,6 +198,15 @@ open class TextArea: EntryFieldBase { return ("\(countStr)" + "/" + "\(maxLength ?? 0)") } } + + open func highlightCharacterOverflow() { + let count = textView.text.count + print("count: \(count), maxLength: \(maxLength ?? 0)") + guard let text = textView.attributedText?.mutableCopy() as? NSMutableAttributedString else { return } + text.addAttribute(NSAttributedString.Key.backgroundColor, value: highlightBackgroundColor.getColor(self), range: NSRange(location:(maxLength ?? 0 ), length: (count - (maxLength ?? 0)))) + text.addAttribute(NSAttributedString.Key.foregroundColor, value: highlightTextColor.getColor(self), range: NSRange(location:(maxLength ?? 0 ), length: (count - (maxLength ?? 0)))) + textView.attributedText = text.copy() as? NSAttributedString + } } extension TextArea: UITextViewDelegate { @@ -189,29 +214,35 @@ extension TextArea: UITextViewDelegate { // MARK: - UITextViewDelegate //-------------------------------------------------- public func textViewDidChange(_ textView: UITextView) { - + //dynamic textView Height sizing based on Figma //if you want it to work "as-is" delete this code //since it will autogrow with the current settings if let textViewHeightConstraint, textView.isEditable { let height = textView.contentSize.height - if height > 88 && height < 176 { - textViewHeightConstraint.constant = 176 - } else if height > 176 { - textViewHeightConstraint.constant = 352 - } else { - textViewHeightConstraint.constant = 88 - } + if height > 88 && height < 176 { + textViewHeightConstraint.constant = 176 + } else if height > 176 { + textViewHeightConstraint.constant = 352 + } else { + textViewHeightConstraint.constant = 88 + } textViewHeightConstraint.isActive = true } + //The exceeding characters will be highlighted to help users correct their entry. if ((maxLength ?? 0) > 0) { if textView.text.count <= allowCharCount { //setting the value and firing control event value = textView.text sendActions(for: .valueChanged) + + if (textView.text.count > (maxLength ?? 0)) { + highlightCharacterOverflow() + } } else { textView.text.removeLast() + highlightCharacterOverflow() } } else { //setting the value and firing control event From 72ef366eedddeeae35e4fdae1fb005777957b033 Mon Sep 17 00:00:00 2001 From: vasavk Date: Mon, 26 Feb 2024 17:02:36 +0530 Subject: [PATCH 012/147] Digital ACT191 story ONEAPP-6682 added accessibility, focused border color to container --- .../TextFields/TextArea/TextArea.swift | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 1ac1900d..01604134 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -108,6 +108,10 @@ open class TextArea: EntryFieldBase { /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. open override func setup() { super.setup() + accessibilityLabel = "TextArea" + isAccessibilityElement = true + + containerStackView.pinToSuperView(.uniform(VDSFormControls.spaceInset)) minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width) minWidthConstraint?.isActive = true controlContainerView.addSubview(textView) @@ -117,10 +121,12 @@ open class TextArea: EntryFieldBase { .pinTrailingLessThanOrEqualTo(nil, 0, .defaultHigh) .pinBottom(0, .defaultHigh) textView.isScrollEnabled = true + textView.autocorrectionType = .no 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) + borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .focused) textView.delegate = self } @@ -182,26 +188,39 @@ open class TextArea: EntryFieldBase { return bottomView } + /// Used to update any Accessibility properties. + open override func updateAccessibility() { + super.updateAccessibility() + if showError { + setAccessibilityLabel(for: [titleLabel, textView, errorLabel, helperLabel]) + } else { + setAccessibilityLabel(for: [titleLabel, textView, helperLabel]) + } + } + //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- private func getCharacterCounterText() -> String { let count = textView.text.count let countStr = (count > maxLength ?? 0) ? ("-" + "\(count-(maxLength ?? 0))") : "\(count)" - if count > maxLength ?? 0 { - showError = true - errorText = "You have exceeded the character limit." - return countStr + if ((maxLength ?? 0) > 0) { + if (count > (maxLength ?? 0)) { + showError = true + errorText = "You have exceeded the character limit." + return countStr + } else { + showError = false + errorText = "" + return ("\(countStr)" + "/" + "\(maxLength ?? 0)") + } } else { - showError = false - errorText = "" - return ("\(countStr)" + "/" + "\(maxLength ?? 0)") + return "" } } open func highlightCharacterOverflow() { let count = textView.text.count - print("count: \(count), maxLength: \(maxLength ?? 0)") guard let text = textView.attributedText?.mutableCopy() as? NSMutableAttributedString else { return } text.addAttribute(NSAttributedString.Key.backgroundColor, value: highlightBackgroundColor.getColor(self), range: NSRange(location:(maxLength ?? 0 ), length: (count - (maxLength ?? 0)))) text.addAttribute(NSAttributedString.Key.foregroundColor, value: highlightTextColor.getColor(self), range: NSRange(location:(maxLength ?? 0 ), length: (count - (maxLength ?? 0)))) From f527ec5483ea03bf8f7318f73c54913175098b01 Mon Sep 17 00:00:00 2001 From: vasavk Date: Mon, 26 Feb 2024 18:02:37 +0530 Subject: [PATCH 013/147] Digital ACT191 story ONEAPP-6682 minor changes --- .../TextFields/TextArea/TextArea.swift | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 01604134..135a2421 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -42,7 +42,7 @@ open class TextArea: EntryFieldBase { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal $0.distribution = .fill - $0.spacing = 12 + $0.spacing = VDSLayout.Spacing.space3X.value } }() @@ -58,6 +58,7 @@ open class TextArea: EntryFieldBase { $0.axis = .horizontal $0.distribution = .fill $0.alignment = .top + $0.spacing = VDSLayout.Spacing.space2X.value } }() @@ -128,6 +129,8 @@ open class TextArea: EntryFieldBase { borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) borderColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .focused) textView.delegate = self + characterCounterLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() + bottomContainerStackView.spacing = VDSLayout.Spacing.space2X.value } /// Resets to default settings. @@ -161,10 +164,10 @@ open class TextArea: EntryFieldBase { minWidthConstraint?.isActive = true } - if ((maxLength ?? 0) > 0) { + if let maxLength, maxLength > 0 { // allow - 20% of character limit - let overflowLimit = Double(maxLength ?? 0) * 0.20 - allowCharCount = Int(overflowLimit) + (maxLength ?? 0) + let overflowLimit = Double(maxLength) * 0.20 + allowCharCount = Int(overflowLimit) + maxLength characterCounterLabel.text = getCharacterCounterText() } else { characterCounterLabel.text = "" @@ -175,8 +178,9 @@ open class TextArea: EntryFieldBase { containerView.layer.borderColor = readOnly ? readOnlyBorderColorConfiguration.getColor(self).cgColor : borderColorConfiguration.getColor(self).cgColor textView.isEditable = readOnly ? false : true textView.backgroundColor = backgroundColorConfiguration.getColor(self) - characterCounterLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() textView.tintColor = iconColorConfiguration.getColor(self) + characterCounterLabel.surface = surface + highlightCharacterOverflow() } /// Container for the area showing helper text, error text, character count, maximum length value. @@ -221,9 +225,11 @@ open class TextArea: EntryFieldBase { open func highlightCharacterOverflow() { let count = textView.text.count - guard let text = textView.attributedText?.mutableCopy() as? NSMutableAttributedString else { return } - text.addAttribute(NSAttributedString.Key.backgroundColor, value: highlightBackgroundColor.getColor(self), range: NSRange(location:(maxLength ?? 0 ), length: (count - (maxLength ?? 0)))) - text.addAttribute(NSAttributedString.Key.foregroundColor, value: highlightTextColor.getColor(self), range: NSRange(location:(maxLength ?? 0 ), length: (count - (maxLength ?? 0)))) + guard let maxLength, + count > maxLength, + let text = textView.attributedText?.mutableCopy() as? NSMutableAttributedString else { return } + text.addAttribute(NSAttributedString.Key.backgroundColor, value: highlightBackgroundColor.getColor(self), range: NSRange(location:maxLength, length: (count - maxLength))) + text.addAttribute(NSAttributedString.Key.foregroundColor, value: highlightTextColor.getColor(self), range: NSRange(location:maxLength, length: (count - maxLength))) textView.attributedText = text.copy() as? NSAttributedString } } From 4f41d9cc93b07d6cf3481bbe8ae141b2827184ff Mon Sep 17 00:00:00 2001 From: vasavk Date: Mon, 26 Feb 2024 22:46:33 +0530 Subject: [PATCH 014/147] Digital ACT191 story ONEAPP-6682 added preset default height property. --- .../TextFields/TextArea/TextArea.swift | 54 +++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 135a2421..a9c1cbf4 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -69,11 +69,44 @@ open class TextArea: EntryFieldBase { $0.numberOfLines = 1 } + private var _minHeight: Height = .twoX + + open var minHeight: Height? { + get { return _minHeight } + set { + if let newValue { + _minHeight = newValue + } else { + _minHeight = .twoX + } + textViewHeightConstraint?.constant = _minHeight.value + setNeedsUpdate() + } + } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- override var containerSize: CGSize { CGSize(width: 182, height: 88) } - + + /// Enum used to describe the the height of TextArea. + public enum Height: String, CaseIterable { + case twoX = "2X" + case fourX = "4X" + case eightX = "8X" + + var value: CGFloat { + switch self { + case .twoX: + 88 + case .fourX: + 176 + case .eightX: + 352 + } + } + } + /// UITextView shown in the TextArea. open var textView = UITextView().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -139,6 +172,8 @@ open class TextArea: EntryFieldBase { textView.text = "" characterCounterLabel.reset() characterCounterLabel.textStyle = .bodySmall + minHeight = .twoX + setNeedsUpdate() } /// Container for the area in which the user interacts. @@ -230,7 +265,7 @@ open class TextArea: EntryFieldBase { let text = textView.attributedText?.mutableCopy() as? NSMutableAttributedString else { return } text.addAttribute(NSAttributedString.Key.backgroundColor, value: highlightBackgroundColor.getColor(self), range: NSRange(location:maxLength, length: (count - maxLength))) text.addAttribute(NSAttributedString.Key.foregroundColor, value: highlightTextColor.getColor(self), range: NSRange(location:maxLength, length: (count - maxLength))) - textView.attributedText = text.copy() as? NSAttributedString + textView.attributedText = text } } @@ -244,15 +279,15 @@ extension TextArea: UITextViewDelegate { //if you want it to work "as-is" delete this code //since it will autogrow with the current settings if let textViewHeightConstraint, textView.isEditable { - let height = textView.contentSize.height - if height > 88 && height < 176 { - textViewHeightConstraint.constant = 176 - } else if height > 176 { - textViewHeightConstraint.constant = 352 + var height = textView.contentSize.height + height = max(height, _minHeight.value) + if height > Height.twoX.value && height < Height.fourX.value { + textViewHeightConstraint.constant = Height.fourX.value + } else if height > Height.fourX.value { + textViewHeightConstraint.constant = Height.eightX.value } else { - textViewHeightConstraint.constant = 88 + textViewHeightConstraint.constant = Height.twoX.value } - textViewHeightConstraint.isActive = true } //The exceeding characters will be highlighted to help users correct their entry. @@ -261,7 +296,6 @@ extension TextArea: UITextViewDelegate { //setting the value and firing control event value = textView.text sendActions(for: .valueChanged) - if (textView.text.count > (maxLength ?? 0)) { highlightCharacterOverflow() } From 11c8ed87565c85e2c4979ff5962c6e461b902d62 Mon Sep 17 00:00:00 2001 From: "Bandaru, Krishna Kishore" Date: Mon, 26 Feb 2024 21:10:53 +0000 Subject: [PATCH 015/147] Fixed conflicting constraints while displaying Notifications --- VDS/Components/Notification/Notification.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 2ed84116..126f83f0 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -398,13 +398,18 @@ open class Notification: View { } private func setConstraints() { + maxWidthConstraint?.deactivate() + labelViewAndButtonViewConstraint?.deactivate() + labelViewBottomConstraint?.deactivate() + buttonGroupCenterYConstraint?.deactivate() + buttonGroupBottomConstraint?.deactivate() maxWidthConstraint?.constant = maxViewWidth maxWidthConstraint?.isActive = UIDevice.isIPad labelViewAndButtonViewConstraint?.isActive = layout == .vertical && !buttonGroup.buttons.isEmpty - typeIconWidthConstraint?.constant = typeIcon.size.dimensions.width - closeIconWidthConstraint?.constant = closeButton.size.dimensions.width labelViewBottomConstraint?.isActive = layout == .horizontal || buttonGroup.buttons.isEmpty buttonGroupCenterYConstraint?.isActive = layout == .horizontal buttonGroupBottomConstraint?.isActive = layout == .vertical + typeIconWidthConstraint?.constant = typeIcon.size.dimensions.width + closeIconWidthConstraint?.constant = closeButton.size.dimensions.width } } From 9e91f38c52475851f072a4291dc891968904b3e3 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 26 Feb 2024 17:50:47 -0600 Subject: [PATCH 016/147] added "text" as a property Signed-off-by: Matt Bruce --- VDS/Components/TextFields/EntryFieldBase.swift | 6 ++++++ VDS/Components/TextFields/InputField/InputField.swift | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index dcb16fbf..e66d31a5 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -180,6 +180,12 @@ open class EntryFieldBase: Control, Changeable { } } + /// Override this to conveniently get/set the textfield(s). + open var text: String? { + get { nil } + set { fatalError("You MUST override EntryField's 'text' variable in your subclass.") } + } + open var tooltipModel: Tooltip.TooltipModel? { didSet { setNeedsUpdate() } } open var transparentBackground: Bool = false { didSet { setNeedsUpdate() } } diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 94ef5231..589ba28f 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -78,6 +78,14 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { /// Representing the type of input. open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } } + /// The text of this textField. + open override var text: String? { + get { textField.text } + set { + textField.text = newValue + } + } + var _showError: Bool = false /// Whether not to show the error. open override var showError: Bool { From 6d38474675932ac6cf855e88aa59d82e5c5090cb Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 26 Feb 2024 17:51:16 -0600 Subject: [PATCH 017/147] added text as a property added subclass of UITextField to deal with text rendering and attributes. Signed-off-by: Matt Bruce --- .../TextFields/TextArea/TextArea.swift | 179 ++++++++++++++++-- 1 file changed, 164 insertions(+), 15 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index a9c1cbf4..e9da9b11 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -107,20 +107,21 @@ open class TextArea: EntryFieldBase { } } + /// The text of this textField. + open override var text: String? { + get { textView.text } + set { + textView.text = newValue + } + } + /// UITextView shown in the TextArea. - open var textView = UITextView().with { + open var textView = TextView().with { $0.translatesAutoresizingMaskIntoConstraints = false - $0.font = TextStyle.bodyLarge.font $0.sizeToFit() $0.isScrollEnabled = false } - /// Color configuration for the textView. - open var textViewTextColorConfiguration: AnyColorable = ViewColorConfiguration().with { - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) - }.eraseToAnyColorable() { didSet { setNeedsUpdate() } } - /// Color configuration for error icon. internal var iconColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) @@ -187,7 +188,9 @@ open class TextArea: EntryFieldBase { super.updateView() textView.isEditable = isEnabled - textView.textColor = textViewTextColorConfiguration.getColor(self) + textView.isEnabled = isEnabled + textView.surface = surface + //set the width constraints if let width { widthConstraint?.constant = width @@ -260,12 +263,18 @@ open class TextArea: EntryFieldBase { open func highlightCharacterOverflow() { let count = textView.text.count - guard let maxLength, - count > maxLength, - let text = textView.attributedText?.mutableCopy() as? NSMutableAttributedString else { return } - text.addAttribute(NSAttributedString.Key.backgroundColor, value: highlightBackgroundColor.getColor(self), range: NSRange(location:maxLength, length: (count - maxLength))) - text.addAttribute(NSAttributedString.Key.foregroundColor, value: highlightTextColor.getColor(self), range: NSRange(location:maxLength, length: (count - maxLength))) - textView.attributedText = text + guard let maxLength, count > maxLength else { + textView.textAttributes = nil + return + } + + var textAttributes = [any LabelAttributeModel]() + let location = maxLength + let length = count - maxLength + textAttributes.append(ColorLabelAttribute(location: location, length: length, color: highlightBackgroundColor.getColor(self), isForegroundColor: false)) + textAttributes.append(ColorLabelAttribute(location: location, length: length, color: highlightTextColor.getColor(self), isForegroundColor: true)) + + textView.textAttributes = textAttributes } } @@ -310,3 +319,143 @@ extension TextArea: UITextViewDelegate { } } } + +/// Will move this into a new file, need to talk with Scott/Kyle +open class TextView: UITextView, ViewProtocol { + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero, textContainer: nil) + initialSetup() + } + + public override init(frame: CGRect, textContainer: NSTextContainer?) { + super.init(frame: frame, textContainer: textContainer) + initialSetup() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + initialSetup() + } + + //-------------------------------------------------- + // MARK: - Combine Properties + //-------------------------------------------------- + /// Set of Subscribers for any Publishers for this Control. + open var subscribers = Set() + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var initialSetupPerformed = false + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + /// Key of whether or not updateView() is called in setNeedsUpdate() + open var shouldUpdateView: Bool = true + + open var surface: Surface = .light { didSet { setNeedsUpdate() } } + + /// Array of LabelAttributeModel objects used in rendering the text. + open var textAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() } } + + /// TextStyle used on the titleLabel. + open var textStyle: TextStyle { .defaultStyle } + + /// Will determine if a scaled font should be used for the titleLabel font. + open var useScaledFont: Bool = false { didSet { setNeedsUpdate() } } + + open var isEnabled: Bool = true { didSet { setNeedsUpdate() } } + + open var textColorConfiguration: AnyColorable = ViewColorConfiguration().with { + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) + }.eraseToAnyColorable(){ didSet { setNeedsUpdate() }} + + open override var textColor: UIColor? { + get { textColorConfiguration.getColor(self) } + set { } + } + + override public var text: String! { + get { super.text } + set { + super.text = newValue + updateLabel() + } + } + + override public var textAlignment: NSTextAlignment { + didSet { + if textAlignment != oldValue { + // Text alignment can be part of our paragraph style, so we may need to + // re-style when changed + updateLabel() + } + } + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open func initialSetup() { + if !initialSetupPerformed { + backgroundColor = .clear + translatesAutoresizingMaskIntoConstraints = false + accessibilityCustomActions = [] + setup() + setNeedsUpdate() + } + } + + + open func setup() { + translatesAutoresizingMaskIntoConstraints = false + } + + open func updateView() { + updateLabel() + } + + open func updateAccessibility() {} + + open func reset() { + shouldUpdateView = false + surface = .light + text = nil + accessibilityCustomActions = [] + shouldUpdateView = true + setNeedsUpdate() + } + + //-------------------------------------------------- + // MARK: - Private Methods + //-------------------------------------------------- + private func updateLabel() { + + //clear the arrays holding actions + accessibilityCustomActions = [] + if let text, !text.isEmpty { + //create the primary string + let mutableText = NSMutableAttributedString.mutableText(for: text, + textStyle: textStyle, + useScaledFont: useScaledFont, + textColor: textColor!, + alignment: textAlignment, + lineBreakMode: .byWordWrapping) + //apply any attributes + if let attributes = textAttributes { + mutableText.apply(attributes: attributes) + } + attributedText = mutableText + } else { + attributedText = nil + } + } + + +} From a2026a4319069a7b56b67a7953511e22d334b75c Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 27 Feb 2024 17:24:16 +0530 Subject: [PATCH 018/147] Digital ACT191 story ONEAPP-6682 removed unnecessary code --- VDS/Components/TextFields/TextArea/TextArea.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index a9c1cbf4..3cf465dc 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -143,7 +143,6 @@ open class TextArea: EntryFieldBase { open override func setup() { super.setup() accessibilityLabel = "TextArea" - isAccessibilityElement = true containerStackView.pinToSuperView(.uniform(VDSFormControls.spaceInset)) minWidthConstraint = containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: containerSize.width) @@ -172,7 +171,6 @@ open class TextArea: EntryFieldBase { textView.text = "" characterCounterLabel.reset() characterCounterLabel.textStyle = .bodySmall - minHeight = .twoX setNeedsUpdate() } From f4f6a005e40e99bb8b620cbeaada917d0be4a792 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 27 Feb 2024 09:47:50 -0600 Subject: [PATCH 019/147] put accessibility changes to method. Signed-off-by: Matt Bruce --- VDS/Components/Loader/Loader.swift | 37 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/VDS/Components/Loader/Loader.swift b/VDS/Components/Loader/Loader.swift index 90d589be..baf6ecdb 100644 --- a/VDS/Components/Loader/Loader.swift +++ b/VDS/Components/Loader/Loader.swift @@ -87,8 +87,26 @@ open class Loader: View { } invalidateIntrinsicContentSize() } - + open override func updateAccessibility() { + super.updateAccessibility() + + // check to make sure VoiceOver is running + guard UIAccessibility.isVoiceOverRunning, isActive else { + loadingTimer?.invalidate() + loadingTimer = nil + return + } + + // Focus VoiceOver on this view + UIAccessibility.post(notification: .layoutChanged, argument: self) + + // setup timer for post + loadingTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { [weak self] _ in + guard let self, self.isActive, self.isVisibleOnScreen else { return } + self.accessibilityLabel = "Still Loading" + UIAccessibility.post(notification: .announcement, argument: "Still Loading") + } } //-------------------------------------------------- @@ -107,23 +125,6 @@ open class Loader: View { rotation.duration = 0.5 rotation.repeatCount = .infinity icon.layer.add(rotation, forKey: rotationLayerName) - - // check to make sure VoiceOver is running - guard UIAccessibility.isVoiceOverRunning else { - loadingTimer?.invalidate() - loadingTimer = nil - return - } - - // Focus VoiceOver on this view - UIAccessibility.post(notification: .layoutChanged, argument: self) - - // setup timer for post - loadingTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { [weak self] _ in - guard let self, self.isActive, self.isVisibleOnScreen else { return } - self.accessibilityLabel = "Still Loading" - UIAccessibility.post(notification: .announcement, argument: "Still Loading") - } } private func stopAnimating() { From d8e393049a8c4bc189e85d1f68e230396cfa122e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 27 Feb 2024 10:02:09 -0600 Subject: [PATCH 020/147] updated release notes and version Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 4 ++-- VDS/SupportingFiles/ReleaseNotes.txt | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index b13f7df5..ef6acb80 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -1253,7 +1253,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 54; + CURRENT_PROJECT_VERSION = 55; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1290,7 +1290,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 54; + CURRENT_PROJECT_VERSION = 55; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 404e531b..e1cd12fd 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,3 +1,8 @@ +1.0.55 +---------------- +- ONEAPP-6305 - BadgeIndicator - Finished Development +- ONEAPP-6679 - TileContainer - Finished Development + 1.0.54 ---------------- - CXTDT-518373 Accessibility Voiceover is reading “Still Loading” after waiting for a short time in all the screens. From af2c5cd368d09b083f1f9712d770edc20ab2d39e Mon Sep 17 00:00:00 2001 From: vasavk Date: Wed, 28 Feb 2024 16:39:44 +0530 Subject: [PATCH 021/147] Digital ACT-191 ONEAPP-6682 story: Fixed minor issue for TextArea height --- VDS/Components/TextFields/TextArea/TextArea.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index aee4ab9a..92f5525a 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -288,7 +288,7 @@ extension TextArea: UITextViewDelegate { if let textViewHeightConstraint, textView.isEditable { var height = textView.contentSize.height height = max(height, _minHeight.value) - if height > Height.twoX.value && height < Height.fourX.value { + if height > Height.twoX.value && height <= Height.fourX.value { textViewHeightConstraint.constant = Height.fourX.value } else if height > Height.fourX.value { textViewHeightConstraint.constant = Height.eightX.value From 301ead74474f52670eac2d3945e88dbf2608f092 Mon Sep 17 00:00:00 2001 From: vasavk Date: Wed, 28 Feb 2024 22:03:17 +0530 Subject: [PATCH 022/147] Digital ACT-191 ONEAPP-6682 story: Fix for the observed crash on removing last char when having char counter and exceeded limit. --- VDS/Components/TextFields/TextArea/TextArea.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 92f5525a..432d24bd 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -300,12 +300,11 @@ extension TextArea: UITextViewDelegate { //The exceeding characters will be highlighted to help users correct their entry. if ((maxLength ?? 0) > 0) { if textView.text.count <= allowCharCount { + highlightCharacterOverflow() + //setting the value and firing control event value = textView.text sendActions(for: .valueChanged) - if (textView.text.count > (maxLength ?? 0)) { - highlightCharacterOverflow() - } } else { textView.text.removeLast() highlightCharacterOverflow() From 05638422f61bf18fe7a2365d8029c573db7ecc24 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 28 Feb 2024 13:04:11 -0600 Subject: [PATCH 023/147] updated labels to ensure string is valid Signed-off-by: Matt Bruce --- VDS/Components/Label/Attributes/AnyLabelAttribute.swift | 1 + VDS/Components/Label/Attributes/ColorLabelAttribute.swift | 2 ++ VDS/Components/Label/Attributes/LabelAttributeModel.swift | 4 ++++ .../Label/Attributes/StrikeThroughLabelAttribute.swift | 1 + VDS/Components/Label/Attributes/TextStyleLabelAttribute.swift | 1 + VDS/Components/Label/Attributes/UnderlineLabelAttribute.swift | 3 ++- 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Label/Attributes/AnyLabelAttribute.swift b/VDS/Components/Label/Attributes/AnyLabelAttribute.swift index b914c912..50e76ba7 100644 --- a/VDS/Components/Label/Attributes/AnyLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/AnyLabelAttribute.swift @@ -30,6 +30,7 @@ public struct AnyAttribute: LabelAttributeModel { } public func setAttribute(on attributedString: NSMutableAttributedString) { + guard isValidRange(on: attributedString) else { return } attributedString.removeAttribute(key, range: range) attributedString.addAttribute(key, value: value, range: range) } diff --git a/VDS/Components/Label/Attributes/ColorLabelAttribute.swift b/VDS/Components/Label/Attributes/ColorLabelAttribute.swift index 354fbc93..50229ab0 100644 --- a/VDS/Components/Label/Attributes/ColorLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/ColorLabelAttribute.swift @@ -31,6 +31,8 @@ public struct ColorLabelAttribute: LabelAttributeModel { } public func setAttribute(on attributedString: NSMutableAttributedString) { + guard isValidRange(on: attributedString) else { return } + var colorRange = range if length == 0 && location == 0 { colorRange = .init(location: location, length: attributedString.length) diff --git a/VDS/Components/Label/Attributes/LabelAttributeModel.swift b/VDS/Components/Label/Attributes/LabelAttributeModel.swift index 62e1bbd8..87708ffb 100644 --- a/VDS/Components/Label/Attributes/LabelAttributeModel.swift +++ b/VDS/Components/Label/Attributes/LabelAttributeModel.swift @@ -29,6 +29,10 @@ extension LabelAttributeModel { public static func == (lhs: any LabelAttributeModel, rhs: any LabelAttributeModel) -> Bool { lhs.isEqual(rhs) } + + public func isValidRange(on attributedString: NSMutableAttributedString) -> Bool { + true//range.location + range.length <= attributedString.string.count + } } public extension NSAttributedString { diff --git a/VDS/Components/Label/Attributes/StrikeThroughLabelAttribute.swift b/VDS/Components/Label/Attributes/StrikeThroughLabelAttribute.swift index 93650f2b..ba4c97ac 100644 --- a/VDS/Components/Label/Attributes/StrikeThroughLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/StrikeThroughLabelAttribute.swift @@ -24,6 +24,7 @@ public struct StrikeThroughLabelAttribute: LabelAttributeModel { } public func setAttribute(on attributedString: NSMutableAttributedString) { + guard isValidRange(on: attributedString) else { return } attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range) attributedString.addAttribute(.baselineOffset, value: 0, range: range) } diff --git a/VDS/Components/Label/Attributes/TextStyleLabelAttribute.swift b/VDS/Components/Label/Attributes/TextStyleLabelAttribute.swift index ae3ea1e5..a161d580 100644 --- a/VDS/Components/Label/Attributes/TextStyleLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TextStyleLabelAttribute.swift @@ -44,6 +44,7 @@ public struct TextStyleLabelAttribute: LabelAttributeModel { } public func setAttribute(on attributedString: NSMutableAttributedString) { + guard isValidRange(on: attributedString) else { return } attributedString.removeAttribute(.font, range: range) attributedString.addAttribute(.font, value: textStyle.font, range: range) if let textColor { diff --git a/VDS/Components/Label/Attributes/UnderlineLabelAttribute.swift b/VDS/Components/Label/Attributes/UnderlineLabelAttribute.swift index 0ca4e2f9..a2ad403e 100644 --- a/VDS/Components/Label/Attributes/UnderlineLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/UnderlineLabelAttribute.swift @@ -52,7 +52,8 @@ public struct UnderlineLabelAttribute: LabelAttributeModel { //-------------------------------------------------- // MARK: - Public Methods //-------------------------------------------------- - public func setAttribute(on attributedString: NSMutableAttributedString) { + public func setAttribute(on attributedString: NSMutableAttributedString) { + guard isValidRange(on: attributedString) else { return } attributedString.addAttribute(.underlineStyle, value: underlineValue.rawValue, range: range) if let color = color { attributedString.addAttribute(.underlineColor, value: color, range: range) From a4582f11a597b50af9bd082500819f256c61e504 Mon Sep 17 00:00:00 2001 From: vasavk Date: Thu, 29 Feb 2024 00:45:54 +0530 Subject: [PATCH 024/147] Digital ACT-191 ONEAPP-6682 story: fixed the bug dealing with the character counter --- VDS/Components/TextFields/TextArea/TextArea.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 432d24bd..8e5f8e58 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -251,7 +251,7 @@ open class TextArea: EntryFieldBase { return countStr } else { showError = false - errorText = "" + errorText = nil return ("\(countStr)" + "/" + "\(maxLength ?? 0)") } } else { @@ -261,7 +261,7 @@ open class TextArea: EntryFieldBase { open func highlightCharacterOverflow() { let count = textView.text.count - guard let maxLength, count > maxLength else { + guard let maxLength, maxLength > 0, count > maxLength else { textView.textAttributes = nil return } @@ -315,6 +315,7 @@ extension TextArea: UITextViewDelegate { sendActions(for: .valueChanged) } } + } /// Will move this into a new file, need to talk with Scott/Kyle From 82a8a32ccbd1f79c6144b83d7a6bc2a328917dc9 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 29 Feb 2024 10:14:42 -0600 Subject: [PATCH 025/147] refactored into base class for dealing with TileContainer Padding --- .../TileContainer/TileContainer.swift | 75 +++++++++++-------- VDS/Components/Tilelet/Tilelet.swift | 52 ++++++++----- 2 files changed, 75 insertions(+), 52 deletions(-) diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index 98090ae4..0484e815 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -10,8 +10,45 @@ import VDSColorTokens import VDSFormControlsTokens import UIKit +public protocol Valuing { + static var defaultValue: Self { get } + var value: CGFloat { get } +} + @objc(VDSTileContainer) -open class TileContainer: Control { +open class TileContainer: TileContainerBase { + + /// Enum used to describe the padding choices used for this component. + public enum Padding: Valuing { + case padding2X + case padding4X + case padding6X + case padding8X + case padding12X + case custom(CGFloat) + + public static var defaultValue: Self { .padding4X } + + public var value: CGFloat { + switch self { + case .padding2X: + return VDSLayout.Spacing.space2X.value + case .padding4X: + return VDSLayout.Spacing.space4X.value + case .padding6X: + return VDSLayout.Spacing.space6X.value + case .padding8X: + return VDSLayout.Spacing.space8X.value + case .padding12X: + return VDSLayout.Spacing.space12X.value + case .custom(let padding): + return padding + } + } + } +} + +open class TileContainerBase: Control { //-------------------------------------------------- // MARK: - Initializers @@ -53,33 +90,6 @@ open class TileContainer: Control { case gradient(String, String) case none } - - /// Enum used to describe the padding choices used for this component. - public enum Padding { - case padding2X - case padding4X - case padding6X - case padding8X - case padding12X - case custom(CGFloat) - - public var value: CGFloat { - switch self { - case .padding2X: - return VDSLayout.Spacing.space2X.value - case .padding4X: - return VDSLayout.Spacing.space4X.value - case .padding6X: - return VDSLayout.Spacing.space6X.value - case .padding8X: - return VDSLayout.Spacing.space8X.value - case .padding12X: - return VDSLayout.Spacing.space12X.value - case .custom(let padding): - return padding - } - } - } /// Enum used to describe the aspect ratios used for this component. public enum AspectRatio: String, CaseIterable { @@ -130,7 +140,7 @@ open class TileContainer: Control { open var backgroundEffect: BackgroundEffect = .none { didSet { setNeedsUpdate() } } /// Sets the inside padding for the component - open var padding: Padding = .padding4X { didSet { setNeedsUpdate() } } + open var padding: PaddingType = PaddingType.defaultValue { didSet { setNeedsUpdate() } } /// Applies a background color if backgroundImage prop fails or has trouble loading. open var imageFallbackColor: Surface = .light { didSet { setNeedsUpdate() } } @@ -253,7 +263,6 @@ open class TileContainer: Control { super.reset() shouldUpdateView = false color = .white - padding = .padding4X aspectRatio = .ratio1x1 imageFallbackColor = .light width = nil @@ -395,7 +404,7 @@ open class TileContainer: Control { } -extension TileContainer { +extension TileContainerBase { struct DropshadowConfiguration: Dropshadowable { var shadowColorConfiguration: AnyColorable = SurfaceColorConfiguration().with { @@ -408,7 +417,7 @@ extension TileContainer { final class BackgroundColorConfiguration: ObjectColorable { - typealias ObjectType = TileContainer + typealias ObjectType = TileContainerBase let primaryColorConfig = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) let secondaryColorConfig = SurfaceColorConfiguration(VDSColor.backgroundSecondaryLight, VDSColor.backgroundSecondaryDark) @@ -418,7 +427,7 @@ extension TileContainer { required init() { } - func getColor(_ object: TileContainer) -> UIColor { + func getColor(_ object: ObjectType) -> UIColor { switch object.color { case .primary: primaryColorConfig.getColor(object.surface) diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 657a735b..3d5fe495 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -16,7 +16,38 @@ import Combine /// while it can include an arrow CTA, it does not require one in order to /// function. @objc(VDSTilelet) -open class Tilelet: TileContainer { +open class Tilelet: TileContainerBase { + + /// Enum used to describe the padding choices used for this component. + public enum Padding: String, Valuing, CaseIterable { + case small + case large + + public static var defaultValue: Self { .large } + + public var value: CGFloat { + switch self { + case .small: + return UIDevice.isIPad ? VDSLayout.Spacing.space3X.value : VDSLayout.Spacing.space4X.value + case .large: + return UIDevice.isIPad ? VDSLayout.Spacing.space4X.value : VDSLayout.Spacing.space6X.value + } + } + + fileprivate var titleLockupBottomSpacing: CGFloat { + switch self.value { + case VDSLayout.Spacing.space3X.value: + return VDSLayout.Spacing.space4X.value + case VDSLayout.Spacing.space4X.value: + return VDSLayout.Spacing.space6X.value + case VDSLayout.Spacing.space4X.value: + return VDSLayout.Spacing.space8X.value + default: + return VDSLayout.Spacing.space4X.value + } + } + } + //-------------------------------------------------- // MARK: - Initializers @@ -392,7 +423,7 @@ open class Tilelet: TileContainer { view = titleLockupContainerView } if let view { - stackView.setCustomSpacing(padding.tiletSpacing, after: view) + stackView.setCustomSpacing(padding.titleLockupBottomSpacing, after: view) } if iconContainerView.superview == nil { stackView.addArrangedSubview(iconContainerView) @@ -403,20 +434,3 @@ open class Tilelet: TileContainer { } } } - -extension TileContainer.Padding { - fileprivate var tiletSpacing: CGFloat { - switch self { - case .padding2X: - return 16 - case .padding4X: - return 24 - case .padding6X: - return 32 - case .padding8X: - return 48 - default: - return 16 - } - } -} From 69a23745040dfb10fe755144124a6905faa455ea Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 29 Feb 2024 10:34:10 -0600 Subject: [PATCH 026/147] First cut at form fiedable change Signed-off-by: Matt Bruce --- .../Attributes/LabelAttributeModel.swift | 2 +- .../TextFields/EntryFieldBase.swift | 4 +- .../TextFields/InputField/InputField.swift | 4 +- .../TextFields/TextArea/TextArea.swift | 43 +++++++++++--- VDS/Protocols/FormFieldable.swift | 58 ++++++++++++++++++- 5 files changed, 97 insertions(+), 14 deletions(-) diff --git a/VDS/Components/Label/Attributes/LabelAttributeModel.swift b/VDS/Components/Label/Attributes/LabelAttributeModel.swift index 87708ffb..ac43472f 100644 --- a/VDS/Components/Label/Attributes/LabelAttributeModel.swift +++ b/VDS/Components/Label/Attributes/LabelAttributeModel.swift @@ -31,7 +31,7 @@ extension LabelAttributeModel { } public func isValidRange(on attributedString: NSMutableAttributedString) -> Bool { - true//range.location + range.length <= attributedString.string.count + range.location + range.length <= attributedString.string.count } } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index e66d31a5..3b738549 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -13,7 +13,7 @@ import Combine /// Base Class used to build out a Input controls. @objc(VDSEntryField) -open class EntryFieldBase: Control, Changeable { +open class EntryFieldBase: Control, Changeable, FormFieldable { //-------------------------------------------------- // MARK: - Initializers @@ -196,7 +196,7 @@ open class EntryFieldBase: Control, Changeable { open var inputId: String? { didSet { setNeedsUpdate() } } - open var value: AnyHashable? { didSet { setNeedsUpdate() } } + open var value: String? { didSet { setNeedsUpdate() } } open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } } diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 589ba28f..7a950a80 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -79,13 +79,13 @@ open class InputField: EntryFieldBase, UITextFieldDelegate { open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } } /// The text of this textField. - open override var text: String? { + open override var value: String? { get { textField.text } set { textField.text = newValue } } - + var _showError: Bool = false /// Whether not to show the error. open override var showError: Bool { diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 92f5525a..4b99eeb3 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -107,14 +107,15 @@ open class TextArea: EntryFieldBase { } } - /// The text of this textField. - open override var text: String? { + open override var value: String? { get { textView.text } set { textView.text = newValue + setNeedsUpdate() + } } - + /// UITextView shown in the TextArea. open var textView = TextView().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -184,7 +185,7 @@ open class TextArea: EntryFieldBase { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - + countRule.maxLength = maxLength textView.isEditable = isEnabled textView.isEnabled = isEnabled textView.surface = surface @@ -208,6 +209,9 @@ open class TextArea: EntryFieldBase { } else { characterCounterLabel.text = "" } + + showError = !validator.validate() + errorText = validator.errorMessage icon.size = .medium icon.color = iconColorConfiguration.getColor(self) @@ -246,12 +250,8 @@ open class TextArea: EntryFieldBase { let countStr = (count > maxLength ?? 0) ? ("-" + "\(count-(maxLength ?? 0))") : "\(count)" if ((maxLength ?? 0) > 0) { if (count > (maxLength ?? 0)) { - showError = true - errorText = "You have exceeded the character limit." return countStr } else { - showError = false - errorText = "" return ("\(countStr)" + "/" + "\(maxLength ?? 0)") } } else { @@ -274,6 +274,33 @@ open class TextArea: EntryFieldBase { textView.textAttributes = textAttributes } + + //-------------------------------------------------- + // MARK: - Validation + //-------------------------------------------------- + var countRule = CharacterCountRule() + lazy var validator: FieldValidator