d
This commit is contained in:
1
Modules/BusX
Symbolic link
1
Modules/BusX
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../../../u/Modules/BusX
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import Combine
|
|
||||||
|
|
||||||
public extension Bus {
|
|
||||||
final class Async<Src, Dst> {
|
|
||||||
let v = PassthroughSubject<Src, Never>()
|
|
||||||
var subscriptions = [AnyCancellable]()
|
|
||||||
|
|
||||||
public init(
|
|
||||||
_ handler: @escaping ((Src) -> Dst?),
|
|
||||||
_ src: String,
|
|
||||||
_ dst: String
|
|
||||||
) {
|
|
||||||
// Вход.
|
|
||||||
Bus.receiveSync(
|
|
||||||
[src],
|
|
||||||
{ [weak self] _, v in self?.v.send(v) },
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
// Выход.
|
|
||||||
Bus.sendSync(
|
|
||||||
dst,
|
|
||||||
v
|
|
||||||
.compactMap { (v: Src) in handler(v) }
|
|
||||||
// Асинхронно.
|
|
||||||
.receive(on: DispatchQueue.main)
|
|
||||||
.eraseToAnyPublisher(),
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
public extension Bus {
|
|
||||||
/// Пропускаем далее единственный ключ.
|
|
||||||
static func convertKeyValue<T>(
|
|
||||||
_ key: String,
|
|
||||||
_ v: (key: String, value: Any)
|
|
||||||
) -> (String, T)? {
|
|
||||||
guard
|
|
||||||
key == v.key,
|
|
||||||
let value = v.value as? T
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return (key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Пропускаем далее множество ключей.
|
|
||||||
static func convertKeyValue<T>(
|
|
||||||
_ keys: Set<String>,
|
|
||||||
_ v: (key: String, value: Any)
|
|
||||||
) -> (String, T)? {
|
|
||||||
guard
|
|
||||||
keys.contains(v.key),
|
|
||||||
let value = v.value as? T
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return (v.key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import Combine
|
|
||||||
|
|
||||||
public extension Bus {
|
|
||||||
final class Debounce<Src, Dst> {
|
|
||||||
let v = PassthroughSubject<Src, Never>()
|
|
||||||
var subscriptions = [AnyCancellable]()
|
|
||||||
|
|
||||||
public init(
|
|
||||||
_ handler: @escaping ((Src) -> Dst?),
|
|
||||||
_ sec: Double,
|
|
||||||
_ src: String,
|
|
||||||
_ dst: String
|
|
||||||
) {
|
|
||||||
// Вход.
|
|
||||||
Bus.receiveSync(
|
|
||||||
[src],
|
|
||||||
{ [weak self] _, v in self?.v.send(v) },
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
// Выход.
|
|
||||||
Bus.sendSync(
|
|
||||||
dst,
|
|
||||||
v
|
|
||||||
.debounce(for: .seconds(sec), scheduler: DispatchQueue.main)
|
|
||||||
.compactMap { (v: Src) in handler(v) }
|
|
||||||
.eraseToAnyPublisher(),
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import Combine
|
|
||||||
|
|
||||||
public extension Bus {
|
|
||||||
final class Delay<Src, Dst> {
|
|
||||||
let v = PassthroughSubject<Src, Never>()
|
|
||||||
var subscriptions = [AnyCancellable]()
|
|
||||||
|
|
||||||
public init(
|
|
||||||
_ handler: @escaping ((Src) -> Dst?),
|
|
||||||
_ sec: Double,
|
|
||||||
_ src: String,
|
|
||||||
_ dst: String
|
|
||||||
) {
|
|
||||||
// Вход.
|
|
||||||
Bus.receiveSync(
|
|
||||||
[src],
|
|
||||||
{ [weak self] _, v in self?.v.send(v) },
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
// Выход.
|
|
||||||
Bus.sendSync(
|
|
||||||
dst,
|
|
||||||
v
|
|
||||||
.delay(for: .seconds(sec), scheduler: DispatchQueue.main)
|
|
||||||
.compactMap { (v: Src) in handler(v) }
|
|
||||||
.eraseToAnyPublisher(),
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import Combine
|
|
||||||
|
|
||||||
public extension Bus {
|
|
||||||
final class Sync<Src, Dst> {
|
|
||||||
let v = PassthroughSubject<Src, Never>()
|
|
||||||
var subscriptions = [AnyCancellable]()
|
|
||||||
|
|
||||||
public init(
|
|
||||||
_ handler: @escaping ((Src) -> Dst?),
|
|
||||||
_ src: String,
|
|
||||||
_ dst: String
|
|
||||||
) {
|
|
||||||
// Вход.
|
|
||||||
Bus.receiveSync(
|
|
||||||
[src],
|
|
||||||
{ [weak self] _, v in self?.v.send(v) },
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
// Выход.
|
|
||||||
Bus.sendSync(
|
|
||||||
dst,
|
|
||||||
v
|
|
||||||
.compactMap { (v: Src) in handler(v) }
|
|
||||||
.eraseToAnyPublisher(),
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import Combine
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public enum Bus {
|
|
||||||
private static let e = PassthroughSubject<(key: String, value: Any), Never>()
|
|
||||||
|
|
||||||
public static var events: AnyPublisher<(key: String, value: Any), Never> {
|
|
||||||
e.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension Bus {
|
|
||||||
/// Асинхронно обрабатываем входящие события из шины.
|
|
||||||
static func receiveAsync<T>(
|
|
||||||
_ keys: Set<String>,
|
|
||||||
_ handler: @escaping ((String, T) -> Void),
|
|
||||||
_ subscriptions: inout [AnyCancellable]
|
|
||||||
) {
|
|
||||||
e
|
|
||||||
.compactMap { convertKeyValue(keys, $0) }
|
|
||||||
.receive(on: DispatchQueue.main)
|
|
||||||
.sink { v in handler(v.0, v.1) }
|
|
||||||
.store(in: &subscriptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Синхронно обрабатываем входящие события из шины.
|
|
||||||
static func receiveSync<T>(
|
|
||||||
_ keys: Set<String>,
|
|
||||||
_ handler: @escaping ((String, T) -> Void),
|
|
||||||
_ subscriptions: inout [AnyCancellable]
|
|
||||||
) {
|
|
||||||
e
|
|
||||||
.compactMap { convertKeyValue(keys, $0) }
|
|
||||||
.sink { v in handler(v.0, v.1) }
|
|
||||||
.store(in: &subscriptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Синхронно отправляем события из узла в шину.
|
|
||||||
///
|
|
||||||
/// Для асинхронной отправки достаточно добавить оператор `receive(on:)`
|
|
||||||
/// в цепочке параметра `node`
|
|
||||||
static func sendSync<T>(
|
|
||||||
_ key: String,
|
|
||||||
_ node: AnyPublisher<T, Never>,
|
|
||||||
_ subscriptions: inout [AnyCancellable]
|
|
||||||
) {
|
|
||||||
node
|
|
||||||
.sink { v in e.send((key, v)) }
|
|
||||||
.store(in: &subscriptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Единоразово синхронно отправляем событие в шину.
|
|
||||||
static func send(_ key: String, _ value: Any) {
|
|
||||||
e.send((key, value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
extension BusUI {
|
|
||||||
/// Пропускаем лишь значения от UI
|
|
||||||
///
|
|
||||||
/// - Returns: Значение без префиксов "a:"/"u:"
|
|
||||||
static func onlyUIText(_ s: String) -> String? {
|
|
||||||
guard s.hasPrefix("u:") else { return nil }
|
|
||||||
return String(s.dropFirst(2))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import Combine
|
|
||||||
|
|
||||||
extension BusUI {
|
|
||||||
public final class Button: ObservableObject {
|
|
||||||
public let v = PassthroughSubject<Void, Never>()
|
|
||||||
var subscriptions = [AnyCancellable]()
|
|
||||||
|
|
||||||
public init(_ key: String) {
|
|
||||||
Bus.sendSync(
|
|
||||||
key,
|
|
||||||
v.map { true }.eraseToAnyPublisher(),
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import Combine
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
extension BusUI {
|
|
||||||
public final class TextField: ObservableObject {
|
|
||||||
@Published public var v = "a:"
|
|
||||||
var subscriptions = [AnyCancellable]()
|
|
||||||
|
|
||||||
public init(
|
|
||||||
_ textApp: String,
|
|
||||||
_ textUI: String
|
|
||||||
) {
|
|
||||||
Bus.sendSync(
|
|
||||||
textUI,
|
|
||||||
$v
|
|
||||||
.removeDuplicates()
|
|
||||||
.compactMap(onlyUIText)
|
|
||||||
.eraseToAnyPublisher(),
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
|
|
||||||
Bus.receiveSync(
|
|
||||||
[textApp],
|
|
||||||
{ [weak self] (_, v: String) in self?.v = "a:\(v)" },
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
|
|
||||||
extension BusUI {
|
|
||||||
public final class TextFieldSource: Formatter {
|
|
||||||
/// Выдаём для отображения очищенную от источника строку.
|
|
||||||
public override func string(for obj: Any?) -> String? {
|
|
||||||
guard let str = obj as? String else { return nil }
|
|
||||||
return String(str.dropFirst(2))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Выдаём для использования кодом строку с указанием источника
|
|
||||||
/// в виде пользователя `u:`
|
|
||||||
public override func getObjectValue(
|
|
||||||
_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?,
|
|
||||||
for string: String,
|
|
||||||
errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?
|
|
||||||
) -> Bool {
|
|
||||||
obj?.pointee = "u:\(string)" as AnyObject
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import Combine
|
|
||||||
|
|
||||||
extension BusUI {
|
|
||||||
public final class Value<T>: ObservableObject {
|
|
||||||
@Published public var v: T
|
|
||||||
var subscriptions = [AnyCancellable]()
|
|
||||||
|
|
||||||
public init(
|
|
||||||
_ key: String,
|
|
||||||
_ defaultValue: T
|
|
||||||
) {
|
|
||||||
v = defaultValue
|
|
||||||
Bus.receiveSync(
|
|
||||||
[key],
|
|
||||||
{ [weak self] (_, v: T) in self?.v = v },
|
|
||||||
&subscriptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
public enum BusUI { }
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
Pod::Spec.new do |s|
|
|
||||||
|
|
||||||
s.name = 'BusX'
|
|
||||||
s.version = '2023.12.30'
|
|
||||||
s.license = 'IVCS'
|
|
||||||
s.summary = 'Шина общения элементов приложения'
|
|
||||||
s.homepage = 'IVCS'
|
|
||||||
s.author = 'IVCS'
|
|
||||||
s.source = { :git => 'https://fake.com/FAKE.git', :tag => s.version }
|
|
||||||
s.source_files = '**/**/*.swift'
|
|
||||||
s.swift_version = '5.2'
|
|
||||||
s.ios.deployment_target = '14.0'
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- AELog (0.6.3)
|
- AELog (0.6.3)
|
||||||
- BusX (2023.12.30)
|
- BusX (2024.01.15)
|
||||||
- MeetupIdX (2023.12.31):
|
- MeetupIdX (2023.12.31):
|
||||||
- AELog
|
- AELog
|
||||||
- BusX
|
- BusX
|
||||||
@@ -27,7 +27,7 @@ EXTERNAL SOURCES:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
AELog: f732b70f7a9d1b4c6a3676304192b3908f362133
|
AELog: f732b70f7a9d1b4c6a3676304192b3908f362133
|
||||||
BusX: d11e857e9cb762f649ee9f88fd5a4f8fbf5bf96b
|
BusX: 1db5cf8652f7b206af468cc115cab3326efd1ced
|
||||||
MeetupIdX: 2fa9fb27717aa8878ff495c1abe960c96e524308
|
MeetupIdX: 2fa9fb27717aa8878ff495c1abe960c96e524308
|
||||||
MPAKX: dc592434f55edf34709f6e4f37c9ec90dcd95185
|
MPAKX: dc592434f55edf34709f6e4f37c9ec90dcd95185
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user