From 258af2284223737299e3290b50f700f827abec8f Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 24 Jul 2024 18:01:00 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../{ScanErrorTest.kt => ScanEmptyTest.kt} | 0 core/res/src/main/res/values-de/strings.xml | 2 +- core/res/src/main/res/values-fr/strings.xml | 3 + core/res/src/main/res/values-ja/strings.xml | 2 +- core/res/src/main/res/values-ru/strings.xml | 2 +- .../src/main/res/values-uk-rUA/strings.xml | 2 +- .../src/main/res/values-zh-rTW/strings.xml | 8 +- .../list/RoundedListWithDividers.kt | 31 +++--- .../staking/GetStakingTransactionUseCase.kt | 4 +- .../presentation/state/StakingStateRouter.kt | 11 +- .../impl/presentation/state/StakingUiState.kt | 11 -- .../ui/StakingInitialInfoContent.kt | 69 +++++++----- .../ui/StakingNavigationButtons.kt | 10 +- .../impl/presentation/ui/StakingScreen.kt | 2 +- .../TokenDetailsLoadedBalanceConverter.kt | 104 ++++++++++++------ .../state/factory/TokenDetailsStateFactory.kt | 2 + .../viewmodels/TokenDetailsViewModel.kt | 13 ++- .../WalletCurrencyActionsClickIntents.kt | 3 + 18 files changed, 180 insertions(+), 99 deletions(-) rename app/src/androidTest/kotlin/com/tangem/tests/{ScanErrorTest.kt => ScanEmptyTest.kt} (100%) diff --git a/app/src/androidTest/kotlin/com/tangem/tests/ScanErrorTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/ScanEmptyTest.kt similarity index 100% rename from app/src/androidTest/kotlin/com/tangem/tests/ScanErrorTest.kt rename to app/src/androidTest/kotlin/com/tangem/tests/ScanEmptyTest.kt diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index df3279230b..500bfaa797 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -633,7 +633,7 @@ ≈ %1$s (inkl. Gebühr: %2$s) %s wird gesendet Die Transaktion wurde erfolgreich signiert und an den Blockchain-Knoten gesendet. Die Walletbilanz wird aktualisiert - %1s ist ein Vermögenswert im Tron-Netzwerk. Um die Gebühr zu berechnen und eine Transaktion durchzuführen, musst du etwas Tron (TRX) auf deinem Konto einzahlen. + %1$s ist ein Vermögenswert im Tron-Netzwerk. Um die Gebühr zu berechnen und eine Transaktion durchzuführen, musst du etwas Tron (TRX) auf deinem Konto einzahlen. Ungültige Adresse %1$s (%2$s) Transaktion gesendet diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index a07a86a3ab..4326cc2b26 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -490,6 +490,8 @@ Il s\'agit du coût que vous êtes prêt à payer pour chaque unité de gaz. Plus le prix du gaz est élevé, plus votre transaction sera traitée rapidement. (Frais de priorité inclus) Frais de priorité Les frais qu\'un utilisateur peut payer aux mineurs ou aux validateurs pour accélérer l\'inclusion de leur transaction dans un bloc. + Les frais requis pour l\'utilisation de chaque sortie de transaction non dépensée (UTXO) dans le réseau Kaspa. Plus vous utilisez d’UTXO dans une transaction, plus les frais seront élevés. + KAS pour UTXO %1$s, %2$s Adresse Destination Tag @@ -718,6 +720,7 @@ Paramètres du portefeuille Tangem Utilisez %s ou scannez une carte pour déverrouiller l\'accès à votre portefeuille + Il semble que l\'activation de la carte ne se soit pas déroulée correctement. Cela peut être dû à un problème avec le module NFC de votre appareil ou à une mauvaise connexion de la carte sur votre appareil. Veuillez contacter notre équipe de support pour obtenir de l’aide. Erreur d\'activation Selon les développeurs du réseau BNB, le support de la norme BEP-2\nprendra fin en juin 2024. Pour éviter de perdre des actifs avec cette norme, veuillez les convertir à la norme BEP-20. Utilisez notre service de d\'échange pour les transférer sur le réseau BNB Smart Chain. BNB Beacon Chain va s\'arrêter de fonctionner diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index de7d3bc1e3..2c83a84083 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -621,7 +621,7 @@ ≈ %1$s (%2$s: 手数料を含む) %sが送信されます 取引は正常に署名され、ブロックチェーンノードに送信されました。ウォレットの残高はしばらくして更新されます。 - %1sはTronネットワークのアセットです。手数料を計算して取引を行うには、アカウントにTron(TRX)を入金する必要があります。 + %1$sはTronネットワークのアセットです。手数料を計算して取引を行うには、アカウントにTron(TRX)を入金する必要があります。 無効なアドレス %1$s ( %2$s ) 取引が送信されました diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 9784dd7cc8..e83c0613ab 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -565,7 +565,7 @@ ≈ %1$s (вкл. комиссию: %2$s) %s будет отправлено Транзакция успешно подписана и отправлена в блокчейн. Баланс будет обновлен через некоторое время - %1s — это монета в сети Tron. Чтобы рассчитать комиссию и совершить транзакцию, вам необходимо внести немного Tron (TRX) на свой адрес. + %1$s — это монета в сети Tron. Чтобы рассчитать комиссию и совершить транзакцию, вам необходимо внести немного Tron (TRX) на свой адрес. Неверный адрес Транзакция отправлена Подготовьтесь к сканированию карты, которую вы хотите настроить. diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index 57f722155b..4385ef8469 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -645,7 +645,7 @@ ≈ %1$s (вкл. комісію: %2$s ) %s буде надіслано Транзакція успішно підписана і відправлена до блокчейну. Баланс гаманця буде оновлено через деякий час - %1s — це монета у мережі Tron. Щоб розрахувати комісію та здійснити транзакцію, вам необхідно внести певну кількість Tron(TRX) на свій рахунок. + %1$s — це монета у мережі Tron. Щоб розрахувати комісію та здійснити транзакцію, вам необхідно внести певну кількість Tron(TRX) на свій рахунок. Недійсна адреса %1$s (%2$s) Трансакцію надіслано diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml index 28f111ab8b..ae1e771935 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -4,6 +4,7 @@ 管理代幣 僅將 %1$s (%2$s) 從 %3$s 網絡發送到此地址。使用其他代幣和網絡可能會導致資金損失 請求支持 + 再試一次 此功能不在展示模式中提供 原因:%s 無法發送交易 @@ -36,6 +37,7 @@ 安全模式 卡片設置 接受 + 允許 注意 餘額: %s 餘額 @@ -127,6 +129,9 @@ 反饋 Tangem反饋 無法發送交易 + 數量 %s + 要繼續,您需要允許 %1s 智能合約使用您的 %2s + 賦予權限 掃描卡片 要更改訪問密碼,請完全按照上圖所示連接手機和卡片 要更改密碼,請完全按照上圖所示連接手機和卡 @@ -171,7 +176,6 @@ 這此情況,您必須要重新開始 您想要離開啟用程序嗎? 開始 - 您要添加的卡上已經創建了另一個錢包。你想重置它並將卡用於新錢包嗎? 創建備份 閱讀更多關於助記詞的訊息 @@ -288,7 +292,7 @@ 您即將在主屏幕上隱藏此代幣。您可以隨時通過管理代幣頁面將其添加回來。 隱藏 %s 隱藏代幣 - %1$s 代幣是 %2$s 網絡上的主要貨幣,只要列表中還有該網絡上的其他代幣,它就無法被隱藏。 + %1$s (%2$s) 代幣是 %3$s 網絡上的主要貨幣,只要列表中還有該網絡上的其他代幣,它就無法被隱藏。 無法隱藏 %s 您還沒有任何交易 無法加載交易 diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/list/RoundedListWithDividers.kt b/core/ui/src/main/java/com/tangem/core/ui/components/list/RoundedListWithDividers.kt index 8161f2ff69..1779adf487 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/list/RoundedListWithDividers.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/list/RoundedListWithDividers.kt @@ -4,6 +4,7 @@ import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -20,19 +21,23 @@ import kotlinx.collections.immutable.persistentListOf @Composable fun RoundedListWithDividers(rows: List, modifier: Modifier = Modifier) { LazyColumn(modifier = modifier) { - itemsIndexed( - items = rows, - key = { _, item -> item.id }, - ) { index, row -> - InitialInfoContentRow( - startText = row.startText.resolveReference(), - endText = row.endText.resolveReference(), - cornersToRound = getCornersToRound(index, rows.size), - iconClick = row.iconClick, - ) - if (index < rows.lastIndex) { - RoundedListDivider() - } + this.roundedListItems(rows) + } +} + +fun LazyListScope.roundedListItems(rows: List) { + itemsIndexed( + items = rows, + key = { _, item -> item.id }, + ) { index, row -> + InitialInfoContentRow( + startText = row.startText.resolveReference(), + endText = row.endText.resolveReference(), + cornersToRound = getCornersToRound(index, rows.size), + iconClick = row.iconClick, + ) + if (index < rows.lastIndex) { + RoundedListDivider() } } } diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingTransactionUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingTransactionUseCase.kt index 02abd643a4..d6d147b1c3 100644 --- a/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingTransactionUseCase.kt +++ b/domain/staking/src/main/java/com/tangem/domain/staking/GetStakingTransactionUseCase.kt @@ -23,7 +23,9 @@ class GetStakingTransactionUseCase( // workaround, sometimes transaction is not created immediately after actions/enter delay(PATCH_TRANSACTION_REQUEST_DELAY) - val createdTransaction = createAction.transactions?.get(0) ?: error("No available transaction to patch") + val createdTransaction = createAction.transactions + ?.get(createAction.currentStepIndex) + ?: error("No available transaction to patch") val patchedTransaction = stakingRepository.constructTransaction(createdTransaction.id) patchedTransaction diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt index 2629f6405b..d0485b1812 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt @@ -32,10 +32,17 @@ internal class StakingStateRouter( } fun onPrevClick() { - when (stateController.uiState.value.currentStep) { + val uiState = stateController.uiState.value + when (uiState.currentStep) { StakingStep.InitialInfo -> onBackClick() StakingStep.Amount -> showInitial() - StakingStep.Confirmation -> showAmount() + StakingStep.Confirmation -> { + if (uiState.routeType == RouteType.OTHER || uiState.routeType == RouteType.UNSTAKE) { + showInitial() + } else { + showAmount() + } + } StakingStep.Validators -> showConfirmation() StakingStep.RewardsValidators -> showInitial() } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt index 2ad72821a5..ae02e3c71b 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt @@ -55,17 +55,6 @@ internal sealed class StakingStates { val isStakeMoreAvailable: Boolean, ) : InitialInfoState() - data class InitialInfoItems( - val available: String, - val onStake: String, - val aprRange: TextReference, - val unbondingPeriod: String, - val minimumRequirement: String, - val rewardClaiming: String, - val warmupPeriod: String, - val rewardSchedule: String, - ) - data class Empty( override val isPrimaryButtonEnabled: Boolean = false, ) : InitialInfoState() diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt index 961cdb9643..eae933e9b6 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt @@ -1,12 +1,12 @@ package com.tangem.features.staking.impl.presentation.ui import android.content.res.Configuration -import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.Icon @@ -22,10 +22,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import com.tangem.core.ui.components.SpacerH12 import com.tangem.core.ui.components.containers.FooterContainer import com.tangem.core.ui.components.inputrow.InputRowDefault import com.tangem.core.ui.components.inputrow.InputRowImageInfo -import com.tangem.core.ui.components.list.RoundedListWithDividers +import com.tangem.core.ui.components.list.roundedListItems import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -39,37 +40,53 @@ import com.tangem.utils.StringsSigns.DOT import com.tangem.utils.StringsSigns.PLUS import com.tangem.utils.extensions.orZero +private const val STAKING_REWARD_BLOCK_KEY = "StakingRewardBlock" +private const val METRICS_BLOCK_KEY = "MetricsBlock" +private const val ACTIVE_STAKING_BLOCK_KEY = "ActiveStakingBlock" + +@OptIn(ExperimentalFoundationApi::class) @Composable internal fun StakingInitialInfoContent(state: StakingStates.InitialInfoState, clickIntents: StakingClickIntents) { if (state !is StakingStates.InitialInfoState.Data) return - Column( - verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), - modifier = Modifier // Do not put fillMaxSize() in here + LazyColumn( + modifier = Modifier .background(TangemTheme.colors.background.tertiary) - .padding( - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - bottom = TangemTheme.dimens.spacing16, - ), + .fillMaxSize(), + contentPadding = PaddingValues(TangemTheme.dimens.spacing16), ) { - AnimatedVisibility(state.yieldBalance == InnerYieldBalanceState.Empty) { - MetricsBlock(state) - } - RoundedListWithDividers(state.infoItems) - AnimatedContent(targetState = state.yieldBalance, label = "Rewards block visibility animation") { - if (it is InnerYieldBalanceState.Data) { - StakingRewardBlock( - rewardCrypto = it.rewardsCrypto, - rewardFiat = it.rewardsFiat, - isRewardsToClaim = it.isRewardsToClaim, - onRewardsClick = clickIntents::openRewardsValidators, - ) + if (state.yieldBalance == InnerYieldBalanceState.Empty) { + item(key = METRICS_BLOCK_KEY) { + Column(modifier = Modifier.animateItemPlacement()) { + MetricsBlock(state) + SpacerH12() + } } } - AnimatedContent(targetState = state.yieldBalance, label = "Staking yield visibility animation") { - if (it is InnerYieldBalanceState.Data) { - ActiveStakingBlock(it.balance, clickIntents::onActiveStake) + + this.roundedListItems(state.infoItems) + item { SpacerH12() } + + if (state.yieldBalance is InnerYieldBalanceState.Data) { + item(key = STAKING_REWARD_BLOCK_KEY) { + Column(modifier = Modifier.animateItemPlacement()) { + StakingRewardBlock( + rewardCrypto = state.yieldBalance.rewardsCrypto, + rewardFiat = state.yieldBalance.rewardsFiat, + isRewardsToClaim = state.yieldBalance.isRewardsToClaim, + onRewardsClick = clickIntents::openRewardsValidators, + ) + SpacerH12() + } + } + } + + if (state.yieldBalance is InnerYieldBalanceState.Data) { + item(key = ACTIVE_STAKING_BLOCK_KEY) { + Column(modifier = Modifier.animateItemPlacement()) { + ActiveStakingBlock(state.yieldBalance.balance, clickIntents::onActiveStake) + SpacerH12() + } } } } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt index 67a7000962..de810623ee 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt @@ -133,7 +133,12 @@ private fun getButtonData(currentState: StakingUiState): Int { if (confirmationState.innerState == InnerConfirmationStakingState.COMPLETED) { R.string.common_close } else { - R.string.common_stake + when (currentState.routeType) { + RouteType.STAKE -> R.string.common_stake + RouteType.CLAIM -> R.string.common_claim_rewards + RouteType.UNSTAKE -> R.string.common_unstake + RouteType.OTHER -> R.string.common_stake + } } } else { R.string.common_close @@ -182,7 +187,8 @@ private fun isButtonEnabled(uiState: StakingUiState): Pair { return when (uiState.currentStep) { StakingStep.InitialInfo -> { val initialState = uiState.initialInfoState as? StakingStates.InitialInfoState.Data - val isDisplayed = initialState?.isStakeMoreAvailable == true + val isDisplayed = initialState?.isStakeMoreAvailable == true || + initialState?.yieldBalance is InnerYieldBalanceState.Empty uiState.initialInfoState.isPrimaryButtonEnabled to isDisplayed } StakingStep.Amount -> uiState.amountState.isPrimaryButtonEnabled to true diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt index c26935b80c..c79fca59ff 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt @@ -29,7 +29,7 @@ import kotlinx.coroutines.flow.withIndex @Composable internal fun StakingScreen(uiState: StakingUiState) { - BackHandler(onBack = uiState.clickIntents::onBackClick) + BackHandler(onBack = uiState.clickIntents::onPrevClick) Column( modifier = Modifier .background(color = TangemTheme.colors.background.tertiary) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt index b5b0f8a5c6..6aa3923cd9 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt @@ -11,10 +11,11 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.staking.model.StakingEntryInfo import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.feature.tokendetails.presentation.tokendetails.state.BalanceType +import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockUM import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState @@ -31,9 +32,11 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList import java.math.BigDecimal +@Suppress("LongParameterList") internal class TokenDetailsLoadedBalanceConverter( private val currentStateProvider: Provider, private val appCurrencyProvider: Provider, + private val stakingEntryInfoProvider: Provider, private val symbol: String, private val decimals: Int, private val clickIntents: TokenDetailsClickIntents, @@ -136,39 +139,28 @@ internal class TokenDetailsLoadedBalanceConverter( private fun getYieldBalance(status: CryptoCurrencyStatus, state: TokenDetailsState): StakingBlockUM { val yieldBalance = status.value.yieldBalance as? YieldBalance.Data - val stakingCryptoAmount = yieldBalance?.getTotalStakingBalance() - val stakingRewardAmount = yieldBalance?.getRewardStakingBalance() - val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) } - return if (stakingCryptoAmount.isNullOrZero()) { - StakingBlockUM.Loading(state.tokenInfoBlockState.iconState) - } else { - StakingBlockUM.Staked( - cryptoAmount = stakingCryptoAmount, - fiatAmount = stakingFiatAmount, - cryptoValue = stringReference( - BigDecimalFormatter.formatCryptoAmount(stakingCryptoAmount, symbol, decimals), - ), - fiatValue = stringReference( - BigDecimalFormatter.formatFiatAmount( - stakingFiatAmount, - appCurrencyProvider().code, - appCurrencyProvider().symbol, - ), - ), - rewardValue = resourceReference( - R.string.staking_details_rewards_to_claim, - wrappedList( - BigDecimalFormatter.formatFiatAmount( - stakingRewardAmount, - appCurrencyProvider().code, - appCurrencyProvider().symbol, - ), - ), - ), - onStakeClicked = clickIntents::onStakeBannerClick, - ) + val stakingEntryInfo = stakingEntryInfoProvider.invoke() + val iconState = state.tokenInfoBlockState.iconState + + return when { + stakingCryptoAmount.isNullOrZero() && stakingEntryInfo != null -> { + getStakeAvailableState(stakingEntryInfo, iconState) + } + stakingCryptoAmount.isNullOrZero() && stakingEntryInfo == null -> { + StakingBlockUM.Error(iconState = iconState) + } + else -> { + val stakingRewardAmount = yieldBalance?.getRewardStakingBalance() + val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) } + + getStakedState( + stakingCryptoAmount = stakingCryptoAmount, + stakingFiatAmount = stakingFiatAmount, + stakingRewardAmount = stakingRewardAmount, + ) + } } } @@ -195,6 +187,54 @@ internal class TokenDetailsLoadedBalanceConverter( } } + private fun getStakeAvailableState( + stakingEntryInfo: StakingEntryInfo, + iconState: IconState, + ): StakingBlockUM.StakeAvailable { + return StakingBlockUM.StakeAvailable( + interestRate = BigDecimalFormatter.formatPercent( + percent = stakingEntryInfo.interestRate, + useAbsoluteValue = true, + ), + periodInDays = stakingEntryInfo.periodInDays, + tokenSymbol = stakingEntryInfo.tokenSymbol, + iconState = iconState, + onStakeClicked = clickIntents::onStakeBannerClick, + ) + } + + private fun getStakedState( + stakingCryptoAmount: BigDecimal?, + stakingFiatAmount: BigDecimal?, + stakingRewardAmount: BigDecimal?, + ): StakingBlockUM.Staked { + return StakingBlockUM.Staked( + cryptoAmount = stakingCryptoAmount, + fiatAmount = stakingFiatAmount, + cryptoValue = stringReference( + BigDecimalFormatter.formatCryptoAmount(stakingCryptoAmount, symbol, decimals), + ), + fiatValue = stringReference( + BigDecimalFormatter.formatFiatAmount( + stakingFiatAmount, + appCurrencyProvider().code, + appCurrencyProvider().symbol, + ), + ), + rewardValue = resourceReference( + R.string.staking_details_rewards_to_claim, + wrappedList( + BigDecimalFormatter.formatFiatAmount( + stakingRewardAmount, + appCurrencyProvider().code, + appCurrencyProvider().symbol, + ), + ), + ), + onStakeClicked = clickIntents::onStakeBannerClick, + ) + } + private fun CryptoCurrencyStatus.Value.toContentConfig(currencySymbol: String): MarketPriceBlockState.Content { return MarketPriceBlockState.Content( currencySymbol = currencySymbol, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt index 3d6080faba..402e674bec 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt @@ -50,6 +50,7 @@ import kotlinx.coroutines.flow.MutableStateFlow internal class TokenDetailsStateFactory( private val currentStateProvider: Provider, private val appCurrencyProvider: Provider, + private val stakingEntryInfoProvider: Provider, private val cryptoCurrencyStatusProvider: Provider, private val clickIntents: TokenDetailsClickIntents, private val featureToggles: TokenDetailsFeatureToggles, @@ -79,6 +80,7 @@ internal class TokenDetailsStateFactory( TokenDetailsLoadedBalanceConverter( currentStateProvider = currentStateProvider, appCurrencyProvider = appCurrencyProvider, + stakingEntryInfoProvider = stakingEntryInfoProvider, symbol = symbol, decimals = decimals, clickIntents = clickIntents, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index b885be8766..0e56efee0d 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -34,6 +34,7 @@ import com.tangem.domain.staking.GetStakingAvailabilityUseCase import com.tangem.domain.staking.GetStakingEntryInfoUseCase import com.tangem.domain.staking.GetYieldUseCase import com.tangem.domain.staking.model.StakingAvailability +import com.tangem.domain.staking.model.StakingEntryInfo import com.tangem.domain.tokens.* import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.domain.tokens.legacy.TradeCryptoAction.TransactionInfo @@ -143,15 +144,16 @@ internal class TokenDetailsViewModel @Inject constructor( private val refreshStateJobHolder = JobHolder() private val warningsJobHolder = JobHolder() private val swapTxJobHolder = JobHolder() - private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null - - private var swapTxStatusTaskScheduler = SingleTaskScheduler>() - private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow() + private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null + private var stakingEntryInfo: StakingEntryInfo? = null + private var swapTxStatusTaskScheduler = SingleTaskScheduler>() + private val stateFactory = TokenDetailsStateFactory( currentStateProvider = Provider { uiState.value }, appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), + stakingEntryInfoProvider = Provider { stakingEntryInfo }, cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, clickIntents = this, symbol = cryptoCurrency.symbol, @@ -397,7 +399,8 @@ internal class TokenDetailsViewModel @Inject constructor( cryptoCurrencyId = cryptoCurrency.id, symbol = cryptoCurrency.symbol, ) - internalUiState.value = stateFactory.getStateWithStaking(stakingInfo) + + stakingEntryInfo = stakingInfo.getOrNull() } } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt index c6b5eb1cff..bdf5dae4ba 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt @@ -370,6 +370,9 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( } override fun onStakeClick(cryptoCurrencyStatus: CryptoCurrencyStatus) { + val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return + stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWallet.walletId)) + viewModelScope.launch { val userWalletId = stateHolder.getSelectedWalletId() val cryptoCurrency = cryptoCurrencyStatus.currency