Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CalenTask/Services/TrashService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,35 @@ enum TrashService {
context.saveOrLog()
return purgeable.count
}

/// Attività nel cestino (radici dei sottoalberi eliminati), le più recenti prima.
@MainActor
static func trashedRoots(in context: ModelContext) -> [TodoTask] {
let predicate = #Predicate<TodoTask> { $0.deletedAt != nil }
return context.fetchOrLog(FetchDescriptor<TodoTask>(predicate: predicate))
.filter { $0.parentTask?.deletedAt == nil }
.sorted { ($0.deletedAt ?? .distantPast) > ($1.deletedAt ?? .distantPast) }
}

/// Ripristina una task e tutto il suo sottoalbero eliminato.
@MainActor
static func restore(_ task: TodoTask) {
for child in task.subtasks where child.deletedAt != nil {
restore(child)
}
guard task.deletedAt != nil else { return }
task.deletedAt = nil
task.touch()
}

/// Elimina definitivamente tutto il cestino. Ritorna quante task ha rimosso.
@MainActor
@discardableResult
static func emptyTrash(in context: ModelContext) -> Int {
let predicate = #Predicate<TodoTask> { $0.deletedAt != nil }
let all = context.fetchOrLog(FetchDescriptor<TodoTask>(predicate: predicate))
all.forEach { context.delete($0) }
context.saveOrLog()
return all.count
}
}
26 changes: 26 additions & 0 deletions CalenTaskTests/TrashServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,30 @@ struct TrashServiceTests {
let titles = try context.fetch(FetchDescriptor<TodoTask>()).map(\.title).sorted()
#expect(titles == ["Recente", "Viva"])
}

@Test func restoreBringsBackSubtree() throws {
let context = try makeContext()
let author = UUID(), ws = UUID()
let parent = TodoTask(workspaceID: ws, title: "Padre", createdByID: author)
let child = TodoTask(workspaceID: ws, title: "Figlio", createdByID: author)
context.insert(parent); context.insert(child)
child.parentTask = parent
parent.softDeleteSubtree()
#expect(TrashService.trashedRoots(in: context).map(\.title) == ["Padre"])

TrashService.restore(parent)
#expect(parent.deletedAt == nil && child.deletedAt == nil)
#expect(TrashService.trashedRoots(in: context).isEmpty)
}

@Test func emptyTrashRemovesOnlyDeleted() throws {
let context = try makeContext()
let author = UUID(), ws = UUID()
let gone = TodoTask(workspaceID: ws, title: "Via", createdByID: author)
let live = TodoTask(workspaceID: ws, title: "Viva", createdByID: author)
context.insert(gone); context.insert(live)
gone.deletedAt = .now
#expect(TrashService.emptyTrash(in: context) == 1)
#expect(try context.fetch(FetchDescriptor<TodoTask>()).map(\.title) == ["Viva"])
}
}
Loading