Catch Pasted Text on TextField SwiftUI

135 Views Asked by At

I have created a PasteBoardObserver class to catch pasted text and change isCodePasted Bool but it can not detect if it is pasted. None of the print statements inside PasteboardObserver is triggered. But the one inside onReceive(pasteboardObserver.$pastedCode) foo pasted is printed

    import SwiftUI
import UIKit
import Combine

class PasteboardObserver: ObservableObject {
    @Published var pastedCode: String = ""
    @Published var isCodePasted: Bool = false

private var cancellable: AnyCancellable?

init() {
    self.cancellable = NotificationCenter.default.publisher(for: UIPasteboard.changedNotification)
        .sink { _ in
            DispatchQueue.main.async {
                print("Pasteboard changed")
                if let string = UIPasteboard.general.string {
                    print("Pasted string: \(string)")
                    self.pastedCode = string
                    self.isCodePasted = true
                } else {
                    print("No string found in pasteboard")
                }
            }
        }
}
}

So I can detect the change and fetch pasted code from my textfield like this.

struct CUINDPasteValidationTextField: View {
 var body: some View {
        VStack(alignment: .leading) {
            HStack {
                    CUINDTextField(text: $text,
                                   focused: $focused,
                                   placeholder: placeholder,
                                   fontColor: style.fontColor
                    )
                    .onReceive(pasteboardObserver.$pastedCode) { pastedCode in
                        print("foo pasted")
                        print(pastedCode)
                    }
            }

Now it does understand when something is pasted but it always is "". How could I catch pasted text and change the status of isPastedCode correctly?

1

There are 1 best solutions below

0
workingdog support Ukraine On

It seems your self.cancellable = NotificationCenter.default.publisher ... may not be working properly.

You could try this simple alternative approach, using a NotificationCenter.default.addObserver, and .onChange(..) to catch the pasted text and change the status of isPastedCode.

Example code:

 import Foundation
 import SwiftUI
 

class PasteboardObserver: ObservableObject {
    @Published var pastedCode = ""
    @Published var isCodePasted = false
    
    init() {
        NotificationCenter.default.addObserver(forName: UIPasteboard.changedNotification, object: nil, queue: .main) { _ in
            if let string = UIPasteboard.general.string {
                self.pastedCode = string
            }
        }
    }
}

struct ContentView: View {
    @StateObject var pboard = PasteboardObserver()
    @State private var txt1 = "xyz"
    @State private var txt2 = ""
    
    var body: some View {
        VStack(spacing: 55) {
            Text("pastedCode: \(pboard.pastedCode)")

            // for testing highlight then copy the text, Cmd+c
            TextField("type and copy text", text: $txt1).border(.red)
            
            // for testing paste the text, Cmg+v
            TextField("paste some text", text: $txt2).border(.blue)
                .onChange(of: txt2) {
                    // for testing
                    if txt2 == pboard.pastedCode {
                        pboard.isCodePasted = true
                        print("---> onChange pastedCode: \(pboard.pastedCode)")
                    }
                }
                 //.onReceive(pboard.pastedCode.publisher) { _ in
                 // print("------> onReceive: \(pboard.pastedCode) ")
                 // }
        }
    }
    
}