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 ChangeGroup
s which themselves have many ProposedChange
s.
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
enabled
isfalse
for allProposedChange
s in thisReport
- Green if
enabled
istrue
for allProposedChange
s in thisReport
- Yellow if
enabled
is mixed for differentProposedChange
s 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?