diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 0eedfd2..e939ed0 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -25,12 +25,12 @@
+
-
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index cde3e19..7061a0d 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -49,6 +49,10 @@
+
+
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 57db0cd..80ff040 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -82,6 +82,7 @@ dependencies {
implementation(project(":feature_jobs"))
implementation(project(":feature_vacansies"))
implementation(project(":core"))
+ implementation(project(":feature_vacancy"))
androidTestImplementation(Deps.TestDeps.androidxEspressoCore)
androidTestImplementation(Deps.TestDeps.jUnit)
diff --git a/app/src/main/java/com/codereview/navigation/CodeReviewNavHost.kt b/app/src/main/java/com/codereview/navigation/CodeReviewNavHost.kt
index e34db9b..98f6106 100644
--- a/app/src/main/java/com/codereview/navigation/CodeReviewNavHost.kt
+++ b/app/src/main/java/com/codereview/navigation/CodeReviewNavHost.kt
@@ -6,10 +6,12 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.codereview.feature_jobs.HomePage
import com.codereview.feature_jobs.HomeScreen
+import com.codereview.feature_vacancy.VacancyScreen
import com.codereview.feature_vacansies.VacanciesScreen
import com.codereview.feature_vacansies.VacancyList
private const val VACANCIES_ARG = "vacanciesArg"
+private const val VACANCY_ARG = "vacancyArg"
@Composable
fun CodeReviewNavHost(navHostController: NavHostController) {
@@ -28,7 +30,20 @@ fun CodeReviewNavHost(navHostController: NavHostController) {
composable(route = VacanciesDestination.route + "/{$VACANCIES_ARG}") { entry ->
val vacanciesArg = entry.arguments?.getString(VACANCIES_ARG)
- VacanciesScreen(vacanciesArg = vacanciesArg)
+ VacanciesScreen(
+ vacanciesArg = vacanciesArg,
+ onNavigateToVacancy = { vacancyArg ->
+ navHostController
+ .navigateSingleTopTo(VacancyDestination.route + vacancyArg)
+ }
+ )
+ }
+ composable(route = VacancyDestination.route + "/{$VACANCY_ARG}") { entry ->
+ val vacancyArg = entry.arguments?.getString(VACANCY_ARG)
+ VacancyScreen(
+ vacancyId = vacancyArg,
+ navigateUp = { navHostController.navigateUp() }
+ )
}
}
}
diff --git a/app/src/main/java/com/codereview/navigation/Route.kt b/app/src/main/java/com/codereview/navigation/Route.kt
index de06f95..e75a5d7 100644
--- a/app/src/main/java/com/codereview/navigation/Route.kt
+++ b/app/src/main/java/com/codereview/navigation/Route.kt
@@ -10,4 +10,8 @@ object HomePageDestination : Route {
object VacanciesDestination : Route {
override val route: String = "vacancies"
+}
+
+object VacancyDestination: Route {
+ override val route: String = "vacancy"
}
\ No newline at end of file
diff --git a/feature_vacansies/src/main/java/com/codereview/feature_vacansies/VacancyList.kt b/feature_vacansies/src/main/java/com/codereview/feature_vacansies/VacancyList.kt
index 69d9062..74b28ba 100644
--- a/feature_vacansies/src/main/java/com/codereview/feature_vacansies/VacancyList.kt
+++ b/feature_vacansies/src/main/java/com/codereview/feature_vacansies/VacancyList.kt
@@ -46,6 +46,7 @@ fun VacanciesScreen(
modifier: Modifier = Modifier,
vacanciesArg: String?,
viewModel: VacanciesViewModel = hiltViewModel(),
+ onNavigateToVacancy: (String) -> Unit
) {
val state by viewModel.state.collectAsStateWithLifecycle()
@@ -68,7 +69,7 @@ fun VacanciesScreen(
val vacancies = (state as VacanciesState.Ready).data
VacancyList(
vacancies = vacancies,
- onVacancyClick = viewModel::onVacancyClick
+ onNavigateToVacancy = onNavigateToVacancy,
)
}
}
@@ -77,7 +78,7 @@ fun VacanciesScreen(
@Composable
fun VacancyList(
vacancies: List,
- onVacancyClick: (String) -> Unit,
+ onNavigateToVacancy: (String) -> Unit,
) {
LazyColumn(
Modifier
@@ -87,7 +88,8 @@ fun VacancyList(
items(vacancies) { vacancy ->
VacancyItem(
vacancy = vacancy,
- onItemClick = onVacancyClick
+ onItemClick = onNavigateToVacancy,
+ idOfVacancy = vacancy.id
)
}
}
@@ -96,6 +98,7 @@ fun VacancyList(
@Composable
fun VacancyItem(
vacancy: Vacancy,
+ idOfVacancy: String,
onItemClick: (String) -> Unit,
) {
Column(
@@ -104,7 +107,7 @@ fun VacancyItem(
.padding(horizontal = 16.dp, vertical = 8.dp)
.clip(RoundedCornerShape(32.dp))
.background(color = Color.White)
- .clickable { onItemClick(vacancy.url) },
+ .clickable { onItemClick("/$idOfVacancy") },
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
diff --git a/network/src/main/java/com/codereview/network/ApiHelper.kt b/network/src/main/java/com/codereview/network/ApiHelper.kt
index 886baac..759f6ef 100644
--- a/network/src/main/java/com/codereview/network/ApiHelper.kt
+++ b/network/src/main/java/com/codereview/network/ApiHelper.kt
@@ -3,13 +3,16 @@ package com.codereview.network
import com.codereview.network.model.VacancyList
import com.codereview.network.model.VacancyNet
import kotlinx.coroutines.flow.Flow
+import kotlinx.serialization.InternalSerializationApi
interface ApiHelper {
+ @OptIn(InternalSerializationApi::class)
fun getVacancyList(
limit: Int = 100,
specialities: String,
): Flow
- fun getVacancyDetails(id: Int): Flow
+ @OptIn(InternalSerializationApi::class)
+ fun getVacancyDetails(id: String): Flow
}
\ No newline at end of file
diff --git a/network/src/main/java/com/codereview/network/ApiHelperImpl.kt b/network/src/main/java/com/codereview/network/ApiHelperImpl.kt
index 0bbcf83..c3b3ec6 100644
--- a/network/src/main/java/com/codereview/network/ApiHelperImpl.kt
+++ b/network/src/main/java/com/codereview/network/ApiHelperImpl.kt
@@ -4,9 +4,11 @@ import com.codereview.network.model.VacancyList
import com.codereview.network.model.VacancyNet
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
+import kotlinx.serialization.InternalSerializationApi
import javax.inject.Inject
class ApiHelperImpl @Inject constructor(private val apiService: ApiService) : ApiHelper {
+ @OptIn(InternalSerializationApi::class)
override fun getVacancyList(
limit: Int,
specialities: String,
@@ -15,7 +17,8 @@ class ApiHelperImpl @Inject constructor(private val apiService: ApiService) : Ap
emit(vacancyList)
}
- override fun getVacancyDetails(id: Int): Flow = flow {
+ @OptIn(InternalSerializationApi::class)
+ override fun getVacancyDetails(id: String): Flow = flow {
emit(apiService.getVacancy(id))
}
}
\ No newline at end of file
diff --git a/network/src/main/java/com/codereview/network/ApiService.kt b/network/src/main/java/com/codereview/network/ApiService.kt
index 2fec006..fe47426 100644
--- a/network/src/main/java/com/codereview/network/ApiService.kt
+++ b/network/src/main/java/com/codereview/network/ApiService.kt
@@ -1,13 +1,14 @@
package com.codereview.network
-import com.codereview.network.model.VacanciesNet
import com.codereview.network.model.VacancyList
import com.codereview.network.model.VacancyNet
+import kotlinx.serialization.InternalSerializationApi
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
interface ApiService {
+ @OptIn(InternalSerializationApi::class)
@GET("jobs/")
suspend fun getVacancies(
@Query("skip") skip: Int = 0,
@@ -15,8 +16,9 @@ interface ApiService {
@Query("specialities") specialities: String,
): VacancyList
- @GET("api/jobs/{vacancy_id}")
+ @OptIn(InternalSerializationApi::class)
+ @GET("jobs/{vacancy_id}")
suspend fun getVacancy(
- @Path("vacancy_id") vacancyId: Int
+ @Path("vacancy_id") vacancyId: String
): VacancyNet
}
\ No newline at end of file
diff --git a/network/src/main/java/com/codereview/network/model/VacanciesNet.kt b/network/src/main/java/com/codereview/network/model/VacanciesNet.kt
index 68b2260..e1d7dc8 100644
--- a/network/src/main/java/com/codereview/network/model/VacanciesNet.kt
+++ b/network/src/main/java/com/codereview/network/model/VacanciesNet.kt
@@ -1,10 +1,11 @@
package com.codereview.network.model
+import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-@Serializable
+@InternalSerializationApi @Serializable
data class VacanciesNet(
@SerialName("total_count")
val totalCount: Int,
diff --git a/network/src/main/java/com/codereview/network/model/VacancyNet.kt b/network/src/main/java/com/codereview/network/model/VacancyNet.kt
index b4cf79f..798c4c3 100644
--- a/network/src/main/java/com/codereview/network/model/VacancyNet.kt
+++ b/network/src/main/java/com/codereview/network/model/VacancyNet.kt
@@ -1,15 +1,16 @@
package com.codereview.network.model
+import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-@Serializable
+@InternalSerializationApi @Serializable
data class VacancyList(
@SerialName("total_count" ) var totalCount : Int? = null,
@SerialName("data" ) var data : ArrayList = arrayListOf()
)
-@Serializable
+@InternalSerializationApi @Serializable
data class VacancyNet(
@SerialName("company_name" ) var companyName : String? = null,
@SerialName("salary" ) var salary : String? = null,
diff --git a/repository/src/main/java/com/codereview/repository/vacancy_repository/Vacancy.kt b/repository/src/main/java/com/codereview/repository/vacancy_repository/Vacancy.kt
index 965438d..900e828 100644
--- a/repository/src/main/java/com/codereview/repository/vacancy_repository/Vacancy.kt
+++ b/repository/src/main/java/com/codereview/repository/vacancy_repository/Vacancy.kt
@@ -1,5 +1,8 @@
package com.codereview.repository.vacancy_repository
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
+
data class Vacancy(
val id: String,
val active: Boolean,
@@ -12,7 +15,8 @@ data class Vacancy(
val title: String,
val externalId: String,
val location: String,
- val internship: Boolean
+ val internship: Boolean,
+ val datePublication: String,
) {
fun getExtras(): Iterator> {
@@ -30,4 +34,39 @@ data class Vacancy(
if (this?.isBlank() == true) "з/п не указана"
else "$this"
+ fun formatSalary(salary: String?): String {
+ return when {
+ salary.isNullOrBlank() -> "з/п не указана"
+ salary.equals("null", ignoreCase = true) -> "з/п не указана"
+ else -> {
+ val cleaned = salary
+ .removePrefix("$")
+ .replace("$", "")
+ .replace(",", "")
+ .replace(" ", "")
+ .replace("-", " - ")
+ .trim()
+
+ when {
+ cleaned.isEmpty() -> "з/п не указана"
+ cleaned.contains("RUR", ignoreCase = true) -> cleaned
+ .replace("RUR", " RUR")
+ .trim()
+ else -> "$cleaned \$"
+ }
+ }
+ }
+ }
+
+ fun formatDate(isoDate: String): String {
+ val inputFormatter = DateTimeFormatter.ISO_DATE_TIME
+ val outputFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
+
+ return try {
+ val dateTime = LocalDateTime.parse(isoDate, inputFormatter)
+ dateTime.format(outputFormatter)
+ } catch (e: Exception) {
+ "Некорректная дата"
+ }
+ }
}
\ No newline at end of file
diff --git a/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyMapper.kt b/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyMapper.kt
index 43c7bb1..8f3cb7b 100644
--- a/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyMapper.kt
+++ b/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyMapper.kt
@@ -14,5 +14,6 @@ fun VacancyNet.toVacancy(): Vacancy = Vacancy(
title = title.toString(),
externalId = externalId ?: "",
location = location.orEmpty(),
- internship = internship ?: false
+ internship = internship ?: false,
+ datePublication = datePublication ?: ""
)
\ No newline at end of file
diff --git a/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyRepository.kt b/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyRepository.kt
index 2cf114a..c14852c 100644
--- a/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyRepository.kt
+++ b/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyRepository.kt
@@ -9,6 +9,6 @@ interface VacancyRepository {
specialities: String,
): Flow>
- fun getVacancyDetails(id: Int): Flow
+ fun getVacancyDetails(id: String): Flow
}
\ No newline at end of file
diff --git a/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyRepositoryImpl.kt b/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyRepositoryImpl.kt
index 57c5297..cecd423 100644
--- a/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyRepositoryImpl.kt
+++ b/repository/src/main/java/com/codereview/repository/vacancy_repository/VacancyRepositoryImpl.kt
@@ -23,7 +23,7 @@ class VacancyRepositoryImpl @Inject constructor(private val apiHelper: ApiHelper
emitAll(vacancies)
}
- override fun getVacancyDetails(id: Int): Flow = flow {
+ override fun getVacancyDetails(id: String): Flow = flow {
val vacancy = apiHelper.getVacancyDetails(id).map { vacancyNet -> vacancyNet.toVacancy() }
emitAll(vacancy)
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index db88ab8..de3d9fc 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -5,3 +5,4 @@ include(":feature_jobs")
include(":core")
include(":network")
include(":repository")
+include(":feature_vacancy")