Updated on 2026-08-14
This commit is contained in:
parent
df938519a2
commit
6cd6210a05
9 changed files with 292 additions and 129 deletions
|
|
@ -35,7 +35,7 @@ internal class DefaultMarketsTokenDetailsComponent @AssistedInject constructor(
|
|||
|
||||
private val portfolioComponent = portfolioComponentFactory.create(
|
||||
context = child("my_portfolio"),
|
||||
params = MarketsPortfolioComponent.Params(params.token.id),
|
||||
params = MarketsPortfolioComponent.Params(params.token),
|
||||
)
|
||||
|
||||
init {
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ import androidx.compose.runtime.Stable
|
|||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Stable
|
||||
interface MarketsPortfolioComponent : ComposableContentComponent {
|
||||
|
||||
@Serializable
|
||||
data class Params(val tokenId: String)
|
||||
data class Params(val token: TokenMarketParams)
|
||||
|
||||
fun setTokenNetworks(networks: List<TokenMarketInfo.Network>)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@ import arrow.core.getOrElse
|
|||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
import com.tangem.domain.tokens.GetAllWalletsCryptoCurrencyStatusesUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||
import com.tangem.features.markets.portfolio.api.MarketsPortfolioComponent
|
||||
import com.tangem.features.markets.portfolio.impl.loader.PortfolioDataLoader
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -23,9 +22,8 @@ import javax.inject.Inject
|
|||
@ComponentScoped
|
||||
internal class MarketsPortfolioModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
getAllWalletsCryptoCurrencyStatusesUseCase: GetAllWalletsCryptoCurrencyStatusesUseCase,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
|
||||
private val portfolioDataLoader: PortfolioDataLoader,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -34,59 +32,134 @@ internal class MarketsPortfolioModel @Inject constructor(
|
|||
|
||||
private val params = paramsContainer.require<MarketsPortfolioComponent.Params>()
|
||||
|
||||
private val availableNetworks = MutableStateFlow<List<TokenMarketInfo.Network>?>(value = null)
|
||||
private val availableNetworksFlow = MutableStateFlow<List<TokenMarketInfo.Network>?>(value = null)
|
||||
|
||||
private val factory = MyPortfolioUMMFactory(::onAddClick, ::onTokenItemClick)
|
||||
/** Multi-wallet [UserWalletId] that user uses to add new tokens in AddToPortfolio bottom sheet */
|
||||
private val selectedMultiWalletIdFlow = MutableStateFlow<UserWalletId?>(value = null)
|
||||
|
||||
/** Map of [UserWalletId] and network ids that user is changed */
|
||||
private val walletsWithChangedNetworksFlow = MutableStateFlow<Map<UserWalletId, List<String>>>(value = emptyMap())
|
||||
|
||||
private val portfolioBSVisibilityModelFlow = MutableStateFlow(value = PortfolioBSVisibilityModel())
|
||||
|
||||
private val factory = MyPortfolioUMMFactory(
|
||||
onAddClick = { onAddToPortfolioBSVisibilityChange(isShow = true) },
|
||||
onTokenItemClick = ::onTokenItemClick,
|
||||
addToPortfolioBSContentUMFactory = AddToPortfolioBSContentUMFactory(
|
||||
token = params.token,
|
||||
onAddToPortfolioVisibilityChange = ::onAddToPortfolioBSVisibilityChange,
|
||||
onWalletSelectorVisibilityChange = ::onWalletSelectorVisibilityChange,
|
||||
onNetworkSwitchClick = ::onNetworkSwitchClick,
|
||||
onWalletSelect = ::onWalletSelect,
|
||||
onContinueClick = ::onContinueClick,
|
||||
),
|
||||
)
|
||||
|
||||
init {
|
||||
combine(
|
||||
flow = getAllWalletsCryptoCurrencyStatusesUseCase(params.tokenId),
|
||||
flow2 = availableNetworks,
|
||||
flow3 = getSelectedAppCurrencyUseCase(),
|
||||
flow4 = getBalanceHidingSettingsUseCase(),
|
||||
) { walletsWithCurrencyStatuses, networks, maybeAppCurrency, isBalanceHidden ->
|
||||
val appCurrency = maybeAppCurrency.getOrElse { e ->
|
||||
Timber.e("Failed to load app currency: $e")
|
||||
AppCurrency.Default
|
||||
}
|
||||
// Subscribe on selected wallet flow to support actual selected wallet
|
||||
subscribeOnSelectedMultiWalletUpdates()
|
||||
|
||||
factory.create(
|
||||
walletsWithCurrencyStatuses = walletsWithCurrencyStatuses,
|
||||
availableNetworks = networks,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden.isBalanceHidden,
|
||||
)
|
||||
}
|
||||
subscribeOnStateUpdates()
|
||||
}
|
||||
|
||||
fun setTokenNetworks(networks: List<TokenMarketInfo.Network>) {
|
||||
availableNetworksFlow.value = networks
|
||||
}
|
||||
|
||||
fun setNoNetworksAvailable() {
|
||||
availableNetworksFlow.value = emptyList()
|
||||
}
|
||||
|
||||
private fun subscribeOnSelectedMultiWalletUpdates() {
|
||||
getSelectedWalletUseCase()
|
||||
.getOrElse { e ->
|
||||
Timber.e("Failed to load selected wallet: $e")
|
||||
error("Failed to load selected wallet")
|
||||
}
|
||||
.onEach {
|
||||
selectedMultiWalletIdFlow.value = it.takeIf { it.isMultiCurrency }?.walletId
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeOnStateUpdates() {
|
||||
combine(
|
||||
flow = portfolioDataLoader.load(params.token.id),
|
||||
flow2 = portfolioBSVisibilityModelFlow,
|
||||
flow3 = availableNetworksFlow,
|
||||
flow4 = selectedMultiWalletIdFlow,
|
||||
flow5 = walletsWithChangedNetworksFlow,
|
||||
transform = factory::create,
|
||||
)
|
||||
.onEach { _state.value = it }
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
fun setTokenNetworks(networks: List<TokenMarketInfo.Network>) {
|
||||
availableNetworks.value = networks
|
||||
}
|
||||
|
||||
fun setNoNetworksAvailable() {
|
||||
availableNetworks.value = emptyList()
|
||||
}
|
||||
|
||||
private fun onAddClick() {
|
||||
// TODO [REDACTED_JIRA]
|
||||
}
|
||||
|
||||
private fun onTokenItemClick(token: CryptoCurrencyStatus) {
|
||||
private fun onTokenItemClick(index: Int, id: CryptoCurrency.ID) {
|
||||
_state.update {
|
||||
(_state.value as? MyPortfolioUM.Tokens)?.let { state ->
|
||||
state.copy(
|
||||
tokens = state.tokens.map { tokenUM ->
|
||||
if (tokenUM.tokenItemState.id == token.currency.id.value) {
|
||||
val state = _state.value as? MyPortfolioUM.Tokens ?: return@update it
|
||||
|
||||
state.copy(
|
||||
tokens = state.tokens
|
||||
.mapIndexed { i, tokenUM ->
|
||||
// check by index and id because id can be the same
|
||||
if (index == i && id.value == tokenUM.tokenItemState.id) {
|
||||
tokenUM.copy(isQuickActionsShown = !tokenUM.isQuickActionsShown)
|
||||
} else {
|
||||
tokenUM
|
||||
}
|
||||
}
|
||||
.toImmutableList(),
|
||||
)
|
||||
} ?: it
|
||||
.toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onNetworkSwitchClick(id: String, isChecked: Boolean) {
|
||||
walletsWithChangedNetworksFlow.update {
|
||||
val selectedWalletId = selectedMultiWalletIdFlow.value
|
||||
|
||||
if (selectedWalletId == null) {
|
||||
Timber.e("Impossible ti switch network when selected wallet is null")
|
||||
return@update it
|
||||
}
|
||||
|
||||
it.toMutableMap().apply {
|
||||
val networkIds = this[selectedWalletId] ?: emptyList()
|
||||
|
||||
if (isChecked) {
|
||||
this[selectedWalletId] = networkIds + id
|
||||
} else {
|
||||
this[selectedWalletId] = networkIds - id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onWalletSelect(userWalletId: UserWalletId) {
|
||||
selectedMultiWalletIdFlow.update { prevUserWalletId ->
|
||||
|
||||
// Clear user changes if user select another wallet
|
||||
walletsWithChangedNetworksFlow.update {
|
||||
it.toMutableMap().apply { remove(prevUserWalletId) }
|
||||
}
|
||||
|
||||
userWalletId
|
||||
}
|
||||
}
|
||||
|
||||
private fun onContinueClick() {
|
||||
// TODO [REDACTED_JIRA]
|
||||
}
|
||||
|
||||
private fun onAddToPortfolioBSVisibilityChange(isShow: Boolean) {
|
||||
portfolioBSVisibilityModelFlow.update {
|
||||
it.copy(addToPortfolioBSVisibility = isShow, walletSelectorBSVisibility = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onWalletSelectorVisibilityChange(isShow: Boolean) {
|
||||
portfolioBSVisibilityModelFlow.update {
|
||||
it.copy(addToPortfolioBSVisibility = true, walletSelectorBSVisibility = isShow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
package com.tangem.features.markets.portfolio.impl.model
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.markets.portfolio.impl.loader.PortfolioData
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
|
||||
|
||||
/**
|
||||
|
|
@ -18,63 +19,142 @@ import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
|
|||
*/
|
||||
internal class MyPortfolioUMMFactory(
|
||||
private val onAddClick: () -> Unit,
|
||||
private val onTokenItemClick: (CryptoCurrencyStatus) -> Unit,
|
||||
private val onTokenItemClick: (Int, CryptoCurrency.ID) -> Unit,
|
||||
private val addToPortfolioBSContentUMFactory: AddToPortfolioBSContentUMFactory,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Create [MyPortfolioUM] from data set
|
||||
*
|
||||
* @param walletsWithCurrencyStatuses wallets with currency statuses
|
||||
* @param availableNetworks available networks
|
||||
* @param appCurrency app currency
|
||||
* @param isBalanceHidden flag that indicates if balance should be hidden
|
||||
*/
|
||||
fun create(
|
||||
walletsWithCurrencyStatuses: Map<UserWallet, List<Either<CurrencyStatusError, CryptoCurrencyStatus>>>,
|
||||
portfolioModel: PortfolioData,
|
||||
portfolioBSVisibilityModel: PortfolioBSVisibilityModel,
|
||||
availableNetworks: List<TokenMarketInfo.Network>?,
|
||||
appCurrency: AppCurrency,
|
||||
isBalanceHidden: Boolean,
|
||||
selectedWalletId: UserWalletId?,
|
||||
walletsWithChangedNetworks: Map<UserWalletId, List<String>>,
|
||||
): MyPortfolioUM {
|
||||
if (availableNetworks == null) return MyPortfolioUM.Loading
|
||||
|
||||
if (availableNetworks.isEmpty()) return MyPortfolioUM.Unavailable
|
||||
|
||||
val availableWalletsWithStatuses = walletsWithCurrencyStatuses
|
||||
.filterAvailable(networks = availableNetworks)
|
||||
.flatMapStatuses()
|
||||
val walletsWithStatuses = portfolioModel.walletsWithCurrencyStatuses
|
||||
.filterAvailableNetworks(networks = availableNetworks)
|
||||
|
||||
if (availableWalletsWithStatuses.isEmpty()) {
|
||||
return MyPortfolioUM.AddFirstToken(onAddClick = onAddClick)
|
||||
val isPortfolioEmpty = walletsWithStatuses.flatMap { it.value }.isEmpty()
|
||||
if (isPortfolioEmpty) {
|
||||
val hasMultiWallets = walletsWithStatuses.filterKeys(UserWallet::isMultiCurrency).isNotEmpty()
|
||||
|
||||
return if (hasMultiWallets) {
|
||||
MyPortfolioUM.AddFirstToken(
|
||||
bsConfig = createAddToPortfolioBSConfig(
|
||||
portfolioModel = portfolioModel,
|
||||
selectedWalletId = selectedWalletId,
|
||||
availableNetworks = availableNetworks,
|
||||
walletsWithChangedNetworks = walletsWithChangedNetworks,
|
||||
portfolioBSVisibilityModel = portfolioBSVisibilityModel,
|
||||
),
|
||||
onAddClick = onAddClick,
|
||||
)
|
||||
} else {
|
||||
MyPortfolioUM.Unavailable
|
||||
}
|
||||
}
|
||||
|
||||
return TokensPortfolioUMConverter(
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
availableNetworks = availableNetworks,
|
||||
appCurrency = portfolioModel.appCurrency,
|
||||
isBalanceHidden = portfolioModel.isBalanceHidden,
|
||||
isAllAvailableNetworksAdded = walletsWithStatuses.isAllAvailableNetworksAdded(availableNetworks),
|
||||
bsConfig = createAddToPortfolioBSConfig(
|
||||
portfolioModel = portfolioModel,
|
||||
selectedWalletId = selectedWalletId,
|
||||
availableNetworks = availableNetworks,
|
||||
portfolioBSVisibilityModel = portfolioBSVisibilityModel,
|
||||
walletsWithChangedNetworks = walletsWithChangedNetworks,
|
||||
),
|
||||
onAddClick = onAddClick,
|
||||
onTokenItemClick = onTokenItemClick,
|
||||
)
|
||||
.convert(availableWalletsWithStatuses)
|
||||
.convert(walletsWithStatuses)
|
||||
}
|
||||
|
||||
private fun Map<UserWallet, List<Either<CurrencyStatusError, CryptoCurrencyStatus>>>.filterAvailable(
|
||||
networks: List<TokenMarketInfo.Network>,
|
||||
): Map<UserWallet, List<CryptoCurrencyStatus>> {
|
||||
val networkIds = networks.map { it.networkId }
|
||||
private fun createAddToPortfolioBSConfig(
|
||||
portfolioModel: PortfolioData,
|
||||
selectedWalletId: UserWalletId?,
|
||||
availableNetworks: List<TokenMarketInfo.Network>,
|
||||
portfolioBSVisibilityModel: PortfolioBSVisibilityModel,
|
||||
walletsWithChangedNetworks: Map<UserWalletId, List<String>>,
|
||||
): TangemBottomSheetConfig {
|
||||
val walletId = requireNotNull(selectedWalletId) {
|
||||
"Selected wallet must be not null in state with AddToPortfolio bottom sheet"
|
||||
}
|
||||
|
||||
return mapValues { entry ->
|
||||
entry.value.mapNotNull { maybeStatus ->
|
||||
maybeStatus.getOrNull()
|
||||
?.takeIf { networkIds.contains(it.currency.network.backendId) }
|
||||
}
|
||||
val selectedWallet = portfolioModel.walletsWithCurrencyStatuses.keys
|
||||
.firstOrNull { it.walletId == walletId }
|
||||
?: error("portfolioModel.walletsWithCurrencyStatuses doesn't contain selected wallet: $walletId")
|
||||
|
||||
val changedNetworks = walletsWithChangedNetworks[selectedWalletId]
|
||||
val alreadyAddedNetworks = requireNotNull(
|
||||
value = portfolioModel.walletsWithCurrencyStatuses[selectedWallet],
|
||||
lazyMessage = {
|
||||
"portfolioModel.walletsWithCurrencyStatuses doesn't contain selected wallet: $walletId"
|
||||
},
|
||||
)
|
||||
.filterAvailableNetworks(availableNetworks)
|
||||
.map { it.currency.network.backendId }
|
||||
|
||||
return addToPortfolioBSContentUMFactory.create(
|
||||
portfolioData = portfolioModel,
|
||||
portfolioBSVisibilityModel = portfolioBSVisibilityModel,
|
||||
selectedWallet = selectedWallet,
|
||||
networksWithToggle = availableNetworks.associateWithToggle(
|
||||
changedNetworks = changedNetworks,
|
||||
alreadyAddedNetworks = alreadyAddedNetworks,
|
||||
),
|
||||
isUserChangedNetworks = changedNetworks != null && alreadyAddedNetworks != changedNetworks,
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<TokenMarketInfo.Network>.associateWithToggle(
|
||||
changedNetworks: List<String>?,
|
||||
alreadyAddedNetworks: List<String>,
|
||||
): Map<TokenMarketInfo.Network, Boolean> {
|
||||
// Use user choice or check already added networks
|
||||
return associateWith { network ->
|
||||
val isSelectedByUser = changedNetworks?.contains(network.networkId)
|
||||
|
||||
if (isSelectedByUser != null) return@associateWith isSelectedByUser
|
||||
|
||||
val isAlreadyAdded = alreadyAddedNetworks.any { it == network.networkId }
|
||||
|
||||
isAlreadyAdded
|
||||
}
|
||||
}
|
||||
|
||||
private fun Map<UserWallet, List<CryptoCurrencyStatus>>.flatMapStatuses(): Map<UserWallet, CryptoCurrencyStatus> {
|
||||
private fun Map<UserWallet, List<CryptoCurrencyStatus>>.isAllAvailableNetworksAdded(
|
||||
availableNetworks: List<TokenMarketInfo.Network>,
|
||||
): Boolean {
|
||||
val networkIds = availableNetworks.map { it.networkId }
|
||||
|
||||
return this
|
||||
.flatMap { entry ->
|
||||
entry.value.map { entry.key to it }
|
||||
}
|
||||
.toMap()
|
||||
// User can add currencies only in multi-currency wallets
|
||||
.filterKeys(UserWallet::isMultiCurrency)
|
||||
.mapValues { it.value.map { it.currency.network.backendId } }
|
||||
// Each wallets contains all available networks?
|
||||
.all { it.value.containsAll(networkIds) }
|
||||
}
|
||||
|
||||
/** Filter map values by available networks [networks] */
|
||||
private fun Map<UserWallet, List<CryptoCurrencyStatus>>.filterAvailableNetworks(
|
||||
networks: List<TokenMarketInfo.Network>,
|
||||
): Map<UserWallet, List<CryptoCurrencyStatus>> {
|
||||
return mapValues { entry -> entry.value.filterAvailableNetworks(networks) }
|
||||
}
|
||||
|
||||
/** Filter list of [CryptoCurrencyStatus] by available networks [networks] */
|
||||
private fun List<CryptoCurrencyStatus>.filterAvailableNetworks(
|
||||
networks: List<TokenMarketInfo.Network>,
|
||||
): List<CryptoCurrencyStatus> {
|
||||
val networkIds = networks.map(TokenMarketInfo.Network::networkId)
|
||||
|
||||
return mapNotNull {
|
||||
it.takeIf { networkIds.contains(it.currency.network.backendId) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,9 +17,9 @@ internal class PortfolioTokenUMConverter(
|
|||
private val appCurrency: AppCurrency,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val onTokenItemClick: (CryptoCurrencyStatus) -> Unit,
|
||||
) : Converter<Map.Entry<UserWallet, CryptoCurrencyStatus>, PortfolioTokenUM> {
|
||||
) : Converter<Pair<UserWallet, CryptoCurrencyStatus>, PortfolioTokenUM> {
|
||||
|
||||
override fun convert(value: Map.Entry<UserWallet, CryptoCurrencyStatus>): PortfolioTokenUM {
|
||||
override fun convert(value: Pair<UserWallet, CryptoCurrencyStatus>): PortfolioTokenUM {
|
||||
val (userWallet, cryptoCurrencyStatus) = value
|
||||
|
||||
val tokenItemStateConverter = TokenItemStateConverter(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.tangem.features.markets.portfolio.impl.model
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
|
||||
|
|
@ -17,42 +18,29 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
internal class TokensPortfolioUMConverter(
|
||||
private val appCurrency: AppCurrency,
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val availableNetworks: List<TokenMarketInfo.Network>,
|
||||
private val isAllAvailableNetworksAdded: Boolean,
|
||||
private val bsConfig: TangemBottomSheetConfig,
|
||||
private val onAddClick: () -> Unit,
|
||||
private val onTokenItemClick: (CryptoCurrencyStatus) -> Unit,
|
||||
) : Converter<Map<UserWallet, CryptoCurrencyStatus>, MyPortfolioUM.Tokens> {
|
||||
private val onTokenItemClick: (index: Int, id: CryptoCurrency.ID) -> Unit,
|
||||
) : Converter<Map<UserWallet, List<CryptoCurrencyStatus>>, MyPortfolioUM.Tokens> {
|
||||
|
||||
override fun convert(value: Map<UserWallet, CryptoCurrencyStatus>): MyPortfolioUM.Tokens {
|
||||
override fun convert(value: Map<UserWallet, List<CryptoCurrencyStatus>>): MyPortfolioUM.Tokens {
|
||||
return MyPortfolioUM.Tokens(
|
||||
tokens = PortfolioTokenUMConverter(appCurrency, isBalanceHidden, onTokenItemClick)
|
||||
.convertList(value.entries)
|
||||
tokens = value
|
||||
.flatMap { entry ->
|
||||
entry.value.map { entry.key to it }
|
||||
}
|
||||
.mapIndexed { index, status ->
|
||||
PortfolioTokenUMConverter(
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
onTokenItemClick = { onTokenItemClick(index, it.currency.id) },
|
||||
).convert(status)
|
||||
}
|
||||
.toImmutableList(),
|
||||
buttonState = getAddButtonState(
|
||||
availableWalletsWithStatuses = value,
|
||||
availableNetworks = availableNetworks,
|
||||
),
|
||||
buttonState = if (isAllAvailableNetworksAdded) AddButtonState.Unavailable else AddButtonState.Available,
|
||||
bsConfig = bsConfig,
|
||||
onAddClick = onAddClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getAddButtonState(
|
||||
availableWalletsWithStatuses: Map<UserWallet, CryptoCurrencyStatus>,
|
||||
availableNetworks: List<TokenMarketInfo.Network>,
|
||||
): AddButtonState {
|
||||
val networkIds = availableNetworks.map { it.networkId }
|
||||
|
||||
val allNetworksAdded = availableWalletsWithStatuses
|
||||
// User can add currencies only in multi-currency wallets
|
||||
.filterKeys(UserWallet::isMultiCurrency)
|
||||
.entries
|
||||
.groupBy(
|
||||
keySelector = { it.key },
|
||||
valueTransform = { it.value.currency.network.backendId },
|
||||
)
|
||||
.mapValues { it.value.toSet() }
|
||||
// Each wallets contains all available networks?
|
||||
.all { it.value.containsAll(networkIds) }
|
||||
|
||||
return if (allNetworksAdded) AddButtonState.Unavailable else AddButtonState.Available
|
||||
}
|
||||
}
|
||||
|
|
@ -53,7 +53,11 @@ internal fun MyPortfolio(state: MyPortfolioUM, modifier: Modifier = Modifier) {
|
|||
}
|
||||
}
|
||||
|
||||
AddToPortfolioBottomSheet(config = state.addToPortfolioBS)
|
||||
when (state) {
|
||||
is MyPortfolioUM.AddFirstToken -> AddToPortfolioBottomSheet(config = state.bsConfig)
|
||||
is MyPortfolioUM.Tokens -> AddToPortfolioBottomSheet(config = state.bsConfig)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.features.markets.portfolio.impl.ui.preview
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
|
||||
|
|
@ -14,19 +16,39 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
|
|||
MyPortfolioUM.Tokens(
|
||||
tokens = persistentListOf(sampleToken, sampleToken),
|
||||
buttonState = MyPortfolioUM.Tokens.AddButtonState.Available,
|
||||
bsConfig = TangemBottomSheetConfig(
|
||||
isShow = false,
|
||||
onDismissRequest = {},
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onAddClick = {},
|
||||
),
|
||||
MyPortfolioUM.Tokens(
|
||||
tokens = persistentListOf(sampleToken, sampleToken.copy(isQuickActionsShown = true)),
|
||||
buttonState = MyPortfolioUM.Tokens.AddButtonState.Unavailable,
|
||||
bsConfig = TangemBottomSheetConfig(
|
||||
isShow = false,
|
||||
onDismissRequest = {},
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onAddClick = {},
|
||||
),
|
||||
MyPortfolioUM.Tokens(
|
||||
tokens = persistentListOf(sampleToken.copy(isQuickActionsShown = true), sampleToken),
|
||||
buttonState = MyPortfolioUM.Tokens.AddButtonState.Loading,
|
||||
bsConfig = TangemBottomSheetConfig(
|
||||
isShow = false,
|
||||
onDismissRequest = {},
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onAddClick = {},
|
||||
),
|
||||
MyPortfolioUM.AddFirstToken(
|
||||
bsConfig = TangemBottomSheetConfig(
|
||||
isShow = false,
|
||||
onDismissRequest = {},
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onAddClick = {},
|
||||
),
|
||||
MyPortfolioUM.Loading,
|
||||
|
|
|
|||
|
|
@ -2,21 +2,15 @@ package com.tangem.features.markets.portfolio.impl.ui.state
|
|||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
internal sealed class MyPortfolioUM {
|
||||
|
||||
val addToPortfolioBS: TangemBottomSheetConfig = TangemBottomSheetConfig(
|
||||
isShow = false,
|
||||
onDismissRequest = {},
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
)
|
||||
|
||||
data class Tokens(
|
||||
val tokens: ImmutableList<PortfolioTokenUM>,
|
||||
val buttonState: AddButtonState,
|
||||
val bsConfig: TangemBottomSheetConfig,
|
||||
val onAddClick: () -> Unit,
|
||||
) : MyPortfolioUM() {
|
||||
|
||||
|
|
@ -28,6 +22,7 @@ internal sealed class MyPortfolioUM {
|
|||
}
|
||||
|
||||
data class AddFirstToken(
|
||||
val bsConfig: TangemBottomSheetConfig,
|
||||
val onAddClick: () -> Unit,
|
||||
) : MyPortfolioUM()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue