I have a SummaryView with a Report as @State.
A Report is a protocol which includes some changes a user might want to make:
protocol Report {
var changeGroups: [ChangeGroup] { get set }
}
There are several kinds of reports; individual reports are implemented as a struct:
struct RealEstateReport: Report {
static let name = "Real Estate Report"
var changeGroups = [ChangeGroup]()
}
A ChangeGroup is a struct with (among other stuff) a human-readable summary and a handful of proposed changes:
struct ChangeGroup: Identifiable {
var summary: String
var proposedChanges = [ProposedChange]()
}
A ProposedChange is a class that represents one discrete change the app proposes to the user, which is enabled by default:
class ProposedChange: ObservableObject, Identifiable {
@Published var enabled = true
let summary: String
(In a detail view, enabled is bound to a Toggle so a user can flip each proposed change on and off.)
So a Report has many ChangeGroups which themselves have many ProposedChanges.
I'm trying to include some high level details on the SummaryView:
struct SummaryView: View {
@State var report: Report
var body: some View {
Text("Summary")
.foregroundColor(…) // ???
}
I want foregroundColor to be red, yellow, or green:
- Red if
enabledisfalsefor allProposedChanges in thisReport - Green if
enabledistruefor allProposedChanges in thisReport - Yellow if
enabledis mixed for differentProposedChanges in thisReport
I've read a bit about Combine, and I think I need to create a new Combine subscription for each ChangeGroup, and map that to a new Combine subscription for each ProposedChange's enabled property, flatten the values when one changes, and check if they're all the same.
I'm a little lost on the exact syntax I'd use. And also it seems like structs don't publish changes in the same way (I guess since the structs are value vs. reference types).
How can I set the foregroundColor of the Text view based on the above logic?