Compare commits

...

1 Commits

Author SHA1 Message Date
a7d99fd523 Signed-off-by: Matt Bruce <mbrucedogs@gmail.com> 2025-02-06 21:31:09 -06:00
7 changed files with 105 additions and 23 deletions

View File

@ -35,6 +35,7 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
// MARK: - Combine Properties // MARK: - Combine Properties
//-------------------------------------------------- //--------------------------------------------------
open var subscribers = Set<AnyCancellable>() open var subscribers = Set<AnyCancellable>()
open var subject = PassthroughSubject<Void, Never>()
open var onClickSubscriber: AnyCancellable? open var onClickSubscriber: AnyCancellable?
@ -78,10 +79,19 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
/// When the view moves to a window, force any pending update immediately.
open override func didMoveToWindow() {
super.didMoveToWindow()
if window != nil {
updateView()
}
}
private func initialSetup() { private func initialSetup() {
if !initialSetupPerformed { if !initialSetupPerformed {
initialSetupPerformed = true initialSetupPerformed = true
shouldUpdateView = false shouldUpdateView = false
setupDidChangeEvent(true)
setup() setup()
setDefaults() setDefaults()
shouldUpdateView = true shouldUpdateView = true

View File

@ -36,7 +36,8 @@ open class View: UIView, ViewProtocol, UserInfoable, Clickable {
// MARK: - Combine Properties // MARK: - Combine Properties
//-------------------------------------------------- //--------------------------------------------------
open var subscribers = Set<AnyCancellable>() open var subscribers = Set<AnyCancellable>()
open var subject = PassthroughSubject<Void, Never>()
open var onClickSubscriber: AnyCancellable? open var onClickSubscriber: AnyCancellable?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
@ -58,10 +59,19 @@ open class View: UIView, ViewProtocol, UserInfoable, Clickable {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
/// When the view moves to a window, force any pending update immediately.
open override func didMoveToWindow() {
super.didMoveToWindow()
if window != nil {
updateView()
}
}
private func initialSetup() { private func initialSetup() {
if !initialSetupPerformed { if !initialSetupPerformed {
initialSetupPerformed = true initialSetupPerformed = true
shouldUpdateView = false shouldUpdateView = false
setupDidChangeEvent(true)
setup() setup()
setDefaults() setDefaults()
shouldUpdateView = true shouldUpdateView = true

View File

@ -38,8 +38,9 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
//-------------------------------------------------- //--------------------------------------------------
/// Set of Subscribers for any Publishers for this Control. /// Set of Subscribers for any Publishers for this Control.
open var subscribers = Set<AnyCancellable>() open var subscribers = Set<AnyCancellable>()
open var subject = PassthroughSubject<Void, Never>()
open var onClickSubscriber: AnyCancellable? open var onClickSubscriber: AnyCancellable?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
@ -97,10 +98,19 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
/// When the view moves to a window, force any pending update immediately.
open override func didMoveToWindow() {
super.didMoveToWindow()
if window != nil {
updateView()
}
}
private func initialSetup() { private func initialSetup() {
if !initialSetupPerformed { if !initialSetupPerformed {
initialSetupPerformed = true initialSetupPerformed = true
shouldUpdateView = false shouldUpdateView = false
setupDidChangeEvent(true)
setup() setup()
setDefaults() setDefaults()
shouldUpdateView = true shouldUpdateView = true

View File

@ -39,7 +39,8 @@ open class Label: UILabel, ViewProtocol, UserInfoable {
//-------------------------------------------------- //--------------------------------------------------
/// Set of Subscribers for any Publishers for this Control. /// Set of Subscribers for any Publishers for this Control.
open var subscribers = Set<AnyCancellable>() open var subscribers = Set<AnyCancellable>()
open var subject = PassthroughSubject<Void, Never>()
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
//-------------------------------------------------- //--------------------------------------------------
@ -192,10 +193,19 @@ open class Label: UILabel, ViewProtocol, UserInfoable {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
/// When the view moves to a window, force any pending update immediately.
open override func didMoveToWindow() {
super.didMoveToWindow()
if window != nil {
updateView()
}
}
private func initialSetup() { private func initialSetup() {
if !initialSetupPerformed { if !initialSetupPerformed {
initialSetupPerformed = true initialSetupPerformed = true
shouldUpdateView = false shouldUpdateView = false
setupDidChangeEvent(true)
setup() setup()
setDefaults() setDefaults()
shouldUpdateView = true shouldUpdateView = true

View File

@ -37,6 +37,7 @@ open class TextField: UITextField, ViewProtocol, Errorable {
//-------------------------------------------------- //--------------------------------------------------
/// Set of Subscribers for any Publishers for this Control. /// Set of Subscribers for any Publishers for this Control.
open var subscribers = Set<AnyCancellable>() open var subscribers = Set<AnyCancellable>()
open var subject = PassthroughSubject<Void, Never>()
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
@ -98,10 +99,19 @@ open class TextField: UITextField, ViewProtocol, Errorable {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
/// When the view moves to a window, force any pending update immediately.
open override func didMoveToWindow() {
super.didMoveToWindow()
if window != nil {
updateView()
}
}
private func initialSetup() { private func initialSetup() {
if !initialSetupPerformed { if !initialSetupPerformed {
initialSetupPerformed = true initialSetupPerformed = true
shouldUpdateView = false shouldUpdateView = false
setupDidChangeEvent(true)
setup() setup()
setDefaults() setDefaults()
shouldUpdateView = true shouldUpdateView = true

View File

@ -37,6 +37,7 @@ open class TextView: UITextView, ViewProtocol, Errorable {
//-------------------------------------------------- //--------------------------------------------------
/// Set of Subscribers for any Publishers for this Control. /// Set of Subscribers for any Publishers for this Control.
open var subscribers = Set<AnyCancellable>() open var subscribers = Set<AnyCancellable>()
open var subject = PassthroughSubject<Void, Never>()
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Private Properties // MARK: - Private Properties
@ -107,10 +108,19 @@ open class TextView: UITextView, ViewProtocol, Errorable {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Lifecycle // MARK: - Lifecycle
//-------------------------------------------------- //--------------------------------------------------
/// When the view moves to a window, force any pending update immediately.
open override func didMoveToWindow() {
super.didMoveToWindow()
if window != nil {
updateView()
}
}
private func initialSetup() { private func initialSetup() {
if !initialSetupPerformed { if !initialSetupPerformed {
initialSetupPerformed = true initialSetupPerformed = true
shouldUpdateView = false shouldUpdateView = false
setupDidChangeEvent(true)
setup() setup()
setDefaults() setDefaults()
shouldUpdateView = true shouldUpdateView = true

View File

@ -10,6 +10,8 @@ import UIKit
import Combine import Combine
public protocol ViewProtocol: AnyObject, Initable, Resettable, Enabling, Surfaceable, AccessibilityUpdatable { public protocol ViewProtocol: AnyObject, Initable, Resettable, Enabling, Surfaceable, AccessibilityUpdatable {
var subject: PassthroughSubject<Void, Never> { get set }
/// Set of Subscribers for any Publishers for this Control. /// Set of Subscribers for any Publishers for this Control.
var subscribers: Set<AnyCancellable> { get set } var subscribers: Set<AnyCancellable> { get set }
@ -36,28 +38,48 @@ extension ViewProtocol {
/// Called when there are changes in a View based off a change events or from local properties. /// Called when there are changes in a View based off a change events or from local properties.
public func setNeedsUpdate() { public func setNeedsUpdate() {
if shouldUpdateView { // if shouldUpdateView {
shouldUpdateView = false // shouldUpdateView = false
//
//see if this is a view that has children // //see if this is a view that has children
let parent = self as? any ParentViewProtocol // let parent = self as? any ParentViewProtocol
let children = parent?.getAllChildren() // let children = parent?.getAllChildren()
//if so turn off the shouldUpdate to keep UI // //if so turn off the shouldUpdate to keep UI
//from blocking // //from blocking
children?.forEach{ $0.shouldUpdateView = false } // children?.forEach{ $0.shouldUpdateView = false }
//
updateView() // updateView()
updateAccessibility() // updateAccessibility()
//
//if so turn on // //if so turn on
children?.forEach{ // children?.forEach{
$0.updateView() // $0.updateView()
$0.updateAccessibility() // $0.updateAccessibility()
$0.shouldUpdateView = true // $0.shouldUpdateView = true
} // }
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<Void, Never> {
if debounce {
return subject
.debounce(for: .seconds(0.05), scheduler: RunLoop.main)
.eraseToAnyPublisher()
} else {
return subject
.eraseToAnyPublisher()
} }
} }
} }
extension ViewProtocol where Self: UIView { extension ViewProtocol where Self: UIView {