updated control to take in generic class

updated toggle to include this and make a abstract class and new subclass

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2022-07-30 10:33:23 -05:00
parent 482d3854a1
commit 49e84c5255
4 changed files with 51 additions and 58 deletions

View File

@ -7,8 +7,21 @@
import Foundation
import UIKit
import Combine
open class VDSControl: UIControl, ViewProtocol {
open class VDSControl<ModelType>: UIControl, Modelable, ViewProtocol {
@Published public var model: ModelType
private var cancellable: AnyCancellable?
open func set(with model: ModelType) {
self.model = model
}
open func onStateChange(viewModel: ModelType) {
}
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -18,18 +31,14 @@ open class VDSControl: UIControl, ViewProtocol {
// MARK: - Initializers
//--------------------------------------------------
public override init(frame: CGRect) {
super.init(frame: .zero)
initialSetup()
}
public init() {
required public init(with model: ModelType) {
self.model = model
super.init(frame: .zero)
initialSetup()
set(with: model)
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("Control does not support xib.")
}
@ -42,6 +51,9 @@ open class VDSControl: UIControl, ViewProtocol {
initialSetupPerformed = true
setupView()
}
cancellable = $model.debounce(for: .seconds(ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in
self?.onStateChange(viewModel: viewModel)
}
}
open func reset() {

View File

@ -10,7 +10,8 @@ import UIKit
import VDSColorTokens
import Combine
open class VDSLabel: UILabel, Modelable {
open class VDSLabel: UILabel, Modelable, Initable {
@Published public var model: VDSLabelModel = DefaultLabelModel()
private var cancellable: AnyCancellable?
@ -30,10 +31,16 @@ open class VDSLabel: UILabel, Modelable {
public var surface: Surface
//Initializers
public convenience init() {
required public convenience init() {
self.init(frame: .zero)
}
public required convenience init(with model: VDSLabelModel) {
self.init()
self.model = model
set(with: model)
}
public override init(frame: CGRect) {
super.init(frame: frame)
setup()

View File

@ -17,11 +17,22 @@ import Combine
Container: The background of the toggle control.
Knob: The circular indicator that slides on the container.
*/
@objcMembers open class VDSToggle: VDSControl, Modelable, Changable {
public typealias ModelType = VDSToggleModel
@Published public var model: ModelType = DefaultToggleModel()
private var cancellable: AnyCancellable?
final public class VDSToggle: VDSToggleBase<DefaultToggleModel>{
public convenience init() {
self.init(with: DefaultToggleModel())
}
required public init(with model: ModelType) {
super.init(with: model)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
@objcMembers open class VDSToggleBase<ModelType: VDSToggleModel>: VDSControl<ModelType>, Changable {
//--------------------------------------------------
// MARK: - Private Properties
@ -76,8 +87,8 @@ import Combine
// MARK: - Static Properties
//--------------------------------------------------
// Sizes are from InVision design specs.
public static var toggleSize = CGSize(width: 52, height: 24)
public static var knobSize = CGSize(width: 20, height: 20)
public let toggleSize = CGSize(width: 52, height: 24)
public let knobSize = CGSize(width: 20, height: 20)
//--------------------------------------------------
// MARK: - Computed Properties
@ -103,7 +114,7 @@ import Combine
@Proxy(\.model.surface)
public var surface: Surface
@Proxy(\VDSToggle.model.on)
@Proxy(\.model.on)
open var isOn: Bool
open override var isEnabled: Bool {
@ -128,29 +139,6 @@ import Combine
private var toggleHeightConstraint: NSLayoutConstraint?
private var toggleWidthConstraint: NSLayoutConstraint?
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
public convenience override init() {
self.init(frame: .zero)
setup()
}
func setup() {
cancellable = $model.debounce(for: .seconds(ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in
self?.onStateChange(viewModel: viewModel)
}
}
//functions
//--------------------------------------------------
// MARK: - Lifecycle
@ -159,9 +147,6 @@ import Combine
public override func updateView(_ size: CGFloat) {
super.updateView(size)
let toggleSize = Self.toggleSize
let knobSize = Self.knobSize
toggleHeightConstraint?.constant = toggleSize.height
toggleWidthConstraint?.constant = toggleSize.width
@ -185,9 +170,6 @@ import Combine
addSubview(stackView)
let toggleSize = Self.toggleSize
let knobSize = Self.knobSize
toggleHeightConstraint = toggleView.heightAnchor.constraint(equalToConstant: toggleSize.height)
toggleHeightConstraint?.isActive = true
@ -209,10 +191,6 @@ import Combine
knobView.topAnchor.constraint(greaterThanOrEqualTo: toggleView.topAnchor).isActive = true
toggleView.bottomAnchor.constraint(greaterThanOrEqualTo: knobView.bottomAnchor).isActive = true
//setup stackview
if showText {
stackView.addArrangedSubview(label)
}
ensureLabel()
stackView.addArrangedSubview(toggleView)
stackView.topAnchor.constraint(equalTo: topAnchor).isActive = true
@ -310,14 +288,14 @@ import Combine
public func knobReformAnimation() {
UIView.animate(withDuration: 0.1, animations: {
self.knobWidthConstraint?.constant = Self.knobSize.width
self.knobWidthConstraint?.constant = self.knobSize.width
self.layoutIfNeeded()
}, completion: nil)
}
/// Follow the SwiftUI View paradigm
/// - Parameter viewModel: state
private func onStateChange(viewModel: ModelType) {
open override func onStateChange(viewModel: ModelType) {
let enabled = !viewModel.disabled
label.set(with: viewModel)
@ -339,7 +317,7 @@ import Combine
}
self.knobTrailingConstraint?.isActive = true
self.knobLeadingConstraint?.isActive = true
self.knobWidthConstraint?.constant = Self.knobSize.width
self.knobWidthConstraint?.constant = self.knobSize.width
self.layoutIfNeeded()
}
@ -374,9 +352,4 @@ import Combine
setNeedsLayout()
layoutIfNeeded()
}
// MARK:- Modable
open func set(with model: ModelType) {
self.model = model
}
}

View File

@ -12,5 +12,6 @@ public let ModelStateDebounce = 0.02
public protocol Modelable {
associatedtype ModelType
var model: ModelType { get set }
init(with model: ModelType)
func set(with model: ModelType)
}