// // SelectorGroupHandlerBase.swift // VDS // // Created by Matt Bruce on 9/8/22. // import Foundation import UIKit import Combine import VDSCoreTokens public protocol SelectorGroup { associatedtype SelectorItemType: Control var items: [SelectorItemType] { get set } var hasSelectedItem: Bool { get } } extension SelectorGroup { public var hasSelectedItem: Bool { items.filter { $0.isSelected == true }.count > 0 } } public protocol SelectorGroupMultiSelect: SelectorGroup, FormFieldable {} extension SelectorGroupMultiSelect { /// Current Selected Control for this group. public var selectedItems: [SelectorItemType]? { let selected = items.filter{ $0.isSelected == true } guard selected.count > 0 else { return nil } return selected } } public protocol SelectorGroupSingleSelect: SelectorGroup, FormFieldable {} extension SelectorGroupSingleSelect { /// Current Selected Control for this group. public var selectedItem: SelectorItemType? { return items.filter { $0.isSelected == true }.first } } /// Base Class used for any Grouped Form Control of a Selector Type. open class SelectorGroupBase: Control, SelectorGroup, Changeable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- open var mainStackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.alignment = .fill $0.distribution = .fill $0.axis = .vertical $0.spacing = VDSLayout.space3X } }() //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- /// Array of the HandlerType registered. /// Array of HandlerType that the user will have the ability to select from. open var items: [SelectorItemType] = [] { willSet { mainStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } } didSet { for selector in items { selector.onClick = { [weak self] handler in self?.didSelect(handler) self?.setNeedsUpdate() } mainStackView.addArrangedSubview(selector) } } } open var onChangeSubscriber: AnyCancellable? /// Whether the Control is enabled or not. override open var isEnabled: Bool { didSet { items.forEach { $0.isEnabled = isEnabled } } } ///The background tint that the component will be placed on. This will automatically adjust other elements as needed and takes “light” or “dark” override open var surface: Surface { didSet { items.forEach { handler in handler.surface = surface } } } //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- /// 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) mainStackView .pinTop() .pinLeading() .pinTrailing() .pinBottom(0, .defaultHigh) } /// Handler for the Group to override on a select event. /// - Parameter selectedControl: Selected Control the user interacted. open func didSelect(_ selectedControl: SelectorItemType) { fatalError("Must override didSelect") } /// Helper method to execute the valueChanged event. open func valueChanged() { DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in self?.sendActions(for: .valueChanged) } } /// Resets to default settings. open override func reset() { super.reset() onChange = nil items.forEach{ $0.reset() } } }