Merge branch 'release/1.0.19' into 'develop'
build for bugfix See merge request BPHV_MIPS/vds_ios!74
This commit is contained in:
commit
495051f04b
@ -95,6 +95,7 @@
|
|||||||
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF4292D371F00998C17 /* ButtonBase.swift */; };
|
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF4292D371F00998C17 /* ButtonBase.swift */; };
|
||||||
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; };
|
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */; };
|
||||||
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FF0029424ACB00998C17 /* UIControl.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 */; };
|
EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */; };
|
||||||
EAC9257D29119B5400091998 /* TextLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9257C29119B5400091998 /* TextLink.swift */; };
|
EAC9257D29119B5400091998 /* TextLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9257C29119B5400091998 /* TextLink.swift */; };
|
||||||
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925822911B35300091998 /* TextLinkCaret.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 = "<group>"; };
|
EAB5FEF4292D371F00998C17 /* ButtonBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonBase.swift; sourceTree = "<group>"; };
|
||||||
EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = "<group>"; };
|
EAB5FEF729393A7200998C17 /* ButtonGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupConstants.swift; sourceTree = "<group>"; };
|
||||||
EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = "<group>"; };
|
EAB5FF0029424ACB00998C17 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = "<group>"; };
|
||||||
|
EABFEB632A26473700C4C106 /* NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = "<group>"; };
|
||||||
EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = "<group>"; };
|
EAC846F2294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||||
EAC9257C29119B5400091998 /* TextLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLink.swift; sourceTree = "<group>"; };
|
EAC9257C29119B5400091998 /* TextLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLink.swift; sourceTree = "<group>"; };
|
||||||
EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = "<group>"; };
|
EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = "<group>"; };
|
||||||
@ -418,6 +420,7 @@
|
|||||||
children = (
|
children = (
|
||||||
EAF7F0992899B17200B287F5 /* CATransaction.swift */,
|
EAF7F0992899B17200B287F5 /* CATransaction.swift */,
|
||||||
EA33622D2891EA3C0071C351 /* DispatchQueue+Once.swift */,
|
EA33622D2891EA3C0071C351 /* DispatchQueue+Once.swift */,
|
||||||
|
EABFEB632A26473700C4C106 /* NSAttributedString.swift */,
|
||||||
EAB2376529E9952D00AABE9A /* UIApplication.swift */,
|
EAB2376529E9952D00AABE9A /* UIApplication.swift */,
|
||||||
EA3361A7288B23300071C351 /* UIColor.swift */,
|
EA3361A7288B23300071C351 /* UIColor.swift */,
|
||||||
EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */,
|
EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */,
|
||||||
@ -871,6 +874,7 @@
|
|||||||
EAF7F0B1289B177F00B287F5 /* ColorLabelAttribute.swift in Sources */,
|
EAF7F0B1289B177F00B287F5 /* ColorLabelAttribute.swift in Sources */,
|
||||||
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */,
|
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */,
|
||||||
EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */,
|
EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */,
|
||||||
|
EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */,
|
||||||
EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */,
|
EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */,
|
||||||
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */,
|
EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */,
|
||||||
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */,
|
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */,
|
||||||
@ -1070,7 +1074,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 18;
|
CURRENT_PROJECT_VERSION = 19;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
@ -1103,7 +1107,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 18;
|
CURRENT_PROJECT_VERSION = 19;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
|||||||
@ -8,6 +8,8 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
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 class BundleManager {
|
||||||
public static var shared = 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) {
|
public static func register(_ path: String) {
|
||||||
if !shared.paths.contains(where: {$0 == path}) {
|
if !shared.paths.contains(where: {$0 == path}) {
|
||||||
if let bundle = Bundle(path: path) {
|
if let bundle = Bundle(path: path) {
|
||||||
@ -40,6 +44,9 @@ public class BundleManager {
|
|||||||
|
|
||||||
extension 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? {
|
public func image(for name: String) -> UIImage? {
|
||||||
var foundImage: UIImage?
|
var foundImage: UIImage?
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,9 @@ public typealias ObjectColorable = Colorable & Initable & ObjectWithable
|
|||||||
/// config.darkColor = .white
|
/// config.darkColor = .white
|
||||||
///
|
///
|
||||||
/// let textColor = config.getColor(model) //returns .black
|
/// 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 {
|
open class SurfaceColorConfiguration: ObjectColorable {
|
||||||
public typealias ObjectType = Surfaceable
|
public typealias ObjectType = Surfaceable
|
||||||
public var lightColor: UIColor = .clear
|
public var lightColor: UIColor = .clear
|
||||||
@ -29,15 +31,27 @@ open class SurfaceColorConfiguration: ObjectColorable {
|
|||||||
|
|
||||||
required public init(){}
|
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) {
|
public init(_ lightColor: UIColor, _ darkColor: UIColor) {
|
||||||
self.lightColor = lightColor
|
self.lightColor = lightColor
|
||||||
self.darkColor = darkColor
|
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 {
|
public func getColor(_ surface: Surface) -> UIColor {
|
||||||
return surface == .light ? lightColor : darkColor
|
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 {
|
public func getColor(_ object: any ObjectType) -> UIColor {
|
||||||
return getColor(object.surface)
|
return getColor(object.surface)
|
||||||
}
|
}
|
||||||
@ -57,16 +71,30 @@ public protocol KeyColorConfigurable: ObjectColorable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension KeyColorConfigurable {
|
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) {
|
public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forKey key: KeyType) {
|
||||||
keyColors.append(.init(key: key, surfaceConfig: .init(lightColor, darkColor)))
|
keyColors.append(.init(key: key, surfaceConfig: .init(lightColor, darkColor)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Removes all keyColors
|
||||||
public func reset() {
|
public func reset() {
|
||||||
keyColors.removeAll()
|
keyColors.removeAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension KeyColorConfigurable where ObjectType: Surfaceable {
|
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 {
|
public func getColor(for object: ObjectType, with key: KeyType) -> UIColor {
|
||||||
if let keyColor = keyColors.first(where: {$0.key == key }) {
|
if let keyColor = keyColors.first(where: {$0.key == key }) {
|
||||||
return keyColor.surfaceConfig.getColor(object)
|
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 class ControlColorConfiguration: KeyColorConfigurable {
|
||||||
public typealias KeyType = UIControl.State
|
public typealias KeyType = UIControl.State
|
||||||
public typealias ObjectType = Surfaceable & UIControl
|
public typealias ObjectType = Surfaceable & UIControl
|
||||||
@ -84,10 +114,19 @@ public class ControlColorConfiguration: KeyColorConfigurable {
|
|||||||
private var lastKeyColor: KeyColorConfiguration<KeyType>?
|
private var lastKeyColor: KeyColorConfiguration<KeyType>?
|
||||||
public required init() { }
|
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) {
|
public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forState state: KeyType) {
|
||||||
setSurfaceColors(lightColor, darkColor, forKey: state)
|
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 {
|
public func getColor(_ object: any ObjectType) -> UIColor {
|
||||||
let state = object.state
|
let state = object.state
|
||||||
let surface = object.surface
|
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 class ViewColorConfiguration: KeyColorConfigurable {
|
||||||
public typealias KeyType = Bool
|
public typealias KeyType = Bool
|
||||||
public typealias ObjectType = Surfaceable & Disabling
|
public typealias ObjectType = Surfaceable & Disabling
|
||||||
@ -122,10 +162,18 @@ public class ViewColorConfiguration: KeyColorConfigurable {
|
|||||||
|
|
||||||
public required init() { }
|
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) {
|
public func setSurfaceColors(_ lightColor: UIColor, _ darkColor: UIColor, forDisabled disabled: KeyType) {
|
||||||
setSurfaceColors(lightColor, darkColor, forKey: disabled)
|
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 {
|
public func getColor(_ object: ObjectType) -> UIColor {
|
||||||
if let keyColor = keyColors.first(where: {$0.key == object.disabled }) {
|
if let keyColor = keyColors.first(where: {$0.key == object.disabled }) {
|
||||||
return keyColor.surfaceConfig.getColor(object)
|
return keyColor.surfaceConfig.getColor(object)
|
||||||
@ -154,11 +202,17 @@ public class KeyedColorConfiguration<ObjectType: Surfaceable, KeyType: Equatable
|
|||||||
self.keyPath = keyPath
|
self.keyPath = keyPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds the KeyColorConfiguration for the Object passed in.
|
||||||
|
/// - Parameter object: Object should be of Surfaceable
|
||||||
|
/// - Returns: KeyType for the Object passed in
|
||||||
public func getKeyValue(_ object: ObjectType) -> KeyType? {
|
public func getKeyValue(_ object: ObjectType) -> KeyType? {
|
||||||
guard let keyPath else { fatalError("keyPath must not be empty, make sure you initialize this class using init(keyPath: \\Object.property) method") }
|
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]
|
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 {
|
public func getColor(_ object: ObjectType) -> UIColor {
|
||||||
if let key = getKeyValue(object), let keyColor = keyColors.first(where: {$0.key == key }) {
|
if let key = getKeyValue(object), let keyColor = keyColors.first(where: {$0.key == key }) {
|
||||||
return keyColor.surfaceConfig.getColor(object)
|
return keyColor.surfaceConfig.getColor(object)
|
||||||
|
|||||||
@ -15,7 +15,11 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Combine Properties
|
// MARK: - Combine Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Set of Subscribers for any Publishers for this Control
|
||||||
public var subscribers = Set<AnyCancellable>()
|
public var subscribers = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
/// Sets the primary Subscriber used for the TouchUpInside
|
||||||
public var onClickSubscriber: AnyCancellable? {
|
public var onClickSubscriber: AnyCancellable? {
|
||||||
willSet {
|
willSet {
|
||||||
if let onClickSubscriber {
|
if let onClickSubscriber {
|
||||||
@ -29,29 +33,37 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
private var initialSetupPerformed = false
|
private var initialSetupPerformed = false
|
||||||
|
|
||||||
|
/// Key of whether or not updateView() is called in setNeedsUpdate()
|
||||||
open var shouldUpdateView: Bool = true
|
open var shouldUpdateView: Bool = true
|
||||||
|
|
||||||
|
/// Dictionary for keeping information for this Control use only Primitives
|
||||||
open var userInfo = [String: Primitive]()
|
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() } }
|
open var surface: Surface = .light { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
|
/// Control is disabled or not
|
||||||
open var disabled: Bool = false { didSet { isEnabled = !disabled } }
|
open var disabled: Bool = false { didSet { isEnabled = !disabled } }
|
||||||
|
|
||||||
|
/// Override for isSelected to handle setNeedsUpdate() on changes
|
||||||
open override var isSelected: Bool { didSet { setNeedsUpdate() } }
|
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
|
public var touchUpInsideCount: Int = 0
|
||||||
|
|
||||||
var isHighlightAnimating = false
|
var isHighlightAnimating = false
|
||||||
|
|
||||||
|
/// Override to deal with only calling setNeedsUpdate() if needed
|
||||||
open override var isHighlighted: Bool {
|
open override var isHighlighted: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
if isHighlightAnimating == false && touchUpInsideCount > 0 {
|
if isHighlightAnimating == false && touchUpInsideCount > 0 {
|
||||||
isHighlightAnimating = true
|
isHighlightAnimating = true
|
||||||
UIView.animate(withDuration: 0.1, animations: { [weak self] in
|
UIView.animate(withDuration: 0.1, animations: { [weak self] in
|
||||||
self?.updateView()
|
self?.setNeedsUpdate()
|
||||||
}) { [weak self] _ in
|
}) { [weak self] _ in
|
||||||
//you update the view since this is typically a quick change
|
//you update the view since this is typically a quick change
|
||||||
UIView.animate(withDuration: 0.1, animations: { [weak self] in
|
UIView.animate(withDuration: 0.1, animations: { [weak self] in
|
||||||
self?.updateView()
|
self?.setNeedsUpdate()
|
||||||
self?.isHighlightAnimating = false
|
self?.isHighlightAnimating = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -59,6 +71,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Override to deal with setNeedsUpdate()
|
||||||
open override var isEnabled: Bool {
|
open override var isEnabled: Bool {
|
||||||
get { !disabled }
|
get { !disabled }
|
||||||
set {
|
set {
|
||||||
@ -92,6 +105,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
|
|||||||
// MARK: - Setup
|
// MARK: - Setup
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Executed on initialization for this Control
|
||||||
open func initialSetup() {
|
open func initialSetup() {
|
||||||
if !initialSetupPerformed {
|
if !initialSetupPerformed {
|
||||||
initialSetupPerformed = true
|
initialSetupPerformed = true
|
||||||
@ -100,6 +114,8 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Override to deal with sending actions for accessibility
|
||||||
|
/// - Returns: Based on whether the userInteraction is enabled
|
||||||
override open func accessibilityActivate() -> Bool {
|
override open func accessibilityActivate() -> Bool {
|
||||||
// Hold state in case User wanted isAnimated to remain off.
|
// Hold state in case User wanted isAnimated to remain off.
|
||||||
guard isUserInteractionEnabled else { return false }
|
guard isUserInteractionEnabled else { return false }
|
||||||
@ -110,22 +126,25 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Overrides
|
// MARK: - Overrides
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Update this view based off of property changes
|
||||||
open func updateView() {
|
open func updateView() {
|
||||||
updateAccessibilityLabel()
|
updateAccessibilityLabel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to update any Accessibility properties
|
||||||
open func updateAccessibilityLabel() {
|
open func updateAccessibilityLabel() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resets to the Controls default values
|
||||||
open func reset() {
|
open func reset() {
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
surface = .light
|
surface = .light
|
||||||
disabled = false
|
disabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - ViewProtocol
|
/// Will be called only once and should be overridden in subclasses to setup UI or defaults
|
||||||
/// Will be called only once.
|
|
||||||
open func setup() {
|
open func setup() {
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|||||||
@ -9,13 +9,17 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
|
/// Base Class used for any Grouped Form Control of a Selector Type
|
||||||
open class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
|
open class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Public Properties
|
// MARK: - Public Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Array of the HandlerType registered
|
||||||
public var selectorViews: [HandlerType] = []
|
public var selectorViews: [HandlerType] = []
|
||||||
|
|
||||||
|
/// The primary subscriber for onChange or the UIControl valueChanged event.
|
||||||
public var onChangeSubscriber: AnyCancellable? {
|
public var onChangeSubscriber: AnyCancellable? {
|
||||||
willSet {
|
willSet {
|
||||||
if let onChangeSubscriber {
|
if let onChangeSubscriber {
|
||||||
@ -27,6 +31,8 @@ open class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Overrides
|
// MARK: - Overrides
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Override to update the child SelectorViews disabled property for this group
|
||||||
override public var disabled: Bool {
|
override public var disabled: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
selectorViews.forEach { handler in
|
selectorViews.forEach { handler in
|
||||||
@ -35,6 +41,7 @@ open class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Override to update the child SelectorViews surface property for this group
|
||||||
override public var surface: Surface {
|
override public var surface: Surface {
|
||||||
didSet {
|
didSet {
|
||||||
selectorViews.forEach { handler in
|
selectorViews.forEach { handler in
|
||||||
@ -43,16 +50,20 @@ open class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handler for the Group to override on a select event
|
||||||
|
/// - Parameter selectedControl: Selected Control the user interacted
|
||||||
open func didSelect(_ selectedControl: HandlerType) {
|
open func didSelect(_ selectedControl: HandlerType) {
|
||||||
fatalError("Must override didSelect")
|
fatalError("Must override didSelect")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper method to execute the valueChanged event
|
||||||
public func valueChanged() {
|
public func valueChanged() {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in
|
||||||
self?.sendActions(for: .valueChanged)
|
self?.sendActions(for: .valueChanged)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Override to update the child SelectorViews reset method for this group
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
selectorViews.forEach{ $0.reset() }
|
selectorViews.forEach{ $0.reset() }
|
||||||
@ -60,6 +71,8 @@ open class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class SelectorGroupSelectedHandlerBase<HandlerType: Control>: SelectorGroupHandlerBase<HandlerType>{
|
open class SelectorGroupSelectedHandlerBase<HandlerType: Control>: SelectorGroupHandlerBase<HandlerType>{
|
||||||
|
|
||||||
|
/// Current Selected Control for this group
|
||||||
public var selectedHandler: HandlerType? {
|
public var selectedHandler: HandlerType? {
|
||||||
return selectorViews.filter { $0.isSelected == true }.first
|
return selectorViews.filter { $0.isSelected == true }.first
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,12 +9,19 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@objc(VDSSelfSizingCollectionView)
|
@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 {
|
public final class SelfSizingCollectionView: UICollectionView {
|
||||||
|
|
||||||
private var contentSizeObservation: NSKeyValueObservation?
|
private var contentSizeObservation: NSKeyValueObservation?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Initializer
|
||||||
|
/// - Parameters:
|
||||||
|
/// - frame: Frame needed
|
||||||
|
/// - layout: Layout used for this CollectionView
|
||||||
public override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
|
public override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
|
||||||
super.init(frame: frame, collectionViewLayout: layout)
|
super.init(frame: frame, collectionViewLayout: layout)
|
||||||
self.setupContentSizeObservation()
|
self.setupContentSizeObservation()
|
||||||
@ -25,7 +32,10 @@ public final class SelfSizingCollectionView: UICollectionView {
|
|||||||
self.setupContentSizeObservation()
|
self.setupContentSizeObservation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - UIView
|
// MARK: - UIView
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
public override var intrinsicContentSize: CGSize {
|
public override var intrinsicContentSize: CGSize {
|
||||||
let contentSize = self.contentSize
|
let contentSize = self.contentSize
|
||||||
@ -33,6 +43,7 @@ public final class SelfSizingCollectionView: UICollectionView {
|
|||||||
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
|
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Overridden to deal with Appearance Changes
|
||||||
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||||
//print(type(of: self), #function)
|
//print(type(of: self), #function)
|
||||||
super.traitCollectionDidChange(previousTraitCollection)
|
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
|
// MARK: - Private
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
private func setupContentSizeObservation() {
|
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.
|
// Observing the value of contentSize seems to be the only reliable way to get the contentSize after the collection view lays out its subviews.
|
||||||
@ -64,6 +71,9 @@ public final class SelfSizingCollectionView: UICollectionView {
|
|||||||
|
|
||||||
extension UITraitCollection {
|
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 {
|
public func hasDifferentTextAppearance(comparedTo traitCollection: UITraitCollection?) -> Bool {
|
||||||
var result = self.preferredContentSizeCategory != traitCollection?.preferredContentSizeCategory
|
var result = self.preferredContentSizeCategory != traitCollection?.preferredContentSizeCategory
|
||||||
result = result || self.legibilityWeight != traitCollection?.legibilityWeight
|
result = result || self.legibilityWeight != traitCollection?.legibilityWeight
|
||||||
|
|||||||
@ -23,14 +23,19 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
private var initialSetupPerformed = false
|
private var initialSetupPerformed = false
|
||||||
|
|
||||||
|
/// Key of whether or not updateView() is called in setNeedsUpdate()
|
||||||
open var shouldUpdateView: Bool = true
|
open var shouldUpdateView: Bool = true
|
||||||
|
|
||||||
|
/// Dictionary for keeping information for this Control use only Primitives
|
||||||
open var userInfo = [String: Primitive]()
|
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 } }
|
open var disabled: Bool = false { didSet { isEnabled = !disabled } }
|
||||||
|
|
||||||
|
/// Override to deal with setNeedsUpdate()
|
||||||
open var isEnabled: Bool {
|
open var isEnabled: Bool {
|
||||||
get { !disabled }
|
get { !disabled }
|
||||||
set {
|
set {
|
||||||
@ -64,6 +69,7 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable {
|
|||||||
// MARK: - Setup
|
// MARK: - Setup
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Executed on initialization for this View
|
||||||
open func initialSetup() {
|
open func initialSetup() {
|
||||||
if !initialSetupPerformed {
|
if !initialSetupPerformed {
|
||||||
initialSetupPerformed = true
|
initialSetupPerformed = true
|
||||||
@ -75,22 +81,25 @@ open class View: UIView, Handlerable, ViewProtocol, Resettable, UserInfoable {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Overrides
|
// MARK: - Overrides
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Update this view based off of property changes
|
||||||
open func updateView() {
|
open func updateView() {
|
||||||
updateAccessibilityLabel()
|
updateAccessibilityLabel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to update any Accessibility properties
|
||||||
open func updateAccessibilityLabel() {
|
open func updateAccessibilityLabel() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resets to the Views default values
|
||||||
open func reset() {
|
open func reset() {
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
surface = .light
|
surface = .light
|
||||||
disabled = false
|
disabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - ViewProtocol
|
/// Will be called only once and should be overridden in subclasses to setup UI or defaults
|
||||||
/// Will be called only once.
|
|
||||||
open func setup() {
|
open func setup() {
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|||||||
@ -28,7 +28,7 @@ open class TextLinkCaret: ButtonBase {
|
|||||||
TextStyle.boldBodyLarge
|
TextStyle.boldBodyLarge
|
||||||
}
|
}
|
||||||
|
|
||||||
private var imageAttribute: ImageSpaceLabelAttribute?
|
private var imageAttribute: CaretLabelAttribute?
|
||||||
|
|
||||||
open override var attributes: [any LabelAttributeModel]? {
|
open override var attributes: [any LabelAttributeModel]? {
|
||||||
guard let imageAttribute else { return nil }
|
guard let imageAttribute else { return nil }
|
||||||
@ -100,20 +100,20 @@ open class TextLinkCaret: ButtonBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
imageAttribute = ImageSpaceLabelAttribute(tintColor: textColor, position: iconPosition)
|
imageAttribute = CaretLabelAttribute(tintColor: textColor, position: iconPosition)
|
||||||
super.updateView()
|
super.updateView()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TextLinkCaret {
|
extension TextLinkCaret {
|
||||||
struct ImageSpaceLabelAttribute: LabelAttributeModel {
|
struct CaretLabelAttribute: LabelAttributeModel {
|
||||||
var id: UUID = .init()
|
var id: UUID = .init()
|
||||||
var location: Int = 0
|
var location: Int = 0
|
||||||
var length: Int = 1
|
var length: Int = 1
|
||||||
var tintColor: UIColor
|
var tintColor: UIColor
|
||||||
var position: IconPosition
|
var position: IconPosition
|
||||||
var spacerWidth: CGFloat = 2.0
|
var spacerWidth: CGFloat = 4.0
|
||||||
var width: CGFloat { caretSize.width + spacerWidth }
|
var width: CGFloat { caretSize.width + spacerWidth }
|
||||||
var caretSize: CGSize { Icon.Size.xsmall.dimensions }
|
var caretSize: CGSize { Icon.Size.xsmall.dimensions }
|
||||||
|
|
||||||
@ -124,22 +124,22 @@ extension TextLinkCaret {
|
|||||||
|
|
||||||
func setAttribute(on attributedString: NSMutableAttributedString) {
|
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 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(),
|
guard let image = try? imageAttr.getAttachment() else { return }
|
||||||
let spacer = try? spaceAttr.getAttachment() else { return }
|
|
||||||
|
|
||||||
if position == .right {
|
if position == .right {
|
||||||
attributedString.append(NSAttributedString(attachment: spacer))
|
attributedString.append(spacer)
|
||||||
attributedString.append(NSAttributedString(attachment: image))
|
attributedString.append(NSAttributedString(attachment: image))
|
||||||
} else {
|
} else {
|
||||||
attributedString.insert(NSAttributedString(attachment: image), at: 0)
|
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
|
return id == equatable.id && range == equatable.range
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,23 +51,16 @@ public class TooltipLabelAttribute: ActionLabelAttributeModel, TooltipLaunchable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//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
|
//create the image icon and match the color of the text
|
||||||
let tooltipAttribute = ImageLabelAttribute(location: location,
|
let tooltipAttribute = ImageLabelAttribute(location: location,
|
||||||
imageName: "info",
|
imageName: "info",
|
||||||
frame: frame,
|
frame: frame,
|
||||||
tintColor: imageTintColor)
|
tintColor: imageTintColor)
|
||||||
|
|
||||||
let spacerAttribute = ImageLabelAttribute(location: location,
|
let spacer = NSAttributedString.spacer(for: VDSLayout.Spacing.space1X.value)
|
||||||
imageName: "info",
|
|
||||||
frame: spacerframe,
|
|
||||||
tintColor: .clear)
|
|
||||||
|
|
||||||
guard let tooltip = try? tooltipAttribute.getAttachment(),
|
guard let tooltip = try? tooltipAttribute.getAttachment() else { return }
|
||||||
let spacer = try? spacerAttribute.getAttachment() else { return }
|
attributedString.append(spacer)
|
||||||
attributedString.append(NSAttributedString(attachment: spacer))
|
|
||||||
attributedString.append(NSAttributedString(attachment: tooltip))
|
attributedString.append(NSAttributedString(attachment: tooltip))
|
||||||
addHandler(on: attributedString)
|
addHandler(on: attributedString)
|
||||||
}
|
}
|
||||||
|
|||||||
19
VDS/Extensions/NSAttributedString.swift
Normal file
19
VDS/Extensions/NSAttributedString.swift
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,6 +10,9 @@ import UIKit
|
|||||||
|
|
||||||
extension UIApplication {
|
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? {
|
public class func topViewController(controller: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? {
|
||||||
|
|
||||||
if let nav = controller as? UINavigationController {
|
if let nav = controller as? UINavigationController {
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import Foundation
|
|||||||
import VDSColorTokens
|
import VDSColorTokens
|
||||||
|
|
||||||
extension UIColor {
|
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 {
|
public enum VDSColor: String, CaseIterable {
|
||||||
case paletteBlack
|
case paletteBlack
|
||||||
case paletteWhite
|
case paletteWhite
|
||||||
@ -96,7 +98,7 @@ extension UIColor {
|
|||||||
case elementsLowcontrastOnlight
|
case elementsLowcontrastOnlight
|
||||||
case elementsLowcontrastOndark
|
case elementsLowcontrastOndark
|
||||||
|
|
||||||
// Map each color name to its corresponding UIColor object.
|
/// Map each color name to its corresponding UIColor object.
|
||||||
public var uiColor: UIColor {
|
public var uiColor: UIColor {
|
||||||
do {
|
do {
|
||||||
let color = try VDSColorTokens.VDSColor.getTokenByString(tokenName: "VDSColor.\(rawValue)")
|
let color = try VDSColorTokens.VDSColor.getTokenByString(tokenName: "VDSColor.\(rawValue)")
|
||||||
@ -108,6 +110,9 @@ 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 {
|
public static func isVDSColor(color: UIColor) -> Bool {
|
||||||
guard let hex = color.hexString else { return false }
|
guard let hex = color.hexString else { return false }
|
||||||
let found = VDSColor.allCases.first{ $0.uiColor.hexString == hex }
|
let found = VDSColor.allCases.first{ $0.uiColor.hexString == hex }
|
||||||
|
|||||||
@ -14,26 +14,45 @@ extension UIColor {
|
|||||||
// MARK: - Functions
|
// 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 {
|
public class func grayscale(rgb: Int, alpha: CGFloat = 1.0) -> UIColor {
|
||||||
|
|
||||||
let grayscale = CGFloat(rgb) / 255.0
|
let grayscale = CGFloat(rgb) / 255.0
|
||||||
return UIColor(red: grayscale, green: grayscale, blue: grayscale, alpha: alpha)
|
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 {
|
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)
|
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 {
|
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)
|
return UIColor(red: red / 255.0, green: green / 255.0, blue: blue / 255.0, alpha: alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets UIColor via an 8 digit hex string.
|
/// 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 {
|
public class func getColorBy(hex: String) -> UIColor {
|
||||||
|
|
||||||
var hexint: UInt64 = 0
|
var hexint: UInt64 = 0
|
||||||
@ -48,7 +67,10 @@ extension UIColor {
|
|||||||
alpha: 1)
|
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 {
|
public class func getColorWithTransparencyBy(hex: String) -> UIColor {
|
||||||
|
|
||||||
var hexint: UInt64 = 0
|
var hexint: UInt64 = 0
|
||||||
@ -63,6 +85,9 @@ extension UIColor {
|
|||||||
alpha: (CGFloat(hexint & 0xFF)) / 255)
|
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 {
|
public class func gradientColor(_ color: UIColor?) -> UIColor {
|
||||||
|
|
||||||
var h: CGFloat = 0
|
var h: CGFloat = 0
|
||||||
@ -77,7 +102,9 @@ extension UIColor {
|
|||||||
return .white
|
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? {
|
public class func hexString(for color: UIColor) -> String? {
|
||||||
|
|
||||||
guard let components = color.cgColor.components else { return nil }
|
guard let components = color.cgColor.components else { return nil }
|
||||||
@ -111,7 +138,8 @@ extension UIColor {
|
|||||||
return nil
|
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? {
|
public var hexString: String? {
|
||||||
|
|
||||||
guard let components = cgColor.components else { return nil }
|
guard let components = cgColor.components else { return nil }
|
||||||
@ -145,6 +173,8 @@ extension UIColor {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize a UIColor with a HexCode string
|
||||||
|
/// - Parameter hexString: HexCode string to convert to a UIColor
|
||||||
public convenience init(hexString: String) {
|
public convenience init(hexString: String) {
|
||||||
let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
||||||
var int = UInt64()
|
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)
|
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
extension UIDevice {
|
extension UIDevice {
|
||||||
|
|
||||||
|
/// Helper property to see if your current device running is an iPad or not
|
||||||
public static var isIPad: Bool {
|
public static var isIPad: Bool {
|
||||||
UIDevice.current.userInterfaceIdiom == .pad
|
UIDevice.current.userInterfaceIdiom == .pad
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,11 @@ import UIKit
|
|||||||
|
|
||||||
extension UITapGestureRecognizer {
|
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 {
|
public func didTapActionInLabel(_ label: UILabel, inRange targetRange: NSRange) -> Bool {
|
||||||
|
|
||||||
guard let attributedText = label.attributedText else { return false }
|
guard let attributedText = label.attributedText else { return false }
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
1.0.19
|
||||||
|
=======
|
||||||
|
- CXTDT-419731 - TextLinkCaret - Spacing issue
|
||||||
|
|
||||||
1.0.18
|
1.0.18
|
||||||
=======
|
=======
|
||||||
- CXTDT-412383 - Badge Corner Radius / Color issue (resolved in previous build)
|
- CXTDT-412383 - Badge Corner Radius / Color issue (resolved in previous build)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user