From 0ae2dd270679314ca59b323275ed4224ef9abc8a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 1 May 2024 17:36:20 -0500 Subject: [PATCH] textview publisher Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 4 ++ VDS/Publishers/UITextView+Publisher.swift | 68 +++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 VDS/Publishers/UITextView+Publisher.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index c51f9af4..e039930a 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -57,6 +57,7 @@ EA2DC9B02BE175BA004F58C5 /* RequiredRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */; }; EA2DC9B22BE175E6004F58C5 /* CharacterCountRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9B12BE175E6004F58C5 /* CharacterCountRule.swift */; }; EA2DC9B42BE2C6FE004F58C5 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9B32BE2C6FE004F58C5 /* TextField.swift */; }; + EA2DC9B62BE2F4A1004F58C5 /* UITextView+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2DC9B52BE2F4A1004F58C5 /* UITextView+Publisher.swift */; }; EA336171288B19200071C351 /* VDS.docc in Sources */ = {isa = PBXBuildFile; fileRef = EA336170288B19200071C351 /* VDS.docc */; }; EA336177288B19210071C351 /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA33616C288B19200071C351 /* VDS.framework */; }; EA33617C288B19210071C351 /* VDSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA33617B288B19210071C351 /* VDSTests.swift */; }; @@ -249,6 +250,7 @@ EA2DC9AF2BE175BA004F58C5 /* RequiredRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequiredRule.swift; sourceTree = ""; }; EA2DC9B12BE175E6004F58C5 /* CharacterCountRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCountRule.swift; sourceTree = ""; }; EA2DC9B32BE2C6FE004F58C5 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = ""; }; + EA2DC9B52BE2F4A1004F58C5 /* UITextView+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Publisher.swift"; sourceTree = ""; }; EA33616C288B19200071C351 /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EA33616F288B19200071C351 /* VDS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VDS.h; sourceTree = ""; }; EA336170288B19200071C351 /* VDS.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = VDS.docc; sourceTree = ""; }; @@ -850,6 +852,7 @@ children = ( EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */, EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */, + EA2DC9B52BE2F4A1004F58C5 /* UITextView+Publisher.swift */, EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */, ); path = Publishers; @@ -1168,6 +1171,7 @@ EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */, EA4DB30228DCBCA500103EE3 /* Badge.swift in Sources */, EA33624728931B050071C351 /* Initable.swift in Sources */, + EA2DC9B62BE2F4A1004F58C5 /* UITextView+Publisher.swift in Sources */, EAF7F0A4289B017C00B287F5 /* LabelAttributeModel.swift in Sources */, EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */, EA5F86D02A1F936100BC83E4 /* TabsContainer.swift in Sources */, diff --git a/VDS/Publishers/UITextView+Publisher.swift b/VDS/Publishers/UITextView+Publisher.swift new file mode 100644 index 00000000..1c9642b9 --- /dev/null +++ b/VDS/Publishers/UITextView+Publisher.swift @@ -0,0 +1,68 @@ +// +// UITextView+Publisher.swift +// VDS +// +// Created by Matt Bruce on 5/1/24. +// + +import Foundation +import UIKit +import Combine + +extension UITextView { + + public enum Event { + case editingChanged + case editingDidBegin + case editingDidEnd + } + + public func publisher(for event: Event) -> AnyPublisher { + TextViewPublisher(textView: self).publisher(for: event) + } +} + +class TextViewPublisher: NSObject, UITextViewDelegate { + var textDidChangePublisher: AnyPublisher + var didBeginEditingPublisher: AnyPublisher + var didEndEditingPublisher: AnyPublisher + + private var cancellables = Set() + + init(textView: UITextView) { + textDidChangePublisher = NotificationCenter.default.publisher(for: UITextView.textDidChangeNotification, object: textView) + .compactMap { notification in + (notification.object as? UITextView) + } + .eraseToAnyPublisher() + + didBeginEditingPublisher = NotificationCenter.default.publisher(for: UITextView.textDidBeginEditingNotification, object: textView) + .compactMap { notification in + (notification.object as? UITextView) + } + .eraseToAnyPublisher() + + didEndEditingPublisher = NotificationCenter.default.publisher(for: UITextView.textDidEndEditingNotification, object: textView) + .compactMap { notification in + (notification.object as? UITextView) + } + .eraseToAnyPublisher() + } + + func publisher(for event: UITextView.Event) -> AnyPublisher { + switch event { + case .editingChanged: + return textDidChangePublisher + .map { $0 } + .eraseToAnyPublisher() + case .editingDidBegin: + return didBeginEditingPublisher + .map { $0 } + .eraseToAnyPublisher() + case .editingDidEnd: + return didEndEditingPublisher + .map { $0 } + .eraseToAnyPublisher() + } + } +}