From 57135f8ac7e4ecf0778d4dd0907a6c2f474c6975 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 15:48:53 -0500 Subject: [PATCH 01/17] updating bundle manager Signed-off-by: Matt Bruce --- VDS/Classes/BundleManager.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/VDS/Classes/BundleManager.swift b/VDS/Classes/BundleManager.swift index e7365b08..50537c0d 100644 --- a/VDS/Classes/BundleManager.swift +++ b/VDS/Classes/BundleManager.swift @@ -8,6 +8,8 @@ import Foundation import UIKit + +/// Bundle Manager keeps all bundles together for ease of use for searching within any of them for a specific asset public class BundleManager { public static var shared = BundleManager() @@ -28,6 +30,8 @@ public class BundleManager { }) } + /// With take a location and if found append to the local array for use later for asset searching. + /// - Parameter path: Location of the bundle public static func register(_ path: String) { if !shared.paths.contains(where: {$0 == path}) { if let bundle = Bundle(path: path) { @@ -40,6 +44,9 @@ public class BundleManager { extension BundleManager { + /// Searches through all registered bundles for an image + /// - Parameter name: Name of the image + /// - Returns: Will find an image or not. public func image(for name: String) -> UIImage? { var foundImage: UIImage? From b0788a85dd94c017861a34605b6ad007b1b280fc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:02:42 -0500 Subject: [PATCH 02/17] added comments for ColorConfiguration Signed-off-by: Matt Bruce --- VDS/Classes/ColorConfiguration.swift | 54 ++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/VDS/Classes/ColorConfiguration.swift b/VDS/Classes/ColorConfiguration.swift index c52a793f..9d902a1d 100644 --- a/VDS/Classes/ColorConfiguration.swift +++ b/VDS/Classes/ColorConfiguration.swift @@ -21,7 +21,9 @@ public typealias ObjectColorable = Colorable & Initable & ObjectWithable /// config.darkColor = .white /// /// let textColor = config.getColor(model) //returns .black +/// +/// You can pass in a Surfaceable object and it will give you the color responding. open class SurfaceColorConfiguration: ObjectColorable { public typealias ObjectType = Surfaceable public var lightColor: UIColor = .clear @@ -29,15 +31,27 @@ open class SurfaceColorConfiguration: ObjectColorable { required public init(){} + /// Inititialization + /// - Parameters: + /// - lightColor: Color used for a light surface + /// - darkColor: Color used for a dark surface public init(_ lightColor: UIColor, _ darkColor: UIColor) { self.lightColor = lightColor self.darkColor = darkColor } + + /// Will get the UIColor for the surface passed in + /// - Parameter surface: surface you currently have + /// - Returns: color corresponding to the surface you passed public func getColor(_ surface: Surface) -> UIColor { return surface == .light ? lightColor : darkColor } + + /// Colorable Generic method that will only take in any object that has a Surfacable implementation + /// - Parameter object: any Surfacable object type + /// - Returns: UIColor for the object type you passed in public func getColor(_ object: any ObjectType) -> UIColor { return getColor(object.surface) } @@ -57,16 +71,30 @@ public protocol KeyColorConfigurable: ObjectColorable { } extension KeyColorConfigurable { + + /// Generic Method to set a KeyColorConfiguration with the parameters given + /// - Parameters: + /// - lightColor: Color used for a light + /// - darkColor: Color used for a dark + /// - key: <#key description#> public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forKey key: KeyType) { keyColors.append(.init(key: key, surfaceConfig: .init(lightColor, darkColor))) } + + /// Removes all keyColors public func reset() { keyColors.removeAll() } } extension KeyColorConfigurable where ObjectType: Surfaceable { + + /// Default Implementation for when the ObjectType is a Surfacable + /// - Parameters: + /// - object: Surfaceable ObjectType + /// - key: KeyPath to the property of the ObjectType + /// - Returns: UIColor corresponding the the key and surface public func getColor(for object: ObjectType, with key: KeyType) -> UIColor { if let keyColor = keyColors.first(where: {$0.key == key }) { return keyColor.surfaceConfig.getColor(object) @@ -77,6 +105,8 @@ extension KeyColorConfigurable where ObjectType: Surfaceable { } +/// ColorConfiguration for UIControls and will implement KeyColorConfigurale. This will then use the +/// register a SurfaceColorConfiguration for each state. public class ControlColorConfiguration: KeyColorConfigurable { public typealias KeyType = UIControl.State public typealias ObjectType = Surfaceable & UIControl @@ -84,10 +114,19 @@ public class ControlColorConfiguration: KeyColorConfigurable { private var lastKeyColor: KeyColorConfiguration? public required init() { } + + /// Helper method to set the SurfaceColorConfiguration for a state + /// - Parameters: + /// - lightColor: Color used for a light + /// - darkColor: Color used for a dark + /// - state: UIControlState you are keying off of. public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forState state: KeyType) { setSurfaceColors(lightColor, darkColor, forKey: state) } + /// Colorable implementation for getColor that where the object passed in will be of a UIControl as well as implementing Surfaceable. + /// - Parameter object: Object that is of UIControl and implements Surfacable + /// - Returns: UIColor corresponding to the UIControl.state and surface property of this object. public func getColor(_ object: any ObjectType) -> UIColor { let state = object.state let surface = object.surface @@ -115,6 +154,7 @@ public class ControlColorConfiguration: KeyColorConfigurable { } } +///Meant to be used with any object that implements Surfaceable and Disabling. More than likely this is any View. public class ViewColorConfiguration: KeyColorConfigurable { public typealias KeyType = Bool public typealias ObjectType = Surfaceable & Disabling @@ -122,10 +162,18 @@ public class ViewColorConfiguration: KeyColorConfigurable { public required init() { } + /// Helper method to set the SurfaceColorConfiguration based on whether the object is disabled or not. + /// - Parameters: + /// - lightColor: Color used for a light + /// - darkColor: Color used for a dark + /// - disabled: True/False for disabled property public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forDisabled disabled: KeyType) { setSurfaceColors(lightColor, darkColor, forKey: disabled) } + /// Colorable implementation for getColor that where the object passed in will any object that implementing Surfaceable and Disabling. + /// - Parameter object: Object that implements Surfaceable and Disabling + /// - Returns: UIColor correspoding to either true/false for the disabled state and surface public func getColor(_ object: ObjectType) -> UIColor { if let keyColor = keyColors.first(where: {$0.key == object.disabled }) { return keyColor.surfaceConfig.getColor(object) @@ -154,11 +202,17 @@ public class KeyedColorConfiguration KeyType? { guard let keyPath else { fatalError("keyPath must not be empty, make sure you initialize this class using init(keyPath: \\Object.property) method") } return object[keyPath: keyPath] } + /// Colorable implementation for getColor that where the object passed in will any object that implementing Surfaceable for the KeyPath registered. + /// - Parameter object: Object matching the type registered + /// - Returns: UIColor for the Object pertaining to the KeyPath it was registered public func getColor(_ object: ObjectType) -> UIColor { if let key = getKeyValue(object), let keyColor = keyColors.first(where: {$0.key == key }) { return keyColor.surfaceConfig.getColor(object) From d358194b7df12322be0e842f359f0b18491e0651 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:15:38 -0500 Subject: [PATCH 03/17] added comments to Control Signed-off-by: Matt Bruce --- VDS/Classes/Control.swift | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 5296e599..7e619aba 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -15,7 +15,11 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab //-------------------------------------------------- // MARK: - Combine Properties //-------------------------------------------------- + + /// Set of Subscribers for any Publishers for this Control public var subscribers = Set() + + /// Sets the primary Subscriber used for the TouchUpInside public var onClickSubscriber: AnyCancellable? { willSet { if let onClickSubscriber { @@ -28,37 +32,46 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab // MARK: - Properties //-------------------------------------------------- private var initialSetupPerformed = false - + + /// Key of whether or not updateView() is called in setNeedsUpdate() open var shouldUpdateView: Bool = true + /// Dictionary for keeping information for this Control use only Primitives open var userInfo = [String: Primitive]() - + + /// Current Surface used within this Control and used to passdown to child views open var surface: Surface = .light { didSet { setNeedsUpdate() } } + /// Control is disabled or not open var disabled: Bool = false { didSet { isEnabled = !disabled } } - + + /// Override for isSelected to handle setNeedsUpdate() on changes open override var isSelected: Bool { didSet { setNeedsUpdate() } } + /// Reference count use to be used in isHighlighted when a subscriber is listening for TouchUpInside. public var touchUpInsideCount: Int = 0 var isHighlightAnimating = false + + /// Override to deal with only calling setNeedsUpdate() if needed open override var isHighlighted: Bool { didSet { if isHighlightAnimating == false && touchUpInsideCount > 0 { isHighlightAnimating = true UIView.animate(withDuration: 0.1, animations: { [weak self] in - self?.updateView() + self?.setNeedsUpdate() }) { [weak self] _ in //you update the view since this is typically a quick change UIView.animate(withDuration: 0.1, animations: { [weak self] in - self?.updateView() + self?.setNeedsUpdate() self?.isHighlightAnimating = false }) } } } } - + + /// Override to deal with setNeedsUpdate() open override var isEnabled: Bool { get { !disabled } set { @@ -92,6 +105,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab // MARK: - Setup //-------------------------------------------------- + /// Executed on initialization for this Control open func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true @@ -99,7 +113,9 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab setNeedsUpdate() } } - + + ///Override to deal with sending actions for accessibility + /// - Returns: Based on whether the userInteraction is enabled override open func accessibilityActivate() -> Bool { // Hold state in case User wanted isAnimated to remain off. guard isUserInteractionEnabled else { return false } @@ -110,6 +126,8 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + + /// Update this view based off of property changes open func updateView() { updateAccessibilityLabel() } @@ -117,7 +135,8 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab open func updateAccessibilityLabel() { } - + + /// Resets to the Controls default values open func reset() { backgroundColor = .clear surface = .light @@ -125,7 +144,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab } // MARK: - ViewProtocol - /// Will be called only once. + /// Will be called only once and should be overridden in subclasses to setup UI or defaults open func setup() { backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false From c9ae6b0954422b9ca812272004b79017e9f953b1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:18:10 -0500 Subject: [PATCH 04/17] added comments to View Signed-off-by: Matt Bruce --- VDS/Classes/View.swift | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/VDS/Classes/View.swift b/VDS/Classes/View.swift index 2372ed4b..8513bd7e 100644 --- a/VDS/Classes/View.swift +++ b/VDS/Classes/View.swift @@ -23,14 +23,19 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { //-------------------------------------------------- private var initialSetupPerformed = false + /// Key of whether or not updateView() is called in setNeedsUpdate() open var shouldUpdateView: Bool = true + /// Dictionary for keeping information for this Control use only Primitives open var userInfo = [String: Primitive]() - - open var surface: Surface = .light { didSet { setNeedsUpdate() }} + /// Current Surface used within this Control and used to passdown to child views + open var surface: Surface = .light { didSet { setNeedsUpdate() } } + + /// Control is disabled or not open var disabled: Bool = false { didSet { isEnabled = !disabled } } - + + /// Override to deal with setNeedsUpdate() open var isEnabled: Bool { get { !disabled } set { @@ -64,6 +69,7 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { // MARK: - Setup //-------------------------------------------------- + /// Executed on initialization for this View open func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true @@ -75,22 +81,25 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + + /// Update this view based off of property changes open func updateView() { updateAccessibilityLabel() } + /// Used to update any Accessibility properties open func updateAccessibilityLabel() { } + /// Resets to the Views default values open func reset() { backgroundColor = .clear surface = .light disabled = false } - // MARK: - ViewProtocol - /// Will be called only once. + /// Will be called only once and should be overridden in subclasses to setup UI or defaults open func setup() { backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false From dcf766a2676114794f3aee840afc90ebd6395e87 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:18:21 -0500 Subject: [PATCH 05/17] updated comments on Control Signed-off-by: Matt Bruce --- VDS/Classes/Control.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 7e619aba..0ca1715f 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -132,6 +132,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab updateAccessibilityLabel() } + /// Used to update any Accessibility properties open func updateAccessibilityLabel() { } @@ -143,7 +144,6 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab disabled = false } - // MARK: - ViewProtocol /// Will be called only once and should be overridden in subclasses to setup UI or defaults open func setup() { backgroundColor = .clear From 814a04869014987cc40ea3e0c61feafb4781ccdc Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:24:25 -0500 Subject: [PATCH 06/17] added comments to the SelectorGroupHandlerBase Signed-off-by: Matt Bruce --- VDS/Classes/SelectorGroupHandlerBase.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/VDS/Classes/SelectorGroupHandlerBase.swift b/VDS/Classes/SelectorGroupHandlerBase.swift index b2483461..09e37abb 100644 --- a/VDS/Classes/SelectorGroupHandlerBase.swift +++ b/VDS/Classes/SelectorGroupHandlerBase.swift @@ -9,13 +9,17 @@ import Foundation import UIKit import Combine +/// Base Class used for any Grouped Form Control of a Selector Type open class SelectorGroupHandlerBase: Control, Changeable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + + /// Array of the HandlerType registered public var selectorViews: [HandlerType] = [] + /// The primary subscriber for onChange or the UIControl valueChanged event. public var onChangeSubscriber: AnyCancellable? { willSet { if let onChangeSubscriber { @@ -27,6 +31,8 @@ open class SelectorGroupHandlerBase: Control, Changeable { //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + + /// Override to update the child SelectorViews disabled property for this group override public var disabled: Bool { didSet { selectorViews.forEach { handler in @@ -35,6 +41,7 @@ open class SelectorGroupHandlerBase: Control, Changeable { } } + /// Override to update the child SelectorViews surface property for this group override public var surface: Surface { didSet { selectorViews.forEach { handler in @@ -43,16 +50,20 @@ open class SelectorGroupHandlerBase: Control, Changeable { } } + /// Handler for the Group to override on a select event + /// - Parameter selectedControl: Selected Control the user interacted open func didSelect(_ selectedControl: HandlerType) { fatalError("Must override didSelect") } + /// Helper method to execute the valueChanged event public func valueChanged() { DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in self?.sendActions(for: .valueChanged) } } + /// Override to update the child SelectorViews reset method for this group open override func reset() { super.reset() selectorViews.forEach{ $0.reset() } @@ -60,6 +71,8 @@ open class SelectorGroupHandlerBase: Control, Changeable { } open class SelectorGroupSelectedHandlerBase: SelectorGroupHandlerBase{ + + /// Current Selected Control for this group public var selectedHandler: HandlerType? { return selectorViews.filter { $0.isSelected == true }.first } From 8fd56aa99bc9895fb7c04fca519175b67ab78c85 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:35:02 -0500 Subject: [PATCH 07/17] added comments for SelfSizingCollectionView Signed-off-by: Matt Bruce --- VDS/Classes/SelfSizingCollectionView.swift | 28 +++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/VDS/Classes/SelfSizingCollectionView.swift b/VDS/Classes/SelfSizingCollectionView.swift index 55c3962b..dbedd80e 100644 --- a/VDS/Classes/SelfSizingCollectionView.swift +++ b/VDS/Classes/SelfSizingCollectionView.swift @@ -9,12 +9,19 @@ import Foundation import UIKit @objc(VDSSelfSizingCollectionView) +/// UICollectionView subclassed used to deal with Changing the size of itself based on its children and layout and changes of its contentSize public final class SelfSizingCollectionView: UICollectionView { private var contentSizeObservation: NSKeyValueObservation? + //-------------------------------------------------- // MARK: - Lifecycle - + //-------------------------------------------------- + + /// Initializer + /// - Parameters: + /// - frame: Frame needed + /// - layout: Layout used for this CollectionView public override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) { super.init(frame: frame, collectionViewLayout: layout) self.setupContentSizeObservation() @@ -25,14 +32,18 @@ public final class SelfSizingCollectionView: UICollectionView { self.setupContentSizeObservation() } + //-------------------------------------------------- // MARK: - UIView + //-------------------------------------------------- + public override var intrinsicContentSize: CGSize { let contentSize = self.contentSize //print(#function, contentSize) return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height) } - + + /// Overridden to deal with Appearance Changes public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { //print(type(of: self), #function) super.traitCollectionDidChange(previousTraitCollection) @@ -43,13 +54,9 @@ public final class SelfSizingCollectionView: UICollectionView { } } - public override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize { - let size = super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority) - //print(type(of: self), #function, targetSize, "->", size) - return size - } - + //-------------------------------------------------- // MARK: - Private + //-------------------------------------------------- private func setupContentSizeObservation() { // Observing the value of contentSize seems to be the only reliable way to get the contentSize after the collection view lays out its subviews. @@ -63,7 +70,10 @@ public final class SelfSizingCollectionView: UICollectionView { } extension UITraitCollection { - + + /// Used within SelfSizingCollectionView to determine if there is an appearance change + /// - Parameter traitCollection: TraitCollection to compare + /// - Returns: True/False based on the trailCollection passed in public func hasDifferentTextAppearance(comparedTo traitCollection: UITraitCollection?) -> Bool { var result = self.preferredContentSizeCategory != traitCollection?.preferredContentSizeCategory result = result || self.legibilityWeight != traitCollection?.legibilityWeight From 6840412f254433f7986df81aa2ec2b432e7cde70 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:36:59 -0500 Subject: [PATCH 08/17] added comments to the UIApplication extension Signed-off-by: Matt Bruce --- VDS/Extensions/UIApplication.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/VDS/Extensions/UIApplication.swift b/VDS/Extensions/UIApplication.swift index 52cf69d6..956bd3d5 100644 --- a/VDS/Extensions/UIApplication.swift +++ b/VDS/Extensions/UIApplication.swift @@ -10,6 +10,9 @@ import UIKit extension UIApplication { + /// Helper method to find the top most viewcontroller in the app + /// - Parameter controller: UIViewController to test against + /// - Returns: Found top most UIViewController public class func topViewController(controller: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? { if let nav = controller as? UINavigationController { From 54abcf8c8d20ffff587f90f8efcb45cf25726942 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:45:03 -0500 Subject: [PATCH 09/17] added comments to the UIColor extension Signed-off-by: Matt Bruce --- VDS/Extensions/UIColor.swift | 62 +++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/VDS/Extensions/UIColor.swift b/VDS/Extensions/UIColor.swift index 84100106..fa90f2cc 100644 --- a/VDS/Extensions/UIColor.swift +++ b/VDS/Extensions/UIColor.swift @@ -14,26 +14,45 @@ extension UIColor { // MARK: - Functions //-------------------------------------------------- - /// Convenience to get a grayscale UIColor where the same value is used for red, green, and blue. + /// Convenience to get a grayscale UIColor where the same value is used for red, green, and blue + /// - Parameters: + /// - rgb: red, green, and blue + /// - alpha: alphay + /// - Returns: UIColor that will be grayscale public class func grayscale(rgb: Int, alpha: CGFloat = 1.0) -> UIColor { let grayscale = CGFloat(rgb) / 255.0 return UIColor(red: grayscale, green: grayscale, blue: grayscale, alpha: alpha) } - /// Convenience to get a UIColor. + /// Convenience to get an 8-Bit UIColor based on RGB values + /// - Parameters: + /// - red: Value for Red + /// - green: Value for Green + /// - blue: Value for Blue + /// - alpha: Value for Alpha + /// - Returns: UIColor for the values above public class func color8Bits(red: Int, green: Int, blue: Int, alpha: CGFloat = 1.0) -> UIColor { return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: alpha) } - /// Convenience to get a UIColor. + /// Convenience to get an UIColor based on RGB values + /// - Parameters: + /// - red: Value for Red + /// - green: Value for Green + /// - blue: Value for Blue + /// - alpha: Value for Alpha + /// - Returns: UIColor for the values above public class func color8Bits(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat = 1.0) -> UIColor { return UIColor(red: red / 255.0, green: green / 255.0, blue: blue / 255.0, alpha: alpha) } /// Gets UIColor via an 8 digit hex string. + /// - Parameters: + /// - hex: HexCode string + /// - Returns: UIColor for the values above public class func getColorBy(hex: String) -> UIColor { var hexint: UInt64 = 0 @@ -48,7 +67,10 @@ extension UIColor { alpha: 1) } - /// Gets UIColor via an 8 digit hex string. The last two being the alpha channel. + /// Gets UIColor via an 8 digit hex string that includes transparency. + /// - Parameters: + /// - hex: HexCode string + /// - Returns: UIColor for the values above public class func getColorWithTransparencyBy(hex: String) -> UIColor { var hexint: UInt64 = 0 @@ -63,6 +85,9 @@ extension UIColor { alpha: (CGFloat(hexint & 0xFF)) / 255) } + /// Generates a gradient color for the color passed in + /// - Parameter color: Primary color for the gradient + /// - Returns: UIColor that is gradient public class func gradientColor(_ color: UIColor?) -> UIColor { var h: CGFloat = 0 @@ -77,7 +102,9 @@ extension UIColor { return .white } - /// - parameter color: The UIColor intended to retrieve its hex value. + /// Gets the hex code value for a UIColor + /// - Parameter color: UIColor intended to retrieve its hex value + /// - Returns: Hex Code public class func hexString(for color: UIColor) -> String? { guard let components = color.cgColor.components else { return nil } @@ -111,7 +138,8 @@ extension UIColor { return nil } - /// - parameter color: The UIColor intended to retrieve its hex value. + /// Gets the hex code value for the current UIColor + /// - Returns: Hex Code string public var hexString: String? { guard let components = cgColor.components else { return nil } @@ -145,6 +173,8 @@ extension UIColor { return nil } + /// Initialize a UIColor with a HexCode string + /// - Parameter hexString: HexCode string to convert to a UIColor public convenience init(hexString: String) { let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var int = UInt64() @@ -163,23 +193,3 @@ extension UIColor { self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) } } - -extension UIColor { - convenience init( - light lightModeColor: @escaping @autoclosure () -> UIColor, - dark darkModeColor: @escaping @autoclosure () -> UIColor - ) { - self.init { traitCollection in - switch traitCollection.userInterfaceStyle { - case .light: - return lightModeColor() - case .dark: - return darkModeColor() - case .unspecified: - return lightModeColor() - @unknown default: - return lightModeColor() - } - } - } -} From cc0c0fbfb2a0b7da4cca393a1b5b192b0b0d8409 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:47:24 -0500 Subject: [PATCH 10/17] added comments for the UIColor+VDSColor extension Signed-off-by: Matt Bruce --- VDS/Extensions/UIColor+VDSColor.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/VDS/Extensions/UIColor+VDSColor.swift b/VDS/Extensions/UIColor+VDSColor.swift index 2b76e403..ad05efc1 100644 --- a/VDS/Extensions/UIColor+VDSColor.swift +++ b/VDS/Extensions/UIColor+VDSColor.swift @@ -9,6 +9,8 @@ import Foundation import VDSColorTokens extension UIColor { + + /// Since VDSColorTokens is just a Class with Static Properties, this is an Enum for each property of that class for each of use within the VDS Library public enum VDSColor: String, CaseIterable { case paletteBlack case paletteWhite @@ -96,7 +98,7 @@ extension UIColor { case elementsLowcontrastOnlight case elementsLowcontrastOndark - // Map each color name to its corresponding UIColor object. + /// Map each color name to its corresponding UIColor object. public var uiColor: UIColor { do { let color = try VDSColorTokens.VDSColor.getTokenByString(tokenName: "VDSColor.\(rawValue)") @@ -107,7 +109,10 @@ extension UIColor { } } } - + + /// Helper method to see if a UIColor exists in the VDSColor enumeration + /// - Parameter color: UIColor needed to compare + /// - Returns: True if found, false in not found in VDSColor enumeration public static func isVDSColor(color: UIColor) -> Bool { guard let hex = color.hexString else { return false } let found = VDSColor.allCases.first{ $0.uiColor.hexString == hex } From d60315b74f7c132945a137824025c0569e4a0897 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:48:41 -0500 Subject: [PATCH 11/17] added comments to UIDevice extension Signed-off-by: Matt Bruce --- VDS/Extensions/UIDevice.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/VDS/Extensions/UIDevice.swift b/VDS/Extensions/UIDevice.swift index ccce58c9..b41e4407 100644 --- a/VDS/Extensions/UIDevice.swift +++ b/VDS/Extensions/UIDevice.swift @@ -9,6 +9,8 @@ import Foundation import UIKit extension UIDevice { + + /// Helper property to see if your current device running is an iPad or not public static var isIPad: Bool { UIDevice.current.userInterfaceIdiom == .pad } From 9a8f45a0027efd8feedfe6f92c26ad861fdb51c5 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 26 May 2023 16:50:59 -0500 Subject: [PATCH 12/17] added comments for UITapGestureRecognizer extension Signed-off-by: Matt Bruce --- VDS/Extensions/UITapGestureRecognizer.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/VDS/Extensions/UITapGestureRecognizer.swift b/VDS/Extensions/UITapGestureRecognizer.swift index 1993fdec..612a11ca 100644 --- a/VDS/Extensions/UITapGestureRecognizer.swift +++ b/VDS/Extensions/UITapGestureRecognizer.swift @@ -10,6 +10,11 @@ import UIKit extension UITapGestureRecognizer { + /// Determines if the touch event has a action attribute within the range given + /// - Parameters: + /// - label: UILabel in question + /// - targetRange: Range to look within + /// - Returns: Wether the range in the label has an action public func didTapActionInLabel(_ label: UILabel, inRange targetRange: NSRange) -> Bool { guard let attributedText = label.attributedText else { return false } From f99a3033d67e7b7c681a0173d4c2361644c9a0b3 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 May 2023 10:05:23 -0500 Subject: [PATCH 13/17] refactored TextLinkCaret spacer/name label attribute Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 4 ++++ .../Buttons/TextLinkCaret/TextLinkCaret.swift | 18 +++++++++--------- VDS/Extensions/NSAttributedString.swift | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 VDS/Extensions/NSAttributedString.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 2f938f80..bb1023cc 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -95,6 +95,7 @@ EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF4292D371F00998C17 /* ButtonBase.swift */; }; EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; }; EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.swift */; }; + EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFEB632A26473700C4C106 /* NSAttributedString.swift */; }; EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */; }; EAC9257D29119B5400091998 /* TextLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9257C29119B5400091998 /* TextLink.swift */; }; EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925822911B35300091998 /* TextLinkCaret.swift */; }; @@ -222,6 +223,7 @@ EAB5FEF4292D371F00998C17 /* ButtonBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonBase.swift; sourceTree = ""; }; EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = ""; }; EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = ""; }; + EABFEB632A26473700C4C106 /* NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = ""; }; EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = ""; }; EAC9257C29119B5400091998 /* TextLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLink.swift; sourceTree = ""; }; EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = ""; }; @@ -418,6 +420,7 @@ children = ( EAF7F0992899B17200B287F5 /* CATransaction.swift */, EA33622D2891EA3C0071C351 /* DispatchQueue+Once.swift */, + EABFEB632A26473700C4C106 /* NSAttributedString.swift */, EAB2376529E9952D00AABE9A /* UIApplication.swift */, EA3361A7288B23300071C351 /* UIColor.swift */, EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */, @@ -871,6 +874,7 @@ EAF7F0B1289B177F00B287F5 /* ColorLabelAttribute.swift in Sources */, EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */, EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */, + EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */, EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */, EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */, diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index a7dd808e..ed741896 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -28,7 +28,7 @@ open class TextLinkCaret: ButtonBase { TextStyle.boldBodyLarge } - private var imageAttribute: ImageSpaceLabelAttribute? + private var imageAttribute: CaretLabelAttribute? open override var attributes: [any LabelAttributeModel]? { guard let imageAttribute else { return nil } @@ -100,14 +100,14 @@ open class TextLinkCaret: ButtonBase { } open override func updateView() { - imageAttribute = ImageSpaceLabelAttribute(tintColor: textColor, position: iconPosition) + imageAttribute = CaretLabelAttribute(tintColor: textColor, position: iconPosition) super.updateView() } } extension TextLinkCaret { - struct ImageSpaceLabelAttribute: LabelAttributeModel { + struct CaretLabelAttribute: LabelAttributeModel { var id: UUID = .init() var location: Int = 0 var length: Int = 1 @@ -124,22 +124,22 @@ extension TextLinkCaret { func setAttribute(on attributedString: NSMutableAttributedString) { let imageAttr = ImageLabelAttribute(location: location, imageName: "\(position.rawValue)-caret-bold", frame: .init(x: 0, y: 0, width: caretSize.width, height: caretSize.height), tintColor: tintColor) - let spaceAttr = ImageLabelAttribute(location: 0, imageName: "info", frame: .init(x: 0, y: 0, width: spacerWidth, height: 5.0), tintColor: .clear) + let spacer = NSAttributedString.spacer(for: spacerWidth) - guard let image = try? imageAttr.getAttachment(), - let spacer = try? spaceAttr.getAttachment() else { return } + guard let image = try? imageAttr.getAttachment() else { return } if position == .right { - attributedString.append(NSAttributedString(attachment: spacer)) + attributedString.append(spacer) attributedString.append(NSAttributedString(attachment: image)) } else { attributedString.insert(NSAttributedString(attachment: image), at: 0) - attributedString.insert(NSAttributedString(attachment: spacer), at: 1) + attributedString.insert(spacer, at: 1) } } - func isEqual(_ equatable: ImageSpaceLabelAttribute) -> Bool { + func isEqual(_ equatable: CaretLabelAttribute) -> Bool { return id == equatable.id && range == equatable.range } + } } diff --git a/VDS/Extensions/NSAttributedString.swift b/VDS/Extensions/NSAttributedString.swift new file mode 100644 index 00000000..d51ec05a --- /dev/null +++ b/VDS/Extensions/NSAttributedString.swift @@ -0,0 +1,19 @@ +// +// NSAttributedString.swift +// VDS +// +// Created by Matt Bruce on 5/30/23. +// + +import Foundation +import UIKit + +extension NSAttributedString { + public static func spacer(for width: CGFloat) -> NSAttributedString { + let spacerImage = UIImage() + let spacerAttachment = NSTextAttachment() + spacerAttachment.bounds = .init(x: 0, y: 0, width: width, height: 1) + spacerAttachment.image = spacerImage + return NSAttributedString(attachment: spacerAttachment) + } +} From 8b9b83791a6fb8319f5cc229ddfc3493694e3f9e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 May 2023 11:22:20 -0500 Subject: [PATCH 14/17] CXTDT-419731 - spacing from 2px to 4px Signed-off-by: Matt Bruce --- VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index ed741896..594a51e5 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -113,7 +113,7 @@ extension TextLinkCaret { var length: Int = 1 var tintColor: UIColor var position: IconPosition - var spacerWidth: CGFloat = 2.0 + var spacerWidth: CGFloat = 4.0 var width: CGFloat { caretSize.width + spacerWidth } var caretSize: CGSize { Icon.Size.xsmall.dimensions } From 43e9642de65cfd776b03efe4964aa48e7419208d Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 30 May 2023 14:58:24 -0500 Subject: [PATCH 15/17] refactored to use new spacer extension Signed-off-by: Matt Bruce --- .../Label/Attributes/TooltipLabelAttribute.swift | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift index 5d5baa8d..b061d747 100644 --- a/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift +++ b/VDS/Components/Label/Attributes/TooltipLabelAttribute.swift @@ -50,24 +50,17 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable frame = CGRect(x: 0, y: -1, width: size.value.dimensions.width, height: size.value.dimensions.height) } } - - //create the frame in which to hold the icon - let spacerframe = CGRect(x: 0, y: 0, width: VDSLayout.Spacing.space1X.value, height: size.value.dimensions.height) - + //create the image icon and match the color of the text let tooltipAttribute = ImageLabelAttribute(location: location, imageName: "info", frame: frame, tintColor: imageTintColor) - let spacerAttribute = ImageLabelAttribute(location: location, - imageName: "info", - frame: spacerframe, - tintColor: .clear) + let spacer = NSAttributedString.spacer(for: VDSLayout.Spacing.space1X.value) - guard let tooltip = try? tooltipAttribute.getAttachment(), - let spacer = try? spacerAttribute.getAttachment() else { return } - attributedString.append(NSAttributedString(attachment: spacer)) + guard let tooltip = try? tooltipAttribute.getAttachment() else { return } + attributedString.append(spacer) attributedString.append(NSAttributedString(attachment: tooltip)) addHandler(on: attributedString) } From 171cf45ce6218e5dceb71b78a6d3e87e5e488833 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 31 May 2023 13:57:46 -0500 Subject: [PATCH 16/17] added release notes Signed-off-by: Matt Bruce --- VDS/SupportingFiles/ReleaseNotes.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 64ba426f..75bee841 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,3 +1,7 @@ +1.0.19 +======= +- CXTDT-419731 - TextLinkCaret - Spacing issue + 1.0.18 ======= - CXTDT-412383 - Badge Corner Radius / Color issue (resolved in previous build) From ff5dbc2537ec7045e5a9a5523f652a55ac48e5a6 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 31 May 2023 13:59:49 -0500 Subject: [PATCH 17/17] updated version to 19 Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index bb1023cc..8df5a950 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -1074,7 +1074,7 @@ buildSettings = { BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 19; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1107,7 +1107,7 @@ buildSettings = { BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 19; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1;