Hello,
I'm working on the Habit Tracker app. How do you save the timesCompleted
property? In the ContentView
, it just shows as 0 and sure enough, when I enter the ActivityView
, timesCompleted
is back to 0. I tried many times but nothing is working. Maybe I haven't realised something about SwiftUI yet. Help would be appreciated!
ContentView:
import SwiftUI
struct ContentView: View {
var activities = Activities()
var body: some View {
NavigationStack {
List {
ForEach(activities.activities, id: \.id) { activity in
NavigationLink {
ActivityView(title: activity.title, description: activity.description, timesCompleted: activity.timesCompleted)
} label: {
VStack(alignment: .leading) {
Text(activity.title)
.font(.headline.bold())
Text("Times completed: \(activity.timesCompleted)")
.font(.caption.bold())
.foregroundStyle(.secondary)
}
}
}
.listRowBackground(Color.lightBackground)
}
.navigationTitle("Quantify")
.toolbar {
NavigationLink {
AddView(activities: activities)
} label: {
Image(systemName: "plus")
.foregroundStyle(.white)
}
}
.scrollContentBackground(.hidden)
.background(.darkBackground)
}
.preferredColorScheme(.dark)
}
}
ActivityView:
import SwiftUI
struct ActivityView: View {
var title: String
var description: String
@State var timesCompleted: Int
var body: some View {
NavigationStack {
ScrollView {
VStack {
Text(description)
.padding()
Text("Times completed: \(timesCompleted)")
.font(.title.bold())
Button("Activity completed!") {
timesCompleted += 1
}
.padding()
.background(.lightBackground)
.foregroundStyle(.white)
.clipShape(RoundedRectangle(cornerRadius: 60))
.font(.title.bold())
}
}
.navigationTitle(title)
.frame(maxWidth: .infinity)
.background(.darkBackground)
}
}
}
AddView:
import SwiftUI
struct AddView: View {
@State private var title = "Untitled activity"
@State private var description = ""
@Environment(\.dismiss) var dismiss
var activities: Activities
var body: some View {
NavigationStack {
Form {
TextField("Enter description", text: $description)
.listRowBackground(Color.lightBackground)
}
.navigationBarBackButtonHidden()
.scrollContentBackground(.hidden)
.background(.darkBackground)
.navigationTitle($title)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button("Save") {
let activity = Activity(title: title, description: description)
activities.activities.append(activity)
dismiss()
}
}
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") {
dismiss()
}
}
}
}
}
}
Activity struct:
import Foundation
struct Activity: Identifiable, Codable {
var title: String
var description: String
var id = UUID()
var timesCompleted = 0
}
Activities class:
import Foundation
@Observable
class Activities {
var activities = [Activity]() {
didSet {
if let encoded = try? JSONEncoder().encode(activities) {
UserDefaults.standard.set(encoded, forKey: "Activities")
}
}
}
init() {
if let savedActivities = UserDefaults.standard.data(forKey: "Activities") {
if let decodedActivities = try? JSONDecoder().decode([Activity].self, from: savedActivities) {
activities = decodedActivities
return
}
}
activities = []
}
}
Colour-Theme:
import SwiftUI
extension ShapeStyle where Self == Color {
static var darkBackground: Color {
Color(red: 0.2, green: 0.4, blue: 0.2)
}
static var lightBackground: Color {
Color(red: 0.3, green: 0.5, blue: 0.3)
}
}