// // RadioButton.swift // VDS // // Created by Matt Bruce on 7/22/22. // import Foundation import UIKit import VDSColorTokens import VDSFormControlsTokens public class RadioButton: RadioButtonBase{} public struct RadioButtonGroupModel: SelectorGroupModel{ public typealias SelectorType = DefaultRadioButtonModel 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 } } public class RadioButtonGroup: SelectorGroup { public override func didSelect(selected: DefaultRadioButtonModel) { for selectorModel in model.selectors { print("Pre Cached Selector: \(selectorModel.inputId): \(selectorModel.selected)") } if var oldSelectedModel = selectedModel { oldSelectedModel.selected = false replace(viewModel: oldSelectedModel) } var newSelectedModel = selected newSelectedModel.selected = true replace(viewModel: newSelectedModel) selectedModel = newSelectedModel for selectorModel in model.selectors { print("Post Cached Selector: \(selectorModel.inputId): \(selectorModel.selected)") } print("\n") } } open class RadioButtonBase: SelectorBase { //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- public let radioButtonSize = CGSize(width: 20, height: 20) public let radioButtonSelectedSize = CGSize(width: 10, height: 10) private var radioButtonBackgroundColorConfiguration: RadioButtonErrorColorConfiguration = { let config = RadioButtonErrorColorConfiguration() //error doesn't care enabled/disable config.error.forTrue.lightColor = VDSColor.elementsPrimaryOnlight config.error.forTrue.darkColor = VDSColor.elementsPrimaryOndark config.error.forFalse.lightColor = VDSColor.feedbackErrorBackgroundOnlight config.error.forFalse.darkColor = VDSColor.feedbackErrorBackgroundOndark return config }() private var radioButtonBorderColorConfiguration: RadioButtonErrorColorConfiguration = { let config = RadioButtonErrorColorConfiguration() config.forTrue.enabled.lightColor = VDSColor.elementsPrimaryOnlight config.forTrue.enabled.darkColor = VDSColor.elementsPrimaryOndark config.forFalse.enabled.lightColor = VDSFormControlsColor.borderOnlight config.forFalse.enabled.darkColor = VDSFormControlsColor.borderOndark config.forTrue.disabled.lightColor = VDSColor.interactiveDisabledOnlight config.forTrue.disabled.darkColor = VDSColor.interactiveDisabledOndark config.forFalse.disabled.lightColor = VDSColor.interactiveDisabledOnlight config.forFalse.disabled.darkColor = VDSColor.interactiveDisabledOndark //error doesn't care enabled/disable config.error.forTrue.lightColor = VDSColor.elementsPrimaryOnlight config.error.forTrue.darkColor = VDSColor.elementsPrimaryOndark config.error.forFalse.lightColor = VDSColor.feedbackErrorOnlight config.error.forFalse.darkColor = VDSColor.feedbackErrorOndark return config }() private var radioButtonCheckColorConfiguration: BinaryDisabledSurfaceColorConfiguration = { let config = BinaryDisabledSurfaceColorConfiguration() config.forTrue.enabled.lightColor = VDSColor.elementsPrimaryOnlight config.forTrue.enabled.darkColor = VDSColor.elementsPrimaryOndark config.forTrue.disabled.lightColor = VDSColor.interactiveDisabledOnlight config.forTrue.disabled.darkColor = VDSColor.interactiveDisabledOndark return config }() //-------------------------------------------------- // MARK: - RadioButton View //-------------------------------------------------- /// Manages the appearance of the radioButton. private var shapeLayer: CAShapeLayer? open override func getSelectorSize() -> CGSize { return radioButtonSize } open override func updateSelector(_ viewModel: ModelType) { //get the colors let backgroundColor = radioButtonBackgroundColorConfiguration.getColor(viewModel) let borderColor = radioButtonBorderColorConfiguration.getColor(viewModel) let radioSelectedColor = radioButtonCheckColorConfiguration.getColor(viewModel) if let shapeLayer = shapeLayer, let sublayers = layer.sublayers, sublayers.contains(shapeLayer) { shapeLayer.removeFromSuperlayer() self.shapeLayer = nil } selectorView.backgroundColor = backgroundColor selectorView.layer.borderColor = borderColor.cgColor selectorView.layer.cornerRadius = selectorView.bounds.width * 0.5 selectorView.layer.borderWidth = 1.0 if shapeLayer == nil { let bounds = selectorView.bounds let selectedBounds = radioButtonSelectedSize let length = max(bounds.size.height, bounds.size.width) guard length > 0.0, shapeLayer == nil else { return } let bezierPath = UIBezierPath(ovalIn: CGRect(x: (bounds.width - selectedBounds.width) / 2, y: (bounds.height - selectedBounds.height) / 2, width: radioButtonSelectedSize.width, height: radioButtonSelectedSize.height)) let shapeLayer = CAShapeLayer() self.shapeLayer = shapeLayer shapeLayer.frame = bounds layer.addSublayer(shapeLayer) shapeLayer.fillColor = radioSelectedColor.cgColor shapeLayer.path = bezierPath.cgPath } } //-------------------------------------------------- // MARK: - Color Class Configurations //-------------------------------------------------- private class RadioButtonErrorColorConfiguration: BinaryDisabledSurfaceColorConfiguration { public let error = BinarySurfaceColorConfiguration() override func getColor(_ viewModel: ModelType) -> UIColor { //only show error is enabled and showError == true let showErrorColor = !viewModel.disabled && viewModel.showError if showErrorColor { return error.getColor(viewModel) } else { return super.getColor(viewModel) } } } open override func shouldUpdateView(viewModel: ModelType) -> Bool { return viewModel.selected != model.selected || viewModel.labelText != model.labelText || viewModel.childText != model.childText || viewModel.showError != model.showError || viewModel.surface != model.surface || viewModel.disabled != model.disabled } }