From 437a10735249704723954c7a54298185fd727007 Mon Sep 17 00:00:00 2001 From: JackEblan Date: Fri, 20 Sep 2024 15:02:19 +0800 Subject: [PATCH] Simplify questions feature --- .../cache/DefaultInMemoryChoiceDataSource.kt | 34 +-- .../core/cache/InMemoryChoiceDataSource.kt | 2 + .../cache/InMemoryChoiceDataSourceTest.kt | 37 +++ .../core/data/repository/ChoiceRepository.kt | 2 + .../repository/DefaultChoiceRepository.kt | 4 + .../core/domain/UpdateChoiceUseCase.kt | 10 +- .../core/model/QuestionData.kt | 3 - .../repository/FakeChoiceRepository.kt | 32 +-- .../feature/question/QuestionUiState.kt | 8 +- .../feature/question/QuestionViewModel.kt | 17 +- .../dialog/question/QuestionsDialog.kt | 211 ------------------ .../question/screen/CorrectChoicesScreen.kt | 74 ++++-- .../question/screen/OnBoardingScreen.kt | 35 +-- .../feature/question/screen/QuestionScreen.kt | 126 ++++------- .../feature/question/screen/ScoreScreen.kt | 209 ----------------- .../feature/question/QuestionViewModelTest.kt | 26 +-- 16 files changed, 217 insertions(+), 613 deletions(-) delete mode 100644 feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/dialog/question/QuestionsDialog.kt delete mode 100644 feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/ScoreScreen.kt diff --git a/core/cache/src/main/kotlin/com/eblan/socialworkreviewer/core/cache/DefaultInMemoryChoiceDataSource.kt b/core/cache/src/main/kotlin/com/eblan/socialworkreviewer/core/cache/DefaultInMemoryChoiceDataSource.kt index 9e478143..392a1b3d 100644 --- a/core/cache/src/main/kotlin/com/eblan/socialworkreviewer/core/cache/DefaultInMemoryChoiceDataSource.kt +++ b/core/cache/src/main/kotlin/com/eblan/socialworkreviewer/core/cache/DefaultInMemoryChoiceDataSource.kt @@ -19,7 +19,6 @@ package com.eblan.socialworkreviewer.core.cache import com.eblan.socialworkreviewer.core.common.Dispatcher import com.eblan.socialworkreviewer.core.common.SwrDispatchers.Default -import com.eblan.socialworkreviewer.core.model.AnsweredQuestion import com.eblan.socialworkreviewer.core.model.Choice import com.eblan.socialworkreviewer.core.model.Question import com.eblan.socialworkreviewer.core.model.QuestionData @@ -63,7 +62,6 @@ internal class DefaultInMemoryChoiceDataSource @Inject constructor( defaultValue = emptyList(), ), questionsWithSelectedChoices = getQuestionsWithSelectedChoices(), - answeredQuestions = getAnsweredQuestions(), ), ) } @@ -79,11 +77,29 @@ internal class DefaultInMemoryChoiceDataSource @Inject constructor( defaultValue = emptyList(), ), questionsWithSelectedChoices = getQuestionsWithSelectedChoices(), - answeredQuestions = getAnsweredQuestions(), ), ) } + override suspend fun replaceChoice(oldChoice: Choice, newChoice: Choice) { + val oldChoiceIndex = _selectedChoices.indexOf(oldChoice) + + if (oldChoiceIndex != -1) { + _selectedChoices[oldChoiceIndex] = newChoice + + _currentQuestionData.emit( + QuestionData( + question = newChoice.question, + selectedChoices = getQuestionsWithSelectedChoices().getOrDefault( + key = newChoice.question, + defaultValue = emptyList(), + ), + questionsWithSelectedChoices = getQuestionsWithSelectedChoices(), + ), + ) + } + } + override fun clearCache() { _questions.clear() @@ -101,7 +117,6 @@ internal class DefaultInMemoryChoiceDataSource @Inject constructor( defaultValue = emptyList(), ), questionsWithSelectedChoices = getQuestionsWithSelectedChoices(), - answeredQuestions = getAnsweredQuestions(), ), ) } @@ -119,15 +134,4 @@ internal class DefaultInMemoryChoiceDataSource @Inject constructor( _selectedChoices.groupBy({ it.question }, { it.choice }) } } - - private suspend fun getAnsweredQuestions(): List { - return withContext(defaultDispatcher) { - _questions.map { question -> - AnsweredQuestion( - question = question, - isAnswered = question in getQuestionsWithSelectedChoices(), - ) - } - } - } } diff --git a/core/cache/src/main/kotlin/com/eblan/socialworkreviewer/core/cache/InMemoryChoiceDataSource.kt b/core/cache/src/main/kotlin/com/eblan/socialworkreviewer/core/cache/InMemoryChoiceDataSource.kt index 859af200..628c75fb 100644 --- a/core/cache/src/main/kotlin/com/eblan/socialworkreviewer/core/cache/InMemoryChoiceDataSource.kt +++ b/core/cache/src/main/kotlin/com/eblan/socialworkreviewer/core/cache/InMemoryChoiceDataSource.kt @@ -35,6 +35,8 @@ interface InMemoryChoiceDataSource { suspend fun deleteChoice(choice: Choice) + suspend fun replaceChoice(oldChoice: Choice, newChoice: Choice) + fun clearCache() suspend fun addCurrentQuestion(question: Question) diff --git a/core/cache/src/test/kotlin/com/eblan/socialworkreviewer/core/cache/InMemoryChoiceDataSourceTest.kt b/core/cache/src/test/kotlin/com/eblan/socialworkreviewer/core/cache/InMemoryChoiceDataSourceTest.kt index 797adee3..08254262 100644 --- a/core/cache/src/test/kotlin/com/eblan/socialworkreviewer/core/cache/InMemoryChoiceDataSourceTest.kt +++ b/core/cache/src/test/kotlin/com/eblan/socialworkreviewer/core/cache/InMemoryChoiceDataSourceTest.kt @@ -82,6 +82,43 @@ class InMemoryChoiceDataSourceTest { assertNotNull(inMemoryChoiceDataSource.currentQuestionData.replayCache.firstOrNull()) } + @Test + fun replaceChoice() = runTest { + val oldChoice = Choice( + question = Question( + question = "0", + correctChoices = listOf(), + wrongChoices = listOf(), + choices = listOf(""), + ), + choice = "", + ) + + val newChoice = Choice( + question = Question( + question = "1", + correctChoices = listOf(), + wrongChoices = listOf(), + choices = listOf(""), + ), + choice = "", + ) + + inMemoryChoiceDataSource.addChoice(choice = oldChoice) + + inMemoryChoiceDataSource.replaceChoice(oldChoice = oldChoice, newChoice = newChoice) + + assertTrue { + inMemoryChoiceDataSource.selectedChoices.contains(newChoice) + } + + assertTrue { + inMemoryChoiceDataSource.selectedChoices.contains(oldChoice).not() + } + + assertNotNull(inMemoryChoiceDataSource.currentQuestionData.replayCache.firstOrNull()) + } + @Test fun clearCache() = runTest { val questions = List(10) { index -> diff --git a/core/data/src/main/kotlin/com/eblan/socialworkreviewer/core/data/repository/ChoiceRepository.kt b/core/data/src/main/kotlin/com/eblan/socialworkreviewer/core/data/repository/ChoiceRepository.kt index e3fd23ce..89756031 100644 --- a/core/data/src/main/kotlin/com/eblan/socialworkreviewer/core/data/repository/ChoiceRepository.kt +++ b/core/data/src/main/kotlin/com/eblan/socialworkreviewer/core/data/repository/ChoiceRepository.kt @@ -33,6 +33,8 @@ interface ChoiceRepository { suspend fun deleteChoice(choice: Choice) + suspend fun replaceChoice(oldChoice: Choice, newChoice: Choice) + fun clearCache() suspend fun addCurrentQuestion(question: Question) diff --git a/core/data/src/main/kotlin/com/eblan/socialworkreviewer/core/data/repository/DefaultChoiceRepository.kt b/core/data/src/main/kotlin/com/eblan/socialworkreviewer/core/data/repository/DefaultChoiceRepository.kt index e47fb3b8..2878dde3 100644 --- a/core/data/src/main/kotlin/com/eblan/socialworkreviewer/core/data/repository/DefaultChoiceRepository.kt +++ b/core/data/src/main/kotlin/com/eblan/socialworkreviewer/core/data/repository/DefaultChoiceRepository.kt @@ -45,6 +45,10 @@ internal class DefaultChoiceRepository @Inject constructor( inMemoryChoiceDataSource.deleteChoice(choice) } + override suspend fun replaceChoice(oldChoice: Choice, newChoice: Choice) { + inMemoryChoiceDataSource.replaceChoice(oldChoice = oldChoice, newChoice = newChoice) + } + override fun clearCache() { inMemoryChoiceDataSource.clearCache() } diff --git a/core/domain/src/main/kotlin/com/eblan/socialworkreviewer/core/domain/UpdateChoiceUseCase.kt b/core/domain/src/main/kotlin/com/eblan/socialworkreviewer/core/domain/UpdateChoiceUseCase.kt index a7c35e53..2810db36 100644 --- a/core/domain/src/main/kotlin/com/eblan/socialworkreviewer/core/domain/UpdateChoiceUseCase.kt +++ b/core/domain/src/main/kotlin/com/eblan/socialworkreviewer/core/domain/UpdateChoiceUseCase.kt @@ -41,13 +41,13 @@ class UpdateChoiceUseCase @Inject constructor( } private suspend fun singleChoice(choice: Choice) { - choiceRepository.selectedChoices.find { previousSelectedChoice -> - choice.question == previousSelectedChoice.question && choice != previousSelectedChoice - }?.let { previousSelectedChoice -> - choiceRepository.deleteChoice(previousSelectedChoice) + val oldChoice = choiceRepository.selectedChoices.find { oldChoice -> + choice.question == oldChoice.question && choice != oldChoice } - if (choice !in choiceRepository.selectedChoices) { + if (oldChoice != null) { + choiceRepository.replaceChoice(oldChoice = oldChoice, newChoice = choice) + } else { choiceRepository.addChoice(choice) } } diff --git a/core/model/src/main/kotlin/com/eblan/socialworkreviewer/core/model/QuestionData.kt b/core/model/src/main/kotlin/com/eblan/socialworkreviewer/core/model/QuestionData.kt index feb4bcfe..895c23ef 100644 --- a/core/model/src/main/kotlin/com/eblan/socialworkreviewer/core/model/QuestionData.kt +++ b/core/model/src/main/kotlin/com/eblan/socialworkreviewer/core/model/QuestionData.kt @@ -21,7 +21,4 @@ data class QuestionData( val question: Question, val selectedChoices: List, val questionsWithSelectedChoices: Map>, - val answeredQuestions: List, ) - -data class AnsweredQuestion(val question: Question, val isAnswered: Boolean) diff --git a/core/testing/src/main/kotlin/com/eblan/socialworkreviewer/core/testing/repository/FakeChoiceRepository.kt b/core/testing/src/main/kotlin/com/eblan/socialworkreviewer/core/testing/repository/FakeChoiceRepository.kt index a977e032..ff4749aa 100644 --- a/core/testing/src/main/kotlin/com/eblan/socialworkreviewer/core/testing/repository/FakeChoiceRepository.kt +++ b/core/testing/src/main/kotlin/com/eblan/socialworkreviewer/core/testing/repository/FakeChoiceRepository.kt @@ -18,7 +18,6 @@ package com.eblan.socialworkreviewer.core.testing.repository import com.eblan.socialworkreviewer.core.data.repository.ChoiceRepository -import com.eblan.socialworkreviewer.core.model.AnsweredQuestion import com.eblan.socialworkreviewer.core.model.Choice import com.eblan.socialworkreviewer.core.model.Question import com.eblan.socialworkreviewer.core.model.QuestionData @@ -60,7 +59,6 @@ class FakeChoiceRepository : ChoiceRepository { defaultValue = emptyList(), ), questionsWithSelectedChoices = getQuestionsWithSelectedChoices(), - answeredQuestions = getAnsweredQuestions(), ), ) } @@ -76,11 +74,29 @@ class FakeChoiceRepository : ChoiceRepository { defaultValue = emptyList(), ), questionsWithSelectedChoices = getQuestionsWithSelectedChoices(), - answeredQuestions = getAnsweredQuestions(), ), ) } + override suspend fun replaceChoice(oldChoice: Choice, newChoice: Choice) { + val oldChoiceIndex = _selectedChoices.indexOf(oldChoice) + + if (oldChoiceIndex != -1) { + _selectedChoices[oldChoiceIndex] = newChoice + + _currentQuestionData.emit( + QuestionData( + question = newChoice.question, + selectedChoices = getQuestionsWithSelectedChoices().getOrDefault( + key = newChoice.question, + defaultValue = emptyList(), + ), + questionsWithSelectedChoices = getQuestionsWithSelectedChoices(), + ), + ) + } + } + override fun clearCache() { _selectedChoices.clear() @@ -96,7 +112,6 @@ class FakeChoiceRepository : ChoiceRepository { defaultValue = emptyList(), ), questionsWithSelectedChoices = getQuestionsWithSelectedChoices(), - answeredQuestions = getAnsweredQuestions(), ), ) } @@ -110,13 +125,4 @@ class FakeChoiceRepository : ChoiceRepository { private fun getQuestionsWithSelectedChoices(): Map> { return _selectedChoices.groupBy({ it.question }, { it.choice }) } - - private fun getAnsweredQuestions(): List { - return _questions.map { question -> - AnsweredQuestion( - question = question, - isAnswered = question in getQuestionsWithSelectedChoices(), - ) - } - } } diff --git a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionUiState.kt b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionUiState.kt index 478a4daf..c3e7e401 100644 --- a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionUiState.kt +++ b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionUiState.kt @@ -29,16 +29,12 @@ sealed interface QuestionUiState { data class CorrectChoices( val questions: List, + val score: Int, + val lastCountDownTime: String?, ) : QuestionUiState data class OnBoarding(val category: Category? = null, val statistics: Statistics) : QuestionUiState data class QuickQuestions(val questions: List) : QuestionUiState - - data class Score( - val score: Int, - val questions: List, - val lastCountDownTime: String?, - ) : QuestionUiState } diff --git a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionViewModel.kt b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionViewModel.kt index 882e9765..ecdf8870 100644 --- a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionViewModel.kt +++ b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionViewModel.kt @@ -80,7 +80,6 @@ class QuestionViewModel @Inject constructor( ), selectedChoices = emptyList(), questionsWithSelectedChoices = emptyMap(), - answeredQuestions = emptyList(), ), ) @@ -145,24 +144,14 @@ class QuestionViewModel @Inject constructor( } } - fun showCorrectChoices(questions: List) { - viewModelScope.launch { - _questionUiState.update { - QuestionUiState.CorrectChoices( - questions = questions, - ) - } - } - } - - fun showScore(questionSettingIndex: Int, questions: List) { + fun showCorrectChoices(questionSettingIndex: Int, questions: List) { viewModelScope.launch { val score = choiceRepository.getScore() _questionUiState.update { - QuestionUiState.Score( - score = score, + QuestionUiState.CorrectChoices( questions = questions, + score = score, lastCountDownTime = countDownTime.value?.minutes, ) } diff --git a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/dialog/question/QuestionsDialog.kt b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/dialog/question/QuestionsDialog.kt deleted file mode 100644 index 9d018378..00000000 --- a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/dialog/question/QuestionsDialog.kt +++ /dev/null @@ -1,211 +0,0 @@ -/* - * - * Copyright 2023 Einstein Blanco - * - * Licensed under the GNU General Public License v3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.gnu.org/licenses/gpl-3.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.eblan.socialworkreviewer.feature.question.dialog.question - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.AlertDialogDefaults -import androidx.compose.material3.Card -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import com.eblan.socialworkreviewer.core.designsystem.icon.Swr -import com.eblan.socialworkreviewer.core.model.AnsweredQuestion - -@Composable -internal fun QuestionsDialog( - modifier: Modifier = Modifier, - minutes: String?, - questionsSize: Int, - answeredQuestions: List, - onQuestionClick: (Int) -> Unit, - onOkayClick: () -> Unit, - contentDescription: String, -) { - QuestionsDialogContainer( - modifier = modifier - .padding(16.dp) - .semantics { this.contentDescription = contentDescription }, - onDismissRequest = {}, - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(10.dp), - ) { - QuestionsDialogTitle() - - QuestionsDialogContent( - minutes = minutes, - questionsSize = questionsSize, - answeredQuestions = answeredQuestions, - onQuestionClick = onQuestionClick, - ) - - QuestionsDialogButtons( - onOkayClick = onOkayClick, - ) - } - } -} - -@Composable -private fun QuestionsDialogContainer( - modifier: Modifier = Modifier, - shape: Shape = AlertDialogDefaults.shape, - containerColor: Color = AlertDialogDefaults.containerColor, - tonalElevation: Dp = AlertDialogDefaults.TonalElevation, - onDismissRequest: () -> Unit, - content: @Composable () -> Unit, -) { - Dialog(onDismissRequest = onDismissRequest) { - Surface( - modifier = modifier, - shape = shape, - color = containerColor, - tonalElevation = tonalElevation, - content = content, - ) - } -} - -@Composable -private fun QuestionsDialogTitle(modifier: Modifier = Modifier) { - Spacer(modifier = Modifier.height(10.dp)) - - Text( - modifier = modifier, - text = "Questions", - style = MaterialTheme.typography.titleLarge, - ) -} - -@Composable -private fun QuestionsDialogContent( - minutes: String?, - questionsSize: Int, - answeredQuestions: List, - onQuestionClick: (Int) -> Unit, -) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Spacer(modifier = Modifier.height(20.dp)) - - Text( - modifier = Modifier, - text = minutes ?: "Time's up!", - style = MaterialTheme.typography.headlineLarge, - ) - - Spacer(modifier = Modifier.height(20.dp)) - - Text( - modifier = Modifier, - textAlign = TextAlign.Center, - text = "Answered ${answeredQuestions.count { it.isAnswered }}/$questionsSize questions", - style = MaterialTheme.typography.bodySmall, - ) - - Spacer(modifier = Modifier.height(20.dp)) - - LazyRow(modifier = Modifier.fillMaxWidth()) { - itemsIndexed(answeredQuestions) { index, answeredQuestion -> - QuestionItem( - index = index, - answeredQuestion = answeredQuestion, - onQuestionClick = onQuestionClick, - ) - } - } - } -} - -@Composable -private fun QuestionItem( - modifier: Modifier = Modifier, - index: Int, - answeredQuestion: AnsweredQuestion, - onQuestionClick: (Int) -> Unit, -) { - Card( - modifier = modifier - .size(100.dp) - .padding(5.dp), - onClick = { onQuestionClick(index) }, - ) { - Column( - modifier = Modifier - .fillMaxSize() - .padding(5.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text(text = "${index + 1}") - - Spacer(modifier = Modifier.height(10.dp)) - - Icon( - imageVector = if (answeredQuestion.isAnswered) Swr.Check else Swr.Close, - contentDescription = "", - ) - } - } -} - -@Composable -private fun QuestionsDialogButtons( - modifier: Modifier = Modifier, - onOkayClick: () -> Unit, -) { - Spacer(modifier = Modifier.height(10.dp)) - - Row( - modifier = modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.End, - ) { - TextButton( - onClick = onOkayClick, - modifier = Modifier.padding(5.dp), - ) { - Text(text = "Okay") - } - } -} diff --git a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/CorrectChoicesScreen.kt b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/CorrectChoicesScreen.kt index c03f7a01..be8101ee 100644 --- a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/CorrectChoicesScreen.kt +++ b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/CorrectChoicesScreen.kt @@ -21,20 +21,24 @@ import androidx.activity.compose.BackHandler import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedCard import androidx.compose.material3.ProgressIndicatorDefaults @@ -48,17 +52,16 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.eblan.socialworkreviewer.core.designsystem.component.SwrLargeTopAppBar import com.eblan.socialworkreviewer.core.designsystem.component.SwrLinearProgressIndicator import com.eblan.socialworkreviewer.core.designsystem.icon.Swr -import com.eblan.socialworkreviewer.core.designsystem.theme.LocalGradientColors import com.eblan.socialworkreviewer.core.model.Question import com.eblan.socialworkreviewer.core.model.QuestionData import com.eblan.socialworkreviewer.feature.question.dialog.quit.QuitAlertDialog @@ -68,6 +71,8 @@ import com.eblan.socialworkreviewer.feature.question.dialog.quit.QuitAlertDialog internal fun CorrectChoicesScreen( modifier: Modifier = Modifier, questions: List, + score: Int, + lastCountDownTime: String?, currentQuestionData: QuestionData, onAddCurrentQuestion: (Question) -> Unit, onQuitQuestions: () -> Unit, @@ -100,30 +105,19 @@ internal fun CorrectChoicesScreen( } } - Scaffold( - topBar = { - SwrLargeTopAppBar( - title = { - Text( - text = "Correct Choices", - style = MaterialTheme.typography.headlineSmall.copy( - brush = Brush.linearGradient( - colors = LocalGradientColors.current.topBarTitleColorsDefault, - ), - ), - ) - }, - modifier = modifier.testTag("correctChoices:largeTopAppBar"), - scrollBehavior = scrollBehavior, - ) - }, - ) { paddingValues -> + Scaffold { paddingValues -> Column( modifier = modifier .fillMaxSize() .consumeWindowInsets(paddingValues) .padding(paddingValues), ) { + CorrectChoicesTopBar( + wrongText = "${questions.size - score}", + correctText = "$score", + lastCountDownTime = lastCountDownTime, + ) + SwrLinearProgressIndicator( progress = { animatedProgress @@ -162,6 +156,44 @@ internal fun CorrectChoicesScreen( } } +@Composable +private fun CorrectChoicesTopBar( + modifier: Modifier = Modifier, + wrongText: String, + correctText: String, + lastCountDownTime: String?, +) { + Row( + modifier = modifier + .fillMaxWidth() + .padding(10.dp), + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically, + ) { + Icon(imageVector = Swr.Close, contentDescription = "Wrong") + + Spacer(modifier = Modifier.width(5.dp)) + + Text(text = wrongText, fontWeight = FontWeight.Bold) + + Spacer(modifier = Modifier.width(20.dp)) + + Icon(imageVector = Swr.Check, contentDescription = "Correct") + + Spacer(modifier = Modifier.width(5.dp)) + + Text(text = correctText, fontWeight = FontWeight.Bold) + + Spacer(modifier = Modifier.width(20.dp)) + + Icon(imageVector = Swr.AccessTime, contentDescription = "Minutes") + + Spacer(modifier = Modifier.width(5.dp)) + + Text(text = lastCountDownTime ?: "Time's Up!", fontWeight = FontWeight.Bold) + } +} + @Composable private fun CorrectChoicesPage( modifier: Modifier = Modifier, diff --git a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/OnBoardingScreen.kt b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/OnBoardingScreen.kt index 16694f0b..66e7f61f 100644 --- a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/OnBoardingScreen.kt +++ b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/OnBoardingScreen.kt @@ -33,6 +33,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.material3.CircularProgressIndicator @@ -112,12 +113,15 @@ internal fun SuccessOnBoardingScreen( columns = GridCells.Adaptive(300.dp), contentPadding = paddingValues, ) { - item { + item( + span = { + GridItemSpan(maxLineSpan) + }, + ) { OutlinedCard( modifier = Modifier.padding(10.dp), ) { Statistics( - modifier = modifier, average = statistics.totalAverage, totalScore = statistics.totalScore, totalNumberOfQuestions = statistics.totalNumberOfQuestions, @@ -200,15 +204,16 @@ private fun Statistics( totalScore: Int, totalNumberOfQuestions: Int, ) { - Column( + Row( modifier = modifier .fillMaxWidth() .padding(15.dp), - horizontalAlignment = Alignment.CenterHorizontally, + horizontalArrangement = Arrangement.SpaceEvenly, + verticalAlignment = Alignment.CenterVertically, ) { AverageCircularProgressIndicator( progress = { (average / 100).toFloat() }, - modifier = Modifier.size(60.dp), + modifier = Modifier.size(100.dp), strokeCap = StrokeCap.Round, trackColor = ProgressIndicatorDefaults.linearTrackColor, ) { @@ -219,21 +224,23 @@ private fun Statistics( ) } - Spacer(modifier = Modifier.height(20.dp)) - - Text(text = "Total Score", style = MaterialTheme.typography.bodySmall) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text(text = "Score", style = MaterialTheme.typography.bodySmall) - Spacer(modifier = Modifier.height(10.dp)) + Spacer(modifier = Modifier.height(10.dp)) - Text(fontWeight = FontWeight.Bold, text = "$totalScore") + Text(fontWeight = FontWeight.Bold, text = "$totalScore") - Spacer(modifier = Modifier.height(10.dp)) + Spacer(modifier = Modifier.height(10.dp)) - Text(text = "Total Number Of Questions", style = MaterialTheme.typography.bodySmall) + Text(text = "Questions", style = MaterialTheme.typography.bodySmall) - Spacer(modifier = Modifier.height(10.dp)) + Spacer(modifier = Modifier.height(10.dp)) - Text(fontWeight = FontWeight.Bold, text = "$totalNumberOfQuestions") + Text(fontWeight = FontWeight.Bold, text = "$totalNumberOfQuestions") + } } } diff --git a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/QuestionScreen.kt b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/QuestionScreen.kt index 3717ce04..5b09c20f 100644 --- a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/QuestionScreen.kt +++ b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/QuestionScreen.kt @@ -37,6 +37,7 @@ import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize @@ -44,12 +45,12 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.CardDefaults -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -59,7 +60,6 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBarDefaults.enterAlwaysScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -77,19 +77,17 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.fromHtml import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.eblan.socialworkreviewer.core.designsystem.component.SwrLargeTopAppBar import com.eblan.socialworkreviewer.core.designsystem.component.SwrLinearProgressIndicator import com.eblan.socialworkreviewer.core.designsystem.icon.Swr -import com.eblan.socialworkreviewer.core.designsystem.theme.LocalGradientColors import com.eblan.socialworkreviewer.core.model.Choice import com.eblan.socialworkreviewer.core.model.CountDownTime import com.eblan.socialworkreviewer.core.model.Question @@ -97,7 +95,6 @@ import com.eblan.socialworkreviewer.core.model.QuestionData import com.eblan.socialworkreviewer.core.model.QuestionSetting import com.eblan.socialworkreviewer.feature.question.QuestionUiState import com.eblan.socialworkreviewer.feature.question.QuestionViewModel -import com.eblan.socialworkreviewer.feature.question.dialog.question.QuestionsDialog import com.eblan.socialworkreviewer.feature.question.dialog.quit.QuitAlertDialog import kotlinx.coroutines.launch @@ -124,7 +121,6 @@ internal fun QuestionRoute( onAddCurrentQuestion = viewModel::addCurrentQuestion, onUpdateChoice = viewModel::updateChoice, onShowCorrectChoices = viewModel::showCorrectChoices, - onShowScore = viewModel::showScore, onStartQuestions = viewModel::startQuestions, onStartQuickQuestions = viewModel::startQuickQuestions, onQuitQuestions = { @@ -145,8 +141,7 @@ internal fun QuestionScreen( countDownTime: CountDownTime?, onAddCurrentQuestion: (Question) -> Unit, onUpdateChoice: (Choice) -> Unit, - onShowCorrectChoices: (questions: List) -> Unit, - onShowScore: (questionSettingIndex: Int, questions: List) -> Unit, + onShowCorrectChoices: (questionSettingIndex: Int, questions: List) -> Unit, onStartQuestions: (Int, QuestionSetting) -> Unit, onStartQuickQuestions: () -> Unit, onQuitQuestions: () -> Unit, @@ -157,7 +152,7 @@ internal fun QuestionScreen( label = "", transitionSpec = { when (targetState) { - is QuestionUiState.Score, is QuestionUiState.CorrectChoices, is QuestionUiState.Questions, is QuestionUiState.QuickQuestions -> { + is QuestionUiState.CorrectChoices, is QuestionUiState.Questions, is QuestionUiState.QuickQuestions -> { (slideInVertically() + fadeIn()).togetherWith( slideOutVertically() + fadeOut(), ) @@ -182,21 +177,23 @@ internal fun QuestionScreen( countDownTime = countDownTime, onAddCurrentQuestion = onAddCurrentQuestion, onUpdateChoice = onUpdateChoice, - onShowScore = onShowScore, + onShowCorrectChoices = onShowCorrectChoices, onQuitQuestions = onQuitQuestions, ) } else { - EmptyState(text = "No Question found!") + EmptyState(text = "No Questions found!") } } - QuestionUiState.Loading -> { + QuestionUiState.Loading, null -> { LoadingScreen() } is QuestionUiState.CorrectChoices -> { CorrectChoicesScreen( questions = state.questions, + score = state.score, + lastCountDownTime = state.lastCountDownTime, currentQuestionData = currentQuestionData, onAddCurrentQuestion = onAddCurrentQuestion, onQuitQuestions = onQuitQuestions, @@ -228,25 +225,10 @@ internal fun QuestionScreen( ) } } - - is QuestionUiState.Score -> { - ScoreScreen( - questions = state.questions, - score = state.score, - minutes = state.lastCountDownTime, - onShowCorrectChoices = onShowCorrectChoices, - onQuitQuestions = onQuitQuestions, - ) - } - - null -> { - LoadingScreen() - } } } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun Questions( modifier: Modifier = Modifier, @@ -257,7 +239,7 @@ private fun Questions( countDownTime: CountDownTime?, onAddCurrentQuestion: (Question) -> Unit, onUpdateChoice: (Choice) -> Unit, - onShowScore: (questionSettingIndex: Int, questions: List) -> Unit, + onShowCorrectChoices: (questionSettingIndex: Int, questions: List) -> Unit, onQuitQuestions: () -> Unit, ) { val pagerState = rememberPagerState( @@ -266,10 +248,6 @@ private fun Questions( }, ) - val scope = rememberCoroutineScope() - - val scrollBehavior = enterAlwaysScrollBehavior() - val animatedProgress by animateFloatAsState( targetValue = (pagerState.currentPage + 1f) / questions.size, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, @@ -280,17 +258,13 @@ private fun Questions( mutableStateOf(false) } - var showQuestionsDialog by rememberSaveable { - mutableStateOf(false) - } - BackHandler(enabled = true) { showQuitAlertDialog = true } LaunchedEffect(key1 = countDownTime) { if (countDownTime != null && countDownTime.isFinished) { - onShowScore(questionSettingIndex, questions) + onShowCorrectChoices(questionSettingIndex, questions) } } @@ -301,38 +275,18 @@ private fun Questions( } Scaffold( - topBar = { - SwrLargeTopAppBar( - title = { - Text( - text = "Questions", - style = MaterialTheme.typography.headlineSmall.copy( - brush = Brush.linearGradient( - colors = LocalGradientColors.current.topBarTitleColorsDefault, - ), - ), - ) - }, - modifier = modifier.testTag("question:largeTopAppBar"), - scrollBehavior = scrollBehavior, - ) - }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, floatingActionButton = { AnimatedVisibility( - visible = scrollBehavior.state.collapsedFraction == 0.0f, + visible = currentQuestionData.questionsWithSelectedChoices.size == questions.size, enter = fadeIn() + scaleIn(), exit = fadeOut() + scaleOut(), ) { FloatingActionButton( onClick = { - if (currentQuestionData.questionsWithSelectedChoices.size < questions.size) { - showQuestionsDialog = true - } else { - onShowScore(questionSettingIndex, questions) - } + onShowCorrectChoices(questionSettingIndex, questions) }, ) { Icon( @@ -349,6 +303,11 @@ private fun Questions( .consumeWindowInsets(paddingValues) .padding(paddingValues), ) { + QuestionScreenTopBar( + questionsWithSelectedChoicesSize = currentQuestionData.questionsWithSelectedChoices.size, + countDownTime = countDownTime, + ) + SwrLinearProgressIndicator( progress = { animatedProgress @@ -365,7 +324,6 @@ private fun Questions( state = pagerState, ) { page -> QuestionPage( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), page = page, questions = questions, currentQuestionData = currentQuestionData, @@ -389,24 +347,36 @@ private fun Questions( icon = Swr.Question, ) } +} - if (showQuestionsDialog) { - QuestionsDialog( - modifier = modifier, - minutes = countDownTime?.minutes, - questionsSize = questions.size, - answeredQuestions = currentQuestionData.answeredQuestions, - onQuestionClick = { index -> - scope.launch { - showQuestionsDialog = false - pagerState.animateScrollToPage(index) - } - }, - onOkayClick = { - showQuestionsDialog = false - }, - contentDescription = "", - ) +@Composable +private fun QuestionScreenTopBar( + modifier: Modifier = Modifier, + questionsWithSelectedChoicesSize: Int, + countDownTime: CountDownTime?, +) { + Row( + modifier = modifier + .fillMaxWidth() + .padding(10.dp), + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically, + ) { + Icon(imageVector = Swr.Check, contentDescription = "Questions With Selected Choices") + + Spacer(modifier = Modifier.width(5.dp)) + + Text(text = "$questionsWithSelectedChoicesSize", fontWeight = FontWeight.Bold) + + if (countDownTime != null && countDownTime.isFinished.not()) { + Spacer(modifier = Modifier.width(20.dp)) + + Icon(imageVector = Swr.AccessTime, contentDescription = "Minutes") + + Spacer(modifier = Modifier.width(5.dp)) + + Text(text = countDownTime.minutes, fontWeight = FontWeight.Bold) + } } } diff --git a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/ScoreScreen.kt b/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/ScoreScreen.kt deleted file mode 100644 index e07b090e..00000000 --- a/feature/question/src/main/kotlin/com/eblan/socialworkreviewer/feature/question/screen/ScoreScreen.kt +++ /dev/null @@ -1,209 +0,0 @@ -/* - * - * Copyright 2023 Einstein Blanco - * - * Licensed under the GNU General Public License v3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.gnu.org/licenses/gpl-3.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.eblan.socialworkreviewer.feature.question.screen - -import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ProgressIndicatorDefaults -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.unit.dp -import androidx.window.core.layout.WindowHeightSizeClass -import androidx.window.core.layout.WindowSizeClass -import com.eblan.socialworkreviewer.core.designsystem.icon.Swr -import com.eblan.socialworkreviewer.core.designsystem.theme.LocalGradientColors -import com.eblan.socialworkreviewer.core.model.Question -import com.eblan.socialworkreviewer.feature.question.dialog.quit.QuitAlertDialog -import kotlin.math.roundToInt - -@Composable -internal fun ScoreScreen( - modifier: Modifier = Modifier, - windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass, - score: Int, - questions: List, - minutes: String?, - onShowCorrectChoices: (questions: List) -> Unit, - onQuitQuestions: () -> Unit, -) { - var showQuitAlertDialog by rememberSaveable { - mutableStateOf(false) - } - - BackHandler(enabled = true) { - showQuitAlertDialog = true - } - - val average = (score.toDouble() / questions.size.toDouble()) * 100.0 - - Scaffold( - floatingActionButton = { - FloatingActionButton( - onClick = { - onShowCorrectChoices(questions) - }, - ) { - Icon( - imageVector = Swr.Eye, - contentDescription = "", - ) - } - }, - ) { paddingValues -> - Box( - modifier = modifier - .fillMaxSize() - .consumeWindowInsets(paddingValues) - .padding(paddingValues), - ) { - if (windowSizeClass.windowHeightSizeClass != WindowHeightSizeClass.COMPACT) { - Column( - modifier = modifier - .fillMaxSize() - .padding(10.dp), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Statistics( - average = average, - score = score, - questions = questions, - minutes = minutes, - ) - } - } else { - Row( - modifier = modifier - .fillMaxSize() - .padding(10.dp), - horizontalArrangement = Arrangement.SpaceAround, - verticalAlignment = Alignment.CenterVertically, - ) { - Statistics( - average = average, - score = score, - questions = questions, - minutes = minutes, - ) - } - } - } - } - - if (showQuitAlertDialog) { - QuitAlertDialog( - onDismissRequest = { - showQuitAlertDialog = false - }, - onConfirmation = { - showQuitAlertDialog = false - onQuitQuestions() - }, - dialogTitle = "Quit Questions", - dialogText = "Are you sure you want to quit?", - icon = Swr.Question, - ) - } -} - -@Composable -private fun Statistics( - average: Double, - score: Int, - questions: List, - minutes: String?, -) { - AverageCircularProgressIndicator( - progress = { (average / 100).toFloat() }, - modifier = Modifier.size(150.dp), - strokeWidth = 8.dp, - strokeCap = StrokeCap.Round, - trackColor = ProgressIndicatorDefaults.linearTrackColor, - ) { - Text( - modifier = Modifier.padding(5.dp), - text = "${average.roundToInt()}%", - style = MaterialTheme.typography.titleLarge.copy( - brush = Brush.linearGradient( - colors = LocalGradientColors.current.topBarTitleColorsDefault, - ), - ), - ) - } - - Spacer(modifier = Modifier.height(20.dp)) - - StatisticsText(title = "Correct", subtitle = "$score") - - Spacer(modifier = Modifier.height(20.dp)) - - StatisticsText(title = "Wrong", subtitle = "${questions.size - score}") - - Spacer(modifier = Modifier.height(20.dp)) - - StatisticsText( - title = "Time", - subtitle = if (minutes.isNullOrBlank()) "Time's up!" else minutes, - ) -} - -@Composable -private fun StatisticsText(modifier: Modifier = Modifier, title: String, subtitle: String) { - Column( - modifier = modifier, - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text( - text = title, - style = MaterialTheme.typography.bodyLarge, - ) - - Spacer(modifier = Modifier.height(10.dp)) - - Text( - text = subtitle, - style = MaterialTheme.typography.headlineLarge.copy( - brush = Brush.linearGradient( - colors = LocalGradientColors.current.topBarTitleColorsDefault, - ), - ), - ) - } -} diff --git a/feature/question/src/test/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionViewModelTest.kt b/feature/question/src/test/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionViewModelTest.kt index dd68129e..4bde111d 100644 --- a/feature/question/src/test/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionViewModelTest.kt +++ b/feature/question/src/test/kotlin/com/eblan/socialworkreviewer/feature/question/QuestionViewModelTest.kt @@ -121,7 +121,6 @@ class QuestionViewModelTest { ), selectedChoices = emptyList(), questionsWithSelectedChoices = emptyMap(), - answeredQuestions = emptyList(), ), actual = viewModel.currentQuestionData.value, ) @@ -219,27 +218,6 @@ class QuestionViewModelTest { viewModel.questionUiState.collect() } - val questions = List(10) { _ -> - Question( - question = "", - correctChoices = listOf(), - wrongChoices = listOf(), - choices = listOf(), - ) - } - choiceRepository.addQuestions(questions) - - viewModel.showCorrectChoices(questions = questions) - - assertIs(viewModel.questionUiState.value) - } - - @Test - fun showScore() = runTest { - backgroundScope.launch(UnconfinedTestDispatcher()) { - viewModel.questionUiState.collect() - } - val questions = List(10) { _ -> Question( question = "", @@ -262,9 +240,9 @@ class QuestionViewModelTest { averageRepository.setAverages(value = averages) - viewModel.showScore(questionSettingIndex = 0, questions = questions) + viewModel.showCorrectChoices(questionSettingIndex = 0, questions = questions) - assertIs(viewModel.questionUiState.value) + assertIs(viewModel.questionUiState.value) } @Test