Skip to content
Closed
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
151 changes: 151 additions & 0 deletions core/ui/src/main/java/ru/yeahub/core_ui/component/QuizAnswerButton.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package ru.yeahub.core_ui.component

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import ru.yeahub.core_ui.example.staticPreview.StaticPreview
import ru.yeahub.core_ui.theme.Theme
import ru.yeahub.core_utils.common.TextOrResource
import ru.yeahub.ui.R

private val FIGMA_LOW_PADDING = 8.dp
private val FIGMA_RADIUS = 12.dp

@Composable
fun KnownAnswerButton(
enabled: Boolean,
isHighlighted: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
QuizAnswerButton(
iconRes = R.drawable.thumbs_up_icon,
text = TextOrResource.Resource(R.string.quiz_answer_known),
enabled = enabled,
isHighlighted = isHighlighted,
onClick = onClick,
modifier = modifier
)
}

@Composable
fun UnknownAnswerButton(
enabled: Boolean,
isHighlighted: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
QuizAnswerButton(
iconRes = R.drawable.thumbs_down_icon,
text = TextOrResource.Resource(R.string.quiz_answer_unknown),
enabled = enabled,
isHighlighted = isHighlighted,
onClick = onClick,
modifier = modifier
)
}

@Composable
private fun QuizAnswerButton(
iconRes: Int,
text: TextOrResource,
enabled: Boolean,
isHighlighted: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
val context = LocalContext.current

val contentColor = if (isHighlighted) {
Theme.colors.purple700
} else {
Theme.colors.black700
}

Button(
onClick = onClick,
modifier = modifier
.width(120.dp)
.height(48.dp),
shape = RoundedCornerShape(FIGMA_RADIUS),
colors = ButtonDefaults.buttonColors(
containerColor = Theme.colors.black10,
contentColor = contentColor,
disabledContainerColor = Theme.colors.black10,
disabledContentColor = contentColor
),
contentPadding = PaddingValues(
horizontal = 12.dp,
vertical = FIGMA_LOW_PADDING
),
enabled = enabled
) {
Icon(
painter = painterResource(iconRes),
contentDescription = null,
modifier = Modifier.padding(end = FIGMA_LOW_PADDING)
)
Text(
text = when (text) {
is TextOrResource.Text -> text.text
is TextOrResource.Resource -> text.getString(context)
},
style = Theme.typography.body2
)
}
}

@StaticPreview
@Composable
fun KnownAnswerHighlightedButtonPreview() {
KnownAnswerButton(
enabled = true,
isHighlighted = true,
onClick = {},
modifier = Modifier
)
}

@StaticPreview
@Composable
fun KnownAnswerButtonPreview() {
KnownAnswerButton(
enabled = true,
isHighlighted = false,
onClick = {},
modifier = Modifier
)
}

@StaticPreview
@Composable
fun UnknownAnswerHighlightedButtonPreview() {
UnknownAnswerButton(
enabled = true,
isHighlighted = true,
onClick = {},
modifier = Modifier
)
}

@StaticPreview
@Composable
fun UnknownAnswerButtonPreview() {
UnknownAnswerButton(
enabled = true,
isHighlighted = true,
onClick = {},
modifier = Modifier
)
}
3 changes: 3 additions & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@

<string name="interview_trainer_title">Интервью тренажер</string>
<string name="interview_trainer_description">Улучшите свои знания перед собеседованием</string>

