feat: add SwiftData persistence for lists and todos

This commit is contained in:
2026-02-12 18:36:01 +01:00
parent 7738f4b52f
commit 71af07eaf1
8 changed files with 102 additions and 33 deletions

View File

@@ -1,26 +1,35 @@
import Foundation
import Observation
import SwiftData
@Observable
class ListStore {
var lists: [TodoList]
var lists: [TodoList] = []
private let modelContext: ModelContext
var inboxID: UUID {
lists.first { $0.isInbox }!.id
}
init() {
self.lists = [TodoList(name: "Inbox", isInbox: true)]
init(modelContext: ModelContext) {
self.modelContext = modelContext
ensureInbox()
fetchLists()
}
func addList(name: String) {
let list = TodoList(name: name)
lists.append(list)
modelContext.insert(list)
save()
fetchLists()
}
func deleteList(_ list: TodoList) {
guard !list.isInbox else { return }
lists.removeAll { $0.id == list.id }
modelContext.delete(list)
save()
fetchLists()
}
func addItem(
@@ -30,14 +39,19 @@ class ListStore {
deadline: Date? = nil,
priority: Priority? = nil
) {
guard let index = lists.firstIndex(where: { $0.id == listID }) else { return }
guard let list = lists.first(where: { $0.id == listID }) else { return }
let item = TodoItem(title: title, notes: notes, deadline: deadline, priority: priority)
lists[index].items.append(item)
list.items.append(item)
save()
fetchLists()
}
func deleteItem(_ itemID: UUID, from listID: UUID) {
guard let listIndex = lists.firstIndex(where: { $0.id == listID }) else { return }
lists[listIndex].items.removeAll { $0.id == itemID }
guard let list = lists.first(where: { $0.id == listID }),
let item = list.items.first(where: { $0.id == itemID }) else { return }
modelContext.delete(item)
save()
fetchLists()
}
func updateItem(
@@ -49,22 +63,51 @@ class ListStore {
priority: Priority? = nil,
isCompleted: Bool? = nil
) {
guard let listIndex = lists.firstIndex(where: { $0.id == listID }),
let itemIndex = lists[listIndex].items.firstIndex(where: { $0.id == itemID }) else { return }
lists[listIndex].items[itemIndex].title = title
lists[listIndex].items[itemIndex].notes = notes
lists[listIndex].items[itemIndex].deadline = deadline
lists[listIndex].items[itemIndex].priority = priority
guard let list = lists.first(where: { $0.id == listID }),
let item = list.items.first(where: { $0.id == itemID }) else { return }
item.title = title
item.notes = notes
item.deadline = deadline
item.priority = priority
if let isCompleted {
lists[listIndex].items[itemIndex].isCompleted = isCompleted
item.isCompleted = isCompleted
}
lists[listIndex].items[itemIndex].modifiedAt = Date()
item.modifiedAt = Date()
save()
fetchLists()
}
func toggleItemCompleted(_ itemID: UUID, in listID: UUID) {
guard let listIndex = lists.firstIndex(where: { $0.id == listID }),
let itemIndex = lists[listIndex].items.firstIndex(where: { $0.id == itemID }) else { return }
lists[listIndex].items[itemIndex].isCompleted.toggle()
lists[listIndex].items[itemIndex].modifiedAt = Date()
guard let list = lists.first(where: { $0.id == listID }),
let item = list.items.first(where: { $0.id == itemID }) else { return }
item.isCompleted.toggle()
item.modifiedAt = Date()
save()
fetchLists()
}
// MARK: - Private
private func ensureInbox() {
let descriptor = FetchDescriptor<TodoList>(predicate: #Predicate { $0.isInbox })
let count = (try? modelContext.fetchCount(descriptor)) ?? 0
if count == 0 {
let inbox = TodoList(name: "Inbox", isInbox: true)
modelContext.insert(inbox)
save()
}
}
private func fetchLists() {
let descriptor = FetchDescriptor<TodoList>(sortBy: [SortDescriptor(\.name)])
let fetched = (try? modelContext.fetch(descriptor)) ?? []
// Inbox always first
let inbox = fetched.filter { $0.isInbox }
let rest = fetched.filter { !$0.isInbox }
lists = inbox + rest
}
private func save() {
try? modelContext.save()
}
}