Issues with implementing the logical code for my timesheetKeyin

Hi DevForum team, I'm struggling with the logic to create behind my nice code:

as you can see in my ButtonHour (last page) I have

if isSet == true {
                    print("true is \(isSet)")
                
                  
                } else {
                    print("false is\(isSet)")
                  
                }

the things is that I cannot place anything in between this lines beside Print( ) which is useless for me, Target was for me to be able to Bind & @state this with the following logic & the swift file I want to link it with

@Observable
class TimesheetCalculation {
    let maxHourPerDay: Double = 8
    var hourchoosen: Double = 0
    var totalhourbooked: Double = 0
    var remainingHour: Double = 8
    var cvsrecordedtrackingcodek: String = "id,value,shortprojectName,day"
    func checkRemainingHours() -> Double {
      
        return remainingHour
    }
`````    // Logic to create, every single button has an ID and a value
    //first is to collect all the clicked button and make sure he cannot clic more than 8 hours
    //but first it to link the variable in TimesheetCalculation class, which is not working so far
    //once I manage to connect this the following logic will apply
    //maxHourPerDay = 8h
    //hourchoosen = value of clic button
    //totalhourbooked = value + value + value - value (if click false)
    //remainingHour = maxHourPerDay - totalhourbooked
    //cvsrecordedtrackingcodek will be to keep track of previous day, converted in cvs for future excel export
    //checkRemainingHours function to automaticly calcuation each time the button has been clic , normlay once the logic will be set I will just put this checkRemainingHours into the action button .
    // the is also anothe logic that I need to put in place.
    //if remainingHour - new Value being click is less than 0 then the button will not be able to toggle, meaning that he will not be able to key-more than 8h `````
    
}

struct TimeKeyinList: View {
    @Environment(ModelData.self) var modelData
    let projects = ModelData().projects 
    @State var isSet: [Bool] = [false, false, false, false, false,false,false,false] 
    var filteredNonTECOProjects: [Project] {
        // removeTECO project
        modelData.projects.filter { project in
            !project.isTeco
        }}
    var body: some View {
        VStack {
            HStack {
                Text("TIME KEY_IN")
                Spacer()
                Text("8h")
            }
            Spacer() 
           VStack(spacing: 5){
                HStack(alignment: .top) {
                    Text(" Project Name")
                        .multilineTextAlignment(.leading)
                        .lineLimit(2)
                        .frame(width: 120.0) // <<-- To get proper alignment
                    
                        Text(".5h")
                        Text("1h")
                        Text("2h")
                        Text("3h")
                        Text("4h")
                        Text("8h")
                    Text("Time Left")
                }
                VStack(spacing: 20) {
                    BlankKeyInRow()
                    ForEach(Array(filteredNonTECOProjects.enumerated()), id: \.offset) { (row, project) in
                       
                        if project .isSpecific {
                            BlankKeyInRow()
                            BlankKeyInRow()
                            TimeKeyInRow(id: project.shortname, project: project, isSet: $isSet[row])
                        } else {
                            TimeKeyInRow(id: project.shortname, project: project, isSet: $isSet[row])
                        }
                    }
                } .listStyle(.inset)
                
                            DatePicker(selection: /*@START_MENU_TOKEN@*/.constant(Date())/*@END_MENU_TOKEN@*/, label: { /*@START_MENU_TOKEN@*/Text("Date")/*@END_MENU_TOKEN@*/ })
            }.environment(\.sizeCategory, .extraExtraExtraLarge)
                .labelsHidden()
            Spacer()
                .onAppear() {
                    // <<-- Added
                    for (row, project) in filteredNonTECOProjects.enumerated() {
                            isSet[row] = !project.isTeco
                        }
                    }
            Spacer()
        }
    }
}

struct TimeKeyinList_Previews2: PreviewProvider {
    static var previews: some View {
        TimeKeyinList().environment(ModelData())
    }
}

second file

struct TimeKeyInRow: View,Identifiable {
    var id: String
    var project: Project
    @Binding var isSet: Bool
    let listOfPossibleHours: [Double] = [0.5,1,2,3,4,8]
    var body: some View {
        HStack {
            Text(project.shortname.paddedToWidth(10)) // Text(projects[1].shortname)
                .font(.custom("Menlo", size: 16))
                .frame(width: 120.0) // <<-- To get proper alignment
            Spacer()
            ForEach(listOfPossibleHours, id: \.self) { hour in
                HourButton(id: "\(project.shortname)", isSet: isSet, value: hour)
            }
            Text("\(project.leftPMtime)")
        }
    }
}


