// // SelectorBase.swift // VDS // // Created by Matt Bruce on 6/5/23. // import Foundation import UIKit import Combine import VDSCoreTokens public protocol SelectorControlable: Control, Changeable { /// Whether not to show the error. var showError: Bool { get set } /// Size of the SelectorView. var size: CGSize { get set } /// Configuration for the Background Color based on Control State. var backgroundColorConfiguration: ControlColorConfiguration { get set } /// Configuration for the Border Color based on Control State. var borderColorConfiguration: ControlColorConfiguration { get set } /// Configuration for the Selector Color based on Control State. var selectorColorConfiguration: ControlColorConfiguration { get set } } /// Base Class used to build out a Selector control. open class SelectorBase: Control, SelectorControlable { //-------------------------------------------------- // 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 //-------------------------------------------------- open var onChangeSubscriber: AnyCancellable? open var size = CGSize(width: 20, height: 20) { didSet { setNeedsUpdate() } } var _showError: Bool = false /// Whether not to show the error. open var showError: Bool { get { _showError } set { if !isSelected && _showError != newValue { _showError = newValue setNeedsUpdate() } } } /// Override UIControl state to add the .error state if showError is true. open override var state: UIControl.State { get { var state = super.state if showError { state.insert(.error) } else { state.remove(.error) } return state } } open var backgroundColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() } } open var borderColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() } } open var selectorColorConfiguration = ControlColorConfiguration() { didSet { setNeedsUpdate() } } /// The natural size for the receiving view, considering only properties of the view itself. open override var intrinsicContentSize: CGSize { size } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var selectorView = View() //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- internal var shapeLayer: CAShapeLayer? //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- /// Executed on initialization for this View. open override func initialSetup() { super.initialSetup() onClick = { control in control.toggle() } } /// 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() isAccessibilityElement = true accessibilityTraits = .button } open override func updateView() { super.updateView() setNeedsLayout() layoutIfNeeded() } /// Used to update any Accessibility properties.ß open override func updateAccessibility() { super.updateAccessibility() accessibilityLabel = "\(Self.self)\(showError ? ", error" : "")" accessibilityHint = !isEnabled ? "" : "Double tap to open." } /// This will change the state of the Selector and execute the actionBlock if provided. open func toggle() { } open override func reset() { super.reset() onChange = nil } open override func accessibilityActivate() -> Bool { guard isEnabled, isUserInteractionEnabled else { return false } guard isEnabled, isUserInteractionEnabled else { return false } var value = true // if #available(iOS 17, *) { // if let block = accessibilityAction { // block(self) // // } else if let block = accessibilityActivateBlock { // value = block() // // } else if let block = bridge_accessibilityActivateBlock { // value = block() // // } else { // toggle() // } // } else { if let block = accessibilityAction { block(self) } else if let block = bridge_accessibilityActivateBlock { value = block() } else { toggle() } // } return value } }