From 92ee3c0273c22f89556186cfb92aa288ad3d608e Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 1 Dec 2023 16:35:36 +0200 Subject: [PATCH] Updated on 2026-08-14 --- .../local/preferences/PreferencesKeys.kt | 2 ++ .../swap/DefaultSwapTransactionRepository.kt | 34 +++++++++++++++++++ .../DefaultInitialToCurrencyResolver.kt | 33 ++++++++++++++++++ .../swap/domain/InitialToCurrencyResolver.kt | 15 ++++++++ .../feature/swap/domain/SwapInteractor.kt | 5 +++ .../feature/swap/domain/SwapInteractorImpl.kt | 21 +++++++++++- .../swap/domain/SwapTransactionRepository.kt | 4 +++ .../swap/domain/di/SwapDomainModule.kt | 14 ++++++++ .../domain/SavedLastSwappedCryptoCurrency.kt | 6 ++++ .../feature/swap/viewmodels/SwapViewModel.kt | 13 +++---- 10 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 features/swap/domain/src/main/java/com/tangem/feature/swap/domain/DefaultInitialToCurrencyResolver.kt create mode 100644 features/swap/domain/src/main/java/com/tangem/feature/swap/domain/InitialToCurrencyResolver.kt create mode 100644 features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/SavedLastSwappedCryptoCurrency.kt diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index 65be83c11a..213d153c62 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -36,6 +36,8 @@ object PreferencesKeys { val SWAP_TRANSACTIONS_KEY by lazy { stringPreferencesKey(name = "swapTransactions") } val WALLETS_SCROLL_PREVIEW_KEY by lazy { booleanPreferencesKey(name = "walletsScrollPreview") } + + val LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY by lazy { stringPreferencesKey(name = "lastSwappedCryptoCurrency") } } /** Preferences keys set that should be migrated from "PreferencesDataSource" to a new DataStore */ diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt index 63c8aecb72..e6cb59c754 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt @@ -3,9 +3,11 @@ package com.tangem.feature.swap import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectList +import com.tangem.datasource.local.preferences.utils.getObjectListSync import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.domain.SwapTransactionRepository +import com.tangem.feature.swap.domain.models.domain.SavedLastSwappedCryptoCurrency import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel import com.tangem.utils.extensions.addOrReplace @@ -128,6 +130,38 @@ class DefaultSwapTransactionRepository( } } + override suspend fun getLastSwappedCryptoCurrencyId(userWalletId: UserWalletId): String? { + val lastSwappedCurrencies = appPreferencesStore.getObjectListSync( + key = PreferencesKeys.LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY, + ) + + return lastSwappedCurrencies.find { userWalletId.stringValue == it.userWalletId }?.cryptoCurrencyId + } + + override suspend fun storeLastSwappedCryptoCurrencyId( + userWalletId: UserWalletId, + cryptoCurrencyId: CryptoCurrency.ID, + ) { + appPreferencesStore.editData { mutablePreferences -> + val lastSwappedCryptoCurrencies: List? = mutablePreferences.getObjectList( + key = PreferencesKeys.LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY, + ) + + val newList = if (lastSwappedCryptoCurrencies != null) { + lastSwappedCryptoCurrencies.filter { + it.userWalletId != userWalletId.stringValue + } + SavedLastSwappedCryptoCurrency(userWalletId.stringValue, cryptoCurrencyId.value) + } else { + listOf(SavedLastSwappedCryptoCurrency(userWalletId.stringValue, cryptoCurrencyId.value)) + } + + mutablePreferences.setObjectList( + key = PreferencesKeys.LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY, + value = newList, + ) + } + } + private fun SavedSwapTransactionListModel.checkId( checkUserWalletId: UserWalletId, fromCurrencyId: CryptoCurrency.ID, diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/DefaultInitialToCurrencyResolver.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/DefaultInitialToCurrencyResolver.kt new file mode 100644 index 0000000000..42e6f2331b --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/DefaultInitialToCurrencyResolver.kt @@ -0,0 +1,33 @@ +package com.tangem.feature.swap.domain + +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase +import com.tangem.feature.swap.domain.models.ui.TokensDataStateExpress +import java.math.BigDecimal + +internal class DefaultInitialToCurrencyResolver( + private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, + private val swapTransactionRepository: SwapTransactionRepository, +) : InitialToCurrencyResolver { + + override suspend fun tryGetFromCache( + initialCryptoCurrency: CryptoCurrency, + state: TokensDataStateExpress, + ): CryptoCurrencyStatus? { + val selectedId = getSelectedWalletSyncUseCase().getOrNull() ?: return null + val id = swapTransactionRepository.getLastSwappedCryptoCurrencyId(selectedId.walletId) ?: return null + + return if (id != initialCryptoCurrency.id.value) { + state.toGroup.available.find { it.currencyStatus.currency.id.value == id }?.currencyStatus + } else { + null + } + } + + override fun tryGetWithMaxAmount(state: TokensDataStateExpress): CryptoCurrencyStatus? { + return state.toGroup.available.maxByOrNull { + it.currencyStatus.value.fiatAmount ?: BigDecimal.ZERO + }?.currencyStatus + } +} \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/InitialToCurrencyResolver.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/InitialToCurrencyResolver.kt new file mode 100644 index 0000000000..da0b0f1b37 --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/InitialToCurrencyResolver.kt @@ -0,0 +1,15 @@ +package com.tangem.feature.swap.domain + +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.feature.swap.domain.models.ui.TokensDataStateExpress + +interface InitialToCurrencyResolver { + + suspend fun tryGetFromCache( + initialCryptoCurrency: CryptoCurrency, + state: TokensDataStateExpress, + ): CryptoCurrencyStatus? + + fun tryGetWithMaxAmount(state: TokensDataStateExpress): CryptoCurrencyStatus? +} \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt index 01193a0ea4..c75b56fd63 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt @@ -85,4 +85,9 @@ interface SwapInteractor { fun isAvailableToSwap(networkId: String): Boolean fun getSelectedWallet(): UserWallet? + + suspend fun selectInitialCurrencyToSwap( + initialCryptoCurrency: CryptoCurrency, + state: TokensDataStateExpress, + ): CryptoCurrencyStatus? } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 685e925ce8..29e2aacdb7 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -43,7 +43,6 @@ internal class SwapInteractorImpl @Inject constructor( private val transactionManager: TransactionManager, private val userWalletManager: UserWalletManager, private val repository: SwapRepository, - private val swapTransactionRepository: SwapTransactionRepository, private val allowPermissionsHandler: AllowPermissionsHandler, private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase, @@ -51,6 +50,8 @@ internal class SwapInteractorImpl @Inject constructor( private val sendTransactionUseCase: SendTransactionUseCase, private val quotesRepository: QuotesRepository, private val dispatcher: CoroutineDispatcherProvider, + private val swapTransactionRepository: SwapTransactionRepository, + private val initialToCurrencyResolver: InitialToCurrencyResolver, ) : SwapInteractor { private val getFeeUseCase by lazy(LazyThreadSafetyMode.NONE) { @@ -427,6 +428,7 @@ internal class SwapInteractorImpl @Inject constructor( ) return when (result) { is SendTxResult.Success -> { + storeLastCryptoCurrencyId(currencyToGet) TxState.TxSent( fromAmount = amountFormatter.formatSwapAmountToUI( amount, @@ -503,6 +505,7 @@ internal class SwapInteractorImpl @Inject constructor( swapDataModel = exchangeData.dataModel, timestamp = timestamp, ) + storeLastCryptoCurrencyId(currencyToGet.currency) TxState.TxSent( fromAmount = amountFormatter.formatSwapAmountToUI( amount, @@ -564,6 +567,13 @@ internal class SwapInteractorImpl @Inject constructor( ) } + private suspend fun storeLastCryptoCurrencyId(cryptoCurrency: CryptoCurrency) { + swapTransactionRepository.storeLastSwappedCryptoCurrencyId( + UserWalletId(userWalletManager.getWalletId()), + cryptoCurrency.id, + ) + } + @Deprecated("used in old swap mechanism") override fun getTokenBalance(token: CryptoCurrencyStatus): SwapAmount { return SwapAmount(token.value.amount ?: BigDecimal.ZERO, getTokenDecimals(token.currency)) @@ -574,6 +584,15 @@ internal class SwapInteractorImpl @Inject constructor( return ONE_INCH_SUPPORTED_NETWORKS.contains(networkId) } + override suspend fun selectInitialCurrencyToSwap( + initialCryptoCurrency: CryptoCurrency, + state: TokensDataStateExpress, + ): CryptoCurrencyStatus? { + return initialToCurrencyResolver.tryGetFromCache(initialCryptoCurrency, state) + ?: initialToCurrencyResolver.tryGetWithMaxAmount(state) + ?: state.toGroup.available.firstOrNull()?.currencyStatus + } + @Deprecated("used in old swap mechanism") private fun getTangemFee(): Double { return repository.getTangemFee() diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt index d89914d537..2db58ee01d 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt @@ -26,4 +26,8 @@ interface SwapTransactionRepository { toCryptoCurrencyId: CryptoCurrency.ID, txId: String, ) + + suspend fun storeLastSwappedCryptoCurrencyId(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID) + + suspend fun getLastSwappedCryptoCurrencyId(userWalletId: UserWalletId): String? } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt index d72ebef25d..f6bf9093c9 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt @@ -40,6 +40,7 @@ class SwapDomainModule { swapTransactionRepository: SwapTransactionRepository, walletManagersFacade: WalletManagersFacade, coroutineDispatcherProvider: CoroutineDispatcherProvider, + initialToCurrencyResolver: InitialToCurrencyResolver, ): SwapInteractor { return SwapInteractorImpl( transactionManager = transactionManager, @@ -53,6 +54,7 @@ class SwapDomainModule { walletManagersFacade = walletManagersFacade, dispatcher = coroutineDispatcherProvider, swapTransactionRepository = swapTransactionRepository, + initialToCurrencyResolver = initialToCurrencyResolver, ) } @@ -124,6 +126,18 @@ class SwapDomainModule { walletManagersFacade = walletManagersFacade, ) } + + @Provides + @Singleton + fun provideInitialToCurrencyResolver( + @SwapScope getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, + swapTransactionRepository: SwapTransactionRepository, + ): InitialToCurrencyResolver { + return DefaultInitialToCurrencyResolver( + getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase, + swapTransactionRepository = swapTransactionRepository, + ) + } } @Qualifier diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/SavedLastSwappedCryptoCurrency.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/SavedLastSwappedCryptoCurrency.kt new file mode 100644 index 0000000000..2db24c66eb --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/SavedLastSwappedCryptoCurrency.kt @@ -0,0 +1,6 @@ +package com.tangem.feature.swap.domain.models.domain + +data class SavedLastSwappedCryptoCurrency( + val userWalletId: String, + val cryptoCurrencyId: String, +) \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 76f1473044..83fb774ca3 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -153,7 +153,13 @@ internal class SwapViewModel @Inject constructor( swapInteractor.getTokensDataState(initialCryptoCurrency) }.onSuccess { state -> updateTokensState(state) - applyInitialTokenChoice(state, selectInitialCurrencyToSwap(state)) + applyInitialTokenChoice( + state, + swapInteractor.selectInitialCurrencyToSwap( + initialCryptoCurrency, + state, + ), + ) }.onFailure { Timber.tag(loggingTag).e(it) } @@ -182,11 +188,6 @@ internal class SwapViewModel @Inject constructor( } } - private fun selectInitialCurrencyToSwap(state: TokensDataStateExpress): CryptoCurrencyStatus? { - // todo add algorithm to select initial currency - return state.toGroup.available.firstOrNull()?.currencyStatus - } - private fun updateTokensState(dataState: TokensDataStateExpress) { val tokensDataState = if (!isOrderReversed) dataState.toGroup else dataState.fromGroup uiState = stateBuilder.addTokensToState(