@@ -0,0 +1,16 @@ | |||||
import Combine | |||||
extension Cord { | |||||
final class Button: ObservableObject { | |||||
let press = PassthroughSubject<Void, Never>() | |||||
var subscriptions = [AnyCancellable]() | |||||
init(_ key: String) { | |||||
Bus.send( | |||||
key, | |||||
press.eraseToAnyPublisher(), | |||||
sub: &subscriptions | |||||
) | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,20 @@ | |||||
import Combine | |||||
extension Cord { | |||||
final class ReadOnly<T>: ObservableObject { | |||||
@Published var value: T | |||||
var subscriptions = [AnyCancellable]() | |||||
init( | |||||
_ key: String, | |||||
_ defaultValue: T | |||||
) { | |||||
value = defaultValue | |||||
Bus.receive( | |||||
[key], | |||||
{ [weak self] (_, v: T) in self?.value = v }, | |||||
sub: &subscriptions | |||||
) | |||||
} | |||||
} | |||||
} |
@@ -12,7 +12,7 @@ extension Cord { | |||||
) { | ) { | ||||
Bus.send( | Bus.send( | ||||
textUI, | textUI, | ||||
$value.compactMap(onlyUIText).eraseToAnyPublisher(), | |||||
$value.removeDuplicates().compactMap(onlyUIText).eraseToAnyPublisher(), | |||||
sub: &subscriptions | sub: &subscriptions | ||||
) | ) | ||||
@@ -7,6 +7,10 @@ enum MeetupId { | |||||
case meetupIdTextUI | case meetupIdTextUI | ||||
} | } | ||||
static func onlyAllowJoin(_ s: String) -> Bool? { | |||||
s.hasPrefix("123") | |||||
} | |||||
static func onlyFormat(_ s: String) -> String? { | static func onlyFormat(_ s: String) -> String? { | ||||
let digits = s.components(separatedBy: NSCharacterSet.decimalDigits.inverted).reduce("") { $0 + $1 } | let digits = s.components(separatedBy: NSCharacterSet.decimalDigits.inverted).reduce("") { $0 + $1 } | ||||
var r = "" | var r = "" | ||||
@@ -1,27 +1,32 @@ | |||||
import SwiftUI | import SwiftUI | ||||
struct V: View { | struct V: View { | ||||
@StateObject var tf = Cord.TextField("text.app", "text.ui") | |||||
@StateObject var vm = VM() | |||||
@StateObject var isJoinAvailable = Cord.ReadOnly("joinAvailable", false) | |||||
@StateObject var join = Cord.Button("join") | |||||
@StateObject var textF = Cord.TextField("text.app", "text.ui") | |||||
let test = Bus.Processor("text.ui", "joinAvailable", MeetupId.onlyAllowJoin) | |||||
var body: some View { | var body: some View { | ||||
VStack { | VStack { | ||||
HStack { | HStack { | ||||
Text("Check text field:") | Text("Check text field:") | ||||
Text("'\(tf.value)'") | |||||
Text("'\(textF.value)'") | |||||
.fontWeight(.bold) | .fontWeight(.bold) | ||||
} | } | ||||
TextField("Binding-3", value: $tf.value, formatter: TextFieldValueOwner()) | |||||
TextField("Binding-3", value: $textF.value, formatter: TextFieldValueOwner()) | |||||
.padding(8) | .padding(8) | ||||
.border(Color.blue, width: 2) | .border(Color.blue, width: 2) | ||||
Button(action: vm.join.send) { | |||||
Button(action: join.press.send) { | |||||
Text("Join") | Text("Join") | ||||
.padding(8) | .padding(8) | ||||
.border(vm.isJoinAvailable ? Color.green : Color.red, width: 4) | |||||
.border( | |||||
isJoinAvailable.value ? Color.green : Color.gray, | |||||
width: isJoinAvailable.value ? 4 : 1 | |||||
) | |||||
} | } | ||||
.disabled(!isJoinAvailable.value) | |||||
} | } | ||||
.frame(width: 320) | .frame(width: 320) | ||||
.padding() | .padding() | ||||
@@ -10,8 +10,7 @@ final class VM: ObservableObject { | |||||
MeetupId.onlyFormat | MeetupId.onlyFormat | ||||
) | ) | ||||
*/ | */ | ||||
var isJoinAvailable = true | |||||
let join = PassthroughSubject<Void, Never>() | |||||
var isJoinAvailable = false | |||||
var subscriptions = [AnyCancellable]() | var subscriptions = [AnyCancellable]() | ||||
init() { | init() { | ||||