more changes

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2023-05-16 15:31:52 -05:00
parent e91465f423
commit facafa308b

View File

@ -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 }
}