You've already forked RekomenciMobile
versions diff
This commit is contained in:
+470
-55
@@ -2,6 +2,7 @@ package com.prodhack.moscow2025.presentation.screens.diffScreen
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -10,7 +11,11 @@ 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.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardColors
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
@@ -21,29 +26,34 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import com.google.gson.Gson
|
||||
import com.prodhack.moscow2025.R
|
||||
import com.prodhack.moscow2025.domain.models.Education
|
||||
import com.prodhack.moscow2025.domain.models.Project
|
||||
import com.prodhack.moscow2025.domain.models.ResumeModel
|
||||
import com.prodhack.moscow2025.domain.usecase.resumes.CalculateResumeDiffUseCase
|
||||
import com.prodhack.moscow2025.domain.models.WorkExperience
|
||||
import com.prodhack.moscow2025.presentation.components.standart.TBubble
|
||||
import com.prodhack.moscow2025.presentation.navigation.AppDestination
|
||||
import com.prodhack.moscow2025.presentation.theme.Paddings
|
||||
import com.prodhack.moscow2025.presentation.utils.ErrorCollectorScope
|
||||
import com.prodhack.moscow2025.presentation.utils.toReadableText
|
||||
import com.prodhack.moscow2025.presentation.utils.toSalaryRangeString
|
||||
import com.prodhack.moscow2025.presentation.utils.ui.noRippleClickable
|
||||
|
||||
@Composable
|
||||
fun ErrorCollectorScope.ResumeDiffScreen(
|
||||
navBackStackEntry: NavBackStackEntry,
|
||||
calculateResumeDiffUseCase: CalculateResumeDiffUseCase = CalculateResumeDiffUseCase(),
|
||||
onBack: () -> Unit = { navController.popBackStack() }
|
||||
) {
|
||||
val gson = remember { Gson() }
|
||||
val firstJson = navBackStackEntry.arguments?.getString(AppDestination.ResumeDiff.ARG_FIRST)
|
||||
val secondJson = navBackStackEntry.arguments?.getString(AppDestination.ResumeDiff.ARG_SECOND)
|
||||
val first = remember(firstJson) { firstJson?.let { gson.fromJson(it, ResumeModel::class.java) } }
|
||||
val first =
|
||||
remember(firstJson) { firstJson?.let { gson.fromJson(it, ResumeModel::class.java) } }
|
||||
val second =
|
||||
remember(secondJson) { secondJson?.let { gson.fromJson(it, ResumeModel::class.java) } }
|
||||
|
||||
@@ -60,7 +70,17 @@ fun ErrorCollectorScope.ResumeDiffScreen(
|
||||
return
|
||||
}
|
||||
|
||||
val diff = remember(first, second) { calculateResumeDiffUseCase(first, second) }
|
||||
val scrollState = rememberScrollState()
|
||||
val salaryDiff =
|
||||
remember(first, second) { calculateSalaryDiff(first.prediction, second.prediction) }
|
||||
val addedSkills = remember(first, second) { second.skills.toSet() - first.skills.toSet() }
|
||||
val removedSkills = remember(first, second) { first.skills.toSet() - second.skills.toSet() }
|
||||
val addedExperience = remember(first, second) { second.experience - first.experience }
|
||||
val removedExperience = remember(first, second) { first.experience - second.experience }
|
||||
val addedEducation = remember(first, second) { second.education - first.education }
|
||||
val removedEducation = remember(first, second) { first.education - second.education }
|
||||
val addedProjects = remember(first, second) { second.projects - first.projects }
|
||||
val removedProjects = remember(first, second) { first.projects - second.projects }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -90,69 +110,124 @@ fun ErrorCollectorScope.ResumeDiffScreen(
|
||||
Spacer(modifier = Modifier.size(24.dp))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.large))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(Paddings.medium)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(scrollState)
|
||||
) {
|
||||
VersionSummaryCard(title = "Версия 1", resume = first)
|
||||
VersionSummaryCard(title = "Версия 2", resume = second)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.large))
|
||||
|
||||
Text(
|
||||
text = "Изменено:",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
FlowRow(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(Paddings.small),
|
||||
verticalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
if (diff.changedFields.isEmpty()) {
|
||||
Text("Изменений не найдено", style = MaterialTheme.typography.labelLarge)
|
||||
} else {
|
||||
diff.changedFields.forEach { field ->
|
||||
Card(shape = MaterialTheme.shapes.small) {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = Paddings.medium, vertical = Paddings.small),
|
||||
text = field,
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.large))
|
||||
|
||||
diff.changes.forEach { change ->
|
||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = Paddings.small),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
|
||||
),
|
||||
shape = MaterialTheme.shapes.medium
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(Paddings.medium),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(Paddings.medium),
|
||||
verticalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
Text(change.title, style = MaterialTheme.typography.titleMedium)
|
||||
Text(change.body, style = MaterialTheme.typography.labelLarge)
|
||||
Text(
|
||||
text = "Разница в зарплате",
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
Text(
|
||||
text = salaryDiff,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 22.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(Paddings.large))
|
||||
|
||||
SectionContainer {
|
||||
DiffValueRow(
|
||||
title = "Должность",
|
||||
previous = first.position,
|
||||
current = second.position
|
||||
)
|
||||
DiffValueRow(
|
||||
title = "Город",
|
||||
previous = first.city,
|
||||
current = second.city
|
||||
)
|
||||
DiffValueRow(
|
||||
title = "Опыт",
|
||||
previous = first.experienceType.toReadableText(),
|
||||
current = second.experienceType.toReadableText()
|
||||
)
|
||||
DiffValueRow(
|
||||
title = "Прогноз зарплаты",
|
||||
previous = first.prediction.toSalaryRangeString(),
|
||||
current = second.prediction.toSalaryRangeString()
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||
|
||||
SectionContainer(title = "О себе") {
|
||||
DiffTextBlock(
|
||||
previous = first.about.ifBlank { "Описание отсутствует" },
|
||||
current = second.about.ifBlank { "Описание отсутствует" }
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||
|
||||
SectionContainer(title = "Ключевые навыки") {
|
||||
SkillsDiffBlock(addedSkills = addedSkills, removedSkills = removedSkills)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||
|
||||
SectionContainer(title = "Опыт работы") {
|
||||
WorkExperienceDiffBlock(
|
||||
added = addedExperience,
|
||||
removed = removedExperience
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||
|
||||
SectionContainer(title = "Образование") {
|
||||
EducationDiffBlock(
|
||||
added = addedEducation,
|
||||
removed = removedEducation
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||
|
||||
SectionContainer(title = "Проекты") {
|
||||
ProjectDiffBlock(
|
||||
added = addedProjects,
|
||||
removed = removedProjects
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Paddings.large * 3))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun VersionSummaryCard(title: String, resume: ResumeModel) {
|
||||
private fun SectionContainer(
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = "",
|
||||
colors: CardColors = CardDefaults.cardColors(),
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
Card(
|
||||
modifier = Modifier,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
colors = colors,
|
||||
shape = MaterialTheme.shapes.medium
|
||||
) {
|
||||
Column(
|
||||
@@ -161,10 +236,350 @@ private fun VersionSummaryCard(title: String, resume: ResumeModel) {
|
||||
.padding(Paddings.medium),
|
||||
verticalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
Text(title, style = MaterialTheme.typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Text(resume.position, style = MaterialTheme.typography.titleMedium)
|
||||
Text(resume.prediction.toSalaryRangeString(), style = MaterialTheme.typography.labelLarge)
|
||||
Text(resume.city, style = MaterialTheme.typography.labelMedium)
|
||||
if (title.isNotBlank()) {
|
||||
Text(
|
||||
text = title,
|
||||
style = typography.titleMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
}
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DiffValueRow(
|
||||
title: String,
|
||||
previous: String,
|
||||
current: String
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val changed = previous != current
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = typography.labelLarge,
|
||||
color = colorScheme.primary
|
||||
)
|
||||
if (changed) {
|
||||
Text(
|
||||
text = previous,
|
||||
style = typography.bodyMedium.copy(textDecoration = TextDecoration.LineThrough),
|
||||
color = colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = current,
|
||||
style = typography.bodyLarge,
|
||||
fontWeight = if (changed) FontWeight.Bold else FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DiffTextBlock(
|
||||
previous: String,
|
||||
current: String
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val changed = previous != current
|
||||
|
||||
if (changed) {
|
||||
Text(
|
||||
text = previous,
|
||||
style = typography.bodyMedium.copy(textDecoration = TextDecoration.LineThrough),
|
||||
color = colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = current,
|
||||
style = typography.bodyLarge,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
} else {
|
||||
Text("Без изменений", style = typography.bodyMedium)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SkillsDiffBlock(
|
||||
addedSkills: Set<String>,
|
||||
removedSkills: Set<String>
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
|
||||
if (addedSkills.isEmpty() && removedSkills.isEmpty()) {
|
||||
Text("Без изменений", style = typography.bodyMedium)
|
||||
return
|
||||
}
|
||||
|
||||
if (addedSkills.isNotEmpty()) {
|
||||
Text("Добавлено", style = typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(Paddings.small),
|
||||
verticalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
addedSkills.forEach { skill ->
|
||||
TBubble(text = skill)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removedSkills.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
Text("Удалено", style = typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(Paddings.small),
|
||||
verticalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
removedSkills.forEach { skill ->
|
||||
TBubble(text = skill)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WorkExperienceDiffBlock(
|
||||
added: List<WorkExperience>,
|
||||
removed: List<WorkExperience>
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
|
||||
if (added.isEmpty() && removed.isEmpty()) {
|
||||
Text("Изменений нет", style = typography.bodyMedium)
|
||||
return
|
||||
}
|
||||
|
||||
if (added.isNotEmpty()) {
|
||||
Text("Добавлено", style = typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
added.forEachIndexed { index, work ->
|
||||
WorkExperienceCard(index = index, workExperience = work)
|
||||
if (index != added.lastIndex || removed.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed.isNotEmpty()) {
|
||||
Text("Удалено", style = typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
removed.forEachIndexed { index, work ->
|
||||
WorkExperienceCard(index = index, workExperience = work, isRemoved = true)
|
||||
if (index != removed.lastIndex) {
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EducationDiffBlock(
|
||||
added: List<Education>,
|
||||
removed: List<Education>
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
|
||||
if (added.isEmpty() && removed.isEmpty()) {
|
||||
Text("Изменений нет", style = typography.bodyMedium)
|
||||
return
|
||||
}
|
||||
|
||||
if (added.isNotEmpty()) {
|
||||
Text("Добавлено", style = typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
added.forEachIndexed { index, education ->
|
||||
EducationCard(index = index, education = education)
|
||||
if (index != added.lastIndex || removed.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed.isNotEmpty()) {
|
||||
Text("Удалено", style = typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
removed.forEachIndexed { index, education ->
|
||||
EducationCard(index = index, education = education, isRemoved = true)
|
||||
if (index != removed.lastIndex) {
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProjectDiffBlock(
|
||||
added: List<Project>,
|
||||
removed: List<Project>
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
|
||||
if (added.isEmpty() && removed.isEmpty()) {
|
||||
Text("Изменений нет", style = typography.bodyMedium)
|
||||
return
|
||||
}
|
||||
|
||||
if (added.isNotEmpty()) {
|
||||
Text("Добавлено", style = typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
added.forEachIndexed { index, project ->
|
||||
ProjectCard(index = index, project = project)
|
||||
if (index != added.lastIndex || removed.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed.isNotEmpty()) {
|
||||
Text("Удалено", style = typography.labelLarge, fontWeight = FontWeight.Bold)
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
removed.forEachIndexed { index, project ->
|
||||
ProjectCard(index = index, project = project, isRemoved = true)
|
||||
if (index != removed.lastIndex) {
|
||||
Spacer(modifier = Modifier.height(Paddings.small))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WorkExperienceCard(
|
||||
index: Int,
|
||||
workExperience: WorkExperience,
|
||||
isRemoved: Boolean = false
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val textDecoration = if (isRemoved) TextDecoration.LineThrough else TextDecoration.None
|
||||
val valueColor = if (isRemoved) colorScheme.onSurfaceVariant else colorScheme.onSurface
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
Text(
|
||||
text = "Место №${index + 1}",
|
||||
style = typography.labelLarge,
|
||||
color = if (isRemoved) colorScheme.error else colorScheme.primary
|
||||
)
|
||||
Text(
|
||||
workExperience.place,
|
||||
style = typography.titleMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
Text(
|
||||
text = workExperience.description,
|
||||
style = typography.bodyMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
Text(
|
||||
text = "Длительность: ${workExperience.monthDuration.toMonthText()}",
|
||||
style = typography.bodyMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EducationCard(index: Int, education: Education, isRemoved: Boolean = false) {
|
||||
val typography = MaterialTheme.typography
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val textDecoration = if (isRemoved) TextDecoration.LineThrough else TextDecoration.None
|
||||
val valueColor = if (isRemoved) colorScheme.onSurfaceVariant else colorScheme.onSurface
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
Text(
|
||||
text = "Учебное место №${index + 1}",
|
||||
style = typography.labelLarge,
|
||||
color = if (isRemoved) colorScheme.error else colorScheme.primary
|
||||
)
|
||||
Text(
|
||||
education.place,
|
||||
style = typography.titleMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
Text(
|
||||
text = "Ступень: ${education.grade.toReadableText()}",
|
||||
style = typography.bodyMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
Text(
|
||||
text = "Специализация: ${education.specialization}",
|
||||
style = typography.bodyMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
Text(
|
||||
text = education.description,
|
||||
style = typography.bodyMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProjectCard(index: Int, project: Project, isRemoved: Boolean = false) {
|
||||
val typography = MaterialTheme.typography
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val textDecoration = if (isRemoved) TextDecoration.LineThrough else TextDecoration.None
|
||||
val valueColor = if (isRemoved) colorScheme.onSurfaceVariant else colorScheme.onSurface
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
Text(
|
||||
text = "Проект №${index + 1}",
|
||||
style = typography.labelLarge,
|
||||
color = if (isRemoved) colorScheme.error else colorScheme.primary
|
||||
)
|
||||
Text(
|
||||
project.name,
|
||||
style = typography.titleMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
Text(
|
||||
project.description,
|
||||
style = typography.bodyMedium.copy(textDecoration = textDecoration),
|
||||
color = valueColor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Int?.toMonthText(): String = when {
|
||||
this == null -> "Не указано"
|
||||
this < 12 -> "$this мес."
|
||||
else -> {
|
||||
val years = this / 12
|
||||
val months = this % 12
|
||||
if (months == 0) "$years г." else "$years г. $months мес."
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateSalaryDiff(
|
||||
prev: Pair<Float?, Float?>?,
|
||||
current: Pair<Float?, Float?>?
|
||||
): String {
|
||||
val prevAvg = prev?.let { listOfNotNull(it.first, it.second).averageOrNull() }
|
||||
val currAvg = current?.let { listOfNotNull(it.first, it.second).averageOrNull() }
|
||||
return if (prevAvg != null && currAvg != null) {
|
||||
val diff = currAvg - prevAvg
|
||||
val sign = if (diff >= 0) "+" else "-"
|
||||
"${sign}${(kotlin.math.abs(diff).toInt() / 1000) * 1000}₽"
|
||||
} else {
|
||||
"н/д"
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<Float>.averageOrNull(): Double? = if (isEmpty()) null else average()
|
||||
|
||||
+13
-16
@@ -168,25 +168,22 @@ private fun ResumeDetailsContent(
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(Paddings.large))
|
||||
SectionContainer {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(Paddings.small)
|
||||
) {
|
||||
Text(
|
||||
resume.position,
|
||||
style = typography.titleLarge,
|
||||
fontSize = 28.sp
|
||||
)
|
||||
|
||||
if (resume.prediction == null) {
|
||||
CircularProgressIndicator(modifier = Modifier.size(18.dp))
|
||||
} else {
|
||||
Text(
|
||||
resume.position,
|
||||
style = typography.titleLarge,
|
||||
fontSize = 28.sp
|
||||
resume.prediction.toSalaryRangeString(),
|
||||
style = typography.titleMedium,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
if (resume.prediction == null) {
|
||||
CircularProgressIndicator(modifier = Modifier.size(18.dp))
|
||||
} else {
|
||||
Text(
|
||||
resume.prediction.toSalaryRangeString(),
|
||||
style = typography.titleMedium,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = resume.city,
|
||||
style = typography.labelLarge,
|
||||
|
||||
Reference in New Issue
Block a user