// // RadioButtonGroup.swift // VDS // // Created by Matt Bruce on 8/8/22. // import Foundation import UIKit import Combine open class SelectorGroupBase>: View, Changable where SelectorType == SelectorGroupType.SelectorType { public var selectorViews: [SelectorHandlerType] = [] public var onChange: Blocks.ActionBlock? //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var mainStackView: UIStackView = { let stackView = UIStackView() stackView.translatesAutoresizingMaskIntoConstraints = false stackView.alignment = .top stackView.axis = .vertical stackView.spacing = 10 return stackView }() //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- override public var disabled: Bool { didSet { updateSelectors() } } override public var surface: Surface { didSet { updateSelectors() } } private func updateSelectors(){ let selectors = model.selectors.compactMap { existing in return existing.with { $0.disabled = disabled $0.surface = surface } } model.selectors = selectors } open override func setup() { super.setup() isAccessibilityElement = true accessibilityTraits = .button addSubview(mainStackView) mainStackView.topAnchor.constraint(equalTo: topAnchor).isActive = true mainStackView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true mainStackView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true mainStackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true } open override func shouldUpdateView(viewModel: SelectorGroupType) -> Bool { let update = viewModel.selectors.count != model.selectors.count || viewModel.hasError != model.hasError || viewModel.surface != model.surface || viewModel.disabled != model.disabled return update } open override func updateView(viewModel: ModelType) { //print("Selector Group update:") func findSelectorView(id: UUID) -> SelectorHandlerType? { return selectorViews.first(where: { existingSelectorView in return existingSelectorView.model.id == id }) } for selectorModel in viewModel.selectors { //see if view is there for the model if let foundSelectorView = findSelectorView(id: selectorModel.id) { foundSelectorView.set(with: selectorModel) } else { //create view let newSelectorView = SelectorHandlerType(with: selectorModel) //add the selectedPublisher for the change newSelectorView.publisher(for: .valueChanged) .sink(receiveValue: { [weak self] control in guard self?.model.selectors.count ?? 0 > 0 else { return } self?.didSelect(selector: control.model) }) .store(in: &subscribers) //add model update to the subscribers newSelectorView.handlerPublisher() .sink { [weak self] model in if let cached = self?.getCachedSelector(viewModel: model), newSelectorView.shouldUpdateView(viewModel: cached) { self?.replace(viewModel: model) } } .store(in: &subscribers) self.selectorViews.append(newSelectorView) mainStackView.addArrangedSubview(newSelectorView) } } } public func getCachedSelector(viewModel: SelectorType) -> SelectorType? { if let index = model.selectors.firstIndex(where: { element in return element.id == viewModel.id }) { return model.selectors[index] } else { return nil } } public func replace(viewModel: SelectorType){ if let index = model.selectors.firstIndex(where: { element in return element.id == viewModel.id }) { model.selectors[index] = viewModel } } open func didSelect(selector: SelectorType) { } }