Merge branch 'feature/atomic-vds-radioButton' into 'develop'
VDS Brand 3.0 Radiobutton ### Summary VDS Brand 3.0 Radiobutton, RadiobuttonItem for IOS * RadiobuttonGroup will be a later integration since this is not in the app at this time. ### JIRA Ticket https://onejira.verizon.com/browse/ONEAPP-7004 Co-authored-by: Matt Bruce <matt.bruce@verizon.com> See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1153
This commit is contained in:
commit
fa650bafb5
@ -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
|
||||
open var fieldKey: String?
|
||||
open var fieldValue: JSONValue?
|
||||
open 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,108 @@ 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
|
||||
//--------------------------------------------------
|
||||
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
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
isSelected = viewModel.state
|
||||
isEnabled = viewModel.enabled && !viewModel.readOnly
|
||||
RadioButtonSelectionHelper.setupForRadioButtonGroup(viewModel, self, delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
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: - MVMViewProtocol
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
open func needsToBeConstrained() -> Bool { true }
|
||||
|
||||
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 func horizontalAlignment() -> UIStackView.Alignment { .leading }
|
||||
|
||||
public func updateView(_ size: CGFloat) {}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,48 +7,29 @@
|
||||
//
|
||||
|
||||
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
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// 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,69 +37,50 @@ 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) {
|
||||
self.inverted = inverted
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,10 @@
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
public protocol RadioButtonSelectionHelperProtocol: AnyObject {
|
||||
var isSelected: Bool { get set }
|
||||
var radioButtonModel: RadioButtonModel { get }
|
||||
}
|
||||
|
||||
@objcMembers public class RadioButtonSelectionHelper: FormFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -14,7 +18,7 @@
|
||||
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
private var selectedRadioButton: RadioButton?
|
||||
private var selectedRadioButton: RadioButtonSelectionHelperProtocol?
|
||||
private var selectedRadioButtonModel: RadioButtonModel?
|
||||
public var baseValue: AnyHashable?
|
||||
public var enabled: Bool = true
|
||||
@ -24,7 +28,7 @@
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public func set(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton) {
|
||||
public func set(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButtonSelectionHelperProtocol) {
|
||||
self.fieldKey = radioButtonModel.fieldKey
|
||||
self.groupName = radioButtonModel.groupName
|
||||
|
||||
@ -49,7 +53,7 @@
|
||||
// MARK: - Functions
|
||||
//--------------------------------------------------
|
||||
|
||||
public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton, delegateObject: MVMCoreUIDelegateObject?) {
|
||||
public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButtonSelectionHelperProtocol, delegateObject: MVMCoreUIDelegateObject?) {
|
||||
|
||||
guard let groupName = radioButtonModel.fieldKey,
|
||||
let formValidator = delegateObject?.formHolderDelegate?.formValidator
|
||||
@ -61,10 +65,10 @@
|
||||
FormValidator.setupValidation(for: radioButtonSelectionHelper, delegate: delegateObject?.formHolderDelegate)
|
||||
}
|
||||
|
||||
public func selected(_ radioButton: RadioButton) {
|
||||
public func selected(_ radioButton: RadioButtonSelectionHelperProtocol) {
|
||||
|
||||
// Checks because the view could be reused
|
||||
if selectedRadioButton?.radioModel === selectedRadioButtonModel {
|
||||
if selectedRadioButton?.radioButtonModel === selectedRadioButtonModel {
|
||||
selectedRadioButton?.isSelected = false
|
||||
} else {
|
||||
selectedRadioButtonModel?.state = false
|
||||
@ -72,7 +76,7 @@
|
||||
|
||||
selectedRadioButton = radioButton
|
||||
selectedRadioButton?.isSelected = true
|
||||
selectedRadioButtonModel = selectedRadioButton?.radioModel
|
||||
selectedRadioButtonModel = selectedRadioButton?.radioButtonModel
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -81,9 +81,7 @@
|
||||
func updateAccessibilityLabel() {
|
||||
|
||||
var message = ""
|
||||
|
||||
radioButton.updateAccessibilityLabel()
|
||||
|
||||
|
||||
if let radioButtonLabel = radioButton.accessibilityLabel {
|
||||
message += radioButtonLabel + ", "
|
||||
}
|
||||
|
||||
@ -98,9 +98,7 @@ import UIKit
|
||||
func updateAccessibilityLabel() {
|
||||
|
||||
var message = ""
|
||||
|
||||
radioButton.updateAccessibilityLabel()
|
||||
|
||||
|
||||
if let radioButtonLabel = radioButton.accessibilityLabel {
|
||||
message += radioButtonLabel + ", "
|
||||
}
|
||||
|
||||
@ -85,7 +85,6 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell {
|
||||
|
||||
var message = ""
|
||||
|
||||
radioButton.updateAccessibilityLabel()
|
||||
if let radioButtonLabel = radioButton.accessibilityLabel {
|
||||
message += radioButtonLabel + ", "
|
||||
}
|
||||
|
||||
@ -7,54 +7,121 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import VDS
|
||||
|
||||
@objcMembers public class RadioButtonLabel: VDS.RadioButtonItem, RadioButtonSelectionHelperProtocol, VDSMoleculeViewProtocol, MFButtonProtocol {
|
||||
|
||||
@objcMembers public class RadioButtonLabel: View {
|
||||
|
||||
public let radioButton = RadioButton()
|
||||
var delegateObject: MVMCoreUIDelegateObject?
|
||||
let label = Label()
|
||||
|
||||
public override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
radioButton.updateView(size)
|
||||
label.updateView(size)
|
||||
}
|
||||
//------------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//------------------------------------------------------
|
||||
open var viewModel: RadioButtonLabelModel!
|
||||
open var delegateObject: MVMCoreUIDelegateObject?
|
||||
open var additionalData: [AnyHashable : Any]?
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
open var radioButtonModel: RadioButtonModel {
|
||||
viewModel.radioButton
|
||||
}
|
||||
|
||||
addSubview(radioButton)
|
||||
radioButton.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor, constant: 0).isActive = true
|
||||
radioButton.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor, constant: PaddingOne).isActive = true
|
||||
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: radioButton.bottomAnchor, constant: PaddingOne).isActive = true
|
||||
radioButton.centerYAnchor.constraint(equalTo: layoutMarginsGuide.centerYAnchor).isActive = true
|
||||
// Form Validation
|
||||
var fieldKey: String?
|
||||
var fieldValue: JSONValue?
|
||||
var groupName: String?
|
||||
|
||||
if let rightView = createRightView() {
|
||||
addSubview(rightView)
|
||||
rightView.leftAnchor.constraint(equalTo: radioButton.rightAnchor, constant: Padding.Component.gutterForApplicationWidth).isActive = true
|
||||
rightView.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor, constant: 0).isActive = true
|
||||
|
||||
var constraint = rightView.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor, constant: PaddingOne)
|
||||
constraint.priority = .defaultHigh
|
||||
constraint.isActive = true
|
||||
|
||||
constraint = layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: rightView.bottomAnchor, constant: PaddingOne)
|
||||
constraint.priority = .defaultHigh
|
||||
constraint.isActive = true
|
||||
layoutMarginsGuide.centerYAnchor.constraint(equalTo: rightView.centerYAnchor).isActive = true
|
||||
open override var isSelected: Bool {
|
||||
didSet {
|
||||
radioButtonModel.state = isSelected
|
||||
if oldValue != isSelected {
|
||||
sendActions(for: .valueChanged)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createRightView() -> Container? {
|
||||
let rightView = Container(andContain: label)
|
||||
return rightView
|
||||
lazy public var radioGroupName: String? = { viewModel.radioButton.fieldKey }()
|
||||
|
||||
lazy public var radioButtonSelectionHelper: RadioButtonSelectionHelper? = {
|
||||
|
||||
guard let radioGroupName = radioGroupName,
|
||||
let radioButtonModel = delegateObject?.formHolderDelegate?.formValidator?.radioButtonsModelByGroup[radioGroupName]
|
||||
else { return nil }
|
||||
|
||||
return radioButtonModel
|
||||
}()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Life Cycle
|
||||
//--------------------------------------------------
|
||||
@objc open func updateView(_ size: CGFloat) {}
|
||||
|
||||
open override func toggle() {
|
||||
guard !isSelected, isEnabled else { return }
|
||||
|
||||
//removed error
|
||||
if showError && isSelected == false {
|
||||
showError.toggle()
|
||||
}
|
||||
|
||||
let wasPreviouslySelected = isSelected
|
||||
if let radioButtonSelectionHelper {
|
||||
radioButtonSelectionHelper.selected(self)
|
||||
} else {
|
||||
isSelected = !isSelected
|
||||
}
|
||||
|
||||
if let actionModel = viewModel.radioButton.action, isSelected, !wasPreviouslySelected {
|
||||
Task(priority: .userInitiated) {
|
||||
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: viewModel)
|
||||
}
|
||||
}
|
||||
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
guard let radioButtonLabelModel = model as? RadioButtonLabelModel else { return }
|
||||
|
||||
radioButton.set(with: radioButtonLabelModel.radioButton, delegateObject, additionalData)
|
||||
label.set(with: radioButtonLabelModel.label, delegateObject, additionalData)
|
||||
//--------------------------------------------------
|
||||
// MARK: - Atomic
|
||||
//--------------------------------------------------
|
||||
public func viewModelDidUpdate() {
|
||||
surface = viewModel.surface
|
||||
|
||||
updateRadioButton()
|
||||
|
||||
//primary label
|
||||
labelText = viewModel.label.text
|
||||
if let attributes = viewModel.label.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) {
|
||||
labelTextAttributes = attributes
|
||||
}
|
||||
|
||||
//secondary label
|
||||
if let subTitleModel = viewModel.subTitle {
|
||||
childText = subTitleModel.text
|
||||
if let attributes = subTitleModel.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) {
|
||||
childTextAttributes = attributes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func updateRadioButton() {
|
||||
|
||||
if let fieldKey = viewModel.radioButton.fieldKey {
|
||||
self.fieldKey = fieldKey
|
||||
}
|
||||
|
||||
//properties
|
||||
isEnabled = viewModel.radioButton.enabled && !viewModel.radioButton.readOnly
|
||||
isSelected = viewModel.radioButton.state
|
||||
|
||||
//forms
|
||||
RadioButtonSelectionHelper.setupForRadioButtonGroup(viewModel.radioButton, self, delegateObject: delegateObject)
|
||||
|
||||
//events
|
||||
viewModel.radioButton.updateUI = {
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
||||
guard let self = self else { return }
|
||||
let isValid = viewModel.radioButton.isValid ?? true
|
||||
showError = !isValid
|
||||
errorText = viewModel.radioButton.errorMessage
|
||||
isEnabled = viewModel.radioButton.enabled
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,8 +8,9 @@
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
import VDS
|
||||
|
||||
@objcMembers public class RadioButtonLabelModel: MoleculeModelProtocol {
|
||||
@objcMembers public class RadioButtonLabelModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -21,14 +22,23 @@ import MVMCore
|
||||
public var moleculeName: String = RadioButtonLabelModel.identifier
|
||||
public var radioButton: RadioButtonModel
|
||||
public var label: LabelModel
|
||||
public var subTitle: LabelModel?
|
||||
public var inverted: Bool? = false
|
||||
public var surface: Surface { inverted ?? false ? .dark : .light }
|
||||
|
||||
public var children: [MoleculeModelProtocol] {
|
||||
guard let subTitle else { return [radioButton, label] }
|
||||
return [radioButton, label, subTitle]
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(radioButton: RadioButtonModel, label: LabelModel) {
|
||||
public init(radioButton: RadioButtonModel, label: LabelModel, subTitle: LabelModel?) {
|
||||
self.radioButton = radioButton
|
||||
self.label = label
|
||||
self.subTitle = subTitle
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user