0

Despite the simplicity of the question I have not been able to find a satisfactory answer yet. I want to update toggle switches based on value in Firebase. I have added listeners but run into problems converting a Bool to Binding Bool, any help is appreciated.

struct oneSeqeuncer : Identifiable{
    var id: String
    var status: Bool
}


struct Sequencers: View {
@ObservedObject var seqModel = SequencerModel()
@State private var novaseq404A :Bool = true
@State private var novaseq404B :Bool = true
@State private var novaseq297A :Bool = true
@State private var novaseq297B :Bool = true
var body: some View {
    ZStack{
        VStack{
            Text("Sequencers")
                .foregroundColor(.white)
                .font(.title)
                .fontWeight(.bold)
                .padding()
            List{
                HStack{
                    Text("404")
                        .font(.title)
                        .padding()
                    Toggle("", isOn: $novaseq404A)
                        .onChange(of: novaseq404A) { newValue in
                            updateStatus(name: "404A", status: novaseq404A)
                        }
                    Toggle("", isOn: $novaseq404B)
                        .padding()
                        .onChange(of: novaseq404B) { newValue in
                            updateStatus(name: "404B", status: novaseq404B)
                        }
                }
                HStack{
                    Text("297")
                        .font(.title)
                        .padding()
                    Toggle("", isOn: $novaseq297A)
                        .onChange(of: novaseq297A) { newValue in
                            updateStatus(name: "297A", status: novaseq297A)
                        }
                    Toggle("", isOn: $novaseq297B)
                        .padding()
                        .onChange(of: novaseq297B) { newValue in
                            updateStatus(name: "297B", status: novaseq297B)
                        }
                }
            }
        }
    }.onAppear(){
        self.seqModel.fetchData()
        for seq in seqModel.seqs{
            if seq.id == "404A"{
                novaseq404A = seq.status
            }
            if seq.id == "404B"{
                novaseq404A = seq.status
            }
            if seq.id == "297A"{
                novaseq297A = seq.status
            }
            if seq.id == "297B"{
                novaseq297B = seq.status
            }
 }
    func updateStatus(name: String, status: Bool){
    let timeInterval = NSDate().timeIntervalSince1970
    let myInt = Int(timeInterval)
    let db = Firestore.firestore()
    if status == false{
        db.collection("Sequencers").document(name).updateData([
            "status": false,
            "lastChange" : myInt
        ]){ error in
            if error != nil{
                print(error!)
            }
        }
    }
    else{
        let docRef  = db.collection("Sequencers").document(name)
        
        docRef.getDocument {(document, error) in
            if error != nil {
                print(error!)
            }
            if let document = document, document.exists{
                let data = document.data()
                if let lastChange = data!["lastChange"]! as? Int{
                    let timeOff = myInt - lastChange
                    if let timeOffTotal = data!["timeOff"]! as? Int{
                        let newTimeOff = timeOffTotal + timeOff
                        db.collection("Sequencers").document(name).updateData([
                            "timeOff" : newTimeOff
                        ])
                    }
                }
                db.collection("Sequencers").document(name).updateData([
                    "previousChange": data!["lastChange"]!,
                    "status": true ,
                    "lastChange" : myInt
                    ])
            }
        }
    }
}
}

struct Sequencers_Previews: PreviewProvider {
    static var previews: some View {
        Sequencers()
    }
}

Below is my model for storing 'sequencers'

import Foundation
import FirebaseFirestore
import Firebase


class SequencerModel : ObservableObject {
    @Published var seqs = [oneSeqeuncer]()
    private var db = Firestore.firestore()

    func fetchData(){
        db.collection("Sequencers").addSnapshotListener { (querySnapshot, error) in
          guard let documents = querySnapshot?.documents else {
            print("No documents")
            return
          }

          self.seqs = documents.map { queryDocumentSnapshot -> oneSeqeuncer in
          
              let data = queryDocumentSnapshot.data()
              let id = queryDocumentSnapshot.documentID
              let status = data["status"] as? Bool
              print(id)
              print(status as Any)

              return oneSeqeuncer(id: id, status: status!)
          }
        }
    }
}
  • You may have a look at this [Stackoverflow case](https://stackoverflow.com/questions/59182246/loginpage-type-is-not-convertible-to-bindingbool-loginpage) which mentions about binding Bool. Let me know if that helps! – Mousumi Roy Feb 01 '22 at 10:31
  • right now you are setting the `@State vars` at `.onAppear`. You should do it at `init` like this: `self._stateVarName = State(initialValue: intitalValuefromModel )` – ChrisR Feb 01 '22 at 15:02
  • `init` seems like a more appropriate use, however I am still forced to give my `@State vars` values before `init`. My toggle switches all still default to on when the app launches. – AndrewWicks Feb 02 '22 at 01:15

1 Answers1

1

My solution was not ideal but solved, I realized the function .fetchData() that I was calling to was taking too long to respond. Ideally I should use some completion handler... However I simply changed my TabView on ContentView to display another page first, to allow time for my call to Firebase to finish, which allowed my for loop in .onAppear to have a non empty iterable. Again not sure this really belongs as an "Answer" but just wanted to share my temp solution as an option.