From fe4e9b7a2bd99f31370cc03e98f30abdaffa32a2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 May 2023 15:27:50 -0500 Subject: [PATCH 1/8] initial cut for ButtonICon Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 12 ++ .../Icon/ButtonIcon/ButtonIcon.swift | 116 ++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 VDS/Components/Icon/ButtonIcon/ButtonIcon.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 615218d1..c5673da2 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E30522950DDA60082B959 /* TitleLockup.swift */; }; EA5E3058295105A40082B959 /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E3057295105A40082B959 /* Tilelet.swift */; }; EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305929510F8B0082B959 /* EnumSubset.swift */; }; + EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */; }; EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; }; EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; }; EA89201328B568D8006B9984 /* RadioBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBox.swift */; }; @@ -167,6 +168,7 @@ EA5E30522950DDA60082B959 /* TitleLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockup.swift; sourceTree = ""; }; EA5E3057295105A40082B959 /* Tilelet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilelet.swift; sourceTree = ""; }; EA5E305929510F8B0082B959 /* EnumSubset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumSubset.swift; sourceTree = ""; }; + EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = ""; }; EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = ""; }; EA89200528B526D6006B9984 /* CheckboxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxGroup.swift; sourceTree = ""; }; EA89201228B568D8006B9984 /* RadioBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBox.swift; sourceTree = ""; }; @@ -540,6 +542,14 @@ path = Tilelet; sourceTree = ""; }; + EA81410C2A0E8E52004F60D2 /* ButtonIcon */ = { + isa = PBXGroup; + children = ( + EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */, + ); + path = ButtonIcon; + sourceTree = ""; + }; EA89200B28B530F0006B9984 /* RadioBox */ = { isa = PBXGroup; children = ( @@ -552,6 +562,7 @@ EA985BF3296C609E00F2FF2E /* Icon */ = { isa = PBXGroup; children = ( + EA81410C2A0E8E52004F60D2 /* ButtonIcon */, EA985BF4296C60C000F2FF2E /* Icon.swift */, EA985BF8296C710100F2FF2E /* IconColor.swift */, EA985BF6296C665E00F2FF2E /* IconName.swift */, @@ -855,6 +866,7 @@ EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */, EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */, EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */, + EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */, EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */, EA336171288B19200071C351 /* VDS.docc in Sources */, EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */, diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift new file mode 100644 index 00000000..1d381df6 --- /dev/null +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -0,0 +1,116 @@ +// +// ButtonIcon.swift +// VDS +// +// Created by Matt Bruce on 5/12/23. +// + +import Foundation +import UIKit + +@objc(VDSButtonIcon) +open class ButtonIcon: Control { + //-------------------------------------------------- + // MARK: - Models + //-------------------------------------------------- + //-------------------------------------------------- + // MARK: - Enums + //-------------------------------------------------- + public enum Kind: String, CaseIterable { + case ghost, lowContrast, highContrast + } + + public enum SurfaceType: String, CaseIterable { + case colorFill, media + } + + public enum Size: String, EnumSubset { + case large + case small + + public var defaultValue: Icon.Size { .large } + } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var widthConstraint: NSLayoutConstraint? + private var heightConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + open var icon = Icon() + + open var iconName: Icon.Name? { didSet { setNeedsUpdate() } } + + open var kind: Kind = .ghost { didSet { setNeedsUpdate() } } + + open var surfaceType: SurfaceType = .colorFill { didSet { setNeedsUpdate() } } + + open var size: Size = .large { didSet { setNeedsUpdate() } } + + open var floating: Bool = false { didSet { setNeedsUpdate() } } + + open var hideBorder: Bool = true { didSet { setNeedsUpdate() } } + + open var iconOffset: CGPoint? { didSet { setNeedsUpdate() } } + + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + open override func setup() { + super.setup() + + } + + open override func reset() { + super.reset() + shouldUpdateView = false + kind = .ghost + surfaceType = .colorFill + size = .large + floating = false + hideBorder = true + iconOffset = nil + iconName = nil + shouldUpdateView = true + setNeedsUpdate() + } + + open override func updateView() { + super.updateView() + + if let iconName { + icon.name = iconName + icon.size = size.value + icon.surface = surface + icon.disabled = disabled + } else { + icon.reset() + } + + } + +} From e065ead02a1e785186e1b25b9c7cc9c8858d2379 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 May 2023 17:05:37 -0500 Subject: [PATCH 2/8] refactored more for changing height/width, offset Signed-off-by: Matt Bruce --- .../Icon/ButtonIcon/ButtonIcon.swift | 85 ++++++++++++++++--- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 1d381df6..8174c05c 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -34,32 +34,32 @@ open class ButtonIcon: Control { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - private var widthConstraint: NSLayoutConstraint? - private var heightConstraint: NSLayoutConstraint? - + private var iconCenterXConstraint: NSLayoutConstraint? + private var iconCenterYConstraint: NSLayoutConstraint? + private var containerViewWidthConstraint: NSLayoutConstraint? + private var containerViewHeightConstraint: NSLayoutConstraint? + private var containerView = UIView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.backgroundColor = .clear + } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- open var icon = Icon() - open var iconName: Icon.Name? { didSet { setNeedsUpdate() } } - open var kind: Kind = .ghost { didSet { setNeedsUpdate() } } - open var surfaceType: SurfaceType = .colorFill { didSet { setNeedsUpdate() } } - + open var iconName: Icon.Name? { didSet { setNeedsUpdate() } } open var size: Size = .large { didSet { setNeedsUpdate() } } - + open var customSize: Int? { didSet { setNeedsUpdate() }} open var floating: Bool = false { didSet { setNeedsUpdate() } } - open var hideBorder: Bool = true { didSet { setNeedsUpdate() } } - open var iconOffset: CGPoint? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - + private var padding: CGFloat = 10.0 //-------------------------------------------------- // MARK: - Initializers @@ -82,7 +82,17 @@ open class ButtonIcon: Control { open override func setup() { super.setup() + addSubview(containerView) + containerView.addSubview(icon) + containerView.pinToSuperView(.init(top: padding, left: padding, bottom: padding, right: padding)) + containerViewWidthConstraint = containerView.widthAnchor.constraint(equalToConstant: size.value.dimensions.width + padding) + containerViewHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: size.value.dimensions.height + padding) + + iconCenterXConstraint = icon.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0) + iconCenterYConstraint = icon.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0) + + NSLayoutConstraint.activate([containerViewWidthConstraint!, containerViewHeightConstraint!, iconCenterXConstraint!, iconCenterYConstraint!]) } open override func reset() { @@ -101,16 +111,67 @@ open class ButtonIcon: Control { open override func updateView() { super.updateView() - + if let iconName { icon.name = iconName icon.size = size.value icon.surface = surface icon.disabled = disabled + icon.customSize = customSize } else { icon.reset() } + setNeedsLayout() + } + + open override func layoutSubviews() { + super.layoutSubviews() + + let bgColor = UIColor.red //backgroundColorConfiguration.getColor(self) + let borderColor = UIColor.green// borderColorConfiguration.getColor(self) + let borderWidth = 2.0 + let cornerRadius = min(frame.width, frame.height) / 2.0 + + if let iconOffset { + // calculate center point for child view with offset + let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) + iconCenterXConstraint?.constant = childCenter.x - containerView.center.x + iconCenterYConstraint?.constant = childCenter.y - containerView.center.y + } else { + iconCenterXConstraint?.constant = 0 + iconCenterYConstraint?.constant = 0 + } + + if let customSize { + containerViewWidthConstraint?.constant = CGFloat(customSize) + padding + containerViewHeightConstraint?.constant = CGFloat(customSize) + padding + } else { + containerViewWidthConstraint?.constant = size.value.dimensions.width + padding + containerViewHeightConstraint?.constant = size.value.dimensions.height + padding + } + + print("containerViewWidthConstraint :\(containerViewWidthConstraint!.constant)") + print("containerViewHeightConstraint :\(containerViewHeightConstraint!.constant)") + + //container + backgroundColor = bgColor + layer.borderColor = borderColor.cgColor + layer.cornerRadius = cornerRadius + layer.borderWidth = borderWidth + + //icon + icon.layer.borderColor = UIColor.purple.cgColor + icon.layer.borderWidth = 2 + + } +} + +// MARK: AppleGuidlinesTouchable +extension ButtonIcon: AppleGuidlinesTouchable { + + override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + Self.acceptablyOutsideBounds(point: point, bounds: bounds) } } From c3aafdea48adab5bb02715a6bf1ae069bde39452 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 May 2023 17:15:12 -0500 Subject: [PATCH 3/8] refactored iconOffset Signed-off-by: Matt Bruce --- .../Icon/ButtonIcon/ButtonIcon.swift | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 8174c05c..157cf477 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -29,6 +29,15 @@ open class ButtonIcon: Control { case small public var defaultValue: Icon.Size { .large } + + public var containerSize: CGFloat { + switch self { + case .large: + return 44.0 + case .small: + return 32.0 + } + } } //-------------------------------------------------- @@ -54,12 +63,11 @@ open class ButtonIcon: Control { open var customSize: Int? { didSet { setNeedsUpdate() }} open var floating: Bool = false { didSet { setNeedsUpdate() } } open var hideBorder: Bool = true { didSet { setNeedsUpdate() } } - open var iconOffset: CGPoint? { didSet { setNeedsUpdate() } } + open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - private var padding: CGFloat = 10.0 //-------------------------------------------------- // MARK: - Initializers @@ -85,9 +93,9 @@ open class ButtonIcon: Control { addSubview(containerView) containerView.addSubview(icon) - containerView.pinToSuperView(.init(top: padding, left: padding, bottom: padding, right: padding)) - containerViewWidthConstraint = containerView.widthAnchor.constraint(equalToConstant: size.value.dimensions.width + padding) - containerViewHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: size.value.dimensions.height + padding) + containerView.pinToSuperView() + containerViewWidthConstraint = containerView.widthAnchor.constraint(equalToConstant: size.containerSize) + containerViewHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: size.containerSize) iconCenterXConstraint = icon.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0) iconCenterYConstraint = icon.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0) @@ -103,7 +111,7 @@ open class ButtonIcon: Control { size = .large floating = false hideBorder = true - iconOffset = nil + iconOffset = .init(x: 0, y: 0) iconName = nil shouldUpdateView = true setNeedsUpdate() @@ -132,28 +140,21 @@ open class ButtonIcon: Control { let borderColor = UIColor.green// borderColorConfiguration.getColor(self) let borderWidth = 2.0 let cornerRadius = min(frame.width, frame.height) / 2.0 - - if let iconOffset { - // calculate center point for child view with offset - let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) - iconCenterXConstraint?.constant = childCenter.x - containerView.center.x - iconCenterYConstraint?.constant = childCenter.y - containerView.center.y - } else { - iconCenterXConstraint?.constant = 0 - iconCenterYConstraint?.constant = 0 - } + // calculate center point for child view with offset + let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) + iconCenterXConstraint?.constant = childCenter.x - containerView.center.x + iconCenterYConstraint?.constant = childCenter.y - containerView.center.y + + // calculate the icon's container size ensuring the padding if let customSize { - containerViewWidthConstraint?.constant = CGFloat(customSize) + padding - containerViewHeightConstraint?.constant = CGFloat(customSize) + padding + containerViewWidthConstraint?.constant = CGFloat(customSize) + containerViewHeightConstraint?.constant = CGFloat(customSize) } else { - containerViewWidthConstraint?.constant = size.value.dimensions.width + padding - containerViewHeightConstraint?.constant = size.value.dimensions.height + padding + containerViewWidthConstraint?.constant = size.containerSize + containerViewHeightConstraint?.constant = size.containerSize } - print("containerViewWidthConstraint :\(containerViewWidthConstraint!.constant)") - print("containerViewHeightConstraint :\(containerViewHeightConstraint!.constant)") - //container backgroundColor = bgColor layer.borderColor = borderColor.cgColor From 19a8d8e09a8d80aad625433d665125c2f82cdb72 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 15 May 2023 11:35:27 -0500 Subject: [PATCH 4/8] refactored out IconColor Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 8 +- VDS/Components/Icon/Icon.swift | 17 ++- VDS/Components/Icon/IconColor.swift | 115 ----------------- .../Notification/Notification.swift | 2 +- .../TextFields/EntryField/EntryField.swift | 2 +- .../TextFields/InputField/InputField.swift | 2 +- VDS/Extensions/VDSColor.swift | 119 ++++++++++++++++++ 7 files changed, 138 insertions(+), 127 deletions(-) delete mode 100644 VDS/Components/Icon/IconColor.swift create mode 100644 VDS/Extensions/VDSColor.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index c5673da2..63be730a 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ EA5E3058295105A40082B959 /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E3057295105A40082B959 /* Tilelet.swift */; }; EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305929510F8B0082B959 /* EnumSubset.swift */; }; EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */; }; + EA8141102A127066004F60D2 /* VDSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA81410F2A127066004F60D2 /* VDSColor.swift */; }; EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; }; EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; }; EA89201328B568D8006B9984 /* RadioBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBox.swift */; }; @@ -62,7 +63,6 @@ EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF12968B5BB00F2FF2E /* TitleLockupTextStyle.swift */; }; EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF4296C60C000F2FF2E /* Icon.swift */; }; EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF6296C665E00F2FF2E /* IconName.swift */; }; - EA985BF9296C710100F2FF2E /* IconColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985BF8296C710100F2FF2E /* IconColor.swift */; }; EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C1C296CD13600F2FF2E /* BundleManager.swift */; }; EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C22296E033A00F2FF2E /* TextArea.swift */; }; EA985C2D296F03FE00F2FF2E /* TileletIconModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */; }; @@ -169,6 +169,7 @@ EA5E3057295105A40082B959 /* Tilelet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilelet.swift; sourceTree = ""; }; EA5E305929510F8B0082B959 /* EnumSubset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumSubset.swift; sourceTree = ""; }; EA81410A2A0E8E3C004F60D2 /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = ""; }; + EA81410F2A127066004F60D2 /* VDSColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDSColor.swift; sourceTree = ""; }; EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = ""; }; EA89200528B526D6006B9984 /* CheckboxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxGroup.swift; sourceTree = ""; }; EA89201228B568D8006B9984 /* RadioBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBox.swift; sourceTree = ""; }; @@ -183,7 +184,6 @@ EA985BF12968B5BB00F2FF2E /* TitleLockupTextStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupTextStyle.swift; sourceTree = ""; }; EA985BF4296C60C000F2FF2E /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = ""; }; EA985BF6296C665E00F2FF2E /* IconName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconName.swift; sourceTree = ""; }; - EA985BF8296C710100F2FF2E /* IconColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconColor.swift; sourceTree = ""; }; EA985C1C296CD13600F2FF2E /* BundleManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleManager.swift; sourceTree = ""; }; EA985C22296E033A00F2FF2E /* TextArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextArea.swift; sourceTree = ""; }; EA985C2C296F03FE00F2FF2E /* TileletIconModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletIconModels.swift; sourceTree = ""; }; @@ -414,6 +414,7 @@ EAB5FED329267EB300998C17 /* UIView.swift */, EAB5FF0029424ACB00998C17 /* UIControl.swift */, EA985C662970C21600F2FF2E /* VDSLayout.swift */, + EA81410F2A127066004F60D2 /* VDSColor.swift */, ); path = Extensions; sourceTree = ""; @@ -564,7 +565,6 @@ children = ( EA81410C2A0E8E52004F60D2 /* ButtonIcon */, EA985BF4296C60C000F2FF2E /* Icon.swift */, - EA985BF8296C710100F2FF2E /* IconColor.swift */, EA985BF6296C665E00F2FF2E /* IconName.swift */, EA985C682971B90B00F2FF2E /* IconSize.swift */, ); @@ -821,6 +821,7 @@ EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */, EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */, EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */, + EA8141102A127066004F60D2 /* VDSColor.swift in Sources */, EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */, EAC925842911C63100091998 /* Colorable.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, @@ -879,7 +880,6 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */, EAF7F0B7289C12A600B287F5 /* UITapGestureRecognizer.swift in Sources */, EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */, - EA985BF9296C710100F2FF2E /* IconColor.swift in Sources */, EAB5FED429267EB300998C17 /* UIView.swift in Sources */, EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */, EA33623E2892EE950071C351 /* UIDevice.swift in Sources */, diff --git a/VDS/Components/Icon/Icon.swift b/VDS/Components/Icon/Icon.swift index 54fe428f..7983d7c9 100644 --- a/VDS/Components/Icon/Icon.swift +++ b/VDS/Components/Icon/Icon.swift @@ -28,7 +28,14 @@ open class Icon: View { $0.clipsToBounds = true } - open var color: Color = .black { didSet { setNeedsUpdate() }} + open var color: UIColor = VDSColor.paletteBlack { + didSet { + if let hex = color.hexString, !UIColor.isVDSColor(color: color) { + print("icon.color is not a VDSColor. Hex: \(hex) is not a supported color") + } + setNeedsUpdate() + } + } open var size: Size = .medium { didSet { setNeedsUpdate() }} open var name: Name? { didSet { setNeedsUpdate() }} open var customSize: Int? { didSet { setNeedsUpdate() }} @@ -57,7 +64,7 @@ open class Icon: View { open override func reset() { super.reset() - color = .black + color = VDSColor.paletteBlack imageView.image = nil } @@ -67,12 +74,12 @@ open class Icon: View { open override func updateView() { super.updateView() //get the color for the image - var imageColor = color.value + var imageColor = color //ensure the correct color for white/black colors - if surface == .dark && color == Color.black { + if surface == .dark && color == VDSColor.paletteBlack { imageColor = VDSColor.elementsPrimaryOndark - } else if surface == .light && color == Color.black { + } else if surface == .light && color == VDSColor.paletteBlack { imageColor = VDSColor.elementsPrimaryOnlight } diff --git a/VDS/Components/Icon/IconColor.swift b/VDS/Components/Icon/IconColor.swift deleted file mode 100644 index bcfc73c1..00000000 --- a/VDS/Components/Icon/IconColor.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// IconColor.swift -// VDS -// -// Created by Matt Bruce on 1/9/23. -// - -import Foundation -import VDSColorTokens -import UIKit - -extension Icon { - public enum Color: String, CaseIterable { - case black - case white - case red - case gray95 - case gray85 - case gray65 - case gray44 - case gray20 - case gray11 - case orange94 - case orange83 - case orange71 - case orange58 - case orange41 - case orange24 - case orange17 - case yellow94 - case yellow87 - case yellow74 - case yellow53 - case yellow39 - case yellow20 - case yellow15 - case blue94 - case blue82 - case blue62 - case blue46 - case blue38 - case blue21 - case blue15 - case green91 - case green77 - case green61 - case green36 - case green26 - case green15 - case green10 - case pink87 - case pink76 - case pink62 - case pink46 - case pink25 - case purple85 - case purple75 - case purple60 - case purple39 - case purple20 - - // Map each color name to its corresponding UIColor object. - public var value: UIColor { - switch self { - case .black: return VDSColor.paletteBlack - case .white: return VDSColor.paletteWhite - case .red: return VDSColor.paletteRed - case .gray95: return VDSColor.paletteGray95 - case .gray85: return VDSColor.paletteGray85 - case .gray65: return VDSColor.paletteGray65 - case .gray44: return VDSColor.paletteGray44 - case .gray20: return VDSColor.paletteGray20 - case .gray11: return VDSColor.paletteGray11 - case .orange94: return VDSColor.paletteOrange94 - case .orange83: return VDSColor.paletteOrange83 - case .orange71: return VDSColor.paletteOrange71 - case .orange58: return VDSColor.paletteOrange58 - case .orange41: return VDSColor.paletteOrange41 - case .orange24: return VDSColor.paletteOrange24 - case .orange17: return VDSColor.paletteOrange17 - case .yellow94: return VDSColor.paletteYellow94 - case .yellow87: return VDSColor.paletteYellow87 - case .yellow74: return VDSColor.paletteYellow74 - case .yellow53: return VDSColor.paletteYellow53 - case .yellow39: return VDSColor.paletteYellow39 - case .yellow20: return VDSColor.paletteYellow20 - case .yellow15: return VDSColor.paletteYellow15 - case .blue94: return VDSColor.paletteBlue94 - case .blue82: return VDSColor.paletteBlue82 - case .blue62: return VDSColor.paletteBlue62 - case .blue46: return VDSColor.paletteBlue46 - case .blue38: return VDSColor.paletteBlue38 - case .blue21: return VDSColor.paletteBlue21 - case .blue15: return VDSColor.paletteBlue15 - case .green91: return VDSColor.paletteGreen91 - case .green77: return VDSColor.paletteGreen77 - case .green61: return VDSColor.paletteGreen61 - case .green36: return VDSColor.paletteGreen36 - case .green26: return VDSColor.paletteGreen26 - case .green15: return VDSColor.paletteGreen15 - case .green10: return VDSColor.paletteGreen10 - case .pink87: return VDSColor.palettePink87 - case .pink76: return VDSColor.palettePink76 - case .pink62: return VDSColor.palettePink62 - case .pink46: return VDSColor.palettePink46 - case .pink25: return VDSColor.palettePink25 - case .purple85: return VDSColor.palettePurple85 - case .purple75: return VDSColor.palettePurple75 - case .purple60: return VDSColor.palettePurple60 - case .purple39: return VDSColor.palettePurple39 - case .purple20: return VDSColor.palettePurple20 - } - } - } -} diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index eacb55d1..c4b54185 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -274,7 +274,7 @@ open class Notification: View { } private func updateIcons() { - let iconColor = surface == .dark ? Icon.Color.white : Icon.Color.black + let iconColor = surface == .dark ? VDSColor.paletteWhite : VDSColor.paletteBlack typeIcon.name = type.styleIconName() typeIcon.color = iconColor closeButton.color = iconColor diff --git a/VDS/Components/TextFields/EntryField/EntryField.swift b/VDS/Components/TextFields/EntryField/EntryField.swift index b57b733b..2501af26 100644 --- a/VDS/Components/TextFields/EntryField/EntryField.swift +++ b/VDS/Components/TextFields/EntryField/EntryField.swift @@ -311,7 +311,7 @@ open class EntryField: Control, Changeable { errorLabel.disabled = disabled errorLabel.isHidden = false icon.name = .error - icon.color = .black + icon.color = VDSColor.paletteBlack icon.surface = surface icon.isHidden = disabled } else { diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 2257ca89..ce2aca7d 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -177,7 +177,7 @@ open class InputField: EntryField, UITextFieldDelegate { successLabel.isHidden = false errorLabel.isHidden = true icon.name = .checkmarkAlt - icon.color = .black + icon.color = VDSColor.paletteBlack icon.surface = surface icon.isHidden = disabled } else { diff --git a/VDS/Extensions/VDSColor.swift b/VDS/Extensions/VDSColor.swift new file mode 100644 index 00000000..3e29e31b --- /dev/null +++ b/VDS/Extensions/VDSColor.swift @@ -0,0 +1,119 @@ +// +// VDSColor.swift +// VDS +// +// Created by Matt Bruce on 5/15/23. +// + +import Foundation +import VDSColorTokens + +extension VDSColor { + public enum Color: String, CaseIterable { + case paletteBlack + case paletteWhite + case paletteRed + case paletteGray95 + case paletteGray85 + case paletteGray65 + case paletteGray44 + case paletteGray20 + case paletteGray11 + case paletteOrange94 + case paletteOrange83 + case paletteOrange71 + case paletteOrange58 + case paletteOrange41 + case paletteOrange24 + case paletteOrange17 + case paletteYellow94 + case paletteYellow87 + case paletteYellow74 + case paletteYellow53 + case paletteYellow39 + case paletteYellow20 + case paletteYellow15 + case paletteBlue94 + case paletteBlue82 + case paletteBlue62 + case paletteBlue46 + case paletteBlue38 + case paletteBlue21 + case paletteBlue15 + case paletteGreen91 + case paletteGreen77 + case paletteGreen61 + case paletteGreen36 + case paletteGreen26 + case paletteGreen15 + case paletteGreen10 + case palettePink87 + case palettePink76 + case palettePink62 + case palettePink46 + case palettePink25 + case palettePurple85 + case palettePurple75 + case palettePurple60 + case palettePurple39 + case palettePurple20 + case backgroundPrimaryLight + case backgroundPrimaryDark + case backgroundSecondaryLight + case backgroundSecondaryDark + case backgroundBrandhighlight + case feedbackErrorOnlight + case feedbackErrorOndark + case feedbackErrorBackgroundOnlight + case feedbackErrorBackgroundOndark + case feedbackWarningOnlight + case feedbackWarningOndark + case feedbackWarningBackgroundOnlight + case feedbackWarningBackgroundOndark + case feedbackInformationOnlight + case feedbackInformationOndark + case feedbackInformationBackgroundOnlight + case feedbackInformationBackgroundOndark + case feedbackSuccessOnlight + case feedbackSuccessOndark + case feedbackSuccessBackgroundOnlight + case feedbackSuccessBackgroundOndark + case interactiveActiveOnlight + case interactiveActiveOndark + case interactiveDisabledOnlight + case interactiveDisabledOndark + case interactiveScrollthumbOnlight + case interactiveScrollthumbOndark + case interactiveScrollthumbHoverOnlight + case interactiveScrollthumbHoverOndark + case interactiveScrolltrackOnlight + case interactiveScrolltrackOndark + case elementsPrimaryOnlight + case elementsPrimaryOndark + case elementsSecondaryOnlight + case elementsSecondaryOndark + case elementsBrandhighlight + case elementsLowcontrastOnlight + case elementsLowcontrastOndark + + // Map each color name to its corresponding UIColor object. + public var uiColor: UIColor { + do { + let color = try VDSColor.getTokenByString(tokenName: "VDSColor.\(rawValue)") + return color + } catch { + print(error) + return VDSColor.paletteBlack + } + } + } +} + +extension UIColor { + public static func isVDSColor(color: UIColor) -> Bool { + guard let hex = color.hexString else { return false } + let found = VDSColor.Color.allCases.first{ $0.uiColor.hexString == hex } + guard let _ = found else { return false} + return true + } +} From 636b5ad9c0e66025b352c7b007d29548025139f2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 15 May 2023 11:35:47 -0500 Subject: [PATCH 5/8] refactored naming Signed-off-by: Matt Bruce --- .../Icon/ButtonIcon/ButtonIcon.swift | 73 +++++++++++-------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 157cf477..cd115e98 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -43,14 +43,11 @@ open class ButtonIcon: Control { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - private var iconCenterXConstraint: NSLayoutConstraint? - private var iconCenterYConstraint: NSLayoutConstraint? - private var containerViewWidthConstraint: NSLayoutConstraint? - private var containerViewHeightConstraint: NSLayoutConstraint? - private var containerView = UIView().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.backgroundColor = .clear - } + private var centerXConstraint: NSLayoutConstraint? + private var centerYConstraint: NSLayoutConstraint? + private var layoutGuideWidthConstraint: NSLayoutConstraint? + private var layoutGuideHeightConstraint: NSLayoutConstraint? + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -90,17 +87,31 @@ open class ButtonIcon: Control { open override func setup() { super.setup() - addSubview(containerView) - containerView.addSubview(icon) + + //create a layoutGuide for the icon to key off of + let iconLayoutGuide = UILayoutGuide() + addLayoutGuide(iconLayoutGuide) - containerView.pinToSuperView() - containerViewWidthConstraint = containerView.widthAnchor.constraint(equalToConstant: size.containerSize) - containerViewHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: size.containerSize) + //add the icon + addSubview(icon) + + //determines the height/width of the icon + layoutGuideWidthConstraint = iconLayoutGuide.widthAnchor.constraint(equalToConstant: size.containerSize) + layoutGuideHeightConstraint = iconLayoutGuide.heightAnchor.constraint(equalToConstant: size.containerSize) - iconCenterXConstraint = icon.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0) - iconCenterYConstraint = icon.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0) + //determines the center point of the icon + centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0) + centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0) - NSLayoutConstraint.activate([containerViewWidthConstraint!, containerViewHeightConstraint!, iconCenterXConstraint!, iconCenterYConstraint!]) + //activate the constraints + NSLayoutConstraint.activate([layoutGuideWidthConstraint!, + layoutGuideHeightConstraint!, + centerXConstraint!, + centerYConstraint!, + iconLayoutGuide.topAnchor.constraint(equalTo: topAnchor), + iconLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), + iconLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), + iconLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) } open override func reset() { @@ -120,6 +131,7 @@ open class ButtonIcon: Control { open override func updateView() { super.updateView() + //ensure there is an icon to set if let iconName { icon.name = iconName icon.size = size.value @@ -130,40 +142,41 @@ open class ButtonIcon: Control { icon.reset() } + // colors + let bgColor = UIColor.red //backgroundColorConfiguration.getColor(self) + let borderColor = UIColor.green// borderColorConfiguration.getColor(self) + backgroundColor = bgColor + layer.borderColor = borderColor.cgColor + icon.layer.borderColor = UIColor.purple.cgColor + setNeedsLayout() } open override func layoutSubviews() { super.layoutSubviews() - let bgColor = UIColor.red //backgroundColorConfiguration.getColor(self) - let borderColor = UIColor.green// borderColorConfiguration.getColor(self) let borderWidth = 2.0 let cornerRadius = min(frame.width, frame.height) / 2.0 // calculate center point for child view with offset let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) - iconCenterXConstraint?.constant = childCenter.x - containerView.center.x - iconCenterYConstraint?.constant = childCenter.y - containerView.center.y + centerXConstraint?.constant = childCenter.x - center.x + centerYConstraint?.constant = childCenter.y - center.y // calculate the icon's container size ensuring the padding + var iconLayoutSize = size.containerSize if let customSize { - containerViewWidthConstraint?.constant = CGFloat(customSize) - containerViewHeightConstraint?.constant = CGFloat(customSize) - } else { - containerViewWidthConstraint?.constant = size.containerSize - containerViewHeightConstraint?.constant = size.containerSize + iconLayoutSize = CGFloat(customSize) } - + layoutGuideWidthConstraint?.constant = iconLayoutSize + layoutGuideHeightConstraint?.constant = iconLayoutSize + //container - backgroundColor = bgColor - layer.borderColor = borderColor.cgColor layer.cornerRadius = cornerRadius layer.borderWidth = borderWidth //icon - icon.layer.borderColor = UIColor.purple.cgColor - icon.layer.borderWidth = 2 + icon.layer.borderWidth = borderWidth } } From e91465f423353e8bc3570b807d955ecadc1c5d69 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 16 May 2023 15:31:42 -0500 Subject: [PATCH 6/8] added removal extension Signed-off-by: Matt Bruce --- VDS/Extensions/UIView.swift | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/VDS/Extensions/UIView.swift b/VDS/Extensions/UIView.swift index e4e1d0ad..5b5c909b 100644 --- a/VDS/Extensions/UIView.swift +++ b/VDS/Extensions/UIView.swift @@ -121,11 +121,7 @@ extension UIView { extension UIView { internal func removeDebugBorder() { - layer.sublayers?.forEach({ layer in - if layer.name?.hasPrefix("debug") ?? false { - layer.removeFromSuperlayer() - } - }) + layer.remove(layerName: "debug") } internal func addDebugBorder(color: UIColor = .red) { @@ -177,3 +173,13 @@ extension UIView { } } } + +extension CALayer { + func remove(layerName: String) { + sublayers?.forEach({ layer in + if layer.name?.hasPrefix(layerName) ?? false { + layer.removeFromSuperlayer() + } + }) + } +} From facafa308b8aee5b4f7943c741c97e2d3b669546 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 16 May 2023 15:31:52 -0500 Subject: [PATCH 7/8] more changes Signed-off-by: Matt Bruce --- .../Icon/ButtonIcon/ButtonIcon.swift | 248 ++++++++++++++++-- 1 file changed, 222 insertions(+), 26 deletions(-) diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index cd115e98..d432f273 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -7,6 +7,7 @@ import Foundation import UIKit +import VDSColorTokens @objc(VDSButtonIcon) open class ButtonIcon: Control { @@ -19,7 +20,7 @@ open class ButtonIcon: Control { public enum Kind: String, CaseIterable { case ghost, lowContrast, highContrast } - + public enum SurfaceType: String, CaseIterable { case colorFill, media } @@ -47,24 +48,85 @@ open class ButtonIcon: Control { private var centerYConstraint: NSLayoutConstraint? private var layoutGuideWidthConstraint: NSLayoutConstraint? private var layoutGuideHeightConstraint: NSLayoutConstraint? + private var currentIconName: Icon.Name? { + if let selectedIconName { + return selectedIconName + } else { + return iconName + } + } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- open var icon = Icon() - + open var kind: Kind = .ghost { didSet { setNeedsUpdate() } } open var surfaceType: SurfaceType = .colorFill { didSet { setNeedsUpdate() } } open var iconName: Icon.Name? { didSet { setNeedsUpdate() } } + open var selectedIconName: Icon.Name? { didSet { setNeedsUpdate() } } open var size: Size = .large { didSet { setNeedsUpdate() } } open var customSize: Int? { didSet { setNeedsUpdate() }} open var floating: Bool = false { didSet { setNeedsUpdate() } } + open var fitToIcon: Bool = false { didSet { setNeedsUpdate() } } open var hideBorder: Bool = true { didSet { setNeedsUpdate() } } open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- + private var iconColorConfig: AnyColorable { + if selectedIconName != nil { + return selectedIconColorConfig + } else { + if kind == .highContrast { + return highContrastIconColorConfig + } else { + return standardIconColorConfig + } + } + } + + private var currentConfiguration: any Configuration { + switch kind { + case .ghost: + return GhostConfiguration() + + case .lowContrast: + if surfaceType == .colorFill { + return floating ? LowContrastColorFillFloatingConfiguration() : LowContrastColorFillConfiguration() + } else { + return floating ? LowContrastMediaFloatingConfiguration() : LowContrastMediaConfiguration() + } + + case .highContrast: + return floating ? HighContrastFloatingConfiguration() : HighContrastConfiguration() + } + } + + private var standardIconColorConfig: AnyColorable = { + return ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + }.eraseToAnyColorable() + }() + + private var highContrastIconColorConfig: AnyColorable = { + return ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveActiveOndark, VDSColor.interactiveActiveOnlight, forState: .highlighted) + $0.setSurfaceColors(VDSColor.interactiveDisabledOndark, VDSColor.interactiveDisabledOnlight, forState: .disabled) + }.eraseToAnyColorable() + }() + + private var selectedIconColorConfig: AnyColorable = { + return ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsBrandhighlight, VDSColor.elementsPrimaryOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + }.eraseToAnyColorable() + }() //-------------------------------------------------- // MARK: - Initializers @@ -84,25 +146,24 @@ open class ButtonIcon: Control { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - open override func setup() { super.setup() - + //create a layoutGuide for the icon to key off of let iconLayoutGuide = UILayoutGuide() addLayoutGuide(iconLayoutGuide) - + //add the icon addSubview(icon) - + //determines the height/width of the icon layoutGuideWidthConstraint = iconLayoutGuide.widthAnchor.constraint(equalToConstant: size.containerSize) layoutGuideHeightConstraint = iconLayoutGuide.heightAnchor.constraint(equalToConstant: size.containerSize) - + //determines the center point of the icon centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0) centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0) - + //activate the constraints NSLayoutConstraint.activate([layoutGuideWidthConstraint!, layoutGuideHeightConstraint!, @@ -130,10 +191,11 @@ open class ButtonIcon: Control { open override func updateView() { super.updateView() - + //ensure there is an icon to set - if let iconName { - icon.name = iconName + if let currentIconName { + icon.name = currentIconName + icon.color = iconColorConfig.getColor(self) icon.size = size.value icon.surface = surface icon.disabled = disabled @@ -141,13 +203,8 @@ open class ButtonIcon: Control { } else { icon.reset() } - - // colors - let bgColor = UIColor.red //backgroundColorConfiguration.getColor(self) - let borderColor = UIColor.green// borderColorConfiguration.getColor(self) - backgroundColor = bgColor - layer.borderColor = borderColor.cgColor - icon.layer.borderColor = UIColor.purple.cgColor + + icon.backgroundColor = .green setNeedsLayout() } @@ -155,30 +212,140 @@ open class ButtonIcon: Control { open override func layoutSubviews() { super.layoutSubviews() - let borderWidth = 2.0 - let cornerRadius = min(frame.width, frame.height) / 2.0 + let currentConfig = currentConfiguration + + backgroundColor = currentConfig.backgroundColorConfig.getColor(self) // calculate center point for child view with offset let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) centerXConstraint?.constant = childCenter.x - center.x centerYConstraint?.constant = childCenter.y - center.y - // calculate the icon's container size ensuring the padding + //updating current container size var iconLayoutSize = size.containerSize if let customSize { iconLayoutSize = CGFloat(customSize) } + // check to see if this is fitToIcon + if fitToIcon && kind == .ghost { + iconLayoutSize = size.value.dimensions.width + layer.cornerRadius = 0 + } else { + layer.cornerRadius = min(frame.width, frame.height) / 2.0 + } + layoutGuideWidthConstraint?.constant = iconLayoutSize layoutGuideHeightConstraint?.constant = iconLayoutSize - //container - layer.cornerRadius = cornerRadius - layer.borderWidth = borderWidth + //border + if let borderable = currentConfig as? Borderable { + layer.borderColor = borderable.borderColorConfig.getColor(self).cgColor + layer.borderWidth = borderable.borderWidth + icon.layer.borderWidth = borderable.borderWidth + } else { + layer.borderColor = nil + layer.borderWidth = 0 + icon.layer.borderWidth = 0 + } - //icon - icon.layer.borderWidth = borderWidth + if let dropshadowable = currentConfig as? Dropshadowable { + layer.masksToBounds = false + layer.shadowColor = dropshadowable.shadowColorConfig.getColor(self).cgColor + layer.shadowOpacity = Float(dropshadowable.shadowOpacity) + layer.shadowOffset = dropshadowable.shadowOffset + layer.shadowRadius = dropshadowable.shadowRadius + layer.shadowPath = UIBezierPath(rect: bounds).cgPath + layer.shouldRasterize = true + layer.rasterizationScale = UIScreen.main.scale + } else { + layer.shadowOpacity = 0 + layer.shadowRadius = 0 + layer.shadowPath = nil + } } + + private struct GhostConfiguration: Configuration { + var kind: Kind = .ghost + var surfaceType: SurfaceType = .colorFill + var floating: Bool = false + var backgroundColorConfig: AnyColorable = { + SurfaceColorConfiguration(.clear, .clear).eraseToAnyColorable() + }() + } + + private struct LowContrastColorFillConfiguration: Configuration { + var kind: Kind = .lowContrast + var surfaceType: SurfaceType = .colorFill + var floating: Bool = false + var backgroundColorConfig: AnyColorable = { + SurfaceColorConfiguration(VDSColor.paletteGray44.withAlphaComponent(0.94), .clear).eraseToAnyColorable() + }() + } + + private struct LowContrastColorFillFloatingConfiguration: Configuration { + var kind: Kind = .lowContrast + var surfaceType: SurfaceType = .colorFill + var floating: Bool = true + var backgroundColorConfig: AnyColorable = { + SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() + }() + } + + private struct LowContrastMediaConfiguration: Configuration, Borderable { + var kind: Kind = .lowContrast + var surfaceType: SurfaceType = .media + var floating: Bool = false + var backgroundColorConfig: AnyColorable = { + SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() + }() + var borderWidth: CGFloat = 1.0 + var borderColorConfig: AnyColorable = { + SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, .clear).eraseToAnyColorable() + }() + } + + private struct LowContrastMediaFloatingConfiguration: Configuration, Dropshadowable { + var kind: Kind = .lowContrast + var surfaceType: SurfaceType = .media + var floating: Bool = true + var backgroundColorConfig: AnyColorable = { + SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() + }() + var shadowColorConfig: AnyColorable = { + SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() + }() + var shadowOpacity: CGFloat = 0.5 + var shadowOffset: CGSize = .init(width: 1, height: 1) + var shadowRadius: CGFloat = 2 + } + + private struct HighContrastConfiguration: Configuration { + var kind: Kind = .highContrast + var surfaceType: SurfaceType = .colorFill + var floating: Bool = false + var backgroundColorConfig: AnyColorable = { + return ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + }.eraseToAnyColorable() + + }() + } + + private struct HighContrastFloatingConfiguration: Configuration { + var kind: Kind = .highContrast + var surfaceType: SurfaceType = .colorFill + var floating: Bool = true + var backgroundColorConfig: AnyColorable = { + return ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forState: .disabled) + }.eraseToAnyColorable() + }() + } } // MARK: AppleGuidlinesTouchable @@ -188,4 +355,33 @@ extension ButtonIcon: AppleGuidlinesTouchable { Self.acceptablyOutsideBounds(point: point, bounds: bounds) } + open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let view = super.hitTest(point, with: event) + + if view == icon { + return self + } + + return view + } + +} + +private protocol Borderable { + var borderWidth: CGFloat { get set } + var borderColorConfig: AnyColorable { get set } +} + +private protocol Dropshadowable { + var shadowColorConfig: AnyColorable { get set } + var shadowOpacity: CGFloat { get set } + var shadowOffset: CGSize { get set } + var shadowRadius: CGFloat { get set } +} + +private protocol Configuration { + var kind: ButtonIcon.Kind { get set } + var surfaceType: ButtonIcon.SurfaceType { get set } + var floating: Bool { get set } + var backgroundColorConfig: AnyColorable { get set } } From 94453b5c2e9b693c0533c177e40bc49583f54436 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 17 May 2023 09:25:51 -0500 Subject: [PATCH 8/8] updated configurations --- .../Icon/ButtonIcon/ButtonIcon.swift | 281 +++++++++--------- 1 file changed, 137 insertions(+), 144 deletions(-) diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index d432f273..a7de9401 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -113,11 +113,7 @@ open class ButtonIcon: Control { }() private var highContrastIconColorConfig: AnyColorable = { - return ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forState: .normal) - $0.setSurfaceColors(VDSColor.interactiveActiveOndark, VDSColor.interactiveActiveOnlight, forState: .highlighted) - $0.setSurfaceColors(VDSColor.interactiveDisabledOndark, VDSColor.interactiveDisabledOnlight, forState: .disabled) - }.eraseToAnyColorable() + return SurfaceColorConfiguration(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight).eraseToAnyColorable() }() private var selectedIconColorConfig: AnyColorable = { @@ -128,143 +124,6 @@ open class ButtonIcon: Control { }.eraseToAnyColorable() }() - //-------------------------------------------------- - // MARK: - Initializers - //-------------------------------------------------- - required public init() { - super.init(frame: .zero) - } - - public override init(frame: CGRect) { - super.init(frame: .zero) - } - - public required init?(coder: NSCoder) { - super.init(coder: coder) - } - - //-------------------------------------------------- - // MARK: - Lifecycle - //-------------------------------------------------- - open override func setup() { - super.setup() - - //create a layoutGuide for the icon to key off of - let iconLayoutGuide = UILayoutGuide() - addLayoutGuide(iconLayoutGuide) - - //add the icon - addSubview(icon) - - //determines the height/width of the icon - layoutGuideWidthConstraint = iconLayoutGuide.widthAnchor.constraint(equalToConstant: size.containerSize) - layoutGuideHeightConstraint = iconLayoutGuide.heightAnchor.constraint(equalToConstant: size.containerSize) - - //determines the center point of the icon - centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0) - centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0) - - //activate the constraints - NSLayoutConstraint.activate([layoutGuideWidthConstraint!, - layoutGuideHeightConstraint!, - centerXConstraint!, - centerYConstraint!, - iconLayoutGuide.topAnchor.constraint(equalTo: topAnchor), - iconLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), - iconLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), - iconLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) - } - - open override func reset() { - super.reset() - shouldUpdateView = false - kind = .ghost - surfaceType = .colorFill - size = .large - floating = false - hideBorder = true - iconOffset = .init(x: 0, y: 0) - iconName = nil - shouldUpdateView = true - setNeedsUpdate() - } - - open override func updateView() { - super.updateView() - - //ensure there is an icon to set - if let currentIconName { - icon.name = currentIconName - icon.color = iconColorConfig.getColor(self) - icon.size = size.value - icon.surface = surface - icon.disabled = disabled - icon.customSize = customSize - } else { - icon.reset() - } - - icon.backgroundColor = .green - - setNeedsLayout() - } - - open override func layoutSubviews() { - super.layoutSubviews() - - let currentConfig = currentConfiguration - - backgroundColor = currentConfig.backgroundColorConfig.getColor(self) - - // calculate center point for child view with offset - let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) - centerXConstraint?.constant = childCenter.x - center.x - centerYConstraint?.constant = childCenter.y - center.y - - //updating current container size - var iconLayoutSize = size.containerSize - if let customSize { - iconLayoutSize = CGFloat(customSize) - } - // check to see if this is fitToIcon - if fitToIcon && kind == .ghost { - iconLayoutSize = size.value.dimensions.width - layer.cornerRadius = 0 - } else { - layer.cornerRadius = min(frame.width, frame.height) / 2.0 - } - - layoutGuideWidthConstraint?.constant = iconLayoutSize - layoutGuideHeightConstraint?.constant = iconLayoutSize - - //border - if let borderable = currentConfig as? Borderable { - layer.borderColor = borderable.borderColorConfig.getColor(self).cgColor - layer.borderWidth = borderable.borderWidth - icon.layer.borderWidth = borderable.borderWidth - } else { - layer.borderColor = nil - layer.borderWidth = 0 - icon.layer.borderWidth = 0 - } - - if let dropshadowable = currentConfig as? Dropshadowable { - layer.masksToBounds = false - layer.shadowColor = dropshadowable.shadowColorConfig.getColor(self).cgColor - layer.shadowOpacity = Float(dropshadowable.shadowOpacity) - layer.shadowOffset = dropshadowable.shadowOffset - layer.shadowRadius = dropshadowable.shadowRadius - layer.shadowPath = UIBezierPath(rect: bounds).cgPath - layer.shouldRasterize = true - layer.rasterizationScale = UIScreen.main.scale - } else { - layer.shadowOpacity = 0 - layer.shadowRadius = 0 - layer.shadowPath = nil - } - - } - private struct GhostConfiguration: Configuration { var kind: Kind = .ghost var surfaceType: SurfaceType = .colorFill @@ -279,7 +138,7 @@ open class ButtonIcon: Control { var surfaceType: SurfaceType = .colorFill var floating: Bool = false var backgroundColorConfig: AnyColorable = { - SurfaceColorConfiguration(VDSColor.paletteGray44.withAlphaComponent(0.94), .clear).eraseToAnyColorable() + SurfaceColorConfiguration(VDSColor.paletteGray44.withAlphaComponent(0.06), VDSColor.paletteGray44.withAlphaComponent(0.26)).eraseToAnyColorable() }() } @@ -346,6 +205,140 @@ open class ButtonIcon: Control { }.eraseToAnyColorable() }() } + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func setup() { + super.setup() + + //create a layoutGuide for the icon to key off of + let iconLayoutGuide = UILayoutGuide() + addLayoutGuide(iconLayoutGuide) + + //add the icon + addSubview(icon) + + //determines the height/width of the icon + layoutGuideWidthConstraint = iconLayoutGuide.widthAnchor.constraint(equalToConstant: size.containerSize) + layoutGuideHeightConstraint = iconLayoutGuide.heightAnchor.constraint(equalToConstant: size.containerSize) + + //determines the center point of the icon + centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0) + centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0) + + //activate the constraints + NSLayoutConstraint.activate([layoutGuideWidthConstraint!, + layoutGuideHeightConstraint!, + centerXConstraint!, + centerYConstraint!, + iconLayoutGuide.topAnchor.constraint(equalTo: topAnchor), + iconLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), + iconLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), + iconLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) + } + + open override func reset() { + super.reset() + shouldUpdateView = false + kind = .ghost + surfaceType = .colorFill + size = .large + floating = false + hideBorder = true + iconOffset = .init(x: 0, y: 0) + iconName = nil + shouldUpdateView = true + setNeedsUpdate() + } + + open override func updateView() { + super.updateView() + + //ensure there is an icon to set + if let currentIconName { + icon.name = currentIconName + let color = iconColorConfig.getColor(self) + icon.color = color + icon.size = size.value + icon.customSize = customSize + } else { + icon.reset() + } + + setNeedsLayout() + } + + open override func layoutSubviews() { + super.layoutSubviews() + + let currentConfig = currentConfiguration + + backgroundColor = currentConfig.backgroundColorConfig.getColor(self) + + // calculate center point for child view with offset + let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) + centerXConstraint?.constant = childCenter.x - center.x + centerYConstraint?.constant = childCenter.y - center.y + + //updating current container size + var iconLayoutSize = size.containerSize + if let customSize { + iconLayoutSize = CGFloat(customSize) + } + // check to see if this is fitToIcon + if fitToIcon && kind == .ghost { + iconLayoutSize = size.value.dimensions.width + layer.cornerRadius = 0 + } else { + layer.cornerRadius = min(frame.width, frame.height) / 2.0 + } + + layoutGuideWidthConstraint?.constant = iconLayoutSize + layoutGuideHeightConstraint?.constant = iconLayoutSize + + //border + if let borderable = currentConfig as? Borderable { + layer.borderColor = borderable.borderColorConfig.getColor(self).cgColor + layer.borderWidth = borderable.borderWidth + icon.layer.borderWidth = borderable.borderWidth + } else { + layer.borderColor = nil + layer.borderWidth = 0 + icon.layer.borderWidth = 0 + } + + if let dropshadowable = currentConfig as? Dropshadowable { + layer.masksToBounds = false + layer.shadowColor = dropshadowable.shadowColorConfig.getColor(self).cgColor + layer.shadowOpacity = Float(dropshadowable.shadowOpacity) + layer.shadowOffset = dropshadowable.shadowOffset + layer.shadowRadius = dropshadowable.shadowRadius + layer.shadowPath = UIBezierPath(rect: bounds).cgPath + layer.shouldRasterize = true + layer.rasterizationScale = UIScreen.main.scale + } else { + layer.shadowOpacity = 0 + layer.shadowRadius = 0 + layer.shadowPath = nil + } + + } } // MARK: AppleGuidlinesTouchable @@ -364,7 +357,7 @@ extension ButtonIcon: AppleGuidlinesTouchable { return view } - + } private protocol Borderable {