Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Реализация Data слоя поиска #36

Merged
merged 10 commits into from
Aug 7, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package ru.practicum.android.diploma.data.components

data class Address(val raw: String?)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ru.practicum.android.diploma.data.components

data class Area(
val id: Int,
val name: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.practicum.android.diploma.data.components

data class Contacts(
val email: String,
val name: String,
val phones: List<Phone>?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.practicum.android.diploma.data.components

import com.google.gson.annotations.SerializedName

data class Employer(
val name: String,
@SerializedName("logo_urls") val logoUrls: LogoUrls?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ru.practicum.android.diploma.data.components

data class Employment(
val id: String,
val name: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ru.practicum.android.diploma.data.components

data class Experience(
val id: String,
val name: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ru.practicum.android.diploma.data.components

data class KeySkill(
val name: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.practicum.android.diploma.data.components

import com.google.gson.annotations.SerializedName

data class LogoUrls(
@SerializedName("240") val logo240: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.practicum.android.diploma.data.components

data class Phone(
val city: String,
val comment: String?,
val country: String,
val formatted: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.practicum.android.diploma.data.components

data class Salary(
val currency: String?,
val from: Int?,
val to: Int?,
val gross: Boolean?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ru.practicum.android.diploma.data.components

data class Schedule(
val id: String,
val name: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ru.practicum.android.diploma.data.dto

import ru.practicum.android.diploma.domain.models.Vacancy

fun VacancyDto.toVacancy(): Vacancy {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мы же вроде догаваривались что не будем писать конвертеры, а делать все через .map? Как например в файле data class Options

return Vacancy(
id = id,
name = name,
company = employer.name,
currency = salary?.currency.orEmpty(),
salaryFrom = salary?.from,
salaryTo = salary?.to,
area = area.name,
icon = employer.logoUrls?.logo240 ?: ""
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ const val RESULT_CODE_SUCCESS = 200
const val RESULT_CODE_BAD_REQUEST = 400
const val RESULT_CODE_SERVER_ERROR = 500

class Response {
open class Response {
var resultCode = 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.practicum.android.diploma.data.dto

data class SearchResponse(
val items: List<VacancyDto>,
val found: Int,
val pages: Int,
val page: Int,
) : Response()
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ru.practicum.android.diploma.data.dto

import ru.practicum.android.diploma.data.components.Area
import ru.practicum.android.diploma.data.components.Employer
import ru.practicum.android.diploma.data.components.Salary

data class VacancyDto(
val id: Int,
val name: String,
val employer: Employer,
val salary: Salary?,
val area: Area
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ru.practicum.android.diploma.data.dto

import com.google.gson.annotations.SerializedName
import ru.practicum.android.diploma.data.components.Address
import ru.practicum.android.diploma.data.components.Area
import ru.practicum.android.diploma.data.components.Contacts
import ru.practicum.android.diploma.data.components.Employer
import ru.practicum.android.diploma.data.components.Employment
import ru.practicum.android.diploma.data.components.Experience
import ru.practicum.android.diploma.data.components.KeySkill
import ru.practicum.android.diploma.data.components.Salary
import ru.practicum.android.diploma.data.components.Schedule

data class VacancyResponse(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может лучше id сделать Long? Я думаю id может быть большим числом.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Снимок экрана 2024-08-07 в 10 09 09 Думаете не влезет?

val id: Int,
val name: String,
val employer: Employer,
val salary: Salary?,
val area: Area,
@SerializedName("alternate_url")
val alternateUrl: String,
val description: String,
val employment: Employment?,
val experience: Experience?,
val schedule: Schedule?,
val contacts: Contacts?,
@SerializedName("key_skills")
val keySkills: List<KeySkill>,
val address: Address?
) : Response()
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package ru.practicum.android.diploma.data.impl

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import ru.practicum.android.diploma.data.dto.RESULT_CODE_BAD_REQUEST
import ru.practicum.android.diploma.data.dto.RESULT_CODE_NO_INTERNET
import ru.practicum.android.diploma.data.dto.Response
import ru.practicum.android.diploma.data.dto.SearchRequest
import ru.practicum.android.diploma.data.dto.SearchResponse
import ru.practicum.android.diploma.data.dto.VacancyDto
import ru.practicum.android.diploma.data.dto.toVacancy
import ru.practicum.android.diploma.data.network.NetworkClient
import ru.practicum.android.diploma.domain.api.SearchRepository
import ru.practicum.android.diploma.domain.models.VacanciesResponse
import ru.practicum.android.diploma.util.Options
import ru.practicum.android.diploma.util.ResponseData

class SearchRepositoryImpl(private val networkClient: NetworkClient) : SearchRepository {

override fun search(options: Options): Flow<ResponseData<VacanciesResponse>> = flow {
emit(
when (val response = networkClient.doRequest(SearchRequest(Options.toMap(options)))) {
is SearchResponse -> {
with(response) {
val vacanciesResponse = VacanciesResponse(
items.map(VacancyDto::toVacancy),
found,
page,
pages,
)
ResponseData.Data(vacanciesResponse)
}
}

else -> {
responseToError(response)
}
}
)
}

private fun responseToError(response: Response): ResponseData<VacanciesResponse> =
ResponseData.Error(
when (response.resultCode) {
RESULT_CODE_NO_INTERNET -> {
ResponseData.ResponseError.NO_INTERNET
}

RESULT_CODE_BAD_REQUEST -> {
ResponseData.ResponseError.CLIENT_ERROR
}

else -> {
ResponseData.ResponseError.SERVER_ERROR
}
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ru.practicum.android.diploma.data.interceptors

import okhttp3.Headers
import okhttp3.Interceptor
import okhttp3.Response
import ru.practicum.android.diploma.BuildConfig

object HeaderInterceptor : Interceptor {
private const val USER_AGENT_AUTHORIZATION = "Authorization: Bearer ${BuildConfig.HH_ACCESS_TOKEN}"
private const val USER_AGENT_APP_NAME = "HH-User-Agent: CareerHub ([email protected])"

private val headers = Headers.Builder()
.add(USER_AGENT_AUTHORIZATION)
.add(USER_AGENT_APP_NAME)
.build()

override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.headers(headers)
.build()

return chain.proceed(request)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package ru.practicum.android.diploma.data.interceptors

import android.util.Log
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import okio.Buffer
import java.nio.charset.Charset
import kotlin.math.min

object LoggingInterceptor : Interceptor {
private val CHARSET: Charset = Charset.forName("UTF-8")
private const val MAX_LOGCAT_SIZE = 4_000L
private const val LOGCAT_TAG = "LoggingInterceptor"

override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
logRequest(request)

val response = chain.proceed(request)
logResponse(response)
return response
}

private fun logRequest(request: Request) {
logD("request =>\n${request.url()}")
val buffer = Buffer()
request.body()?.writeTo(buffer)
while (!buffer.exhausted()) {
logD(buffer.readString(min(MAX_LOGCAT_SIZE, buffer.size()), CHARSET))
}
}

private fun logResponse(response: Response) {
response.body()?.apply {
source().request(Long.MAX_VALUE)
val buffer = source().buffer.clone()
logD("response =>\n")
while (!buffer.exhausted()) {
logD(buffer.readString(min(MAX_LOGCAT_SIZE, buffer.size()), CHARSET))
}
}
}

private fun logD(message: String) {
Log.d(LOGCAT_TAG, message)
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
package ru.practicum.android.diploma.data.network

import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.Path
import retrofit2.http.QueryMap
import ru.practicum.android.diploma.BuildConfig
import ru.practicum.android.diploma.data.dto.Response

const val USER_AGENT_AUTHORIZATION = "Authorization: Bearer ${BuildConfig.HH_ACCESS_TOKEN}"
const val USER_AGENT_APP_NAME = "HH-User-Agent: CareerHub ([email protected])"
import ru.practicum.android.diploma.data.dto.SearchResponse
import ru.practicum.android.diploma.data.dto.VacancyResponse

interface HHApiService {
@Headers(USER_AGENT_AUTHORIZATION, USER_AGENT_APP_NAME)
@GET("vacancies/{vacancy_id}")
suspend fun getVacancy(@Path("vacancy_id") id: Int): Response
suspend fun getVacancy(@Path("vacancy_id") id: Int): VacancyResponse

@Headers(USER_AGENT_AUTHORIZATION, USER_AGENT_APP_NAME)
@GET("vacancies")
suspend fun searchVacancies(@QueryMap options: Map<String, String>): Response
suspend fun searchVacancies(@QueryMap options: Map<String, String>): SearchResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ class RetrofitNetworkClient(
if (!isInternetAvailable(context)) {
return Response().apply { resultCode = RESULT_CODE_NO_INTERNET }
}
return getResponce(dto = dto)
return getResponse(dto = dto)
}

private suspend fun getResponce(dto: Any): Response {
private suspend fun getResponse(dto: Any): Response {
return withContext(Dispatchers.IO) {
try {
when (dto) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package ru.practicum.android.diploma.di

import androidx.room.Room
import okhttp3.OkHttpClient
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import ru.practicum.android.diploma.data.db.AppDatabase
import ru.practicum.android.diploma.data.interceptors.HeaderInterceptor
import ru.practicum.android.diploma.data.interceptors.LoggingInterceptor
import ru.practicum.android.diploma.data.network.HHApiService
import ru.practicum.android.diploma.data.network.NetworkClient
import ru.practicum.android.diploma.data.network.RetrofitNetworkClient
Expand All @@ -20,8 +23,14 @@ val dataModule = module {
}

single<HHApiService> {
val client = OkHttpClient.Builder()
.addInterceptor(LoggingInterceptor)
.addInterceptor(HeaderInterceptor)
.build()

Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(HHApiService::class.java)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ru.practicum.android.diploma.domain.api

import kotlinx.coroutines.flow.Flow
import ru.practicum.android.diploma.domain.models.VacanciesResponse
import ru.practicum.android.diploma.util.Options
import ru.practicum.android.diploma.util.ResponseData

interface SearchRepository {
fun search(options: Options): Flow<ResponseData<VacanciesResponse>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.practicum.android.diploma.domain.models

data class VacanciesResponse(
val results: List<Vacancy>,
val foundVacancies: Int,
val page: Int,
val pages: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ru.practicum.android.diploma.domain.models

data class Vacancy(
val id: Int,
val name: String,
val company: String,
val currency: String,
val salaryFrom: Int?,
val salaryTo: Int?,
val area: String,
val icon: String
)
Loading
Loading