converted to VDS
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
fa52fa8c12
commit
10c55b12be
@ -7,37 +7,35 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import VDSCoreTokens
|
||||
import VDS
|
||||
|
||||
@objcMembers open class RadioButton: Control, MFButtonProtocol {
|
||||
//--------------------------------------------------
|
||||
@objcMembers open class RadioButton: VDS.RadioButton, RadioButtonSelectionHelperProtocol, VDSMoleculeViewProtocol, MFButtonProtocol, MVMCoreUIViewConstrainingProtocol {
|
||||
//------------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var diameter: CGFloat = 20 {
|
||||
didSet { widthConstraint?.constant = diameter }
|
||||
//------------------------------------------------------
|
||||
open var viewModel: RadioButtonModel!
|
||||
open var delegateObject: MVMCoreUIDelegateObject?
|
||||
open var additionalData: [AnyHashable : Any]?
|
||||
|
||||
open var radioButtonModel: RadioButtonModel {
|
||||
viewModel
|
||||
}
|
||||
|
||||
@objc public override var isSelected: Bool {
|
||||
// Form Validation
|
||||
var fieldKey: String?
|
||||
var fieldValue: JSONValue?
|
||||
var groupName: String?
|
||||
|
||||
open override var isSelected: Bool {
|
||||
didSet {
|
||||
radioModel?.state = isSelected
|
||||
updateAccessibilityLabel()
|
||||
viewModel.state = isSelected
|
||||
if oldValue != isSelected {
|
||||
sendActions(for: .valueChanged)
|
||||
}
|
||||
}
|
||||
}
|
||||
public var enabledColor: UIColor {
|
||||
return radioModel?.inverted ?? false ? VDSColor.elementsPrimaryOndark : VDSColor.elementsPrimaryOnlight
|
||||
}
|
||||
public var disabledColor: UIColor {
|
||||
return radioModel?.inverted ?? false ? VDSColor.interactiveDisabledOndark : VDSColor.interactiveDisabledOnlight
|
||||
}
|
||||
public var delegateObject: MVMCoreUIDelegateObject?
|
||||
var additionalData: [AnyHashable: Any]?
|
||||
|
||||
public var radioModel: RadioButtonModel? {
|
||||
model as? RadioButtonModel
|
||||
}
|
||||
|
||||
lazy public var radioGroupName: String? = { radioModel?.fieldKey }()
|
||||
|
||||
lazy public var radioGroupName: String? = { viewModel.fieldKey }()
|
||||
|
||||
lazy public var radioButtonSelectionHelper: RadioButtonSelectionHelper? = {
|
||||
|
||||
@ -48,132 +46,120 @@ import VDSCoreTokens
|
||||
return radioButtonModel
|
||||
}()
|
||||
|
||||
public override var isEnabled: Bool {
|
||||
didSet {
|
||||
isUserInteractionEnabled = isEnabled
|
||||
setNeedsDisplay()
|
||||
}
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
|
||||
public var widthConstraint: NSLayoutConstraint?
|
||||
public var heightConstraint: NSLayoutConstraint?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func draw(_ rect: CGRect) {
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
let color = isEnabled == false ? disabledColor.cgColor : enabledColor.cgColor
|
||||
layer.cornerRadius = bounds.width * 0.5
|
||||
layer.borderColor = color
|
||||
layer.borderWidth = bounds.width * 0.0333
|
||||
|
||||
if isSelected {
|
||||
// Space around inner circle is 1/5 the size
|
||||
context.addEllipse(in: CGRect(x: bounds.width * 0.2,
|
||||
y: bounds.height * 0.2,
|
||||
width: bounds.width * 0.6,
|
||||
height: bounds.height * 0.6))
|
||||
context.setFillColor(color)
|
||||
context.fillPath()
|
||||
}
|
||||
/// There is currently no intention on using xib files.
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
fatalError("xib file is not implemented for Checkbox.")
|
||||
}
|
||||
|
||||
public convenience required init() {
|
||||
self.init(frame:.zero)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
/// The action performed when tapped.
|
||||
func tapAction() {
|
||||
if !isEnabled {
|
||||
return
|
||||
public func isValidField() -> Bool { isSelected }
|
||||
|
||||
public func formFieldName() -> String? {
|
||||
viewModel.fieldKey
|
||||
}
|
||||
|
||||
public func formFieldGroupName() -> String? {
|
||||
viewModel.fieldKey
|
||||
}
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard let radioModel = viewModel, radioModel.enabled else { return nil }
|
||||
return radioModel.fieldValue
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
bridge_accessibilityLabelBlock = { [weak self] in
|
||||
guard let self else { return nil }
|
||||
if let message = MVMCoreUIUtility.hardcodedString(withKey: "radio_button"),
|
||||
let selectedState = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "radio_selected_state" : "radio_not_selected_state") {
|
||||
return message + selectedState
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint")
|
||||
}
|
||||
|
||||
open override func toggle() {
|
||||
guard !isSelected, isEnabled else { return }
|
||||
|
||||
//removed error
|
||||
if showError && isSelected == false {
|
||||
showError.toggle()
|
||||
}
|
||||
|
||||
let wasPreviouslySelected = isSelected
|
||||
if let radioButtonModel = radioButtonSelectionHelper {
|
||||
radioButtonModel.selected(self)
|
||||
if let radioButtonSelectionHelper {
|
||||
radioButtonSelectionHelper.selected(self)
|
||||
} else {
|
||||
isSelected = !isSelected
|
||||
}
|
||||
|
||||
if let radioModel = radioModel, let actionModel = radioModel.action, isSelected, !wasPreviouslySelected {
|
||||
if let actionModel = viewModel.action, isSelected, !wasPreviouslySelected {
|
||||
Task(priority: .userInitiated) {
|
||||
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioModel)
|
||||
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
public func isValidField() -> Bool { isSelected }
|
||||
|
||||
public func formFieldName() -> String? {
|
||||
radioModel?.fieldKey
|
||||
}
|
||||
|
||||
public func formFieldGroupName() -> String? {
|
||||
radioModel?.fieldKey
|
||||
}
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard let radioModel = radioModel, radioModel.enabled else { return nil }
|
||||
return radioModel.fieldValue
|
||||
setNeedsUpdate()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
// MARK: - Actions
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Adjust accessibility label based on state of RadioButton.
|
||||
func updateAccessibilityLabel() {
|
||||
if let message = MVMCoreUIUtility.hardcodedString(withKey: "radio_button"),
|
||||
let selectedState = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "radio_selected_state" : "radio_not_selected_state") {
|
||||
accessibilityLabel = message + selectedState
|
||||
/// This will toggle the state of the Checkbox and execute the actionBlock if provided.
|
||||
public func tapAction() {
|
||||
toggle()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Molecular
|
||||
//--------------------------------------------------
|
||||
|
||||
open func needsToBeConstrained() -> Bool { true }
|
||||
|
||||
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
|
||||
|
||||
public func updateView(_ size: CGFloat) {}
|
||||
|
||||
public func viewModelDidUpdate() {
|
||||
|
||||
//events
|
||||
viewModel.updateUI = {
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
||||
guard let self = self else { return }
|
||||
let isValid = viewModel.isValid ?? true
|
||||
showError = !isValid
|
||||
isEnabled = viewModel.enabled
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MVMViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
backgroundColor = .clear
|
||||
clipsToBounds = true
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: 20)
|
||||
widthConstraint?.isActive = true
|
||||
heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1)
|
||||
heightConstraint?.isActive = true
|
||||
|
||||
addTarget(self, action: #selector(tapAction), for: .touchUpInside)
|
||||
isAccessibilityElement = true
|
||||
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint")
|
||||
accessibilityTraits = .button
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
self.delegateObject = delegateObject
|
||||
self.additionalData = additionalData
|
||||
|
||||
guard let model = model as? RadioButtonModel else { return }
|
||||
|
||||
isSelected = model.state
|
||||
isEnabled = model.enabled && !model.readOnly
|
||||
RadioButtonSelectionHelper.setupForRadioButtonGroup(model, self, delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
backgroundColor = .clear
|
||||
|
||||
isSelected = viewModel.state
|
||||
isEnabled = viewModel.enabled && !viewModel.readOnly
|
||||
RadioButtonSelectionHelper.setupForRadioButtonGroup(viewModel, self, delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,47 +7,31 @@
|
||||
//
|
||||
|
||||
import MVMCore
|
||||
import VDS
|
||||
|
||||
|
||||
open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
open class RadioButtonModel: FormFieldModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "radioButton"
|
||||
public var id: String = UUID().uuidString
|
||||
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public static override var identifier: String { "radioButton" }
|
||||
public var state: Bool = false
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
|
||||
/// The specific value to send to server. TODO: update this to be more generic.
|
||||
public var fieldValue: String?
|
||||
|
||||
public var baseValue: AnyHashable?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var fieldKey: String?
|
||||
public var action: ActionModelProtocol?
|
||||
public var inverted: Bool = false
|
||||
|
||||
public var surface: Surface { inverted ? .dark : .light }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case state
|
||||
case enabled
|
||||
case fieldValue
|
||||
case fieldKey
|
||||
case groupName
|
||||
case action
|
||||
case readOnly
|
||||
case inverted
|
||||
}
|
||||
|
||||
@ -56,49 +40,41 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(_ state: Bool) {
|
||||
super.init()
|
||||
self.state = state
|
||||
baseValue = state
|
||||
self.baseValue = state
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
public override func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
return fieldValue
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Server Value
|
||||
//--------------------------------------------------
|
||||
open func formFieldServerValue() -> AnyHashable? {
|
||||
return formFieldValue()
|
||||
open override func setValidity(_ valid: Bool, errorMessage: String?) {
|
||||
if let ruleErrorMessage = errorMessage, fieldKey != nil {
|
||||
self.errorMessage = ruleErrorMessage
|
||||
}
|
||||
isValid = valid
|
||||
updateUI?()
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
try super.init(from: decoder)
|
||||
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
|
||||
|
||||
if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) {
|
||||
self.state = state
|
||||
}
|
||||
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
baseValue = state
|
||||
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
|
||||
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
|
||||
if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
|
||||
@ -106,17 +82,10 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(id, forKey: .id)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(state, forKey: .state)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
try container.encodeIfPresent(inverted, forKey: .inverted)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user