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)
}
}