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
@@ -0,0 +1,9 @@
package ru.yeahub.interview_trainer.impl.createQuiz.domain

class GetSpecializationsListUseCaseImpl(
private val repository: CreateQuizRepositoryApi,
) : GetSpecializationsUseCase {
override suspend fun invoke(
request: SpecializationsRequest,
): DomainSpecializationListResponse = repository.getSpecializationsList(request = request)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ru.yeahub.interview_trainer.impl.createQuiz.domain

interface GetSpecializationsUseCase {
suspend operator fun invoke(request: SpecializationsRequest): DomainSpecializationListResponse
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package ru.yeahub.interview_trainer.impl.createQuiz.presentation

import ru.yeahub.interview_trainer.impl.createQuiz.domain.DomainSpecialization

object CreateQuizScreenMapper {

fun getScreenState(
specializations: List<CreateQuizState.Loaded.VoSpecialization>,
specializations: List<DomainSpecialization>,
selectedSpecializationId: Long,
questionsCount: Int,
): CreateQuizState = CreateQuizState.Loaded(
specializations = specializations,
specializations = specializations.map { domainSpec ->
CreateQuizState.Loaded.VoSpecialization(
id = domainSpec.id,
title = domainSpec.title
)
},
selectedSpecializationId = selectedSpecializationId,
questionsCount = questionsCount
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import ru.yeahub.core_utils.BaseViewModel
import ru.yeahub.interview_trainer.impl.createQuiz.ui.specializations
import ru.yeahub.interview_trainer.impl.createQuiz.domain.GetSpecializationsUseCase
import ru.yeahub.interview_trainer.impl.createQuiz.domain.SpecializationsRequest

open class CreateQuizViewModel(
private val getSpecializationsListUseCase: GetSpecializationsUseCase,
private val screenMapper: CreateQuizScreenMapper,
) : BaseViewModel() {

Expand All @@ -25,8 +27,10 @@ open class CreateQuizViewModel(

val screenState = userInputState
.map { userInput ->
val request = SpecializationsRequest(page = 1, limit = 99)

screenMapper.getScreenState(
specializations = specializations,
specializations = getSpecializationsListUseCase(request).data,
selectedSpecializationId = userInput.selectedSpecializationId,
questionsCount = userInput.questionsCount
)
Expand Down Expand Up @@ -69,32 +73,26 @@ open class CreateQuizViewModel(
}

private fun incrementQuestionsCount(questionsCount: Int) {
viewModelScopeSafe.launch {
userInputState.update { currentInputState ->
val incrementedCount = questionsCount + 1
val newCount = incrementedCount.coerceAtMost(MAX_QUESTIONS_COUNT)
userInputState.update { currentInputState ->
val incrementedCount = questionsCount + 1
val newCount = incrementedCount.coerceAtMost(MAX_QUESTIONS_COUNT)

currentInputState.copy(questionsCount = newCount)
}
currentInputState.copy(questionsCount = newCount)
}
}

private fun decrementQuestionsCount(questionsCount: Int) {
viewModelScopeSafe.launch {
userInputState.update { currentInputState ->
val incrementedCount = questionsCount - 1
val newCount = incrementedCount.coerceAtLeast(MIN_QUESTIONS_COUNT)
userInputState.update { currentInputState ->
val incrementedCount = questionsCount - 1
val newCount = incrementedCount.coerceAtLeast(MIN_QUESTIONS_COUNT)

currentInputState.copy(questionsCount = newCount)
}
currentInputState.copy(questionsCount = newCount)
}
}

private fun changeChosenSpecialization(newSpecializationId: Long) {
viewModelScopeSafe.launch {
userInputState.update { currentInputState ->
currentInputState.copy(selectedSpecializationId = newSpecializationId)
}
userInputState.update { currentInputState ->
currentInputState.copy(selectedSpecializationId = newSpecializationId)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import ru.yeahub.core_ui.component.ErrorScreen
import ru.yeahub.core_ui.component.PrimaryButton
import ru.yeahub.core_ui.component.SkillButton
Expand All @@ -47,8 +48,15 @@ import ru.yeahub.core_ui.example.staticPreview.StaticPreview
import ru.yeahub.core_ui.theme.LocalAppTypography
import ru.yeahub.core_ui.theme.colors
import ru.yeahub.core_utils.common.TextOrResource
import ru.yeahub.core_utils.common.observe
import ru.yeahub.interview_trainer.impl.R
import ru.yeahub.interview_trainer.impl.createQuiz.domain.DomainSpecialization
import ru.yeahub.interview_trainer.impl.createQuiz.domain.DomainSpecializationListResponse
import ru.yeahub.interview_trainer.impl.createQuiz.domain.GetSpecializationsUseCase
import ru.yeahub.interview_trainer.impl.createQuiz.domain.SpecializationsRequest
import ru.yeahub.interview_trainer.impl.createQuiz.presentation.CreateQuizCommand
import ru.yeahub.interview_trainer.impl.createQuiz.presentation.CreateQuizEvent
import ru.yeahub.interview_trainer.impl.createQuiz.presentation.CreateQuizResult
import ru.yeahub.interview_trainer.impl.createQuiz.presentation.CreateQuizScreenMapper
import ru.yeahub.interview_trainer.impl.createQuiz.presentation.CreateQuizState
import ru.yeahub.interview_trainer.impl.createQuiz.presentation.CreateQuizViewModel
Expand Down Expand Up @@ -117,6 +125,24 @@ private fun ScreenUI(
}
}

@Composable
fun HandleCommand(
commandFlow: Flow<CreateQuizCommand>,
onResult: (CreateQuizResult) -> Unit,
) {
commandFlow.observe { command ->
when (command) {
is CreateQuizCommand.NavigateBack -> onResult(CreateQuizResult.NavigateBack)
is CreateQuizCommand.NavigateToInterviewQuizScreen -> onResult(
CreateQuizResult.NavigateToInterviewQuizScreen(
specializationId = command.specializationId,
questionCount = command.questionCount
)
)
}
}
}

@Composable
private fun BaseCreateQuizScreen(
specializations: List<CreateQuizState.Loaded.VoSpecialization>,
Expand Down Expand Up @@ -390,11 +416,27 @@ fun CreateQuizScreenPreview(
@Preview(showBackground = true)
@Composable
fun DynamicPreviewUI() {
val mockDomainList = specializations.map { voSpec ->
DomainSpecialization(id = voSpec.id, title = voSpec.title)
}

val mockUseCase = object : GetSpecializationsUseCase {
override suspend fun invoke(
request: SpecializationsRequest,
): DomainSpecializationListResponse {
delay(RESPONSE_DELAY)
return DomainSpecializationListResponse(
total = mockDomainList.size.toLong(),
data = mockDomainList
)
}
}

val mockViewModel = viewModelCreator<CreateQuizViewModel> {
CreateQuizViewModel(CreateQuizScreenMapper)
CreateQuizViewModel(mockUseCase, CreateQuizScreenMapper)
}

val state by mockViewModel.screenState.collectAsState()
val mockState by mockViewModel.screenState.collectAsState()

LaunchedEffect(Unit) {
delay(RESPONSE_DELAY)
Expand All @@ -408,13 +450,13 @@ fun DynamicPreviewUI() {
mockViewModel.onEvent(CreateQuizEvent.OnMinusQuestionClick(3))
delay(RESPONSE_DELAY)
// должно быть снова 2
mockViewModel.onEvent(CreateQuizEvent.OnSpecializationClick(21))
mockViewModel.onEvent(CreateQuizEvent.OnSpecializationClick(27))
// С изначально выбранного Frontend Dev должно быть выбрано Android Dev
}

ProvidePreviewCompositionLocals {
ScreenUI(
state = state,
state = mockState,
onEvent = mockViewModel::onEvent,
headerText = TextOrResource.Resource(R.string.create_quiz_top_bar_header_text)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,9 @@ import ru.yeahub.network_api.models.GetSpecializationResponse
import ru.yeahub.network_api.models.GetSpecializationsResponse
import ru.yeahub.test.TestArgumentsProvider

class CreateQuizMapperTest {
class CreateQuizDataToDomainMapperTest {
private val toDomainMapper = CreateQuizDataToDomainMapper()

//CreateQuizDataToDomainMapper параметризированный тест
class ArgumentsProvider :
TestArgumentsProvider<SpecializationSelectionDataToDomainMapperTestCase>() {
override fun testCases(): List<SpecializationSelectionDataToDomainMapperTestCase> = listOf(
SpecializationSelectionDataToDomainMapperTestCase(
dataToTest = SpecializationExampleDataClasses.defaultSpecialListResponse,
expectedResult = SpecializationExampleDataClasses.defaultDomainSpecialListResponse
)
)
}

@ParameterizedTest
@ArgumentsSource(ArgumentsProvider::class)
fun specializationSelectionDataToDomainMapperTestCase(
Expand Down Expand Up @@ -79,4 +68,14 @@ class CreateQuizMapperTest {
val dataToTest: GetSpecializationsResponse,
val expectedResult: DomainSpecializationListResponse,
)

class ArgumentsProvider :
TestArgumentsProvider<SpecializationSelectionDataToDomainMapperTestCase>() {
override fun testCases(): List<SpecializationSelectionDataToDomainMapperTestCase> = listOf(
SpecializationSelectionDataToDomainMapperTestCase(
dataToTest = SpecializationExampleDataClasses.defaultSpecialListResponse,
expectedResult = SpecializationExampleDataClasses.defaultDomainSpecialListResponse
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package test

import org.junit.jupiter.api.Assertions
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ArgumentsSource
import ru.yeahub.interview_trainer.impl.createQuiz.domain.DomainSpecialization
import ru.yeahub.interview_trainer.impl.createQuiz.presentation.CreateQuizScreenMapper
import ru.yeahub.interview_trainer.impl.createQuiz.presentation.CreateQuizState
import ru.yeahub.test.TestArgumentsProvider

class CreateQuizScreenMapperTest {

@ParameterizedTest
@ArgumentsSource(ArgumentsProvider::class)
fun getScreenStateTest(
testCase: CreateQuizScreenMapperTestCase,
) {
val result = CreateQuizScreenMapper.getScreenState(
specializations = testCase.specializations,
selectedSpecializationId = testCase.selectedSpecializationId,
questionsCount = testCase.questionsCount
)
Assertions.assertEquals(testCase.expectedResult, result)
}

object ScreenMapperExampleDataClasses {
val defaultDomainSpecial = DomainSpecialization(
id = 0L,
title = "default title num 0"
)

val defaultDomainSpecialWithImage = DomainSpecialization(
id = 1L,
title = "default title num 1"
)

val defaultDomainSpecialList = listOf(
defaultDomainSpecial,
defaultDomainSpecialWithImage
)

val defaultVoSpecial = CreateQuizState.Loaded.VoSpecialization(
id = 0L,
title = "default title num 0"
)

val defaultVoSpecialWithImage = CreateQuizState.Loaded.VoSpecialization(
id = 1L,
title = "default title num 1"
)

val defaultLoadedState = CreateQuizState.Loaded(
specializations = listOf(defaultVoSpecial, defaultVoSpecialWithImage),
selectedSpecializationId = 0L,
questionsCount = 10
)

val loadedStateWithDifferentSelection = CreateQuizState.Loaded(
specializations = listOf(defaultVoSpecial, defaultVoSpecialWithImage),
selectedSpecializationId = 1L,
questionsCount = 5
)
}

data class CreateQuizScreenMapperTestCase(
val specializations: List<DomainSpecialization>,
val selectedSpecializationId: Long,
val questionsCount: Int,
val expectedResult: CreateQuizState.Loaded,
)

class ArgumentsProvider :
TestArgumentsProvider<CreateQuizScreenMapperTestCase>() {
override fun testCases(): List<CreateQuizScreenMapperTestCase> = listOf(
CreateQuizScreenMapperTestCase(
specializations = ScreenMapperExampleDataClasses.defaultDomainSpecialList,
selectedSpecializationId = 0L,
questionsCount = 10,
expectedResult = ScreenMapperExampleDataClasses.defaultLoadedState
),
CreateQuizScreenMapperTestCase(
specializations = ScreenMapperExampleDataClasses.defaultDomainSpecialList,
selectedSpecializationId = 1L,
questionsCount = 5,
expectedResult = ScreenMapperExampleDataClasses.loadedStateWithDifferentSelection
)
)
}
}

This file was deleted.

Loading