1

I have a struct and I displayed the product list screen from that struct.There is a heart button in product list view, I want to add the particular item to favourite view on button press and also button color needs to change.and also can remove the item from favourites while unfavourite it from product list screen. I have a user defaults, and I can see displayed, added and removed products in my console.but I have a problem with displaying it to favourite screen.can anyone please help me?

struct ProductModel : Codable {
    let productData : [ProductData]
    
    private enum CodingKeys:String,CodingKey {
        case productData = "data"
    }
}
struct ProductData : Identifiable,Codable,Hashable {
    var id : Int
    var title :String
    var type : String
    var description : String
    var filename : String
    var price : Float
    var rating : Int
    
    init() {
        self.id = 0
        self.title = ""
        self.type = ""
        self.description = ""
        self.filename = ""
        self.price = 0.0
        self.rating = 0
    }
   
}

this is my view model

import Foundation
class FavouriteViewModel : ObservableObject {
    @Published var isfavourite = false
    @Published var productData : [ProductData] = []
    // the products which user marked as favourites
    @Published var favourites = [ProductData]()
    let defaults = UserDefaults.standard
    var favItems : [ProductData] = []
    init() {
        guard let data = defaults.data(forKey: "Favourites") else {  return }
        self.favItems = (try? PropertyListDecoder().decode([ProductData].self, from: data)) ?? []
    }
    func getIds() -> [ProductData] {
        return self.favourites
    }
    func contains(productItem:ProductData) -> Bool {
        favourites.contains(productItem)
        
    }
    func addToFav(productItem:ProductData) {
        print("the add to fav called\(productItem)")
        favourites.insert(productItem, at: 0)
        favourites.append(productItem)
        save()
    }
    func removeFromFav(productItem:ProductData) {
        print("the remove from fav called\(productItem)")
        if let index = favourites.lastIndex(of: productItem) {
            favourites.remove(at: index)
        }
        save()
    }
    func save() {
        defaults.set(try? PropertyListEncoder().encode(favourites), forKey: "Favourites")
        getDataFromUserDefaults()
    }
    
    func getDataFromUserDefaults()  {
        guard let data = defaults.data(forKey: "Favourites") else {  return }
        self.favItems = (try? PropertyListDecoder().decode([ProductData].self, from: data)) ?? []
        print("the favourite data are \(favItems)")
        
    }
}

I have done these code in button pf product list screen

   import SwiftUI
import Kingfisher

struct ProductListView: View {
    
    @StateObject var favouriteViewModel : FavouriteViewModel = FavouriteViewModel()
    @State var item : String
    @State var filteredData : [ProductData]
    var body: some View {
        let columns = [GridItem(.flexible(minimum: 100,maximum: 150),spacing: 10),
                       GridItem(.adaptive(minimum: 100, maximum: 150),spacing: 10),
                       GridItem(.adaptive(minimum: 100, maximum: 150))]
        NavigationStack {
            ScrollView {
                LazyVGrid(columns: columns,spacing: 35) {
                    ForEach(filteredData,id: \.id) {
                        product in
                        NavigationLink(destination: DetailsCardView(productData: product),label: {
                            VStack(alignment: .center,spacing: 4){
                                KFImage(URL(string: product.filename))
                                    .resizable()
                                    .frame(width: 50,height: 50,alignment: .center)
                                    .scaledToFill()
                                Text(product.title)
                                    .font(.system(size: 10,weight: .semibold))
                                    .foregroundColor(.black)
                                HStack(spacing: 40) {
                                    Text("\(product.price,specifier: "%.2f")/1Kg")
                                        .font(.system(size: 9,weight: .regular))
                                        .foregroundColor(.black)
                                    Button(action: {
                                        if self.favouriteViewModel.contains(productItem: product) {
                                            self.favouriteViewModel.removeFromFav(productItem: product)
                                        } else {
                                            self.favouriteViewModel.addToFav(productItem: product)
                                        }
                                    }) {
                                        Image(favouriteViewModel.contains(productItem: product) ? "heartfill" : "heart")
                                            .frame(alignment: .bottomTrailing)
                                    }
                                }
                                
                            }
                            
                        }
                                       
                        ) }
                    
                    .overlay(
                        RoundedRectangle(cornerRadius: 20,style: .circular)
                            .stroke(Color.gray,lineWidth: 0.3)
                            .shadow(radius: 1)
                            .frame(width: 115,height: 120)
                    )
                }
                .padding(15)
            }
            .navigationBarTitle(Text(item),displayMode: .inline)
        }
    }
}

