diff --git a/src/SrcFmt.swift b/src/SrcFmt.swift deleted file mode 100644 index 2f8b33a..0000000 --- a/src/SrcFmt.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation - -class SrcFmt: Formatter { - override func string(for obj: Any?) -> String? { - /**///print("ИГР SrcF.string obj: '\(obj)'") - guard let str = obj as? String else { return nil } - return String(str.dropFirst(2)) - } - - override func getObjectValue( - _ obj: AutoreleasingUnsafeMutablePointer?, - for string: String, - errorDescription error: AutoreleasingUnsafeMutablePointer? - ) -> Bool { - /**///print("ИГР SrcF.getOV string: '\(string)'") - let val: String - if string.hasPrefix("a:") || string.hasPrefix("u:") { - /**///print("ИГР SrcF.getOV-1") - val = string - } else { - /**///print("ИГР SrcF.getOV-2") - val = "u:\(string)" - } - obj?.pointee = val as AnyObject - return true - } -} diff --git a/src/TextFieldValueOwner.swift b/src/TextFieldValueOwner.swift new file mode 100644 index 0000000..2e245cf --- /dev/null +++ b/src/TextFieldValueOwner.swift @@ -0,0 +1,17 @@ +import Foundation + +class TextFieldValueOwner: Formatter { + override func string(for obj: Any?) -> String? { + guard let str = obj as? String else { return nil } + return String(str.dropFirst(2)) + } + + override func getObjectValue( + _ obj: AutoreleasingUnsafeMutablePointer?, + for string: String, + errorDescription error: AutoreleasingUnsafeMutablePointer? + ) -> Bool { + obj?.pointee = "u:\(string)" as AnyObject + return true + } +} diff --git a/src/V.swift b/src/V.swift index 0eb6dda..809fb64 100644 --- a/src/V.swift +++ b/src/V.swift @@ -7,21 +7,13 @@ struct V: View { VStack { HStack { Text("Check text field:") - Text("'\(vm.t3)'") + Text("'\(vm.text)'") .fontWeight(.bold) } - /* - TextField("Placeholder", text: $vm.text) - .padding(8) - .border(Color.red, width: 2) - - TextField("Binding-2", text: vm.bt2) + + TextField("Binding-3", value: $vm.text, formatter: TextFieldValueOwner()) .padding(8) - .border(Color.blue, width: 2) - */ - TextField("Binding-3", value: $vm.t3, formatter: SrcFmt()) - .padding(8) - .border(Color.green, width: 4) + .border(Color.green, width: 4) } .frame(width: 320) .padding() diff --git a/src/VM.swift b/src/VM.swift index 2621c05..35eef6a 100644 --- a/src/VM.swift +++ b/src/VM.swift @@ -2,93 +2,25 @@ import Combine import SwiftUI final class VM: ObservableObject { - /* - @Published var text = "" - let changeText = PassthroughSubject() - - @Published var t2 = "a:value" - var bt2: Binding! - */ - - @Published var t3 = "a:value" + @Published var text = "a:" var subscriptions = Set() init() { - $t3 + $text + // Исключаем конфликты от UI и App путём игнорирования спама. .debounce(for: .seconds(0.3), scheduler: DispatchQueue.main) - .sink { v in - /**/print("ИГР VM.init t3: '\(v)'") - // Ignore repoting application initiated strings - // Only report user initiated strings - guard v.hasPrefix("u:") else { return } - Bus.send(MeetupId.Keys.meetupIdTextUI.rawValue, String(v.dropFirst(2))) - } + // Нужны лишь значения от UI. + .filter { $0.hasPrefix("u:") } + // Убираем источник. + .map { String($0.dropFirst(2)) } + .sink { Bus.send(MeetupId.Keys.meetupIdTextUI.rawValue, $0) } .store(in: &subscriptions) Bus.receiveAsync( &subscriptions, [MeetupId.Keys.meetupIdTextApp.rawValue], - { [weak self] _, v in self?.applyFormattedValue(v) } - ) - - -/* - bt2 = Binding( - get: { [weak self] in - String(self?.t2.dropFirst(2) ?? "") - }, - set: { [weak self] v in - if v.hasPrefix("a:") { - self?.t2 = v - } else { - self?.t2 = "u:\(v)" - } - } - ) - - $t2 - .debounce(for: .seconds(0.3), scheduler: DispatchQueue.main) - .sink { v in - /**/print("ИГР VM.init t2: '\(v)'") - // Ignore repoting application initiated strings - // Only report user initiated strings - guard v.hasPrefix("u:") else { return } - Bus.Service.singleton?.send(MeetupId.Keys.meetupIdTextUI.rawValue, String(v.dropFirst(2))) - } - .store(in: &subscriptions) - - Bus.receive( - &subscriptions, - [MeetupId.Keys.meetupIdTextApp.rawValue], - { [weak self] k, v in self?.handleAppValue(k, v) } + { [weak self] (_, v: String) in self?.text = "a:\(v)" } ) - - // Интерпретируем текст с задержкой, потому что: - // 1. смена @Published в ту же секунду игнорируется - // полем ввода, т.е. нужна задержка - // 2. ожидаем окончания ввода (спама), чтобы - // обработать введённое без потерь из-за конфликта - // старых данных и новых. - $text - .debounce(for: .seconds(0.3), scheduler: DispatchQueue.main) - .sink { [weak self] v in - guard - let out = MeetupId.shouldFormat(v), - v != out - else { - return - } - /**/print("ИГР TFCVM.init changeT in/out: '\(v)'/'\(out)'") - self?.text = out - } - .store(in: &subscriptions) - */ - } - - func applyFormattedValue(_ value: String) { - /**/print("ИГР VM.handleFV value: '\(value)'") - t3 = "a:\(value)" } - }