You've already forked RekomenciMobile
fix fix and fix
This commit is contained in:
+14
-11
@@ -1,5 +1,6 @@
|
|||||||
package com.prodhack.moscow2025.data.data_providers.api
|
package com.prodhack.moscow2025.data.data_providers.api
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import com.prodhack.moscow2025.common.Constants
|
import com.prodhack.moscow2025.common.Constants
|
||||||
import com.prodhack.moscow2025.data.data_providers.localInfo.AuthorizationDataStore
|
import com.prodhack.moscow2025.data.data_providers.localInfo.AuthorizationDataStore
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
@@ -48,19 +49,21 @@ class ApiKtorClient(authorizationDataStore: AuthorizationDataStore) {
|
|||||||
}
|
}
|
||||||
install(Auth) {
|
install(Auth) {
|
||||||
bearer {
|
bearer {
|
||||||
sendWithoutRequest { request ->
|
// sendWithoutRequest { request ->
|
||||||
val segments = request.url.pathSegments
|
// val segments = request.url.pathSegments
|
||||||
|
//
|
||||||
val endpointsWithoutAuth = listOf(
|
// val endpointsWithoutAuth = listOf(
|
||||||
"sign_in",
|
// "sign_in",
|
||||||
"sign_up"
|
// "sign_up"
|
||||||
)
|
// )
|
||||||
|
//
|
||||||
endpointsWithoutAuth.any { segments.contains(it) }.not()
|
// endpointsWithoutAuth.any { segments.contains(it) }.not()
|
||||||
}
|
// }
|
||||||
loadTokens {
|
loadTokens {
|
||||||
return@loadTokens authorizationDataStore.token.first()
|
return@loadTokens authorizationDataStore.token.first()
|
||||||
.toBearerTokens()
|
.toBearerTokens().also {
|
||||||
|
Log.d("csmlc", it.accessToken)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
refreshTokens {
|
refreshTokens {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.prodhack.moscow2025.domain.models.Education
|
|||||||
import com.prodhack.moscow2025.domain.models.EducationGrades
|
import com.prodhack.moscow2025.domain.models.EducationGrades
|
||||||
import com.prodhack.moscow2025.domain.models.ExperienceType
|
import com.prodhack.moscow2025.domain.models.ExperienceType
|
||||||
import com.prodhack.moscow2025.domain.models.Project
|
import com.prodhack.moscow2025.domain.models.Project
|
||||||
|
import com.prodhack.moscow2025.domain.models.ResumeCreationModel
|
||||||
import com.prodhack.moscow2025.domain.models.ResumeModel
|
import com.prodhack.moscow2025.domain.models.ResumeModel
|
||||||
import com.prodhack.moscow2025.domain.models.WorkExperience
|
import com.prodhack.moscow2025.domain.models.WorkExperience
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -55,11 +56,12 @@ data class ResumeDTO(
|
|||||||
@SerialName("key_skills")
|
@SerialName("key_skills")
|
||||||
val keySkills: List<String>,
|
val keySkills: List<String>,
|
||||||
val position: String,
|
val position: String,
|
||||||
|
@SerialName("location")
|
||||||
val city: String,
|
val city: String,
|
||||||
val experience: List<ExperienceDTO>,
|
val experience: List<ExperienceDTO> = emptyList(),
|
||||||
val education: List<EducationDTO>,
|
val education: List<EducationDTO> = emptyList(),
|
||||||
val project: List<ProjectDTO>,
|
val project: List<ProjectDTO> = emptyList(),
|
||||||
val prediction: PredictionDTO
|
val prediction: PredictionDTO? = null
|
||||||
) {
|
) {
|
||||||
fun mapToDomain(): ResumeModel = ResumeModel(
|
fun mapToDomain(): ResumeModel = ResumeModel(
|
||||||
id = id,
|
id = id,
|
||||||
@@ -67,11 +69,13 @@ data class ResumeDTO(
|
|||||||
skills = keySkills,
|
skills = keySkills,
|
||||||
position = position,
|
position = position,
|
||||||
experienceType = experienceType.mapToDomain(),
|
experienceType = experienceType.mapToDomain(),
|
||||||
prediction = Pair(
|
prediction = prediction?.let {
|
||||||
prediction.fromSalary.toIntOrNull(),
|
Pair(
|
||||||
prediction.toSalary.toIntOrNull()
|
it.fromSalary.toIntOrNull(),
|
||||||
),
|
it.toSalary.toIntOrNull()
|
||||||
recommendedSkills = prediction.recommendedSkills,
|
)
|
||||||
|
},
|
||||||
|
recommendedSkills = prediction?.recommendedSkills,
|
||||||
city = city,
|
city = city,
|
||||||
experience = experience.map { it.mapToDomain() },
|
experience = experience.map { it.mapToDomain() },
|
||||||
education = education.map { it.mapToDomain() },
|
education = education.map { it.mapToDomain() },
|
||||||
@@ -83,9 +87,9 @@ data class ResumeDTO(
|
|||||||
aboutMe = aboutMe,
|
aboutMe = aboutMe,
|
||||||
keySkills = keySkills.joinToString("|"),
|
keySkills = keySkills.joinToString("|"),
|
||||||
position = position,
|
position = position,
|
||||||
fromSalary = prediction.fromSalary.toIntOrNull(),
|
fromSalary = prediction?.fromSalary?.toIntOrNull(),
|
||||||
toSalary = prediction.toSalary.toIntOrNull(),
|
toSalary = prediction?.toSalary?.toIntOrNull(),
|
||||||
recommendedSkills = prediction.recommendedSkills.joinToString("|"),
|
recommendedSkills = prediction?.recommendedSkills?.joinToString("|") ?: "",
|
||||||
experienceType = experienceType.mapToDomain().name,
|
experienceType = experienceType.mapToDomain().name,
|
||||||
city = city,
|
city = city,
|
||||||
experience = JsonTypeConverters.fromWorkExperienceList(experience.map { it.mapToDomain() }),
|
experience = JsonTypeConverters.fromWorkExperienceList(experience.map { it.mapToDomain() }),
|
||||||
@@ -108,6 +112,12 @@ data class ExperienceDTO(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun WorkExperience.mapToData(): ExperienceDTO = ExperienceDTO(
|
||||||
|
place = place,
|
||||||
|
description = description,
|
||||||
|
monthDuration = monthDuration ?: 0
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class EducationDTO(
|
data class EducationDTO(
|
||||||
val place: String,
|
val place: String,
|
||||||
@@ -123,6 +133,13 @@ data class EducationDTO(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Education.mapToData(): EducationDTO = EducationDTO(
|
||||||
|
place = place,
|
||||||
|
grade = grade.mapToData(),
|
||||||
|
specialization = specialization,
|
||||||
|
description = description
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class EducationGradesDTO {
|
enum class EducationGradesDTO {
|
||||||
@SerialName("basic_general_education")
|
@SerialName("basic_general_education")
|
||||||
@@ -161,6 +178,18 @@ enum class EducationGradesDTO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun EducationGrades.mapToData(): EducationGradesDTO =
|
||||||
|
when (this) {
|
||||||
|
EducationGrades.BasicGeneralEducation -> EducationGradesDTO.BasicGeneralEducation
|
||||||
|
EducationGrades.SecondaryGeneralEducation -> EducationGradesDTO.SecondaryGeneralEducation
|
||||||
|
EducationGrades.SecondaryProfessionalEducation -> EducationGradesDTO.SecondaryProfessionalEducation
|
||||||
|
EducationGrades.Bachelor -> EducationGradesDTO.Bachelor
|
||||||
|
EducationGrades.Specialist -> EducationGradesDTO.Specialist
|
||||||
|
EducationGrades.Master -> EducationGradesDTO.Master
|
||||||
|
EducationGrades.PostgraduateStudies -> EducationGradesDTO.PostgraduateStudies
|
||||||
|
EducationGrades.Other -> EducationGradesDTO.Other
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ProjectDTO(
|
data class ProjectDTO(
|
||||||
val name: String,
|
val name: String,
|
||||||
@@ -172,6 +201,11 @@ data class ProjectDTO(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Project.mapToData(): ProjectDTO = ProjectDTO(
|
||||||
|
name = name,
|
||||||
|
description = description
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ResumeCreateDTO(
|
data class ResumeCreateDTO(
|
||||||
@SerialName("experience_type")
|
@SerialName("experience_type")
|
||||||
@@ -181,12 +215,24 @@ data class ResumeCreateDTO(
|
|||||||
@SerialName("key_skills")
|
@SerialName("key_skills")
|
||||||
val keySkills: List<String>,
|
val keySkills: List<String>,
|
||||||
val position: String,
|
val position: String,
|
||||||
|
@SerialName("location")
|
||||||
val city: String,
|
val city: String,
|
||||||
val experience: List<ExperienceDTO>,
|
val experience: List<ExperienceDTO>,
|
||||||
val education: List<EducationDTO>,
|
val education: List<EducationDTO>,
|
||||||
val project: List<ProjectDTO>,
|
val project: List<ProjectDTO>,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun ResumeCreationModel.mapToData(): ResumeCreateDTO = ResumeCreateDTO(
|
||||||
|
experienceType = experienceType.mapToData(),
|
||||||
|
aboutMe = about,
|
||||||
|
keySkills = skills,
|
||||||
|
position = position,
|
||||||
|
city = city,
|
||||||
|
experience = experience.map { it.mapToData() },
|
||||||
|
education = education.map { it.mapToData() },
|
||||||
|
project = projects.map { it.mapToData() }
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PredictionDTO(
|
data class PredictionDTO(
|
||||||
@SerialName("from_salary")
|
@SerialName("from_salary")
|
||||||
|
|||||||
+2
@@ -1,5 +1,6 @@
|
|||||||
package com.prodhack.moscow2025.data.repImplementations
|
package com.prodhack.moscow2025.data.repImplementations
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import com.prodhack.moscow2025.data.base.BaseRepository
|
import com.prodhack.moscow2025.data.base.BaseRepository
|
||||||
import com.prodhack.moscow2025.data.data_providers.api.ApiKtorClient
|
import com.prodhack.moscow2025.data.data_providers.api.ApiKtorClient
|
||||||
import com.prodhack.moscow2025.data.data_providers.localInfo.AuthorizationDataStore
|
import com.prodhack.moscow2025.data.data_providers.localInfo.AuthorizationDataStore
|
||||||
@@ -14,6 +15,7 @@ import io.ktor.http.ContentType
|
|||||||
import io.ktor.http.HttpMethod
|
import io.ktor.http.HttpMethod
|
||||||
import io.ktor.http.contentType
|
import io.ktor.http.contentType
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -8,6 +8,7 @@ import com.prodhack.moscow2025.data.dto.ResumeCreateDTO
|
|||||||
import com.prodhack.moscow2025.data.dto.ResumeIdDTO
|
import com.prodhack.moscow2025.data.dto.ResumeIdDTO
|
||||||
import com.prodhack.moscow2025.data.dto.ResumeListDTO
|
import com.prodhack.moscow2025.data.dto.ResumeListDTO
|
||||||
import com.prodhack.moscow2025.data.dto.ResumeSkillDTO
|
import com.prodhack.moscow2025.data.dto.ResumeSkillDTO
|
||||||
|
import com.prodhack.moscow2025.data.dto.mapToData
|
||||||
import com.prodhack.moscow2025.domain.interfaces.resumes.ResumeRepository
|
import com.prodhack.moscow2025.domain.interfaces.resumes.ResumeRepository
|
||||||
import com.prodhack.moscow2025.domain.models.ResumeCreationModel
|
import com.prodhack.moscow2025.domain.models.ResumeCreationModel
|
||||||
import com.prodhack.moscow2025.domain.models.ResumeModel
|
import com.prodhack.moscow2025.domain.models.ResumeModel
|
||||||
@@ -64,7 +65,7 @@ class ResumeRepositoryImpl(
|
|||||||
url("/resume")
|
url("/resume")
|
||||||
}
|
}
|
||||||
|
|
||||||
setBody(ResumeCreateDTO)
|
setBody(resumeForm.mapToData())
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
}.map { it.resumeId }
|
}.map { it.resumeId }
|
||||||
}
|
}
|
||||||
@@ -10,15 +10,15 @@ data class ResumeModel(
|
|||||||
val experience: List<WorkExperience>,
|
val experience: List<WorkExperience>,
|
||||||
val education: List<Education>,
|
val education: List<Education>,
|
||||||
val projects: List<Project>,
|
val projects: List<Project>,
|
||||||
val prediction: Pair<Int?, Int?>,
|
val prediction: Pair<Int?, Int?>?,
|
||||||
val recommendedSkills: List<String>
|
val recommendedSkills: List<String>?
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ResumeCreationModel(
|
data class ResumeCreationModel(
|
||||||
val position: String,
|
val position: String,
|
||||||
val about: String,
|
val about: String,
|
||||||
val skills: List<String>,
|
val skills: List<String>,
|
||||||
val city: String?,
|
val city: String,
|
||||||
val experienceType: ExperienceType,
|
val experienceType: ExperienceType,
|
||||||
val experience: List<WorkExperience>,
|
val experience: List<WorkExperience>,
|
||||||
val education: List<Education>,
|
val education: List<Education>,
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package com.prodhack.moscow2025.domain.usecase.resumes
|
||||||
|
|
||||||
|
import com.prodhack.moscow2025.domain.models.ResumeModel
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class GetResumeInfoUseCase {
|
||||||
|
operator fun invoke(): Flow<Result<ResumeModel>> {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
-29
@@ -10,35 +10,35 @@ import org.koin.core.annotation.Single
|
|||||||
|
|
||||||
@Single
|
@Single
|
||||||
class LoadResumeListUseCase(private val resumeRepository: ResumeRepository) {
|
class LoadResumeListUseCase(private val resumeRepository: ResumeRepository) {
|
||||||
// operator fun invoke(): RemotePagingWrapper<ResumeModel> = resumeRepository.loadResumeList()
|
operator fun invoke(): RemotePagingWrapper<ResumeModel> = resumeRepository.loadResumeList()
|
||||||
|
|
||||||
// Mocked data
|
// Mocked data
|
||||||
operator fun invoke(): RemotePagingWrapper<ResumeModel> = flow {
|
// operator fun invoke(): RemotePagingWrapper<ResumeModel> = flow {
|
||||||
emit(
|
// emit(
|
||||||
PagingData.from(
|
// PagingData.from(
|
||||||
listOf(
|
// listOf(
|
||||||
ResumeModel(
|
// ResumeModel(
|
||||||
id = "iajxioasdkmcaolsd,c",
|
// id = "iajxioasdkmcaolsd,c",
|
||||||
position = "Android разработчик",
|
// position = "Android разработчик",
|
||||||
about = "Ну оооочень крутой андроид разраб, с огромным количеством опыта. " +
|
// about = "Ну оооочень крутой андроид разраб, с огромным количеством опыта. " +
|
||||||
"И нет это я не про себя, это просто какие-то данные," +
|
// "И нет это я не про себя, это просто какие-то данные," +
|
||||||
" чтобы проверить, что это чудовище работает",
|
// " чтобы проверить, что это чудовище работает",
|
||||||
skills = listOf(
|
// skills = listOf(
|
||||||
"Android SDK",
|
// "Android SDK",
|
||||||
"Kotlin",
|
// "Kotlin",
|
||||||
"Room",
|
// "Room",
|
||||||
"Ktor"
|
// "Ktor"
|
||||||
),
|
// ),
|
||||||
experienceType = ExperienceType.Between3And6,
|
// experienceType = ExperienceType.Between3And6,
|
||||||
city = "Moscow",
|
// city = "Moscow",
|
||||||
experience = listOf(),
|
// experience = listOf(),
|
||||||
education = listOf(),
|
// education = listOf(),
|
||||||
projects = listOf(),
|
// projects = listOf(),
|
||||||
prediction = Pair(200000, 230000),
|
// prediction = Pair(200000, 230000),
|
||||||
recommendedSkills = listOf("KMP")
|
// recommendedSkills = listOf("KMP")
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.offset
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
@@ -36,6 +37,7 @@ import androidx.compose.ui.text.input.VisualTransformation
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.prodhack.moscow2025.R
|
import com.prodhack.moscow2025.R
|
||||||
|
import com.prodhack.moscow2025.presentation.theme.Paddings
|
||||||
import com.prodhack.moscow2025.presentation.utils.ui.noRippleClickable
|
import com.prodhack.moscow2025.presentation.utils.ui.noRippleClickable
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class)
|
||||||
@@ -254,6 +256,10 @@ fun <T> TTTextFieldWithDropdown(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dropdownItems.isEmpty()){
|
||||||
|
Text(modifier = Modifier.padding(Paddings.small), text = "Ничего нет", style = typography.labelLarge, fontSize = 16.sp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -362,6 +368,9 @@ fun <T> TTTextFieldWithSearch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (dropdownItems.isEmpty()){
|
||||||
|
Text(modifier = Modifier.padding(Paddings.small), text = "Ничего не нашлось", style = typography.labelLarge, fontSize = 16.sp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -11,7 +11,7 @@ data class UIResumeBaseInfo(
|
|||||||
fun ResumeModel.mapToBaseUIInfo(): UIResumeBaseInfo = UIResumeBaseInfo(
|
fun ResumeModel.mapToBaseUIInfo(): UIResumeBaseInfo = UIResumeBaseInfo(
|
||||||
id = id,
|
id = id,
|
||||||
positionName = position,
|
positionName = position,
|
||||||
salary = prediction.first?.let { from ->
|
salary = prediction?.first?.let { from ->
|
||||||
prediction.second?.let { to -> "$from-$to" } ?: from.toString()
|
prediction.second?.let { to -> "$from-$to₽" } ?: "$from₽"
|
||||||
} ?: prediction.second?.toString() ?: "Ошибка"
|
} ?: prediction?.second?.let { "$it₽" } ?: "Загрузка..."
|
||||||
)
|
)
|
||||||
@@ -118,7 +118,7 @@ fun TTasksNavHost(
|
|||||||
}
|
}
|
||||||
|
|
||||||
composable(AppDestination.ResumeCreation.route) {
|
composable(AppDestination.ResumeCreation.route) {
|
||||||
CreateResumeScreen()
|
CreateResumeScreen({ navController.popBackStack() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+298
-223
@@ -15,7 +15,7 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonColors
|
import androidx.compose.material3.ButtonColors
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -43,6 +43,7 @@ import org.koin.androidx.compose.koinViewModel
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CreateResumeScreen(
|
fun CreateResumeScreen(
|
||||||
|
goBack: () -> Unit,
|
||||||
viewModel: CreateResumeViewModel = koinViewModel()
|
viewModel: CreateResumeViewModel = koinViewModel()
|
||||||
) {
|
) {
|
||||||
val colorScheme = MaterialTheme.colorScheme
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
@@ -64,7 +65,8 @@ fun CreateResumeScreen(
|
|||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.rotate(180f)
|
.rotate(180f)
|
||||||
.size(24.dp),
|
.size(24.dp)
|
||||||
|
.noRippleClickable(goBack),
|
||||||
painter = painterResource(R.drawable.ic_arr_details),
|
painter = painterResource(R.drawable.ic_arr_details),
|
||||||
tint = colorScheme.onBackground,
|
tint = colorScheme.onBackground,
|
||||||
contentDescription = "go back"
|
contentDescription = "go back"
|
||||||
@@ -114,7 +116,7 @@ fun CreateResumeScreen(
|
|||||||
error = formState.value.errors[ResumeField.Experience],
|
error = formState.value.errors[ResumeField.Experience],
|
||||||
dropdownItems = viewModel.experienceOptions,
|
dropdownItems = viewModel.experienceOptions,
|
||||||
dropDownItem = {
|
dropDownItem = {
|
||||||
Text(text = it.friendlyName, style = typography.titleMedium, fontSize = 16.sp)
|
Text(text = it.friendlyName, style = typography.labelLarge, fontSize = 16.sp)
|
||||||
},
|
},
|
||||||
onDropdownItemSelected = viewModel::onExperienceSelect
|
onDropdownItemSelected = viewModel::onExperienceSelect
|
||||||
)
|
)
|
||||||
@@ -179,243 +181,316 @@ fun CreateResumeScreen(
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.large))
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
Text(
|
Card {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
Column(modifier = Modifier.padding(Paddings.medium)) {
|
||||||
text = "Подробнее о вашем опыте работы:",
|
Text(
|
||||||
style = typography.titleMedium,
|
modifier = Modifier.fillMaxWidth(),
|
||||||
fontSize = 20.sp,
|
text = "Подробнее о вашем опыте работы:",
|
||||||
textAlign = TextAlign.Center
|
style = typography.titleMedium,
|
||||||
)
|
fontSize = 20.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
Spacer(modifier = Modifier.height(Paddings.large))
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
|
|
||||||
formState.value.workExperience.forEachIndexed { index, workExp ->
|
|
||||||
Text(
|
|
||||||
text = "№${index + 1}:",
|
|
||||||
style = typography.labelLarge,
|
|
||||||
fontSize = 18.sp
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
|
||||||
TTTextField(
|
|
||||||
value = workExp.place,
|
|
||||||
onValueChange = {
|
|
||||||
viewModel.changeWorkExperiencePlace(index, it)
|
|
||||||
},
|
|
||||||
label = "Место работы",
|
|
||||||
error = formState.value.errors[ResumeField.WorkExperiencePlace(index)]
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
|
||||||
TTTextField(
|
|
||||||
value = workExp.description,
|
|
||||||
onValueChange = {
|
|
||||||
viewModel.changeWorkExperienceDescription(index, it)
|
|
||||||
},
|
|
||||||
singleLine = false,
|
|
||||||
maxLines = 10,
|
|
||||||
label = "Расскажите подробнее",
|
|
||||||
error = formState.value.errors[ResumeField.WorkExperienceDescription(index)]
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
|
||||||
TTTextField(
|
|
||||||
value = workExp.monthDuration?.toString() ?: "",
|
|
||||||
onValueChange = {
|
|
||||||
viewModel.changeWorkExperienceMonthDuration(index, it)
|
|
||||||
},
|
|
||||||
label = "Продолжительность (в месяцах)",
|
|
||||||
error = formState.value.errors[ResumeField.WorkExperienceMonthDuration(index)]
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formState.value.workExperience.isEmpty()) {
|
formState.value.workExperience.forEachIndexed { index, workExp ->
|
||||||
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::addNewExperience,
|
|
||||||
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.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)]
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
|
||||||
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(
|
||||||
text = it.friendlyName,
|
text = "№${index + 1}:",
|
||||||
style = typography.labelLarge,
|
style = typography.labelLarge,
|
||||||
fontSize = 16.sp
|
fontSize = 18.sp
|
||||||
)
|
)
|
||||||
},
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
onDropdownItemSelected = { viewModel.changeEducationGrade(index, it) }
|
TTTextField(
|
||||||
)
|
value = workExp.place,
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
onValueChange = {
|
||||||
TTTextField(
|
viewModel.changeWorkExperiencePlace(index, it)
|
||||||
value = education.specialization,
|
},
|
||||||
onValueChange = { viewModel.changeEducationSpecialization(index, it) },
|
label = "Место работы",
|
||||||
label = "Специализация",
|
error = formState.value.errors[ResumeField.WorkExperiencePlace(index)]
|
||||||
error = formState.value.errors[ResumeField.EducationSpecialization(index)]
|
)
|
||||||
)
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
TTTextField(
|
||||||
TTTextField(
|
value = workExp.description,
|
||||||
value = education.description,
|
onValueChange = {
|
||||||
onValueChange = { viewModel.changeEducationDescription(index, it) },
|
viewModel.changeWorkExperienceDescription(index, it)
|
||||||
singleLine = false,
|
},
|
||||||
maxLines = 10,
|
singleLine = false,
|
||||||
label = "Расскажите подробнее (опционально)",
|
maxLines = 10,
|
||||||
error = formState.value.errors[ResumeField.EducationDescription(index)]
|
label = "Расскажите подробнее",
|
||||||
)
|
error = formState.value.errors[ResumeField.WorkExperienceDescription(
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
index
|
||||||
}
|
)]
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
TTTextField(
|
||||||
|
value = workExp.monthDuration?.toString() ?: "",
|
||||||
|
onValueChange = {
|
||||||
|
viewModel.changeWorkExperienceMonthDuration(index, it)
|
||||||
|
},
|
||||||
|
label = "Продолжительность (в месяцах)",
|
||||||
|
error = formState.value.errors[ResumeField.WorkExperienceMonthDuration(
|
||||||
|
index
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
shape = Shapes.smallRoundedBox,
|
||||||
|
onClick = { viewModel.removeExperience(index) },
|
||||||
|
colors = ButtonColors(
|
||||||
|
containerColor = colorScheme.errorContainer,
|
||||||
|
contentColor = colorScheme.onErrorContainer,
|
||||||
|
disabledContainerColor = colorScheme.errorContainer,
|
||||||
|
disabledContentColor = colorScheme.onErrorContainer
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Удалить",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
}
|
||||||
|
|
||||||
if (formState.value.education.isEmpty()) {
|
if (formState.value.workExperience.isEmpty()) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = "Пока ничего нет",
|
text = "Пока ничего нет",
|
||||||
style = typography.labelLarge,
|
style = typography.labelLarge,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
shape = Shapes.smallRoundedBox,
|
shape = Shapes.smallRoundedBox,
|
||||||
onClick = viewModel::addNewEducation,
|
onClick = viewModel::addNewExperience,
|
||||||
colors = ButtonColors(
|
colors = ButtonColors(
|
||||||
containerColor = colorScheme.onSecondary,
|
containerColor = colorScheme.onSecondary,
|
||||||
contentColor = colorScheme.secondary,
|
contentColor = colorScheme.secondary,
|
||||||
disabledContainerColor = colorScheme.onSecondary,
|
disabledContainerColor = colorScheme.onSecondary,
|
||||||
disabledContentColor = colorScheme.secondary
|
disabledContentColor = colorScheme.secondary
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Добавить",
|
text = "Добавить",
|
||||||
style = typography.labelLarge,
|
style = typography.labelLarge,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
|
Card {
|
||||||
|
Column(modifier = Modifier.padding(Paddings.medium)) {
|
||||||
|
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)]
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
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.labelLarge,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onDropdownItemSelected = { viewModel.changeEducationGrade(index, it) }
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
TTTextField(
|
||||||
|
value = education.specialization,
|
||||||
|
onValueChange = { viewModel.changeEducationSpecialization(index, it) },
|
||||||
|
label = "Специализация",
|
||||||
|
error = formState.value.errors[ResumeField.EducationSpecialization(index)]
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
TTTextField(
|
||||||
|
value = education.description,
|
||||||
|
onValueChange = { viewModel.changeEducationDescription(index, it) },
|
||||||
|
singleLine = false,
|
||||||
|
maxLines = 10,
|
||||||
|
label = "Расскажите подробнее (опционально)",
|
||||||
|
error = formState.value.errors[ResumeField.EducationDescription(index)]
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
shape = Shapes.smallRoundedBox,
|
||||||
|
onClick = { viewModel.removeEducation(index) },
|
||||||
|
colors = ButtonColors(
|
||||||
|
containerColor = colorScheme.errorContainer,
|
||||||
|
contentColor = colorScheme.onErrorContainer,
|
||||||
|
disabledContainerColor = colorScheme.errorContainer,
|
||||||
|
disabledContentColor = colorScheme.onErrorContainer
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Удалить",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
Text(
|
Card {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
Column(modifier = Modifier.padding(Paddings.medium)) {
|
||||||
text = "Интересные проекты:",
|
Text(
|
||||||
style = typography.titleMedium,
|
modifier = Modifier.fillMaxWidth(),
|
||||||
fontSize = 20.sp,
|
text = "Интересные проекты:",
|
||||||
textAlign = TextAlign.Center
|
style = typography.titleMedium,
|
||||||
)
|
fontSize = 20.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.large))
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
formState.value.projects.forEachIndexed { index, project ->
|
formState.value.projects.forEachIndexed { index, project ->
|
||||||
Text(
|
Text(
|
||||||
text = "№${index + 1}:",
|
text = "№${index + 1}:",
|
||||||
style = typography.labelLarge,
|
style = typography.labelLarge,
|
||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
|
||||||
TTTextField(
|
TTTextField(
|
||||||
value = project.name,
|
value = project.name,
|
||||||
onValueChange = { viewModel.changeProjectName(index, it) },
|
onValueChange = { viewModel.changeProjectName(index, it) },
|
||||||
label = "Название проекта",
|
label = "Название проекта",
|
||||||
error = formState.value.errors[ResumeField.ProjectName(index)]
|
error = formState.value.errors[ResumeField.ProjectName(index)]
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
TTTextField(
|
TTTextField(
|
||||||
value = project.description,
|
value = project.description,
|
||||||
onValueChange = { viewModel.changeProjectDescription(index, it) },
|
onValueChange = { viewModel.changeProjectDescription(index, it) },
|
||||||
singleLine = false,
|
singleLine = false,
|
||||||
maxLines = 10,
|
maxLines = 10,
|
||||||
label = "Расскажите подробнее",
|
label = "Расскажите подробнее",
|
||||||
error = formState.value.errors[ResumeField.ProjectDescription(index)]
|
error = formState.value.errors[ResumeField.ProjectDescription(index)]
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
}
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
shape = Shapes.smallRoundedBox,
|
||||||
|
onClick = { viewModel.removeProject(index) },
|
||||||
|
colors = ButtonColors(
|
||||||
|
containerColor = colorScheme.errorContainer,
|
||||||
|
contentColor = colorScheme.onErrorContainer,
|
||||||
|
disabledContainerColor = colorScheme.errorContainer,
|
||||||
|
disabledContentColor = colorScheme.onErrorContainer
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Удалить",
|
||||||
|
style = typography.labelLarge,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (formState.value.projects.isEmpty()) {
|
if (formState.value.projects.isEmpty()) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = "Пока ничего нет",
|
text = "Пока ничего нет",
|
||||||
style = typography.labelLarge,
|
style = typography.labelLarge,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(Paddings.medium))
|
Spacer(modifier = Modifier.height(Paddings.medium))
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
shape = Shapes.smallRoundedBox,
|
shape = Shapes.smallRoundedBox,
|
||||||
onClick = viewModel::addNewProject,
|
onClick = viewModel::addNewProject,
|
||||||
colors = ButtonColors(
|
colors = ButtonColors(
|
||||||
containerColor = colorScheme.onSecondary,
|
containerColor = colorScheme.onSecondary,
|
||||||
contentColor = colorScheme.secondary,
|
contentColor = colorScheme.secondary,
|
||||||
disabledContainerColor = colorScheme.onSecondary,
|
disabledContainerColor = colorScheme.onSecondary,
|
||||||
disabledContentColor = colorScheme.secondary
|
disabledContentColor = colorScheme.secondary
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Добавить",
|
text = "Добавить",
|
||||||
style = typography.labelLarge,
|
style = typography.labelLarge,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(Paddings.large))
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|||||||
+28
-3
@@ -80,9 +80,9 @@ sealed class UIEducationGrade(val friendlyName: String) {
|
|||||||
data object Specialist : UIEducationGrade("Специалитет")
|
data object Specialist : UIEducationGrade("Специалитет")
|
||||||
data object Master : UIEducationGrade("Магистратура")
|
data object Master : UIEducationGrade("Магистратура")
|
||||||
|
|
||||||
data object PostgraduateStudies: UIEducationGrade("Аспирантура и выше")
|
data object PostgraduateStudies : UIEducationGrade("Аспирантура и выше")
|
||||||
|
|
||||||
data object Other: UIEducationGrade("Другое")
|
data object Other : UIEducationGrade("Другое")
|
||||||
|
|
||||||
fun mapToDomain(): EducationGrades = when (this) {
|
fun mapToDomain(): EducationGrades = when (this) {
|
||||||
BasicGeneralEducation -> EducationGrades.BasicGeneralEducation
|
BasicGeneralEducation -> EducationGrades.BasicGeneralEducation
|
||||||
@@ -161,6 +161,7 @@ class CreateResumeViewModel(
|
|||||||
errors = it.errors - ResumeField.KeySkills
|
errors = it.errors - ResumeField.KeySkills
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
skillSearchQuery.value = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRemoveSkill(value: String) {
|
fun onRemoveSkill(value: String) {
|
||||||
@@ -270,6 +271,19 @@ class CreateResumeViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeEducation(id: Int) {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
education = it.education.filterIndexed { index, _ -> index != id },
|
||||||
|
errors = it.errors
|
||||||
|
- ResumeField.EducationSpecialization(id)
|
||||||
|
- ResumeField.EducationDescription(id)
|
||||||
|
- ResumeField.EducationPlace(id)
|
||||||
|
- ResumeField.EducationGrade(id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun changeEducationPlace(index: Int, value: String) {
|
fun changeEducationPlace(index: Int, value: String) {
|
||||||
_formStateFillResume.update {
|
_formStateFillResume.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
@@ -323,6 +337,17 @@ class CreateResumeViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeProject(id: Int) {
|
||||||
|
_formStateFillResume.update {
|
||||||
|
it.copy(
|
||||||
|
projects = it.projects.filterIndexed { index, _ -> index != id },
|
||||||
|
errors = it.errors
|
||||||
|
- ResumeField.ProjectDescription(id)
|
||||||
|
- ResumeField.ProjectName(id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun changeProjectName(index: Int, value: String) {
|
fun changeProjectName(index: Int, value: String) {
|
||||||
_formStateFillResume.update {
|
_formStateFillResume.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
@@ -372,7 +397,7 @@ class CreateResumeViewModel(
|
|||||||
about = about,
|
about = about,
|
||||||
skills = keySkills.toList(),
|
skills = keySkills.toList(),
|
||||||
experienceType = experience!!.mapToDomain(),
|
experienceType = experience!!.mapToDomain(),
|
||||||
city = city.ifBlank { null },
|
city = city,
|
||||||
experience = workExperience,
|
experience = workExperience,
|
||||||
education = education.map {
|
education = education.map {
|
||||||
Education(
|
Education(
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ fun ErrorCollectorScope.MainScreen(
|
|||||||
color = colorScheme.onBackground
|
color = colorScheme.onBackground
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(Paddings.large))
|
||||||
|
|
||||||
BigButton(
|
BigButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
TODO()
|
TODO()
|
||||||
@@ -165,7 +167,7 @@ fun ResumeShortInfoCard(
|
|||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
"${info.salary}₽",
|
info.salary,
|
||||||
style = typography.titleMedium,
|
style = typography.titleMedium,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
|
|||||||
-2
@@ -17,6 +17,4 @@ fun ResumeDetailsScreen(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Text("Opened resume details for id ${navBackStackEntry.arguments?.getString(AppDestination.ResumeDetails.ARG_ID, "") ?: ""}")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+3
-1
@@ -1,11 +1,13 @@
|
|||||||
package com.prodhack.moscow2025.presentation.screens.resumeDetails
|
package com.prodhack.moscow2025.presentation.screens.resumeDetails
|
||||||
|
|
||||||
|
import com.prodhack.moscow2025.domain.usecase.resumes.GetResumeInfoUseCase
|
||||||
import com.prodhack.moscow2025.presentation.utils.base.BaseViewModel
|
import com.prodhack.moscow2025.presentation.utils.base.BaseViewModel
|
||||||
import org.koin.android.annotation.KoinViewModel
|
import org.koin.android.annotation.KoinViewModel
|
||||||
import org.koin.core.annotation.Provided
|
import org.koin.core.annotation.Provided
|
||||||
|
|
||||||
@KoinViewModel
|
@KoinViewModel
|
||||||
class ResumeDetailsViewModel(
|
class ResumeDetailsViewModel(
|
||||||
@Provided resumeId: String
|
@Provided resumeId: String,
|
||||||
|
private val getResumeInfoUseCase: GetResumeInfoUseCase
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user