You will have to restructure a lot.
I let you try this.
If that's what you want, try to understand code and ask for anything unclear. Please do it in a new thread, to avoid ever lasting thread.
Note: that's quick and dirty code, just to have a starting point.
There are clarification questions as comments in code. Please answer.
extension String {
func paddedToWidth(_ width: Int) -> String {
let length = self.count
guard length < width else {
return self
}
let spaces = Array<Character>.init(repeating: " ", count: width - length)
return self + spaces
}
}
let allHoursFalse = [false, false, false, false, false, false] // To simplify code writing, we hard code: there are 6 hours defined
struct TimeKeyinList: View { // }, Identifiable {
@State var projects = [Project] () // Now need a State var to be able to modify
// Not the correct var to keep hours for each project. @State var isSet: [Bool] = [true, false, false, true]
@State private var hideTeco = false // What's the purpose of this ? Not used in code
@State var filteredProjects: [Project] = [] /* { Init will be done in onAppear
// removeTECO project
projects.filter { project in
!project.isTeco
}
}*/
var body: some View {
VStack(spacing: 10) {
ForEach($filteredProjects, id: \.id) { $project in
TimeKeyInRow(id: project.shortname, projects: $projects, projectNum: project.projectRow)
}
}
.labelsHidden()
.onAppear() { // <<-- Added. All isHourSet initialised as false
projects = [
Project(id: 1, projectRow: 0, name: "Project1, isTeco = false, shortname = MORN, leftPMTime = 131",shortname : "MORN", leftPMtime : 131, isTeco: false, isHourSet: allHoursFalse),
Project(id: 2, projectRow: 1, name: "Project2, isTeco = false, shortname = MORN, leftPMTime = 122",shortname : "IFF", leftPMtime : 122, isTeco: true, isHourSet: allHoursFalse),
Project(id: 3, projectRow: 2, name: "Project3, isTeco = false, shortname = MORN, leftPMTime = 133",shortname : "FFI", leftPMtime : 133, isTeco: true, isHourSet: allHoursFalse),
Project(id: 4, projectRow: 3, name: "Project4, isTeco = false, shortname = MORN, leftPMTime = 444",shortname : "IFFCO", leftPMtime : 444, isTeco: false, isHourSet: allHoursFalse)
]
filteredProjects = projects.filter { project in
!project.isTeco // What does isTeco mean ????
}
// for (row, project) in filteredProjects.enumerated() { // Replaced by array of Bool for hours in each project
// isSet[row] = !project.isTeco // I do not understand what was isSet used for here.
// }
}
}
}
struct Project: Identifiable {
var id: Int = 0// UUID = UUID()
var projectRow: Int // inside projects
var name: String
var shortname: String
var leftPMtime: Int
var isTeco: Bool
var isHourSet: [Bool] // ### To store for each hour of the project
// private enum CodingKeys : String, CodingKey {
// case name, shortname, leftPMtime, isTeco
// }
}
struct TimeKeyInRow: View,Identifiable {
var id: String
@Binding var projects: [Project] // we pass all projects as well as the projectNum to handle. That eases the update of the project properties
var projectNum: Int // The project displayed in the row
// @Binding var isSet: Bool ### No need, it is now a property in project
let listOfPossibleHours: [Double] = [0.5, 1, 2, 3, 4, 8]
var body: some View {
HStack {
Spacer()
Text(projects[projectNum].shortname.paddedToWidth(5)) // Text(projects[1].shortname)
.font(.custom("Menlo", size: 16)) // <<-- To get proper alignment
Spacer()
ForEach(Array(listOfPossibleHours.enumerated()), id: \.offset) { (index, hour) in
HourButton(id: "\(projects[projectNum].shortname)", isSet: $projects[projectNum].isHourSet[index], value: hour) // HourButton has changed, to pass value of isSet for each hour
}
Text("\(projects[projectNum].leftPMtime)")
.font(.custom("Menlo", size: 16)) // <<-- To get proper alignment
Spacer()
// Let's add a button on each row to reset all hours to false for the project. We do it directly in projects array
Button {
projects[projectNum].isHourSet = allHoursFalse
} label: {
Text("all off")
}
Spacer() // ADDED
}
}
}
struct HourButton: View,Identifiable {
var id: String = "hour"
@Binding var isSet: Bool // A Binding, as we change the value and want it updated in TimeKeyInRow
var value: Double = 1
var body: some View {
HStack {
Button {
isSet.toggle()
print("clic already \(isSet) \(id)h & \(value) has Value")
} label: {
Label("8h", systemImage: isSet ? "circle.fill" : "circle")
.labelStyle(.iconOnly)
.foregroundStyle(isSet ? .blue : .gray)
}.id(id)
}
}
}