// // RadioBoxGroup.swift // VDS // // Created by Matt Bruce on 8/23/22. // import Foundation import UIKit @objc(VDSRadioBoxGroup) open class RadioBoxGroup: SelectorGroupSelectedHandlerBase { //-------------------------------------------------- // 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 override var selectorViews: [RadioBoxItem] { willSet { mainStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } } didSet { for selector in selectorViews { selector.onClick = { [weak self] handler in self?.didSelect(handler) self?.setNeedsUpdate() } mainStackView.addArrangedSubview(selector) } } } open var selectorModels: [RadioBoxItemModel]? { didSet { if let selectorModels { selectorViews = selectorModels.enumerated().map { index, model in return RadioBoxItem().with { $0.accessibilityLabel = model.accessibileText $0.accessibilityValue = "item \(index+1) of \(selectorModels.count)" $0.text = model.text $0.textAttributes = model.textAttributes $0.subText = model.subText $0.subTextAttributes = model.subTextAttributes $0.subTextRight = model.subText $0.subTextRightAttributes = model.subTextAttributes $0.isEnabled = !model.disabled $0.inputId = model.inputId $0.isSelected = model.selected } } } setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var mainStackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.spacing = VDSLayout.Spacing.space3X.value } }() //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- private func ensureDevice() { if UIDevice.isIPad { mainStackView.axis = .horizontal mainStackView.distribution = .fillEqually } else { if UIDevice.current.orientation.isPortrait || UIDevice.current.orientation == .unknown { mainStackView.axis = .vertical mainStackView.distribution = .fill } else { mainStackView.axis = .horizontal mainStackView.distribution = .fillEqually } } } /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. open override func setup() { super.setup() addSubview(mainStackView) ensureDevice() mainStackView.pinToSuperView() NotificationCenter.default .publisher(for: UIDevice.orientationDidChangeNotification) .sink() { [weak self] _ in UIView.animate(withDuration: 1.0) { self?.ensureDevice() } }.store(in: &subscribers) } open override func didSelect(_ selectedControl: RadioBoxItem) { let oldSelectedControl = selectorViews.filter { $0.isSelected == true }.first oldSelectedControl?.toggle() selectedControl.toggle() valueChanged() } } extension RadioBoxGroup { public struct RadioBoxItemModel: Surfaceable, Initable, FormFieldable { /// 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 text: String /// Array of LabelAttributeModel objects used in rendering the text. public var textAttributes: [any LabelAttributeModel]? public var subText: String? /// Array of LabelAttributeModel objects used in rendering the subText. public var subTextAttributes: [any LabelAttributeModel]? public var subTextRight: String? /// Array of LabelAttributeModel objects used in rendering the subTextRight. public var subTextRightAttributes: [any LabelAttributeModel]? public var selected: Bool public init(disabled: Bool, surface: Surface = .light, inputId: String? = nil, value: AnyHashable? = nil, text: String = "", textAttributes: [any LabelAttributeModel]? = nil, subText: String? = nil, subTextAttributes: [any LabelAttributeModel]? = nil, subTextRight: String? = nil, subTextRightAttributes: [any LabelAttributeModel]? = nil, selected: Bool = false, errorText: String? = nil, accessibileText: String? = nil) { self.disabled = disabled self.surface = surface self.inputId = inputId self.value = value self.text = text self.textAttributes = textAttributes self.subText = subText self.subTextAttributes = subTextAttributes self.subTextRight = subTextRight self.subTextRightAttributes = subTextRightAttributes self.selected = selected self.accessibileText = accessibileText } public init() { self.init(disabled: false) } } }