diff --git a/src/App.swift b/src/App.swift index cfaabc4..238ee04 100644 --- a/src/App.swift +++ b/src/App.swift @@ -22,73 +22,3 @@ class AppDelegate: UIResponder, UIApplicationDelegate return true } } - -/* -// Bus.Pipe.swift -public extension Bus { - final class BindingPipe: ObservableObject { - public let input = PassthroughSubject() - public let output = PassthroughSubject() - @Published var value: T - var isInput = false - var subscriptions = [AnyCancellable]() - - deinit { - print("ИГР BusBP.DEinit(\(Unmanaged.passUnretained(self).toOpaque()))") - } - - init( - _ defaultValue: T, - _ keyApp: String, - _ keyUI: String - ) { - value = defaultValue - /**/dbg("ИГР BusBP.init(\(Unmanaged.passUnretained(self).toOpaque())) keyA: '\(keyApp)'") - - // TextField -> output. - $value - .sink { [weak self] v in - assert(Thread.isMainThread) - // Ignore values received from input. - // Only accept UI provided values. - guard - let self, - !self.isInput - else { - return - } - self.output.send(v) - } - .store(in: &subscriptions) - - // input -> TextField. - input - .sink { [weak self] v in - assert(Thread.isMainThread) - guard let self else { return } - /**/dbg("ИГР BusBP.init input: '\(v)'") - self.isInput = true - self.value = v - self.isInput = false - } - .store(in: &subscriptions) - - // Оповещаем в мир об изменениях от UI. - Bus.sendAsync( - &subscriptions, - keyUI, - output.eraseToAnyPublisher() - ) - - Bus.receive( - &subscriptions, - [keyApp], - { [weak self] _, v in - self?.input.send(v) - /**/print("ИГР BusBP.init receive: '\(v)'") - } - ) - } - } -} -*/ diff --git a/src/Bus.swift b/src/Bus.swift index 5fbf9b9..b61cad6 100644 --- a/src/Bus.swift +++ b/src/Bus.swift @@ -24,7 +24,7 @@ extension Bus { } public extension Bus { - static func receive( + static func receiveAsync( _ subscriptions: inout Set, _ keys: Set, _ handler: @escaping ((String, T) -> Void) @@ -39,11 +39,12 @@ public extension Bus { } return (v.key, value) } + .receive(on: DispatchQueue.main) .sink { v in handler(v.0, v.1) } .store(in: &subscriptions) } - - static func receiveAsync( + + static func receiveSync( _ subscriptions: inout Set, _ keys: Set, _ handler: @escaping ((String, T) -> Void) @@ -58,18 +59,11 @@ public extension Bus { } return (v.key, value) } - .receive(on: DispatchQueue.main) .sink { v in handler(v.0, v.1) } .store(in: &subscriptions) } - static func send(_ key: String, _ value: Any) { - Service.singleton?.send(key, value) - } - - - /* - static func sendAsync( + static func sendAsync( _ subscriptions: inout Set, _ key: String, _ node: AnyPublisher @@ -79,5 +73,36 @@ public extension Bus { .sink { v in Service.singleton?.send(key, v) } .store(in: &subscriptions) } - */ + + static func sendSync( + _ subscriptions: inout Set, + _ key: String, + _ node: AnyPublisher + ) { + node + .sink { v in Service.singleton?.send(key, v) } + .store(in: &subscriptions) + } + + static func sendOnce(_ key: String, _ value: Any) { + Service.singleton?.send(key, value) + } +} + +public extension Bus { + static func registerProcessing( + _ subscriptions: inout Set, + _ keyIn: String, + _ keyOut: String, + _ handler: @escaping ((Src) -> Dst?) + ) { + Service.singleton?.broadcaster + .filter { $0.key == keyIn } + .compactMap { + guard let vIn = $0.value as? Src else { return nil } + return handler(vIn) + } + .sink { vOut in Service.singleton?.send(keyOut, vOut) } + .store(in: &subscriptions) + } } diff --git a/src/MeetupId.swift b/src/MeetupId.swift index cdfef31..99df8ea 100644 --- a/src/MeetupId.swift +++ b/src/MeetupId.swift @@ -18,6 +18,9 @@ enum MeetupId { r += "-" } } + if r.hasSuffix("-") { + r = String(r.dropLast(1)) + } return r } @@ -29,36 +32,13 @@ enum MeetupId { } init() { - Bus.receive( - &subscriptions, - [Keys.meetupIdTextUI.rawValue], - Self.handleFormatting + Bus.registerProcessing( + &subscriptions, + Keys.meetupIdTextUI.rawValue, + Keys.meetupIdTextApp.rawValue, + MeetupId.shouldFormat ) /**/print("ИГР MeetupIF.init") } - - static func handleFormatting(_: String, _ value: String) { - let out = MeetupId.shouldFormat(value) - /**/print("ИГР MeetupIF.handleF out/dt: '\(out)'/'\(Date())'") - Bus.send(Keys.meetupIdTextApp.rawValue, out) - } - } -/* - struct V: View { - /*@StateObject*/ var fmt = MeetupIdFormatter() - @StateObject var txt = Bus.BindingPipe("", Keys.meetupIdTextApp.rawValue, Keys.meetupIdTextUI.rawValue) - - var body: some View { - VStack { - Text("Hi, the text is: '\(txt.value)'") - .fontWeight(.bold) - TextField("Placeholder", text: $txt.value) - .padding(8) - .border(Color.blue, width: 2) - } - .frame(width: 320) - .padding() - } } - */ } diff --git a/src/VM.swift b/src/VM.swift index 35eef6a..f79d2c5 100644 --- a/src/VM.swift +++ b/src/VM.swift @@ -7,15 +7,18 @@ final class VM: ObservableObject { var subscriptions = Set() init() { - $text - // Исключаем конфликты от UI и App путём игнорирования спама. - .debounce(for: .seconds(0.3), scheduler: DispatchQueue.main) - // Нужны лишь значения от UI. - .filter { $0.hasPrefix("u:") } - // Убираем источник. - .map { String($0.dropFirst(2)) } - .sink { Bus.send(MeetupId.Keys.meetupIdTextUI.rawValue, $0) } - .store(in: &subscriptions) + Bus.sendSync( + &subscriptions, + MeetupId.Keys.meetupIdTextUI.rawValue, + $text + // Исключаем конфликты от UI и App путём игнорирования спама. + .debounce(for: .seconds(0.3), scheduler: DispatchQueue.main) + // Нужны лишь значения от UI. + .filter { $0.hasPrefix("u:") } + // Убираем источник. + .map { String($0.dropFirst(2)) } + .eraseToAnyPublisher() + ) Bus.receiveAsync( &subscriptions,