From 9c4840152b1083e3d5f8950a1a20a43193774ac8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 May 2025 12:44:35 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../wallets/usecase/GetCardImageUseCase.kt | 2 +- features/markets/impl/build.gradle.kts | 3 ++ .../model/AddToPortfolioBSContentUMFactory.kt | 23 +++++++++- .../impl/model/MarketsPortfolioModel.kt | 43 ++++++++++++++++++- .../impl/model/MyPortfolioUMFactory.kt | 17 +++++++- 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetCardImageUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetCardImageUseCase.kt index 7a71823750..6b3f2f5ab8 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetCardImageUseCase.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetCardImageUseCase.kt @@ -36,7 +36,7 @@ class GetCardImageUseCase( cardPublicKey: ByteArray, manufacturerName: String, firmwareVersion: FirmwareVersion, - size: ArtworkSize, + size: ArtworkSize = ArtworkSize.SMALL, ): ArtworkModel { return if (cardSdkFeatureToggles.isNewArtworkLoadingEnabled) { val result = cardArtworksProvider.getArtwork( diff --git a/features/markets/impl/build.gradle.kts b/features/markets/impl/build.gradle.kts index fded1c34bc..3925b760a6 100644 --- a/features/markets/impl/build.gradle.kts +++ b/features/markets/impl/build.gradle.kts @@ -78,4 +78,7 @@ dependencies { /* Libs */ implementation(projects.libs.crypto) implementation(projects.libs.blockchainSdk) + + /** Tangem libraries */ + implementation(tangemDeps.card.core) } \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/AddToPortfolioBSContentUMFactory.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/AddToPortfolioBSContentUMFactory.kt index aecd1f943e..fb81a30b2e 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/AddToPortfolioBSContentUMFactory.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/AddToPortfolioBSContentUMFactory.kt @@ -7,6 +7,8 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent import com.tangem.core.ui.components.rows.model.BlockchainRowUM import com.tangem.domain.markets.TokenMarketInfo import com.tangem.domain.markets.TokenMarketParams +import com.tangem.domain.models.ArtworkModel +import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.markets.portfolio.impl.loader.PortfolioData @@ -44,19 +46,25 @@ internal class AddToPortfolioBSContentUMFactory( * @param selectedWallet selected wallet * @param alreadyAddedNetworks already added networks */ + @Suppress("LongParameterList") fun create( currentState: TangemBottomSheetConfig?, portfolioData: PortfolioData, portfolioUIData: PortfolioUIData, selectedWallet: UserWallet?, alreadyAddedNetworks: Set?, + artworks: HashMap, ): TangemBottomSheetConfig { return (currentState ?: TangemBottomSheetConfig.Empty).copy( isShown = portfolioUIData.portfolioBSVisibilityModel.addToPortfolioBSVisibility, onDismissRequest = { onAddToPortfolioVisibilityChange(false) }, content = if (selectedWallet != null && alreadyAddedNetworks != null) { AddToPortfolioBSContentUM( - selectedWallet = selectedWallet.toSelectedUserWalletItemUM(), + selectedWallet = selectedWallet.toSelectedUserWalletItemUM( + portfolioData = portfolioData, + balance = portfolioData.walletsWithBalance[selectedWallet.walletId]?.getOrNull(), + artwork = artworks[selectedWallet.walletId], + ), selectNetworkUM = SelectNetworkUMConverter( networksWithToggle = portfolioUIData.addToPortfolioData.associateWithToggle( userWalletId = selectedWallet.walletId, @@ -86,6 +94,7 @@ internal class AddToPortfolioBSContentUMFactory( isShow = portfolioUIData.portfolioBSVisibilityModel.walletSelectorBSVisibility, portfolioData = portfolioData, selectedWalletId = selectedWallet.walletId, + artworks = artworks, ), isWalletBlockVisible = portfolioData.walletsWithCurrencies .filterKeys(UserWallet::isMultiCurrency).size > 1, @@ -96,10 +105,18 @@ internal class AddToPortfolioBSContentUMFactory( ) } - private fun UserWallet.toSelectedUserWalletItemUM(): UserWalletItemUM { + private fun UserWallet.toSelectedUserWalletItemUM( + artwork: ArtworkModel? = null, + portfolioData: PortfolioData, + balance: TotalFiatBalance?, + ): UserWalletItemUM { return UserWalletItemUMConverter( onClick = { onWalletSelectorVisibilityChange(true) }, endIcon = UserWalletItemUM.EndIcon.Arrow, + balance = balance, + artwork = artwork, + appCurrency = portfolioData.appCurrency, + isBalanceHidden = portfolioData.isBalanceHidden, ).convert(value = this) } @@ -107,6 +124,7 @@ internal class AddToPortfolioBSContentUMFactory( isShow: Boolean, portfolioData: PortfolioData, selectedWalletId: UserWalletId, + artworks: HashMap, ): TangemBottomSheetConfig { return TangemBottomSheetConfig( isShown = isShow, @@ -133,6 +151,7 @@ internal class AddToPortfolioBSContentUMFactory( } else { UserWalletItemUM.EndIcon.None }, + artwork = artworks[userWallet.walletId], ).convert(userWallet) } .toImmutableList(), diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt index aa930886b0..ab9607b53d 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt @@ -20,11 +20,16 @@ import com.tangem.domain.managetokens.CheckCurrencyUnsupportedUseCase import com.tangem.domain.managetokens.model.CurrencyUnsupportedState import com.tangem.domain.markets.SaveMarketTokensUseCase import com.tangem.domain.markets.TokenMarketInfo +import com.tangem.domain.models.ArtworkModel +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.domain.wallets.usecase.GetCardImageUseCase import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase import com.tangem.features.markets.impl.R import com.tangem.features.markets.portfolio.api.MarketsPortfolioComponent import com.tangem.features.markets.portfolio.impl.analytics.PortfolioAnalyticsEvent +import com.tangem.features.markets.portfolio.impl.loader.PortfolioData import com.tangem.features.markets.portfolio.impl.loader.PortfolioDataLoader import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM import com.tangem.lib.crypto.BlockchainUtils @@ -32,6 +37,8 @@ import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import timber.log.Timber import javax.inject.Inject @@ -49,6 +56,7 @@ internal class MarketsPortfolioModel @Inject constructor( private val portfolioDataLoader: PortfolioDataLoader, private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase, private val saveMarketTokensUseCase: SaveMarketTokensUseCase, + private val getCardImageUseCase: GetCardImageUseCase, private val addToPortfolioManager: AddToPortfolioManager, private val analyticsEventHandler: AnalyticsEventHandler, ) : Model() { @@ -56,6 +64,10 @@ internal class MarketsPortfolioModel @Inject constructor( val state: StateFlow get() = _state private val _state: MutableStateFlow = MutableStateFlow(value = MyPortfolioUM.Loading) + private val loadedArtworks: HashMap = hashMapOf() + private val artworksState: MutableStateFlow> = MutableStateFlow(hashMapOf()) + private val loadArtworksMutex = Mutex() + private val params = paramsContainer.require() private val analyticsEventBuilder = PortfolioAnalyticsEvent.EventBuilder( token = params.token, @@ -161,14 +173,43 @@ internal class MarketsPortfolioModel @Inject constructor( private fun subscribeOnStateUpdates() { combine( - flow = portfolioDataLoader.load(params.token.id, addToPortfolioManager.availableNetworks), + flow = loadPortfolioData(params.token.id, addToPortfolioManager.availableNetworks), flow2 = getPortfolioUIDataFlow(), + flow3 = artworksState, transform = factory::create, ) .onEach { _state.value = it } .launchIn(modelScope) } + private fun loadPortfolioData( + currencyRawId: CryptoCurrency.RawID, + availableNetworksFlow: Flow?>, + ): Flow { + portfolioDataLoader.load(currencyRawId, availableNetworksFlow).onEach { + loadArtworks(it.walletsWithCurrencies.keys.toList()) + }.also { return it } + } + + private fun loadArtworks(wallets: List) { + modelScope.launch { + loadArtworksMutex.withLock { + wallets.forEach { wallet -> + if (!loadedArtworks.containsKey(wallet.walletId)) { + val artwork = getCardImageUseCase( + cardId = wallet.cardId, + manufacturerName = wallet.scanResponse.card.manufacturer.name, + firmwareVersion = wallet.scanResponse.card.firmwareVersion.toSdkFirmwareVersion(), + cardPublicKey = wallet.scanResponse.card.cardPublicKey, + ) + loadedArtworks[wallet.walletId] = artwork + artworksState.emit(loadedArtworks) + } + } + } + } + } + private fun getPortfolioUIDataFlow(): Flow { return combine( flow = portfolioBSVisibilityModelFlow, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MyPortfolioUMFactory.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MyPortfolioUMFactory.kt index 5729f632b6..90662804f0 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MyPortfolioUMFactory.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MyPortfolioUMFactory.kt @@ -2,8 +2,10 @@ package com.tangem.features.markets.portfolio.impl.model import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.domain.markets.TokenMarketInfo +import com.tangem.domain.models.ArtworkModel 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 import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM.Tokens.AddButtonState @@ -30,7 +32,11 @@ internal class MyPortfolioUMFactory( private val updateTokens: ((ImmutableList) -> ImmutableList) -> Unit, ) { - fun create(portfolioData: PortfolioData, portfolioUIData: PortfolioUIData): MyPortfolioUM { + fun create( + portfolioData: PortfolioData, + portfolioUIData: PortfolioUIData, + artworks: HashMap, + ): MyPortfolioUM { val addToPortfolioData = portfolioUIData.addToPortfolioData val isOnlyUnavailableNetworks = addToPortfolioData.availableNetworks?.isEmpty() == true @@ -51,6 +57,7 @@ internal class MyPortfolioUMFactory( addToPortfolioBSConfig = createAddToPortfolioBSConfig( portfolioData = portfolioData, portfolioUIData = portfolioUIData, + artworks = artworks, ), onAddClick = onAddClick, ) @@ -65,7 +72,11 @@ internal class MyPortfolioUMFactory( addButtonState = walletsWithCurrencies.getAddButtonState( availableNetworks = addToPortfolioData.availableNetworks, ), - bsConfig = createAddToPortfolioBSConfig(portfolioData = portfolioData, portfolioUIData = portfolioUIData), + bsConfig = createAddToPortfolioBSConfig( + portfolioData = portfolioData, + portfolioUIData = portfolioUIData, + artworks = artworks, + ), onAddClick = onAddClick, quickActionsIntents = tokenActionsHandler, currentState = currentState, @@ -77,6 +88,7 @@ internal class MyPortfolioUMFactory( private fun createAddToPortfolioBSConfig( portfolioData: PortfolioData, portfolioUIData: PortfolioUIData, + artworks: HashMap, ): TangemBottomSheetConfig { val selectedWallet = portfolioData.walletsWithCurrencies.keys .firstOrNull { it.walletId == portfolioUIData.selectedWalletId } @@ -95,6 +107,7 @@ internal class MyPortfolioUMFactory( portfolioUIData = portfolioUIData, selectedWallet = selectedWallet, alreadyAddedNetworks = alreadyAddedNetworks, + artworks = artworks, ) }