<string name="quiz_answer_unknown">Не знаю</string>
<string name="quiz_answer_known">Знаю</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.FilledIconButton
Expand Down Expand Up @@ -50,9 +48,11 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import ru.yeahub.core_ui.component.ErrorScreen
import ru.yeahub.core_ui.component.KnownAnswerButton
import ru.yeahub.core_ui.component.PrimaryButton
import ru.yeahub.core_ui.component.SecondaryButton
import ru.yeahub.core_ui.component.TopAppBarWithBottomBorder
import ru.yeahub.core_ui.component.UnknownAnswerButton
import ru.yeahub.core_ui.component.YeahubButtonDefaults
import ru.yeahub.core_ui.example.staticPreview.StaticPreview
import ru.yeahub.core_ui.theme.Theme
Expand Down Expand Up @@ -283,18 +283,16 @@ private fun QuestionCard(
Spacer(Modifier.height(FIGMA_VERTICAL_FIRST_AND_LAST_ELEMENT_PADDING))

Row(Modifier.padding(bottom = FIGMA_MEDIUM_PADDING)) {
QuizAnswerButton(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему не твой экран с изменениями? Откати изменения чтоб не было конфликта (но вообще странно, что изменения показываются как дифф. По идеи вроде Иван подлил и конфликтов не будет, но хз. Мб у Антона уточнить(?))

painter = painterResource(R.drawable.thumbs_down_icon),
text = TextOrResource.Resource(R.string.quiz_answer_unknown),
onClick = onUnknownClick,
isSelected = state.selectedAnswer == InterviewQuizState.Loaded.QuizAnswer.UNKNOWN
UnknownAnswerButton(
enabled = true,
isHighlighted = state.selectedAnswer == InterviewQuizState.Loaded.QuizAnswer.UNKNOWN,
onClick = onUnknownClick
)
Spacer(Modifier.weight(1f))
QuizAnswerButton(
painter = painterResource(R.drawable.thumbs_up_icon),
text = TextOrResource.Resource(R.string.quiz_answer_known),
onClick = onKnownClick,
isSelected = state.selectedAnswer == InterviewQuizState.Loaded.QuizAnswer.KNOWN
KnownAnswerButton(
enabled = true,
isHighlighted = state.selectedAnswer == InterviewQuizState.Loaded.QuizAnswer.KNOWN,
onClick = onKnownClick
)
}
HorizontalDivider(
Expand Down Expand Up @@ -408,51 +406,6 @@ private fun NavigationButton(
}
}

@Composable
private fun QuizAnswerButton(
painter: Painter,
text: TextOrResource,
onClick: () -> Unit,
isSelected: Boolean
) {
val context = LocalContext.current

val contentColor = if (isSelected) {
Theme.colors.purple700
} else {
Theme.colors.black700
}

Button(
onClick = onClick,
modifier = Modifier
.width(120.dp)
.height(48.dp),
shape = RoundedCornerShape(FIGMA_RADIUS),
colors = ButtonDefaults.buttonColors(
containerColor = Theme.colors.black10,
contentColor = contentColor
),
contentPadding = PaddingValues(
horizontal = 12.dp,
vertical = FIGMA_LOW_PADDING
)
) {
Icon(
painter = painter,
contentDescription = null,
modifier = Modifier.padding(end = FIGMA_LOW_PADDING)
)
Text(
text = when (text) {
is TextOrResource.Text -> text.text
is TextOrResource.Resource -> text.getString(context)
},
style = Theme.typography.body2
)
}
}

private val shortAnswerForPreview = "Виртуальный DOM (VDOM) — это легковесное " +
"представление реального DOM в памяти, которое используется в " +
"JavaScript-библиотеках, таких как React и Vue, " +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ru.yeahub.interview_trainer.impl.interviewQuizResult

sealed interface InterviewQuizResultEvent {
Comment thread
arte123ras marked this conversation as resolved.

data object Todo : InterviewQuizResultEvent // TODO: сделать ивенты
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ru.yeahub.interview_trainer.impl.interviewQuizResult

import InterviewQuizResultState
import kotlinx.collections.immutable.persistentListOf

private const val DEFAULT_PERCENTAGE = 0.75f
private const val DEFAULT_TOTAL_QUESTIONS = 20
private const val DEFAULT_NEW_QUESTIONS = 50
private const val DEFAULT_IN_PROGRESS = 120
private const val DEFAULT_STUDIED = 12
private const val DEFAULT_SKILL_SCORE = 60
private const val DEFAULT_SKILL_MAX = 120

class InterviewQuizResultScreenMapper {

fun getScreenState(): InterviewQuizResultState = InterviewQuizResultState.Loaded(
overallPercentage = DEFAULT_PERCENTAGE,
totalQuestions = DEFAULT_TOTAL_QUESTIONS,
newQuestions = DEFAULT_NEW_QUESTIONS,
inProgress = DEFAULT_IN_PROGRESS,
studied = DEFAULT_STUDIED,
skills = persistentListOf(
InterviewQuizResultState.Loaded.VoSkillStat("HTML", DEFAULT_SKILL_SCORE, DEFAULT_SKILL_MAX),
InterviewQuizResultState.Loaded.VoSkillStat("CSS", DEFAULT_SKILL_SCORE, DEFAULT_SKILL_MAX),
InterviewQuizResultState.Loaded.VoSkillStat("JavaScript", DEFAULT_SKILL_SCORE, DEFAULT_SKILL_MAX),
InterviewQuizResultState.Loaded.VoSkillStat("React", DEFAULT_SKILL_SCORE, DEFAULT_SKILL_MAX),
InterviewQuizResultState.Loaded.VoSkillStat("PHP", DEFAULT_SKILL_SCORE, DEFAULT_SKILL_MAX),
InterviewQuizResultState.Loaded.VoSkillStat("JavaScript", DEFAULT_SKILL_SCORE, DEFAULT_SKILL_MAX)
),
questions = persistentListOf(
InterviewQuizResultState.Loaded.VoQuestionResult("Что такое Virtual DOM, и как он работает?", false),
InterviewQuizResultState.Loaded.VoQuestionResult("Что такое Virtual DOM, и как он работает?", true),
InterviewQuizResultState.Loaded.VoQuestionResult("Что такое Virtual DOM, и как он работает?", true),
InterviewQuizResultState.Loaded.VoQuestionResult("Что такое Virtual DOM, и как он работает?", false),
InterviewQuizResultState.Loaded.VoQuestionResult("Что такое Virtual DOM, и как он работает?", true),
InterviewQuizResultState.Loaded.VoQuestionResult("Что такое Virtual DOM, и как он работает?", false)
)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import androidx.compose.runtime.Immutable
import kotlinx.collections.immutable.PersistentList

Comment thread
arte123ras marked this conversation as resolved.
@Immutable
sealed interface InterviewQuizResultState {
data object Loading : InterviewQuizResultState

data class Loaded(
val overallPercentage: Float,
val totalQuestions: Int,
val newQuestions: Int,
val inProgress: Int,
val studied: Int,
val skills: PersistentList<VoSkillStat>,
val questions: PersistentList<VoQuestionResult>
) : InterviewQuizResultState {
@Immutable
data class VoSkillStat(
val name: String,
val current: Int,
val max: Int
)

@Immutable
data class VoQuestionResult(
val questionText: String,
val isCorrect: Boolean
)
}

data class Error(val throwable: Throwable) : InterviewQuizResultState
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import ru.yeahub.core_utils.BaseViewModel
import ru.yeahub.interview_trainer.impl.interviewQuizResult.InterviewQuizResultEvent
import ru.yeahub.interview_trainer.impl.interviewQuizResult.InterviewQuizResultScreenMapper

private const val STOP_TIMEOUT_MILLIS = 5000L

class InterviewQuizResultViewModel(
private val mapper: InterviewQuizResultScreenMapper
) : BaseViewModel() {

val state: StateFlow<InterviewQuizResultState> =
flow {
emit(mapper.getScreenState())
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(STOP_TIMEOUT_MILLIS),
initialValue = InterviewQuizResultState.Loading
)

fun onEvent(event: InterviewQuizResultEvent) {
// TODO:
}
}
Loading
Loading