// // ContentView.swift // Todos // // Created by Sam Jaffe on 2/28/26. // import SwiftUI import SwiftData struct ContentView: View { @Environment(\.modelContext) private var modelContext @AppStorage(UserDefaultsKeys.WeekStart) private var weekStart = Date() let inPreview = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" @Binding var isMoveMode: Bool @Query private var items: [Project] @State private var selection: Project? var body: some View { NavigationSplitView { List(selection: $selection) { ForEach(items, id: \.self) { item in NavigationLink(value: item) { ProjectSidebarView(name: Bindable(item).name) } .contextMenu { Button(action: { deleteItem(item: item) }) { Label("Delete", systemImage: "trash") } } } .onDelete(perform: deleteItems) } .navigationSplitViewColumnWidth(min: 180, ideal: 200) .toolbar { ToolbarItem { Button(action: addItem) { Label("New Project", systemImage: "plus") } } } } detail: { if let selection = selection { ProjectPanelView(item: selection, isMoveMode: $isMoveMode) } else { let header = items.isEmpty ? "Create a New Project" : "Select a project from the sidebar" ContentUnavailableView(header, systemImage: "doc.text.image.fill") } } .onAppear(perform: autosave) } private func addItem() { withAnimation { let newItem = Project(timestamp: Date()) modelContext.insert(newItem) } } private func autosave() { if inPreview { // This isn't great, but we shouldn't be running this in a preview // environment in the first place, so w/e. return } let now = Date() let sunday = Calendar.current.nextDate(after: weekStart, matching: DateComponents(weekday: 1), matchingPolicy: .nextTime) if now <= sunday! { return } let ymd = weekStart.formatted(.iso8601.year().month().day()) SaveController.save(items, to: SaveController.filename(date: ymd)) weekStart = now cleanup() } private func cleanup() { for item in items { item.tasks.removeAll(where: { $0.status == .Complete }) for task in item.tasks { if task.status == .InProgress { task.status = .Todo } task.subtasks.removeAll(where: { $0.status == .Complete }) for subtask in task.subtasks { if subtask.status == .InProgress { subtask.status = .Todo } } } } } private func deleteItem(item: Project) { if let selection = selection, selection == item { self.selection = nil } withAnimation { modelContext.delete(item) } } private func deleteItems(offsets: IndexSet) { if let selection = selection, offsets.contains(where: { items[$0] == selection }) { self.selection = nil } withAnimation { for index in offsets { modelContext.delete(items[index]) } } } } #Preview { @Previewable @State var isMoveMode = false ContentView(isMoveMode: $isMoveMode) .modelContainer(for: Project.self, inMemory: true) }