From a7d99fd523bb0590522b41afbacfb7d3928fac0a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 6 Feb 2025 21:31:09 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- VDS/BaseClasses/Control.swift | 10 +++ VDS/BaseClasses/View.swift | 12 +++- VDS/Components/Buttons/ButtonBase.swift | 12 +++- VDS/Components/Label/Label.swift | 12 +++- .../TextFields/InputField/TextField.swift | 10 +++ .../TextFields/TextArea/TextView.swift | 10 +++ VDS/Protocols/ViewProtocol.swift | 62 +++++++++++++------ 7 files changed, 105 insertions(+), 23 deletions(-) diff --git a/VDS/BaseClasses/Control.swift b/VDS/BaseClasses/Control.swift index 7ebe3824..f454b531 100644 --- a/VDS/BaseClasses/Control.swift +++ b/VDS/BaseClasses/Control.swift @@ -35,6 +35,7 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { // MARK: - Combine Properties //-------------------------------------------------- open var subscribers = Set() + open var subject = PassthroughSubject() open var onClickSubscriber: AnyCancellable? @@ -78,10 +79,19 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // 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() { if !initialSetupPerformed { initialSetupPerformed = true shouldUpdateView = false + setupDidChangeEvent(true) setup() setDefaults() shouldUpdateView = true diff --git a/VDS/BaseClasses/View.swift b/VDS/BaseClasses/View.swift index a78905ba..a43c7f0d 100644 --- a/VDS/BaseClasses/View.swift +++ b/VDS/BaseClasses/View.swift @@ -36,7 +36,8 @@ open class View: UIView, ViewProtocol, UserInfoable, Clickable { // MARK: - Combine Properties //-------------------------------------------------- open var subscribers = Set() - + open var subject = PassthroughSubject() + open var onClickSubscriber: AnyCancellable? //-------------------------------------------------- // MARK: - Private Properties @@ -58,10 +59,19 @@ open class View: UIView, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // 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() { if !initialSetupPerformed { initialSetupPerformed = true shouldUpdateView = false + setupDidChangeEvent(true) setup() setDefaults() shouldUpdateView = true diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index b555218d..7ca4ccff 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -38,8 +38,9 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- /// Set of Subscribers for any Publishers for this Control. open var subscribers = Set() + open var subject = PassthroughSubject() - open var onClickSubscriber: AnyCancellable? + open var onClickSubscriber: AnyCancellable? //-------------------------------------------------- // MARK: - Private Properties @@ -97,10 +98,19 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // 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() { if !initialSetupPerformed { initialSetupPerformed = true shouldUpdateView = false + setupDidChangeEvent(true) setup() setDefaults() shouldUpdateView = true diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 245dcf81..883f8630 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -39,7 +39,8 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- /// Set of Subscribers for any Publishers for this Control. open var subscribers = Set() - + open var subject = PassthroughSubject() + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -192,10 +193,19 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- // 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() { if !initialSetupPerformed { initialSetupPerformed = true shouldUpdateView = false + setupDidChangeEvent(true) setup() setDefaults() shouldUpdateView = true diff --git a/VDS/Components/TextFields/InputField/TextField.swift b/VDS/Components/TextFields/InputField/TextField.swift index 9fb8d7f6..d398155d 100644 --- a/VDS/Components/TextFields/InputField/TextField.swift +++ b/VDS/Components/TextFields/InputField/TextField.swift @@ -37,6 +37,7 @@ open class TextField: UITextField, ViewProtocol, Errorable { //-------------------------------------------------- /// Set of Subscribers for any Publishers for this Control. open var subscribers = Set() + open var subject = PassthroughSubject() //-------------------------------------------------- // MARK: - Private Properties @@ -98,10 +99,19 @@ open class TextField: UITextField, ViewProtocol, Errorable { //-------------------------------------------------- // 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() { if !initialSetupPerformed { initialSetupPerformed = true shouldUpdateView = false + setupDidChangeEvent(true) setup() setDefaults() shouldUpdateView = true diff --git a/VDS/Components/TextFields/TextArea/TextView.swift b/VDS/Components/TextFields/TextArea/TextView.swift index b8098a49..148a74ab 100644 --- a/VDS/Components/TextFields/TextArea/TextView.swift +++ b/VDS/Components/TextFields/TextArea/TextView.swift @@ -37,6 +37,7 @@ open class TextView: UITextView, ViewProtocol, Errorable { //-------------------------------------------------- /// Set of Subscribers for any Publishers for this Control. open var subscribers = Set() + open var subject = PassthroughSubject() //-------------------------------------------------- // MARK: - Private Properties @@ -107,10 +108,19 @@ open class TextView: UITextView, ViewProtocol, Errorable { //-------------------------------------------------- // 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() { if !initialSetupPerformed { initialSetupPerformed = true shouldUpdateView = false + setupDidChangeEvent(true) setup() setDefaults() shouldUpdateView = true diff --git a/VDS/Protocols/ViewProtocol.swift b/VDS/Protocols/ViewProtocol.swift index 6d3dc4f3..1e184a2d 100644 --- a/VDS/Protocols/ViewProtocol.swift +++ b/VDS/Protocols/ViewProtocol.swift @@ -10,6 +10,8 @@ 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 } @@ -36,28 +38,48 @@ 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 +// 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 {