It's not clear to me how you would combine the output of the following computed property, to the UI.
var isComplete: Bool {
Set([.givenName, .familyName]).isSubset(of: elements)
}
I essentially want the user interface to update if the above changes. How would I do this using Combine?
Reactive programming demands that I now think backwards and I'm having trouble thinking about model <<< UI rather than model >>> UI.
Here is the code in context.
struct EditPersonView: View {
let model: ViewModel
private var captionView: some View {
HStack {
/*
stuff
*/
if submitted && model.name.isComplete {
Spacer()
Text("select".localizedCapitalized) + Text(" ") + Text("save") + Text(" ") + Text("")
}
}
}
var body: some View {
/*
stuff - including captionView
*/
}
}
extension EditPersonView {
final class ViewModel {
let name: PersonName
init(person: Person) {
self.name = PersonName(for: person)
}
}
}
extension EditPersonView.ViewModel {
final class PersonName {
let person: Person
private let formatter = PersonNameComponentsFormatter()
init(for person: Person) {
self.person = person
}
var text: String {
get { person.name ?? "" }
set { person.name = newValue }
}
private var components: PersonNameComponents? {
formatter.personNameComponents(from: text)
}
var givenName: String? {
components?.givenName
}
var familyName: String? {
components?.familyName
}
private func isValid(component: String?) -> Bool {
if let name = component, name.count > 1 {
return true
}
return false
}
var elements: Set<Elements> {
var collection = Set<Elements>()
if isValid(component: givenName) { collection.insert(.givenName) }
if isValid(component: familyName) { collection.insert(.familyName) }
return collection
}
var isComplete: Bool {
Set([.givenName, .familyName]).isSubset(of: elements)
}
}
}
extension EditPersonView.ViewModel.PersonName {
enum Elements {
case givenName, familyName
}
}