refactor: centralize shared error handling

This commit is contained in:
Codex
2026-05-14 17:48:56 +03:00
parent cb653eddc2
commit 22d13fcbe5
8 changed files with 34 additions and 163 deletions
@@ -1,24 +1,18 @@
package dev.meloda.fast.data package dev.meloda.fast.data
import androidx.core.net.toUri
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
import java.net.URLEncoder
class AccessTokenInterceptor : Interceptor { class AccessTokenInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
val builder = chain.request().url.newBuilder() val request = chain.request()
val urlBuilder = request.url.newBuilder()
val uri = builder.build().toUri().toString().toUri() if (request.url.queryParameter("access_token") == null) {
urlBuilder.addQueryParameter("access_token", UserConfig.accessToken)
if (uri.getQueryParameter("access_token") == null) {
builder.addQueryParameter(
"access_token",
URLEncoder.encode(UserConfig.accessToken, "utf-8")
)
} }
return chain.proceed(chain.request().newBuilder().apply { url(builder.build()) }.build()) return chain.proceed(request.newBuilder().url(urlBuilder.build()).build())
} }
} }
@@ -1,6 +1,5 @@
package dev.meloda.fast.data package dev.meloda.fast.data
import dev.meloda.fast.data.UserConfig.userId
import dev.meloda.fast.model.api.domain.VkContactDomain import dev.meloda.fast.model.api.domain.VkContactDomain
import dev.meloda.fast.model.api.domain.VkConvo import dev.meloda.fast.model.api.domain.VkConvo
import dev.meloda.fast.model.api.domain.VkGroupDomain import dev.meloda.fast.model.api.domain.VkGroupDomain
@@ -38,7 +37,15 @@ object VkMemoryCache {
contacts.forEach { contact -> VkMemoryCache.contacts[contact.userId] = contact } contacts.forEach { contact -> VkMemoryCache.contacts[contact.userId] = contact }
} }
operator fun set(userid: Long, user: VkUser) { fun clear() {
users.clear()
groups.clear()
messages.clear()
convos.clear()
contacts.clear()
}
operator fun set(userId: Long, user: VkUser) {
users[userId] = user users[userId] = user
} }
@@ -10,11 +10,11 @@ import dev.meloda.fast.chatmaterials.util.asPresentation
import dev.meloda.fast.common.extensions.listenValue import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.data.State import dev.meloda.fast.data.State
import dev.meloda.fast.data.VkUtils
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.domain.MessagesUseCase import dev.meloda.fast.domain.MessagesUseCase
import dev.meloda.fast.model.BaseError import dev.meloda.fast.model.BaseError
import dev.meloda.fast.model.api.domain.VkAttachmentHistoryMessage import dev.meloda.fast.model.api.domain.VkAttachmentHistoryMessage
import dev.meloda.fast.network.VkErrorCode
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -131,40 +131,8 @@ class ChatMaterialsViewModelImpl(
} }
private fun handleError(error: State.Error) { private fun handleError(error: State.Error) {
when (error) { VkUtils.parseError(error)?.let { newBaseError ->
is State.Error.ApiError -> { baseError.setValue { newBaseError }
when (error.errorCode) {
VkErrorCode.USER_AUTHORIZATION_FAILED -> {
baseError.setValue { BaseError.SessionExpired }
}
else -> {
baseError.setValue {
BaseError.SimpleError(message = error.errorMessage)
}
}
}
}
State.Error.ConnectionError -> {
baseError.setValue {
BaseError.SimpleError(message = "Connection error")
}
}
State.Error.InternalError -> {
baseError.setValue {
BaseError.SimpleError(message = "Internal error")
}
}
State.Error.UnknownError -> {
baseError.setValue {
BaseError.SimpleError(message = "Unknown error")
}
}
else -> Unit
} }
} }
@@ -10,6 +10,7 @@ import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.convos.model.CreateChatScreenState import dev.meloda.fast.convos.model.CreateChatScreenState
import dev.meloda.fast.data.State import dev.meloda.fast.data.State
import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.UserConfig
import dev.meloda.fast.data.VkUtils
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.datastore.UserSettings import dev.meloda.fast.datastore.UserSettings
import dev.meloda.fast.domain.FriendsUseCase import dev.meloda.fast.domain.FriendsUseCase
@@ -18,7 +19,6 @@ import dev.meloda.fast.domain.MessagesUseCase
import dev.meloda.fast.domain.util.asPresentation import dev.meloda.fast.domain.util.asPresentation
import dev.meloda.fast.model.BaseError import dev.meloda.fast.model.BaseError
import dev.meloda.fast.model.api.domain.VkUser import dev.meloda.fast.model.api.domain.VkUser
import dev.meloda.fast.network.VkErrorCode
import dev.meloda.fast.ui.model.vk.UiFriend import dev.meloda.fast.ui.model.vk.UiFriend
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -228,40 +228,8 @@ class CreateChatViewModel(
} }
private fun handleError(error: State.Error) { private fun handleError(error: State.Error) {
when (error) { VkUtils.parseError(error)?.let { newBaseError ->
is State.Error.ApiError -> { _baseError.setValue { newBaseError }
when (error.errorCode) {
VkErrorCode.USER_AUTHORIZATION_FAILED -> {
_baseError.setValue { BaseError.SessionExpired }
}
else -> {
_baseError.setValue {
BaseError.SimpleError(message = error.errorMessage)
}
}
}
}
State.Error.ConnectionError -> {
_baseError.setValue {
BaseError.SimpleError(message = "Connection error")
}
}
State.Error.InternalError -> {
_baseError.setValue {
BaseError.SimpleError(message = "Internal error")
}
}
State.Error.UnknownError -> {
_baseError.setValue {
BaseError.SimpleError(message = "Unknown error")
}
}
else -> Unit
} }
} }
@@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import dev.meloda.fast.common.extensions.listenValue import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.data.State import dev.meloda.fast.data.State
import dev.meloda.fast.data.VkUtils
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.datastore.UserSettings import dev.meloda.fast.datastore.UserSettings
import dev.meloda.fast.domain.FriendsUseCase import dev.meloda.fast.domain.FriendsUseCase
@@ -13,7 +14,6 @@ import dev.meloda.fast.domain.util.asPresentation
import dev.meloda.fast.friends.model.FriendsScreenState import dev.meloda.fast.friends.model.FriendsScreenState
import dev.meloda.fast.model.BaseError import dev.meloda.fast.model.BaseError
import dev.meloda.fast.model.api.domain.VkUser import dev.meloda.fast.model.api.domain.VkUser
import dev.meloda.fast.network.VkErrorCode
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
@@ -80,40 +80,8 @@ abstract class BaseFriendsViewModelImpl : ViewModel(), FriendsViewModel {
abstract fun loadFriends(offset: Int = currentOffset.value) abstract fun loadFriends(offset: Int = currentOffset.value)
protected fun handleError(error: State.Error) { protected fun handleError(error: State.Error) {
when (error) { VkUtils.parseError(error)?.let { newBaseError ->
is State.Error.ApiError -> { baseError.setValue { newBaseError }
when (error.errorCode) {
VkErrorCode.USER_AUTHORIZATION_FAILED -> {
baseError.setValue { BaseError.SessionExpired }
}
else -> {
baseError.setValue {
BaseError.SimpleError(message = error.errorMessage)
}
}
}
}
State.Error.ConnectionError -> {
baseError.setValue {
BaseError.SimpleError(message = "Connection error")
}
}
State.Error.InternalError -> {
baseError.setValue {
BaseError.SimpleError(message = "Internal error")
}
}
State.Error.UnknownError -> {
baseError.setValue {
BaseError.SimpleError(message = "Unknown error")
}
}
else -> Unit
} }
} }
@@ -33,6 +33,7 @@ import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.common.provider.ResourceProvider import dev.meloda.fast.common.provider.ResourceProvider
import dev.meloda.fast.data.State import dev.meloda.fast.data.State
import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.UserConfig
import dev.meloda.fast.data.VkUtils
import dev.meloda.fast.data.VkMemoryCache import dev.meloda.fast.data.VkMemoryCache
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.datastore.AppSettings import dev.meloda.fast.datastore.AppSettings
@@ -58,7 +59,6 @@ import dev.meloda.fast.model.LongPollParsedEvent
import dev.meloda.fast.model.api.domain.FormatDataType import dev.meloda.fast.model.api.domain.FormatDataType
import dev.meloda.fast.model.api.domain.VkMessage import dev.meloda.fast.model.api.domain.VkMessage
import dev.meloda.fast.model.api.domain.VkPhotoDomain import dev.meloda.fast.model.api.domain.VkPhotoDomain
import dev.meloda.fast.network.VkErrorCode
import dev.meloda.fast.ui.R import dev.meloda.fast.ui.R
import dev.meloda.fast.ui.model.vk.MessageUiItem import dev.meloda.fast.ui.model.vk.MessageUiItem
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -954,40 +954,8 @@ class MessagesHistoryViewModelImpl(
} }
private fun handleError(error: State.Error) { private fun handleError(error: State.Error) {
when (error) { VkUtils.parseError(error)?.let { newBaseError ->
is State.Error.ApiError -> { baseError.setValue { newBaseError }
when (error.errorCode) {
VkErrorCode.USER_AUTHORIZATION_FAILED -> {
baseError.setValue { BaseError.SessionExpired }
}
else -> {
baseError.setValue {
BaseError.SimpleError(message = error.errorMessage)
}
}
}
}
State.Error.ConnectionError -> {
baseError.setValue {
BaseError.SimpleError(message = "Connection error")
}
}
State.Error.InternalError -> {
baseError.setValue {
BaseError.SimpleError(message = "Internal error")
}
}
State.Error.UnknownError -> {
baseError.setValue {
BaseError.SimpleError(message = "Unknown error")
}
}
else -> Unit
} }
} }
@@ -7,11 +7,11 @@ import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.data.State import dev.meloda.fast.data.State
import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.UserConfig
import dev.meloda.fast.data.VkUtils
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.domain.GetLocalUserByIdUseCase import dev.meloda.fast.domain.GetLocalUserByIdUseCase
import dev.meloda.fast.domain.LoadUserByIdUseCase import dev.meloda.fast.domain.LoadUserByIdUseCase
import dev.meloda.fast.model.BaseError import dev.meloda.fast.model.BaseError
import dev.meloda.fast.network.VkErrorCode
import dev.meloda.fast.profile.model.ProfileScreenState import dev.meloda.fast.profile.model.ProfileScreenState
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -38,14 +38,8 @@ class ProfileViewModelImpl(
.listenValue(viewModelScope) { state -> .listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
if (error is State.Error.ApiError) { VkUtils.parseError(error)?.let { newBaseError ->
when (error.errorCode) { baseError.setValue { newBaseError }
VkErrorCode.USER_AUTHORIZATION_FAILED -> {
baseError.setValue { BaseError.SessionExpired }
}
else -> Unit
}
} }
screenState.setValue { old -> screenState.setValue { old ->
@@ -17,6 +17,7 @@ import dev.meloda.fast.common.model.LongPollState
import dev.meloda.fast.common.model.UiText import dev.meloda.fast.common.model.UiText
import dev.meloda.fast.common.model.parseString import dev.meloda.fast.common.model.parseString
import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.UserConfig
import dev.meloda.fast.data.VkMemoryCache
import dev.meloda.fast.data.db.AccountsRepository import dev.meloda.fast.data.db.AccountsRepository
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.datastore.AppSettings import dev.meloda.fast.datastore.AppSettings
@@ -45,7 +46,8 @@ class SettingsViewModel(
private val getCurrentAccountUseCase: GetCurrentAccountUseCase, private val getCurrentAccountUseCase: GetCurrentAccountUseCase,
private val userSettings: UserSettings, private val userSettings: UserSettings,
private val resources: Resources, private val resources: Resources,
private val longPollController: LongPollController private val longPollController: LongPollController,
private val vkMemoryCache: VkMemoryCache
) : ViewModel() { ) : ViewModel() {
private val _screenState = MutableStateFlow(SettingsScreenState.EMPTY) private val _screenState = MutableStateFlow(SettingsScreenState.EMPTY)
@@ -112,6 +114,7 @@ class SettingsViewModel(
) )
accountsRepository.storeAccounts(listOf(account)) accountsRepository.storeAccounts(listOf(account))
vkMemoryCache.clear()
_isNeedToRestart.setValue { true } _isNeedToRestart.setValue { true }
} }
@@ -164,6 +167,7 @@ class SettingsViewModel(
) )
tasks.awaitAll() tasks.awaitAll()
vkMemoryCache.clear()
} }
} }