xxxxxxxxxx
import SwiftUI
@main
struct BucketListApp: App {
@StateObject var dataStore = DataStore()
var body: some Scene {
WindowGroup {
BucketListView()
.environmentObject(dataStore)
.onAppear {
print(URL.documentsDirectory.path)
}
}
}
}
xxxxxxxxxx
import SwiftUI
struct BucketListView: View {
@EnvironmentObject var dataStore: DataStore
@State private var newItem = ""
var body: some View {
NavigationStack {
VStack {
HStack {
TextField("New Bucket Item", text: $newItem)
.textFieldStyle(.roundedBorder)
Button {
dataStore.create(newItem)
newItem = ""
} label: {
Image(systemName: "plus.circle.fill")
}
.disabled(newItem.isEmpty)
}
.padding()
if !dataStore.bucketList.isEmpty {
List {
ForEach($dataStore.bucketList) { $item in
NavigationLink(value: item) {
TextField(item.name, text: $item.name, axis: .vertical)
.textFieldStyle(.roundedBorder)
.font(.title3)
.foregroundColor(item.completedDate == .distantPast ? .primary : .red)
}
.listRowSeparator(.hidden)
.onChange(of: item) { _ in
dataStore.saveList()
}
}
.onDelete { indexSet in
dataStore.delete(indexSet: indexSet)
}
}
.listStyle(.plain)
} else {
Text("Add your first BucketList item.")
Image("bucketList")
Spacer()
}
}
.navigationTitle("Bucket List")
.navigationDestination(for: BucketItem.self) { item in
DetailView(bucketItem: item)
}
}
}
}
struct BucketListView_Previews: PreviewProvider {
static var previews: some View {
BucketListView()
.environmentObject(DataStore())
}
}
xxxxxxxxxx
import SwiftUI
struct DetailView: View {
@EnvironmentObject var dataStore: DataStore
let bucketItem: BucketItem
@State private var note = ""
@State private var completedDate = Date.distantPast
@Environment(\.dismiss) var dismiss
var body: some View {
Form {
TextField("Bucket Note", text: $note, axis: .vertical)
if completedDate != Date.distantPast {
DatePicker("Completed on", selection: $completedDate, displayedComponents: .date)
}
Button(completedDate == Date.distantPast ? "Add Date" : "Clear Date") {
if completedDate == Date.distantPast {
completedDate = Date()
} else {
completedDate = Date.distantPast
}
}
.buttonStyle(.borderedProminent)
}
.onAppear {
note = bucketItem.note
completedDate = bucketItem.completedDate
}
.toolbar {
ToolbarItem {
Button("Update") {
dataStore.update(bucketItem: bucketItem, note: note, completedDate: completedDate)
dismiss()
}
.buttonStyle(.borderedProminent)
}
}
.navigationTitle(bucketItem.name)
}
}
struct DetailView_Previews: PreviewProvider {
static let bucketItem = BucketItem.samples[2]
static var previews: some View {
NavigationStack{
DetailView(bucketItem: bucketItem)
.environmentObject(DataStore())
}
}
}
xxxxxxxxxx
import Foundation
struct BucketItem: Identifiable, Hashable, Codable {
var id = UUID()
var name: String
var note = ""
var completedDate = Date.distantPast
static var samples: [BucketItem] {
[
BucketItem(name: "Climb Mt. Everest"),
BucketItem(name: "Visit Hawaii", note: "Go to Maui and Oahu"),
BucketItem(name: "Get Married", note: "Found the love of my life", completedDate: Date())
]
}
}
xxxxxxxxxx
import Foundation
class DataStore: ObservableObject {
@Published var bucketList:[BucketItem] = []
let fileURL = URL.documentsDirectory.appending(path: "bucketList.json")
init() {
loadItems()
}
func loadItems() {
if FileManager().fileExists(atPath: fileURL.path) {
do {
let data = try Data(contentsOf: fileURL)
bucketList = try JSONDecoder().decode([BucketItem].self, from: data)
} catch {
// The file is corrupt so currently the bucketList is empty so store it and replace the damaged file
saveList()
}
}
}
func update(bucketItem: BucketItem, note: String, completedDate: Date) {
if let index = bucketList.firstIndex(where: {$0.id == bucketItem.id}) {
bucketList[index].note = note
bucketList[index].completedDate = completedDate
saveList()
}
}
func saveList() {
do {
let bucketListData = try JSONEncoder().encode(bucketList)
let bucketListString = String(decoding: bucketListData, as: UTF8.self)
try bucketListString.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
fatalError("Could not encode bucket list and save it.")
}
}
func create(_ newItem: String) {
let newBucketItem = BucketItem(name: newItem)
bucketList.append(newBucketItem)
saveList()
}
func delete(indexSet: IndexSet) {
bucketList.remove(atOffsets: indexSet)
saveList()
}
}