struct TimeKeyInRow_Previews: PreviewProvider {
    static var previews: some View {
        let projects = ModelData().projects
        TimeKeyInRow(id: "test", project: projects[2], isSet: .constant(true))
    }
}
extension String {  // To align text
    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
    }
}

struct BlankKeyInRow: View {
    var body: some View {
        HStack {
            Text("") // Text(projects[1].shortname)
        }
    }
}

and the starting button point

import SwiftUI

struct HourButton: View,Identifiable {
    var id: String = "hour"
    @State var isSet: Bool
  var value: Double

    var body: some View {
        
        HStack {

            Button {
                isSet.toggle()
                print("clic on Project : \(id) an turn to : \(isSet) for  \(value)h")
                if isSet == true {
                    print("true is \(isSet)")
                } else {
                    print("false is\(isSet)")
                }  } label: {
                Label("8h", systemImage: isSet ? "circle.fill" : "circle")
                    .labelStyle(.iconOnly)
                    .foregroundStyle(isSet ? .blue : .gray)
            }.id(id)     
        }
        }
}

struct HourButton_Previews: PreviewProvider {
    static var previews: some View {
        //#Preview {
        HourButton(id: "MORN", isSet: true, value: 3)
    }
}

to be able to Bind & @state this with the following logic & the swift file I want to link it with

This is not clear. Please explain what you want to have instead of the print here ?

                if isSet { //  == true {
                    print("true is \(isSet)")
                } else {
                    print("false is\(isSet)")
                }

If I understand your code, Binding works the other way. I could not test, so there may be other changes needed elsewhere.

Change as follows:

struct TimeKeyInRow: View,Identifiable {
    var id: String
    var project: Project
    @State var isSet: Bool  // This is the State, not the Binding

    let listOfPossibleHours: [Double] = [0.5,1,2,3,4,8]

    var body: some View {
        HStack {
            Text(project.shortname.paddedToWidth(10)) // Text(projects[1].shortname)
                .font(.custom("Menlo", size: 16))
                .frame(width: 120.0) 
            Spacer()
            ForEach(listOfPossibleHours, id: \.self) { hour in
                HourButton(id: "\(project.shortname)", isSet: $isSet, value: hour)  // $isSet as it is to a Binding
            }
            Text("\(project.leftPMtime)")
        }
    }
}

and

struct HourButton: View,Identifiable {
    var id: String = "hour"
    @Binding var isSet: Bool  // Here is the Binding, not State

Note: when you post a screenshot, reduce its size, no need to have such a large image.

Hi @Claude31 , seems like I will call you Master soon ^^, lol ok for the photo I'm not sure how I will reduce them but I will find the way , as for what I want in term of binding and state is to link the Value feedback to another swift file here :


@Observable
class TimesheetCalculation {
    let maxHourPerDay: Double = 8
    var hourchoosen: Double = 0
    var totalhourbooked: Double = 0
    var remainingHour: Double = 8
    var cvsrecordedtrackingcodek: String = "id,value,shortprojectName,day"
    func checkRemainingHours() -> Double {
      
        return remainingHour
    }

And here is the whole logic I want to build once I manage to insert my own code below and after this print

 // Logic to create, every single button has an ID and a value
    //first is to collect all the clicked button and make sure he cannot clic more than 8 hours
    //but first it to link the variable in TimesheetCalculation class, which is not working so far
    //once I manage to connect this the following logic will apply
    //maxHourPerDay = 8h
    //hourchoosen = value of clic button
    //totalhourbooked = value + value + value - value (if click false)
    //remainingHour = maxHourPerDay - totalhourbooked
    //cvsrecordedtrackingcodek will be to keep track of previous day, converted in cvs for future excel export
    //checkRemainingHours function to automaticly calcuation each time the button has been clic , normlay once the logic will be set I will just put this checkRemainingHours into the action button .
    // the is also anothe logic that I need to put in place.
 if remainingHour - new Value being click is less than 0 then the button will not be able to toggle, meaning that he will not be able to key-more than 8h `````
 
Issues with implementing the logical code for my timesheetKeyin
 
 
Q