Add batch actions for multi-task completion (Phase 7)
Implement batch task completion feature allowing users to select and complete multiple care tasks at once. Adds edit mode to Today View with selection checkmarks, floating BatchActionBar, and confirmation dialog for completing more than 3 tasks. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -157,7 +157,7 @@ final class CreateCareScheduleUseCaseTests: XCTestCase {
|
||||
|
||||
// Then
|
||||
let wateringTasks = result.tasks.filter { $0.type == .watering }
|
||||
XCTAssertTrue(wateringTasks.allSatisfy { $0.notes?.contains("thorough") ?? false })
|
||||
XCTAssertTrue(wateringTasks.allSatisfy { $0.notes.contains("thorough") })
|
||||
}
|
||||
|
||||
func testExecute_WateringTasks_HaveCorrectPlantID() async throws {
|
||||
@@ -242,7 +242,7 @@ final class CreateCareScheduleUseCaseTests: XCTestCase {
|
||||
|
||||
// Then
|
||||
let fertilizerTasks = result.tasks.filter { $0.type == .fertilizing }
|
||||
XCTAssertTrue(fertilizerTasks.allSatisfy { $0.notes?.contains("highNitrogen") ?? false })
|
||||
XCTAssertTrue(fertilizerTasks.allSatisfy { $0.notes.contains("highNitrogen") })
|
||||
}
|
||||
|
||||
// MARK: - User Preferences Tests
|
||||
|
||||
@@ -26,6 +26,7 @@ final class MockCareScheduleRepository: CareScheduleRepositoryProtocol, @uncheck
|
||||
var fetchAllTasksCallCount = 0
|
||||
var updateTaskCallCount = 0
|
||||
var deleteCallCount = 0
|
||||
var batchCompleteCallCount = 0
|
||||
|
||||
// MARK: - Error Configuration
|
||||
|
||||
@@ -35,6 +36,7 @@ final class MockCareScheduleRepository: CareScheduleRepositoryProtocol, @uncheck
|
||||
var shouldThrowOnFetchAllTasks = false
|
||||
var shouldThrowOnUpdateTask = false
|
||||
var shouldThrowOnDelete = false
|
||||
var shouldThrowOnBatchComplete = false
|
||||
|
||||
var errorToThrow: Error = NSError(
|
||||
domain: "MockError",
|
||||
@@ -48,6 +50,7 @@ final class MockCareScheduleRepository: CareScheduleRepositoryProtocol, @uncheck
|
||||
var lastFetchedPlantID: UUID?
|
||||
var lastUpdatedTask: CareTask?
|
||||
var lastDeletedPlantID: UUID?
|
||||
var lastBatchCompletedTaskIDs: Set<UUID>?
|
||||
|
||||
// MARK: - CareScheduleRepositoryProtocol
|
||||
|
||||
@@ -111,6 +114,35 @@ final class MockCareScheduleRepository: CareScheduleRepositoryProtocol, @uncheck
|
||||
schedules.removeValue(forKey: plantID)
|
||||
}
|
||||
|
||||
func batchCompleteTasks(_ taskIDs: Set<UUID>) async throws {
|
||||
batchCompleteCallCount += 1
|
||||
lastBatchCompletedTaskIDs = taskIDs
|
||||
if shouldThrowOnBatchComplete {
|
||||
throw errorToThrow
|
||||
}
|
||||
|
||||
let now = Date()
|
||||
for (plantID, var schedule) in schedules {
|
||||
var modified = false
|
||||
for (index, task) in schedule.tasks.enumerated() {
|
||||
if taskIDs.contains(task.id) && !task.isCompleted {
|
||||
schedule.tasks[index] = CareTask(
|
||||
id: task.id,
|
||||
plantID: task.plantID,
|
||||
type: task.type,
|
||||
scheduledDate: task.scheduledDate,
|
||||
completedDate: now,
|
||||
notes: task.notes
|
||||
)
|
||||
modified = true
|
||||
}
|
||||
}
|
||||
if modified {
|
||||
schedules[plantID] = schedule
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
/// Resets all state for clean test setup
|
||||
@@ -123,6 +155,7 @@ final class MockCareScheduleRepository: CareScheduleRepositoryProtocol, @uncheck
|
||||
fetchAllTasksCallCount = 0
|
||||
updateTaskCallCount = 0
|
||||
deleteCallCount = 0
|
||||
batchCompleteCallCount = 0
|
||||
|
||||
shouldThrowOnSave = false
|
||||
shouldThrowOnFetch = false
|
||||
@@ -130,11 +163,13 @@ final class MockCareScheduleRepository: CareScheduleRepositoryProtocol, @uncheck
|
||||
shouldThrowOnFetchAllTasks = false
|
||||
shouldThrowOnUpdateTask = false
|
||||
shouldThrowOnDelete = false
|
||||
shouldThrowOnBatchComplete = false
|
||||
|
||||
lastSavedSchedule = nil
|
||||
lastFetchedPlantID = nil
|
||||
lastUpdatedTask = nil
|
||||
lastDeletedPlantID = nil
|
||||
lastBatchCompletedTaskIDs = nil
|
||||
}
|
||||
|
||||
/// Adds a schedule directly to storage (bypasses save method)
|
||||
|
||||
Reference in New Issue
Block a user