xxxxxxxxxximport SwiftUI
@mainstruct BucketListApp: App { @StateObject var dataStore = DataStore() var body: some Scene { WindowGroup { BucketListView() .environmentObject(dataStore) .onAppear { print(URL.documentsDirectory.path) } } }}xxxxxxxxxximport 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()) }}xxxxxxxxxximport 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()) } }}xxxxxxxxxximport 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()) ] }}xxxxxxxxxximport 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() }}