Updated on 2026-08-14

This commit is contained in:
Tangem 2025-12-12 14:18:29 +03:00
commit d44fcb3218
61 changed files with 1333 additions and 232 deletions

View file

@ -58,6 +58,7 @@ internal class YieldSupplyActiveModel @Inject constructor(
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val urlOpener: UrlOpener,
private val appRouter: AppRouter,
private val yieldSupplyGetDustMinAmountUseCase: YieldSupplyGetDustMinAmountUseCase,
) : Model(), YieldSupplyStopEarningComponent.ModelCallback,
YieldSupplyApproveComponent.ModelCallback {
@ -241,11 +242,13 @@ internal class YieldSupplyActiveModel @Inject constructor(
userWalletId,
cryptoCurrencyStatusFlow.value,
).onRight { minAmount ->
val dustAmount = yieldSupplyGetDustMinAmountUseCase(minAmount = minAmount, appCurrency = appCurrency)
uiState.update(
YieldSupplyActiveMinAmountTransformer(
cryptoCurrencyStatus = cryptoCurrencyStatusFlow.value,
appCurrency = appCurrency,
minAmount = minAmount,
dustMinAmount = dustAmount,
analyticsHandler = analyticsHandler,
onApprove = ::onApprove,
),

View file

@ -28,11 +28,12 @@ import java.math.BigDecimal
* - Builds the fee policy note text using the minimum amount.
* - Adds contextual notifications:
* - Approval required notification when spending is not yet allowed (emits analytics on CTA).
* - "Not all amount supplied" info when wallet balance exceeds the supplied balance by more than [minAmount].
* - "Not all amount supplied" info when the not-supplied balance exceeds the dust threshold [dustMinAmount].
*
* @property cryptoCurrencyStatus Current currency status used to calculate values and flags.
* @property appCurrency Preferred fiat currency for formatting.
* @property minAmount Protocol-required minimal amount to deposit/supply (in crypto units).
* @property dustMinAmount Threshold used to detect dust/not-supplied balance (in crypto units).
* @property analyticsHandler Analytics reporter for user actions.
* @property onApprove Action invoked when the "Approve" notification button is tapped.
*/
@ -40,6 +41,7 @@ internal class YieldSupplyActiveMinAmountTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val appCurrency: AppCurrency,
private val minAmount: BigDecimal,
private val dustMinAmount: BigDecimal,
private val analyticsHandler: AnalyticsEventHandler,
private val onApprove: () -> Unit,
) : Transformer<YieldSupplyActiveContentUM> {
@ -89,7 +91,7 @@ internal class YieldSupplyActiveMinAmountTransformer(
}
private fun getNotSuppliedNotification(cryptoCurrencyStatus: CryptoCurrencyStatus): NotificationUM? {
return if (cryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(minAmount)) {
return if (cryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(dustMinAmount)) {
val cryptoCurrency = cryptoCurrencyStatus.currency
val notDepositedAmount = cryptoCurrencyStatus.notSuppliedAmountOrNull()
val formattedAmount =

View file

@ -1,5 +1,6 @@
package com.tangem.features.yield.supply.impl.main.model
import arrow.core.getOrElse
import com.tangem.common.routing.AppRoute
import android.os.SystemClock
import com.tangem.common.routing.AppRoute.YieldSupplyPromo
@ -12,6 +13,8 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.combinedReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
@ -51,6 +54,7 @@ internal class YieldSupplyModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val analyticsEventsHandler: AnalyticsEventHandler,
private val appRouter: AppRouter,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getUserWalletUseCase: GetUserWalletUseCase,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
@ -61,6 +65,7 @@ internal class YieldSupplyModel @Inject constructor(
private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase,
private val yieldSupplyRepository: YieldSupplyRepository,
private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase,
private val yieldSupplyGetDustMinAmountUseCase: YieldSupplyGetDustMinAmountUseCase,
) : Model(), YieldSupplyClickIntents {
private val params = paramsContainer.require<YieldSupplyComponent.Params>()
@ -69,6 +74,7 @@ internal class YieldSupplyModel @Inject constructor(
field = MutableStateFlow<YieldSupplyUM>(YieldSupplyUM.Initial)
private val cryptoCurrency = params.cryptoCurrency
private var appCurrency: AppCurrency = AppCurrency.Default
var userWallet: UserWallet by Delegates.notNull()
private val fetchCurrencyJobHolder = JobHolder()
@ -81,10 +87,17 @@ internal class YieldSupplyModel @Inject constructor(
}
private fun checkIfYieldSupplyIsAvailable() {
modelScope.launch(dispatchers.io) {
modelScope.launch(dispatchers.default) {
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
val isAvailable = yieldSupplyIsAvailableUseCase(params.userWalletId, params.cryptoCurrency)
if (isAvailable) {
subscribeOnCurrencyStatusUpdates()
singleNetworkStatusFetcher(
params = SingleNetworkStatusFetcher.Params(
userWalletId = params.userWalletId,
network = cryptoCurrency.network,
),
)
}
}
}
@ -334,7 +347,11 @@ internal class YieldSupplyModel @Inject constructor(
val minAmount = yieldSupplyMinAmountUseCase(userWalletId = userWallet.walletId, cryptoCurrencyStatus)
.getOrNull()
if (minAmount != null) {
cryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(minAmount)
val dustAmount = yieldSupplyGetDustMinAmountUseCase(
minAmount = minAmount,
appCurrency = appCurrency,
)
cryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(dustAmount)
} else {
false
}