Updated on 2026-08-14

This commit is contained in:
Tangem 2023-04-14 20:47:58 +09:00
parent 3c14484840
commit 8a1239f014
10 changed files with 374 additions and 110 deletions

View file

@ -35,6 +35,7 @@ internal object TokensListInteractorModule {
reduxStateHolder = reduxStateHolder,
testnetTokensStorage = testnetTokensStorage,
),
reduxStateHolder = reduxStateHolder,
)
}
}

View file

@ -1,17 +1,245 @@
package com.tangem.tap.features.tokens.domain
import androidx.paging.PagingData
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.common.CompletionResult
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toMapKey
import com.tangem.common.flatMap
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.features.tokens.domain.models.Token
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
import com.tangem.tap.features.tokens.redux.TokensMiddleware
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.tap.userWalletsListManager
import com.tangem.tap.walletCurrenciesManager
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import timber.log.Timber
/**
* Default implementation of tokens list interactor
* FIXME("Necessary to avoid using redux actions")
*
* @property repository repository of tokens list feature
* @property repository repository of tokens list feature
* @property reduxStateHolder redux state holder
*/
internal class DefaultTokensListInteractor(private val repository: TokensListRepository) : TokensListInteractor {
internal class DefaultTokensListInteractor(
private val repository: TokensListRepository,
private val reduxStateHolder: AppStateHolder,
) : TokensListInteractor {
override fun getTokensList(searchText: String): Flow<PagingData<Token>> {
return repository.getAvailableTokens(searchText = searchText.ifBlank(defaultValue = { null }))
}
override suspend fun saveChanges(tokens: List<TokenWithBlockchain>, blockchains: List<Blockchain>) {
val scanResponse = requireNotNull(reduxStateHolder.scanResponse)
val currentTokens = store.state.tokensState.addedWallets
.toNonCustomTokensWithBlockchains(style = scanResponse.card.derivationStyle)
val currentBlockchains = store.state.tokensState.addedWallets
.toNonCustomBlockchains(derivationStyle = scanResponse.card.derivationStyle)
val blockchainsToAdd = blockchains.filterNot(currentBlockchains::contains)
val blockchainsToRemove = currentBlockchains.filterNot(blockchains::contains)
val tokensToAdd = tokens.filterNot(currentTokens::contains)
val tokensToRemove = currentTokens.filterNot { token -> tokens.any { it.token == token.token } }
val isNothingToDoWithTokens = tokensToAdd.isEmpty() && tokensToRemove.isEmpty()
val isNothingToDoWithBlockchain = blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty()
if (isNothingToDoWithTokens && isNothingToDoWithBlockchain) {
store.dispatchDebugErrorNotification(message = "Nothing to save")
return
}
remove(
tokens = tokensToRemove,
blockchains = blockchainsToRemove,
derivationStyle = scanResponse.card.derivationStyle,
)
add(tokens = tokensToAdd, blockchains = blockchainsToAdd, scanResponse = scanResponse)
}
private fun List<WalletDataModel>.toNonCustomTokensWithBlockchains(
style: DerivationStyle?,
): List<TokenWithBlockchain> {
return this.map(WalletDataModel::currency)
.mapNotNull { currency ->
if (currency !is Currency.Token || currency.isCustomCurrency(style)) return@mapNotNull null
TokenWithBlockchain(token = currency.token, blockchain = currency.blockchain)
}
.distinct()
}
private fun List<WalletDataModel>.toNonCustomBlockchains(derivationStyle: DerivationStyle?): List<Blockchain> {
return this.map(WalletDataModel::currency)
.mapNotNull { currency ->
if (currency.isCustomCurrency(derivationStyle)) return@mapNotNull null
(currency as? Currency.Blockchain)?.blockchain
}
.distinct()
}
private suspend fun remove(
tokens: List<TokenWithBlockchain>,
blockchains: List<Blockchain>,
derivationStyle: DerivationStyle?,
) {
val currencies = convertToCurrencies(tokens, blockchains, derivationStyle)
if (currencies.isEmpty()) return
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
Timber.e("Unable to remove currencies, no user wallet selected")
return
}
walletCurrenciesManager.removeCurrencies(userWallet = selectedUserWallet, currenciesToRemove = currencies)
}
private suspend fun add(
tokens: List<TokenWithBlockchain>,
blockchains: List<Blockchain>,
scanResponse: ScanResponse,
) {
val currenciesToAdd = convertToCurrencies(
tokens = tokens,
blockchains = blockchains,
derivationStyle = scanResponse.card.derivationStyle,
)
// TODO("[REDACTED_TASK_KEY] use DerivationManager")
if (scanResponse.supportsHdWallet()) {
deriveMissingBlockchains(scanResponse, currenciesToAdd)
} else {
submitAdd(scanResponse, currenciesToAdd)
return
}
}
private suspend fun deriveMissingBlockchains(scanResponse: ScanResponse, currencies: List<Currency>) {
val derivations = listOfNotNull(
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencies),
getDerivations(EllipticCurve.Ed25519, scanResponse, currencies),
).associate(transform = TokensMiddleware.DerivationData::derivations)
if (derivations.isEmpty()) {
submitAdd(scanResponse, currencies)
return
}
when (val result = tangemSdkManager.derivePublicKeys(cardId = null, derivations = derivations)) {
is CompletionResult.Success -> {
val newDerivedKeys = result.data.entries
val oldDerivedKeys = scanResponse.derivedKeys
val walletKeys = (newDerivedKeys.keys + oldDerivedKeys.keys).toSet()
val updatedDerivedKeys = walletKeys.associateWith { walletKey ->
val oldDerivations = ExtendedPublicKeysMap(map = oldDerivedKeys[walletKey] ?: emptyMap())
val newDerivations = newDerivedKeys[walletKey] ?: ExtendedPublicKeysMap(map = emptyMap())
ExtendedPublicKeysMap(map = oldDerivations + newDerivations)
}
val updatedScanResponse = scanResponse.copy(derivedKeys = updatedDerivedKeys)
store.dispatchOnMain(GlobalAction.SaveScanResponse(updatedScanResponse))
delay(DELAY_SDK_DIALOG_CLOSE)
submitAdd(scanResponse, currencies)
return
}
is CompletionResult.Failure -> {
store.dispatchDebugErrorNotification(TapError.CustomError(customMessage = "Error adding tokens"))
}
}
}
private fun getDerivations(
curve: EllipticCurve,
scanResponse: ScanResponse,
currencyList: List<Currency>,
): TokensMiddleware.DerivationData? {
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
val manageTokensCandidates = currencyList
.map(Currency::blockchain)
.distinct()
.filter { it.getSupportedCurves().contains(curve) }
.mapNotNull { it.derivationPath(scanResponse.card.derivationStyle) }
val customTokensCandidates = currencyList
.filter { it.blockchain.getSupportedCurves().contains(curve) }
.mapNotNull(Currency::derivationPath)
.map(::DerivationPath)
val bothCandidates = (manageTokensCandidates + customTokensCandidates).distinct()
if (bothCandidates.isEmpty()) return null
val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
val alreadyDerivedKeys = scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap())
val alreadyDerivedPaths = alreadyDerivedKeys.keys.toList()
val toDerive = bothCandidates.filterNot(alreadyDerivedPaths::contains)
if (toDerive.isEmpty()) return null
return TokensMiddleware.DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
}
private suspend fun submitAdd(scanResponse: ScanResponse, currencies: List<Currency>) {
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
Timber.e("Unable to add currencies, no user wallet selected")
return
}
userWalletsListManager
.update(
userWalletId = selectedUserWallet.walletId,
update = { userWallet -> userWallet.copy(scanResponse = scanResponse) },
)
.flatMap { updatedUserWallet ->
walletCurrenciesManager.addCurrencies(
userWallet = updatedUserWallet,
currenciesToAdd = currencies,
)
}
}
private fun convertToCurrencies(
tokens: List<TokenWithBlockchain>,
blockchains: List<Blockchain>,
derivationStyle: DerivationStyle?,
): List<Currency> {
return tokens.map { tokenWithBlockchain ->
Currency.Token(
token = tokenWithBlockchain.token,
blockchain = tokenWithBlockchain.blockchain,
derivationPath = tokenWithBlockchain.blockchain.derivationPath(derivationStyle)?.rawPath,
)
}.plus(
blockchains.map { blockchain ->
Currency.Blockchain(
blockchain = blockchain,
derivationPath = blockchain.derivationPath(derivationStyle)?.rawPath,
)
},
)
}
}

View file

@ -1,7 +1,9 @@
package com.tangem.tap.features.tokens.domain
import androidx.paging.PagingData
import com.tangem.blockchain.common.Blockchain
import com.tangem.tap.features.tokens.domain.models.Token
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
import kotlinx.coroutines.flow.Flow
/**
@ -13,4 +15,12 @@ internal interface TokensListInteractor {
/** Get tokens list using filter by text [searchText] */
fun getTokensList(searchText: String): Flow<PagingData<Token>>
/**
* Save added tokens
*
* @param tokens tokens list that need to save
* @param blockchains blockchains list that need to save
*/
suspend fun saveChanges(tokens: List<TokenWithBlockchain>, blockchains: List<Blockchain>)
}

View file

@ -1,11 +1,17 @@
package com.tangem.tap.features.tokens.presentation.router
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchNotification
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.tokens.redux.TokensAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.store
import com.tangem.wallet.R
/**
* Default implementation of tokens list router
* FIXME("Necessary to avoid using redux actions")
*
[REDACTED_AUTHOR]
*/
@ -19,4 +25,29 @@ internal class DefaultTokensListRouter : TokensListRouter {
override fun openAddCustomTokenScreen() {
store.dispatch(TokensAction.PrepareAndNavigateToAddCustomToken)
}
override fun showAddressCopiedNotification() {
store.dispatchNotification(R.string.contract_address_copied_message)
}
override fun openUnableHideMainTokenAlert(tokenName: String, tokenSymbol: String) {
store.dispatchDialogShow(
dialog = WalletDialog.TokensAreLinkedDialog(currencyTitle = tokenName, currencySymbol = tokenSymbol),
)
}
override fun openRemoveWalletAlert(tokenName: String, onOkClick: () -> Unit) {
store.dispatchDialogShow(
dialog = WalletDialog.RemoveWalletDialog(currencyTitle = tokenName, onOk = onOkClick),
)
}
override fun openUnsupportedSoltanaNetworkAlert() {
store.dispatchDialogShow(
AppDialog.SimpleOkDialogRes(
headerId = R.string.common_warning,
messageId = R.string.alert_manage_tokens_unsupported_message,
),
)
}
}

View file

@ -6,6 +6,28 @@ internal interface TokensListRouter {
/** Return to last screen */
fun popBackStack()
/** Open screen for adding custom token */
/** Open adding custom token screen */
fun openAddCustomTokenScreen()
/** Show notification to inform about copied address */
fun showAddressCopiedNotification()
/**
* Open alert if unable to hide the main token
*
* @param tokenName token name
* @param tokenSymbol token brief name
*/
fun openUnableHideMainTokenAlert(tokenName: String, tokenSymbol: String)
/**
* Open alert to remove wallet
*
* @param tokenName token name
* @param onOkClick lambda be invoked if OkButton is been clicked
*/
fun openRemoveWalletAlert(tokenName: String, onOkClick: () -> Unit)
/** Open alert if solana network is unsupported */
fun openUnsupportedSoltanaNetworkAlert()
}

View file

@ -14,6 +14,9 @@ internal sealed interface TokensListStateHolder {
/** Toolbar state */
val toolbarState: TokensListToolbarState
/** Loading state */
val isLoading: Boolean
/** Tokens list */
val tokens: Flow<PagingData<TokenItemState>>
@ -24,34 +27,22 @@ internal sealed interface TokensListStateHolder {
* Util function that allow to make a copy
*
* @param toolbarState toolbar state
* @param isLoading loading state
* @param tokens tokens list
* @param onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed
*/
fun copySealed(
toolbarState: TokensListToolbarState = this.toolbarState,
isLoading: Boolean = this.isLoading,
tokens: Flow<PagingData<TokenItemState>> = this.tokens,
onTokensLoadStateChanged: (LoadState) -> Unit = this.onTokensLoadStateChanged,
): TokensListStateHolder {
return when (this) {
is ManageContent -> copy(toolbarState, tokens, onTokensLoadStateChanged)
is Loading -> copy(toolbarState, tokens, onTokensLoadStateChanged)
is ReadContent -> copy(toolbarState, tokens, onTokensLoadStateChanged)
is ManageContent -> copy(toolbarState, isLoading, tokens, onTokensLoadStateChanged)
is ReadContent -> copy(toolbarState, isLoading, tokens, onTokensLoadStateChanged)
}
}
/**
* Loading state
*
* @property toolbarState toolbar state
* @property tokens tokens list
* @property onTokensLoadStateChanged callback to be invoked when tokens loading state is been changed
*/
data class Loading(
override val toolbarState: TokensListToolbarState,
override val tokens: Flow<PagingData<TokenItemState>>,
override val onTokensLoadStateChanged: (LoadState) -> Unit,
) : TokensListStateHolder
/**
* State screen that is available only for read
*
@ -61,6 +52,7 @@ internal sealed interface TokensListStateHolder {
*/
data class ReadContent(
override val toolbarState: TokensListToolbarState,
override val isLoading: Boolean,
override val tokens: Flow<PagingData<TokenItemState>>,
override val onTokensLoadStateChanged: (LoadState) -> Unit,
) : TokensListStateHolder
@ -75,6 +67,7 @@ internal sealed interface TokensListStateHolder {
*/
data class ManageContent(
override val toolbarState: TokensListToolbarState,
override val isLoading: Boolean,
override val tokens: Flow<PagingData<TokenItemState>>,
override val onTokensLoadStateChanged: (LoadState) -> Unit,
val onSaveButtonClick: () -> Unit,

View file

@ -55,15 +55,12 @@ internal fun TokensListScreen(stateHolder: TokensListStateHolder) {
) { scaffoldPadding ->
val tokens = stateHolder.tokens.collectAsLazyPagingItems()
TokensListContent(
tokens = tokens,
scaffoldPadding = scaffoldPadding,
)
TokensListContent(tokens, scaffoldPadding)
stateHolder.onTokensLoadStateChanged(tokens.loadState.refresh)
AnimatedVisibility(
visible = stateHolder is TokensListStateHolder.Loading,
visible = stateHolder.isLoading,
enter = fadeIn(),
exit = fadeOut(),
) {
@ -122,13 +119,14 @@ private fun SaveChangesButton(onClick: () -> Unit) {
private fun Preview_TokensListScreen_Loading() {
TangemTheme {
TokensListScreen(
stateHolder = TokensListStateHolder.Loading(
stateHolder = TokensListStateHolder.ReadContent(
toolbarState = TokensListToolbarState.Title.Manage(
titleResId = R.string.main_manage_tokens,
onBackButtonClick = {},
onSearchButtonClick = {},
onAddCustomTokenClick = {},
),
isLoading = true,
tokens = emptyFlow(),
onTokensLoadStateChanged = {},
),
@ -148,6 +146,7 @@ private fun Preview_TokensListScreen_Manage() {
onSearchButtonClick = {},
onAddCustomTokenClick = {},
),
isLoading = false,
tokens = flow {
emit(
PagingData.from(
@ -176,6 +175,7 @@ private fun Preview_TokensListScreen_Read() {
onBackButtonClick = {},
onSearchButtonClick = {},
),
isLoading = false,
tokens = flow {
emit(
PagingData.from(

View file

@ -13,12 +13,9 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchNotification
import com.tangem.tap.common.extensions.fullNameWithoutTestnet
import com.tangem.tap.common.extensions.getGreyedOutIconRes
import com.tangem.tap.common.extensions.getNetworkName
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.features.tokens.domain.TokensListInteractor
import com.tangem.tap.features.tokens.domain.models.Token
import com.tangem.tap.features.tokens.domain.models.Token.Network
@ -29,10 +26,7 @@ import com.tangem.tap.features.tokens.presentation.states.TokenItemState
import com.tangem.tap.features.tokens.presentation.states.TokensListStateHolder
import com.tangem.tap.features.tokens.presentation.states.TokensListToolbarState
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
import com.tangem.tap.features.tokens.redux.TokensAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.store
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import com.tangem.utils.coroutines.Debouncer
import com.tangem.wallet.R
@ -40,7 +34,9 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import kotlinx.coroutines.withContext
import javax.inject.Inject
import com.tangem.blockchain.common.Token as BlockchainToken
@ -72,15 +68,28 @@ internal class TokensListViewModel @Inject constructor(
var uiState by mutableStateOf(value = getInitialUiState())
private set
private val addedTokenList: MutableList<TokenWithBlockchain> = args.mainScreenTokenList.toMutableList()
private val addedBlockchainList: MutableList<Blockchain> = args.mainScreenBlockchainList.toMutableList()
private val changedTokensList: MutableList<TokenWithBlockchain> = args.mainScreenTokenList.toMutableList()
private val changedBlockchainList: MutableList<Blockchain> = args.mainScreenBlockchainList.toMutableList()
private var saveButtonPressed = false
private fun getInitialUiState(): TokensListStateHolder {
return TokensListStateHolder.Loading(
toolbarState = getInitialToolbarState(),
tokens = getInitialTokensList(),
onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged,
)
return if (args.isManageAccess) {
TokensListStateHolder.ManageContent(
toolbarState = getInitialToolbarState(),
isLoading = true,
tokens = getInitialTokensList(),
onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged,
onSaveButtonClick = actionsHandler::onSaveButtonClick,
)
} else {
TokensListStateHolder.ReadContent(
toolbarState = getInitialToolbarState(),
isLoading = true,
tokens = getInitialTokensList(),
onTokensLoadStateChanged = actionsHandler::onTokensLoadStateChanged,
)
}
}
private fun getInitialToolbarState(): TokensListToolbarState {
@ -101,6 +110,8 @@ internal class TokensListViewModel @Inject constructor(
}
private fun getInitialTokensList(searchText: String = ""): Flow<PagingData<TokenItemState>> {
if (searchText.isNotEmpty()) analyticsSender.sendWhenTokenSearched()
return interactor.getTokensList(searchText = searchText).map {
it.map { token ->
if (args.isManageAccess) createManageTokenContent(token) else createReadTokenContent(token)
@ -177,11 +188,11 @@ internal class TokensListViewModel @Inject constructor(
private fun isAdded(address: String?, blockchain: Blockchain?): Boolean {
return if (address != null) {
addedTokenList.any { addedToken ->
changedTokensList.any { addedToken ->
address == addedToken.token.contractAddress && blockchain == addedToken.blockchain
}
} else {
addedBlockchainList.contains(blockchain)
changedBlockchainList.contains(blockchain)
}
}
@ -221,38 +232,22 @@ internal class TokensListViewModel @Inject constructor(
}
}
// FIXME("Necessary to avoid using redux actions")
fun onNetworkClick() {
store.dispatchNotification(R.string.contract_address_copied_message)
router.showAddressCopiedNotification()
}
fun onTokensLoadStateChanged(state: LoadState) {
uiState = when (state) {
is LoadState.NotLoading -> {
analyticsSender.sendWhenTokenSearched()
uiState = uiState.copySealed(isLoading = state is LoadState.Loading || saveButtonPressed)
if (saveButtonPressed) saveButtonPressed = false
}
if (args.isManageAccess) {
TokensListStateHolder.ManageContent(
toolbarState = uiState.toolbarState,
tokens = uiState.tokens,
onTokensLoadStateChanged = uiState.onTokensLoadStateChanged,
onSaveButtonClick = this::onSaveButtonClick,
)
} else {
TokensListStateHolder.ReadContent(
toolbarState = uiState.toolbarState,
tokens = uiState.tokens,
onTokensLoadStateChanged = uiState.onTokensLoadStateChanged,
)
}
}
else -> {
TokensListStateHolder.Loading(
toolbarState = uiState.toolbarState,
tokens = uiState.tokens,
onTokensLoadStateChanged = uiState.onTokensLoadStateChanged,
)
}
fun onSaveButtonClick() {
viewModelScope.launch(dispatchers.main) {
saveButtonPressed = true
analyticsSender.sendWhenSaveButtonClicked()
uiState = uiState.copySealed(isLoading = true)
withContext(dispatchers.io) { interactor.saveChanges(changedTokensList, changedBlockchainList) }
router.popBackStack()
}
}
@ -276,38 +271,34 @@ internal class TokensListViewModel @Inject constructor(
}
private fun updateBlockchainItem(toggledNetwork: NetworkItemState.ManageContent, blockchain: Blockchain) {
val isRemoveAction = addedBlockchainList.contains(blockchain)
val isRemoveAction = changedBlockchainList.contains(blockchain)
if (isRemoveAction) {
val isTokenWithSameBlockchainFound = addedTokenList.any { it.blockchain == blockchain }
val isTokenWithSameBlockchainFound = changedTokensList.any { it.blockchain == blockchain }
val isAddedOnMainScreen = args.mainScreenBlockchainList.contains(blockchain)
if (isTokenWithSameBlockchainFound) {
store.dispatchDialogShow(
WalletDialog.TokensAreLinkedDialog(
currencyTitle = blockchain.name,
currencySymbol = blockchain.currency,
),
router.openUnableHideMainTokenAlert(
tokenName = blockchain.name,
tokenSymbol = blockchain.currency,
)
} else if (isAddedOnMainScreen) {
store.dispatchDialogShow(
WalletDialog.RemoveWalletDialog(
currencyTitle = blockchain.name,
onOk = {
analyticsSender.sendWhenBlockchainAdded(blockchain)
addedBlockchainList.remove(blockchain)
toggledNetwork.changeToggleState()
},
),
router.openRemoveWalletAlert(
tokenName = blockchain.name,
onOkClick = {
analyticsSender.sendWhenBlockchainAdded(blockchain)
changedBlockchainList.remove(blockchain)
toggledNetwork.changeToggleState()
},
)
} else {
analyticsSender.sendWhenBlockchainRemoved(blockchain)
addedBlockchainList.remove(blockchain)
changedBlockchainList.remove(blockchain)
toggledNetwork.changeToggleState()
}
} else {
analyticsSender.sendWhenBlockchainAdded(blockchain)
addedBlockchainList.add(blockchain)
changedBlockchainList.add(blockchain)
toggledNetwork.changeToggleState()
}
}
@ -327,25 +318,23 @@ internal class TokensListViewModel @Inject constructor(
blockchain = toggledNetwork.blockchain,
)
val isRemoveAction = addedTokenList.contains(token)
val isRemoveAction = changedTokensList.contains(token)
if (isRemoveAction) {
val isAddedOnMainScreen = args.mainScreenTokenList.contains(token)
if (isAddedOnMainScreen) {
store.dispatchDialogShow(
WalletDialog.RemoveWalletDialog(
currencyTitle = token.token.name,
onOk = {
analyticsSender.sendWhenTokenRemoved(token.token)
addedTokenList.remove(token)
toggledNetwork.changeToggleState()
},
),
router.openRemoveWalletAlert(
tokenName = token.token.name,
onOkClick = {
analyticsSender.sendWhenTokenRemoved(token.token)
changedTokensList.remove(token)
toggledNetwork.changeToggleState()
},
)
} else {
analyticsSender.sendWhenTokenRemoved(token.token)
addedTokenList.remove(token)
changedTokensList.remove(token)
toggledNetwork.changeToggleState()
}
} else {
@ -353,24 +342,14 @@ internal class TokensListViewModel @Inject constructor(
!(reduxStateHolder.scanResponse?.card?.canHandleToken(token.blockchain) ?: false)
if (isUnsupportedToken) {
store.dispatchDialogShow(
AppDialog.SimpleOkDialogRes(
headerId = R.string.common_warning,
messageId = R.string.alert_manage_tokens_unsupported_message,
),
)
router.openUnsupportedSoltanaNetworkAlert()
} else {
analyticsSender.sendWhenTokenAdded(token.token)
addedTokenList.add(token)
changedTokensList.add(token)
toggledNetwork.changeToggleState()
}
}
}
private fun onSaveButtonClick() {
analyticsSender.sendWhenSaveButtonClicked()
store.dispatch(TokensAction.SaveChanges(addedTokenList, addedBlockchainList))
}
}
private companion object {

View file

@ -252,7 +252,7 @@ class TokensMiddleware {
return DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
}
private class DerivationData(val derivations: Pair<ByteArrayKey, List<DerivationPath>>)
class DerivationData(val derivations: Pair<ByteArrayKey, List<DerivationPath>>)
private fun submitAdd(scanResponse: ScanResponse, currencyList: List<Currency>) {
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {

View file

@ -71,7 +71,7 @@ kotlinSerialization = "1.4.1"
# endregion Other libraries
# region Tangem
tangemBlockchainSdk = "develop-197"
tangemBlockchainSdk = "develop-198"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-213"
# tangemCardSdk = "0.0.1" # Keep it! - used for local builds