diff --git a/app/src/main/java/com/tangem/tap/di/domain/AccountDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/AccountDomainModule.kt index ce95153840..2afd20f31a 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/AccountDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/AccountDomainModule.kt @@ -38,9 +38,13 @@ internal object AccountDomainModule { @Provides @Singleton fun provideUpdateCryptoPortfolioUseCase( + singleAccountListFetcher: SingleAccountListFetcher, accountsCRUDRepository: AccountsCRUDRepository, ): UpdateCryptoPortfolioUseCase { - return UpdateCryptoPortfolioUseCase(crudRepository = accountsCRUDRepository) + return UpdateCryptoPortfolioUseCase( + singleAccountListFetcher = singleAccountListFetcher, + crudRepository = accountsCRUDRepository, + ) } @Provides diff --git a/data/account/src/main/kotlin/com/tangem/data/account/fetcher/DefaultWalletAccountsFetcher.kt b/data/account/src/main/kotlin/com/tangem/data/account/fetcher/DefaultWalletAccountsFetcher.kt index 208bdb7817..99d4ac7ff6 100644 --- a/data/account/src/main/kotlin/com/tangem/data/account/fetcher/DefaultWalletAccountsFetcher.kt +++ b/data/account/src/main/kotlin/com/tangem/data/account/fetcher/DefaultWalletAccountsFetcher.kt @@ -54,9 +54,10 @@ internal class DefaultWalletAccountsFetcher @Inject constructor( override suspend fun fetch(userWalletId: UserWalletId): GetWalletAccountsResponse { val savedAccountsResponse = getAccountsResponseStore(userWalletId = userWalletId).getSyncOrNull() - val accountsResponse = fetchWalletAccounts(userWalletId, savedAccountsResponse) + val fetchResult = fetchWalletAccounts(userWalletId, savedAccountsResponse) + val accountsResponse = fetchResult.accountsResponse - return when { + val updatedResponse = when { accountsResponse.accounts.isEmpty() -> { initializeAccounts(userWalletId, accountsResponse) } @@ -65,6 +66,12 @@ internal class DefaultWalletAccountsFetcher @Inject constructor( } else -> accountsResponse } + + if (fetchResult.error != null) { + throw fetchResult.error + } + + return updatedResponse } override suspend fun getSaved(userWalletId: UserWalletId): GetWalletAccountsResponse? { @@ -123,7 +130,7 @@ internal class DefaultWalletAccountsFetcher @Inject constructor( private suspend fun fetchWalletAccounts( userWalletId: UserWalletId, savedAccountsResponse: GetWalletAccountsResponse?, - ): GetWalletAccountsResponse { + ): FetchResult { return safeApiCall( call = { val apiResponse = withContext(dispatchers.io) { @@ -138,7 +145,7 @@ internal class DefaultWalletAccountsFetcher @Inject constructor( val responseBody = apiResponse.bind() store(userWalletId = userWalletId, response = responseBody) - responseBody + FetchResult(responseBody) }, onError = { throwable -> // pushWalletAccounts and storeWalletAccounts help to avoid cyclic dependency @@ -211,4 +218,9 @@ internal class DefaultWalletAccountsFetcher @Inject constructor( private fun getAccountsResponseStore(userWalletId: UserWalletId): AccountsResponseStore { return accountsResponseStoreFactory.create(userWalletId = userWalletId) } + + data class FetchResult( + val accountsResponse: GetWalletAccountsResponse, + val error: Throwable? = null, + ) } \ No newline at end of file diff --git a/data/account/src/main/kotlin/com/tangem/data/account/fetcher/FetchWalletAccountsErrorHandler.kt b/data/account/src/main/kotlin/com/tangem/data/account/fetcher/FetchWalletAccountsErrorHandler.kt index c4b9d76100..b8cc75cc58 100644 --- a/data/account/src/main/kotlin/com/tangem/data/account/fetcher/FetchWalletAccountsErrorHandler.kt +++ b/data/account/src/main/kotlin/com/tangem/data/account/fetcher/FetchWalletAccountsErrorHandler.kt @@ -1,5 +1,6 @@ package com.tangem.data.account.fetcher +import com.tangem.data.account.fetcher.DefaultWalletAccountsFetcher.FetchResult import com.tangem.data.account.utils.DefaultWalletAccountsResponseFactory import com.tangem.data.common.cache.etag.ETagsStore import com.tangem.data.common.currency.UserTokensResponseAccountIdEnricher @@ -69,13 +70,15 @@ internal class FetchWalletAccountsErrorHandler @Inject constructor( savedAccountsResponse: GetWalletAccountsResponse?, pushWalletAccounts: suspend (UserWalletId, List) -> GetWalletAccountsResponse?, storeWalletAccounts: suspend (UserWalletId, GetWalletAccountsResponse) -> Unit, - ): GetWalletAccountsResponse { + ): FetchResult { val isResponseUpToDate = error.isNetworkError(code = Code.NOT_MODIFIED) if (isResponseUpToDate) { Timber.e("ETag is up to date, no need to update accounts for wallet: $userWalletId") - return requireNotNull(savedAccountsResponse) { + val response = requireNotNull(savedAccountsResponse) { "Saved accounts response is null for wallet: $userWalletId" } + + return FetchResult(response) } val response = savedAccountsResponse ?: createDefaultResponse(userWalletId) @@ -95,7 +98,7 @@ internal class FetchWalletAccountsErrorHandler @Inject constructor( storeWalletAccounts(userWalletId, response) - return response + return FetchResult(response, error) } private suspend fun createDefaultResponse(userWalletId: UserWalletId): GetWalletAccountsResponse { diff --git a/data/account/src/main/kotlin/com/tangem/data/account/repository/DefaultAccountsCRUDRepository.kt b/data/account/src/main/kotlin/com/tangem/data/account/repository/DefaultAccountsCRUDRepository.kt index 2bae8a091f..2bb36f1808 100644 --- a/data/account/src/main/kotlin/com/tangem/data/account/repository/DefaultAccountsCRUDRepository.kt +++ b/data/account/src/main/kotlin/com/tangem/data/account/repository/DefaultAccountsCRUDRepository.kt @@ -151,9 +151,9 @@ internal class DefaultAccountsCRUDRepository( ) val syncedResponse = walletAccountsSaver.push(userWalletId = accountList.userWalletId, accounts = accountDTOs) - if (syncedResponse != null) { - walletAccountsSaver.store(userWalletId = accountList.userWalletId, response = syncedResponse) - } + ?: error("Failed to push accounts for wallet: ${accountList.userWalletId}") + + walletAccountsSaver.store(userWalletId = accountList.userWalletId, response = syncedResponse) } override suspend fun saveAccount(account: Account.CryptoPortfolio) { diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt index 12ebfeda6d..ed2887e114 100644 --- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt +++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt @@ -163,6 +163,7 @@ internal class DefaultManageTokensRepository( ) } + @Suppress("CyclomaticComplexMethod") private suspend fun createManagedCryptoCurrencyList( params: ManageTokensListConfig.Account, userWallet: UserWallet?, @@ -172,11 +173,15 @@ internal class DefaultManageTokensRepository( updatedCoinsResponse: CoinsResponse, ): List { val response = params.userWalletId?.let { userWalletId -> - if (loadUserTokensFromRemote && userWallet != null) { + val shouldFetch = loadUserTokensFromRemote && userWallet != null + + val fetchedResponse = if (shouldFetch) { runCatching { walletAccountsFetcher.fetch(userWalletId = userWallet.walletId) }.getOrNull() } else { - walletAccountsFetcher.getSaved(userWalletId) + null } + + fetchedResponse ?: walletAccountsFetcher.getSaved(userWalletId) } val accountId = when { diff --git a/domain/account/src/main/java/com/tangem/domain/account/usecase/UpdateCryptoPortfolioUseCase.kt b/domain/account/src/main/java/com/tangem/domain/account/usecase/UpdateCryptoPortfolioUseCase.kt index f70ff26efa..38fce13c3b 100644 --- a/domain/account/src/main/java/com/tangem/domain/account/usecase/UpdateCryptoPortfolioUseCase.kt +++ b/domain/account/src/main/java/com/tangem/domain/account/usecase/UpdateCryptoPortfolioUseCase.kt @@ -3,6 +3,7 @@ package com.tangem.domain.account.usecase import arrow.core.Either import arrow.core.getOrElse import arrow.core.raise.* +import com.tangem.domain.account.fetcher.SingleAccountListFetcher import com.tangem.domain.account.models.AccountList import com.tangem.domain.account.repository.AccountsCRUDRepository import com.tangem.domain.models.account.Account @@ -14,11 +15,13 @@ import com.tangem.domain.models.wallet.UserWalletId /** * Use case for updating a crypto portfolio account. * + * @property singleAccountListFetcher the fetcher used to retrieve a single account list * @property crudRepository the repository used for performing CRUD operations on accounts * [REDACTED_AUTHOR] */ class UpdateCryptoPortfolioUseCase( + private val singleAccountListFetcher: SingleAccountListFetcher, private val crudRepository: AccountsCRUDRepository, ) { @@ -37,6 +40,8 @@ class UpdateCryptoPortfolioUseCase( ): Either = either { validate(accountName, icon) + fetchAccountList(accountId.userWalletId) + val accountList = getAccountList(userWalletId = accountId.userWalletId) val account = accountList.accounts @@ -64,6 +69,12 @@ class UpdateCryptoPortfolioUseCase( ensure(accountName != null || icon != null) { Error.NothingToUpdate } } + private suspend fun Raise.fetchAccountList(userWalletId: UserWalletId) { + singleAccountListFetcher(params = SingleAccountListFetcher.Params(userWalletId)).onLeft { + raise(Error.DataOperationFailed(cause = it)) + } + } + private suspend fun Raise.getAccountList(userWalletId: UserWalletId): AccountList { return catch( block = { crudRepository.getAccountListSync(userWalletId = userWalletId) }, @@ -91,7 +102,7 @@ class UpdateCryptoPortfolioUseCase( private fun Raise.checkDefaultName(accountList: AccountList, accountName: AccountName) { withError({ AccountList.Error.DuplicateAccountNames }) { - Either.Companion.catch { crudRepository.checkDefaultAccountName(accountList, accountName) }.bind() + Either.catch { crudRepository.checkDefaultAccountName(accountList, accountName) }.bind() } }