42 Commits
lvl4 ... main

Author SHA1 Message Date
Михаил Капелько
cb527c2154 d 2024-01-10 10:38:45 +03:00
Михаил Капелько
0309ab67b4 d 2024-01-08 18:33:54 +03:00
Михаил Капелько
3bb8d453c4 d 2024-01-08 18:19:33 +03:00
Михаил Капелько
46d2602ef7 d 2024-01-08 18:14:46 +03:00
Михаил Капелько
8f2ed4ae51 d 2024-01-08 18:13:25 +03:00
Михаил Капелько
d2a948e7c7 d 2024-01-08 18:12:59 +03:00
Михаил Капелько
567d322516 d 2024-01-08 18:06:52 +03:00
Михаил Капелько
e032918bf3 d 2024-01-08 18:06:11 +03:00
Михаил Капелько
00a9a25997 d 2024-01-08 17:56:57 +03:00
Михаил Капелько
a35ffcfbd4 d 2024-01-08 17:48:00 +03:00
Михаил Капелько
e8f330ad2a d 2024-01-08 17:45:45 +03:00
Михаил Капелько
aa203c2337 d 2024-01-08 16:29:16 +03:00
Михаил Капелько
27fb18c484 d 2024-01-08 16:28:59 +03:00
Михаил Капелько
2758b24ef7 d 2024-01-08 16:22:59 +03:00
Михаил Капелько
e7975f151c d 2024-01-08 16:10:55 +03:00
Михаил Капелько
65977e902f d 2024-01-08 16:02:04 +03:00
Михаил Капелько
7f7a27f4e0 d 2024-01-08 16:01:12 +03:00
Михаил Капелько
92e89bb0cf d 2024-01-08 16:00:01 +03:00
Михаил Капелько
dbcf2a17a6 d 2024-01-08 15:58:44 +03:00
Михаил Капелько
7faab99ad2 d 2024-01-08 15:40:59 +03:00
Михаил Капелько
27865e97b3 d 2024-01-08 15:38:11 +03:00
Михаил Капелько
f605fdbf52 d 2024-01-08 15:34:06 +03:00
Михаил Капелько
95f66ab82c d 2024-01-08 15:33:18 +03:00
Михаил Капелько
005621eccc d 2024-01-08 15:12:13 +03:00
Михаил Капелько
336aa98fd2 d 2024-01-08 15:07:40 +03:00
Михаил Капелько
da24b42515 d 2024-01-08 15:03:29 +03:00
Михаил Капелько
cfe804522f d 2024-01-08 15:01:02 +03:00
Михаил Капелько
1f501d8276 d 2024-01-08 10:14:18 +03:00
Михаил Капелько
de42152b9f d 2024-01-08 10:09:32 +03:00
Михаил Капелько
c3265592a7 d 2024-01-08 10:05:59 +03:00
Михаил Капелько
895f74440b d 2024-01-08 09:50:08 +03:00
Михаил Капелько
af7ddfa161 d 2024-01-08 09:40:36 +03:00
Михаил Капелько
f4bb4e50e3 d 2024-01-06 18:43:44 +03:00
Михаил Капелько
a018cbee59 d 2024-01-06 18:41:12 +03:00
Михаил Капелько
676ec75bef d 2024-01-06 18:40:23 +03:00
Михаил Капелько
f11dde1c8e d 2024-01-06 18:38:19 +03:00
Михаил Капелько
676a1ada17 d 2024-01-06 18:35:45 +03:00
Михаил Капелько
f3807b76f6 d 2024-01-06 18:31:59 +03:00
Михаил Капелько
56512ca26a d 2024-01-06 18:22:22 +03:00
Михаил Капелько
a5de0484fd d 2024-01-06 17:59:47 +03:00
Михаил Капелько
f838021562 d 2024-01-06 17:59:15 +03:00
Михаил Капелько
752b34b95d d 2024-01-06 17:55:56 +03:00
29 changed files with 413 additions and 41 deletions

