// // RadioButtonGroup.swift // VDS // // Created by Matt Bruce on 8/11/22. // import Foundation import UIKit /// Radio buttons items are single-select components through which a customer indicates a choice. /// They must always be paired with one or more other ``RadioButtonItem`` within a radio button group. /// Use radio buttons to display choices like delivery method. @objc(VDSRadioButtonGroup) open class RadioButtonGroup: SelectorGroupBase, SelectorGroupSingleSelect { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- required public init() { super.init(frame: .zero) } public override init(frame: CGRect) { super.init(frame: .zero) } public required init?(coder: NSCoder) { super.init(coder: coder) } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- public var inputId: String? public var value: SelectorItemType? { selectedItem } /// Array of ``RadioButtonItemModel`` that will be used to build the selectorViews of type ``RadioButtonItem``. open var selectorModels: [RadioButtonItemModel]? { didSet { if let selectorModels { items = selectorModels.enumerated().map { index, model in return RadioButtonItem().with { $0.isEnabled = !model.disabled $0.surface = model.surface $0.inputId = model.inputId $0.hiddenValue = model.value $0.labelText = model.labelText $0.labelTextAttributes = model.labelTextAttributes $0.childText = model.childText $0.childTextAttributes = model.childTextAttributes $0.isSelected = model.selected $0.errorText = model.errorText $0.showError = model.showError $0.selectorView.bridge_accessibilityValueBlock = { "item \(index+1) of \(selectorModels.count)" } } } } setNeedsUpdate() } } private var _showError: Bool = false /// Whether not to show the error. open var showError: Bool { get { _showError } set { var newShowError = newValue if hasSelectedItem && newShowError { newShowError = false } items.forEach { $0.showError = newShowError } _showError = newShowError } } open override func reset() { super.reset() showError = false } public override func didSelect(_ selectedControl: RadioButtonItem) { if let selectedItem { updateToggle(selectedItem) } updateToggle(selectedControl) if showError { showError = false } valueChanged() } private func updateToggle(_ radioButton: RadioButtonItem) { if radioButton.showError && radioButton.isSelected == false { radioButton.showError.toggle() } radioButton.isSelected.toggle() } } extension RadioButtonGroup { public struct RadioButtonItemModel: Surfaceable, Initable, FormFieldable, Errorable { /// Whether this object is disabled or not public var disabled: Bool /// Current Surface and this is used to pass down to child objects that implement Surfacable public var surface: Surface public var inputId: String? public var value: AnyHashable? public var accessibileText: String? public var labelText: String? /// Array of LabelAttributeModel objects used in rendering the labelText. public var labelTextAttributes: [any LabelAttributeModel]? public var childText: String? /// Array of LabelAttributeModel objects used in rendering the childText. public var childTextAttributes: [any LabelAttributeModel]? public var selected: Bool /// Whether not to show the error. public var showError: Bool public var errorText: String? public init(disabled: Bool, surface: Surface = .light, inputId: String? = nil, value: AnyHashable? = nil, accessibileText: String? = nil, labelText: String? = nil, labelTextAttributes: [any LabelAttributeModel]? = nil, childText: String? = nil, childTextAttributes: [any LabelAttributeModel]? = nil, selected: Bool = false, showError: Bool = false, errorText: String? = nil) { self.disabled = disabled self.surface = surface self.inputId = inputId self.value = value self.accessibileText = accessibileText self.labelText = labelText self.labelTextAttributes = labelTextAttributes self.childText = childText self.childTextAttributes = childTextAttributes self.selected = selected self.showError = showError self.errorText = errorText } public init() { self.init(disabled: false) } } }