diff --git a/VDS/Classes/VDSControl.swift b/VDS/Classes/VDSControl.swift index ec48eb74..3ce9dc1d 100644 --- a/VDS/Classes/VDSControl.swift +++ b/VDS/Classes/VDSControl.swift @@ -9,7 +9,7 @@ import Foundation import UIKit import Combine -open class VDSControl: UIControl, Modelable, ViewProtocol { +open class VDSControl: UIControl, Modelable, ViewProtocol { @Published public var model: ModelType private var cancellable: AnyCancellable? @@ -39,7 +39,9 @@ open class VDSControl: UIControl, Modelable, ViewProtocol { } public required init?(coder: NSCoder) { - fatalError("Control does not support xib.") + self.model = ModelType.init() + super.init(coder: coder) + initialSetup() } //-------------------------------------------------- diff --git a/VDS/Components/Label/VDSLabel.swift b/VDS/Components/Label/VDSLabel.swift index e6f1d630..91556d4b 100644 --- a/VDS/Components/Label/VDSLabel.swift +++ b/VDS/Components/Label/VDSLabel.swift @@ -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 private func onStateChange(viewModel: VDSLabelModel) { 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 { font = VDSFontStyle.RegularBodyLarge.font diff --git a/VDS/Components/Label/VDSLabelModel.swift b/VDS/Components/Label/VDSLabelModel.swift index 1958b84c..721f87ea 100644 --- a/VDS/Components/Label/VDSLabelModel.swift +++ b/VDS/Components/Label/VDSLabelModel.swift @@ -8,14 +8,15 @@ import Foundation import UIKit -public protocol VDSLabelModel: Labelable, Surfaceable { +public protocol VDSLabelModel: Labelable, Surfaceable, Disabling { } open class DefaultLabelModel: VDSLabelModel { public var fontCategory: VDSFontCategory = .body - public var fontSize: VDSFontSize = .large + public var fontSize: VDSFontSize = .small public var fontWeight: VDSFontWeight = .regular public var textPosition: VDSTextPosition = .left public var surface: Surface = .light + public var disabled: Bool = false required public init(){} } diff --git a/VDS/Components/Toggle/VDSToggle.swift b/VDS/Components/Toggle/VDSToggle.swift index e5ed5777..28f2ce29 100644 --- a/VDS/Components/Toggle/VDSToggle.swift +++ b/VDS/Components/Toggle/VDSToggle.swift @@ -18,7 +18,7 @@ import Combine Knob: The circular indicator that slides on the container. */ -final public class VDSToggle: VDSToggleBase{ +@objcMembers public class VDSToggle: VDSToggleBase{ public convenience init() { self.init(with: DefaultToggleModel()) } @@ -37,15 +37,46 @@ final public class VDSToggle: VDSToggleBase{ //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - /// Holds the on and off colors for the container. - private var containerTintColor: (on: UIColor, off: UIColor) = (on: VDSColor.paletteGreen26, off: VDSColor.paletteGray44) + private var toggleTintColor: (on: UIColor, off: UIColor) { + return getToggleColor(for: disabled, surface: surface) + } - /// Holds the on and off colors for the knob. - private var knobTintColor: (on: UIColor, off: UIColor) = (on: VDSColor.paletteWhite, off: VDSColor.paletteWhite) + private var knobTintColor: (on: UIColor, off: UIColor) { + 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 { showText ? 12 : 0 } @@ -94,7 +125,13 @@ final public class VDSToggle: VDSToggleBase{ // MARK: - Computed Properties //-------------------------------------------------- @Proxy(\.model.showText) - public var showText: Bool + public var showText: Bool { + didSet { + if oldValue != showText { + ensureLabel() + } + } + } @Proxy(\.model.onText) public var onText: String @@ -103,7 +140,13 @@ final public class VDSToggle: VDSToggleBase{ public var offText: String @Proxy(\.model.textPosition) - public var textPosition: VDSTextPosition + public var textPosition: VDSTextPosition { + didSet { + if oldValue != textPosition { + ensureLabel() + } + } + } @Proxy(\.model.fontSize) public var fontSize: VDSFontSize @@ -117,6 +160,9 @@ final public class VDSToggle: VDSToggleBase{ @Proxy(\.model.on) open var isOn: Bool + @Proxy(\.model.disabled) + open var disabled: Bool + open override var isEnabled: Bool { get { !model.disabled } set { @@ -164,10 +210,7 @@ final public class VDSToggle: VDSToggleBase{ super.setupView() isAccessibilityElement = true - setAccessibilityHint() - setAccessibilityLabel() accessibilityTraits = .button - addSubview(stackView) toggleHeightConstraint = toggleView.heightAnchor.constraint(equalToConstant: toggleSize.height) @@ -179,7 +222,7 @@ final public class VDSToggle: VDSToggleBase{ toggleView.layer.cornerRadius = toggleSize.height / 2.0 knobView.layer.cornerRadius = knobSize.height / 2.0 - toggleView.backgroundColor = containerTintColor.off + toggleView.backgroundColor = toggleTintColor.off toggleView.addSubview(knobView) @@ -216,7 +259,7 @@ final public class VDSToggle: VDSToggleBase{ public override func reset() { super.reset() - toggleView.backgroundColor = containerTintColor.off + toggleView.backgroundColor = toggleTintColor.off knobView.backgroundColor = knobTintColor.off setAccessibilityLabel() onChange = nil @@ -262,22 +305,16 @@ final public class VDSToggle: VDSToggleBase{ } public override func touchesEnded(_ touches: Set, with event: UIEvent?) { - knobReformAnimation() - // Action only occurs of the user lifts up from withing acceptable region of the toggle. - guard let coordinates = touches.first?.location(in: self), - coordinates.x > -20, - coordinates.x < bounds.width + 20, - coordinates.y > -20, - coordinates.y < bounds.height + 20 - else { return } + let value = 20.0 + guard let coordinates = touches.first?.location(in: self) else { return } + guard coordinates.x > -value else { return } sendActions(for: .touchUpInside) } - public func touchesCancelled(_ touches: Set, with event: UIEvent) { - + open override func touchesCancelled(_ touches: Set, with event: UIEvent?) { knobReformAnimation() sendActions(for: .touchCancel) } @@ -297,7 +334,7 @@ final public class VDSToggle: VDSToggleBase{ /// - Parameter viewModel: state open override func onStateChange(viewModel: ModelType) { let enabled = !viewModel.disabled - + label.set(with: viewModel) label.text = viewModel.on ? viewModel.onText : viewModel.offText @@ -321,33 +358,30 @@ final public class VDSToggle: VDSToggleBase{ self.layoutIfNeeded() } + let toggleColor = getToggleColor(for: viewModel.disabled, surface: viewModel.surface) + let knobColor = getKnobColor(for: viewModel.disabled, surface: viewModel.surface) + if viewModel.disabled { - toggleView.backgroundColor = enabled ? viewModel.on ? containerTintColor.on : containerTintColor.off : disabledTintColor.container - knobView.backgroundColor = enabled ? viewModel.on ? knobTintColor.on : knobTintColor.off : disabledTintColor.knob + toggleView.backgroundColor = viewModel.on ? toggleColor.on : toggleColor.off + knobView.backgroundColor = viewModel.on ? knobColor.on : knobColor.off constrainKnob() } else { UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: { - if viewModel.on { - self.knobView.backgroundColor = self.knobTintColor.on - self.toggleView.backgroundColor = self.containerTintColor.on - - } else { - self.knobView.backgroundColor = self.knobTintColor.off - self.toggleView.backgroundColor = self.containerTintColor.off - } + self.toggleView.backgroundColor = viewModel.on ? toggleColor.on : toggleColor.off + self.knobView.backgroundColor = viewModel.on ? knobColor.on : knobColor.off }, 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() }, completion: nil) } - backgroundColor = viewModel.surface == .dark ? VDSColor.backgroundPrimaryDark : .clear + backgroundColor = viewModel.surface.color isUserInteractionEnabled = !viewModel.disabled - accessibilityHint = enabled ? viewModel.accessibilityHintEnabled :viewModel.accessibilityHintDisabled - accessibilityValue = viewModel.on ? viewModel.accessibilityValueEnabled : viewModel.accessibilityValueDisabled - accessibilityLabel = viewModel.on ? viewModel.accessibilityLabelEnabled : viewModel.accessibilityLabelDisabled + setAccessibilityHint(enabled) + setAccessibilityValue(viewModel.on) + setAccessibilityLabel(viewModel.on) setNeedsLayout() layoutIfNeeded() diff --git a/VDS/Components/Toggle/VDSToggleModel.swift b/VDS/Components/Toggle/VDSToggleModel.swift index 41c14372..c335fdfb 100644 --- a/VDS/Components/Toggle/VDSToggleModel.swift +++ b/VDS/Components/Toggle/VDSToggleModel.swift @@ -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 showText: Bool { get set } var on: Bool { get set } @@ -32,7 +32,6 @@ extension VDSToggleModel { public class DefaultToggleModel: DefaultLabelModel, VDSToggleModel { public var id: String? public var inputId: String? - public var disabled: Bool = false public var showText: Bool = false public var on: Bool = false public var offText: String = "Off" diff --git a/VDS/Extensions/UIColor.swift b/VDS/Extensions/UIColor.swift index 66142845..63c0cc57 100644 --- a/VDS/Extensions/UIColor.swift +++ b/VDS/Extensions/UIColor.swift @@ -7,6 +7,12 @@ import Foundation import UIKit +import VDSColorTokens + +extension VDSColor { + public static let elementsDisabledOnlight: UIColor = .init(hexString: "#D8DADA") + public static let elementsDisabledOnDark: UIColor = .init(hexString: "#333333") +} extension UIColor { //-------------------------------------------------- @@ -143,5 +149,22 @@ extension UIColor { 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) + } } diff --git a/VDS/Protocols/Accessable.swift b/VDS/Protocols/Accessable.swift index 7fa273fc..67905b27 100644 --- a/VDS/Protocols/Accessable.swift +++ b/VDS/Protocols/Accessable.swift @@ -18,7 +18,7 @@ public protocol Accessable { } //Helpers to set within the UIControl -extension Modelable where Self: UIControl { +extension Modelable where Self: UIView { private var accessableModel: Accessable? { guard let model = self.model as? Accessable else { return nil diff --git a/VDS/Protocols/Surfaceable.swift b/VDS/Protocols/Surfaceable.swift index 4988a146..c00fd04c 100644 --- a/VDS/Protocols/Surfaceable.swift +++ b/VDS/Protocols/Surfaceable.swift @@ -6,9 +6,14 @@ // import Foundation +import UIKit +import VDSColorTokens public enum Surface: String, Codable { case light, dark + public var color: UIColor { + return self == .dark ? VDSColor.backgroundPrimaryDark : .clear + } } public protocol Surfaceable { diff --git a/VDS/Typography/FontProtocol.swift b/VDS/Typography/FontProtocol.swift index 48b6bf43..9524f2a4 100644 --- a/VDS/Typography/FontProtocol.swift +++ b/VDS/Typography/FontProtocol.swift @@ -14,9 +14,8 @@ public protocol FontProtocol: CaseIterable, RawRepresentable, Hashable { } extension FontProtocol { - 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 if let url = bundle.url(forResource: font.fontName, withExtension: font.fontFileExtension){ do{ diff --git a/VDS/Typography/VDSFontStyles.swift b/VDS/Typography/VDSFontStyles.swift index f4f1daef..0851b97a 100644 --- a/VDS/Typography/VDSFontStyles.swift +++ b/VDS/Typography/VDSFontStyles.swift @@ -21,7 +21,7 @@ public enum VDSFontWeight: String, Codable { } } -public enum VDSTextPosition: String, Codable { +public enum VDSTextPosition: String, Codable, CaseIterable { case left, right, center 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 title 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 xlarge 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 { case fontNotFound }