this is my favourite view

import SwiftUI
import Kingfisher
struct FavouriteView:View {
   
    @ObservedObject var favouriteViewModel : FavouriteViewModel = FavouriteViewModel()
    var body: some View {
        NavigationStack {
                List {
                    ForEach(favouriteViewModel.favItems) { item in
                    ZStack {
                        RoundedRectangle(cornerRadius: 20,style: .circular)
                            .fill(.white)
                            .shadow(radius: 1)
                            .frame(width: 360,height: 120)
                        
                        HStack(spacing:10){
                            KFImage(URL(string: item.filename))
                                .resizable()
                                .frame(width: 50,height: 50)
                                .scaledToFit()
                                .padding(.leading,20)
                            
                            VStack(alignment: .leading,spacing: 10) {
                                Text(item.title)
                                Text("\(item.price,specifier: "%.2f")/1Kg")
                                    .foregroundColor(Color.gray)
                            }
                            Spacer()
                           Image(favouriteViewModel.contains(productItem: item) ? "heart" : "heartfill")
                                    .padding(.trailing,10)
                            
                            }
                        }
                    }
                    .onAppear {
                        favouriteViewModel.getDataFromUserDefaults()
                        //favouriteViewModel.addToFav(productItem: ProductData())
                        //favouriteViewModel.removeFromFav(productItem: ProductData())
                    }
                   
                }
                .frame(maxWidth: .infinity)
                .edgesIgnoringSafeArea(.horizontal)
                .listStyle(GroupedListStyle())
                    
                }
              
            .navigationBarTitle(Text("Favourites"),displayMode: .inline)
        }
    }
  • seems to be the same question you've asked before, here: https://stackoverflow.com/questions/76480233/how-can-add-data-from-user-defaults-to-next-view-in-swiftui-on-button-press and here: https://stackoverflow.com/questions/76470415/how-to-add-item-to-favourites-screen-in-swiftui that you never acknowledge. – workingdog support Ukraine Jun 16 '23 at 07:17
  • But I have added user defaults this time and also make some changes ,that's why Iam posting as a new question – Vinduja Narayanan K Jun 16 '23 at 07:27
  • I have tried many times with above code. but I didn't get the results, can anyone please help me? – Vinduja Narayanan K Jun 16 '23 at 07:38
  • 1
    Show a minimal reproducible code that produces your issue, see: [minimal code](https://stackoverflow.com/help/minimal-reproducible-example). Currently there are many elements missing. For example: in the view you call `favourite view`, you declare `@StateObject var favouriteViewModel : FavouriteViewModel = FavouriteViewModel()`. And in the other view with `LazyVGrid(....)` you also have a `favouriteViewModel`, but you don't show how you declare it, or pass the model to the view. Also in `favourite view`, you should not have `NavigationView { NavigationStack { ...`, one is enough. – workingdog support Ukraine Jun 16 '23 at 07:54
  • In `FavouriteView` you should have `@ObservedObject var favouriteViewModel : FavouriteViewModel` only. – workingdog support Ukraine Jun 16 '23 at 08:27
  • Here the favourite view model is called once, how can I update the favourite view model? – Vinduja Narayanan K Jun 16 '23 at 09:34
  • Did you change your code with `@ObservedObject var favouriteViewModel : FavouriteViewModel`? You **must** pass `favouriteViewModel` from `ProductListView` to other views, using either `.environmentObject(favouriteViewModel)` or directly using `FavouriteView(favouriteViewModel: favouriteViewModel)`. Show the code where do you call `FavouriteView(...)`. You must have only **one** `@StateObject var favouriteViewModel = FavouriteViewModel()` – workingdog support Ukraine Jun 16 '23 at 11:28
  • Here I can list the favorites on favorite screen only for first time. when we go back any other screen and come to product list screen for favourite any other,it can't. I think the view can't update.init() is called only once.what did I do for view updation? – Vinduja Narayanan K Jun 17 '23 at 05:35

0 Answers0