diff --git a/common/ui/src/main/java/com/tangem/common/ui/account/TokensListPortfolioItemConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/account/TokensListPortfolioItemConverter.kt new file mode 100644 index 0000000000..f4d414cae3 --- /dev/null +++ b/common/ui/src/main/java/com/tangem/common/ui/account/TokensListPortfolioItemConverter.kt @@ -0,0 +1,31 @@ +package com.tangem.common.ui.account + +import com.tangem.core.ui.components.token.state.TokenItemState +import com.tangem.core.ui.components.tokenlist.state.PortfolioItemContentUM +import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM +import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM +import com.tangem.utils.converter.Converter +import kotlinx.collections.immutable.ImmutableList + +class TokensListPortfolioItemConverter( + val tokenItemUM: TokenItemState, + val isExpanded: Boolean, + val isCollapsable: Boolean, + val tokens: ImmutableList, + val onEmptyAction: PortfolioItemContentUM.Empty.Action? = null, +) : Converter { + + override fun convert(value: Unit): TokensListItemUM.Portfolio { + val content = if (tokens.isEmpty()) { + PortfolioItemContentUM.Empty(onEmptyAction) + } else { + PortfolioItemContentUM.Tokens(tokens) + } + return TokensListItemUM.Portfolio( + tokenItemUM = tokenItemUM, + isExpanded = isExpanded, + isCollapsable = isCollapsable, + content = content, + ) + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/tokenlist/state/TokensListItemUM.kt b/core/ui/src/main/java/com/tangem/core/ui/components/tokenlist/state/TokensListItemUM.kt index 7797159dc1..c09e64697b 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/tokenlist/state/TokensListItemUM.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/tokenlist/state/TokensListItemUM.kt @@ -5,6 +5,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM import com.tangem.core.ui.components.token.state.TokenItemState import com.tangem.core.ui.extensions.TextReference import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf /** Tokens list item state */ @Immutable @@ -45,15 +46,34 @@ sealed interface TokensListItemUM { val tokenItemUM: TokenItemState, val isExpanded: Boolean, val isCollapsable: Boolean, - val tokens: ImmutableList, + val content: PortfolioItemContentUM, ) : TokensListItemUM { override val id: String = tokenItemUM.id + + val tokens: ImmutableList + get() = when (content) { + is PortfolioItemContentUM.Tokens -> content.tokens + is PortfolioItemContentUM.Empty -> persistentListOf() + } } data class Text(override val id: Any, val text: TextReference) : TokensListItemUM } +@Immutable sealed interface PortfolioTokensListItemUM { /** Unique ID */ val id: Any +} + +@Immutable +sealed interface PortfolioItemContentUM { + data class Tokens(val tokens: ImmutableList) : PortfolioItemContentUM + data class Empty(val action: Action? = null) : PortfolioItemContentUM { + + data class Action( + val text: TextReference, + val onClick: () -> Unit, + ) + } } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/entity/converters/LoadingAccountTokenItemConverter.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/entity/converters/LoadingAccountTokenItemConverter.kt index 8040f59244..61552e4822 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/entity/converters/LoadingAccountTokenItemConverter.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/entity/converters/LoadingAccountTokenItemConverter.kt @@ -1,6 +1,7 @@ package com.tangem.features.onramp.swap.availablepairs.entity.converters import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter +import com.tangem.common.ui.account.TokensListPortfolioItemConverter import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.TotalFiatBalance @@ -15,7 +16,7 @@ internal class LoadingAccountTokenItemConverter( override fun convert(value: AccountStatus.CryptoPortfolio): TokensListItemUM.Portfolio { val (account, currencies) = value - return TokensListItemUM.Portfolio( + return TokensListPortfolioItemConverter( tokenItemUM = AccountCryptoPortfolioItemStateConverter( appCurrency = appCurrency, account = account, @@ -26,6 +27,6 @@ internal class LoadingAccountTokenItemConverter( tokens = currencies.flattenCurrencies() .map { LoadingTokenListItemConverter.convert(it.currency) } .toPersistentList(), - ) + ).convert(Unit) } } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/entity/transformers/SetNoAvailablePairsTransformerV2.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/entity/transformers/SetNoAvailablePairsTransformerV2.kt index ac87e348b8..eba2f260ee 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/entity/transformers/SetNoAvailablePairsTransformerV2.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/entity/transformers/SetNoAvailablePairsTransformerV2.kt @@ -1,6 +1,7 @@ package com.tangem.features.onramp.swap.availablepairs.entity.transformers import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter +import com.tangem.common.ui.account.TokensListPortfolioItemConverter import com.tangem.common.ui.notifications.NotificationUM import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.core.ui.extensions.TextReference @@ -34,7 +35,7 @@ internal class SetNoAvailablePairsTransformerV2( tokensListData = if (isAccountsMode) { TokenListUMData.AccountList( tokensList = accountList.map { (account, cryptoCurrencies) -> - TokensListItemUM.Portfolio( + TokensListPortfolioItemConverter( tokenItemUM = AccountCryptoPortfolioItemStateConverter( appCurrency = appCurrency, account = account, @@ -45,7 +46,7 @@ internal class SetNoAvailablePairsTransformerV2( tokens = unavailableConverter.convertList(cryptoCurrencies) .map(TokensListItemUM::Token) .toPersistentList(), - ) + ).convert(Unit) }.toPersistentList(), totalTokensCount = totalTokensCount, ) diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/entity/transformer/UpdateAccountTokenItemConverter.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/entity/transformer/UpdateAccountTokenItemConverter.kt index f90f1e9794..791645af20 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/entity/transformer/UpdateAccountTokenItemConverter.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/entity/transformer/UpdateAccountTokenItemConverter.kt @@ -1,6 +1,7 @@ package com.tangem.features.onramp.tokenlist.entity.transformer import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter +import com.tangem.common.ui.account.TokensListPortfolioItemConverter import com.tangem.core.ui.components.token.state.TokenItemState import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.core.ui.extensions.TextReference @@ -25,7 +26,7 @@ internal class UpdateAccountTokenItemConverter( .createUnavailableItemConverterV2(appCurrency = appCurrency, unavailableErrorText = unavailableErrorText) override fun convert(value: AccountAvailabilityUM): TokensListItemUM.Portfolio { - return TokensListItemUM.Portfolio( + return TokensListPortfolioItemConverter( tokenItemUM = AccountCryptoPortfolioItemStateConverter( appCurrency = appCurrency, account = value.account, @@ -40,6 +41,6 @@ internal class UpdateAccountTokenItemConverter( unavailableConverter.convert(status) } }.map(TokensListItemUM::Token).toPersistentList(), - ) + ).convert(Unit) } } \ No newline at end of file diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/converters/AccountTokenItemConverter.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/converters/AccountTokenItemConverter.kt index 919e908498..915211edc6 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/converters/AccountTokenItemConverter.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/converters/AccountTokenItemConverter.kt @@ -3,6 +3,7 @@ package com.tangem.feature.swap.converters import com.tangem.common.getTotalCryptoAmount import com.tangem.common.getTotalFiatAmount import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter +import com.tangem.common.ui.account.TokensListPortfolioItemConverter import com.tangem.common.ui.tokens.TokenItemStateConverter import com.tangem.common.ui.tokens.TokenItemStateConverter.Companion.isFlickering import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter @@ -27,7 +28,7 @@ internal class AccountTokenItemConverter( ) : Converter { override fun convert(value: AccountSwapAvailability): TokensListItemUM.Portfolio { - return TokensListItemUM.Portfolio( + return TokensListPortfolioItemConverter( tokenItemUM = AccountCryptoPortfolioItemStateConverter( appCurrency = appCurrency, account = value.account, @@ -39,7 +40,7 @@ internal class AccountTokenItemConverter( createAvailableItemConverter() .convert(accountSwapCurrency.cryptoCurrencyStatus) }.map(TokensListItemUM::Token).toPersistentList(), - ) + ).convert(Unit) } fun createAvailableItemConverter(): TokenItemStateConverter { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt index 4e6ddfac2c..9ccb19d1f6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt @@ -9,6 +9,7 @@ import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.domain.models.account.Account +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.staking.StakingBalance @@ -28,7 +29,11 @@ import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAn import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory import com.tangem.feature.wallet.presentation.wallet.domain.unwrap import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController -import com.tangem.feature.wallet.presentation.wallet.state.model.* +import com.tangem.feature.wallet.presentation.wallet.state.model.ActionsBottomSheetConfig +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAlertUM +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNFTItemUM +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.OpenBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletCurrencyActionsConverter @@ -48,16 +53,11 @@ internal interface WalletContentClickIntents { fun onDismissMarketsTooltip() - fun onTokenItemClick(userWalletId: UserWalletId, currencyStatus: CryptoCurrencyStatus) + fun onTokenItemClick(accountId: AccountId, currencyStatus: CryptoCurrencyStatus) - fun onTokenItemLongClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) + fun onTokenItemLongClick(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus) - fun onApyLabelClick( - userWalletId: UserWalletId, - currencyStatus: CryptoCurrencyStatus, - apySource: ApySource, - apy: String, - ) + fun onApyLabelClick(accountId: AccountId, currencyStatus: CryptoCurrencyStatus, apySource: ApySource, apy: String) fun onYieldPromoCloseClick() @@ -69,6 +69,8 @@ internal interface WalletContentClickIntents { fun onAccountCollapseClick(account: Account) + fun onManageTokensClick(accountId: AccountId) + fun onTransactionClick(txHash: String) fun onDissmissBottomSheet() @@ -119,12 +121,13 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } } - override fun onTokenItemClick(userWalletId: UserWalletId, currencyStatus: CryptoCurrencyStatus) { - router.openTokenDetails(userWalletId, currencyStatus) + override fun onTokenItemClick(accountId: AccountId, currencyStatus: CryptoCurrencyStatus) { + router.openTokenDetails(accountId.userWalletId, currencyStatus) } - override fun onTokenItemLongClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) { + override fun onTokenItemLongClick(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus) { modelScope.launch(dispatchers.main) { + val userWalletId = accountId.userWalletId val userWallet = getUserWalletUseCase(userWalletId).getOrElse { Timber.e( """ @@ -140,13 +143,13 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( getCryptoCurrencyActionsUseCase(userWallet = userWallet, cryptoCurrencyStatus = cryptoCurrencyStatus) .take(count = 1) .collectLatest { - showActionsBottomSheet(it, userWallet) + showActionsBottomSheet(it, userWallet, accountId) } } } override fun onApyLabelClick( - userWalletId: UserWalletId, + accountId: AccountId, currencyStatus: CryptoCurrencyStatus, apySource: ApySource, apy: String, @@ -161,9 +164,13 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( sendApyLabelClickAnalytics(navigationAction, currencyStatus) when (navigationAction) { - is NavigationAction.Staking -> router.openTokenDetails(userWalletId, currencyStatus, navigationAction) + is NavigationAction.Staking -> router.openTokenDetails( + accountId.userWalletId, + currencyStatus, + navigationAction, + ) is NavigationAction.YieldSupply -> openYieldSupply( - userWalletId = userWalletId, + userWalletId = accountId.userWalletId, cryptoCurrencyStatus = currencyStatus, apy = apy, ) @@ -209,6 +216,10 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( accountDependencies.expandedAccountsHolder.collapseAccount(account.accountId) } + override fun onManageTokensClick(accountId: AccountId) { + router.openManageTokensScreen(accountId) + } + private fun openYieldSupply(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus, apy: String) { router.openYieldSupplyEntryScreen( userWalletId = userWalletId, @@ -248,11 +259,16 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( analyticsEventHandler.send(event) } - private fun showActionsBottomSheet(tokenActionsState: TokenActionsState, userWallet: UserWallet) { + private fun showActionsBottomSheet( + tokenActionsState: TokenActionsState, + userWallet: UserWallet, + accountId: AccountId, + ) { stateHolder.showBottomSheet( ActionsBottomSheetConfig( actions = MultiWalletCurrencyActionsConverter( userWallet = userWallet, + accountId = accountId, clickIntents = currencyActionsClickIntents, ).convert(tokenActionsState), ), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt index 25d595780c..b57effd249 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt @@ -22,7 +22,6 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.haptic.TangemHapticEffect import com.tangem.core.ui.haptic.VibratorHapticManager import com.tangem.core.ui.message.DialogMessage -import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.extenstions.unwrap @@ -32,6 +31,7 @@ import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.exchange.RampStateManager import com.tangem.domain.markets.TokenMarketParams import com.tangem.domain.models.TokenReceiveConfig +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.network.NetworkAddress @@ -68,14 +68,13 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch -import timber.log.Timber import java.math.BigDecimal import javax.inject.Inject interface WalletCurrencyActionsClickIntents { fun onSendClick( - userWalletId: UserWalletId, + accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason, ) @@ -83,32 +82,28 @@ interface WalletCurrencyActionsClickIntents { fun onSellClick(cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason) fun onBuyClick( - userWalletId: UserWalletId, + accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason, ) fun onSwapClick( cryptoCurrencyStatus: CryptoCurrencyStatus, - userWalletId: UserWalletId, + accountId: AccountId, unavailabilityReason: ScenarioUnavailabilityReason, ) - fun onReceiveClick( - userWalletId: UserWalletId, - cryptoCurrencyStatus: CryptoCurrencyStatus, - event: AnalyticsEvent? = null, - ) + fun onReceiveClick(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus, event: AnalyticsEvent? = null) - fun onStakeClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus, option: StakingOption?) + fun onStakeClick(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus, option: StakingOption?) fun onCopyAddressLongClick(cryptoCurrencyStatus: CryptoCurrencyStatus): TextReference? - fun onCopyAddressClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) + fun onCopyAddressClick(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus) - fun onHideTokensClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) + fun onHideTokensClick(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus) - fun onPerformHideToken(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) + fun onPerformHideToken(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus) fun onExploreClick() @@ -146,13 +141,12 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( private val needShowYieldSupplyDepositedWarningUseCase: NeedShowYieldSupplyDepositedWarningUseCase, private val saveViewedYieldSupplyWarningUseCase: SaveViewedYieldSupplyWarningUseCase, private val isCryptoCurrencyCoinCouldHide: IsCryptoCurrencyCoinCouldHideUseCase, - private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase, private val uiMessageSender: UiMessageSender, ) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents { override fun onSendClick( - userWalletId: UserWalletId, + accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason, ) { @@ -176,18 +170,18 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( modelScope.launch { saveViewedYieldSupplyWarningUseCase(cryptoCurrencyStatus.currency.name) stateHolder.hideBottomSheet() - navigateToSend(cryptoCurrencyStatus, userWalletId) + navigateToSend(cryptoCurrencyStatus, accountId.userWalletId) } }, ) } else { - navigateToSend(cryptoCurrencyStatus, userWalletId) + navigateToSend(cryptoCurrencyStatus, accountId.userWalletId) } } } override fun onReceiveClick( - userWalletId: UserWalletId, + accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus, event: AnalyticsEvent?, ) { @@ -240,7 +234,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( return resourceReference(R.string.wallet_notification_address_copied) } - override fun onCopyAddressClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) { + override fun onCopyAddressClick(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus) { analyticsEventHandler.send( event = TokenReceiveNewAnalyticsEvent.ButtonCopyAddress( token = cryptoCurrencyStatus.currency.symbol, @@ -251,10 +245,10 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( modelScope.launch(dispatchers.main) { walletManagersFacade.getDefaultAddress( - userWalletId = userWalletId, + userWalletId = accountId.userWalletId, network = cryptoCurrencyStatus.currency.network, )?.let { address -> - stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWalletId)) + stateHolder.update(CloseBottomSheetTransformer(userWalletId = accountId.userWalletId)) clipboardManager.setText(text = address, isSensitive = true) walletEventSender.send(event = WalletEvent.CopyAddress) @@ -262,7 +256,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( } } - override fun onHideTokensClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) { + override fun onHideTokensClick(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus) { analyticsEventHandler.send( event = TokenScreenAnalyticsEvent.ButtonRemoveToken(cryptoCurrencyStatus.currency.symbol), ) @@ -270,34 +264,22 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( modelScope.launch(dispatchers.main) { val currency = cryptoCurrencyStatus.currency val isCryptoCurrencyCoinCouldHide = currency is CryptoCurrency.Coin && - !isCryptoCurrencyCoinCouldHide(userWalletId = userWalletId, cryptoCurrencyCoin = currency) + !isCryptoCurrencyCoinCouldHide(userWalletId = accountId.userWalletId, cryptoCurrencyCoin = currency) if (isCryptoCurrencyCoinCouldHide) { uiMessageSender.send(WalletAlertUM.unableHideToken(cryptoCurrency = cryptoCurrencyStatus.currency)) } else { uiMessageSender.send( WalletAlertUM.hideTokenConfirm(cryptoCurrency = cryptoCurrencyStatus.currency) { - onPerformHideToken(userWalletId, cryptoCurrencyStatus) + onPerformHideToken(accountId, cryptoCurrencyStatus) }, ) } } } - override fun onPerformHideToken(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) { + override fun onPerformHideToken(accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus) { modelScope.launch(dispatchers.io) { - val accountId = getAccountCurrencyStatusUseCase.invokeSync( - userWalletId = userWalletId, - currency = cryptoCurrencyStatus.currency, - ) - .map { it.account.accountId } - .getOrNull() - - if (accountId == null) { - Timber.e("Account ID is null, cannot hide currency ${cryptoCurrencyStatus.currency.id}") - return@launch - } - manageCryptoCurrenciesUseCase(accountId = accountId, remove = cryptoCurrencyStatus.currency) .fold( ifLeft = { @@ -306,7 +288,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( ) }, ifRight = { - stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWalletId)) + stateHolder.update(CloseBottomSheetTransformer(userWalletId = accountId.userWalletId)) }, ) } @@ -340,7 +322,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( } override fun onBuyClick( - userWalletId: UserWalletId, + accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason, ) { @@ -356,7 +338,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( appRouter.push( AppRoute.Onramp( - userWalletId = userWalletId, + userWalletId = accountId.userWalletId, currency = cryptoCurrencyStatus.currency, source = OnrampSource.TOKEN_LONG_TAP, ), @@ -365,7 +347,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( override fun onSwapClick( cryptoCurrencyStatus: CryptoCurrencyStatus, - userWalletId: UserWalletId, + accountId: AccountId, unavailabilityReason: ScenarioUnavailabilityReason, ) { analyticsEventHandler.send( @@ -388,12 +370,12 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( modelScope.launch { saveViewedYieldSupplyWarningUseCase(cryptoCurrencyStatus.currency.name) stateHolder.hideBottomSheet() - navigateToSwap(cryptoCurrencyStatus, userWalletId) + navigateToSwap(cryptoCurrencyStatus, accountId.userWalletId) } }, ) } else { - navigateToSwap(cryptoCurrencyStatus, userWalletId) + navigateToSwap(cryptoCurrencyStatus, accountId.userWalletId) } } } @@ -435,11 +417,11 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( } override fun onStakeClick( - userWalletId: UserWalletId, + accountId: AccountId, cryptoCurrencyStatus: CryptoCurrencyStatus, option: StakingOption?, ) { - stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWalletId)) + stateHolder.update(CloseBottomSheetTransformer(userWalletId = accountId.userWalletId)) val integrationId = option?.integrationId ?: return @@ -448,7 +430,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( appRouter.push( AppRoute.Staking( - userWalletId = userWalletId, + userWalletId = accountId.userWalletId, cryptoCurrency = cryptoCurrency, integrationId = integrationId, ), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewDataLegacy.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewDataLegacy.kt index ab76474be4..be54495064 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewDataLegacy.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewDataLegacy.kt @@ -6,6 +6,7 @@ import com.tangem.core.ui.components.marketprice.PriceChangeType import com.tangem.core.ui.components.notifications.NotificationConfig.ButtonsState import com.tangem.core.ui.components.token.AccountItemPreviewData import com.tangem.core.ui.components.token.state.TokenItemState +import com.tangem.core.ui.components.tokenlist.state.PortfolioItemContentUM import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.core.ui.event.consumedEvent @@ -97,14 +98,20 @@ internal object WalletScreenPreviewDataLegacy { private val portfolioContentState = WalletTokensListState.ContentState.PortfolioContent( items = persistentListOf( TokensListItemUM.Portfolio( - tokens = textContentTokensState.items.filterIsInstance().toPersistentList(), + content = PortfolioItemContentUM.Tokens( + tokens = textContentTokensState.items.filterIsInstance() + .toPersistentList(), + ), isExpanded = false, isCollapsable = true, tokenItemUM = AccountItemPreviewData.accountItem .copy(iconState = AccountItemPreviewData.accountLetterIcon), ), TokensListItemUM.Portfolio( - tokens = textContentTokensState.items.filterIsInstance().toPersistentList(), + content = PortfolioItemContentUM.Tokens( + tokens = textContentTokensState.items.filterIsInstance() + .toPersistentList(), + ), isExpanded = true, isCollapsable = true, tokenItemUM = AccountItemPreviewData.accountItem, @@ -119,14 +126,22 @@ internal object WalletScreenPreviewDataLegacy { private val emptyPortfolioContentState = WalletTokensListState.ContentState.PortfolioContent( items = persistentListOf( TokensListItemUM.Portfolio( - tokens = textContentTokensState.items.filterIsInstance().toPersistentList(), + content = PortfolioItemContentUM.Tokens( + tokens = textContentTokensState.items.filterIsInstance() + .toPersistentList(), + ), isExpanded = false, isCollapsable = true, tokenItemUM = AccountItemPreviewData.accountItem .copy(iconState = AccountItemPreviewData.accountLetterIcon), ), TokensListItemUM.Portfolio( - tokens = persistentListOf(), + content = PortfolioItemContentUM.Empty( + action = PortfolioItemContentUM.Empty.Action( + text = stringReference("Manage tokens"), + onClick = {}, + ), + ), isExpanded = true, isCollapsable = true, tokenItemUM = AccountItemPreviewData.accountItem, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index 49f35c817d..625fe4fa31 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -6,7 +6,9 @@ import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.navigation.url.UrlOpener +import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.TokenReceiveConfig +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.scan.ScanResponse @@ -50,6 +52,14 @@ internal class DefaultWalletRouter @Inject constructor( ) } + override fun openManageTokensScreen(accountId: AccountId) { + val route = AppRoute.ManageTokens( + source = AppRoute.ManageTokens.Source.ACCOUNT, + portfolioId = PortfolioId(accountId), + ) + router.push(route) + } + override fun openOnboardingScreen(scanResponse: ScanResponse, continueBackup: Boolean) { router.push( AppRoute.Onboarding( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt index afad2d5fe7..3e9f99185e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable import com.arkivanov.decompose.router.slot.SlotNavigation import com.tangem.common.routing.AppRoute import com.tangem.domain.models.TokenReceiveConfig +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.scan.ScanResponse @@ -37,6 +38,9 @@ internal interface InnerWalletRouter { /** Open details screen */ fun openDetailsScreen(selectedWalletId: UserWalletId) + /** Open manage tokens screen */ + fun openManageTokensScreen(accountId: AccountId) + /** Open onboarding screen */ fun openOnboardingScreen(scanResponse: ScanResponse, continueBackup: Boolean = false) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetCryptoCurrencyActionsTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetCryptoCurrencyActionsTransformer.kt index df4942ff07..f3dbd5dd9e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetCryptoCurrencyActionsTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetCryptoCurrencyActionsTransformer.kt @@ -1,7 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers import com.tangem.domain.card.common.util.cardTypesResolver -import com.tangem.domain.models.PortfolioId +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState @@ -16,7 +16,7 @@ import timber.log.Timber internal class SetCryptoCurrencyActionsTransformer( private val tokenActionsState: TokenActionsState, private val userWallet: UserWallet, - private val portfolioId: PortfolioId, + private val accountId: AccountId, private val clickIntents: WalletClickIntents, ) : WalletStateTransformer(userWallet.walletId) { @@ -51,7 +51,7 @@ internal class SetCryptoCurrencyActionsTransformer( dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None, onClick = { clickIntents.onBuyClick( - userWalletId = portfolioId.userWalletId, + accountId = accountId, cryptoCurrencyStatus = cryptoCurrencyStatus, unavailabilityReason = action.unavailabilityReason, ) @@ -64,7 +64,7 @@ internal class SetCryptoCurrencyActionsTransformer( dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None, onClick = { clickIntents.onReceiveClick( - portfolioId.userWalletId, + accountId, cryptoCurrencyStatus = cryptoCurrencyStatus, ) }, @@ -91,7 +91,7 @@ internal class SetCryptoCurrencyActionsTransformer( dimContent = action.unavailabilityReason != ScenarioUnavailabilityReason.None, onClick = { clickIntents.onSendClick( - userWalletId = portfolioId.userWalletId, + accountId = accountId, cryptoCurrencyStatus = cryptoCurrencyStatus, unavailabilityReason = action.unavailabilityReason, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TokenConverterParams.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TokenConverterParams.kt index fd8229e5e8..03ffab9a92 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TokenConverterParams.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TokenConverterParams.kt @@ -1,16 +1,17 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers import com.tangem.domain.account.models.AccountStatusList -import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.tokenlist.TokenList sealed interface TokenConverterParams { + /** Wallet mode; list of tokens for main account */ data class Wallet( - val portfolioId: PortfolioId, + val accountId: AccountId, val tokenList: TokenList, ) : TokenConverterParams + /** Account mode; list of accounts */ data class Account( val accountList: AccountStatusList, val expandedAccounts: Set, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt index ad35b058ea..0e3d985f61 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt @@ -3,9 +3,9 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.convert import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.card.common.util.cardTypesResolver +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWallet -import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.feature.wallet.child.wallet.model.intents.WalletCurrencyActionsClickIntents @@ -18,11 +18,10 @@ import kotlinx.collections.immutable.toImmutableList internal class MultiWalletCurrencyActionsConverter( private val userWallet: UserWallet, + private val accountId: AccountId, private val clickIntents: WalletCurrencyActionsClickIntents, ) : Converter> { - private val userWalletId: UserWalletId = userWallet.walletId - override fun convert(value: TokenActionsState): ImmutableList { return value.states .filterIfSingleWithToken() @@ -58,17 +57,17 @@ internal class MultiWalletCurrencyActionsConverter( is TokenActionsState.ActionState.Buy -> { title = resourceReference(R.string.common_buy) icon = R.drawable.ic_plus_24 - action = { clickIntents.onBuyClick(userWalletId, cryptoCurrencyStatus, noneReason) } + action = { clickIntents.onBuyClick(accountId, cryptoCurrencyStatus, noneReason) } } is TokenActionsState.ActionState.Receive -> { title = resourceReference(R.string.common_receive) icon = R.drawable.ic_arrow_down_24 - action = { clickIntents.onReceiveClick(userWalletId, cryptoCurrencyStatus) } + action = { clickIntents.onReceiveClick(accountId, cryptoCurrencyStatus) } } is TokenActionsState.ActionState.Stake -> { title = resourceReference(R.string.common_stake) icon = R.drawable.ic_staking_24 - action = { clickIntents.onStakeClick(userWalletId, cryptoCurrencyStatus, actionsState.option) } + action = { clickIntents.onStakeClick(accountId, cryptoCurrencyStatus, actionsState.option) } } is TokenActionsState.ActionState.Sell -> { title = resourceReference(R.string.common_sell) @@ -78,7 +77,7 @@ internal class MultiWalletCurrencyActionsConverter( is TokenActionsState.ActionState.Send -> { title = resourceReference(R.string.common_send) icon = R.drawable.ic_arrow_up_24 - action = { clickIntents.onSendClick(userWalletId, cryptoCurrencyStatus, noneReason) } + action = { clickIntents.onSendClick(accountId, cryptoCurrencyStatus, noneReason) } } is TokenActionsState.ActionState.Swap -> { title = resourceReference(R.string.swapping_swap_action) @@ -86,7 +85,7 @@ internal class MultiWalletCurrencyActionsConverter( action = { clickIntents.onSwapClick( cryptoCurrencyStatus = cryptoCurrencyStatus, - userWalletId = userWalletId, + accountId = accountId, unavailabilityReason = noneReason, ) } @@ -94,12 +93,12 @@ internal class MultiWalletCurrencyActionsConverter( is TokenActionsState.ActionState.CopyAddress -> { title = resourceReference(R.string.common_copy_address) icon = R.drawable.ic_copy_24 - action = { clickIntents.onCopyAddressClick(userWalletId, cryptoCurrencyStatus) } + action = { clickIntents.onCopyAddressClick(accountId, cryptoCurrencyStatus) } } is TokenActionsState.ActionState.HideToken -> { title = resourceReference(R.string.token_details_hide_token) icon = R.drawable.ic_hide_24 - action = { clickIntents.onHideTokensClick(userWalletId, cryptoCurrencyStatus) } + action = { clickIntents.onHideTokensClick(accountId, cryptoCurrencyStatus) } } is TokenActionsState.ActionState.Analytics -> { title = resourceReference(R.string.common_analytics) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt index 1847ff842f..c33c75e00e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt @@ -1,7 +1,9 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter +import com.tangem.common.ui.account.TokensListPortfolioItemConverter import com.tangem.common.ui.tokens.TokenItemStateConverter +import com.tangem.core.ui.components.tokenlist.state.PortfolioItemContentUM import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.core.ui.extensions.resourceReference @@ -9,7 +11,6 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.account.models.AccountStatusList import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.card.common.util.cardTypesResolver -import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.TotalFiatBalance import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.AccountId @@ -49,35 +50,39 @@ internal class TokenListStateConverter( shouldShowMainPromo, ) - private val onTokenClick: (accountId: AccountId?, currencyStatus: CryptoCurrencyStatus) -> Unit = + private val onTokenClick: (accountId: AccountId, currencyStatus: CryptoCurrencyStatus) -> Unit = { accountId, currencyStatus -> - clickIntents.onTokenItemClick(selectedWallet.walletId, currencyStatus) + clickIntents.onTokenItemClick(accountId, currencyStatus) } - private val onTokenLongClick: (accountId: AccountId?, currencyStatus: CryptoCurrencyStatus) -> Unit = + private val onTokenLongClick: (accountId: AccountId, currencyStatus: CryptoCurrencyStatus) -> Unit = { accountId, currencyStatus -> - clickIntents.onTokenItemLongClick(selectedWallet.walletId, currencyStatus) + clickIntents.onTokenItemLongClick(accountId, currencyStatus) } - private val onApyLabelClick: - (currencyStatus: CryptoCurrencyStatus, apySource: TokenItemStateConverter.ApySource, apy: String) -> Unit = - { currencyStatus, apySource, apy -> + private val onApyLabelClick: ( + currencyStatus: CryptoCurrencyStatus, + accountId: AccountId, + apySource: TokenItemStateConverter.ApySource, + apy: String, + ) -> Unit = + { currencyStatus, accountId, apySource, apy -> clickIntents.onApyLabelClick( - userWalletId = selectedWallet.walletId, + accountId = accountId, currencyStatus = currencyStatus, apySource = apySource, apy = apy, ) } - private fun tokenStatusConverter(accountId: AccountId? = null) = TokenItemStateConverter( + private fun tokenStatusConverter(accountId: AccountId) = TokenItemStateConverter( appCurrency = appCurrency, yieldModuleApyMap = yieldModuleApyMap, promoCryptoCurrencyStatus = yieldSupplyPromoBannerConverter.convert(params), stakingApyMap = stakingAvailabilityMap, onItemClick = { _, status -> onTokenClick(accountId, status) }, onItemLongClick = { _, status -> onTokenLongClick(accountId, status) }, - onApyLabelClick = { status, apySource, apy -> onApyLabelClick(status, apySource, apy) }, + onApyLabelClick = { status, apySource, apy -> onApyLabelClick(status, accountId, apySource, apy) }, onYieldPromoCloseClick = clickIntents::onYieldPromoCloseClick, onYieldPromoShown = clickIntents::onYieldPromoShown, onYieldPromoClicked = clickIntents::onYieldPromoClicked, @@ -87,7 +92,7 @@ internal class TokenListStateConverter( return when (params) { is TokenConverterParams.Account -> convertAccountList(params) is TokenConverterParams.Wallet -> convertTokenList( - tokenConverter = tokenStatusConverter((params.portfolioId as? PortfolioId.Account)?.accountId), + tokenConverter = tokenStatusConverter(params.accountId), tokenList = params.tokenList, ) } @@ -136,12 +141,17 @@ internal class TokenListStateConverter( is WalletTokensListState.ContentState.Locked -> tokensListState.items is WalletTokensListState.Empty -> listOf() } - return TokensListItemUM.Portfolio( + val onEmptyAction = PortfolioItemContentUM.Empty.Action( + text = resourceReference(id = R.string.main_manage_tokens), + onClick = { clickIntents.onManageTokensClick(account.accountId) }, + ) + return TokensListPortfolioItemConverter( tokenItemUM = accountItem, isExpanded = isExtend, isCollapsable = true, tokens = items.filterIsInstance().toPersistentList(), - ) + onEmptyAction = onEmptyAction, + ).convert(Unit) } val accountItems = accountList.accountStatuses diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/WalletTokenCurrencyItemConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/WalletTokenCurrencyItemConverter.kt index 0828c8e871..ed2a68e455 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/WalletTokenCurrencyItemConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/WalletTokenCurrencyItemConverter.kt @@ -17,9 +17,9 @@ import com.tangem.core.ui.format.bigdecimal.* import com.tangem.core.ui.res.TangemTheme import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.StatusSource +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.staking.model.StakingAvailability import com.tangem.feature.wallet.child.wallet.model.intents.WalletContentClickIntents import com.tangem.feature.wallet.impl.R @@ -33,11 +33,12 @@ import java.math.BigDecimal internal class WalletTokenCurrencyItemConverter( private val appCurrency: AppCurrency, - private val selectedWallet: UserWallet, + private val accountId: AccountId, + private val shouldShowPromo: Boolean, private val yieldModuleApyMap: Map, private val clickIntents: WalletContentClickIntents, stakingAvailabilityMap: Map, -) : Converter, TangemTokenRowUM> { +) : Converter { private val currencyToIconStateConverter = CryptoCurrencyToIconStateConverter() private val earnApyConverter = EarnApyConverter( @@ -45,8 +46,7 @@ internal class WalletTokenCurrencyItemConverter( stakingApyMap = stakingAvailabilityMap, ) - override fun convert(value: Pair): TangemTokenRowUM { - val (currencyStatus, shouldShowPromo) = value + override fun convert(currencyStatus: CryptoCurrencyStatus): TangemTokenRowUM { val earnApyInfo = earnApyConverter.convert(currencyStatus) return TangemTokenRowUM.Content( @@ -59,6 +59,7 @@ internal class WalletTokenCurrencyItemConverter( topEndContentUM = toCurrencyRowTopEnd(currencyStatus), bottomEndContentUM = toCurrencyRowBottomEnd(currencyStatus), promoBannerUM = toPromoBannerUM( + accountId, currencyStatus, earnApyInfo.takeIf { shouldShowPromo }, ), @@ -68,7 +69,7 @@ internal class WalletTokenCurrencyItemConverter( -> null else -> { { - clickIntents.onTokenItemClick(selectedWallet.walletId, currencyStatus) + clickIntents.onTokenItemClick(accountId, currencyStatus) } } }, @@ -76,7 +77,7 @@ internal class WalletTokenCurrencyItemConverter( CryptoCurrencyStatus.Loading -> null else -> { { - clickIntents.onTokenItemLongClick(selectedWallet.walletId, currencyStatus) + clickIntents.onTokenItemLongClick(accountId, currencyStatus) } } }, @@ -117,7 +118,7 @@ internal class WalletTokenCurrencyItemConverter( onClick = if (earnApyInfo.apy != null) { { clickIntents.onApyLabelClick( - userWalletId = selectedWallet.walletId, + accountId = accountId, currencyStatus = currencyStatus, apySource = earnApyInfo.source, apy = earnApyInfo.apy, @@ -261,6 +262,7 @@ internal class WalletTokenCurrencyItemConverter( } private fun toPromoBannerUM( + accountId: AccountId, currencyStatus: CryptoCurrencyStatus, earnApyInfo: EarnApyConverter.EarnApyInfo?, ): TangemTokenRowUM.PromoBannerUM { @@ -281,7 +283,7 @@ internal class WalletTokenCurrencyItemConverter( onPromoBannerClick = { clickIntents.onYieldPromoClicked(currency) clickIntents.onApyLabelClick( - userWalletId = selectedWallet.walletId, + accountId = accountId, currencyStatus = currencyStatus, apySource = earnApyInfo.source, apy = earnApyInfo.apy, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/WalletTokensListUMConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/WalletTokensListUMConverter.kt index b4cf26bf7e..005d2bb298 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/WalletTokensListUMConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/WalletTokensListUMConverter.kt @@ -35,7 +35,7 @@ internal class WalletTokensListUMConverter( private val yieldModuleApyMap: Map, private val isAccountsModeEnabled: Boolean, private val expandedAccounts: Set, - stakingAvailabilityMap: Map, + private val stakingAvailabilityMap: Map, shouldShowMainPromo: Boolean, ) : Converter { @@ -48,15 +48,6 @@ internal class WalletTokensListUMConverter( ) } - private val currencyRowConverter by lazy(LazyThreadSafetyMode.NONE) { - WalletTokenCurrencyItemConverter( - appCurrency = appCurrency, - selectedWallet = selectedWallet, - yieldModuleApyMap = yieldModuleApyMap, - stakingAvailabilityMap = stakingAvailabilityMap, - clickIntents = clickIntents, - ) - } private val yieldSupplyPromoBannerConverter by lazy(LazyThreadSafetyMode.NONE) { YieldSupplyPromoBannerConverter( yieldModuleApyMap, @@ -64,6 +55,20 @@ internal class WalletTokensListUMConverter( ) } + private fun currencyRowConverter( + accountId: AccountId, + shouldShowPromo: Boolean, + ): WalletTokenCurrencyItemConverter { + return WalletTokenCurrencyItemConverter( + appCurrency = appCurrency, + accountId = accountId, + shouldShowPromo = shouldShowPromo, + yieldModuleApyMap = yieldModuleApyMap, + stakingAvailabilityMap = stakingAvailabilityMap, + clickIntents = clickIntents, + ) + } + override fun convert(value: AccountStatusList): WalletTokensListUM { val promoCryptoCurrency = yieldSupplyPromoBannerConverter.convert2(value = value) return if (value.accountStatuses.isEmpty()) { @@ -85,13 +90,13 @@ internal class WalletTokensListUMConverter( isExpanded = isExpanded || !isCollapsable, isCollapsable = isCollapsable, tokenList = getTokenListItems( - accountStatus.tokenList, + accountStatus, promoCryptoCurrency, ).toPersistentList(), ), ) } else { - getTokenListItems(accountStatus.tokenList, promoCryptoCurrency) + getTokenListItems(accountStatus, promoCryptoCurrency) } }.toPersistentList() @@ -103,10 +108,10 @@ internal class WalletTokensListUMConverter( } private fun getTokenListItems( - tokenList: TokenList, + accountStatus: AccountStatus.CryptoPortfolio, promoCryptoCurrency: CryptoCurrencyStatus?, ): Sequence { - return when (tokenList) { + return when (val tokenList = accountStatus.tokenList) { TokenList.Empty -> emptySequence() is TokenList.GroupedByNetwork -> { tokenList.groups.asSequence().flatMap { (network, currencies) -> @@ -120,7 +125,10 @@ internal class WalletTokensListUMConverter( currencies.asSequence().map { currencyStatus -> val shouldShowPromo = promoCryptoCurrency?.currency?.id == currencyStatus.currency.id TokensListItemUM2.Token( - tokenRowUM = currencyRowConverter.convert(currencyStatus to shouldShowPromo), + tokenRowUM = currencyRowConverter( + accountStatus.accountId, + shouldShowPromo, + ).convert(currencyStatus), ) }.toList(), ) @@ -131,7 +139,10 @@ internal class WalletTokensListUMConverter( tokenList.currencies.asSequence().map { currencyStatus -> val shouldShowPromo = promoCryptoCurrency?.currency?.id == currencyStatus.currency.id TokensListItemUM2.Token( - tokenRowUM = currencyRowConverter.convert(currencyStatus to shouldShowPromo), + tokenRowUM = currencyRowConverter( + accountStatus.accountId, + shouldShowPromo, + ).convert(currencyStatus), ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicAccountListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicAccountListSubscriber.kt index 5c944d4473..8bff35ab6f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicAccountListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicAccountListSubscriber.kt @@ -6,7 +6,6 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.core.lce.Lce import com.tangem.domain.core.utils.getOrElse -import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.tokenlist.TokenList @@ -66,7 +65,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() { singleAccountTransform( maybeTokenList = maybeTokenList, appCurrency = appCurrency, - portfolioId = PortfolioId(mainAccount.accountId), + accountId = mainAccount.accountId, yieldSupplyApyMap = yieldSupplyApyMap, stakingAvailabilityMap = stakingAvailabilityMap, shouldShowMainPromo = shouldShowMainPromo, @@ -111,7 +110,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() { private fun singleAccountTransform( maybeTokenList: Lce, appCurrency: AppCurrency, - portfolioId: PortfolioId, + accountId: AccountId, yieldSupplyApyMap: Map = emptyMap(), stakingAvailabilityMap: Map = emptyMap(), shouldShowMainPromo: Boolean, @@ -140,7 +139,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() { ) updateContent( - params = TokenConverterParams.Wallet(portfolioId, tokenList), + params = TokenConverterParams.Wallet(accountId, tokenList), appCurrency = appCurrency, yieldSupplyApyMap = yieldSupplyApyMap, stakingAvailabilityMap = stakingAvailabilityMap, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt index dfeb7d4b35..c00cc2569d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/SingleWalletButtonsSubscriber.kt @@ -2,7 +2,6 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2 -import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.tokens.model.TokenActionsState import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents @@ -33,17 +32,17 @@ internal class SingleWalletButtonsSubscriber @AssistedInject constructor( getCryptoCurrencyActionsUseCaseV2(accountId = accountId, currency = it.currency) } .onEach { - updateContent(tokenActionsState = it, portfolioId = PortfolioId(userWallet.walletId)) + updateContent(tokenActionsState = it) } } - private fun updateContent(tokenActionsState: TokenActionsState, portfolioId: PortfolioId) { + private fun updateContent(tokenActionsState: TokenActionsState) { stateController.update( SetCryptoCurrencyActionsTransformer( tokenActionsState = tokenActionsState, userWallet = userWallet, clickIntents = clickIntents, - portfolioId = portfolioId, + accountId = accountId, ), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/multicurrency/MultiCurrencyAccountContent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/multicurrency/MultiCurrencyAccountContent.kt index 29616c5969..f8349a879c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/multicurrency/MultiCurrencyAccountContent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/multicurrency/MultiCurrencyAccountContent.kt @@ -3,22 +3,23 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrenc import androidx.compose.animation.* import androidx.compose.animation.core.FastOutLinearInEasing import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.SpacerH16 +import com.tangem.core.ui.components.SpacerH24 +import com.tangem.core.ui.components.buttons.SecondarySmallButton +import com.tangem.core.ui.components.buttons.SmallButtonConfig import com.tangem.core.ui.components.tokenlist.PortfolioListItem import com.tangem.core.ui.components.tokenlist.PortfolioTokensListItem +import com.tangem.core.ui.components.tokenlist.state.PortfolioItemContentUM import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.core.ui.decorations.roundedShapeItemDecoration import com.tangem.core.ui.res.TangemTheme @@ -58,7 +59,8 @@ internal fun LazyListScope.portfolioTokensList( portfolioIndex = portfolioIndex, isBalanceHidden = isBalanceHidden, ) - if (tokens.isEmpty()) { + val portfolioContent = portfolio.content + if (portfolioContent is PortfolioItemContentUM.Empty) { item( key = "$NON_CONTENT_TOKENS_LIST_KEY account-${portfolio.id}", contentType = "$NON_CONTENT_TOKENS_LIST_KEY account-${portfolio.id}", @@ -76,9 +78,7 @@ internal fun LazyListScope.portfolioTokensList( ), visible = isExpanded, ) { - NonContentItemContent( - modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing28), - ) + EmptyAccountContent(portfolioContent) } } return @@ -114,6 +114,28 @@ internal fun LazyListScope.portfolioTokensList( ) } +@Composable +private fun EmptyAccountContent(emptyConent: PortfolioItemContentUM.Empty, modifier: Modifier = Modifier) { + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + SpacerH16() + NonContentItemContent() + val emptyAction = emptyConent.action + if (emptyAction != null) { + SpacerH16() + SecondarySmallButton( + config = SmallButtonConfig( + text = emptyAction.text, + onClick = { emptyAction.onClick() }, + ), + ) + } + SpacerH24() + } +} + @Suppress("MagicNumber") private fun LazyListScope.portfolioItem( portfolio: TokensListItemUM.Portfolio, diff --git a/features/wallet/impl/src/test/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerConverterTest.kt b/features/wallet/impl/src/test/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerConverterTest.kt index efb582f714..cbdb878996 100644 --- a/features/wallet/impl/src/test/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerConverterTest.kt +++ b/features/wallet/impl/src/test/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/YieldSupplyPromoBannerConverterTest.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.convert import com.google.common.truth.Truth.assertThat import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.StatusSource +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.network.Network @@ -22,7 +23,7 @@ class YieldSupplyPromoBannerConverterTest { val status = createLoadedStatus(token = token, amount = BigDecimal.ONE, isYieldActive = false) val tokenList = ungroupedTokenList(status) val params = TokenConverterParams.Wallet( - portfolioId = PortfolioId.Wallet(UserWalletId("00")), + accountId = AccountId.forMainCryptoPortfolio(UserWalletId("00")), tokenList = tokenList, ) val converter = YieldSupplyPromoBannerConverter( @@ -40,7 +41,7 @@ class YieldSupplyPromoBannerConverterTest { val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xA1") val status = createLoadedStatus(token = token, amount = BigDecimal("2.0"), isYieldActive = false) val params = TokenConverterParams.Wallet( - portfolioId = PortfolioId.Wallet(UserWalletId("00")), + accountId = AccountId.forMainCryptoPortfolio(UserWalletId("00")), tokenList = ungroupedTokenList(status), ) val converter = YieldSupplyPromoBannerConverter( @@ -58,7 +59,7 @@ class YieldSupplyPromoBannerConverterTest { val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xAA") val statusActive = createLoadedStatus(token = token, amount = BigDecimal("5"), isYieldActive = true) val params = TokenConverterParams.Wallet( - portfolioId = PortfolioId.Wallet(UserWalletId("00")), + accountId = AccountId.forMainCryptoPortfolio(UserWalletId("00")), tokenList = ungroupedTokenList(statusActive), ) val converter = YieldSupplyPromoBannerConverter( @@ -86,7 +87,7 @@ class YieldSupplyPromoBannerConverterTest { ) val params = TokenConverterParams.Wallet( - portfolioId = PortfolioId.Wallet(UserWalletId("00")), + accountId = AccountId.forMainCryptoPortfolio(UserWalletId("00")), tokenList = ungroupedTokenList(statusSmall, statusBig), ) val converter = YieldSupplyPromoBannerConverter( @@ -109,7 +110,7 @@ class YieldSupplyPromoBannerConverterTest { val apyMap = mapOf(mismatchedKey to BigDecimal("0.07")) val params = TokenConverterParams.Wallet( - portfolioId = PortfolioId.Wallet(UserWalletId("00")), + accountId = AccountId.forMainCryptoPortfolio(UserWalletId("00")), tokenList = ungroupedTokenList(status), ) val converter = YieldSupplyPromoBannerConverter( @@ -127,7 +128,7 @@ class YieldSupplyPromoBannerConverterTest { val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xCUSTOM") val status = createCustomStatus(token = token, amount = BigDecimal("5.0"), isYieldActive = false) val params = TokenConverterParams.Wallet( - portfolioId = PortfolioId.Wallet(UserWalletId("00")), + accountId = AccountId.forMainCryptoPortfolio(UserWalletId("00")), tokenList = ungroupedTokenList(status), ) val converter = YieldSupplyPromoBannerConverter(