Updated on 2026-08-14
This commit is contained in:
commit
5f4318ca5d
39 changed files with 619 additions and 120 deletions
|
|
@ -51,7 +51,17 @@ internal class PreviewCustomTokenSelectorComponent(
|
|||
)
|
||||
|
||||
CurrencyNetworkUM(
|
||||
networkId = n.id,
|
||||
network = Network(
|
||||
id = n.id,
|
||||
backendId = n.id.value,
|
||||
name = "",
|
||||
currencySymbol = "",
|
||||
derivationPath = Network.DerivationPath.Card(""),
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.ERC20,
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = false,
|
||||
),
|
||||
name = "Network $index",
|
||||
type = "N$index",
|
||||
iconResId = R.drawable.ic_eth_16,
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ internal class PreviewManageTokensComponent : ManageTokensComponent {
|
|||
isNextBatchLoading = true,
|
||||
loadMore = { false },
|
||||
saveChanges = {},
|
||||
isSavingInProgress = false,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -134,7 +135,17 @@ internal class PreviewManageTokensComponent : ManageTokensComponent {
|
|||
|
||||
private fun getCurrencyNetworks(currencyIndex: Int) = List(size = 3) { networkIndex ->
|
||||
CurrencyNetworkUM(
|
||||
networkId = Network.ID(networkIndex.toString()),
|
||||
network = Network(
|
||||
id = Network.ID(networkIndex.toString()),
|
||||
backendId = networkIndex.toString(),
|
||||
name = "",
|
||||
currencySymbol = "",
|
||||
derivationPath = Network.DerivationPath.Card(""),
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.ERC20,
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = false,
|
||||
),
|
||||
name = "NETWORK$networkIndex",
|
||||
type = "N$networkIndex",
|
||||
iconResId = R.drawable.ic_eth_16,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.features.managetokens.entity.item
|
|||
import com.tangem.domain.tokens.model.Network
|
||||
|
||||
internal data class CurrencyNetworkUM(
|
||||
val networkId: Network.ID,
|
||||
val network: Network,
|
||||
val name: String,
|
||||
val type: String,
|
||||
val iconResId: Int,
|
||||
|
|
@ -12,5 +12,5 @@ internal data class CurrencyNetworkUM(
|
|||
override val onSelectedStateChange: (Boolean) -> Unit,
|
||||
) : SelectableItemUM {
|
||||
|
||||
override val id: String = networkId.value
|
||||
override val id: String = network.id.value
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ internal sealed class ManageTokensUM {
|
|||
override val loadMore: () -> Boolean,
|
||||
val saveChanges: () -> Unit,
|
||||
val hasChanges: Boolean,
|
||||
val isSavingInProgress: Boolean,
|
||||
) : ManageTokensUM()
|
||||
|
||||
fun copySealed(
|
||||
|
|
@ -44,6 +45,7 @@ internal sealed class ManageTokensUM {
|
|||
hasChanges: Boolean = this is ManageContent && this.hasChanges,
|
||||
isInitialBatchLoading: Boolean = this.isInitialBatchLoading,
|
||||
isNextBatchLoading: Boolean = this.isNextBatchLoading,
|
||||
isSavingInProgress: Boolean = this is ManageContent && this.isSavingInProgress,
|
||||
): ManageTokensUM {
|
||||
return when (this) {
|
||||
is ManageContent -> copy(
|
||||
|
|
@ -52,6 +54,7 @@ internal sealed class ManageTokensUM {
|
|||
hasChanges = hasChanges,
|
||||
isInitialBatchLoading = isInitialBatchLoading,
|
||||
isNextBatchLoading = isNextBatchLoading,
|
||||
isSavingInProgress = isSavingInProgress,
|
||||
)
|
||||
is ReadContent -> copy(
|
||||
search = search,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.managetokens.SaveManagedTokensUseCase
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.ManageTokensComponent
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyItemUM
|
||||
|
|
@ -21,12 +22,14 @@ import com.tangem.features.managetokens.entity.managetokens.ManageTokensUM
|
|||
import com.tangem.features.managetokens.impl.R
|
||||
import com.tangem.features.managetokens.utils.list.ChangedCurrencies
|
||||
import com.tangem.features.managetokens.utils.list.ManageTokensListManager
|
||||
import com.tangem.pagination.BatchFetchResult
|
||||
import com.tangem.pagination.PaginationStatus
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ComponentScoped
|
||||
|
|
@ -35,6 +38,7 @@ internal class ManageTokensModel @Inject constructor(
|
|||
private val router: Router,
|
||||
private val manageTokensListManager: ManageTokensListManager,
|
||||
private val messageSender: UiMessageSender,
|
||||
private val saveManagedTokensUseCase: SaveManagedTokensUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -76,7 +80,7 @@ internal class ManageTokensModel @Inject constructor(
|
|||
popBack = router::pop,
|
||||
isInitialBatchLoading = true,
|
||||
isNextBatchLoading = false,
|
||||
items = getInitialItems(),
|
||||
items = persistentListOf(),
|
||||
topBar = ManageTokensTopBarUM.ReadContent(
|
||||
title = resourceReference(R.string.common_search_tokens),
|
||||
onBackButtonClick = router::pop,
|
||||
|
|
@ -97,7 +101,7 @@ internal class ManageTokensModel @Inject constructor(
|
|||
popBack = router::pop,
|
||||
isInitialBatchLoading = true,
|
||||
isNextBatchLoading = false,
|
||||
items = getInitialItems(),
|
||||
items = persistentListOf(),
|
||||
topBar = ManageTokensTopBarUM.ManageContent(
|
||||
title = resourceReference(id = R.string.main_manage_tokens),
|
||||
onBackButtonClick = router::pop,
|
||||
|
|
@ -116,6 +120,7 @@ internal class ManageTokensModel @Inject constructor(
|
|||
hasChanges = false,
|
||||
saveChanges = ::saveChanges,
|
||||
loadMore = ::loadMoreItems,
|
||||
isSavingInProgress = false,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -157,9 +162,16 @@ internal class ManageTokensModel @Inject constructor(
|
|||
isNextBatchLoading = false,
|
||||
)
|
||||
}
|
||||
is PaginationStatus.Paginating,
|
||||
is PaginationStatus.EndOfPagination,
|
||||
-> state.copySealed(
|
||||
is PaginationStatus.Paginating -> {
|
||||
(status.lastResult as? BatchFetchResult.Error)?.let { fetchError ->
|
||||
Timber.e(fetchError.throwable)
|
||||
}
|
||||
state.copySealed(
|
||||
isInitialBatchLoading = false,
|
||||
isNextBatchLoading = false,
|
||||
)
|
||||
}
|
||||
is PaginationStatus.EndOfPagination -> state.copySealed(
|
||||
isInitialBatchLoading = false,
|
||||
isNextBatchLoading = false,
|
||||
)
|
||||
|
|
@ -189,10 +201,6 @@ internal class ManageTokensModel @Inject constructor(
|
|||
return true
|
||||
}
|
||||
|
||||
private fun getInitialItems(): ImmutableList<CurrencyItemUM> {
|
||||
return persistentListOf()
|
||||
}
|
||||
|
||||
private fun navigateToAddCustomToken() {
|
||||
params.userWalletId?.let {
|
||||
bottomSheetNavigation.activate(BottomSheetConfig.AddCustomToken(it))
|
||||
|
|
@ -200,7 +208,18 @@ internal class ManageTokensModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun saveChanges() {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
modelScope.launch {
|
||||
state.update { state -> state.copySealed(isSavingInProgress = true) }
|
||||
saveManagedTokensUseCase.invoke(
|
||||
userWalletId = requireNotNull(params.userWalletId),
|
||||
currenciesToAdd = manageTokensListManager.currenciesToAdd.value,
|
||||
currenciesToRemove = manageTokensListManager.currenciesToRemove.value,
|
||||
).fold(
|
||||
ifLeft = { Timber.e(it, "Failed to save changes") },
|
||||
ifRight = { router.pop() },
|
||||
)
|
||||
state.update { state -> state.copySealed(isSavingInProgress = false) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun searchCurrencies(query: String) {
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modi
|
|||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
isVisible = state.hasChanges,
|
||||
showProgress = state.isSavingInProgress,
|
||||
onClick = state.saveChanges,
|
||||
)
|
||||
}
|
||||
|
|
@ -133,7 +134,12 @@ private fun ManageTokensTopBar(topBar: ManageTokensTopBarUM, search: SearchBarUM
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun SaveChangesButton(isVisible: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
private fun SaveChangesButton(
|
||||
isVisible: Boolean,
|
||||
showProgress: Boolean,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
modifier = modifier,
|
||||
visible = isVisible,
|
||||
|
|
@ -144,6 +150,7 @@ private fun SaveChangesButton(isVisible: Boolean, onClick: () -> Unit, modifier:
|
|||
PrimaryButtonIconEnd(
|
||||
text = stringResource(id = R.string.common_save),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
showProgress = showProgress,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,54 +5,54 @@ import com.tangem.domain.tokens.model.Network
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
internal typealias ChangedCurrencies = Map<ManagedCryptoCurrency.ID, Set<Network.ID>>
|
||||
internal typealias ChangedCurrencies = Map<ManagedCryptoCurrency.Token, Set<Network>>
|
||||
|
||||
internal class ChangedCurrenciesManager {
|
||||
|
||||
val currenciesToAdd: MutableStateFlow<ChangedCurrencies> = MutableStateFlow(emptyMap())
|
||||
val currenciesToRemove: MutableStateFlow<ChangedCurrencies> = MutableStateFlow(emptyMap())
|
||||
|
||||
fun addCurrency(currencyId: ManagedCryptoCurrency.ID, networkId: Network.ID) {
|
||||
updateChangedItems(currencyId, networkId, currenciesToRemove, currenciesToAdd)
|
||||
fun addCurrency(currency: ManagedCryptoCurrency.Token, network: Network) {
|
||||
updateChangedItems(currency, network, currenciesToRemove, currenciesToAdd)
|
||||
}
|
||||
|
||||
fun removeCurrency(currencyId: ManagedCryptoCurrency.ID, networkId: Network.ID) {
|
||||
updateChangedItems(currencyId, networkId, currenciesToAdd, currenciesToRemove)
|
||||
fun removeCurrency(currency: ManagedCryptoCurrency.Token, network: Network) {
|
||||
updateChangedItems(currency, network, currenciesToAdd, currenciesToRemove)
|
||||
}
|
||||
|
||||
fun containsCurrency(currencyId: ManagedCryptoCurrency.ID, networkId: Network.ID): Boolean {
|
||||
return networkId in currenciesToAdd.value[currencyId].orEmpty() ||
|
||||
networkId in currenciesToRemove.value[currencyId].orEmpty()
|
||||
fun containsCurrency(currency: ManagedCryptoCurrency.Token, network: Network): Boolean {
|
||||
return network in currenciesToAdd.value[currency].orEmpty() ||
|
||||
network in currenciesToRemove.value[currency].orEmpty()
|
||||
}
|
||||
|
||||
private fun updateChangedItems(
|
||||
currencyId: ManagedCryptoCurrency.ID,
|
||||
networkId: Network.ID,
|
||||
currency: ManagedCryptoCurrency.Token,
|
||||
network: Network,
|
||||
removeFromIfPresent: MutableStateFlow<ChangedCurrencies>,
|
||||
addToIfNotPresent: MutableStateFlow<ChangedCurrencies>,
|
||||
) {
|
||||
val present = removeFromIfPresent.value[currencyId].orEmpty()
|
||||
val present = removeFromIfPresent.value[currency].orEmpty()
|
||||
|
||||
if (networkId in present) {
|
||||
if (network in present) {
|
||||
removeFromIfPresent.update { items ->
|
||||
items.toMutableMap().apply {
|
||||
val ids = present - networkId
|
||||
val ids = present - network
|
||||
|
||||
if (ids.isEmpty()) {
|
||||
remove(currencyId)
|
||||
remove(currency)
|
||||
} else {
|
||||
set(currencyId, ids)
|
||||
set(currency, ids)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addToIfNotPresent.update { items ->
|
||||
val alreadyAdded = items[currencyId] ?: emptySet()
|
||||
if (networkId in alreadyAdded) {
|
||||
val alreadyAdded = items[currency] ?: emptySet()
|
||||
if (network in alreadyAdded) {
|
||||
return@update items
|
||||
}
|
||||
|
||||
items + (currencyId to alreadyAdded + networkId)
|
||||
items + (currency to alreadyAdded + network)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ internal class ManageTokensListManager @Inject constructor(
|
|||
scopeProvider = Provider { scope },
|
||||
)
|
||||
|
||||
val currenciesToAdd: StateFlow<ChangedCurrencies> = changedCurrenciesManager.currenciesToAdd
|
||||
val currenciesToRemove: StateFlow<ChangedCurrencies> = changedCurrenciesManager.currenciesToRemove
|
||||
val currenciesToAdd: StateFlow<ChangedCurrencies> = changedCurrenciesManager.currenciesToAdd.asStateFlow()
|
||||
val currenciesToRemove: StateFlow<ChangedCurrencies> = changedCurrenciesManager.currenciesToRemove.asStateFlow()
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val paginationStatus: Flow<PaginationStatus<*>> = state
|
||||
|
|
@ -148,32 +148,32 @@ internal class ManageTokensListManager @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun addCurrency(batchKey: Int, currencyId: ManagedCryptoCurrency.ID, networkId: Network.ID) {
|
||||
changedCurrenciesManager.addCurrency(currencyId, networkId)
|
||||
override fun addCurrency(batchKey: Int, currency: ManagedCryptoCurrency.Token, network: Network) {
|
||||
changedCurrenciesManager.addCurrency(currency, network)
|
||||
|
||||
sendSelectCurrencyAction(batchKey, currencyId, networkId, isSelected = true)
|
||||
sendSelectCurrencyAction(batchKey, currency.id, network, isSelected = true)
|
||||
}
|
||||
|
||||
override fun removeCurrency(batchKey: Int, currencyId: ManagedCryptoCurrency.ID, networkId: Network.ID) {
|
||||
changedCurrenciesManager.removeCurrency(currencyId, networkId)
|
||||
override fun removeCurrency(batchKey: Int, currency: ManagedCryptoCurrency.Token, network: Network) {
|
||||
changedCurrenciesManager.removeCurrency(currency, network)
|
||||
|
||||
sendSelectCurrencyAction(batchKey, currencyId, networkId, isSelected = false)
|
||||
sendSelectCurrencyAction(batchKey, currency.id, network, isSelected = false)
|
||||
}
|
||||
|
||||
override fun checkNeedToShowRemoveNetworkWarning(
|
||||
currencyId: ManagedCryptoCurrency.ID,
|
||||
networkId: Network.ID,
|
||||
): Boolean = !changedCurrenciesManager.containsCurrency(currencyId, networkId)
|
||||
currency: ManagedCryptoCurrency.Token,
|
||||
network: Network,
|
||||
): Boolean = !changedCurrenciesManager.containsCurrency(currency, network)
|
||||
|
||||
private fun sendSelectCurrencyAction(
|
||||
batchKey: Int,
|
||||
currencyId: ManagedCryptoCurrency.ID,
|
||||
networkId: Network.ID,
|
||||
network: Network,
|
||||
isSelected: Boolean,
|
||||
) {
|
||||
val request = ManageTokensUpdateAction.AddCurrency(
|
||||
currencyId = currencyId,
|
||||
networkId = networkId,
|
||||
network = network,
|
||||
isSelected = isSelected,
|
||||
)
|
||||
val action = BatchAction.UpdateBatches(
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
|
||||
internal interface ManageTokensUiActions {
|
||||
|
||||
fun addCurrency(batchKey: Int, currencyId: ManagedCryptoCurrency.ID, networkId: Network.ID)
|
||||
fun addCurrency(batchKey: Int, currency: ManagedCryptoCurrency.Token, network: Network)
|
||||
|
||||
fun removeCurrency(batchKey: Int, currencyId: ManagedCryptoCurrency.ID, networkId: Network.ID)
|
||||
fun removeCurrency(batchKey: Int, currency: ManagedCryptoCurrency.Token, network: Network)
|
||||
|
||||
fun checkNeedToShowRemoveNetworkWarning(currencyId: ManagedCryptoCurrency.ID, networkId: Network.ID): Boolean
|
||||
fun checkNeedToShowRemoveNetworkWarning(currency: ManagedCryptoCurrency.Token, network: Network): Boolean
|
||||
|
||||
suspend fun checkHasLinkedTokens(userWalletId: UserWalletId, network: Network): Boolean
|
||||
}
|
||||
|
|
@ -142,19 +142,19 @@ internal class ManageTokensUiManager(
|
|||
if (currency !is ManagedCryptoCurrency.Token) return@launch
|
||||
|
||||
if (isSelected) {
|
||||
actions.addCurrency(batchKey, currency.id, source.id)
|
||||
actions.addCurrency(batchKey, currency, source.network)
|
||||
} else {
|
||||
if (actions.checkNeedToShowRemoveNetworkWarning(currency.id, source.id)) {
|
||||
if (actions.checkNeedToShowRemoveNetworkWarning(currency, source.network)) {
|
||||
showRemoveNetworkWarning(
|
||||
currency = currency,
|
||||
network = source.network,
|
||||
isCoin = source is ManagedCryptoCurrency.SourceNetwork.Main,
|
||||
onConfirm = {
|
||||
actions.removeCurrency(batchKey, currency.id, source.id)
|
||||
actions.removeCurrency(batchKey, currency, source.network)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
actions.removeCurrency(batchKey, currency.id, source.id)
|
||||
actions.removeCurrency(batchKey, currency, source.network)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ internal fun ManagedCryptoCurrency.Token.toUiNetworksModel(
|
|||
NetworksUM.Expanded(
|
||||
networks = availableNetworks.map {
|
||||
it.toUiModel(
|
||||
isSelected = it.id in addedIn,
|
||||
isSelected = it.network in addedIn,
|
||||
isEditable = isItemsEditable,
|
||||
onSelectedStateChange = onSelectedStateChange,
|
||||
)
|
||||
|
|
@ -33,7 +33,7 @@ private fun SourceNetwork.toUiModel(
|
|||
onSelectedStateChange: (SourceNetwork, Boolean) -> Unit,
|
||||
): CurrencyNetworkUM {
|
||||
return CurrencyNetworkUM(
|
||||
networkId = id,
|
||||
network = network,
|
||||
name = network.name.uppercase(),
|
||||
iconResId = id.getIconRes(isColored = isSelected || !isEditable),
|
||||
isSelected = isSelected || !isEditable,
|
||||
|
|
|
|||
|
|
@ -55,10 +55,10 @@ private fun CurrencyItemUM.Basic.updateNetworks(currency: ManagedCryptoCurrency.
|
|||
is NetworksUM.Collapsed -> networks
|
||||
is NetworksUM.Expanded -> networks.copy(
|
||||
networks = networks.networks.map { network ->
|
||||
val isSelected = network.networkId in currency.addedIn
|
||||
val isSelected = network.network in currency.addedIn
|
||||
|
||||
network.copy(
|
||||
iconResId = network.networkId.getIconRes(isSelected),
|
||||
iconResId = network.network.id.getIconRes(isSelected),
|
||||
isSelected = isSelected,
|
||||
)
|
||||
}.toImmutableList(),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM
|
|||
|
||||
internal fun CurrencyNetworkUM.select(isSelected: Boolean): CurrencyNetworkUM {
|
||||
return copy(
|
||||
iconResId = networkId.getIconRes(isSelected),
|
||||
iconResId = network.id.getIconRes(isSelected),
|
||||
isSelected = isSelected,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.markets.portfolio.impl.loader
|
||||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Portfolio data. Combined data from all flows that required to setup portfolio
|
||||
*
|
||||
* @property walletsWithCurrencyStatuses wallets with crypto currency statuses
|
||||
* @property appCurrency app currency
|
||||
* @property isBalanceHidden flag that indicates if balance should be hidden
|
||||
* @property walletsWithBalance wallets with total balance
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal data class PortfolioData(
|
||||
val walletsWithCurrencyStatuses: Map<UserWallet, List<CryptoCurrencyStatus>>,
|
||||
val appCurrency: AppCurrency,
|
||||
val isBalanceHidden: Boolean,
|
||||
val walletsWithBalance: Map<UserWalletId, Lce<TokenListError, TotalFiatBalance>>,
|
||||
)
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.tangem.features.markets.portfolio.impl.loader
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.tokens.GetAllWalletsCryptoCurrencyStatusesUseCase
|
||||
import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Loader of portfolio data
|
||||
*
|
||||
* @property getAllWalletsCryptoCurrencyStatusesUseCase use case for getting all wallets crypto currency statuses
|
||||
* @property getSelectedAppCurrencyUseCase use case for getting selected app currency
|
||||
* @property getBalanceHidingSettingsUseCase use case for getting balance hiding settings
|
||||
* @property getWalletTotalBalanceUseCase use case for getting wallet total balance
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class PortfolioDataLoader @Inject constructor(
|
||||
private val getAllWalletsCryptoCurrencyStatusesUseCase: GetAllWalletsCryptoCurrencyStatusesUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase,
|
||||
) {
|
||||
|
||||
/** Load data by [currencyRawId] */
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun load(currencyRawId: String): Flow<PortfolioData> {
|
||||
return combine(
|
||||
flow = getAllWalletsCryptoCurrencyStatusesFlow(currencyRawId = currencyRawId),
|
||||
flow2 = getSelectedAppCurrencyFlow(),
|
||||
flow3 = getBalanceHidingSettingsFlow(),
|
||||
) { walletsWithCurrencyStatuses, appCurrency, isBalanceHidden ->
|
||||
PortfolioData(
|
||||
walletsWithCurrencyStatuses = walletsWithCurrencyStatuses,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
walletsWithBalance = emptyMap(),
|
||||
)
|
||||
}
|
||||
// setup balances for wallets from walletsWithCurrencyStatuses
|
||||
.flatMapLatest { portfolioData ->
|
||||
getWalletsWithTotalBalanceFlow(
|
||||
ids = portfolioData.walletsWithCurrencyStatuses.keys.map(UserWallet::walletId),
|
||||
)
|
||||
.map { portfolioData.copy(walletsWithBalance = it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAllWalletsCryptoCurrencyStatusesFlow(
|
||||
currencyRawId: String,
|
||||
): Flow<Map<UserWallet, List<CryptoCurrencyStatus>>> {
|
||||
return getAllWalletsCryptoCurrencyStatusesUseCase(currencyRawId)
|
||||
.distinctUntilChanged()
|
||||
.map { walletsWithMaybeStatuses ->
|
||||
walletsWithMaybeStatuses.mapValues { entry ->
|
||||
entry.value.mapNotNull { it.getOrNull() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectedAppCurrencyFlow(): Flow<AppCurrency> {
|
||||
return getSelectedAppCurrencyUseCase()
|
||||
.map {
|
||||
it.getOrElse { e ->
|
||||
Timber.e("Failed to load app currency: $e")
|
||||
AppCurrency.Default
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getBalanceHidingSettingsFlow(): Flow<Boolean> {
|
||||
return getBalanceHidingSettingsUseCase()
|
||||
.map { it.isBalanceHidden }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getWalletsWithTotalBalanceFlow(
|
||||
ids: List<UserWalletId>,
|
||||
): Flow<Map<UserWalletId, Lce<TokenListError, TotalFiatBalance>>> {
|
||||
return combine(
|
||||
flows = ids
|
||||
.map { userWalletId ->
|
||||
getWalletTotalBalanceUseCase(userWalletId)
|
||||
.map { userWalletId to it }
|
||||
.distinctUntilChanged()
|
||||
},
|
||||
transform = { it.toMap() },
|
||||
)
|
||||
.distinctUntilChanged()
|
||||
.onEmpty { ids.associateWith { Lce.Loading<TotalFiatBalance>(partialContent = null) } }
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,6 @@ private fun Preview() {
|
|||
),
|
||||
),
|
||||
onBack = {},
|
||||
onWalletSelected = {},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -135,7 +134,6 @@ private fun PreviewContent() {
|
|||
),
|
||||
),
|
||||
onBack = {},
|
||||
onWalletSelected = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,5 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
|
||||
internal data class WalletSelectorBSContentUM(
|
||||
val userWallets: ImmutableList<UserWalletItemUM>,
|
||||
val onWalletSelected: (UserWalletItemUM) -> Unit,
|
||||
val onBack: () -> Unit,
|
||||
) : TangemBottomSheetConfigContent
|
||||
Loading…
Add table
Add a link
Reference in a new issue