View File

@@ -0,0 +1,36 @@
import Combine
import MPAKX
extension BusUI {
public final class ManyButton: ObservableObject {
let key: String
public let v = PassthroughSubject<Void, Never>()
@Published public var id: String?
var sub = [AnyCancellable]()
var subscriptions = [AnyCancellable]()
public init(_ key: String) {
self.key = key
$id
.sink { [weak self] id in self?.setup(id) }
.store(in: &sub)
}
private func setup(_ id: String?) {
subscriptions = []
Bus.sendSync(
key,
v
.compactMap { v -> Any? in
guard let id else { return nil }
var d = [String: Bool]()
return MPAK.Many([id], d)
}
.eraseToAnyPublisher(),
&subscriptions
)
}
}
}

View File

@@ -0,0 +1,64 @@
import Combine
import MPAKX
import SwiftUI
extension BusUI {
public final class ManyTextField: ObservableObject {
let textApp: String
let textUI: String
@Published public var id: String?
@Published public var v = "a:"
var sub = [AnyCancellable]()
var subscriptions = [AnyCancellable]()
public init(
_ textApp: String,
_ textUI: String
) {
self.textApp = textApp
self.textUI = textUI
$id
.sink { [weak self] id in self?.setup(id) }
.store(in: &sub)
}
private func setup(_ id: String?) {
subscriptions = []
Bus.sendSync(
textUI,
$v
.removeDuplicates()
.compactMap { v -> Any? in
guard
let id,
let text = onlyUIText(v)
else {
return nil
}
var d = [String: String]()
d[id] = text
return MPAK.Many([id], d)
}
.eraseToAnyPublisher(),
&subscriptions
)
Bus.receiveSync(
[textApp],
{ [weak self] (_, m: MPAK.Many<String>) in
guard
let id,
m.keys.contains(id),
let text = m.dict[id]
else {
return
}
self?.v = "a:\(text)"
},
&subscriptions
)
}
}
}

View File

@@ -0,0 +1,43 @@
import Combine
import MPAKX
extension BusUI {
public final class ManyValue<T>: ObservableObject {
let key: String
@Published public var id: String?
@Published public var v: T
var sub = [AnyCancellable]()
var subscriptions = [AnyCancellable]()
public init(
_ key: String,
_ defaultValue: T
) {
self.key = key
v = defaultValue
$id
.sink { [weak self] id in self?.setup(id) }
.store(in: &sub)
}
private func setup(_ id: String?) {
subscriptions = []
Bus.receiveSync(
[key],
{ [weak self] (_, m: MPAK.Many<T>) in
guard
let id,
m.keys.contains(id),
let v = m.dict[id]
else {
return
}
self?.v = v
},
&subscriptions
)
}
}
}

View File

@@ -10,5 +10,6 @@ s.source = { :git => 'https://fake.com/FAKE.git', :tag => s.versi
s.source_files = '**/**/*.swift'
s.swift_version = '5.2'
s.ios.deployment_target = '14.0'
s.dependency 'MPAKX'
end

View File

@@ -0,0 +1,16 @@
extension MPAK {
public struct Many<T> {
public var keys: Set<String>
public var dict: [String: T]
public var isRecent: Bool { !keys.isEmpty }
public init(
_ keys: Set<String> = [],
_ dict: [String: T] = [:]
) {
self.keys = keys
self.dict = dict
}
}
}

View File

@@ -0,0 +1,10 @@
extension MPAK {
public struct Recent<T> {
public var isRecent = false
public var value: T
public init(_ value: T) {
self.value = value
}
}
}

View File

@@ -1,10 +1 @@
public enum MPAK {
public struct Recent<T> {
public var isRecent = false
public var value: T
public init(_ value: T) {
self.value = value
}
}
}
public enum MPAK { }

View File

@@ -5,14 +5,16 @@ model:
isLoading: [Bool, false]
join: [Bool, false]
textUI: [String, ""]
testTextUI: [String, ""]
service:
actions:
busModel
pipes:
finishLoading: [toggle, K.finishLoading]
isLoading: [recent, K.isLoading]
isLoading: [many, K.isLoading]
join: [toggle, K.join]
textUI: [recent, K.textUI]
textUI: [many, K.textUI]
testTextUI: [many, K.testTextUI]
world:

View File

@@ -15,6 +15,7 @@ public protocol MeetupIdContext {
var isLoading: MPAK.Recent<Bool> { get }
var join: Bool { get }
var textUI: MPAK.Recent<String> { get }
var testTextUI: MPAK.Many<String> { get }
}
// MARK: - Controller
@@ -39,6 +40,7 @@ extension MeetupId {
public var isLoading: MPAK.Recent<Bool> = .init(false)
public var join: Bool = false
public var textUI: MPAK.Recent<String> = .init("")
public var testTextUI: MPAK.Many<String> = .init()
}
// MARK: - Service
@@ -47,12 +49,14 @@ extension MeetupId {
let ctrl = Controller()
let world: World
var any = [Any]()
var subscriptions = [AnyCancellable]()
static private(set) weak var singleton: Service?
public init(_ world: World) {
self.world = world
Self.singleton = self
SectionBus.setupService(ctrl, self, world)
SectionGenerated.setupPlatform(ctrl, self, world)
}
}
@@ -141,6 +145,18 @@ extension MeetupId {
ctrl.pipeValue(
dbg: "testTUI",
sub: nil,
Bus.events.compactMap { Bus.convertKeyValue(K.testTextUI, $0) }.map { (k: String, v: MPAK.Many<String>) in v }.eraseToAnyPublisher(),
{
$0.testTextUI = $1
},
{ m, _ in m.testTextUI.keys = [] }
)
}

View File

@@ -7,6 +7,9 @@ public extension MeetupId {
static let M = "MeetupId"
static let textApp = "MeetupId.textApp"
static let textUI = "MeetupId.textUI"
static let testTextApp = "MeetupId.testTextApp"
static let testTextUI = "MeetupId.testTextUI"
}
}

View File

@@ -0,0 +1,24 @@
import BusX
extension MeetupId {
enum SectionBus {
static func setupService(
_ ctrl: Controller,
_ service: Service,
_ world: World
) {
service.any.append(contentsOf: [
//Bus.Debounce(shouldResetText, 0.2, K.M, K.textApp),
Bus.Debounce(shouldManyResetText, 0.2, K.M, K.textApp),
//Bus.Delay(shouldFinishLoading, 5, K.M, K.finishLoading),
Bus.Delay(shouldManyFinishLoading, 5, K.M, K.finishLoading),
//Bus.Sync(shouldEnableJoin, K.M, K.isJoinAvailable),
Bus.Sync(shouldManyJoin, K.M, K.isJoinAvailable),
//Bus.Sync(shouldResetLoading, K.M, K.isLoading),
Bus.Sync(shouldManyResetLoading, K.M, K.isLoading),
Bus.Debounce(shouldManyTestResetText, 0.2, K.M, K.testTextApp),
])
}
}
}

View File

@@ -1,6 +1,8 @@
import Foundation
import MPAKX
public extension MeetupId {
/*
static func shouldEnableJoin(_ c: MeetupIdContext) -> Bool? {
guard !c.isLoading.value else { return nil }
@@ -24,7 +26,49 @@ public extension MeetupId {
return nil
}
*/
static func shouldManyEnableJoin(_ c: MeetupIdContext) -> MPAK.Many<Bool>? {
var d = [String: Bool]()
// TODO: Когда копировать dict isLoading?
if c.textUI.isRecent {
for id in c.textUI.keys {
guard
c.isLoading.dict[id] == nil
let text = c.testTextUI.dict[id]
else {
continue
}
let sid = formatId(text)
d[id] = sid.count > 2
}
if !d.isEmpty {
return .init(Set(d.keys), d)
}
}
/*
if c.join,
!c.isLoading.value
{
return false
}
if
c.isLoading.isRecent,
!c.isLoading.value
!c.isLoading.value
{
return true
}
*/
return nil
}
/*
static func shouldFinishLoading(_ c: MeetupIdContext) -> Bool? {
guard
c.isLoading.isRecent,
@@ -34,6 +78,11 @@ public extension MeetupId {
}
return true
}
*/
/*
это ещё конвертнуть надо в Many
static func shouldResetLoading(_ c: MeetupIdContext) -> Bool? {
if
@@ -52,9 +101,48 @@ public extension MeetupId {
return nil
}
*/
/*
static func shouldResetText(_ c: MeetupIdContext) -> String? {
guard c.textUI.isRecent else { return nil }
return formatId(c.textUI.value)
}
*/
static func shouldManyFinishLoading(_ c: MeetupIdContext) -> MPAK.Many<Bool>? {
guard c.isLoading.isRecent else { return nil }
var keys = Set<String>()
for id in c.isLoading.keys {
if
let isLoading = c.isLoading.dict[id],
isLoading
{
keys.insert(id)
}
}
let d = [String: Bool]()
return MPAK.Many(keys, d)
}
static func shouldManyResetText(_ c: MeetupIdContext) -> MPAK.Many<String>? {
guard !c.textUI.keys.isEmpty else { return nil }
var d = [String: String]()
for id in c.textUI.keys {
let text = c.textUI.dict[id] ?? ""
d[id] = formatId(text)
}
return MPAK.Many(c.textUI.keys, d)
}
static func shouldManyTestResetText(_ c: MeetupIdContext) -> MPAK.Many<String>? {
guard !c.testTextUI.keys.isEmpty else { return nil }
var d = [String: String]()
for id in c.testTextUI.keys {
let text = c.testTextUI.dict[id] ?? ""
d[id] = formatId(text)
}
return MPAK.Many(c.testTextUI.keys, d)
}
}

View File

@@ -0,0 +1,27 @@
import BusX
import SwiftUI
extension MeetupId {
public struct TV: View {
let id: String
@StateObject var textField = BusUI.ManyTextField(K.testTextApp, K.testTextUI)
public init(_ id: String) {
self.id = id
}
public var body: some View {
TextField("TV", value: $textField.v, formatter: BusUI.TextFieldSource())
.padding(8)
.border(Color.blue)
.animation(.easeInOut(duration: 0.3))
.onAppear {
textField.id = id
}
.onChange(of: id) { newValue in
textField.id = newValue
}
}
}
}

View File

@@ -3,25 +3,20 @@ import SwiftUI
extension MeetupId {
public struct V: View {
@StateObject var isJoinAvailable = BusUI.Value(K.isJoinAvailable, false)
@StateObject var isLoading = BusUI.Value(K.isLoading, false)
@StateObject var join = BusUI.Button(K.join)
@StateObject var textField = BusUI.TextField(K.textApp, K.textUI)
let processors: [Any]
let id: String
@StateObject var isJoinAvailable = BusUI.ManyValue(K.isJoinAvailable, false)
@StateObject var isLoading = BusUI.ManyValue(K.isLoading, false)
@StateObject var join = BusUI.ManyButton(K.join)
@StateObject var textField = BusUI.ManyTextField(K.textApp, K.textUI)
public init() {
processors = [
Bus.Debounce(shouldResetText, 0.2, K.M, K.textApp),
Bus.Delay(shouldFinishLoading, 5, K.M, K.finishLoading),
Bus.Sync(shouldEnableJoin, K.M, K.isJoinAvailable),
Bus.Sync(shouldResetLoading, K.M, K.isLoading)
]
public init(_ id: String) {
self.id = id
}
public var body: some View {
VStack(spacing: 8) {
HStack {
TextField("Binding-3", value: $textField.v, formatter: BusUI.TextFieldSource())
ManyTextField("Binding-3", value: $textField.v, formatter: BusUI.TextFieldSource())
.disabled(isLoading.v)
.padding(8)
.border(
@@ -34,7 +29,7 @@ extension MeetupId {
}
}
Button(action: join.v.send) {
ManyButton(action: join.v.send) {
Text("Join")
.padding(8)
.border(
@@ -47,6 +42,18 @@ extension MeetupId {
.frame(width: 320)
.padding()
.animation(.easeInOut(duration: 0.3))
.onAppear {
isJoinAvailable.id = id
isLoading.id = id
join.id = id
textField.id = id
}
.onChange(of: id) { newValue in
isJoinAvailable.id = newValue
isLoading.id = newValue
join.id = newValue
textField.id = newValue
}
}
}
}

View File

@@ -1,10 +1,17 @@
from generation.isPipeMany import *
from generation.isPipeRecent import *
def fieldFormat(fmtPlain, fmtRecent, name, structure):
def fieldFormat(fmtMany, fmtPlain, fmtRecent, name, structure):
fmt = fmtPlain
if (
isPipeRecent(name, structure.core) or
isPipeRecent(name, structure.service)
):
fmt = fmtRecent
if (
isPipeMany(name, structure.core) or
isPipeMany(name, structure.service)
):
fmt = fmtMany
return fmt

View File

@@ -5,11 +5,12 @@ def generateContextFields(c):
lines = c.readFile(fileName)
fmtPlain = lines[0]
fmtRecent = lines[1]
fmtMany = lines[2]
fields = []
for key in c.structure.model.fields:
values = c.structure.model.fields[key]
fmt = fieldFormat(fmtPlain, fmtRecent, key, c.structure)
fmt = fieldFormat(fmtMany, fmtPlain, fmtRecent, key, c.structure)
ln = fmt \
.replace("%NAME%", key) \
.replace("%TYPE%", values[0])

View File

@@ -5,11 +5,12 @@ def generateModelFields(c):
lines = c.readFile(fileName)
fmtPlain = lines[0]
fmtRecent = lines[1]
fmtMany = lines[2]
fields = []
for key in c.structure.model.fields:
values = c.structure.model.fields[key]
fmt = fieldFormat(fmtPlain, fmtRecent, key, c.structure)
fmt = fieldFormat(fmtMany, fmtPlain, fmtRecent, key, c.structure)
ln = fmt \
.replace("%NAME%", key) \
.replace("%TYPE%", values[0]) \

View File

@@ -1,6 +1,7 @@
def isNotKeyword(str):
keywords = [
"ex",
"many",
"recent",
"set",
"toggle",

View File

@@ -0,0 +1,5 @@
def isPipeMany(name, entity):
if name in entity.pipes:
props = entity.pipes[name]
return "many" in props
return False

View File

@@ -1,5 +1,11 @@
from generation.isPipeMany import *
def pipeBusSource(name, entity, busKey, structure, fmt):
valueType = structure.model.fields[name][0]
print(f"pipeBS-1 name: '{name}'")
if isPipeMany(name, entity):
valueType = f"MPAK.Many<{valueType}>"
return fmt \
.replace("%BUS_KEY%", busKey) \
.replace("%BUS_VALUE_TYPE%", valueType)

View File

@@ -1,6 +1,8 @@
def pipeFormat(fmtExRecent, fmtRecent, fmtSet, fmtToggle, fmtToggleNil, name, entity):
def pipeFormat(fmtExRecent, fmtMany, fmtRecent, fmtSet, fmtToggle, fmtToggleNil, name, entity):
props = entity.pipes[name]
if "recent" and "ex" in props:
if "many" in props:
return fmtMany
elif "recent" and "ex" in props:
return fmtExRecent
elif "recent" in props:
return fmtRecent

View File

@@ -6,6 +6,7 @@ from generation.pipeSource import *
def sectionGeneratedPipes(entity, sub, c):
fmtBusPipe = c.readFile(f"{c.dir}/templates/section-generated-pipe-src-bus")[0]
fmtExRecent = c.readFile(f"{c.dir}/templates/section-generated-pipe-ex-recent")
fmtMany = c.readFile(f"{c.dir}/templates/section-generated-pipe-many")
fmtRecent = c.readFile(f"{c.dir}/templates/section-generated-pipe-recent")
fmtSet = c.readFile(f"{c.dir}/templates/section-generated-pipe-set")
fmtToggle = c.readFile(f"{c.dir}/templates/section-generated-pipe-toggle")
@@ -14,6 +15,7 @@ def sectionGeneratedPipes(entity, sub, c):
for key in entity.pipes:
values = entity.pipes[key]
print(f"sectionGP-1 key/values: '{key}'/'{values}'")
# EX_NAME.
firstLetter = key[:1].capitalize()
@@ -29,11 +31,13 @@ def sectionGeneratedPipes(entity, sub, c):
# SRC.
src = pipeSource(key, entity)
print(f"sectionGP-2 key/src: '{key}'/'{src}'")
# Bus.
if src.startswith("K."):
print(f"sectionGP-3 key: '{key}' bus")
src = pipeBusSource(key, entity, src, c.structure, fmtBusPipe)
fmtPipe = pipeFormat(fmtExRecent, fmtRecent, fmtSet, fmtToggle, fmtToggleNil, key, entity)
fmtPipe = pipeFormat(fmtExRecent, fmtMany, fmtRecent, fmtSet, fmtToggle, fmtToggleNil, key, entity)
for fmt in fmtPipe:
ln = fmt \
.replace("%EX_NAME%", exName) \

View File

@@ -1,2 +1,3 @@
var %NAME%: %TYPE% { get }
var %NAME%: MPAK.Recent<%TYPE%> { get }
var %NAME%: MPAK.Many<%TYPE%> { get }

View File

@@ -36,6 +36,7 @@ extension %MODULE% {
let ctrl = Controller()
let world: World
%SERVICE_CORE%
var any = [Any]()
var subscriptions = [AnyCancellable]()
static private(set) weak var singleton: Service?

View File

@@ -1,2 +1,3 @@
public var %NAME%: %TYPE% = %DEFAULT%
public var %NAME%: MPAK.Recent<%TYPE%> = .init(%DEFAULT%)
public var %NAME%: MPAK.Many<%TYPE%> = .init()

View File

@@ -0,0 +1,12 @@
ctrl.%PIPE%(
dbg: "%SHORT_SRC%",
sub: %SUB%,
%SRC%.eraseToAnyPublisher(),
{
$0.%NAME% = $1
},
{ m, _ in m.%NAME%.keys = [] }
)

View File

@@ -1,6 +1 @@
Bus.events.compactMap { Bus.convertKeyValue(%BUS_KEY%, $0) }.map { (k: String, v: %BUS_VALUE_TYPE%) in v }

View File

@@ -1,6 +1,7 @@
PODS:
- AELog (0.6.3)
- BusX (2023.12.30)
- BusX (2023.12.30):
- MPAKX
- MeetupIdX (2023.12.31):
- AELog
- BusX
@@ -27,7 +28,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
AELog: f732b70f7a9d1b4c6a3676304192b3908f362133
BusX: d11e857e9cb762f649ee9f88fd5a4f8fbf5bf96b
BusX: eff20bdef75eb529d679d6a710f9531135c263fb
MeetupIdX: 2fa9fb27717aa8878ff495c1abe960c96e524308
MPAKX: dc592434f55edf34709f6e4f37c9ec90dcd95185

View File

@@ -4,9 +4,15 @@ import UIKit
struct Content: View {
var body: some View {
MeetupId.V()
MeetupId.V("w1")
Divider()
MeetupId.V()
MeetupId.V("w2")
Divider()
Divider()
Divider()
MeetupId.TV("uuid-1")
Divider()
MeetupId.TV("uuid-2")
}
}