You've already forked RekomenciMobile
feat: added education and projects
This commit is contained in:
+161
-6
@@ -199,21 +199,21 @@ fun CreateResumeScreen(
|
|||||||
TTTextField(
|
TTTextField(
|
||||||
value = workExp.description,
|
value = workExp.description,
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
viewModel.changeWorkExperiencePlace(index, it)
|
viewModel.changeWorkExperienceDescription(index, it)
|
||||||
},
|
},
|
||||||
singleLine = false,
|
singleLine = false,
|
||||||
maxLines = 10,
|
maxLines = 10,
|
||||||
label = "Расскажите подробнее",
|
label = "Расскажите подробнее",
|
||||||
error = formState.value.errors[ResumeField.WorkExperiencePlace(index)]
|
error = formState.value.errors[ResumeField.WorkExperienceDescription(index)]
|
||||||
)
|
)
|
||||||
|
|
||||||
TTTextField(
|
TTTextField(
|
||||||
value = workExp.place,
|
value = workExp.monthDuration?.toString() ?: "",
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
viewModel.changeWorkExperiencePlace(index, it)
|
viewModel.changeWorkExperienceMonthDuration(index, it)
|
||||||
},
|
},
|
||||||
label = "Место работы",
|
label = "Продолжительность (в месяцах)",
|
||||||
error = formState.value.errors[ResumeField.WorkExperiencePlace(index)]
|
error = formState.value.errors[ResumeField.WorkExperienceMonthDuration(index)]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,6 +246,161 @@ fun CreateResumeScreen(
|
|||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = "Образование:",
|
||||||
|
style = typography.titleMedium,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
|
formState.value.education.forEachIndexed { index, education ->
|
||||||
|
Text(
|
||||||
|
text = "№${index + 1}:",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
|
||||||
|
TTTextField(
|
||||||
|
value = education.place,
|
||||||
|
onValueChange = { viewModel.changeEducationPlace(index, it) },
|
||||||
|
label = "Учебное заведение",
|
||||||
|
error = formState.value.errors[ResumeField.EducationPlace(index)]
|
||||||
|
)
|
||||||
|
|
||||||
|
TTTextFieldWithDropdown(
|
||||||
|
value = education.grade.friendlyName,
|
||||||
|
onValueChange = {},
|
||||||
|
singleLine = false,
|
||||||
|
maxLines = Int.MAX_VALUE,
|
||||||
|
label = "Уровень образования",
|
||||||
|
error = formState.value.errors[ResumeField.EducationGrade(index)],
|
||||||
|
dropdownItems = viewModel.educationGradeOptions,
|
||||||
|
dropDownItem = {
|
||||||
|
Text(text = it.friendlyName, style = typography.titleMedium, fontSize = 16.sp)
|
||||||
|
},
|
||||||
|
onDropdownItemSelected = { viewModel.changeEducationGrade(index, it) }
|
||||||
|
)
|
||||||
|
|
||||||
|
TTTextField(
|
||||||
|
value = education.specialization,
|
||||||
|
onValueChange = { viewModel.changeEducationSpecialization(index, it) },
|
||||||
|
label = "Специализация",
|
||||||
|
error = formState.value.errors[ResumeField.EducationSpecialization(index)]
|
||||||
|
)
|
||||||
|
|
||||||
|
TTTextField(
|
||||||
|
value = education.description,
|
||||||
|
onValueChange = { viewModel.changeEducationDescription(index, it) },
|
||||||
|
singleLine = false,
|
||||||
|
maxLines = 10,
|
||||||
|
label = "Расскажите подробнее",
|
||||||
|
error = formState.value.errors[ResumeField.EducationDescription(index)]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formState.value.education.isEmpty()){
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = "Пока ничего нет",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
shape = Shapes.smallRoundedBox,
|
||||||
|
onClick = viewModel::addNewEducation,
|
||||||
|
colors = ButtonColors(
|
||||||
|
containerColor = colorScheme.onSecondary,
|
||||||
|
contentColor = colorScheme.secondary,
|
||||||
|
disabledContainerColor = colorScheme.onSecondary,
|
||||||
|
disabledContentColor = colorScheme.secondary
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Добавить",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = "Проекты:",
|
||||||
|
style = typography.titleMedium,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
|
formState.value.projects.forEachIndexed { index, project ->
|
||||||
|
Text(
|
||||||
|
text = "№${index + 1}:",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
|
||||||
|
TTTextField(
|
||||||
|
value = project.name,
|
||||||
|
onValueChange = { viewModel.changeProjectName(index, it) },
|
||||||
|
label = "Название проекта",
|
||||||
|
error = formState.value.errors[ResumeField.ProjectName(index)]
|
||||||
|
)
|
||||||
|
|
||||||
|
TTTextField(
|
||||||
|
value = project.description,
|
||||||
|
onValueChange = { viewModel.changeProjectDescription(index, it) },
|
||||||
|
singleLine = false,
|
||||||
|
maxLines = 10,
|
||||||
|
label = "Расскажите подробнее",
|
||||||
|
error = formState.value.errors[ResumeField.ProjectDescription(index)]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formState.value.projects.isEmpty()){
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = "Пока ничего нет",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
shape = Shapes.smallRoundedBox,
|
||||||
|
onClick = viewModel::addNewProject,
|
||||||
|
colors = ButtonColors(
|
||||||
|
containerColor = colorScheme.onSecondary,
|
||||||
|
contentColor = colorScheme.secondary,
|
||||||
|
disabledContainerColor = colorScheme.onSecondary,
|
||||||
|
disabledContentColor = colorScheme.secondary
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Добавить",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.large))
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
BigButton(
|
BigButton(
|
||||||
onClick = viewModel::submit,
|
onClick = viewModel::submit,
|
||||||
|
|||||||
+118
-5
@@ -22,7 +22,6 @@ import kotlinx.coroutines.flow.update
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.annotation.KoinViewModel
|
import org.koin.android.annotation.KoinViewModel
|
||||||
import kotlin.collections.minus
|
import kotlin.collections.minus
|
||||||
import kotlin.math.exp
|
|
||||||
|
|
||||||
data class ResumeFormState(
|
data class ResumeFormState(
|
||||||
val about: String = "",
|
val about: String = "",
|
||||||
@@ -67,6 +66,15 @@ sealed class UIEducationGrade(val friendlyName: String) {
|
|||||||
data object HighNotFinished : UIEducationGrade("Неоконченное высшее")
|
data object HighNotFinished : UIEducationGrade("Неоконченное высшее")
|
||||||
data object High : UIEducationGrade("Высшее")
|
data object High : UIEducationGrade("Высшее")
|
||||||
data object Additional : UIEducationGrade("Другое")
|
data object Additional : UIEducationGrade("Другое")
|
||||||
|
|
||||||
|
fun mapToDomain(): EducationGrades = when (this) {
|
||||||
|
Common -> EducationGrades.Common
|
||||||
|
Middle -> EducationGrades.Middle
|
||||||
|
MiddleSpec -> EducationGrades.MiddleSpec
|
||||||
|
HighNotFinished -> EducationGrades.HighNotFinished
|
||||||
|
High -> EducationGrades.High
|
||||||
|
Additional -> EducationGrades.Additional
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@KoinViewModel
|
@KoinViewModel
|
||||||
@@ -219,6 +227,104 @@ class CreateResumeViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Education
|
||||||
|
val educationGradeOptions = listOf(
|
||||||
|
UIEducationGrade.Common,
|
||||||
|
UIEducationGrade.Middle,
|
||||||
|
UIEducationGrade.MiddleSpec,
|
||||||
|
UIEducationGrade.HighNotFinished,
|
||||||
|
UIEducationGrade.High,
|
||||||
|
UIEducationGrade.Additional
|
||||||
|
)
|
||||||
|
|
||||||
|
fun addNewEducation() {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
education = it.education + UIEducation(
|
||||||
|
place = "",
|
||||||
|
grade = UIEducationGrade.High,
|
||||||
|
specialization = "",
|
||||||
|
description = ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeEducationPlace(index: Int, value: String) {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
education = it.education.mapIndexed { ind, education ->
|
||||||
|
if (ind == index) education.copy(place = value) else education
|
||||||
|
},
|
||||||
|
errors = it.errors - ResumeField.EducationPlace(index)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeEducationGrade(index: Int, value: UIEducationGrade) {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
education = it.education.mapIndexed { ind, education ->
|
||||||
|
if (ind == index) education.copy(grade = value) else education
|
||||||
|
},
|
||||||
|
errors = it.errors - ResumeField.EducationGrade(index)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeEducationSpecialization(index: Int, value: String) {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
education = it.education.mapIndexed { ind, education ->
|
||||||
|
if (ind == index) education.copy(specialization = value) else education
|
||||||
|
},
|
||||||
|
errors = it.errors - ResumeField.EducationSpecialization(index)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeEducationDescription(index: Int, value: String) {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
education = it.education.mapIndexed { ind, education ->
|
||||||
|
if (ind == index) education.copy(description = value) else education
|
||||||
|
},
|
||||||
|
errors = it.errors - ResumeField.EducationDescription(index)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Projects
|
||||||
|
fun addNewProject() {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
projects = it.projects + Project("", "")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeProjectName(index: Int, value: String) {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
projects = it.projects.mapIndexed { ind, project ->
|
||||||
|
if (ind == index) project.copy(name = value) else project
|
||||||
|
},
|
||||||
|
errors = it.errors - ResumeField.ProjectName(index)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeProjectDescription(index: Int, value: String) {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
projects = it.projects.mapIndexed { ind, project ->
|
||||||
|
if (ind == index) project.copy(description = value) else project
|
||||||
|
},
|
||||||
|
errors = it.errors - ResumeField.ProjectDescription(index)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun submit() {
|
fun submit() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val validation = validateDataUseCase.validateResume(
|
val validation = validateDataUseCase.validateResume(
|
||||||
@@ -242,10 +348,17 @@ class CreateResumeViewModel(
|
|||||||
about = about,
|
about = about,
|
||||||
skills = keySkills.toList(),
|
skills = keySkills.toList(),
|
||||||
experienceType = experience!!.mapToDomain(),
|
experienceType = experience!!.mapToDomain(),
|
||||||
city = null,
|
city = city.ifBlank { null },
|
||||||
experience = emptyList(),
|
experience = workExperience,
|
||||||
education = emptyList(),
|
education = education.map {
|
||||||
projects = emptyList()
|
Education(
|
||||||
|
place = it.place,
|
||||||
|
grade = it.grade.mapToDomain(),
|
||||||
|
specialization = it.specialization,
|
||||||
|
description = it.description
|
||||||
|
)
|
||||||
|
},
|
||||||
|
projects = projects
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user