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
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -112,6 +113,46 @@ class UpcomingViewModelTest : ViewModelTest<UpcomingViewModel, UpcomingViewData,
}
}

@Test
fun `should call markCompleted when MarkTaskAsCompleted is emitted`() {
val taskId = Uuid.parse("550e8400-e29b-41d4-a716-446655440000")

fakeUpcomingViewDataMapper.result = UpcomingViewData.Empty
every { mockTaskRepository.findAllPendingTasks() } returns flowOf(emptyList())
everySuspend { mockTaskRepository.markCompleted(taskId) } returns Unit

test {
expectState(UpcomingViewData.Loading)
expectState(UpcomingViewData.Empty)

viewModel.onEvent(UpcomingEvent.MarkTaskAsCompleted(taskId.toString()))
// Let the Orbit intent run before verifying its effect.
delay(1)
}

verifySuspend { mockTaskRepository.markCompleted(taskId) }
}

@Test
fun `should call markNotCompleted when MarkTaskAsNotCompleted is emitted`() {
val taskId = Uuid.parse("550e8400-e29b-41d4-a716-446655440000")

fakeUpcomingViewDataMapper.result = UpcomingViewData.Empty
every { mockTaskRepository.findAllPendingTasks() } returns flowOf(emptyList())
everySuspend { mockTaskRepository.markNotCompleted(taskId) } returns Unit

test {
expectState(UpcomingViewData.Loading)
expectState(UpcomingViewData.Empty)

viewModel.onEvent(UpcomingEvent.MarkTaskAsNotCompleted(taskId.toString()))
// Let the Orbit intent run before verifying its effect.
delay(1)
}

verifySuspend { mockTaskRepository.markNotCompleted(taskId) }
}

private class FakeUpcomingViewDataMapper(
timeProvider: DefaultTimeProvider = DefaultTimeProvider(),
) : UpcomingViewDataMapper(
Expand Down
Loading