Search code examples
swiftswiftuiidentifiable

How to change value from an identifiable object in one view from another view swiftui


I am making an achievement system in my app, i want people to be awarded for using my app. Im trying to change the isComplete value from content view, for the identifiable object in achievement view. My achievement view is being called to run in a sheet from content view.


struct ContentView: View {
    var body: some View {
        // change value from here
    }
}

struct Achievement: Identifiable {
    let id = UUID()
    let title: String
    let description: String
    let isComplete: Bool
}

struct AchievementView: View {
    @State var Achievements = [
        Achievement(title: "Done and Done I", description: "delete 1 task", isComplete: false),
        Achievement(title: "Done and Done II", description: "delete 10 tasks", isComplete: false),
        Achievement(title: "Done and Done III", description: "delete 50 tasks", isComplete: false),
        Achievement(title: "Done and Done IV", description: "delete 100 tasks", isComplete: false),
        Achievement(title: "Done and Done V", description: "delete 1000 tasks", isComplete: false),
        Achievement(title: "Busy bee I", description: "add 1 task", isComplete: false),
        Achievement(title: "Busy bee II", description: "add 10 tasks", isComplete: false),
        Achievement(title: "Busy bee III", description: "add 50 tasks", isComplete: false),
        Achievement(title: "Busy bee IV", description: "add 100 tasks", isComplete: false),
        Achievement(title: "Busy bee V", description: "add 1000 tasks", isComplete: false),
        Achievement(title: "Thank you", description: "rate our app", isComplete: false),
        Achievement(title: "Sharing is caring", description: "share your list", isComplete: false),
        Achievement(title: "No place like home", description: "customize taskfairy", isComplete: false)
    ]
    var body: some View {
        List {
            Section(header: Text("completed")) {
                ForEach(Achievements) { i in
                    if i.isComplete {
                        HStack {
                            Image(systemName: "trophy.circle")
                                .scaleEffect(1.5)
                                .padding()
                            VStack {
                                Text("\(i.title)")
                                Text("\(i.description)")
                                    .font(.custom("SanFrancisco", size: 12))
                                    .foregroundColor(.gray)
                            }
                        }
                    }
                }
            }
            Section(header: Text("incomplete")) {
                ForEach(Achievements) { i in
                    if !i.isComplete {
                        HStack {
                            Image(systemName: "trophy.circle")
                                .scaleEffect(1.5)
                                .padding()
                            VStack {
                                Text("\(i.title)")
                                Text("\(i.description)")
                                    .font(.custom("SanFrancisco", size: 12))
                                    .foregroundColor(.gray)
                            }
                        }
                    }
                }
            }
        }
    }
}



Solution

  • I figured it out. You can use userDefaults to save data from one View, then view it in the other.

    struct Achievement: Codable, Identifiable {
        let id: String
        let title: String
        let description: String
        var isComplete: Bool = false
        init(title: String, description: String, isComplete: Bool) {
            self.title = title
            self.description = description
            self.isComplete = isComplete
            self.id = UUID().uuidString
        }
    }
    
    // to read (not full code)
    .onAppear {
                LoadAchievements()
            }
        }
        
        func LoadAchievements() {
            let decoder = JSONDecoder()
            if let data = UserDefaults.standard.data(forKey: "achievements") {
                achievements = try! decoder.decode([Achievement].self, from: data) as? [Achievement] ?? [
                    Achievement(title: "Busy Bee I", description: "Make 10 tasks", isComplete: false),
                    Achievement(title: "Busy Bee II", description: "Make 25 tasks", isComplete: false),
                    Achievement(title: "Busy Bee III", description: "Make 50 tasks", isComplete: false),
                    Achievement(title: "Busy Bee IV", description: "Make 100 tasks", isComplete: false),
                    Achievement(title: "Done and Done I", description: "Make 10 tasks", isComplete: false),
                    Achievement(title: "Done and Done II", description: "Delete 25 tasks", isComplete: false),
                    Achievement(title: "Done and Done III", description: "Delete 50 tasks", isComplete: false),
                    Achievement(title: "Done and Done IV", description: "Delete 100 tasks", isComplete: false),
                    Achievement(title: "Home Sweet Home", description: "Customize Something In Settings", isComplete: false),
                    Achievement(title: "Sharing Is Caring", description: "Share your taskfairy list", isComplete: false)
                ]
            }
        }
    
    // to set
    tasksMadeCount += 1
                            userDefaults.set(tasksMadeCount, forKey: "tasksMadeCount")
                            if(userDefaults.integer(forKey: "tasksMadeCount") == 10) {
                                achievements[0].isComplete = true
                            }