From 4b97be34f348b93cfec6554ffce76333f67ce6a8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 7 Dec 2025 11:13:28 +0300 Subject: [PATCH 01/13] Updated on 2026-08-14 --- .../wallet/model/TangemPayMainInfoManager.kt | 11 +++++++---- .../subscribers/TangemPayMainSubscriber.kt | 18 +++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/TangemPayMainInfoManager.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/TangemPayMainInfoManager.kt index 184cc926bd..ee1c60aee1 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/TangemPayMainInfoManager.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/TangemPayMainInfoManager.kt @@ -7,6 +7,7 @@ import com.tangem.domain.pay.model.TangemPayCustomerInfoError import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.update import javax.inject.Inject import javax.inject.Singleton @@ -16,11 +17,13 @@ internal class TangemPayMainInfoManager @Inject constructor( ) { val mainScreenCustomerInfo: - StateFlow>?> - field = MutableStateFlow(null) + StateFlow>> + field = MutableStateFlow(mapOf()) suspend fun refreshTangemPayInfo(userWalletId: UserWalletId) { - val info = tangemPayMainScreenCustomerInfoUseCase(userWalletId) - mainScreenCustomerInfo.value = Pair(userWalletId, info) + mainScreenCustomerInfo.update { currentMap -> + val info = tangemPayMainScreenCustomerInfoUseCase(userWalletId) + currentMap.toMutableMap().apply { this[userWalletId] = info } + } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt index 0664439d54..4ba4c3e8f1 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt @@ -19,7 +19,10 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.onEach import timber.log.Timber @Suppress("LongParameterList") @@ -39,10 +42,11 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( private fun subscribeOnTangemPayInfoUpdates(): Flow<*> { return tangemPayMainInfoManager.mainScreenCustomerInfo - .filterNotNull() - .filter { it.first == userWallet.walletId } + .filter { it.isNotEmpty() } .distinctUntilChanged() - .onEach { (userWalletId, mainInfoData) -> + .onEach { data -> + val userWalletId = userWallet.walletId + val mainInfoData = data[userWalletId] ?: return@onEach mainInfoData.onLeft { tangemPayError -> when (tangemPayError) { TangemPayCustomerInfoError.RefreshNeededError -> { @@ -66,9 +70,9 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( ) } } - }.onRight { data -> - updateTangemPay(data, userWalletId) - analytics.send(customerInfo = data) + }.onRight { customerInfo -> + updateTangemPay(customerInfo, userWalletId) + analytics.send(customerInfo = customerInfo) } } } From cf55199f17d2b9e4bb992bff1de50ae0a061096c Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 13:53:14 +0500 Subject: [PATCH 02/13] Updated on 2026-08-14 --- .../tangem/feature/wallet/child/wallet/model/WalletModel.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index fe327cc2e0..12f7478a3e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -357,7 +357,10 @@ internal class WalletModel @Inject constructor( }.distinctUntilChanged(), transform = ::Pair, ).onEach { (inBackground, userWalletId) -> - if (inBackground) return@onEach + if (inBackground) { + updateTangemPayJobHolder.cancel() + return@onEach + } val savedCustomerInfo = tangemPayOnboardingRepository.getSavedCustomerInfo(userWalletId) From e6b4d2ae7b13b8cb477f1d956c1d783a15e142e1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 14:04:59 +0400 Subject: [PATCH 03/13] Updated on 2026-08-14 --- .../tangempay/ui/TangemPayDetailsScreen.kt | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt index aa81c82ede..e59ab905cb 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt @@ -99,19 +99,6 @@ internal fun TangemPayDetailsScreen( } else -> Unit } - item( - key = TangemPayDetailsBalanceBlockState::class.java, - content = { - TangemPayDetailsBalanceBlock( - modifier = modifier - .padding(horizontal = TangemTheme.dimens.spacing16) - .padding(top = 12.dp) - .fillMaxWidth(), - state = state.balanceBlockState, - isBalanceHidden = state.isBalanceHidden, - ) - }, - ) if (state.addToWalletBlockState != null) { item( key = AddToWalletBlockState::class.java, @@ -125,6 +112,19 @@ internal fun TangemPayDetailsScreen( }, ) } + item( + key = TangemPayDetailsBalanceBlockState::class.java, + content = { + TangemPayDetailsBalanceBlock( + modifier = modifier + .padding(horizontal = TangemTheme.dimens.spacing16) + .padding(top = 12.dp) + .fillMaxWidth(), + state = state.balanceBlockState, + isBalanceHidden = state.isBalanceHidden, + ) + }, + ) with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) } } } From c2625a0de7c84019e5cc6e57fd9644fee80a726b Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 12:37:31 +0300 Subject: [PATCH 04/13] Updated on 2026-08-14 --- .../tangem/data/pay/DefaultTangemPaySwapDataFactory.kt | 8 +++----- .../data/pay/repository/TangemPayRequestPerformer.kt | 8 ++++---- .../tangem/data/pay/util/TangemPayWalletsManager.kt | 6 +++++- .../com/tangem/domain/pay/TangemPaySwapDataFactory.kt | 2 ++ .../features/tangempay/model/TangemPayAddFundsModel.kt | 6 ++++++ .../features/tangempay/model/TangemPayDetailsModel.kt | 10 ++++++++-- .../wallet/subscribers/TangemPayMainSubscriber.kt | 1 + 7 files changed, 29 insertions(+), 12 deletions(-) diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPaySwapDataFactory.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPaySwapDataFactory.kt index b7f0683742..8533ae4744 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPaySwapDataFactory.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPaySwapDataFactory.kt @@ -9,7 +9,6 @@ import com.tangem.core.error.UniversalError import com.tangem.data.common.currency.CryptoCurrencyFactory import com.tangem.data.common.network.NetworkFactory import com.tangem.data.pay.util.TangemPayErrorConverter -import com.tangem.data.pay.util.TangemPayWalletsManager import com.tangem.datasource.di.NetworkMoshi import com.tangem.domain.models.ReceiveAddressModel import com.tangem.domain.models.ReceiveAddressModel.NameService @@ -32,7 +31,6 @@ private const val TOKEN_DECIMALS = 6 internal class DefaultTangemPaySwapDataFactory @Inject constructor( @NetworkMoshi moshi: Moshi, - private val tangemPayWalletsManager: TangemPayWalletsManager, excludedBlockchains: ExcludedBlockchains, ) : TangemPaySwapDataFactory { @@ -63,17 +61,17 @@ internal class DefaultTangemPaySwapDataFactory @Inject constructor( } override fun create( + userWallet: UserWallet, depositAddress: String, chainId: Int, cryptoBalance: BigDecimal, fiatBalance: BigDecimal, ): Either { return catch { - val wallet = tangemPayWalletsManager.getDefaultWalletForTangemPayBlocking() - val currency = getCurrency(wallet, chainId) + val currency = getCurrency(userWallet, chainId) TangemPayTopUpData( currency = currency, - walletId = wallet.walletId, + walletId = userWallet.walletId, cryptoBalance = cryptoBalance, fiatBalance = fiatBalance, depositAddress = depositAddress, diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt index f3aacb104e..7e6b5ec06c 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt @@ -21,11 +21,11 @@ import com.tangem.domain.visa.model.TangemPayAuthTokens import com.tangem.domain.visa.model.getAuthHeader import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import timber.log.Timber +import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject import javax.inject.Singleton @@ -40,7 +40,7 @@ internal class TangemPayRequestPerformer @Inject constructor( private val tangemPayStorage: TangemPayStorage, ) { - private val customerWalletAddress = MutableStateFlow(null) + private val customerWalletAddresses = ConcurrentHashMap() private val tokensMutex = Mutex() private val errorConverter = TangemPayErrorConverter(moshi) @@ -110,7 +110,7 @@ internal class TangemPayRequestPerformer @Inject constructor( } suspend fun getCustomerWalletAddress(userWalletId: UserWalletId): String { - val existingAddress = customerWalletAddress.value + val existingAddress = customerWalletAddresses[userWalletId] if (existingAddress != null) { return existingAddress } @@ -118,7 +118,7 @@ internal class TangemPayRequestPerformer @Inject constructor( userWalletId = userWalletId, ) ?: error("Can not find customer address") - customerWalletAddress.value = storedAddress + customerWalletAddresses[userWalletId] = storedAddress return storedAddress } diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayWalletsManager.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayWalletsManager.kt index b4c31a08cb..054e839ebb 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayWalletsManager.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayWalletsManager.kt @@ -15,12 +15,14 @@ class TangemPayWalletsManager @Inject constructor( private val hotWalletFeatureToggles: HotWalletFeatureToggles, ) { + @Deprecated("Don't use and put userWallet in features that need it") suspend fun getDefaultWalletForTangemPay(): UserWallet.Cold { val userWalletsFlow = if (useNewRepository()) repository.userWallets else manager.userWallets val userWallets = userWalletsFlow.filter { !it.isNullOrEmpty() }.first() return findColdWallet(userWallets) } + @Deprecated("Don't use and put userWallet in features that need it") fun getDefaultWalletForTangemPayBlocking(): UserWallet.Cold { val userWallets = if (useNewRepository()) repository.userWallets.value else manager.userWalletsSync return findColdWallet(userWallets) @@ -29,7 +31,9 @@ class TangemPayWalletsManager @Inject constructor( private fun useNewRepository(): Boolean = hotWalletFeatureToggles.isHotWalletEnabled private fun findColdWallet(userWallets: List?): UserWallet.Cold { - return userWallets?.find { it is UserWallet.Cold } as? UserWallet.Cold + return userWallets?.find { + it is UserWallet.Cold && it.isMultiCurrency + } as? UserWallet.Cold ?: error("Cannot find cold user wallet") } } \ No newline at end of file diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/TangemPaySwapDataFactory.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/TangemPaySwapDataFactory.kt index fe6cb7af82..c23f9becab 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/TangemPaySwapDataFactory.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/TangemPaySwapDataFactory.kt @@ -4,12 +4,14 @@ import arrow.core.Either import com.tangem.core.error.UniversalError import com.tangem.domain.models.ReceiveAddressModel import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId import java.math.BigDecimal interface TangemPaySwapDataFactory { fun create( + userWallet: UserWallet, depositAddress: String, chainId: Int, cryptoBalance: BigDecimal, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayAddFundsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayAddFundsModel.kt index eb7110543b..4f2ae1c371 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayAddFundsModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayAddFundsModel.kt @@ -5,6 +5,7 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.domain.pay.TangemPaySwapDataFactory +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.features.tangempay.components.TangemPayAddFundsComponent import com.tangem.features.tangempay.entity.TangemPayAddFundsUM import com.tangem.features.tangempay.model.transformers.TangemPayAddFundsUMConverter @@ -17,6 +18,7 @@ internal class TangemPayAddFundsModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, private val tangemPaySwapDataFactory: TangemPaySwapDataFactory, + private val getUserWalletUseCase: GetUserWalletUseCase, ) : Model() { private val params = paramsContainer.require() @@ -24,7 +26,11 @@ internal class TangemPayAddFundsModel @Inject constructor( val uiState: TangemPayAddFundsUM = getInitialState() private fun getInitialState(): TangemPayAddFundsUM { + val userWallet = requireNotNull( + getUserWalletUseCase(params.walletId).getOrNull(), + ) { "User wallet not found for id: ${params.walletId}" } val data = tangemPaySwapDataFactory.create( + userWallet = userWallet, depositAddress = params.depositAddress, chainId = params.chainId, cryptoBalance = params.cryptoBalance, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt index b3a558564e..c75973bf0f 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt @@ -18,14 +18,15 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.SnackbarMessage import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.models.TokenReceiveConfig -import com.tangem.domain.pay.TangemPayTopUpData import com.tangem.domain.pay.TangemPaySwapDataFactory +import com.tangem.domain.pay.TangemPayTopUpData import com.tangem.domain.pay.model.TangemPayCardBalance import com.tangem.domain.pay.repository.CustomerOrderRepository import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository import com.tangem.domain.tangempay.TangemPayAnalyticsEvents import com.tangem.domain.visa.model.TangemPayCardFrozenState import com.tangem.domain.visa.model.TangemPayTxHistoryItem +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.features.tangempay.TangemPayConstants import com.tangem.features.tangempay.components.AddFundsListener import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent @@ -55,7 +56,7 @@ import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject -@Suppress("LongParameterList") +@Suppress("LongParameterList", "LargeClass") @Stable @ModelScoped internal class TangemPayDetailsModel @Inject constructor( @@ -71,6 +72,7 @@ internal class TangemPayDetailsModel @Inject constructor( private val txHistoryUpdateListener: TangemPayTxHistoryUpdateListener, private val tangemPaySwapDataFactory: TangemPaySwapDataFactory, private val orderRepository: CustomerOrderRepository, + private val getUserWalletUseCase: GetUserWalletUseCase, ) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener { private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require() @@ -234,7 +236,11 @@ internal class TangemPayDetailsModel @Inject constructor( if (hasActiveWithdrawal) { showBottomSheetError(TangemPayDetailsErrorType.WithdrawInProgress) } else { + val userWallet = requireNotNull( + getUserWalletUseCase(params.userWalletId).getOrNull(), + ) { "User wallet not found: ${params.userWalletId}" } val data = tangemPaySwapDataFactory.create( + userWallet = userWallet, depositAddress = depositAddress, chainId = params.config.chainId, cryptoBalance = currentBalance.cryptoBalance, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt index 4ba4c3e8f1..5f74c8d01a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt @@ -46,6 +46,7 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( .distinctUntilChanged() .onEach { data -> val userWalletId = userWallet.walletId + Timber.tag("scan===").e("onEach $userWalletId $data") val mainInfoData = data[userWalletId] ?: return@onEach mainInfoData.onLeft { tangemPayError -> when (tangemPayError) { From fa55f1753c793f0e0e11cf7a841166c9586ab6b3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 13:02:48 +0300 Subject: [PATCH 05/13] Updated on 2026-08-14 --- .../tangempay/entity/TangemPayDetailsStateFactory.kt | 1 - .../TangemPayFreezeUnfreezeStateTransformer.kt | 12 ++++++++++++ .../wallet/subscribers/TangemPayMainSubscriber.kt | 1 - 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt index 44b0b79cb1..0036f7c5ba 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt @@ -41,7 +41,6 @@ internal class TangemPayDetailsStateFactory( ), ) } - return TangemPayDetailsUM( topBarConfig = TangemPayDetailsTopBarConfig( onBackClick = onBack, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt index c6dc60c3d9..7fb2efcb5e 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt @@ -6,6 +6,7 @@ import com.tangem.core.ui.extensions.themedColor import com.tangem.core.ui.res.TangemTheme import com.tangem.domain.visa.model.TangemPayCardFrozenState import com.tangem.features.tangempay.details.impl.R +import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarMenuItem import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarMenuItemType.FreezeCard import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarMenuItemType.UnfreezeCard @@ -31,9 +32,20 @@ internal class TangemPayFreezeUnfreezeStateTransformer( it.type == FreezeCard || it.type == UnfreezeCard } val dropdownMenuItems = createUpdatedMenuItems(filteredItems?.toPersistentList()) + val balanceBlockState = if (prevState.balanceBlockState is TangemPayDetailsBalanceBlockState.Content) { + val actionButtons = prevState.balanceBlockState.actionButtons.map { + it.copy(isEnabled = cardFrozenState == TangemPayCardFrozenState.Unfrozen) + } + prevState.balanceBlockState.copy( + actionButtons = actionButtons.toPersistentList(), + ) + } else { + prevState.balanceBlockState + } return prevState.copy( topBarConfig = prevState.topBarConfig.copy(items = dropdownMenuItems), cardFrozenState = converter.convert(cardFrozenState), + balanceBlockState = balanceBlockState, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt index 5f74c8d01a..4ba4c3e8f1 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt @@ -46,7 +46,6 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( .distinctUntilChanged() .onEach { data -> val userWalletId = userWallet.walletId - Timber.tag("scan===").e("onEach $userWalletId $data") val mainInfoData = data[userWalletId] ?: return@onEach mainInfoData.onLeft { tangemPayError -> when (tangemPayError) { From 1ccd4f3b6c941a63ee10a5c624d695bbfbcbc788 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 4 Dec 2025 11:15:40 +0300 Subject: [PATCH 06/13] Updated on 2026-08-14 --- .../utils/list/ChangedCurrenciesManager.kt | 5 +++++ .../utils/list/ManageTokensListManager.kt | 4 ++++ .../utils/mapper/CurrencyNetworksMapper.kt | 14 +++++++++++--- .../utils/ui/CurrencyItemOperations.kt | 3 +++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ChangedCurrenciesManager.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ChangedCurrenciesManager.kt index 0e54d8528d..44529b9688 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ChangedCurrenciesManager.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ChangedCurrenciesManager.kt @@ -7,6 +7,11 @@ import kotlinx.coroutines.flow.update internal typealias ChangedCurrencies = Map> +internal data class CurrencyUpdates( + val toAdd: ChangedCurrencies = emptyMap(), + val toRemove: ChangedCurrencies = emptyMap(), +) + internal class ChangedCurrenciesManager { val currenciesToAdd: MutableStateFlow = MutableStateFlow(emptyMap()) diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt index 59bf275e11..d0221350ce 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt @@ -329,6 +329,10 @@ internal class ManageTokensListManager @AssistedInject constructor( val updatedUiItem = uiBatch.data[currencyIndex].toggleExpanded( currency = currencyBatch.data[currencyIndex], isEditable = batches.canEditItems, + updates = CurrencyUpdates( + toAdd = currenciesToAdd.value, + toRemove = currenciesToRemove.value, + ), onSelectCurrencyNetwork = { networkId, isSelected -> selectNetwork(currencyBatch.key, currency, networkId, isSelected) }, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/mapper/CurrencyNetworksMapper.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/mapper/CurrencyNetworksMapper.kt index 58cea15030..c92243274e 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/mapper/CurrencyNetworksMapper.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/mapper/CurrencyNetworksMapper.kt @@ -5,20 +5,28 @@ import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork import com.tangem.domain.models.network.Network import com.tangem.features.managetokens.entity.item.CurrencyItemUM.Basic.NetworksUM import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM +import com.tangem.features.managetokens.utils.list.CurrencyUpdates import com.tangem.features.managetokens.utils.ui.getIconRes import kotlinx.collections.immutable.toImmutableList internal fun ManagedCryptoCurrency.Token.toUiNetworksModel( isExpanded: Boolean, isItemsEditable: Boolean, + updates: CurrencyUpdates, onSelectedStateChange: (SourceNetwork, Boolean) -> Unit, onLongTap: (SourceNetwork) -> Unit, ): NetworksUM { return if (isExpanded) { NetworksUM.Expanded( - networks = availableNetworks.map { - it.toCurrencyNetworkModel( - isSelected = it.network in addedIn, + networks = availableNetworks.map { sourceNetwork -> + val isSelectedByDefault = sourceNetwork.network in addedIn + val isSelected = when (sourceNetwork.network) { + in updates.toAdd[this].orEmpty() -> true + in updates.toRemove[this].orEmpty() -> false + else -> isSelectedByDefault + } + sourceNetwork.toCurrencyNetworkModel( + isSelected = isSelected, isEditable = isItemsEditable, onSelectedStateChange = onSelectedStateChange, onLongTap = onLongTap, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/ui/CurrencyItemOperations.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/ui/CurrencyItemOperations.kt index d92b7108d0..fd675f17cd 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/ui/CurrencyItemOperations.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/ui/CurrencyItemOperations.kt @@ -4,12 +4,14 @@ import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork import com.tangem.features.managetokens.entity.item.CurrencyItemUM import com.tangem.features.managetokens.entity.item.CurrencyItemUM.Basic.NetworksUM +import com.tangem.features.managetokens.utils.list.CurrencyUpdates import com.tangem.features.managetokens.utils.mapper.toUiNetworksModel import kotlinx.collections.immutable.toImmutableList internal fun CurrencyItemUM.toggleExpanded( currency: ManagedCryptoCurrency, isEditable: Boolean, + updates: CurrencyUpdates, onSelectCurrencyNetwork: (SourceNetwork, Boolean) -> Unit, onLongTap: (SourceNetwork) -> Unit, ): CurrencyItemUM { @@ -30,6 +32,7 @@ internal fun CurrencyItemUM.toggleExpanded( networks = currency.toUiNetworksModel( isExpanded = isExpanded, isItemsEditable = isEditable, + updates = updates, onSelectedStateChange = onSelectCurrencyNetwork, onLongTap = onLongTap, ), From b3ed607c1aa51f19d8a9efbffe30c29aaf1d8793 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 18:39:36 +0300 Subject: [PATCH 07/13] Updated on 2026-08-14 --- .../tangem/tap/common/extensions/String.kt | 6 ------ .../visa/TangemPaySignWithdrawalHashTask.kt | 21 +------------------ .../com/tangem/utils/extensions/StringExt.kt | 4 ++++ .../DefaultTangemPaySwapRepository.kt | 3 ++- 4 files changed, 7 insertions(+), 27 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/extensions/String.kt diff --git a/app/src/main/java/com/tangem/tap/common/extensions/String.kt b/app/src/main/java/com/tangem/tap/common/extensions/String.kt deleted file mode 100644 index 0396cf84fc..0000000000 --- a/app/src/main/java/com/tangem/tap/common/extensions/String.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.tap.common.extensions - -fun String.removePrefixOrNull(prefix: String): String? = when { - startsWith(prefix) -> substring(prefix.length) - else -> null -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPaySignWithdrawalHashTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPaySignWithdrawalHashTask.kt index faf32983a0..d5bc3b64c1 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPaySignWithdrawalHashTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPaySignWithdrawalHashTask.kt @@ -15,7 +15,6 @@ import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey import com.tangem.domain.card.common.visa.VisaUtilities import com.tangem.domain.visa.error.VisaActivationError -import com.tangem.operations.ScanTask import com.tangem.operations.derivation.DeriveWalletPublicKeyTask import com.tangem.operations.sign.SignHashCommand @@ -92,25 +91,7 @@ class TangemPaySignWithdrawalHashTask( ?: targetWalletPublicKey.toDecompressedPublicKey(), ).asRSVLegacyEVM().toHexString().lowercase() - scanCard( - session = session, - callback = callback, - signedData = rsvSignature, - ) - } - is CompletionResult.Failure -> { - callback(CompletionResult.Failure(result.error)) - } - } - } - } - - private fun scanCard(signedData: String, session: CardSession, callback: CompletionCallback) { - val scanTask = ScanTask() - scanTask.run(session) { result -> - when (result) { - is CompletionResult.Success -> { - callback(CompletionResult.Success(signedData)) + callback(CompletionResult.Success(rsvSignature)) } is CompletionResult.Failure -> { callback(CompletionResult.Failure(result.error)) diff --git a/core/utils/src/main/java/com/tangem/utils/extensions/StringExt.kt b/core/utils/src/main/java/com/tangem/utils/extensions/StringExt.kt index bba0975985..fd6c6e5846 100644 --- a/core/utils/src/main/java/com/tangem/utils/extensions/StringExt.kt +++ b/core/utils/src/main/java/com/tangem/utils/extensions/StringExt.kt @@ -9,4 +9,8 @@ fun String.uriValidate(): Boolean { val regex = DEEPLINK_VALIDATION_REGEX.toRegex() return !regex.containsMatchIn(this) +} + +fun String.addHexPrefix(): String { + return if (this.startsWith("0x")) this else "0x$this" } \ No newline at end of file diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPaySwapRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPaySwapRepository.kt index d1d72250d3..042686b6e7 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPaySwapRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPaySwapRepository.kt @@ -18,6 +18,7 @@ import com.tangem.domain.pay.repository.TangemPaySwapRepository import com.tangem.domain.visa.error.VisaApiError import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.features.hotwallet.HotWalletFeatureToggles +import com.tangem.utils.extensions.addHexPrefix import java.math.BigDecimal import java.math.RoundingMode import java.util.Currency @@ -66,7 +67,7 @@ internal class DefaultTangemPaySwapRepository @Inject constructor( recipientAddress = receiverAddress, adminSalt = result.salt, senderAddress = result.senderAddress, - adminSignature = signatureResult.signature, + adminSignature = signatureResult.signature.addHexPrefix(), ) tangemPayApi.withdraw(authHeader = authHeader, body = request) } From b9a2ab5fed01af4e66dc86245ca62155ebe3c6ce Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 19:26:33 +0300 Subject: [PATCH 08/13] Updated on 2026-08-14 --- .../tangem/tap/routing/utils/ChildFactory.kt | 9 ++++-- .../com/tangem/common/routing/AppRoute.kt | 5 ++- .../data/pay/util/TangemPayWalletsManager.kt | 3 +- .../tangempay/onboarding/api/build.gradle.kts | 3 ++ .../TangemPayOnboardingComponent.kt | 9 +++++- .../onboarding/impl/build.gradle.kts | 1 + .../DefaultOnboardVisaDeepLinkHandler.kt | 12 +++++-- .../model/TangemPayOnboardingModel.kt | 31 +++++++++++++++++-- .../router/DefaultWalletRouter.kt | 10 ++++-- .../presentation/router/InnerWalletRouter.kt | 2 +- .../subscribers/TangemPayMainSubscriber.kt | 2 +- 11 files changed, 71 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 57dc3d376e..a3a9cf4047 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -660,8 +660,13 @@ internal class ChildFactory @Inject constructor( createComponentChild( context = context, params = when (val mode = route.mode) { - is AppRoute.TangemPayOnboarding.Mode.ContinueOnboarding -> ContinueOnboarding - is AppRoute.TangemPayOnboarding.Mode.Deeplink -> Deeplink(deeplink = mode.deeplink) + is AppRoute.TangemPayOnboarding.Mode.ContinueOnboarding -> ContinueOnboarding( + userWalletId = mode.userWalletId, + ) + is AppRoute.TangemPayOnboarding.Mode.Deeplink -> Deeplink( + deeplink = mode.deeplink, + userWalletId = mode.userWalletId, + ) }, componentFactory = tangemPayOnboardingComponentFactory, ) diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index f1c07144f6..4e22012973 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -431,10 +431,13 @@ sealed class AppRoute(val path: String) : Route { @Serializable data class Deeplink( val deeplink: String, + val userWalletId: UserWalletId?, ) : Mode() @Serializable - object ContinueOnboarding : Mode() + data class ContinueOnboarding( + val userWalletId: UserWalletId?, + ) : Mode() } } diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayWalletsManager.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayWalletsManager.kt index 054e839ebb..4423dddf32 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayWalletsManager.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/util/TangemPayWalletsManager.kt @@ -33,7 +33,6 @@ class TangemPayWalletsManager @Inject constructor( private fun findColdWallet(userWallets: List?): UserWallet.Cold { return userWallets?.find { it is UserWallet.Cold && it.isMultiCurrency - } as? UserWallet.Cold - ?: error("Cannot find cold user wallet") + } as? UserWallet.Cold ?: error("Cannot find cold user wallet") } } \ No newline at end of file diff --git a/features/tangempay/onboarding/api/build.gradle.kts b/features/tangempay/onboarding/api/build.gradle.kts index a52e5bbccd..5d9c35cc08 100644 --- a/features/tangempay/onboarding/api/build.gradle.kts +++ b/features/tangempay/onboarding/api/build.gradle.kts @@ -13,6 +13,9 @@ dependencies { implementation(projects.core.decompose) implementation(projects.core.ui) + /** Domain */ + implementation(projects.domain.models) + /** Compose */ implementation(deps.compose.runtime) } \ No newline at end of file diff --git a/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayOnboardingComponent.kt b/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayOnboardingComponent.kt index 0ad307aa79..408d809672 100644 --- a/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayOnboardingComponent.kt +++ b/features/tangempay/onboarding/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayOnboardingComponent.kt @@ -2,15 +2,22 @@ package com.tangem.features.tangempay.components import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.models.wallet.UserWalletId interface TangemPayOnboardingComponent : ComposableContentComponent { sealed class Params { + + abstract val userWalletId: UserWalletId? + data class Deeplink( val deeplink: String, + override val userWalletId: UserWalletId?, ) : Params() - object ContinueOnboarding : Params() + data class ContinueOnboarding( + override val userWalletId: UserWalletId?, + ) : Params() } interface Factory : ComponentFactory diff --git a/features/tangempay/onboarding/impl/build.gradle.kts b/features/tangempay/onboarding/impl/build.gradle.kts index 0d109bd508..7b71ee3d94 100644 --- a/features/tangempay/onboarding/impl/build.gradle.kts +++ b/features/tangempay/onboarding/impl/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { /** Domain */ implementation(projects.domain.visa) + implementation(projects.domain.wallets) /** Data **/ implementation(projects.data.visa) diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/deeplink/DefaultOnboardVisaDeepLinkHandler.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/deeplink/DefaultOnboardVisaDeepLinkHandler.kt index 15313ee912..cb6bf2f491 100644 --- a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/deeplink/DefaultOnboardVisaDeepLinkHandler.kt +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/deeplink/DefaultOnboardVisaDeepLinkHandler.kt @@ -1,10 +1,11 @@ package com.tangem.features.tangempay.deeplink import android.net.Uri -import dagger.assisted.Assisted import com.tangem.common.routing.AppRoute -import com.tangem.features.tangempay.TangemPayFeatureToggles import com.tangem.common.routing.AppRouter +import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase +import com.tangem.features.tangempay.TangemPayFeatureToggles +import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -12,11 +13,16 @@ internal class DefaultOnboardVisaDeepLinkHandler @AssistedInject constructor( @Assisted uri: Uri, appRouter: AppRouter, tangemPayFeatureToggles: TangemPayFeatureToggles, + getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, ) : OnboardVisaDeepLinkHandler { init { if (tangemPayFeatureToggles.isTangemPayEnabled) { - val mode = AppRoute.TangemPayOnboarding.Mode.Deeplink(uri.toString()) + val userWallet = getSelectedWalletSyncUseCase.invoke().getOrNull() + val mode = AppRoute.TangemPayOnboarding.Mode.Deeplink( + deeplink = uri.toString(), + userWalletId = userWallet?.walletId, + ) appRouter.push(AppRoute.TangemPayOnboarding(mode)) } else { appRouter.push(AppRoute.Home()) diff --git a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayOnboardingModel.kt b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayOnboardingModel.kt index de4d3018a3..246b7a1ce7 100644 --- a/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayOnboardingModel.kt +++ b/features/tangempay/onboarding/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayOnboardingModel.kt @@ -9,9 +9,13 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.navigation.url.UrlOpener import com.tangem.data.pay.util.TangemPayWalletsManager +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.models.wallet.isMultiCurrency import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase import com.tangem.domain.tangempay.TangemPayAnalyticsEvents +import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.features.tangempay.TangemPayConstants import com.tangem.features.tangempay.components.TangemPayOnboardingComponent import com.tangem.features.tangempay.model.transformers.TangemPayOnboardingButtonLoadingTransformer @@ -37,6 +41,8 @@ internal class TangemPayOnboardingModel @Inject constructor( private val produceInitialDataUseCase: ProduceTangemPayInitialDataUseCase, private val urlOpener: UrlOpener, private val tangemPayWalletsManager: TangemPayWalletsManager, + private val getUserWalletUseCase: GetUserWalletUseCase, + private val getSelectedWalletUseCase: GetSelectedWalletUseCase, ) : Model() { private val params = paramsContainer.require() @@ -74,8 +80,9 @@ internal class TangemPayOnboardingModel @Inject constructor( private suspend fun checkCustomerInfo() { // TODO implement selector + val userWalletId = getUserWalletForPay(params.userWalletId) repository.getCustomerInfo( - userWalletId = tangemPayWalletsManager.getDefaultWalletForTangemPayBlocking().walletId, + userWalletId = userWalletId, ) // selector .onRight { customerInfo -> @@ -92,6 +99,24 @@ internal class TangemPayOnboardingModel @Inject constructor( .onLeft { back() } } + private fun getUserWalletForPay(userWalletId: UserWalletId?): UserWalletId { + val userWallet = userWalletId?.let { getUserWalletUseCase(it).getOrNull() } + return if (userWallet?.isMultiCurrency == true) { + userWallet.walletId + } else { + tryGetSelectedWalletId() + } + } + + private fun tryGetSelectedWalletId(): UserWalletId { + val selectedWallet = getSelectedWalletUseCase.sync().getOrNull() + return if (selectedWallet?.isMultiCurrency == true) { + selectedWallet.walletId + } else { + tangemPayWalletsManager.getDefaultWalletForTangemPayBlocking().walletId + } + } + private fun onTermsClick() { analytics.send(TangemPayAnalyticsEvents.ViewTermsClicked) urlOpener.openUrl(TangemPayConstants.TERMS_AND_LIMITS_LINK) @@ -102,7 +127,7 @@ internal class TangemPayOnboardingModel @Inject constructor( uiState.transformerUpdate(TangemPayOnboardingButtonLoadingTransformer(isLoading = true)) modelScope.launch { // TODO implement selector - val userWalletId = tangemPayWalletsManager.getDefaultWalletForTangemPayBlocking().walletId + val userWalletId = getUserWalletForPay(params.userWalletId) val result = produceInitialDataUseCase(userWalletId) if (result.isLeft()) { Timber.e("Error producing initial data: ${result.leftOrNull()?.message}") @@ -134,7 +159,7 @@ internal class TangemPayOnboardingModel @Inject constructor( router.replaceAll( AppRoute.Wallet, AppRoute.Kyc( - userWalletId = tangemPayWalletsManager.getDefaultWalletForTangemPayBlocking().walletId, + userWalletId = getUserWalletForPay(params.userWalletId), ), ) } 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 5d2fbf72f2..98d68adf5f 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 @@ -111,8 +111,14 @@ internal class DefaultWalletRouter @Inject constructor( ) } - override fun openTangemPayOnboarding() { - router.push(AppRoute.TangemPayOnboarding(AppRoute.TangemPayOnboarding.Mode.ContinueOnboarding)) + override fun openTangemPayOnboarding(userWalletId: UserWalletId) { + router.push( + AppRoute.TangemPayOnboarding( + AppRoute.TangemPayOnboarding.Mode.ContinueOnboarding( + userWalletId = userWalletId, + ), + ), + ) } override fun openTangemPayDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig) { 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 a71880095a..cf9d3ea617 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 @@ -63,7 +63,7 @@ internal interface InnerWalletRouter { fun openTokenReceiveBottomSheet(tokenReceiveConfig: TokenReceiveConfig) - fun openTangemPayOnboarding() + fun openTangemPayOnboarding(userWalletId: UserWalletId) fun openTangemPayDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt index 4ba4c3e8f1..44174f221d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt @@ -86,7 +86,7 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( userWalletId = userWalletId, value = data, cardFrozenState = cardFrozenState, - onClickKyc = innerWalletRouter::openTangemPayOnboarding, + onClickKyc = { innerWalletRouter.openTangemPayOnboarding(userWalletId) }, onIssuingCard = clickIntents::onIssuingCardClicked, onIssuingFailed = clickIntents::onIssuingFailedClicked, openDetails = { config -> From 5c93d3973a3a387cad13d6db2d60ba59d785ece3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 21:28:30 +0500 Subject: [PATCH 09/13] Updated on 2026-08-14 --- .../tangem/domain/pay/model/CustomerInfo.kt | 5 ++ .../TangemPayMainScreenCustomerInfoUseCase.kt | 78 +++++++++++-------- .../wallet/model/TangemPayMainInfoManager.kt | 29 ------- .../wallet/child/wallet/model/WalletModel.kt | 9 ++- .../model/intents/TangemPayClickIntents.kt | 8 +- .../wallet/state/model/TangemPayState.kt | 2 + .../TangemPayLoadingStateTransformer.kt | 15 ++++ .../subscribers/TangemPayMainSubscriber.kt | 35 +++++---- .../presentation/wallet/ui/WalletScreen.kt | 4 +- .../visa/TangemPayLoadingScreenBlock.kt | 37 +++++++++ .../visa/TangemPayMainScreenBlock.kt | 3 + 11 files changed, 139 insertions(+), 86 deletions(-) delete mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/TangemPayMainInfoManager.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayLoadingStateTransformer.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayLoadingScreenBlock.kt diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/CustomerInfo.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/CustomerInfo.kt index 7f1092646f..ad9583243f 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/CustomerInfo.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/model/CustomerInfo.kt @@ -3,6 +3,11 @@ package com.tangem.domain.pay.model import com.tangem.domain.visa.model.TangemPayCardFrozenState import java.math.BigDecimal +sealed class MainCustomerInfoContentState { + object Loading : MainCustomerInfoContentState() + data class Content(val info: MainScreenCustomerInfo) : MainCustomerInfoContentState() +} + data class MainScreenCustomerInfo( val info: CustomerInfo, val orderStatus: OrderStatus, diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt index 313aa94bb3..07950a5cec 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt @@ -2,16 +2,13 @@ package com.tangem.domain.pay.usecase import arrow.core.Either import arrow.core.left -import arrow.core.raise.catch import arrow.core.right import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.pay.model.CustomerInfo -import com.tangem.domain.pay.model.MainScreenCustomerInfo -import com.tangem.domain.pay.model.OrderStatus -import com.tangem.domain.pay.model.TangemPayCustomerInfoError +import com.tangem.domain.pay.model.* import com.tangem.domain.pay.repository.CustomerOrderRepository import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.visa.error.VisaApiError +import kotlinx.coroutines.flow.* import timber.log.Timber private const val TAG = "TangemPayMainScreenCustomerInfoUseCase" @@ -26,32 +23,50 @@ class TangemPayMainScreenCustomerInfoUseCase( private val tangemPayOnboardingRepository: OnboardingRepository, ) { - suspend operator fun invoke( - userWalletId: UserWalletId, - ): Either = catch( - block = { - Timber.tag(TAG).d("checkCustomerWallet") - repository.checkCustomerWallet(userWalletId) - .fold( - ifLeft = { error -> - Timber.tag(TAG).e("Failed to check customer wallet ${error.javaClass.simpleName}") - TangemPayCustomerInfoError.UnknownError.left() - }, - ifRight = { hasTangemPay -> - Timber.tag(TAG).i("checkCustomerWallet $hasTangemPay") - if (hasTangemPay) { - proceedWithPaeraCustomerResult(userWalletId) - } else { - TangemPayCustomerInfoError.UnknownError.left() // ignore if there's no TangemPay + val state: StateFlow>> + field = MutableStateFlow(value = mapOf()) + + suspend fun fetch(userWalletId: UserWalletId) { + Timber.tag(TAG).i("fetch: $userWalletId") + repository.checkCustomerWallet(userWalletId) + .fold( + ifLeft = { error -> + Timber.tag(TAG).e("Failed checkCustomerWallet for $userWalletId: ${error.javaClass.simpleName}") + updateState(userWalletId, TangemPayCustomerInfoError.UnknownError.left()) + }, + ifRight = { hasTangemPay -> + Timber.tag(TAG).i("checkCustomerWallet for $userWalletId: $hasTangemPay") + if (hasTangemPay) { + val oldResult = state.value[userWalletId] + if (oldResult == null) { + updateState(userWalletId, MainCustomerInfoContentState.Loading.right()) } - }, - ) - }, - catch = { error -> - Timber.tag(TAG).e(error) - TangemPayCustomerInfoError.UnknownError.left() - }, - ) + + val result = proceedWithPaeraCustomerResult(userWalletId) + .map(MainCustomerInfoContentState::Content) + updateState(userWalletId, result) + } else { + // ignore if there's no TangemPay + updateState(userWalletId, TangemPayCustomerInfoError.UnknownError.left()) + } + }, + ) + } + + operator fun invoke( + userWalletId: UserWalletId, + ): Flow> { + return state.mapNotNull { map -> map[userWalletId] } + } + + private fun updateState( + userWalletId: UserWalletId, + either: Either, + ) { + state.update { currentMap -> + currentMap.toMutableMap().apply { this[userWalletId] = either } + } + } private suspend fun proceedWithPaeraCustomerResult( userWalletId: UserWalletId, @@ -70,14 +85,13 @@ class TangemPayMainScreenCustomerInfoUseCase( private suspend fun proceedWithoutOrder( userWalletId: UserWalletId, ): Either { - Timber.tag(TAG).d("proceedWithoutOrder") return repository.getCustomerInfo(userWalletId) .mapLeft { error -> Timber.tag(TAG).e("mapErrorForCustomer: $error") error.mapErrorForCustomer() } .map { customerInfo -> - Timber.tag(TAG).d("customerInfo") + Timber.tag(TAG).i("customerInfo") if (customerInfo.cardInfo == null && customerInfo.isKycApproved) { // If order id wasn't saved -> start order creation and get customer info repository.createOrder(userWalletId) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/TangemPayMainInfoManager.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/TangemPayMainInfoManager.kt deleted file mode 100644 index ee1c60aee1..0000000000 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/TangemPayMainInfoManager.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.tangem.feature.wallet.child.wallet.model - -import arrow.core.Either -import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.pay.model.MainScreenCustomerInfo -import com.tangem.domain.pay.model.TangemPayCustomerInfoError -import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -internal class TangemPayMainInfoManager @Inject constructor( - private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase, -) { - - val mainScreenCustomerInfo: - StateFlow>> - field = MutableStateFlow(mapOf()) - - suspend fun refreshTangemPayInfo(userWalletId: UserWalletId) { - mainScreenCustomerInfo.update { currentMap -> - val info = tangemPayMainScreenCustomerInfoUseCase(userWalletId) - currentMap.toMutableMap().apply { this[userWalletId] = info } - } - } -} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 12f7478a3e..87e381b581 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -20,6 +20,7 @@ import com.tangem.domain.nft.ObserveAndClearNFTCacheIfNeedUseCase import com.tangem.domain.notifications.GetIsHuaweiDeviceWithoutGoogleServicesUseCase import com.tangem.domain.notifications.repository.NotificationsRepository import com.tangem.domain.pay.repository.OnboardingRepository +import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase import com.tangem.domain.settings.* import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase import com.tangem.domain.wallets.usecase.* @@ -94,7 +95,7 @@ internal class WalletModel @Inject constructor( private val tangemPayOnboardingRepository: OnboardingRepository, private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles, private val accountsFeatureToggles: AccountsFeatureToggles, - private val tangemPayMainInfoManager: TangemPayMainInfoManager, + private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase, val screenLifecycleProvider: ScreenLifecycleProvider, val innerWalletRouter: InnerWalletRouter, ) : Model() { @@ -371,15 +372,15 @@ internal class WalletModel @Inject constructor( if (isShouldLaunchPeriodicUpdate) { updateTangemPayJobHolder.cancel() modelScope.launch { - tangemPayMainInfoManager.refreshTangemPayInfo(userWalletId) + tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) while (isActive) { delay(TANGEM_PAY_UPDATE_INTERVAL) - tangemPayMainInfoManager.refreshTangemPayInfo(userWalletId) + tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) } }.saveIn(updateTangemPayJobHolder) } else { // Don't refresh customer info periodically if the card was already issued, only update on swipe to refresh - tangemPayMainInfoManager.refreshTangemPayInfo(userWalletId) + tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) } }.launchIn(modelScope) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt index 7ccd2dac17..480d649409 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt @@ -13,8 +13,8 @@ import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.requireColdWallet import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase +import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase -import com.tangem.feature.wallet.child.wallet.model.TangemPayMainInfoManager import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.features.tangempay.TangemPayFeatureToggles import kotlinx.coroutines.launch @@ -43,7 +43,7 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( private val getWalletMetainfoUseCase: GetWalletMetaInfoUseCase, private val getUserWalletUseCase: GetUserWalletUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, - private val tangemPayInfoManager: TangemPayMainInfoManager, + private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase, private val uiMessageSender: UiMessageSender, ) : BaseWalletClickIntents(), TangemPayIntents { @@ -54,13 +54,13 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( ) { return } - tangemPayInfoManager.refreshTangemPayInfo(userWalletId) + tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) } override fun onRefreshPayToken(userWalletId: UserWalletId) { modelScope.launch { produceInitialDataTangemPay.invoke(userWalletId) - tangemPayInfoManager.refreshTangemPayInfo(userWalletId) + tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/TangemPayState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/TangemPayState.kt index 71ad45e71a..bbe8472d49 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/TangemPayState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/TangemPayState.kt @@ -9,6 +9,8 @@ internal sealed class TangemPayState { object Empty : TangemPayState() + data object Loading : TangemPayState() + data class Progress( val title: TextReference, val description: TextReference, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayLoadingStateTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayLoadingStateTransformer.kt new file mode 100644 index 0000000000..f731cb119d --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayLoadingStateTransformer.kt @@ -0,0 +1,15 @@ +package com.tangem.feature.wallet.presentation.wallet.state.transformers + +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState + +internal class TangemPayLoadingStateTransformer(userWalletId: UserWalletId) : WalletStateTransformer(userWalletId) { + override fun transform(prevState: WalletState): WalletState { + return if (prevState is WalletState.MultiCurrency.Content) { + prevState.copy(tangemPayState = TangemPayState.Loading) + } else { + prevState + } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt index 44174f221d..6f182566d8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt @@ -2,26 +2,23 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.pay.model.MainCustomerInfoContentState import com.tangem.domain.pay.model.MainScreenCustomerInfo import com.tangem.domain.pay.model.TangemPayCustomerInfoError import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository +import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase import com.tangem.domain.visa.model.TangemPayCardFrozenState -import com.tangem.feature.wallet.child.wallet.model.TangemPayMainInfoManager import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.router.InnerWalletRouter import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletTangemPayAnalyticsEventSender import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController -import com.tangem.feature.wallet.presentation.wallet.state.transformers.TangemPayHiddenStateTransformer -import com.tangem.feature.wallet.presentation.wallet.state.transformers.TangemPayRefreshNeededStateTransformer -import com.tangem.feature.wallet.presentation.wallet.state.transformers.TangemPayUnavailableStateTransformer -import com.tangem.feature.wallet.presentation.wallet.state.transformers.TangemPayUpdateInfoStateTransformer +import com.tangem.feature.wallet.presentation.wallet.state.transformers.* import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.onEach import timber.log.Timber @@ -32,7 +29,7 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( private val clickIntents: WalletClickIntents, private val innerWalletRouter: InnerWalletRouter, private val cardDetailsRepository: TangemPayCardDetailsRepository, - private val tangemPayMainInfoManager: TangemPayMainInfoManager, + private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase, private val analytics: WalletTangemPayAnalyticsEventSender, ) : WalletSubscriber() { @@ -41,12 +38,10 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( } private fun subscribeOnTangemPayInfoUpdates(): Flow<*> { - return tangemPayMainInfoManager.mainScreenCustomerInfo - .filter { it.isNotEmpty() } + return tangemPayMainScreenCustomerInfoUseCase(userWalletId = userWallet.walletId) .distinctUntilChanged() - .onEach { data -> + .onEach { mainInfoData -> val userWalletId = userWallet.walletId - val mainInfoData = data[userWalletId] ?: return@onEach mainInfoData.onLeft { tangemPayError -> when (tangemPayError) { TangemPayCustomerInfoError.RefreshNeededError -> { @@ -70,13 +65,23 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( ) } } - }.onRight { customerInfo -> - updateTangemPay(customerInfo, userWalletId) - analytics.send(customerInfo = customerInfo) - } + }.onRight { contentState -> handleContentState(state = contentState) } } } + private suspend fun handleContentState(state: MainCustomerInfoContentState) { + val userWalletId = userWallet.walletId + when (state) { + MainCustomerInfoContentState.Loading -> stateController.update( + transformer = TangemPayLoadingStateTransformer(userWalletId), + ) + is MainCustomerInfoContentState.Content -> { + updateTangemPay(data = state.info, userWalletId = userWalletId) + analytics.send(customerInfo = state.info) + } + } + } + private suspend fun updateTangemPay(data: MainScreenCustomerInfo, userWalletId: UserWalletId) { val cardFrozenState = data.info.productInstance?.cardId?.let { cardDetailsRepository.cardFrozenStateSync(it) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index 3a0f5202b9..16212dc865 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -224,9 +224,9 @@ private fun WalletContent( contentType = selectedWallet.tangemPayState::class.java, ) { TangemPayMainScreenBlock( - selectedWallet.tangemPayState, + state = selectedWallet.tangemPayState, isBalanceHidden = state.isHidingMode, - itemModifier, + modifier = itemModifier, ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayLoadingScreenBlock.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayLoadingScreenBlock.kt new file mode 100644 index 0000000000..a2dbe13375 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayLoadingScreenBlock.kt @@ -0,0 +1,37 @@ +package com.tangem.feature.wallet.presentation.wallet.ui.components.visa + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.CircleShimmer +import com.tangem.core.ui.components.RectangleShimmer +import com.tangem.core.ui.components.SpacerWMax +import com.tangem.core.ui.res.TangemTheme + +@Composable +internal fun TangemPayLoadingScreenBlock(modifier: Modifier = Modifier) { + Row( + modifier = modifier + .fillMaxWidth() + .background(color = TangemTheme.colors.background.primary, shape = TangemTheme.shapes.roundedCornersXMedium) + .padding(horizontal = 12.dp, vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + CircleShimmer(modifier = Modifier.size(36.dp)) + Column( + modifier = Modifier.padding(start = 12.dp), + verticalArrangement = Arrangement.spacedBy(2.dp), + ) { + RectangleShimmer(modifier = Modifier.padding(vertical = 4.dp).sizeIn(minWidth = 70.dp, minHeight = 12.dp)) + RectangleShimmer(modifier = Modifier.padding(vertical = 2.dp).sizeIn(minWidth = 52.dp, minHeight = 12.dp)) + } + SpacerWMax() + Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { + RectangleShimmer(modifier = Modifier.padding(vertical = 4.dp).sizeIn(minWidth = 40.dp, minHeight = 12.dp)) + RectangleShimmer(modifier = Modifier.padding(vertical = 2.dp).sizeIn(minWidth = 40.dp, minHeight = 12.dp)) + } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayMainScreenBlock.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayMainScreenBlock.kt index d2750a8903..24f11c043c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayMainScreenBlock.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayMainScreenBlock.kt @@ -23,6 +23,7 @@ internal fun TangemPayMainScreenBlock(state: TangemPayState, isBalanceHidden: Bo is TangemPayState.RefreshNeeded -> TangemPayRefreshBlock(state, modifier) is TangemPayState.TemporaryUnavailable -> TangemPayUnavailableBlock(state, modifier) is TangemPayState.FailedIssue -> TangemPayFailedIssueState(state, modifier) + TangemPayState.Loading -> TangemPayLoadingScreenBlock(modifier) } } @@ -32,6 +33,8 @@ internal fun TangemPayMainScreenBlock(state: TangemPayState, isBalanceHidden: Bo private fun TangemPayMainScreenBlockPreview() { TangemThemePreview { Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) { + TangemPayMainScreenBlock(state = TangemPayState.Loading, isBalanceHidden = false) + TangemPayMainScreenBlock( Progress( title = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_title), From 1e2ea28ff95e8fc295dba53809fbacecdd92dfc9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 8 Dec 2025 22:25:17 +0500 Subject: [PATCH 10/13] Updated on 2026-08-14 --- .../DefaultTangemPayTxHistoryRepository.kt | 13 ++++--- .../components/TangemPayDetailsComponent.kt | 1 + .../TangemPayTxHistoryDetailsComponent.kt | 7 +++- .../entity/TangemPayDetailsNavigation.kt | 5 ++- .../entity/TangemPayTxHistoryDetailsUM.kt | 1 + .../tangempay/model/TangemPayDetailsModel.kt | 7 +++- .../model/TangemPayTxHistoryDetailsModel.kt | 38 ++++++++++++++----- .../TangemPayTxHistoryDetailsConverter.kt | 2 + .../tangempay/ui/TangempayTxDetailsUi.kt | 8 +++- 9 files changed, 61 insertions(+), 21 deletions(-) diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayTxHistoryRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayTxHistoryRepository.kt index 243e008c99..021605d89a 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayTxHistoryRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayTxHistoryRepository.kt @@ -21,7 +21,6 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider import javax.inject.Inject private const val INITIAL_CURSOR = "initial_cursor_key" -private const val TAG = "TangemPay: TangemPayTxHistoryRepository:" internal class DefaultTangemPayTxHistoryRepository @Inject constructor( private val requestPerformer: TangemPayRequestPerformer, @@ -106,12 +105,14 @@ internal class DefaultTangemPayTxHistoryRepository @Inject constructor( cursor: String?, pageSize: Int, ) { - requestPerformer.runWithErrorLogs(TAG) { - val result = requestPerformer.request(userWalletId) { authHeader -> - visaApi.getTangemPayTxHistory(authHeader = authHeader, limit = pageSize, cursor = cursor) - }.result + requestPerformer.performRequest(userWalletId = userWalletId) { authHeader -> + visaApi.getTangemPayTxHistory(authHeader = authHeader, limit = pageSize, cursor = cursor) + }.onLeft { + error(it.toString()) + }.onRight { response -> + val result = response.result val items = txHistoryItemConverter.convertList(result.transactions).filterNotNull() txHistoryItemsStore.store(key = customerWalletAddress, cursor = cursor ?: INITIAL_CURSOR, value = items) - }.onLeft { error(it.toString()) } + } } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt index 38d29ced5d..44a23b3ed8 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt @@ -84,6 +84,7 @@ internal class TangemPayDetailsComponent( appComponentContext = context, params = TangemPayTxHistoryDetailsComponent.Params( transaction = navigation.transaction, + isBalanceHidden = navigation.isBalanceHidden, userWalletId = params.userWalletId, onDismiss = model.bottomSheetNavigation::dismiss, ), diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/txHistory/TangemPayTxHistoryDetailsComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/txHistory/TangemPayTxHistoryDetailsComponent.kt index 345ca4a497..eeb2b77c8f 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/txHistory/TangemPayTxHistoryDetailsComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/txHistory/TangemPayTxHistoryDetailsComponent.kt @@ -1,10 +1,11 @@ package com.tangem.features.tangempay.components.txHistory import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.model.getOrCreateModel import com.tangem.core.ui.decompose.ComposableBottomSheetComponent -import com.tangem.core.ui.extensions.* import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.visa.model.TangemPayTxHistoryItem import com.tangem.features.tangempay.model.TangemPayTxHistoryDetailsModel @@ -23,11 +24,13 @@ internal class TangemPayTxHistoryDetailsComponent( @Composable override fun BottomSheet() { - TangemPayTxHistoryDetailsContent(state = model.uiState) + val state by model.uiState.collectAsStateWithLifecycle() + TangemPayTxHistoryDetailsContent(state = state) } data class Params( val transaction: TangemPayTxHistoryItem, + val isBalanceHidden: Boolean, val userWalletId: UserWalletId, val onDismiss: () -> Unit, ) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsNavigation.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsNavigation.kt index 9e4c9f8854..86009f09f0 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsNavigation.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsNavigation.kt @@ -22,5 +22,8 @@ internal sealed class TangemPayDetailsNavigation { ) : TangemPayDetailsNavigation() @Serializable - data class TransactionDetails(val transaction: TangemPayTxHistoryItem) : TangemPayDetailsNavigation() + data class TransactionDetails( + val transaction: TangemPayTxHistoryItem, + val isBalanceHidden: Boolean, + ) : TangemPayDetailsNavigation() } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayTxHistoryDetailsUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayTxHistoryDetailsUM.kt index d6d716c254..4d2aa7c66e 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayTxHistoryDetailsUM.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayTxHistoryDetailsUM.kt @@ -8,6 +8,7 @@ import com.tangem.core.ui.extensions.TextReference import kotlinx.collections.immutable.ImmutableList internal data class TangemPayTxHistoryDetailsUM( + val isBalanceHidden: Boolean, val title: TextReference, val iconState: ImageReference, val transactionTitle: TextReference, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt index c75973bf0f..bfe48f97c9 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt @@ -373,7 +373,12 @@ internal class TangemPayDetailsModel @Inject constructor( } override fun onTransactionClick(item: TangemPayTxHistoryItem) { - bottomSheetNavigation.activate(TangemPayDetailsNavigation.TransactionDetails(item)) + bottomSheetNavigation.activate( + configuration = TangemPayDetailsNavigation.TransactionDetails( + transaction = item, + isBalanceHidden = uiState.value.isBalanceHidden, + ), + ) } override fun onClickTermsAndLimits() { diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayTxHistoryDetailsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayTxHistoryDetailsModel.kt index 48d190991e..02fd1df5b7 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayTxHistoryDetailsModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayTxHistoryDetailsModel.kt @@ -5,6 +5,7 @@ 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.navigation.url.UrlOpener +import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType @@ -14,39 +15,56 @@ import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryDeta import com.tangem.features.tangempay.entity.TangemPayTxHistoryDetailsUM import com.tangem.features.tangempay.model.transformers.TangemPayTxHistoryDetailsConverter import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject @Stable @ModelScoped +@Suppress("LongParameterList") internal class TangemPayTxHistoryDetailsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val getUserWalletsUseCase: GetWalletsUseCase, private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val urlOpener: UrlOpener, + private val balanceHidingSettings: GetBalanceHidingSettingsUseCase, paramsContainer: ParamsContainer, ) : Model() { private val params = paramsContainer.require() - val uiState: TangemPayTxHistoryDetailsUM = TangemPayTxHistoryDetailsConverter.convert( - TangemPayTxHistoryDetailsConverter.Input( - item = params.transaction, - onExplorerClick = ::openExplorer, - onDisputeClick = ::dispute, - onDismiss = ::dismiss, - ), - ) + val uiState: StateFlow + field = MutableStateFlow( + value = TangemPayTxHistoryDetailsConverter.convert( + value = TangemPayTxHistoryDetailsConverter.Input( + item = params.transaction, + isBalanceHidden = params.isBalanceHidden, + onExplorerClick = ::openExplorer, + onDisputeClick = ::dispute, + onDismiss = ::dismiss, + ), + ), + ) + + init { + subscribeToBalanceHiding() + } fun dismiss() { params.onDismiss() } - fun openExplorer(txHash: String?) { + private fun subscribeToBalanceHiding() { + balanceHidingSettings.isBalanceHidden() + .onEach { isBalanceHidden -> uiState.update { it.copy(isBalanceHidden = isBalanceHidden) } } + .launchIn(modelScope) + } + + private fun openExplorer(txHash: String?) { txHash?.let(urlOpener::openUrlExternalBrowser) } - fun dispute() { + private fun dispute() { modelScope.launch { val userWalletId = params.userWalletId val userWallet = getUserWalletsUseCase.invokeSync() diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt index b6e45d0c9a..9bfd3722fc 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayTxHistoryDetailsConverter.kt @@ -29,6 +29,7 @@ internal object TangemPayTxHistoryDetailsConverter : override fun convert(value: Input): TangemPayTxHistoryDetailsUM { val transaction = value.item return TangemPayTxHistoryDetailsUM( + isBalanceHidden = value.isBalanceHidden, title = transaction.extractDate(), iconState = transaction.extractIcon(), transactionTitle = transaction.extractTransactionTitle(), @@ -254,6 +255,7 @@ internal object TangemPayTxHistoryDetailsConverter : data class Input( val item: TangemPayTxHistoryItem, + val isBalanceHidden: Boolean, val onExplorerClick: (String?) -> Unit, val onDisputeClick: () -> Unit, val onDismiss: () -> Unit, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUi.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUi.kt index f9534f5d05..4e280d9cb7 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUi.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUi.kt @@ -77,7 +77,7 @@ internal fun TangemPayTxHistoryDetailsContent(state: TangemPayTxHistoryDetailsUM ) Text( modifier = Modifier.padding(top = 8.dp), - text = state.transactionAmount, + text = state.transactionAmount.orMaskWithStars(state.isBalanceHidden), style = TangemTheme.typography.head, color = state.transactionAmountColor.resolveReference(), ) @@ -158,6 +158,7 @@ private fun TangemPayTxHistoryDetailsContentPreview( private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterProvider( listOf( TangemPayTxHistoryDetailsUM( + isBalanceHidden = true, title = stringReference("12 June • 12:40"), iconState = ImageReference.Res(R.drawable.ic_category_24), transactionTitle = stringReference("Starbucks"), @@ -180,6 +181,7 @@ private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterPr dismiss = {}, ), TangemPayTxHistoryDetailsUM( + isBalanceHidden = true, title = stringReference("12 June • 12:40"), iconState = ImageReference.Res(R.drawable.ic_category_24), transactionTitle = stringReference("Starbucks"), @@ -205,6 +207,7 @@ private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterPr dismiss = {}, ), TangemPayTxHistoryDetailsUM( + isBalanceHidden = false, title = stringReference("12 June • 12:40"), iconState = ImageReference.Res(R.drawable.ic_category_24), transactionTitle = stringReference("Starbucks"), @@ -226,6 +229,7 @@ private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterPr dismiss = {}, ), TangemPayTxHistoryDetailsUM( + isBalanceHidden = false, title = stringReference("12 June • 12:40"), iconState = ImageReference.Res(R.drawable.ic_percent_24), transactionTitle = stringReference("Fee"), @@ -248,6 +252,7 @@ private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterPr dismiss = {}, ), TangemPayTxHistoryDetailsUM( + isBalanceHidden = false, title = stringReference("12 June • 12:40"), iconState = ImageReference.Res(R.drawable.ic_arrow_down_24), transactionTitle = stringReference("Deposit"), @@ -266,6 +271,7 @@ private class TangemPayTxHistoryDetailsUMProvider : CollectionPreviewParameterPr dismiss = {}, ), TangemPayTxHistoryDetailsUM( + isBalanceHidden = false, title = stringReference("12 June • 12:40"), iconState = ImageReference.Res(R.drawable.ic_arrow_up_24), transactionTitle = stringReference("Withdrawal"), From a7a41d752622277a654141c8eb155eafe94214d7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 9 Dec 2025 13:16:12 +0200 Subject: [PATCH 11/13] Updated on 2026-08-14 --- .../ui/tokens/TokenItemStateConverter.kt | 14 ++++++++--- .../intents/WalletContentClickIntents.kt | 25 +++++++++++++------ .../converter/TokenListStateConverter.kt | 14 ++++++++--- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index 9817a2f88a..639e9a9910 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -48,7 +48,7 @@ class TokenItemStateConverter( private val iconStateProvider: (CryptoCurrencyStatus) -> CurrencyIconState = { CryptoCurrencyToIconStateConverter().convert(it) }, - private val onApyLabelClick: ((CryptoCurrencyStatus, String) -> Unit)? = null, + private val onApyLabelClick: ((CryptoCurrencyStatus, ApySource, String) -> Unit)? = null, private val titleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.TitleState = { currencyStatus -> createTitleState( currencyStatus = currencyStatus, @@ -166,7 +166,7 @@ class TokenItemStateConverter( currencyStatus: CryptoCurrencyStatus, yieldModuleApyMap: Map, stakingApyMap: Map>, - onApyLabelClick: ((CryptoCurrencyStatus, String) -> Unit)?, + onApyLabelClick: ((CryptoCurrencyStatus, ApySource, String) -> Unit)?, ): TokenItemState.TitleState { return when (val value = currencyStatus.value) { is CryptoCurrencyStatus.Loading, @@ -192,7 +192,7 @@ class TokenItemStateConverter( earnApy = apyInfo?.text, earnApyIsActive = apyInfo?.isActive == true, onApyLabelClick = if (apyInfo?.apy != null && onApyLabelClick != null) { - { onApyLabelClick.invoke(currencyStatus, apyInfo.apy) } + { onApyLabelClick.invoke(currencyStatus, apyInfo.source, apyInfo.apy) } } else { null }, @@ -224,6 +224,7 @@ class TokenItemStateConverter( ), isActive = isActive, apy = yieldSupplyApy, + source = ApySource.YIELD_SUPPLY, ) } } @@ -249,6 +250,7 @@ class TokenItemStateConverter( ), isActive = stakingInfo.isActive, apy = apyString, + source = ApySource.STAKING, ) } } @@ -430,5 +432,11 @@ class TokenItemStateConverter( val text: TextReference?, val isActive: Boolean, val apy: String?, + val source: ApySource, ) + + enum class ApySource { + STAKING, + YIELD_SUPPLY, + } } \ No newline at end of file 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 8c1278e5b6..b6d7d15a65 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 @@ -2,11 +2,11 @@ package com.tangem.feature.wallet.child.wallet.model.intents import arrow.core.getOrElse import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig +import com.tangem.common.ui.tokens.TokenItemStateConverter.ApySource import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.models.account.Account -import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.staking.YieldBalance import com.tangem.domain.models.wallet.UserWallet @@ -50,7 +50,12 @@ internal interface WalletContentClickIntents { fun onTokenItemLongClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) - fun onApyLabelClick(userWalletId: UserWalletId, currencyStatus: CryptoCurrencyStatus, apy: String) + fun onApyLabelClick( + userWalletId: UserWalletId, + currencyStatus: CryptoCurrencyStatus, + apySource: ApySource, + apy: String, + ) fun onAccountExpandClick(account: Account) @@ -162,11 +167,17 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } } - override fun onApyLabelClick(userWalletId: UserWalletId, currencyStatus: CryptoCurrencyStatus, apy: String) { - val navigationAction = if (currencyStatus.currency is CryptoCurrency.Token) { - NavigationAction.YieldSupply(currencyStatus.value.yieldSupplyStatus?.isActive == true) - } else { - NavigationAction.Staking + override fun onApyLabelClick( + userWalletId: UserWalletId, + currencyStatus: CryptoCurrencyStatus, + apySource: ApySource, + apy: String, + ) { + val navigationAction = when (apySource) { + ApySource.STAKING -> NavigationAction.Staking + ApySource.YIELD_SUPPLY -> { + NavigationAction.YieldSupply(currencyStatus.value.yieldSupplyStatus?.isActive == true) + } } sendApyLabelClickAnalytics(navigationAction, currencyStatus) 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 f9eefeccd6..6dd7d7de6c 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 @@ -49,9 +49,15 @@ internal class TokenListStateConverter( clickIntents.onTokenItemLongClick(selectedWallet.walletId, currencyStatus) } - private val onApyLabelClick: (currencyStatus: CryptoCurrencyStatus, apy: String) -> Unit = - { currencyStatus, apy -> - clickIntents.onApyLabelClick(selectedWallet.walletId, currencyStatus, apy) + private val onApyLabelClick: + (currencyStatus: CryptoCurrencyStatus, apySource: TokenItemStateConverter.ApySource, apy: String) -> Unit = + { currencyStatus, apySource, apy -> + clickIntents.onApyLabelClick( + userWalletId = selectedWallet.walletId, + currencyStatus = currencyStatus, + apySource = apySource, + apy = apy, + ) } private fun tokenStatusConverter(accountId: AccountId? = null) = TokenItemStateConverter( @@ -60,7 +66,7 @@ internal class TokenListStateConverter( stakingApyMap = stakingApyMap, onItemClick = { _, status -> onTokenClick(accountId, status) }, onItemLongClick = { _, status -> onTokenLongClick(accountId, status) }, - onApyLabelClick = { status, apy -> onApyLabelClick(status, apy) }, + onApyLabelClick = { status, apySource, apy -> onApyLabelClick(status, apySource, apy) }, ) override fun convert(value: WalletTokensListState): WalletTokensListState { From c3ea39c47dd00d50638a6aa328551be9d48e9d25 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 9 Dec 2025 11:30:21 +0300 Subject: [PATCH 12/13] Updated on 2026-08-14 --- .../features/onramp/settings/model/OnrampSettingsModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt index 9fe53c12a0..e7eba0a83f 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt @@ -29,13 +29,13 @@ internal class OnrampSettingsModel @Inject constructor( paramsContainer: ParamsContainer, ) : Model() { + private val params: OnrampSettingsComponent.Params = paramsContainer.require() + val state: StateFlow field = MutableStateFlow(getInitialState()) val bottomSheetNavigation: SlotNavigation = SlotNavigation() - private val params: OnrampSettingsComponent.Params = paramsContainer.require() - init { analyticsEventHandler.send(OnrampAnalyticsEvent.SettingsOpened) subscribeOnUpdateState() From 45b1b619fbf1b8897ac57cfa99cf4ef72c9f5875 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 9 Dec 2025 11:38:41 +0000 Subject: [PATCH 13/13] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 07be659f64..8c10bcaf9d 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,13 +5,13 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.31-1314" +tangemBlockchainSdk = "develop-1317" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.31-569" +tangemCardSdk = "develop-568" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem12" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ -tangemHotSdk = "develop-531" +tangemHotSdk = "develop-532" #tangemHotSdk = "0.0.1" # Keep it! - used for local builds ^