Merge branch 'develop' into generic-class

# Conflicts:
#	VDS/Classes/VDSControl.swift
#	VDS/Components/Toggle/VDSToggle.swift

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2022-08-01 17:05:58 -05:00
commit 2c4b0a578a
10 changed files with 135 additions and 56 deletions

View File

@ -9,7 +9,7 @@ import Foundation
import UIKit import UIKit
import Combine import Combine
open class VDSControl<ModelType>: UIControl, Modelable, ViewProtocol { open class VDSControl<ModelType: Initable>: UIControl, Modelable, ViewProtocol {
@Published public var model: ModelType @Published public var model: ModelType
private var cancellable: AnyCancellable? private var cancellable: AnyCancellable?
@ -39,7 +39,9 @@ open class VDSControl<ModelType>: UIControl, Modelable, ViewProtocol {
} }
public required init?(coder: NSCoder) { public required init?(coder: NSCoder) {
fatalError("Control does not support xib.") self.model = ModelType.init()
super.init(coder: coder)
initialSetup()
} }
//-------------------------------------------------- //--------------------------------------------------

View File

@ -57,10 +57,26 @@ open class VDSLabel: UILabel, Modelable, Initable {
} }
} }
private func getTextColor(for disabled: Bool, surface: Surface) -> UIColor {
if disabled {
if surface == .light {
return VDSColor.elementsSecondaryOnlight
} else {
return VDSColor.elementsSecondaryOndark
}
} else {
if surface == .light {
return VDSColor.elementsPrimaryOnlight
} else {
return VDSColor.elementsPrimaryOndark
}
}
}
//functions //functions
private func onStateChange(viewModel: VDSLabelModel) { private func onStateChange(viewModel: VDSLabelModel) {
textAlignment = viewModel.textPosition.textAlignment textAlignment = viewModel.textPosition.textAlignment
textColor = viewModel.surface == .dark ? VDSColor.elementsPrimaryOndark : VDSColor.elementsPrimaryOnlight textColor = getTextColor(for: viewModel.disabled, surface: viewModel.surface)
guard let vdsFont = try? VDSFontStyle.font(for: viewModel.fontCategory, fontWeight: viewModel.fontWeight, fontSize: viewModel.fontSize) else { guard let vdsFont = try? VDSFontStyle.font(for: viewModel.fontCategory, fontWeight: viewModel.fontWeight, fontSize: viewModel.fontSize) else {
font = VDSFontStyle.RegularBodyLarge.font font = VDSFontStyle.RegularBodyLarge.font

View File

@ -8,14 +8,15 @@
import Foundation import Foundation
import UIKit import UIKit
public protocol VDSLabelModel: Labelable, Surfaceable { public protocol VDSLabelModel: Labelable, Surfaceable, Disabling {
} }
open class DefaultLabelModel: VDSLabelModel { open class DefaultLabelModel: VDSLabelModel {
public var fontCategory: VDSFontCategory = .body public var fontCategory: VDSFontCategory = .body
public var fontSize: VDSFontSize = .large public var fontSize: VDSFontSize = .small
public var fontWeight: VDSFontWeight = .regular public var fontWeight: VDSFontWeight = .regular
public var textPosition: VDSTextPosition = .left public var textPosition: VDSTextPosition = .left
public var surface: Surface = .light public var surface: Surface = .light
public var disabled: Bool = false
required public init(){} required public init(){}
} }

View File

@ -18,7 +18,7 @@ import Combine
Knob: The circular indicator that slides on the container. Knob: The circular indicator that slides on the container.
*/ */
final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{ @objcMembers public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
public convenience init() { public convenience init() {
self.init(with: DefaultToggleModel()) self.init(with: DefaultToggleModel())
} }
@ -37,15 +37,46 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
/// Holds the on and off colors for the container. private var toggleTintColor: (on: UIColor, off: UIColor) {
private var containerTintColor: (on: UIColor, off: UIColor) = (on: VDSColor.paletteGreen26, off: VDSColor.paletteGray44) return getToggleColor(for: disabled, surface: surface)
}
/// Holds the on and off colors for the knob. private var knobTintColor: (on: UIColor, off: UIColor) {
private var knobTintColor: (on: UIColor, off: UIColor) = (on: VDSColor.paletteWhite, off: VDSColor.paletteWhite) return getKnobColor(for: disabled, surface: surface)
}
private func getToggleColor(for disabled: Bool, surface: Surface) -> (on: UIColor, off: UIColor) {
if disabled {
if surface == .light {
return (on: VDSColor.elementsDisabledOnlight, off: VDSColor.elementsDisabledOnlight)
} else {
return (on: VDSColor.elementsDisabledOnDark, off: VDSColor.elementsDisabledOnDark)
}
} else {
if surface == .light {
return (on: VDSColor.paletteGreen26, off: VDSColor.elementsSecondaryOnlight)
} else {
return (on: VDSColor.paletteGreen34, off: VDSColor.paletteGray44)
}
}
}
private func getKnobColor(for disabled: Bool, surface: Surface) -> (on: UIColor, off: UIColor) {
if disabled {
if surface == .light {
return (on: VDSColor.paletteGray95, off: VDSColor.paletteGray95)
} else {
return (on: VDSColor.paletteGray44, off: VDSColor.paletteGray44)
}
} else {
if surface == .light {
return (on: VDSColor.elementsPrimaryOndark, off: VDSColor.elementsPrimaryOndark)
} else {
return (on: VDSColor.elementsPrimaryOndark, off: VDSColor.elementsPrimaryOndark)
}
}
}
/// Holds the on and off colors for the disabled state..
private var disabledTintColor: (container: UIColor, knob: UIColor) = (container: VDSColor.paletteGray11, knob: VDSColor.paletteWhite)
private var showTextSpacing: CGFloat { private var showTextSpacing: CGFloat {
showText ? 12 : 0 showText ? 12 : 0
} }
@ -94,7 +125,13 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
// MARK: - Computed Properties // MARK: - Computed Properties
//-------------------------------------------------- //--------------------------------------------------
@Proxy(\.model.showText) @Proxy(\.model.showText)
public var showText: Bool public var showText: Bool {
didSet {
if oldValue != showText {
ensureLabel()
}
}
}
@Proxy(\.model.onText) @Proxy(\.model.onText)
public var onText: String public var onText: String
@ -103,7 +140,13 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
public var offText: String public var offText: String
@Proxy(\.model.textPosition) @Proxy(\.model.textPosition)
public var textPosition: VDSTextPosition public var textPosition: VDSTextPosition {
didSet {
if oldValue != textPosition {
ensureLabel()
}
}
}
@Proxy(\.model.fontSize) @Proxy(\.model.fontSize)
public var fontSize: VDSFontSize public var fontSize: VDSFontSize
@ -117,6 +160,9 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
@Proxy(\.model.on) @Proxy(\.model.on)
open var isOn: Bool open var isOn: Bool
@Proxy(\.model.disabled)
open var disabled: Bool
open override var isEnabled: Bool { open override var isEnabled: Bool {
get { !model.disabled } get { !model.disabled }
set { set {
@ -164,10 +210,7 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
super.setupView() super.setupView()
isAccessibilityElement = true isAccessibilityElement = true
setAccessibilityHint()
setAccessibilityLabel()
accessibilityTraits = .button accessibilityTraits = .button
addSubview(stackView) addSubview(stackView)
toggleHeightConstraint = toggleView.heightAnchor.constraint(equalToConstant: toggleSize.height) toggleHeightConstraint = toggleView.heightAnchor.constraint(equalToConstant: toggleSize.height)
@ -179,7 +222,7 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
toggleView.layer.cornerRadius = toggleSize.height / 2.0 toggleView.layer.cornerRadius = toggleSize.height / 2.0
knobView.layer.cornerRadius = knobSize.height / 2.0 knobView.layer.cornerRadius = knobSize.height / 2.0
toggleView.backgroundColor = containerTintColor.off toggleView.backgroundColor = toggleTintColor.off
toggleView.addSubview(knobView) toggleView.addSubview(knobView)
@ -216,7 +259,7 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
public override func reset() { public override func reset() {
super.reset() super.reset()
toggleView.backgroundColor = containerTintColor.off toggleView.backgroundColor = toggleTintColor.off
knobView.backgroundColor = knobTintColor.off knobView.backgroundColor = knobTintColor.off
setAccessibilityLabel() setAccessibilityLabel()
onChange = nil onChange = nil
@ -262,22 +305,16 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
} }
public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
knobReformAnimation() knobReformAnimation()
// Action only occurs of the user lifts up from withing acceptable region of the toggle. // Action only occurs of the user lifts up from withing acceptable region of the toggle.
guard let coordinates = touches.first?.location(in: self), let value = 20.0
coordinates.x > -20, guard let coordinates = touches.first?.location(in: self) else { return }
coordinates.x < bounds.width + 20, guard coordinates.x > -value else { return }
coordinates.y > -20,
coordinates.y < bounds.height + 20
else { return }
sendActions(for: .touchUpInside) sendActions(for: .touchUpInside)
} }
public func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) { open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
knobReformAnimation() knobReformAnimation()
sendActions(for: .touchCancel) sendActions(for: .touchCancel)
} }
@ -297,7 +334,7 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
/// - Parameter viewModel: state /// - Parameter viewModel: state
open override func onStateChange(viewModel: ModelType) { open override func onStateChange(viewModel: ModelType) {
let enabled = !viewModel.disabled let enabled = !viewModel.disabled
label.set(with: viewModel) label.set(with: viewModel)
label.text = viewModel.on ? viewModel.onText : viewModel.offText label.text = viewModel.on ? viewModel.onText : viewModel.offText
@ -321,33 +358,30 @@ final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
self.layoutIfNeeded() self.layoutIfNeeded()
} }
let toggleColor = getToggleColor(for: viewModel.disabled, surface: viewModel.surface)
let knobColor = getKnobColor(for: viewModel.disabled, surface: viewModel.surface)
if viewModel.disabled { if viewModel.disabled {
toggleView.backgroundColor = enabled ? viewModel.on ? containerTintColor.on : containerTintColor.off : disabledTintColor.container toggleView.backgroundColor = viewModel.on ? toggleColor.on : toggleColor.off
knobView.backgroundColor = enabled ? viewModel.on ? knobTintColor.on : knobTintColor.off : disabledTintColor.knob knobView.backgroundColor = viewModel.on ? knobColor.on : knobColor.off
constrainKnob() constrainKnob()
} else { } else {
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: { UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: {
if viewModel.on { self.toggleView.backgroundColor = viewModel.on ? toggleColor.on : toggleColor.off
self.knobView.backgroundColor = self.knobTintColor.on self.knobView.backgroundColor = viewModel.on ? knobColor.on : knobColor.off
self.toggleView.backgroundColor = self.containerTintColor.on
} else {
self.knobView.backgroundColor = self.knobTintColor.off
self.toggleView.backgroundColor = self.containerTintColor.off
}
}, completion: nil) }, completion: nil)
UIView.animate(withDuration: 0.33, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.2, options: [], animations: { UIView.animate(withDuration: 0.33, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: [], animations: {
constrainKnob() constrainKnob()
}, completion: nil) }, completion: nil)
} }
backgroundColor = viewModel.surface == .dark ? VDSColor.backgroundPrimaryDark : .clear backgroundColor = viewModel.surface.color
isUserInteractionEnabled = !viewModel.disabled isUserInteractionEnabled = !viewModel.disabled
accessibilityHint = enabled ? viewModel.accessibilityHintEnabled :viewModel.accessibilityHintDisabled setAccessibilityHint(enabled)
accessibilityValue = viewModel.on ? viewModel.accessibilityValueEnabled : viewModel.accessibilityValueDisabled setAccessibilityValue(viewModel.on)
accessibilityLabel = viewModel.on ? viewModel.accessibilityLabelEnabled : viewModel.accessibilityLabelDisabled setAccessibilityLabel(viewModel.on)
setNeedsLayout() setNeedsLayout()
layoutIfNeeded() layoutIfNeeded()

View File

@ -14,7 +14,7 @@ extension VDSToggle {
} }
} }
public protocol VDSToggleModel: VDSLabelModel, FormFieldable, DataTrackable, Disabling, Accessable { public protocol VDSToggleModel: VDSLabelModel, FormFieldable, DataTrackable, Accessable, Initable {
var id: String? { get set } var id: String? { get set }
var showText: Bool { get set } var showText: Bool { get set }
var on: Bool { get set } var on: Bool { get set }
@ -32,7 +32,6 @@ extension VDSToggleModel {
public class DefaultToggleModel: DefaultLabelModel, VDSToggleModel { public class DefaultToggleModel: DefaultLabelModel, VDSToggleModel {
public var id: String? public var id: String?
public var inputId: String? public var inputId: String?
public var disabled: Bool = false
public var showText: Bool = false public var showText: Bool = false
public var on: Bool = false public var on: Bool = false
public var offText: String = "Off" public var offText: String = "Off"

View File

@ -7,6 +7,12 @@
import Foundation import Foundation
import UIKit import UIKit
import VDSColorTokens
extension VDSColor {
public static let elementsDisabledOnlight: UIColor = .init(hexString: "#D8DADA")
public static let elementsDisabledOnDark: UIColor = .init(hexString: "#333333")
}
extension UIColor { extension UIColor {
//-------------------------------------------------- //--------------------------------------------------
@ -143,5 +149,22 @@ extension UIColor {
return nil return nil
} }
public convenience init(hexString: String) {
let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
var int = UInt64()
Scanner(string: hex).scanHexInt64(&int)
let a, r, g, b: UInt64
switch hex.count {
case 3: // RGB (12-bit)
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
case 6: // RGB (24-bit)
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
case 8: // ARGB (32-bit)
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
default:
(a, r, g, b) = (255, 0, 0, 0)
}
self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
}
} }

View File

@ -18,7 +18,7 @@ public protocol Accessable {
} }
//Helpers to set within the UIControl //Helpers to set within the UIControl
extension Modelable where Self: UIControl { extension Modelable where Self: UIView {
private var accessableModel: Accessable? { private var accessableModel: Accessable? {
guard let model = self.model as? Accessable else { guard let model = self.model as? Accessable else {
return nil return nil

View File

@ -6,9 +6,14 @@
// //
import Foundation import Foundation
import UIKit
import VDSColorTokens
public enum Surface: String, Codable { public enum Surface: String, Codable {
case light, dark case light, dark
public var color: UIColor {
return self == .dark ? VDSColor.backgroundPrimaryDark : .clear
}
} }
public protocol Surfaceable { public protocol Surfaceable {

View File

@ -14,9 +14,8 @@ public protocol FontProtocol: CaseIterable, RawRepresentable, Hashable {
} }
extension FontProtocol { extension FontProtocol {
public func register() { public func register() {
guard let bundle = Bundle(identifier: "com.verizon.vega.metrics") else { return } guard let bundle = Bundle(identifier: "com.vzw.vds") else { return }
Self.allCases.forEach{ font in Self.allCases.forEach{ font in
if let url = bundle.url(forResource: font.fontName, withExtension: font.fontFileExtension){ if let url = bundle.url(forResource: font.fontName, withExtension: font.fontFileExtension){
do{ do{

View File

@ -21,7 +21,7 @@ public enum VDSFontWeight: String, Codable {
} }
} }
public enum VDSTextPosition: String, Codable { public enum VDSTextPosition: String, Codable, CaseIterable {
case left, right, center case left, right, center
var textAlignment: NSTextAlignment { var textAlignment: NSTextAlignment {
@ -36,7 +36,7 @@ public enum VDSTextPosition: String, Codable {
} }
} }
public enum VDSFontCategory: String, Codable { public enum VDSFontCategory: String, Codable, CaseIterable {
case feature case feature
case title case title
case body case body
@ -52,7 +52,7 @@ public enum VDSFontCategory: String, Codable {
} }
} }
public enum VDSFontSize: String, Codable { public enum VDSFontSize: String, Codable, CaseIterable {
case xxlarge case xxlarge
case xlarge case xlarge
case large case large
@ -72,7 +72,7 @@ public enum VDSFontSize: String, Codable {
} }
} }
public enum VDSFontStyle: String, Codable { public enum VDSFontStyle: String, Codable, CaseIterable {
public enum Error: Swift.Error { public enum Error: Swift.Error {
case fontNotFound case fontNotFound
} }