Skip to content

Instantly share code, notes, and snippets.

@mjarraya
Last active May 5, 2020 12:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjarraya/ed2e6a0a4b9a961597f04a019701dbfc to your computer and use it in GitHub Desktop.
Save mjarraya/ed2e6a0a4b9a961597f04a019701dbfc to your computer and use it in GitHub Desktop.
//
// ContentView.swift
// HabitTracker
//
// Created by Montasar on 05/05/2020.
// Copyright © 2020 Montasar. All rights reserved.
//
import SwiftUI
struct Activity: Identifiable, Codable {
let id = UUID()
let name: String
let description: String
var count: Int
// init(name: String, description: String, count: Int) {
// self.id = UUID()
// self.name = name
// self.description = description
// self.count = count
// }
}
class Activities: ObservableObject {
@Published var items = [Activity]() {
didSet {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(items) {
UserDefaults.standard.set(encoded, forKey: "activities")
}
}
}
init() {
let decoder = JSONDecoder()
if let activities = UserDefaults.standard.data(forKey: "activities") {
if let decoded = try? decoder.decode([Activity].self, from: activities) {
self.items = decoded
return
}
}
self.items = []
}
}
struct AddActivity: View {
@Environment (\.presentationMode) var presentationMode
@ObservedObject var activities: Activities
@State private var name = ""
@State private var description = ""
func createActivity() {
let activity = Activity(name: name, description: description, count: 1)
activities.items.append(activity)
}
var body: some View {
NavigationView {
VStack {
TextField("Activity name", text: $name) .multilineTextAlignment(TextAlignment.center).padding(10)
TextField("Description", text: $description) .multilineTextAlignment(TextAlignment.center).padding(10)
Button(action: {
self.createActivity()
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Create").padding( .vertical, 5).padding(.horizontal, 15).foregroundColor(.white)
.background(Color.blue).cornerRadius(20)
}
}
.navigationBarItems(trailing: Button("Cancel") {
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
struct ActivityDetail: View {
@State var activity: Activity
@ObservedObject var activities: Activities
func incrementCount() {
// here is the ugly part where I would have preferred to use an ObservedObject and mutate it directly
if let index = activities.items.firstIndex(where: { $0.id == activity.id }) {
var newActivity = activities.items[index]
newActivity.count += 1
activities.items[index] = newActivity
activity = newActivity
}
}
var body: some View {
VStack {
Text(activity.name)
Text(activity.description)
Text("Completed \(activity.count) times")
Button(action: {
self.incrementCount()
}) {
Text("Increment").padding( .vertical, 5).padding(.horizontal, 15).foregroundColor(.white)
.background(Color.blue).cornerRadius(20)
}
}
}
}
struct ContentView: View {
@State private var showingAddActivity = false
@ObservedObject var activities = Activities()
func removeActivity(at offsets: IndexSet) {
activities.items.remove(atOffsets: offsets)
}
var body: some View {
NavigationView {
List {
ForEach(activities.items) { item in
NavigationLink(destination: ActivityDetail(activity: item, activities: self.activities)) {
Text("\(item.name) (\(item.count))")
}
}.onDelete(perform: removeActivity)
}
.navigationBarTitle("HabitTracker")
.navigationBarItems(trailing: Button(action: {
self.showingAddActivity.toggle()
}) {
HStack {
Image(systemName: "plus")
Text("Add an activity")
}
})
.sheet(isPresented: $showingAddActivity) {
AddActivity(activities: self.activities)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment