Updated on 2026-08-14

This commit is contained in:
Tangem 2023-10-05 17:41:54 +03:00
parent 81ad4db392
commit 5bbbd9e945
5 changed files with 109 additions and 77 deletions

View file

@ -22,6 +22,7 @@ import com.tangem.domain.common.extensions.*
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.features.addCustomToken.CustomCurrency
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenInteractor
import com.tangem.tap.features.customtoken.impl.domain.models.FoundToken
@ -35,7 +36,6 @@ import com.tangem.tap.features.customtoken.impl.presentation.validators.ContactA
import com.tangem.tap.features.customtoken.impl.presentation.validators.ContractAddressValidatorResult
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.store
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import com.tangem.utils.coroutines.runCatching
@ -51,11 +51,11 @@ import javax.inject.Inject
/**
* ViewModel for add custom token screen
*
* @param analyticsEventHandler analytics event handler
* @param featureRouter feature router
* @property featureInteractor feature interactor
* @property dispatchers coroutine dispatchers provider
* @property reduxStateHolder redux state holder
* @param analyticsEventHandler analytics event handler
* @param featureRouter feature router
* @property featureInteractor feature interactor
* @property getSelectedWalletUseCase use case that returns selected wallet
* @property dispatchers coroutine dispatchers provider
*
[REDACTED_AUTHOR]
*/
@ -66,7 +66,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
featureRouter: CustomTokenRouter,
private val featureInteractor: CustomTokenInteractor,
private val dispatchers: AppCoroutineDispatcherProvider,
private val reduxStateHolder: AppStateHolder,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
) : ViewModel(), DefaultLifecycleObserver {
private val analyticsSender = AddCustomTokenAnalyticsSender(analyticsEventHandler)
@ -208,7 +208,10 @@ internal class AddCustomTokenViewModel @Inject constructor(
private fun getNetworkSelectorItems(): List<SelectorItem.Title> {
val defaultNetwork = createNetworkSelectorItem(blockchain = Blockchain.Unknown)
val scanResponse = reduxStateHolder.scanResponse
val scanResponse = getSelectedWalletUseCase().fold(
ifLeft = { null },
ifRight = { it.scanResponse },
)
val derivationStyle = scanResponse?.derivationStyleProvider?.getDerivationStyle()
return listOf(defaultNetwork) + Blockchain.values()
.filter { blockchain ->
@ -262,17 +265,20 @@ internal class AddCustomTokenViewModel @Inject constructor(
}
private fun createDerivationPathsSelectorField(): AddCustomTokenSelectorField.DerivationPath? {
val scanResponse = reduxStateHolder.scanResponse
if (scanResponse?.card?.settings?.isHDWalletAllowed == false) return null
return getSelectedWalletUseCase().fold(
ifLeft = { null },
ifRight = {
if (!it.scanResponse.card.settings.isHDWalletAllowed) return null
val selectorItems =
getDerivationPathsSelectorItems(scanResponse?.derivationStyleProvider)
return AddCustomTokenSelectorField.DerivationPath(
label = TextReference.Res(R.string.custom_token_derivation_path_input_title),
selectedItem = requireNotNull(selectorItems.firstOrNull()),
items = selectorItems,
onMenuItemClick = actionsHandler::onDerivationPathSelectorItemClick,
isEnabled = true,
val selectorItems = getDerivationPathsSelectorItems(it.scanResponse.derivationStyleProvider)
AddCustomTokenSelectorField.DerivationPath(
label = TextReference.Res(R.string.custom_token_derivation_path_input_title),
selectedItem = requireNotNull(selectorItems.firstOrNull()),
items = selectorItems,
onMenuItemClick = actionsHandler::onDerivationPathSelectorItemClick,
isEnabled = true,
)
},
)
}
@ -315,14 +321,19 @@ internal class AddCustomTokenViewModel @Inject constructor(
}
private fun createDerivationPathInputField(): AddCustomTokenInputField.DerivationPath? {
if (reduxStateHolder.scanResponse?.card?.settings?.isHDWalletAllowed == false) return null
return getSelectedWalletUseCase().fold(
ifLeft = { null },
ifRight = {
if (!it.scanResponse.card.settings.isHDWalletAllowed) return null
return AddCustomTokenInputField.DerivationPath(
value = "",
onValueChange = actionsHandler::onDerivationPathValueChange,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
label = TextReference.Res(R.string.custom_token_custom_derivation),
placeholder = TextReference.Str(value = DERIVATION_PATH_PLACEHOLDER),
AddCustomTokenInputField.DerivationPath(
value = "",
onValueChange = actionsHandler::onDerivationPathValueChange,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
label = TextReference.Res(R.string.custom_token_custom_derivation),
placeholder = TextReference.Str(value = DERIVATION_PATH_PLACEHOLDER),
)
},
)
}
}
@ -440,11 +451,15 @@ internal class AddCustomTokenViewModel @Inject constructor(
val isSupportedToken = if (!isNetworkSelected()) {
true
} else {
val scanResponse = reduxStateHolder.scanResponse
scanResponse?.card?.canHandleToken(
blockchain = networkSelectorValue,
cardTypesResolver = scanResponse.cardTypesResolver,
) ?: false
getSelectedWalletUseCase().fold(
ifLeft = { false },
ifRight = {
it.scanResponse.card.canHandleToken(
blockchain = networkSelectorValue,
cardTypesResolver = it.scanResponse.cardTypesResolver,
)
},
)
}
return buildSet {
@ -478,13 +493,16 @@ internal class AddCustomTokenViewModel @Inject constructor(
address = uiState.form.contractAddressInputField.value,
blockchain = networkSelectorValue,
)
val scanResponse = reduxStateHolder.scanResponse
val isSupportedToken = scanResponse?.card
?.canHandleToken(
blockchain = networkSelectorValue,
cardTypesResolver = scanResponse.cardTypesResolver,
)
?: false
val isSupportedToken = getSelectedWalletUseCase().fold(
ifLeft = { false },
ifRight = {
it.scanResponse.card.canHandleToken(
blockchain = networkSelectorValue,
cardTypesResolver = it.scanResponse.cardTypesResolver,
)
},
)
uiState.copySealed(
floatingButton = uiState.floatingButton.copy(
@ -641,8 +659,12 @@ internal class AddCustomTokenViewModel @Inject constructor(
private fun getDerivationPathForBlockchain(blockchain: Blockchain?): DerivationPath? {
if (blockchain == null) return null
val derivationStyle = reduxStateHolder.scanResponse?.derivationStyleProvider?.getDerivationStyle()
?: DerivationStyle.V1
val derivationStyle = getSelectedWalletUseCase().fold(
ifLeft = { null },
ifRight = {
it.scanResponse.derivationStyleProvider.getDerivationStyle()
},
)
val derivationNetwork = if (blockchain == Blockchain.Unknown) {
uiState.form.networkSelectorField.selectedItem.blockchain
@ -653,12 +675,15 @@ internal class AddCustomTokenViewModel @Inject constructor(
}
private fun isUnsupportedBlockchain(blockchain: Blockchain): Boolean {
val scanResponse = reduxStateHolder.scanResponse
val canHandleToken = scanResponse?.card?.canHandleBlockchain(
blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
) ?: false
return !canHandleToken
return getSelectedWalletUseCase().fold(
ifLeft = { false },
ifRight = {
!it.scanResponse.card.canHandleBlockchain(
blockchain = blockchain,
cardTypesResolver = it.scanResponse.cardTypesResolver,
)
},
)
}
private inner class ActionsHandler(private val featureRouter: CustomTokenRouter) {
@ -827,7 +852,6 @@ internal class AddCustomTokenViewModel @Inject constructor(
}
fun onResetButtonClick() {
val scanResponse = reduxStateHolder.scanResponse
with(uiState.form) {
uiState = uiState.copySealed(
form = uiState.form.copy(

View file

@ -6,26 +6,26 @@ import androidx.paging.PagingData
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.testnet.TestnetTokensStorage
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.tap.features.tokens.impl.domain.TokensListRepository
import com.tangem.tap.features.tokens.impl.domain.models.Token
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.Flow
/**
* Default repository implementation of tokens list feature
*
* @property tangemTechApi Tangem Tech API
* @property dispatchers coroutine dispatchers provider
* @property reduxStateHolder redux state holder
* @property testnetTokensStorage storage for getting testnet tokens data
* @property tangemTechApi Tangem Tech API
* @property dispatchers coroutine dispatchers provider
* @property getSelectedWalletUseCase use case that returns selected wallet
* @property testnetTokensStorage storage for getting testnet tokens data
*
[REDACTED_AUTHOR]
*/
internal class DefaultTokensListRepository(
private val tangemTechApi: TangemTechApi,
private val dispatchers: CoroutineDispatcherProvider,
private val reduxStateHolder: AppStateHolder,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val testnetTokensStorage: TestnetTokensStorage,
) : TokensListRepository {
@ -37,16 +37,23 @@ internal class DefaultTokensListRepository(
enablePlaceholders = false,
),
pagingSourceFactory = {
if (reduxStateHolder.scanResponse?.card?.isTestCard == true) {
TestnetTokensPagingSource(testnetTokensStorage, searchText)
} else {
TangemApiTokensPagingSource(
api = tangemTechApi,
dispatchers = dispatchers,
reduxStateHolder = reduxStateHolder,
searchText = searchText,
)
}
val defaultSource = TangemApiTokensPagingSource(
api = tangemTechApi,
dispatchers = dispatchers,
getSelectedWalletUseCase = getSelectedWalletUseCase,
searchText = searchText,
)
getSelectedWalletUseCase().fold(
ifLeft = { defaultSource },
ifRight = {
if (it.scanResponse.card.isTestCard) {
TestnetTokensPagingSource(testnetTokensStorage, searchText)
} else {
defaultSource
}
},
)
},
).flow
}

View file

@ -7,24 +7,24 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.common.extensions.supportedBlockchains
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.tap.features.tokens.impl.data.converters.CoinsResponseConverter
import com.tangem.tap.features.tokens.impl.domain.models.Token
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runCatching
/**
* Paging source that get tokens by Tangem Tech API
*
* @property api Tangem Tech API
* @property dispatchers coroutine dispatchers provider
* @property reduxStateHolder redux state holder
* @property searchText search text
* @property api Tangem Tech API
* @property dispatchers coroutine dispatchers provider
* @property getSelectedWalletUseCase use case that returns selected wallet
* @property searchText search text
*/
internal class TangemApiTokensPagingSource(
private val api: TangemTechApi,
private val dispatchers: CoroutineDispatcherProvider,
private val reduxStateHolder: AppStateHolder,
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
private val searchText: String?,
) : PagingSource<Int, Token>() {
@ -39,9 +39,10 @@ internal class TangemApiTokensPagingSource(
val page = params.key ?: 0
return runCatching(dispatchers.io) {
val scanResponse = reduxStateHolder.scanResponse
val supportedBlockchains = scanResponse?.card?.supportedBlockchains(scanResponse.cardTypesResolver)
?: Blockchain.values().toList()
val supportedBlockchains = getSelectedWalletUseCase().fold(
ifLeft = { Blockchain.values().toList() },
ifRight = { it.scanResponse.card.supportedBlockchains(it.scanResponse.cardTypesResolver) },
)
api.getCoins(
networkIds = supportedBlockchains.joinToString(separator = ",", transform = Blockchain::toNetworkId),

View file

@ -2,10 +2,10 @@ package com.tangem.tap.features.tokens.impl.di
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.testnet.TestnetTokensStorage
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.tap.features.tokens.impl.data.DefaultTokensListRepository
import com.tangem.tap.features.tokens.impl.domain.DefaultTokensListInteractor
import com.tangem.tap.features.tokens.impl.domain.TokensListInteractor
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@ -25,14 +25,14 @@ internal object TokensListInteractorModule {
fun provideTokensListInteractor(
tangemTechApi: TangemTechApi,
dispatchers: CoroutineDispatcherProvider,
reduxStateHolder: AppStateHolder,
getSelectedWalletUseCase: GetSelectedWalletUseCase,
testnetTokensStorage: TestnetTokensStorage,
): TokensListInteractor {
return DefaultTokensListInteractor(
repository = DefaultTokensListRepository(
tangemTechApi = tangemTechApi,
dispatchers = dispatchers,
reduxStateHolder = reduxStateHolder,
getSelectedWalletUseCase = getSelectedWalletUseCase,
testnetTokensStorage = testnetTokensStorage,
),
)

View file

@ -2,9 +2,9 @@ package com.tangem.tap.features.tokens.impl.di
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.testnet.TestnetTokensStorage
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.tap.features.tokens.impl.data.DefaultTokensListRepository
import com.tangem.tap.features.tokens.impl.domain.TokensListRepository
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@ -24,13 +24,13 @@ internal object TokensListRepositoryModule {
fun providesTokensListRepository(
tangemTechApi: TangemTechApi,
dispatchers: CoroutineDispatcherProvider,
reduxStateHolder: AppStateHolder,
getSelectedWalletUseCase: GetSelectedWalletUseCase,
testnetTokensStorage: TestnetTokensStorage,
): TokensListRepository {
return DefaultTokensListRepository(
tangemTechApi = tangemTechApi,
dispatchers = dispatchers,
reduxStateHolder = reduxStateHolder,
getSelectedWalletUseCase = getSelectedWalletUseCase,
testnetTokensStorage = testnetTokensStorage,
)
}