refactor: decouple card detail viewmodel datasource contracts
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package space.hackenslacker.kanbn4droid.app.carddetail
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import java.time.LocalDate
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -45,13 +46,55 @@ sealed interface CardDetailUiEvent {
|
||||
data class ShowSnackbar(val message: String) : CardDetailUiEvent
|
||||
}
|
||||
|
||||
sealed interface DataSourceResult<out T> {
|
||||
data class Success<T>(val value: T) : DataSourceResult<T>
|
||||
data class GenericError(val message: String) : DataSourceResult<Nothing>
|
||||
data object SessionExpired : DataSourceResult<Nothing>
|
||||
}
|
||||
|
||||
interface CardDetailDataSource {
|
||||
suspend fun loadCard(cardId: String): CardDetailRepository.Result<CardDetail>
|
||||
suspend fun updateTitle(cardId: String, title: String): CardDetailRepository.Result<Unit>
|
||||
suspend fun updateDescription(cardId: String, description: String): CardDetailRepository.Result<Unit>
|
||||
suspend fun updateDueDate(cardId: String, dueDate: LocalDate?): CardDetailRepository.Result<Unit>
|
||||
suspend fun listActivities(cardId: String): CardDetailRepository.Result<List<CardActivity>>
|
||||
suspend fun addComment(cardId: String, comment: String): CardDetailRepository.Result<Unit>
|
||||
suspend fun loadCard(cardId: String): DataSourceResult<CardDetail>
|
||||
suspend fun updateTitle(cardId: String, title: String): DataSourceResult<Unit>
|
||||
suspend fun updateDescription(cardId: String, description: String): DataSourceResult<Unit>
|
||||
suspend fun updateDueDate(cardId: String, dueDate: LocalDate?): DataSourceResult<Unit>
|
||||
suspend fun listActivities(cardId: String): DataSourceResult<List<CardActivity>>
|
||||
suspend fun addComment(cardId: String, comment: String): DataSourceResult<Unit>
|
||||
}
|
||||
|
||||
internal class CardDetailRepositoryDataSource(
|
||||
private val repository: CardDetailRepository,
|
||||
private val loadCardCall: suspend (String) -> CardDetailRepository.Result<CardDetail>,
|
||||
) : CardDetailDataSource {
|
||||
override suspend fun loadCard(cardId: String): DataSourceResult<CardDetail> {
|
||||
return loadCardCall(cardId).toDataSourceResult()
|
||||
}
|
||||
|
||||
override suspend fun updateTitle(cardId: String, title: String): DataSourceResult<Unit> {
|
||||
return repository.updateTitle(cardId, title).toDataSourceResult()
|
||||
}
|
||||
|
||||
override suspend fun updateDescription(cardId: String, description: String): DataSourceResult<Unit> {
|
||||
return repository.updateDescription(cardId, description).toDataSourceResult()
|
||||
}
|
||||
|
||||
override suspend fun updateDueDate(cardId: String, dueDate: LocalDate?): DataSourceResult<Unit> {
|
||||
return repository.updateDueDate(cardId, dueDate).toDataSourceResult()
|
||||
}
|
||||
|
||||
override suspend fun listActivities(cardId: String): DataSourceResult<List<CardActivity>> {
|
||||
return repository.listActivities(cardId).toDataSourceResult()
|
||||
}
|
||||
|
||||
override suspend fun addComment(cardId: String, comment: String): DataSourceResult<Unit> {
|
||||
val result = repository.addComment(cardId, comment)
|
||||
return when (result) {
|
||||
is CardDetailRepository.Result.Success -> DataSourceResult.Success(Unit)
|
||||
is CardDetailRepository.Result.Failure.SessionExpired -> DataSourceResult.SessionExpired
|
||||
is CardDetailRepository.Result.Failure.Generic -> {
|
||||
DataSourceResult.GenericError(result.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CardDetailViewModel(
|
||||
@@ -93,7 +136,7 @@ class CardDetailViewModel(
|
||||
}
|
||||
|
||||
when (val result = repository.loadCard(cardId)) {
|
||||
is CardDetailRepository.Result.Success -> {
|
||||
is DataSourceResult.Success -> {
|
||||
val detail = result.value
|
||||
persistedTitle = detail.title
|
||||
persistedDescription = detail.description
|
||||
@@ -114,7 +157,7 @@ class CardDetailViewModel(
|
||||
loadActivities()
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.SessionExpired -> {
|
||||
is DataSourceResult.SessionExpired -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isInitialLoading = false,
|
||||
@@ -124,7 +167,7 @@ class CardDetailViewModel(
|
||||
_events.emit(CardDetailUiEvent.SessionExpired)
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.Generic -> {
|
||||
is DataSourceResult.GenericError -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isInitialLoading = false,
|
||||
@@ -249,7 +292,7 @@ class CardDetailViewModel(
|
||||
viewModelScope.launch {
|
||||
_uiState.update { it.copy(isCommentSubmitting = true, commentErrorMessage = null) }
|
||||
when (val result = repository.addComment(cardId, payload)) {
|
||||
is CardDetailRepository.Result.Success -> {
|
||||
is DataSourceResult.Success -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isCommentSubmitting = false,
|
||||
@@ -262,7 +305,7 @@ class CardDetailViewModel(
|
||||
loadActivities()
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.SessionExpired -> {
|
||||
is DataSourceResult.SessionExpired -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isCommentSubmitting = false,
|
||||
@@ -272,7 +315,7 @@ class CardDetailViewModel(
|
||||
_events.emit(CardDetailUiEvent.SessionExpired)
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.Generic -> {
|
||||
is DataSourceResult.GenericError -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isCommentSubmitting = false,
|
||||
@@ -310,7 +353,7 @@ class CardDetailViewModel(
|
||||
viewModelScope.launch {
|
||||
_uiState.update { it.copy(isTitleSaving = true, titleErrorMessage = null) }
|
||||
when (val result = repository.updateTitle(cardId, normalized)) {
|
||||
is CardDetailRepository.Result.Success -> {
|
||||
is DataSourceResult.Success -> {
|
||||
persistedTitle = normalized
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
@@ -321,7 +364,7 @@ class CardDetailViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.SessionExpired -> {
|
||||
is DataSourceResult.SessionExpired -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isTitleSaving = false,
|
||||
@@ -331,7 +374,7 @@ class CardDetailViewModel(
|
||||
_events.emit(CardDetailUiEvent.SessionExpired)
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.Generic -> {
|
||||
is DataSourceResult.GenericError -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isTitleSaving = false,
|
||||
@@ -387,7 +430,7 @@ class CardDetailViewModel(
|
||||
inFlightDescriptionPayload = normalized
|
||||
_uiState.update { it.copy(isDescriptionSaving = true, descriptionErrorMessage = null) }
|
||||
when (val result = repository.updateDescription(cardId, normalized)) {
|
||||
is CardDetailRepository.Result.Success -> {
|
||||
is DataSourceResult.Success -> {
|
||||
persistedDescription = normalized
|
||||
_uiState.update {
|
||||
val stillDirty = it.description != persistedDescription
|
||||
@@ -399,7 +442,7 @@ class CardDetailViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.SessionExpired -> {
|
||||
is DataSourceResult.SessionExpired -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isDescriptionSaving = false,
|
||||
@@ -409,7 +452,7 @@ class CardDetailViewModel(
|
||||
_events.emit(CardDetailUiEvent.SessionExpired)
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.Generic -> {
|
||||
is DataSourceResult.GenericError -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isDescriptionSaving = false,
|
||||
@@ -450,7 +493,7 @@ class CardDetailViewModel(
|
||||
}
|
||||
|
||||
when (val result = repository.updateDueDate(cardId, dueDate)) {
|
||||
is CardDetailRepository.Result.Success -> {
|
||||
is DataSourceResult.Success -> {
|
||||
persistedDueDate = dueDate
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
@@ -460,7 +503,7 @@ class CardDetailViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.SessionExpired -> {
|
||||
is DataSourceResult.SessionExpired -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isDueDateSaving = false,
|
||||
@@ -470,7 +513,7 @@ class CardDetailViewModel(
|
||||
_events.emit(CardDetailUiEvent.SessionExpired)
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.Generic -> {
|
||||
is DataSourceResult.GenericError -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isDueDateSaving = false,
|
||||
@@ -489,17 +532,17 @@ class CardDetailViewModel(
|
||||
viewModelScope.launch {
|
||||
_uiState.update { it.copy(isActivitiesLoading = true, activitiesErrorMessage = null) }
|
||||
when (val result = repository.listActivities(cardId)) {
|
||||
is CardDetailRepository.Result.Success -> {
|
||||
is DataSourceResult.Success -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isActivitiesLoading = false,
|
||||
activities = result.value.sortedByDescending { activity -> activity.createdAtEpochMillis },
|
||||
activities = result.value,
|
||||
activitiesErrorMessage = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.SessionExpired -> {
|
||||
is DataSourceResult.SessionExpired -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isActivitiesLoading = false,
|
||||
@@ -509,7 +552,7 @@ class CardDetailViewModel(
|
||||
_events.emit(CardDetailUiEvent.SessionExpired)
|
||||
}
|
||||
|
||||
is CardDetailRepository.Result.Failure.Generic -> {
|
||||
is DataSourceResult.GenericError -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
isActivitiesLoading = false,
|
||||
@@ -520,4 +563,25 @@ class CardDetailViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val cardId: String,
|
||||
private val dataSource: CardDetailDataSource,
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
if (modelClass.isAssignableFrom(CardDetailViewModel::class.java)) {
|
||||
return CardDetailViewModel(cardId = cardId, repository = dataSource) as T
|
||||
}
|
||||
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> CardDetailRepository.Result<T>.toDataSourceResult(): DataSourceResult<T> {
|
||||
return when (this) {
|
||||
is CardDetailRepository.Result.Success -> DataSourceResult.Success(value)
|
||||
is CardDetailRepository.Result.Failure.Generic -> DataSourceResult.GenericError(message)
|
||||
is CardDetailRepository.Result.Failure.SessionExpired -> DataSourceResult.SessionExpired
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun initialLoad_fillsEditableFieldsAndActivities() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(sampleActivitiesShuffled()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(sampleActivitiesShuffled()),
|
||||
)
|
||||
val viewModel = CardDetailViewModel(
|
||||
cardId = "card-1",
|
||||
@@ -61,7 +61,7 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun loadSessionExpired_emitsEvent_andRetryPathsDoNotRun() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Failure.SessionExpired(),
|
||||
loadCardResult = DataSourceResult.SessionExpired,
|
||||
)
|
||||
val viewModel = CardDetailViewModel(cardId = "card-1", repository = repository)
|
||||
val eventDeferred = async { viewModel.events.first() }
|
||||
@@ -90,8 +90,8 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun titleTrimRejectsBlank_andIsolatedFromDescription() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(emptyList()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(emptyList()),
|
||||
)
|
||||
val viewModel = loadedViewModel(this, repository)
|
||||
|
||||
@@ -109,8 +109,8 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun dueDateSetAndClear_areIndependentAndSaved() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(emptyList()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(emptyList()),
|
||||
)
|
||||
val viewModel = loadedViewModel(this, repository)
|
||||
|
||||
@@ -130,8 +130,8 @@ class CardDetailViewModelTest {
|
||||
fun descriptionDebounce_savesLatestOnly_andSuppressesDuplicateInflight() = runTest {
|
||||
val gate = CompletableDeferred<Unit>()
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(emptyList()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(emptyList()),
|
||||
updateDescriptionGate = gate,
|
||||
)
|
||||
val viewModel = loadedViewModel(this, repository)
|
||||
@@ -164,8 +164,8 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun descriptionFocusLossAndOnStop_flushLatestDirtyImmediately() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(emptyList()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(emptyList()),
|
||||
)
|
||||
val viewModel = loadedViewModel(this, repository)
|
||||
|
||||
@@ -186,8 +186,8 @@ class CardDetailViewModelTest {
|
||||
val firstGate = CompletableDeferred<Unit>()
|
||||
val secondGate = CompletableDeferred<Unit>()
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(emptyList()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(emptyList()),
|
||||
updateDescriptionGates = ArrayDeque(listOf(firstGate, secondGate)),
|
||||
)
|
||||
val viewModel = loadedViewModel(this, repository)
|
||||
@@ -222,14 +222,14 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun addComment_success_closesDialog_showsSnackbar_refreshesActivities() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResults = ArrayDeque(
|
||||
listOf(
|
||||
CardDetailRepository.Result.Success(emptyList()),
|
||||
CardDetailRepository.Result.Success(sampleActivitiesShuffled()),
|
||||
DataSourceResult.Success(emptyList()),
|
||||
DataSourceResult.Success(sampleActivitiesShuffled()),
|
||||
),
|
||||
),
|
||||
addCommentResult = CardDetailRepository.Result.Success(Unit),
|
||||
addCommentResult = DataSourceResult.Success(Unit),
|
||||
)
|
||||
val viewModel = loadedViewModel(this, repository)
|
||||
val eventDeferred = async { viewModel.events.first { it is CardDetailUiEvent.ShowSnackbar } }
|
||||
@@ -250,9 +250,9 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun addComment_failure_keepsDialogOpen_andStoresRetryPayload() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(emptyList()),
|
||||
addCommentResult = CardDetailRepository.Result.Failure.Generic("Cannot add comment"),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(emptyList()),
|
||||
addCommentResult = DataSourceResult.GenericError("Cannot add comment"),
|
||||
)
|
||||
val viewModel = loadedViewModel(this, repository)
|
||||
|
||||
@@ -272,11 +272,11 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun activitiesRetry_recoversFromFailure() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResults = ArrayDeque(
|
||||
listOf(
|
||||
CardDetailRepository.Result.Failure.Generic("Network error"),
|
||||
CardDetailRepository.Result.Success(sampleActivitiesShuffled()),
|
||||
DataSourceResult.GenericError("Network error"),
|
||||
DataSourceResult.Success(sampleActivitiesShuffled()),
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -296,8 +296,8 @@ class CardDetailViewModelTest {
|
||||
val viewModel = loadedViewModel(
|
||||
this,
|
||||
FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(emptyList()),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(emptyList()),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -312,11 +312,11 @@ class CardDetailViewModelTest {
|
||||
@Test
|
||||
fun fieldSpecificRetry_usesLastAttemptedPayload() = runTest {
|
||||
val repository = FakeCardDetailDataSource(
|
||||
loadCardResult = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
listActivitiesResult = CardDetailRepository.Result.Success(emptyList()),
|
||||
updateTitleResult = CardDetailRepository.Result.Failure.Generic("title failed"),
|
||||
updateDueDateResult = CardDetailRepository.Result.Failure.Generic("due failed"),
|
||||
updateDescriptionResult = CardDetailRepository.Result.Failure.Generic("desc failed"),
|
||||
loadCardResult = DataSourceResult.Success(sampleCardDetail()),
|
||||
listActivitiesResult = DataSourceResult.Success(emptyList()),
|
||||
updateTitleResult = DataSourceResult.GenericError("title failed"),
|
||||
updateDueDateResult = DataSourceResult.GenericError("due failed"),
|
||||
updateDescriptionResult = DataSourceResult.GenericError("desc failed"),
|
||||
)
|
||||
val viewModel = loadedViewModel(this, repository)
|
||||
|
||||
@@ -358,13 +358,13 @@ class CardDetailViewModelTest {
|
||||
}
|
||||
|
||||
private class FakeCardDetailDataSource(
|
||||
var loadCardResult: CardDetailRepository.Result<CardDetail> = CardDetailRepository.Result.Success(sampleCardDetail()),
|
||||
var listActivitiesResult: CardDetailRepository.Result<List<CardActivity>> = CardDetailRepository.Result.Success(emptyList()),
|
||||
var listActivitiesResults: ArrayDeque<CardDetailRepository.Result<List<CardActivity>>> = ArrayDeque(),
|
||||
var updateTitleResult: CardDetailRepository.Result<Unit> = CardDetailRepository.Result.Success(Unit),
|
||||
var updateDescriptionResult: CardDetailRepository.Result<Unit> = CardDetailRepository.Result.Success(Unit),
|
||||
var updateDueDateResult: CardDetailRepository.Result<Unit> = CardDetailRepository.Result.Success(Unit),
|
||||
var addCommentResult: CardDetailRepository.Result<Unit> = CardDetailRepository.Result.Success(Unit),
|
||||
var loadCardResult: DataSourceResult<CardDetail> = DataSourceResult.Success(sampleCardDetail()),
|
||||
var listActivitiesResult: DataSourceResult<List<CardActivity>> = DataSourceResult.Success(emptyList()),
|
||||
var listActivitiesResults: ArrayDeque<DataSourceResult<List<CardActivity>>> = ArrayDeque(),
|
||||
var updateTitleResult: DataSourceResult<Unit> = DataSourceResult.Success(Unit),
|
||||
var updateDescriptionResult: DataSourceResult<Unit> = DataSourceResult.Success(Unit),
|
||||
var updateDueDateResult: DataSourceResult<Unit> = DataSourceResult.Success(Unit),
|
||||
var addCommentResult: DataSourceResult<Unit> = DataSourceResult.Success(Unit),
|
||||
var updateDescriptionGate: CompletableDeferred<Unit>? = null,
|
||||
var updateDescriptionGates: ArrayDeque<CompletableDeferred<Unit>> = ArrayDeque(),
|
||||
) : CardDetailDataSource {
|
||||
@@ -380,18 +380,18 @@ class CardDetailViewModelTest {
|
||||
val updateDueDatePayloads: MutableList<LocalDate?> = mutableListOf()
|
||||
val addCommentPayloads: MutableList<String> = mutableListOf()
|
||||
|
||||
override suspend fun loadCard(cardId: String): CardDetailRepository.Result<CardDetail> {
|
||||
override suspend fun loadCard(cardId: String): DataSourceResult<CardDetail> {
|
||||
loadCalls += 1
|
||||
return loadCardResult
|
||||
}
|
||||
|
||||
override suspend fun updateTitle(cardId: String, title: String): CardDetailRepository.Result<Unit> {
|
||||
override suspend fun updateTitle(cardId: String, title: String): DataSourceResult<Unit> {
|
||||
updateTitleCalls += 1
|
||||
updateTitlePayloads += title
|
||||
return updateTitleResult
|
||||
}
|
||||
|
||||
override suspend fun updateDescription(cardId: String, description: String): CardDetailRepository.Result<Unit> {
|
||||
override suspend fun updateDescription(cardId: String, description: String): DataSourceResult<Unit> {
|
||||
updateDescriptionCalls += 1
|
||||
updateDescriptionPayloads += description
|
||||
if (updateDescriptionGates.isNotEmpty()) {
|
||||
@@ -401,13 +401,13 @@ class CardDetailViewModelTest {
|
||||
return updateDescriptionResult
|
||||
}
|
||||
|
||||
override suspend fun updateDueDate(cardId: String, dueDate: LocalDate?): CardDetailRepository.Result<Unit> {
|
||||
override suspend fun updateDueDate(cardId: String, dueDate: LocalDate?): DataSourceResult<Unit> {
|
||||
updateDueDateCalls += 1
|
||||
updateDueDatePayloads += dueDate
|
||||
return updateDueDateResult
|
||||
}
|
||||
|
||||
override suspend fun listActivities(cardId: String): CardDetailRepository.Result<List<CardActivity>> {
|
||||
override suspend fun listActivities(cardId: String): DataSourceResult<List<CardActivity>> {
|
||||
listActivitiesCalls += 1
|
||||
if (listActivitiesResults.isNotEmpty()) {
|
||||
return listActivitiesResults.removeFirst()
|
||||
@@ -415,7 +415,7 @@ class CardDetailViewModelTest {
|
||||
return listActivitiesResult
|
||||
}
|
||||
|
||||
override suspend fun addComment(cardId: String, comment: String): CardDetailRepository.Result<Unit> {
|
||||
override suspend fun addComment(cardId: String, comment: String): DataSourceResult<Unit> {
|
||||
addCommentCalls += 1
|
||||
addCommentPayloads += comment
|
||||
return addCommentResult
|
||||
@@ -440,9 +440,9 @@ class CardDetailViewModelTest {
|
||||
|
||||
fun sampleActivitiesShuffled(): List<CardActivity> {
|
||||
return listOf(
|
||||
CardActivity(id = "a-new", type = "comment", text = "new", createdAtEpochMillis = 3L),
|
||||
CardActivity(id = "a-mid", type = "comment", text = "mid", createdAtEpochMillis = 2L),
|
||||
CardActivity(id = "a-old", type = "comment", text = "old", createdAtEpochMillis = 1L),
|
||||
CardActivity(id = "a-new", type = "comment", text = "new", createdAtEpochMillis = 3L),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user