From 216e6ad0768d4fc03de366a1395d37570e9b7076 Mon Sep 17 00:00:00 2001 From: Messias Junior Date: Thu, 22 Oct 2026 12:36:51 +0100 Subject: [PATCH] upcoming task completion --- .../feature/upcoming/UpcomingScreen.kt | 8 +++- .../feature/upcoming/UpcomingViewModel.kt | 12 +++++ .../feature/upcoming/UpcomingScreenTest.kt | 48 +++++++++++++++++++ .../feature/upcoming/UpcomingViewModelTest.kt | 41 ++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/foliary/src/commonMain/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingScreen.kt b/foliary/src/commonMain/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingScreen.kt index efb48f0..626eef7 100644 --- a/foliary/src/commonMain/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingScreen.kt +++ b/foliary/src/commonMain/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingScreen.kt @@ -235,7 +235,13 @@ private fun UpcomingTaskItem( .padding(horizontal = 16.dp, vertical = 4.dp) .align(Alignment.Center), task = task, - onCompletedChange = {}, + onCompletedChange = { isCompleted -> + if (isCompleted) { + onEvent(UpcomingEvent.MarkTaskAsCompleted(task.id)) + } else { + onEvent(UpcomingEvent.MarkTaskAsNotCompleted(task.id)) + } + }, onClick = { onEvent(UpcomingEvent.OnTaskClick(task.id)) }, onPillClick = { clickedPill -> when (clickedPill) { diff --git a/foliary/src/commonMain/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingViewModel.kt b/foliary/src/commonMain/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingViewModel.kt index 204a3d0..f905a51 100644 --- a/foliary/src/commonMain/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingViewModel.kt +++ b/foliary/src/commonMain/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingViewModel.kt @@ -29,6 +29,8 @@ class UpcomingViewModel( UpcomingEvent.OnAddTaskClick -> onAddTaskClick() is UpcomingEvent.OnTaskClick -> onTaskClick(event.taskId) is UpcomingEvent.OnUrlPillClick -> onUrlPillClick(event.taskId) + is UpcomingEvent.MarkTaskAsCompleted -> onMarkTaskAsCompleted(event.taskId) + is UpcomingEvent.MarkTaskAsNotCompleted -> onMarkTaskAsNotCompleted(event.taskId) } } @@ -44,6 +46,14 @@ class UpcomingViewModel( val task = taskRepository.getById(Uuid.parse(taskId)) task.url?.let { browserLauncher.launch(it) } } + + private fun onMarkTaskAsCompleted(taskId: String) = intent { + taskRepository.markCompleted(Uuid.parse(taskId)) + } + + private fun onMarkTaskAsNotCompleted(taskId: String) = intent { + taskRepository.markNotCompleted(Uuid.parse(taskId)) + } } sealed interface UpcomingViewData { @@ -72,6 +82,8 @@ sealed interface UpcomingEvent { data object OnAddTaskClick : UpcomingEvent data class OnTaskClick(val taskId: String) : UpcomingEvent data class OnUrlPillClick(val taskId: String) : UpcomingEvent + data class MarkTaskAsCompleted(val taskId: String) : UpcomingEvent + data class MarkTaskAsNotCompleted(val taskId: String) : UpcomingEvent } sealed interface UpcomingAction : Action { diff --git a/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingScreenTest.kt b/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingScreenTest.kt index 8fd377a..aee22f5 100644 --- a/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingScreenTest.kt +++ b/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingScreenTest.kt @@ -149,4 +149,52 @@ class UpcomingScreenTest { event shouldBe UpcomingEvent.OnUrlPillClick(task.id) } + + @Test + fun `should emit MarkTaskAsCompleted when an unfinished task checkbox is checked`() = runComposeUiTest { + val task = FoliaryTaskCardViewData.fixture(id = "task-id", isCompleted = false) + var event: UpcomingEvent? = null + val group = UpcomingViewData.TaskGroup.fixture( + label = UpcomingViewData.GroupLabel.Today, + tasks = listOf(task) + ) + + setContent { + UpcomingScreenContent( + lazyListState = rememberLazyListState(), + viewData = UpcomingViewData.Loaded(listOf(group)), + onEvent = { event = it }, + ) + } + + onNodeWithTag("FoliaryTaskCard:Checkbox", useUnmergedTree = true) + .assertIsDisplayed() + .performClick() + + event shouldBe UpcomingEvent.MarkTaskAsCompleted(task.id) + } + + @Test + fun `should emit MarkTaskAsNotCompleted when a completed task checkbox is unchecked`() = runComposeUiTest { + val task = FoliaryTaskCardViewData.fixture(id = "task-id", isCompleted = true) + var event: UpcomingEvent? = null + val group = UpcomingViewData.TaskGroup.fixture( + label = UpcomingViewData.GroupLabel.Today, + tasks = listOf(task) + ) + + setContent { + UpcomingScreenContent( + lazyListState = rememberLazyListState(), + viewData = UpcomingViewData.Loaded(listOf(group)), + onEvent = { event = it }, + ) + } + + onNodeWithTag("FoliaryTaskCard:Checkbox", useUnmergedTree = true) + .assertIsDisplayed() + .performClick() + + event shouldBe UpcomingEvent.MarkTaskAsNotCompleted(task.id) + } } diff --git a/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingViewModelTest.kt b/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingViewModelTest.kt index 51caea5..05a3d33 100644 --- a/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingViewModelTest.kt +++ b/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/upcoming/UpcomingViewModelTest.kt @@ -13,6 +13,7 @@ import dev.mokkery.every import dev.mokkery.everySuspend import dev.mokkery.mock import dev.mokkery.verify +import dev.mokkery.verifySuspend import io.kotest.matchers.shouldBe import kotlinx.coroutines.delay import kotlinx.coroutines.flow.flowOf @@ -112,6 +113,46 @@ class UpcomingViewModelTest : ViewModelTest