156 lines
5.2 KiB
Swift
156 lines
5.2 KiB
Swift
//
|
|
// 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 {
|
|
/// Set of Subscribers for any Publishers for this Control.
|
|
var subscribers: Set<AnyCancellable> { get set }
|
|
|
|
/// Key of whether or not updateView() is called in setNeedsUpdate()
|
|
var shouldUpdateView: Bool { get set }
|
|
|
|
/// Key of whether or not updateAccessibility() is called in setNeedsUpdate()
|
|
var shouldUpdateAccessibility: Bool { get set }
|
|
|
|
/// Used for setting an implementation for the default Accessible Action
|
|
var accessibilityAction: ((Self) -> Void)? { get set }
|
|
|
|
/// Executed on initialization for this View.
|
|
func initialSetup()
|
|
|
|
/// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations.
|
|
func setup()
|
|
|
|
/// 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
|
|
updateView()
|
|
if shouldUpdateAccessibility {
|
|
updateAccessibility()
|
|
}
|
|
shouldUpdateView = true
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
public protocol AccessibilityUpdatable {
|
|
// Basic accessibility
|
|
var bridge_isAccessibilityElementBlock: AXBoolReturnBlock? { get set }
|
|
|
|
var bridge_accessibilityLabelBlock: AXStringReturnBlock? { get set }
|
|
|
|
var bridge_accessibilityValueBlock: AXStringReturnBlock? { get set }
|
|
|
|
var bridge_accessibilityHintBlock: AXStringReturnBlock? { get set }
|
|
|
|
var bridge_accessibilityActivateBlock: AXBoolReturnBlock? { get set }
|
|
|
|
}
|
|
|
|
extension NSObject: AccessibilityUpdatable {
|
|
static var isAccessibilityElementBlockKey: UInt8 = 0
|
|
static var activateBlockKey: UInt8 = 1
|
|
static var valueBlockKey: UInt8 = 2
|
|
static var hintBlockKey: UInt8 = 3
|
|
static var labelBlockKey: UInt8 = 4
|
|
|
|
public var bridge_isAccessibilityElementBlock: AXBoolReturnBlock? {
|
|
get {
|
|
return objc_getAssociatedObject(self, &NSObject.isAccessibilityElementBlockKey) as? AXBoolReturnBlock
|
|
}
|
|
set {
|
|
objc_setAssociatedObject(self, &NSObject.isAccessibilityElementBlockKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
// if #available(iOS 17, *) {
|
|
// self.isAccessibilityElementBlock = newValue
|
|
// }
|
|
}
|
|
}
|
|
|
|
public var bridge_accessibilityActivateBlock: AXBoolReturnBlock? {
|
|
get {
|
|
return objc_getAssociatedObject(self, &NSObject.activateBlockKey) as? AXBoolReturnBlock
|
|
}
|
|
set {
|
|
objc_setAssociatedObject(self, &NSObject.activateBlockKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
// if #available(iOS 17, *) {
|
|
// self.accessibilityActivateBlock = newValue
|
|
// }
|
|
}
|
|
}
|
|
|
|
public var bridge_accessibilityValueBlock: AXStringReturnBlock? {
|
|
get {
|
|
return objc_getAssociatedObject(self, &NSObject.valueBlockKey) as? AXStringReturnBlock
|
|
}
|
|
set {
|
|
objc_setAssociatedObject(self, &NSObject.valueBlockKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
// if #available(iOS 17, *) {
|
|
// self.accessibilityValueBlock = newValue
|
|
// }
|
|
}
|
|
}
|
|
|
|
public var bridge_accessibilityHintBlock: AXStringReturnBlock? {
|
|
get {
|
|
return objc_getAssociatedObject(self, &NSObject.hintBlockKey) as? AXStringReturnBlock
|
|
}
|
|
set {
|
|
objc_setAssociatedObject(self, &NSObject.hintBlockKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
// if #available(iOS 17, *) {
|
|
// self.accessibilityHintBlock = newValue
|
|
// }
|
|
}
|
|
}
|
|
|
|
public var bridge_accessibilityLabelBlock: AXStringReturnBlock? {
|
|
get {
|
|
return objc_getAssociatedObject(self, &NSObject.labelBlockKey) as? AXStringReturnBlock
|
|
}
|
|
set {
|
|
objc_setAssociatedObject(self, &NSObject.labelBlockKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
// if #available(iOS 17, *) {
|
|
// self.accessibilityLabelBlock = newValue
|
|
// }
|
|
}
|
|
}
|
|
|
|
}
|