// // ViewProtocol.swift // VDS // // Created by Matt Bruce on 7/22/22. // import Foundation import UIKit import Combine public protocol ViewProtocol: AnyObject, Initable, Resettable, Enabling, Surfaceable, AccessibilityUpdatable { var subject: PassthroughSubject { get set } /// Set of Subscribers for any Publishers for this Control. var subscribers: Set { get set } /// Key of whether or not updateView() is called in setNeedsUpdate() var shouldUpdateView: Bool { get set } /// Used for setting an implementation for the default Accessible Action var accessibilityAction: ((Self) -> Void)? { get set } /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. func setup() /// Default configurations for values and properties. This is called in the setup() and reset(). func setDefaults() /// Used to make changes to the View based off a change events or from local properties. func updateView() /// Used to update any Accessibility properties. func updateAccessibility() } extension ViewProtocol { /// Called when there are changes in a View based off a change events or from local properties. public func setNeedsUpdate() { // if shouldUpdateView { // shouldUpdateView = false // // //see if this is a view that has children // let parent = self as? any ParentViewProtocol // let children = parent?.getAllChildren() // //if so turn off the shouldUpdate to keep UI // //from blocking // children?.forEach{ $0.shouldUpdateView = false } // // updateView() // updateAccessibility() // // //if so turn on // children?.forEach{ // $0.updateView() // $0.updateAccessibility() // $0.shouldUpdateView = true // } // shouldUpdateView = true // } subject.send() } public func setupDidChangeEvent(_ debounce: Bool = false) { handlerPublisher(debounce) .sink { [weak self] _ in self?.updateView() }.store(in: &subscribers) } public func handlerPublisher(_ debounce: Bool = false) -> AnyPublisher { if debounce { return subject .debounce(for: .seconds(0.05), scheduler: RunLoop.main) .eraseToAnyPublisher() } else { return subject .eraseToAnyPublisher() } } } extension ViewProtocol where Self: UIView { /// Helper method for removing a superview and updating Self. public func removeFromSuperview(_ view: UIView){ if view.superview != nil { view.removeFromSuperview() setNeedsDisplay() } } } extension ViewProtocol where Self: UIControl { /// Helper method to assign a completion block to a specific UIControl Event using Combine and stored in the subscribers. public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) { publisher(for: event) .sink(receiveValue: { c in block(c) }).store(in: &subscribers) } }