How to change value of a boolean get only property by toggling of a binding bool parameter in SwiftUI

96 Views Asked by At

I am new in SwiftUI and struggling with some property conversion issues. I developed an app, keeping book details in Firebase such as title, publisher and whether book is finished or not. I used a star image in the BookDetails page to toggle whether the book is finished or not. The related book's data passes from the main screen list view when any book row is selected. I can see the selected book's (book.finished) data but I can't change it because it complains that it is a get property. When the book is finished a small system image star color to be changed and I use binding Bool parameter to pass the data. I can't set book.finished when it is toggled. Could you please help me how to fix it? I get "Cannot assign to property: 'finished' is a get-only property" error code. My code for the Bookdetails page:

import SwiftUI

struct BookDetail: View {
    @ObservedObject var libraryListVM = LibraryListViewModel()

    @State var book : LibraryViewModel
    @ScaledMetric var width: CGFloat = 200
    @ScaledMetric var height: CGFloat = 40
  
   
    var body: some View {

        NavigationStack {
            VStack{
                Section {
                    HStack{
                        Text("Author:").bold()
                            .padding(.leading)
                        Text(book.author)
                    }
                    
                    HStack{
                        Text("Publishing Year:").bold()
                        
                        Text(book.published.description)
                    }
                }.padding()
                
        
                VStack {

                    FinishButton(finishedStar: $book.finished)

                        .onTapGesture {

                         book.finished = !book.finished
                            
                            libraryListVM.setData(libraryId: book.bookId, finished: book.finished, completion: { error in
                                if let error = error {
                                    print(error.localizedDescription)
                                } else {
                                   
                                    libraryListVM.getAllBooksForUser()
                                }
                            })
                        }
                }
                
                Button("Delete") {
                 
                    libraryListVM.deleteBook(libraryId: book.bookId, completion: {error in
                        if let error = error {
                            print(error.localizedDescription)
                        } else {
                           
                            
                            libraryListVM.getAllBooksForUser()
                        }
                    })
                    
                }.buttonStyle(PrimaryButtonStyle())
                    .font(.system(size: 20))
                    .padding(.top,80)
                    .padding(20)
            }
        }
    }
}

struct BookDetail_Previews: PreviewProvider {
    static var previews: some View {
        
        BookDetail(book: LibraryViewModel(book: BookData(id: "123", Finished: true,  Author: "Yasar Kemal", Publishing_at: "1980")) )
    }
}

    struct FinishButton: View {
    @Binding var finishedStar:Bool
    var body: some View {
        Image(systemName: finishedStar ? "star.fill" : "star"  )
            .foregroundColor(finishedStar ? .purple : .gray)
    }
}

When the user taps the star icon on the view, its status toggles between "purple filled star" or "gray star". I am going to set current status of (book.finished) parameter in the Firebase if this code block works.

My LibraryViewModel is here:

import Foundation

struct LibraryViewModel:Decodable {
    
    let book: BookData
    
    var bookId: String {
        book.id ?? ""
    }
    
    var finished: Bool {
        book.Finished
    }
    
    var title: String {
        book.Title
    }
    
    var author: String {
        book.Author
    }
    
    var published: String {
        book.Publishing_at
    }
}

Related portion of MyLibraryListViewModel is here:

import Foundation
import Firebase
import FirebaseFirestoreSwift
import SwiftUI

enum LoadingState {
    case idle
    case loading
    case success
    case failure
}

class LibraryListViewModel: ObservableObject {

    let db = Firestore.firestore()
    
    @Published var library: [LibraryViewModel] = []
    @Published var loadingState: LoadingState = .idle


    func setData(libraryId: String,finished: Bool, completion: (Error?) -> Void) {
       
        do {
            let _ =  try db.collection("Libraries").document(libraryId).setData(["Finished" : finished] )
            completion(nil)
        } catch let error {
            completion(error)
        }

    }
0

There are 0 best solutions below