Updated on 2026-08-14
This commit is contained in:
parent
199c2795ad
commit
92ee3c0273
10 changed files with 140 additions and 7 deletions
|
|
@ -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<Preferences> */
|
||||
|
|
|
|||
|
|
@ -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<SavedLastSwappedCryptoCurrency>(
|
||||
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<SavedLastSwappedCryptoCurrency>? = 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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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?
|
||||
}
|
||||
|
|
@ -85,4 +85,9 @@ interface SwapInteractor {
|
|||
fun isAvailableToSwap(networkId: String): Boolean
|
||||
|
||||
fun getSelectedWallet(): UserWallet?
|
||||
|
||||
suspend fun selectInitialCurrencyToSwap(
|
||||
initialCryptoCurrency: CryptoCurrency,
|
||||
state: TokensDataStateExpress,
|
||||
): CryptoCurrencyStatus?
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.feature.swap.domain.models.domain
|
||||
|
||||
data class SavedLastSwappedCryptoCurrency(
|
||||
val userWalletId: String,
|
||||
val cryptoCurrencyId: String,
|
||||
)
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue