impl ui logic

This commit is contained in:
Shcherbatykh Oleg
2026-02-24 15:19:20 +03:00
parent 97c9091038
commit cff73f0f35
19 changed files with 696 additions and 397 deletions

View File

@@ -13,6 +13,5 @@ sealed interface DataResult<out T> {
val cause: Throwable? = null
) : DataResult<T>
/** Состояние загрузки */
data object Loading : DataResult<Nothing>
}

View File

@@ -45,11 +45,11 @@ dependencies {
api(libs.okhttp)
implementation(libs.okhttp.logging)
implementation(libs.converter.gson)
implementation(libs.retrofit.gson)
api(libs.moshi)
api(libs.moshiKotlin)
api(libs.retrofitMoshi)
api(libs.moshi.kotlin)
api(libs.retrofit.moshi)
implementation(projects.core.common)
}

View File

@@ -0,0 +1,77 @@
package ru.fincode.tsudesk.core.network.interceptor
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException
import kotlin.math.min
class RetryInterceptor(
private val maxAttempts: Int = 3,
private val baseDelayMs: Long = 300L
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
// На всякий: ретраим только идемпотентные методы
val method = request.method.uppercase()
val retryAllowed = method == "GET" || method == "HEAD"
var attempt = 1
var lastException: IOException? = null
var lastResponse: Response? = null
while (attempt <= maxAttempts) {
// закрываем предыдущий response, чтобы не текли ресурсы
lastResponse?.close()
lastResponse = null
try {
val response = chain.proceed(request)
if (!retryAllowed) return response
if (!response.shouldRetry()) {
return response
}
// Нужно ретраить — подождём и попробуем снова
if (attempt == maxAttempts) return response
sleepBackoff(attempt)
attempt++
continue
} catch (e: IOException) {
lastException = e
if (!retryAllowed || attempt == maxAttempts) throw e
sleepBackoff(attempt)
attempt++
}
}
// Теоретически не должны попасть сюда
lastResponse?.let { return it }
lastException?.let { throw it }
throw IOException("RetryInterceptor: exhausted attempts without response/exception")
}
private fun Response.shouldRetry(): Boolean {
return when (code) {
408, 429 -> true
in 500..599 -> true
else -> false
}
}
private fun sleepBackoff(attempt: Int) {
val delay = baseDelayMs * min(attempt.toLong(), 2L)
try {
Thread.sleep(delay)
} catch (_: InterruptedException) {
}
}
}

View File

@@ -35,7 +35,6 @@ android {
}
}
dependencies {
implementation(libs.core.ktx)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
}