From 51efb0e7814887471cf9e27c077e1c3e9b1da7df Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 27 Jun 2025 12:47:02 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../common/ui/userwallet/UserWalletItem.kt | 64 +++++++++++-------- .../converter/ArtworkUMConverter.kt | 23 +++++++ .../converter/UserWalletItemUMConverter.kt | 5 +- .../core/ui/components/artwork/ArtworkUM.kt | 13 +--- .../onboarding/v2/common/ui/WalletCard.kt | 36 +++++++---- .../impl/model/OnboardingMultiWalletModel.kt | 11 ++-- .../topup/ui/OnboardingNoteTopUpHeader.kt | 3 +- .../v2/note/impl/model/OnboardingNoteModel.kt | 5 +- 8 files changed, 101 insertions(+), 59 deletions(-) create mode 100644 common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/ArtworkUMConverter.kt diff --git a/common/ui/src/main/java/com/tangem/common/ui/userwallet/UserWalletItem.kt b/common/ui/src/main/java/com/tangem/common/ui/userwallet/UserWalletItem.kt index 5d2c226351..bc60544cb1 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/userwallet/UserWalletItem.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/userwallet/UserWalletItem.kt @@ -12,7 +12,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.vectorResource @@ -178,32 +180,42 @@ private fun CardImage(imageState: UserWalletItemUM.ImageState, modifier: Modifie ) } is UserWalletItemUM.ImageState.Image -> { - SubcomposeAsyncImage( - modifier = imageModifier, - model = ImageRequest.Builder(LocalContext.current) - .size( - width = with(LocalDensity.current) { TangemTheme.dimens.size36.roundToPx() }, - height = with(LocalDensity.current) { TangemTheme.dimens.size24.roundToPx() }, - ) - .data(imageState.artwork.verifiedArtwork?.toByteArray() ?: imageState.artwork.defaultUrl) - .crossfade(enable = true) - .allowHardware(enable = false) - .build(), - loading = { - RectangleShimmer( - modifier = imageModifier, - radius = TangemTheme.dimens.size2, - ) - }, - error = { - Image( - modifier = imageModifier.then(Modifier.rotate(90F)), - imageVector = ImageVector.vectorResource(R.drawable.img_card_wallet_2_gray_22_36), - contentDescription = null, - ) - }, - contentDescription = null, - ) + val verifiedArtwork = imageState.artwork.verifiedArtwork + if (verifiedArtwork != null) { + Image( + modifier = imageModifier, + painter = BitmapPainter(verifiedArtwork), + contentScale = ContentScale.Fit, + contentDescription = null, + ) + } else { + SubcomposeAsyncImage( + modifier = imageModifier, + model = ImageRequest.Builder(LocalContext.current) + .size( + width = with(LocalDensity.current) { TangemTheme.dimens.size36.roundToPx() }, + height = with(LocalDensity.current) { TangemTheme.dimens.size24.roundToPx() }, + ) + .data(imageState.artwork.defaultUrl) + .crossfade(enable = true) + .allowHardware(enable = false) + .build(), + loading = { + RectangleShimmer( + modifier = imageModifier, + radius = TangemTheme.dimens.size2, + ) + }, + error = { + Image( + modifier = imageModifier.then(Modifier.rotate(90F)), + imageVector = ImageVector.vectorResource(R.drawable.img_card_wallet_2_gray_22_36), + contentDescription = null, + ) + }, + contentDescription = null, + ) + } } } } diff --git a/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/ArtworkUMConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/ArtworkUMConverter.kt new file mode 100644 index 0000000000..3278017126 --- /dev/null +++ b/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/ArtworkUMConverter.kt @@ -0,0 +1,23 @@ +package com.tangem.common.ui.userwallet.converter + +import android.graphics.BitmapFactory +import androidx.compose.ui.graphics.asImageBitmap +import com.tangem.core.ui.components.artwork.ArtworkUM +import com.tangem.domain.models.ArtworkModel +import com.tangem.utils.converter.Converter +import javax.inject.Inject + +class ArtworkUMConverter @Inject constructor() : Converter { + + override fun convert(value: ArtworkModel): ArtworkUM { + val bimap = try { + value.verifiedArtwork?.let { BitmapFactory.decodeByteArray(it, 0, it.size) } + } catch (ignore: Exception) { + null + } + return ArtworkUM( + verifiedArtwork = bimap?.asImageBitmap(), + defaultUrl = value.defaultUrl, + ) + } +} \ No newline at end of file diff --git a/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/UserWalletItemUMConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/UserWalletItemUMConverter.kt index 875f1044f8..534a8de836 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/UserWalletItemUMConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/UserWalletItemUMConverter.kt @@ -2,7 +2,6 @@ package com.tangem.common.ui.userwallet.converter import com.tangem.common.ui.R import com.tangem.common.ui.userwallet.state.UserWalletItemUM -import com.tangem.core.ui.components.artwork.ArtworkUM import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList @@ -38,6 +37,8 @@ class UserWalletItemUMConverter( private val artwork: ArtworkModel? = null, ) : Converter { + private val artworkUMConverter = ArtworkUMConverter() + override fun convert(value: UserWallet): UserWalletItemUM { return with(value) { UserWalletItemUM( @@ -49,7 +50,7 @@ class UserWalletItemUMConverter( endIcon = endIcon, onClick = { onClick(value.walletId) }, imageState = artwork?.let { - UserWalletItemUM.ImageState.Image(ArtworkUM(it.verifiedArtwork, it.defaultUrl)) + UserWalletItemUM.ImageState.Image(artworkUMConverter.convert(it)) } ?: UserWalletItemUM.ImageState.Loading, ) } diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/artwork/ArtworkUM.kt b/core/ui/src/main/java/com/tangem/core/ui/components/artwork/ArtworkUM.kt index 5c1f568b02..a0e9d2e0f7 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/artwork/ArtworkUM.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/artwork/ArtworkUM.kt @@ -1,17 +1,10 @@ package com.tangem.core.ui.components.artwork import androidx.compose.runtime.Immutable -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toImmutableList +import androidx.compose.ui.graphics.ImageBitmap @Immutable data class ArtworkUM( - val verifiedArtwork: ImmutableList? = null, + val verifiedArtwork: ImageBitmap? = null, val defaultUrl: String, -) { - - constructor(bytes: ByteArray?, defaultUrl: String) : this( - verifiedArtwork = bytes?.toList()?.toImmutableList(), - defaultUrl = defaultUrl, - ) -} \ No newline at end of file +) \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/ui/WalletCard.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/ui/WalletCard.kt index bd7b6d1a54..1fd4c123e5 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/ui/WalletCard.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/ui/WalletCard.kt @@ -1,7 +1,9 @@ package com.tangem.features.onboarding.v2.common.ui +import androidx.compose.foundation.Image import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource @@ -12,16 +14,26 @@ import com.tangem.features.onboarding.v2.impl.R @Composable internal fun WalletCard(artwork: ArtworkUM?, modifier: Modifier = Modifier) { - AsyncImage( - modifier = modifier, - model = ImageRequest.Builder(LocalContext.current) - .data(artwork?.verifiedArtwork?.toByteArray() ?: artwork?.defaultUrl) - .crossfade(true) - .build(), - placeholder = painterResource(R.drawable.card_placeholder_black), - error = painterResource(R.drawable.card_placeholder_black), - fallback = painterResource(R.drawable.card_placeholder_black), - contentScale = ContentScale.Fit, - contentDescription = null, - ) + val verifiedArtwork = artwork?.verifiedArtwork + if (verifiedArtwork != null) { + Image( + modifier = modifier, + painter = BitmapPainter(verifiedArtwork), + contentScale = ContentScale.Fit, + contentDescription = null, + ) + } else { + AsyncImage( + modifier = modifier, + model = ImageRequest.Builder(LocalContext.current) + .data(artwork?.defaultUrl) + .crossfade(true) + .build(), + placeholder = painterResource(R.drawable.card_placeholder_black), + error = painterResource(R.drawable.card_placeholder_black), + fallback = painterResource(R.drawable.card_placeholder_black), + contentScale = ContentScale.Fit, + contentDescription = null, + ) + } } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt index 6d5a640d3d..bf9980e12d 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt @@ -1,19 +1,19 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.model +import com.tangem.common.ui.userwallet.converter.ArtworkUMConverter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender -import com.tangem.core.ui.components.artwork.ArtworkUM import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ProductType import com.tangem.domain.onboarding.repository.OnboardingRepository import com.tangem.domain.wallets.usecase.GetCardImageUseCase -import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent import com.tangem.features.onboarding.v2.common.ui.interruptBackupDialog +import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams import com.tangem.features.onboarding.v2.multiwallet.impl.model.OnboardingMultiWalletState.FinalizeStage import com.tangem.features.onboarding.v2.multiwallet.impl.ui.state.OnboardingMultiWalletUM @@ -39,6 +39,7 @@ internal class OnboardingMultiWalletModel @Inject constructor( private val onboardingRepository: OnboardingRepository, private val getCardImageUseCase: GetCardImageUseCase, private val uiMessageSender: UiMessageSender, + private val artworkUMConverter: ArtworkUMConverter, ) : Model() { private val params = paramsContainer.require() private val _uiState = MutableStateFlow(OnboardingMultiWalletUM()) @@ -90,7 +91,7 @@ internal class OnboardingMultiWalletModel @Inject constructor( firmwareVersion = backup.card2.firmwareVersion, ) _uiState.update { - it.copy(artwork2 = ArtworkUM(artwork.verifiedArtwork, artwork.defaultUrl)) + it.copy(artwork2 = artworkUMConverter.convert(artwork)) } } _uiState.value.artwork3 == null && backup.card3 != null -> { @@ -103,7 +104,7 @@ internal class OnboardingMultiWalletModel @Inject constructor( firmwareVersion = backup.card3.firmwareVersion, ) _uiState.update { - it.copy(artwork3 = ArtworkUM(artwork.verifiedArtwork, artwork.defaultUrl)) + it.copy(artwork3 = artworkUMConverter.convert(artwork)) } } } @@ -179,7 +180,7 @@ internal class OnboardingMultiWalletModel @Inject constructor( ) _uiState.update { - it.copy(artwork1 = ArtworkUM(artwork.verifiedArtwork, artwork.defaultUrl)) + it.copy(artwork1 = artworkUMConverter.convert(artwork)) } } } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/child/topup/ui/OnboardingNoteTopUpHeader.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/child/topup/ui/OnboardingNoteTopUpHeader.kt index 9830905a93..672d5e838b 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/child/topup/ui/OnboardingNoteTopUpHeader.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/child/topup/ui/OnboardingNoteTopUpHeader.kt @@ -22,7 +22,6 @@ import com.tangem.features.onboarding.v2.common.ui.RefreshButton import com.tangem.features.onboarding.v2.common.ui.WalletCard import com.tangem.features.onboarding.v2.impl.R import com.valentinilk.shimmer.shimmer -import kotlinx.collections.immutable.ImmutableList @Composable fun OnboardingNoteTopUpHeader( @@ -95,7 +94,7 @@ private fun OnboardinNoteTopUpHeaderPreview() { TangemThemePreview { OnboardingNoteTopUpHeader( balance = "0.00000001 BTC", - cardArtwork = ArtworkUM(null as ImmutableList?, ""), + cardArtwork = ArtworkUM(null, ""), onRefreshBalanceClick = {}, isRefreshing = false, ) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/model/OnboardingNoteModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/model/OnboardingNoteModel.kt index 43d12d119e..27e57382fd 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/model/OnboardingNoteModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/model/OnboardingNoteModel.kt @@ -1,12 +1,12 @@ package com.tangem.features.onboarding.v2.note.impl.model import com.arkivanov.decompose.router.stack.StackNavigation +import com.tangem.common.ui.userwallet.converter.ArtworkUMConverter import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender -import com.tangem.core.ui.components.artwork.ArtworkUM import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.GetCardImageUseCase import com.tangem.features.onboarding.v2.common.ui.exitOnboardingDialog @@ -29,6 +29,7 @@ internal class OnboardingNoteModel @Inject constructor( private val router: Router, private val messageSender: UiMessageSender, private val getCardImageUseCase: GetCardImageUseCase, + private val artworkUMConverter: ArtworkUMConverter, ) : Model() { @Suppress("UnusedPrivateMember") @@ -98,7 +99,7 @@ internal class OnboardingNoteModel @Inject constructor( firmwareVersion = cardInfo.firmwareVersion.toSdkFirmwareVersion(), ) _uiState.update { - it.copy(cardArtwork = ArtworkUM(artwork.verifiedArtwork, artwork.defaultUrl)) + it.copy(cardArtwork = artworkUMConverter.convert(artwork)) } } }