update
This commit is contained in:
@@ -23,7 +23,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
val result = getScheduleUseCase(
|
val result = getScheduleUseCase(
|
||||||
ScheduleType.Group("220631")
|
ScheduleType.Group("220631")
|
||||||
)
|
)
|
||||||
Log.d("TSUDesk", result.isSuccess.toString())
|
Log.d("TSUDesk", result.toString())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("TSUDesk", "Error loading schedule", e)
|
Log.e("TSUDesk", "Error loading schedule", e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,4 @@ dependencies {
|
|||||||
api(libs.moshi)
|
api(libs.moshi)
|
||||||
api(libs.moshiKotlin)
|
api(libs.moshiKotlin)
|
||||||
api(libs.retrofitMoshi)
|
api(libs.retrofitMoshi)
|
||||||
|
|
||||||
api(libs.retrofit.simplexml)
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,24 @@
|
|||||||
package ru.fincode.tsudesk.core.network
|
package ru.fincode.tsudesk.core.network
|
||||||
|
|
||||||
class NetworkCall {
|
import retrofit2.HttpException
|
||||||
|
import ru.fincode.tsudesk.core.network.model.NetworkError
|
||||||
|
import ru.fincode.tsudesk.core.network.model.NetworkResult
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.SocketTimeoutException
|
||||||
|
|
||||||
|
suspend inline fun <T> safeApiCall(
|
||||||
|
crossinline block: suspend () -> T
|
||||||
|
): NetworkResult<T> {
|
||||||
|
return try {
|
||||||
|
NetworkResult.Success(block())
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
NetworkResult.Error(t.toNetworkError())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Throwable.toNetworkError(): NetworkError = when (this) {
|
||||||
|
is SocketTimeoutException -> NetworkError.Timeout
|
||||||
|
is IOException -> NetworkError.NoInternet
|
||||||
|
is HttpException -> NetworkError.Http(code())
|
||||||
|
else -> NetworkError.Unknown(this)
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,13 @@ import retrofit2.Retrofit
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import ru.fincode.tsudesk.core.network.interceptor.DebugInterceptor
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
object NetworkModule {
|
object NetworkModule {
|
||||||
|
|
||||||
private const val TIMEOUT_SEC = 30L
|
private const val TIMEOUT = 30L
|
||||||
val logging = HttpLoggingInterceptor().apply {
|
val logging = HttpLoggingInterceptor().apply {
|
||||||
level = HttpLoggingInterceptor.Level.BODY
|
level = HttpLoggingInterceptor.Level.BODY
|
||||||
}
|
}
|
||||||
@@ -23,9 +24,9 @@ object NetworkModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
fun provideOkHttpClient(): OkHttpClient =
|
fun provideOkHttpClient(): OkHttpClient =
|
||||||
OkHttpClient.Builder()
|
OkHttpClient.Builder()
|
||||||
.connectTimeout(TIMEOUT_SEC, TimeUnit.SECONDS)
|
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
|
||||||
.readTimeout(TIMEOUT_SEC, TimeUnit.SECONDS)
|
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
|
||||||
.writeTimeout(TIMEOUT_SEC, TimeUnit.SECONDS)
|
.writeTimeout(TIMEOUT, TimeUnit.SECONDS)
|
||||||
.retryOnConnectionFailure(true)
|
.retryOnConnectionFailure(true)
|
||||||
.addInterceptor(DebugInterceptor())
|
.addInterceptor(DebugInterceptor())
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@@ -1,2 +1,20 @@
|
|||||||
package ru.fincode.tsudesk.core.network.interceptor
|
package ru.fincode.tsudesk.core.network.interceptor
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
private const val TAG = "NETWORK_DEBUG"
|
||||||
|
|
||||||
|
class DebugInterceptor : Interceptor {
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val request = chain.request()
|
||||||
|
|
||||||
|
Log.d(TAG, "URL: ${request.url}")
|
||||||
|
Log.d(TAG, "Method: ${request.method}")
|
||||||
|
Log.d(TAG, "Headers: ${request.headers}")
|
||||||
|
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,8 @@
|
|||||||
package ru.fincode.tsudesk.core.network.model
|
package ru.fincode.tsudesk.core.network.model
|
||||||
|
|
||||||
|
sealed class NetworkError {
|
||||||
|
object NoInternet : NetworkError()
|
||||||
|
object Timeout : NetworkError()
|
||||||
|
data class Http(val code: Int) : NetworkError()
|
||||||
|
data class Unknown(val throwable: Throwable) : NetworkError()
|
||||||
|
}
|
||||||
@@ -1,2 +1,6 @@
|
|||||||
package ru.fincode.tsudesk.core.network.model
|
package ru.fincode.tsudesk.core.network.model
|
||||||
|
|
||||||
|
sealed class NetworkResult<out T> {
|
||||||
|
data class Success<T>(val data: T) : NetworkResult<T>()
|
||||||
|
data class Error(val error: NetworkError) : NetworkResult<Nothing>()
|
||||||
|
}
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
package ru.fincode.tsudesk.core.network.model
|
package ru.fincode.tsudesk.core.network.model
|
||||||
|
|
||||||
class NetworkResultExt {
|
inline fun <T, R> NetworkResult<T>.map(
|
||||||
|
transform: (T) -> R
|
||||||
|
): NetworkResult<R> = when (this) {
|
||||||
|
is NetworkResult.Success -> NetworkResult.Success(transform(data))
|
||||||
|
is NetworkResult.Error -> this
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package ru.fincode.tsudesk.feature.schedule.data
|
package ru.fincode.tsudesk.feature.schedule.data
|
||||||
|
|
||||||
|
import ru.fincode.tsudesk.core.network.model.NetworkResult
|
||||||
|
import ru.fincode.tsudesk.core.network.model.map
|
||||||
import ru.fincode.tsudesk.feature.schedule.data.datasource.ScheduleRemoteDataSource
|
import ru.fincode.tsudesk.feature.schedule.data.datasource.ScheduleRemoteDataSource
|
||||||
import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleDtoToDomainMapper
|
import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleDtoToDomainMapper
|
||||||
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
|
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
|
||||||
@@ -7,14 +9,15 @@ import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ScheduleRepositoryImpl @Inject constructor(
|
class ScheduleRepositoryImpl @Inject constructor(
|
||||||
private val remote: ScheduleRemoteDataSource, private val mapper: ScheduleDtoToDomainMapper
|
private val remote: ScheduleRemoteDataSource,
|
||||||
|
private val mapper: ScheduleDtoToDomainMapper
|
||||||
) : ScheduleRepository {
|
) : ScheduleRepository {
|
||||||
|
|
||||||
override suspend fun loadScheduleByGroup(
|
override suspend fun loadScheduleByGroup(number: String): NetworkResult<ScheduleEntity> =
|
||||||
groupNumber: String
|
remote.loadScheduleByGroup(number).map(mapper::invoke)
|
||||||
): Result<ScheduleEntity> = remote.loadScheduleByGroup(groupNumber).map(mapper::invoke)
|
|
||||||
|
override suspend fun loadScheduleByTeacher(name: String): NetworkResult<ScheduleEntity> =
|
||||||
|
remote.loadScheduleByTeacher(name).map(mapper::invoke)
|
||||||
|
|
||||||
override suspend fun loadScheduleByTeacher(
|
|
||||||
name: String
|
|
||||||
): Result<ScheduleEntity> = remote.loadScheduleByTeacher(name).map(mapper::invoke)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package ru.fincode.tsudesk.feature.schedule.data.datasource
|
package ru.fincode.tsudesk.feature.schedule.data.datasource
|
||||||
|
|
||||||
|
import ru.fincode.tsudesk.core.network.model.NetworkResult
|
||||||
|
import ru.fincode.tsudesk.core.network.safeApiCall
|
||||||
import ru.fincode.tsudesk.feature.schedule.data.remote.ScheduleApi
|
import ru.fincode.tsudesk.feature.schedule.data.remote.ScheduleApi
|
||||||
import ru.fincode.tsudesk.feature.schedule.data.remote.model.LessonDto.ScheduleSearchField.GROUP_P
|
import ru.fincode.tsudesk.feature.schedule.data.remote.model.LessonDto.ScheduleSearchField.GROUP_P
|
||||||
import ru.fincode.tsudesk.feature.schedule.data.remote.model.LessonDto.ScheduleSearchField.PREP
|
import ru.fincode.tsudesk.feature.schedule.data.remote.model.LessonDto.ScheduleSearchField.PREP
|
||||||
@@ -9,9 +11,9 @@ import javax.inject.Inject
|
|||||||
class ScheduleRemoteDataSource @Inject constructor(
|
class ScheduleRemoteDataSource @Inject constructor(
|
||||||
private val api: ScheduleApi
|
private val api: ScheduleApi
|
||||||
) {
|
) {
|
||||||
suspend fun loadScheduleByGroup(groupNumber: String): Result<ScheduleDto> =
|
suspend fun loadScheduleByGroup(number: String): NetworkResult<ScheduleDto> =
|
||||||
runCatching { api.getSchedule(GROUP_P, groupNumber) }
|
safeApiCall { api.getSchedule(GROUP_P, number) }
|
||||||
|
|
||||||
suspend fun loadScheduleByTeacher(name: String): Result<ScheduleDto> =
|
suspend fun loadScheduleByTeacher(name: String): NetworkResult<ScheduleDto> =
|
||||||
runCatching { api.getSchedule(PREP, name) }
|
safeApiCall { api.getSchedule(PREP, name) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package ru.fincode.tsudesk.feature.schedule.data.datasource
|
package ru.fincode.tsudesk.feature.schedule.data.datasource
|
||||||
|
|
||||||
|
import ru.fincode.tsudesk.core.network.model.NetworkResult
|
||||||
|
import ru.fincode.tsudesk.core.network.model.map
|
||||||
import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleDtoToDomainMapper
|
import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleDtoToDomainMapper
|
||||||
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
|
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
|
||||||
import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
|
import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
|
||||||
@@ -10,13 +12,10 @@ class ScheduleRemoteDataSourceImpl @Inject constructor(
|
|||||||
private val mapper: ScheduleDtoToDomainMapper
|
private val mapper: ScheduleDtoToDomainMapper
|
||||||
) : ScheduleRepository {
|
) : ScheduleRepository {
|
||||||
|
|
||||||
override suspend fun loadScheduleByGroup(groupNumber: String): Result<ScheduleEntity> =
|
override suspend fun loadScheduleByGroup(number: String): NetworkResult<ScheduleEntity> =
|
||||||
remote
|
remote.loadScheduleByGroup(number).map(mapper::invoke)
|
||||||
.loadScheduleByGroup(groupNumber) // Result<ScheduleDto>
|
|
||||||
.map(mapper::invoke) // Result<ScheduleEntity>
|
override suspend fun loadScheduleByTeacher(name: String): NetworkResult<ScheduleEntity> =
|
||||||
|
remote.loadScheduleByTeacher(name).map(mapper::invoke)
|
||||||
|
|
||||||
override suspend fun loadScheduleByTeacher(name: String): Result<ScheduleEntity> =
|
|
||||||
remote
|
|
||||||
.loadScheduleByTeacher(name) // Result<ScheduleDto>
|
|
||||||
.map(mapper::invoke) // Result<ScheduleEntity>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package ru.fincode.tsudesk.feature.schedule.domain.repository
|
package ru.fincode.tsudesk.feature.schedule.domain.repository
|
||||||
|
|
||||||
|
import ru.fincode.tsudesk.core.network.model.NetworkResult
|
||||||
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
|
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
|
||||||
|
|
||||||
interface ScheduleRepository {
|
interface ScheduleRepository {
|
||||||
suspend fun loadScheduleByGroup(groupNumber: String): Result<ScheduleEntity>
|
suspend fun loadScheduleByGroup(number: String): NetworkResult<ScheduleEntity>
|
||||||
suspend fun loadScheduleByTeacher(name: String): Result<ScheduleEntity>
|
suspend fun loadScheduleByTeacher(name: String): NetworkResult<ScheduleEntity>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.fincode.tsudesk.feature.schedule.domain.usecase
|
package ru.fincode.tsudesk.feature.schedule.domain.usecase
|
||||||
|
|
||||||
|
import ru.fincode.tsudesk.core.network.model.NetworkResult
|
||||||
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
|
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
|
||||||
import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
|
import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -8,13 +9,13 @@ class GetScheduleUseCase @Inject constructor(
|
|||||||
private val repository: ScheduleRepository
|
private val repository: ScheduleRepository
|
||||||
) {
|
) {
|
||||||
sealed interface ScheduleType {
|
sealed interface ScheduleType {
|
||||||
data class Group(val groupNumber: String) : ScheduleType
|
data class Group(val number: String) : ScheduleType
|
||||||
data class Teacher(val teacherName: String) : ScheduleType
|
data class Teacher(val name: String) : ScheduleType
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend operator fun invoke(type: ScheduleType): Result<ScheduleEntity> =
|
suspend operator fun invoke(type: ScheduleType): NetworkResult<ScheduleEntity> =
|
||||||
when (type) {
|
when (type) {
|
||||||
is ScheduleType.Group -> repository.loadScheduleByGroup(type.groupNumber)
|
is ScheduleType.Group -> repository.loadScheduleByGroup(type.number)
|
||||||
is ScheduleType.Teacher -> repository.loadScheduleByTeacher(type.teacherName)
|
is ScheduleType.Teacher -> repository.loadScheduleByTeacher(type.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user