146 lines
4.9 KiB
Swift
146 lines
4.9 KiB
Swift
//
|
|
// RadioButtonGroup.swift
|
|
// VDS
|
|
//
|
|
// Created by Matt Bruce on 8/8/22.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
|
|
|
|
public protocol SelectorGroupModel<SelectorType>: Modelable, FormFieldable {
|
|
associatedtype SelectorType: SelectorModel
|
|
var selectors: [SelectorType] { get set }
|
|
}
|
|
|
|
public struct DefaultSelectorGroupModel<SelectorType: SelectorModel>: SelectorGroupModel {
|
|
public var id: UUID = UUID()
|
|
public var inputId: String?
|
|
public var value: AnyHashable?
|
|
public var surface: Surface = .light
|
|
public var disabled: Bool = false
|
|
public var selectors: [SelectorType]
|
|
public init() { selectors = [] }
|
|
public init(selectors: [SelectorType]){
|
|
self.selectors = selectors
|
|
}
|
|
}
|
|
|
|
open class SelectorGroup<SelectorType, SelectorGroupType: SelectorGroupModel<SelectorType>, SelectorHandlerType: SelectorBase<SelectorType>>: View<SelectorGroupType>, Changable {
|
|
|
|
public var selectorViews: [SelectorHandlerType] = []
|
|
public var selectedModel: SelectorType?
|
|
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 {
|
|
let selectors = model.selectors.compactMap { existing in
|
|
return updated(existing){
|
|
$0.disabled = disabled
|
|
}
|
|
}
|
|
model.selectors = selectors
|
|
}
|
|
}
|
|
|
|
override public var surface: Surface {
|
|
didSet {
|
|
let selectors = model.selectors.compactMap { existing in
|
|
return updated(existing){
|
|
$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: ModelType) -> Bool {
|
|
return true
|
|
}
|
|
|
|
open override func updateView(viewModel: ModelType) {
|
|
print("Selector Group update:")
|
|
func findSelectorView(inputId: String) -> SelectorHandlerType? {
|
|
return selectorViews.first(where: { existingSelectorView in
|
|
return existingSelectorView.model.inputId == inputId
|
|
})
|
|
}
|
|
|
|
for selectorModel in viewModel.selectors {
|
|
//see if view is there for the model
|
|
if let inputId = selectorModel.inputId, let foundSelectorView = findSelectorView(inputId: inputId) {
|
|
foundSelectorView.set(with: selectorModel)
|
|
} else {
|
|
|
|
//create view
|
|
let newSelectorView = SelectorHandlerType(with: selectorModel)
|
|
|
|
//add the selectedPublisher for the change
|
|
newSelectorView.selectedPublisher().sink { [weak self] model in
|
|
self?.didSelect(selected: model)
|
|
}.store(in: &cancellables)
|
|
|
|
newSelectorView.$model.sink { [weak self] model in
|
|
//should replace
|
|
if let cached = self?.getCachedSelector(viewModel: model), newSelectorView.shouldUpdateView(viewModel: cached) {
|
|
self?.replace(viewModel: model)
|
|
}
|
|
}.store(in: &cancellables)
|
|
|
|
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(selected: SelectorType) { }
|
|
}
|