You've already forked RekomenciMobile
feat: added education and projects
This commit is contained in:
+162
-7
@@ -199,21 +199,21 @@ fun CreateResumeScreen(
|
||||
TTTextField(
|
||||
value = workExp.description,
|
||||
onValueChange = {
|
||||
viewModel.changeWorkExperiencePlace(index, it)
|
||||
viewModel.changeWorkExperienceDescription(index, it)
|
||||
},
|
||||
singleLine = false,
|
||||
maxLines = 10,
|
||||
label = "Расскажите подробнее",
|
||||
error = formState.value.errors[ResumeField.WorkExperiencePlace(index)]
|
||||
error = formState.value.errors[ResumeField.WorkExperienceDescription(index)]
|
||||
)
|
||||
|
||||
TTTextField(
|
||||
value = workExp.place,
|
||||
value = workExp.monthDuration?.toString() ?: "",
|
||||
onValueChange = {
|
||||
viewModel.changeWorkExperiencePlace(index, it)
|
||||
viewModel.changeWorkExperienceMonthDuration(index, it)
|
||||
},
|
||||
label = "Место работы",
|
||||
error = formState.value.errors[ResumeField.WorkExperiencePlace(index)]
|
||||
label = "Продолжительность (в месяцах)",
|
||||
error = formState.value.errors[ResumeField.WorkExperienceMonthDuration(index)]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -246,6 +246,161 @@ fun CreateResumeScreen(
|
||||
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))
|
||||
BigButton(
|
||||
onClick = viewModel::submit,
|
||||
@@ -254,4 +409,4 @@ fun CreateResumeScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+119
-6
@@ -22,7 +22,6 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.annotation.KoinViewModel
|
||||
import kotlin.collections.minus
|
||||
import kotlin.math.exp
|
||||
|
||||
data class ResumeFormState(
|
||||
val about: String = "",
|
||||
@@ -67,6 +66,15 @@ sealed class UIEducationGrade(val friendlyName: String) {
|
||||
data object HighNotFinished : UIEducationGrade("Неоконченное высшее")
|
||||
data object High : 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
|
||||
@@ -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() {
|
||||
viewModelScope.launch {
|
||||
val validation = validateDataUseCase.validateResume(
|
||||
@@ -242,10 +348,17 @@ class CreateResumeViewModel(
|
||||
about = about,
|
||||
skills = keySkills.toList(),
|
||||
experienceType = experience!!.mapToDomain(),
|
||||
city = null,
|
||||
experience = emptyList(),
|
||||
education = emptyList(),
|
||||
projects = emptyList()
|
||||
city = city.ifBlank { null },
|
||||
experience = workExperience,
|
||||
education = education.map {
|
||||
Education(
|
||||
place = it.place,
|
||||
grade = it.grade.mapToDomain(),
|
||||
specialization = it.specialization,
|
||||
description = it.description
|
||||
)
|
||||
},
|
||||
projects = projects
|
||||
)
|
||||
}
|
||||
|
||||
@@ -253,4 +366,4 @@ class CreateResumeViewModel(
|
||||
result.collectRequest(_resumeFillState)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user