@@ -4,6 +4,7 @@ import UIKit | |||||
class AppDelegate: UIResponder, UIApplicationDelegate | class AppDelegate: UIResponder, UIApplicationDelegate | ||||
{ | { | ||||
let bus = Bus.Service() | let bus = Bus.Service() | ||||
let fmt = MeetupId.MeetupIdFormatter() | |||||
var window: UIWindow? | var window: UIWindow? | ||||
func application( | func application( | ||||
@@ -17,6 +17,7 @@ extension Bus { | |||||
} | } | ||||
func send(_ key: String, _ value: Any) { | func send(_ key: String, _ value: Any) { | ||||
/**/print("ИГР BusS.send key/value: '\(key)'/'\(value)'") | |||||
broadcaster.send((key, value)) | broadcaster.send((key, value)) | ||||
} | } | ||||
} | } | ||||
@@ -1,3 +1,4 @@ | |||||
import Combine | |||||
import Foundation | import Foundation | ||||
enum MeetupId { | enum MeetupId { | ||||
@@ -9,13 +10,12 @@ enum MeetupId { | |||||
static func shouldFormat(_ s: String) -> String? { | static func shouldFormat(_ s: String) -> String? { | ||||
s.components(separatedBy: NSCharacterSet.decimalDigits.inverted).reduce("") { $0 + $1 } | s.components(separatedBy: NSCharacterSet.decimalDigits.inverted).reduce("") { $0 + $1 } | ||||
} | } | ||||
/* | |||||
final class MeetupIdFormatter { | final class MeetupIdFormatter { | ||||
var subscriptions = [AnyCancellable]() | |||||
var subscriptions = Set<AnyCancellable>() | |||||
deinit { | deinit { | ||||
/**/dbg("ИГР MeetupIF.DEinit") | |||||
/**/print("ИГР MeetupIF.DEinit") | |||||
} | } | ||||
init() { | init() { | ||||
@@ -24,16 +24,16 @@ enum MeetupId { | |||||
[Keys.meetupIdTextUI.rawValue], | [Keys.meetupIdTextUI.rawValue], | ||||
{ [weak self] k, v in self?.handleFormatting(k, v) } | { [weak self] k, v in self?.handleFormatting(k, v) } | ||||
) | ) | ||||
/**/dbg("ИГР MeetupIF.init") | |||||
/**/print("ИГР MeetupIF.init") | |||||
} | } | ||||
func handleFormatting(_: String, _ value: String) { | func handleFormatting(_: String, _ value: String) { | ||||
let out = MeetupId.shouldFormat(value) | let out = MeetupId.shouldFormat(value) | ||||
/**/dbg("ИГР MeetupIF.handleF out/dt: '\(out)'/'\(Date())'") | |||||
/**/print("ИГР MeetupIF.handleF out/dt: '\(out)'/'\(Date())'") | |||||
Bus.Service.singleton?.send(Keys.meetupIdTextApp.rawValue, out) | Bus.Service.singleton?.send(Keys.meetupIdTextApp.rawValue, out) | ||||
} | } | ||||
} | } | ||||
/* | |||||
struct V: View { | struct V: View { | ||||
/*@StateObject*/ var fmt = MeetupIdFormatter() | /*@StateObject*/ var fmt = MeetupIdFormatter() | ||||
@StateObject var txt = Bus.BindingPipe("", Keys.meetupIdTextApp.rawValue, Keys.meetupIdTextUI.rawValue) | @StateObject var txt = Bus.BindingPipe("", Keys.meetupIdTextApp.rawValue, Keys.meetupIdTextUI.rawValue) | ||||
@@ -13,6 +13,10 @@ struct V: View { | |||||
TextField("Placeholder", text: $vm.text) | TextField("Placeholder", text: $vm.text) | ||||
.padding(8) | .padding(8) | ||||
.border(Color.red, width: 2) | .border(Color.red, width: 2) | ||||
TextField("Binding-2", text: vm.bt2) | |||||
.padding(8) | |||||
.border(Color.blue, width: 2) | |||||
} | } | ||||
.frame(width: 320) | .frame(width: 320) | ||||
.padding() | .padding() | ||||
@@ -4,9 +4,42 @@ import SwiftUI | |||||
final class VM: ObservableObject { | final class VM: ObservableObject { | ||||
@Published var text = "" | @Published var text = "" | ||||
let changeText = PassthroughSubject<String, Never>() | let changeText = PassthroughSubject<String, Never>() | ||||
@Published var t2 = "a:value" | |||||
var bt2: Binding<String>! | |||||
var subscriptions = Set<AnyCancellable>() | var subscriptions = Set<AnyCancellable>() | ||||
init() { | init() { | ||||
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 в ту же секунду игнорируется | // 1. смена @Published в ту же секунду игнорируется | ||||
// полем ввода, т.е. нужна задержка | // полем ввода, т.е. нужна задержка | ||||
@@ -27,4 +60,14 @@ final class VM: ObservableObject { | |||||
} | } | ||||
.store(in: &subscriptions) | .store(in: &subscriptions) | ||||
} | } | ||||
func handleAppValue(_: String, _ value: String) { | |||||
/**/print("ИГР VM.handleAV value: '\(value)'") | |||||
/* | |||||
DispatchQueue.main.async { [weak self] in | |||||
self?.t2 = value | |||||
} | |||||
*/ | |||||
} | |||||
} | } |