Files
aris-old/IrisCompanion/iris/ViewModels/TodosViewModel.swift

74 lines
1.9 KiB
Swift
Raw Normal View History

2026-01-10 20:20:32 +00:00
//
// TodosViewModel.swift
// iris
//
// Created by Codex.
//
import Foundation
@MainActor
final class TodosViewModel: ObservableObject {
@Published private(set) var todos: [TodoItem] = []
@Published var newTitle: String = ""
private let store: TodoStore
init(store: TodoStore = TodoStore()) {
self.store = store
refresh()
}
func refresh() {
todos = sortedItems(store.snapshot())
}
func addTodo() {
let trimmed = normalizedTitle(newTitle)
guard !trimmed.isEmpty else { return }
store.add(title: trimmed)
newTitle = ""
refresh()
}
func deleteTodo(id: UUID) {
store.delete(id: id)
refresh()
}
func toggleCompleted(id: UUID) {
guard let current = todos.first(where: { $0.id == id }) else { return }
store.setCompleted(id: id, completed: !current.isCompleted)
refresh()
}
func updateTitle(id: UUID, title: String) {
let trimmed = normalizedTitle(title)
guard !trimmed.isEmpty else { return }
store.updateTitle(id: id, title: trimmed)
refresh()
}
private func normalizedTitle(_ raw: String) -> String {
raw.trimmingCharacters(in: .whitespacesAndNewlines)
}
private func sortedItems(_ items: [TodoItem]) -> [TodoItem] {
items.sorted { lhs, rhs in
if lhs.isCompleted != rhs.isCompleted {
return !lhs.isCompleted
}
if lhs.isCompleted {
let lhsDate = lhs.completedAt ?? lhs.updatedAt
let rhsDate = rhs.completedAt ?? rhs.updatedAt
if lhsDate != rhsDate {
return lhsDate > rhsDate
}
} else if lhs.createdAt != rhs.createdAt {
return lhs.createdAt > rhs.createdAt
}
return lhs.id.uuidString < rhs.id.uuidString
}
}
}