d
This commit is contained in:
@@ -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<AnyObject?>?,
|
|
||||||
for string: String,
|
|
||||||
errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?
|
|
||||||
) -> 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
17
src/TextFieldValueOwner.swift
Normal file
17
src/TextFieldValueOwner.swift
Normal file
@@ -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<AnyObject?>?,
|
||||||
|
for string: String,
|
||||||
|
errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?
|
||||||
|
) -> Bool {
|
||||||
|
obj?.pointee = "u:\(string)" as AnyObject
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/V.swift
16
src/V.swift
@@ -7,21 +7,13 @@ struct V: View {
|
|||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Check text field:")
|
Text("Check text field:")
|
||||||
Text("'\(vm.t3)'")
|
Text("'\(vm.text)'")
|
||||||
.fontWeight(.bold)
|
.fontWeight(.bold)
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
TextField("Placeholder", text: $vm.text)
|
TextField("Binding-3", value: $vm.text, formatter: TextFieldValueOwner())
|
||||||
.padding(8)
|
.padding(8)
|
||||||
.border(Color.red, width: 2)
|
.border(Color.green, width: 4)
|
||||||
|
|
||||||
TextField("Binding-2", text: vm.bt2)
|
|
||||||
.padding(8)
|
|
||||||
.border(Color.blue, width: 2)
|
|
||||||
*/
|
|
||||||
TextField("Binding-3", value: $vm.t3, formatter: SrcFmt())
|
|
||||||
.padding(8)
|
|
||||||
.border(Color.green, width: 4)
|
|
||||||
}
|
}
|
||||||
.frame(width: 320)
|
.frame(width: 320)
|
||||||
.padding()
|
.padding()
|
||||||
|
|||||||
86
src/VM.swift
86
src/VM.swift
@@ -2,93 +2,25 @@ import Combine
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class VM: ObservableObject {
|
final class VM: ObservableObject {
|
||||||
/*
|
@Published var text = "a:"
|
||||||
@Published var text = ""
|
|
||||||
let changeText = PassthroughSubject<String, Never>()
|
|
||||||
|
|
||||||
@Published var t2 = "a:value"
|
|
||||||
var bt2: Binding<String>!
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Published var t3 = "a:value"
|
|
||||||
|
|
||||||
var subscriptions = Set<AnyCancellable>()
|
var subscriptions = Set<AnyCancellable>()
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
$t3
|
$text
|
||||||
|
// Исключаем конфликты от UI и App путём игнорирования спама.
|
||||||
.debounce(for: .seconds(0.3), scheduler: DispatchQueue.main)
|
.debounce(for: .seconds(0.3), scheduler: DispatchQueue.main)
|
||||||
.sink { v in
|
// Нужны лишь значения от UI.
|
||||||
/**/print("ИГР VM.init t3: '\(v)'")
|
.filter { $0.hasPrefix("u:") }
|
||||||
// Ignore repoting application initiated strings
|
// Убираем источник.
|
||||||
// Only report user initiated strings
|
.map { String($0.dropFirst(2)) }
|
||||||
guard v.hasPrefix("u:") else { return }
|
.sink { Bus.send(MeetupId.Keys.meetupIdTextUI.rawValue, $0) }
|
||||||
Bus.send(MeetupId.Keys.meetupIdTextUI.rawValue, String(v.dropFirst(2)))
|
|
||||||
}
|
|
||||||
.store(in: &subscriptions)
|
.store(in: &subscriptions)
|
||||||
|
|
||||||
Bus.receiveAsync(
|
Bus.receiveAsync(
|
||||||
&subscriptions,
|
&subscriptions,
|
||||||
[MeetupId.Keys.meetupIdTextApp.rawValue],
|
[MeetupId.Keys.meetupIdTextApp.rawValue],
|
||||||
{ [weak self] _, v in self?.applyFormattedValue(v) }
|
{ [weak self] (_, v: String) in self?.text = "a:\(v)" }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
bt2 = Binding<String>(
|
|
||||||
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) }
|
|
||||||
)
|
|
||||||
|
|
||||||
// Интерпретируем текст с задержкой, потому что:
|
|
||||||
// 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)"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user