diff --git a/.gitignore b/.gitignore
index cb56a9e269..345207b4eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,4 @@ app/src/external/google-services.json
# Kotlin Plugin
.kotlin/
+find-latest-release-branch.output
diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt
index 662a404f90..7425a7aa0f 100644
--- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt
+++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt
@@ -275,14 +275,6 @@ sealed class NotificationUM(val config: NotificationConfig) {
title = resourceReference(id = R.string.yield_module_balance_info_sheet_title, wrappedList(tokenName)),
subtitle = resourceReference(id = R.string.yield_module_balance_info_sheet_subtitle),
)
-
- data class YieldSupplyNotAllAmountSupplied(val formattedAmount: String, val symbol: String) : Warning(
- title = resourceReference(
- id = R.string.yield_module_amount_not_transfered_to_aave_title,
- formatArgs = wrappedList(formattedAmount, symbol),
- ),
- subtitle = TextReference.EMPTY,
- )
}
open class Info(
@@ -301,7 +293,15 @@ sealed class NotificationUM(val config: NotificationConfig) {
onCloseClick = onCloseClick,
iconTint = iconTint,
),
- )
+ ) {
+ data class YieldSupplyNotAllAmountSupplied(val formattedAmount: String, val symbol: String) : Info(
+ title = resourceReference(
+ id = R.string.yield_module_amount_not_transfered_to_aave_title,
+ formatArgs = wrappedList(formattedAmount, symbol),
+ ),
+ subtitle = TextReference.EMPTY,
+ )
+ }
sealed interface Cardano {
diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml
index 211f153257..797ee47246 100644
--- a/core/res/src/main/res/values-ja/strings.xml
+++ b/core/res/src/main/res/values-ja/strings.xml
@@ -269,7 +269,7 @@
無料
送信元
アドレスを同期する
- はじめる
+ もっと詳しく
トークンを取得
プロバイダーへ移動
トークンへ移動
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/label/Label.kt b/core/ui/src/main/java/com/tangem/core/ui/components/label/Label.kt
index 951e6a5042..2cc6209978 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/label/Label.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/label/Label.kt
@@ -16,6 +16,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
@@ -68,9 +69,18 @@ fun Label(state: LabelUM, modifier: Modifier = Modifier) {
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = modifier
.padding(horizontal = 4.dp)
- .background(
- color = backgroundColor,
- shape = TangemTheme.shapes.roundedCorners8,
+ .clip(TangemTheme.shapes.roundedCorners8)
+ .background(color = backgroundColor)
+ .then(
+ if (state.onClick != null) {
+ Modifier.clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = ripple(),
+ onClick = state.onClick,
+ )
+ } else {
+ Modifier
+ },
)
.padding(horizontal = 8.dp, vertical = 4.dp),
) {
@@ -86,11 +96,13 @@ fun Label(state: LabelUM, modifier: Modifier = Modifier) {
imageVector = ImageVector.vectorResource(wrappedIcon),
tint = iconColor,
contentDescription = null,
- modifier = Modifier.size(16.dp).clickable(
- interactionSource = remember { MutableInteractionSource() },
- indication = ripple(bounded = false),
- onClick = { state.onIconClick?.invoke() },
- ),
+ modifier = Modifier
+ .size(16.dp)
+ .clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = ripple(bounded = false),
+ onClick = { state.onIconClick?.invoke() },
+ ),
)
}
}
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/label/entity/LabelUM.kt b/core/ui/src/main/java/com/tangem/core/ui/components/label/entity/LabelUM.kt
index 1be654c994..9982a897b0 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/label/entity/LabelUM.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/label/entity/LabelUM.kt
@@ -8,6 +8,7 @@ data class LabelUM(
val style: LabelStyle,
@DrawableRes val icon: Int? = null,
val onIconClick: (() -> Unit)? = null,
+ val onClick: (() -> Unit)? = null,
)
enum class LabelStyle {
diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt
index 5701b7eb2e..dae65d3ec7 100644
--- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt
+++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt
@@ -1,10 +1,13 @@
package com.tangem.data.walletmanager.utils
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
+import com.tangem.blockchain.blockchains.ethereum.tokenmethods.ApprovalERC20TokenCallData
import com.tangem.blockchain.common.*
import com.tangem.blockchain.yieldsupply.providers.ethereum.factory.EthereumYieldSupplyDeployCallData
import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyEnterCallData
import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyExitCallData
+import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyInitTokenCallData
+import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyReactivateTokenCallData
import com.tangem.blockchainsdk.models.UpdateWalletManagerResult.Address
import com.tangem.domain.models.network.TxInfo
import com.tangem.utils.converter.Converter
@@ -37,25 +40,12 @@ internal class TransactionDataToTxHistoryItemConverter(
addressType = TxInfo.AddressType.User(value.destinationAddress),
),
sourceType = TxInfo.SourceType.Single(value.sourceAddress),
- interactionAddressType = TxInfo.InteractionAddressType.User(
- address = if (isOutgoing) value.destinationAddress else value.sourceAddress,
- ),
+ interactionAddressType = getInteractionAddressType(value, isOutgoing),
status = when (value.status) {
TransactionStatus.Confirmed -> TxInfo.TransactionStatus.Confirmed
TransactionStatus.Unconfirmed -> TxInfo.TransactionStatus.Unconfirmed
},
- type = when (val extras = value.extras) {
- is EthereumTransactionExtras -> {
- when (extras.callData) {
- is EthereumYieldSupplyDeployCallData,
- is EthereumYieldSupplyEnterCallData,
- -> TxInfo.TransactionType.YieldSupply.Enter
- is EthereumYieldSupplyExitCallData -> TxInfo.TransactionType.YieldSupply.Exit
- else -> TxInfo.TransactionType.Transfer
- }
- }
- else -> TxInfo.TransactionType.Transfer
- },
+ type = getTransactionType(value.extras),
amount = amount,
)
}
@@ -89,4 +79,41 @@ internal class TransactionDataToTxHistoryItemConverter(
return amountToken.contractAddress.equals(feeToken.contractAddress, ignoreCase = true) &&
amountToken.symbol.equals(feeToken.symbol, ignoreCase = true)
}
+
+ private fun getInteractionAddressType(
+ value: TransactionData.Uncompiled,
+ isOutgoing: Boolean,
+ ): TxInfo.InteractionAddressType = when (val extras = value.extras) {
+ is EthereumTransactionExtras -> {
+ when (val callData = extras.callData) {
+ is ApprovalERC20TokenCallData -> TxInfo.InteractionAddressType.Contract(
+ address = callData.spenderAddress,
+ )
+ else -> TxInfo.InteractionAddressType.User(
+ address = if (isOutgoing) value.destinationAddress else value.sourceAddress,
+ )
+ }
+ }
+ else -> TxInfo.InteractionAddressType.User(
+ address = if (isOutgoing) value.destinationAddress else value.sourceAddress,
+ )
+ }
+
+ private fun getTransactionType(extras: TransactionExtras?): TxInfo.TransactionType {
+ return when (extras) {
+ is EthereumTransactionExtras -> {
+ when (extras.callData) {
+ is EthereumYieldSupplyDeployCallData,
+ is EthereumYieldSupplyReactivateTokenCallData,
+ is EthereumYieldSupplyInitTokenCallData,
+ is EthereumYieldSupplyEnterCallData,
+ -> TxInfo.TransactionType.YieldSupply.Enter
+ is EthereumYieldSupplyExitCallData -> TxInfo.TransactionType.YieldSupply.Exit
+ is ApprovalERC20TokenCallData -> TxInfo.TransactionType.Approve
+ else -> TxInfo.TransactionType.Transfer
+ }
+ }
+ else -> TxInfo.TransactionType.Transfer
+ }
+ }
}
\ No newline at end of file
diff --git a/data/yield-supply/build.gradle.kts b/data/yield-supply/build.gradle.kts
index 73b4ac8ab2..b53babcf05 100644
--- a/data/yield-supply/build.gradle.kts
+++ b/data/yield-supply/build.gradle.kts
@@ -28,6 +28,7 @@ dependencies {
implementation(projects.domain.yieldSupply.models)
implementation(projects.domain.walletManager)
implementation(projects.domain.legacy)
+ implementation(projects.domain.txhistory.models)
implementation(projects.libs.blockchainSdk)
diff --git a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt
index cdc6d867fc..75f2634213 100644
--- a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt
+++ b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt
@@ -12,6 +12,8 @@ import com.tangem.datasource.api.tangemTech.YieldSupplyApi
import com.tangem.datasource.api.tangemTech.models.YieldSupplyChangeTokenStatusBody
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.models.currency.CryptoCurrencyStatus
+import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.yield.supply.YieldSupplyRepository
@@ -22,6 +24,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
+import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap
internal class DefaultYieldSupplyRepository(
@@ -109,16 +112,21 @@ internal class DefaultYieldSupplyRepository(
override suspend fun saveTokenProtocolStatus(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
- yieldSupplyEnterStatus: YieldSupplyEnterStatus,
+ yieldSupplyEnterStatus: YieldSupplyEnterStatus?,
) {
- statusMap["${userWalletId}_${cryptoCurrency.id.value}"] = yieldSupplyEnterStatus
+ val key = getTokenProtocolStatusKey(userWalletId, cryptoCurrency)
+ if (yieldSupplyEnterStatus != null) {
+ statusMap[key] = yieldSupplyEnterStatus
+ } else {
+ statusMap.remove(key)
+ }
}
override fun getTokenProtocolStatus(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): YieldSupplyEnterStatus? {
- return statusMap["${userWalletId}_${cryptoCurrency.id.value}"]
+ return statusMap[getTokenProtocolStatusKey(userWalletId, cryptoCurrency)]
}
private fun List.enrichNetworkIds(): List {
@@ -127,4 +135,44 @@ internal class DefaultYieldSupplyRepository(
token.copy(backendId = chainIdMap[token.chainId])
}
}
+
+ override suspend fun getTokenPendingStatus(
+ userWalletId: UserWalletId,
+ cryptoCurrencyStatus: CryptoCurrencyStatus,
+ ): YieldSupplyEnterStatus? = try {
+ val cryptoCurrency = cryptoCurrencyStatus.currency
+ val walletManager = walletManagersFacade.getOrCreateWalletManager(
+ userWalletId = userWalletId,
+ blockchain = cryptoCurrency.network.toBlockchain(),
+ derivationPath = cryptoCurrency.network.derivationPath.value,
+ ) ?: error("Wallet manager not found")
+
+ val pendingTxs = cryptoCurrencyStatus.value.pendingTransactions
+
+ val yieldAddress = walletManager.calculateYieldModuleAddress()
+ val hasRecentYieldEnterTxs = pendingTxs.hasYieldEnterTransactions(yieldAddress)
+ val hasRecentYieldExitTxs = pendingTxs.hasYieldExitTransactions()
+
+ when {
+ hasRecentYieldEnterTxs -> YieldSupplyEnterStatus.Enter
+ hasRecentYieldExitTxs -> YieldSupplyEnterStatus.Exit
+ else -> null
+ }
+ } catch (e: Exception) {
+ Timber.e(e, "Failed to get pending yield supply status")
+ null
+ }
+
+ private fun Set.hasYieldEnterTransactions(yieldAddress: String) = any {
+ it.type == TxInfo.TransactionType.YieldSupply.Enter ||
+ it.type == TxInfo.TransactionType.Approve &&
+ (it.interactionAddressType as? TxInfo.InteractionAddressType.Contract)?.address == yieldAddress
+ }
+
+ private fun Set.hasYieldExitTransactions() = any {
+ it.type == TxInfo.TransactionType.YieldSupply.Exit
+ }
+
+ private fun getTokenProtocolStatusKey(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): String =
+ "${userWalletId}_${cryptoCurrency.id.value}"
}
\ No newline at end of file
diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/analytics/StakingAnalyticsEvent.kt b/domain/staking/src/main/java/com/tangem/domain/staking/analytics/StakingAnalyticsEvent.kt
index 8279bb4189..42da91d04f 100644
--- a/domain/staking/src/main/java/com/tangem/domain/staking/analytics/StakingAnalyticsEvent.kt
+++ b/domain/staking/src/main/java/com/tangem/domain/staking/analytics/StakingAnalyticsEvent.kt
@@ -160,10 +160,20 @@ sealed class StakingAnalyticsEvent(
),
)
- data class UnitializedAddress(val token: String) : StakingAnalyticsEvent(
+ data class UninitializedAddress(val token: String) : StakingAnalyticsEvent(
event = "Notice - Uninitialized Address",
params = mapOf(AnalyticsParam.TOKEN_PARAM to token),
)
+
+ data class UninitializedAddressScreen(val token: String) : StakingAnalyticsEvent(
+ event = "Uninitialized Address Screen",
+ params = mapOf(AnalyticsParam.TOKEN_PARAM to token),
+ )
+
+ data class ButtonActivate(val token: String) : StakingAnalyticsEvent(
+ event = "Button - Activate",
+ params = mapOf(AnalyticsParam.TOKEN_PARAM to token),
+ )
}
enum class StakeScreenSource {
diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt
index 7fbbc6d543..8ab13bbac1 100644
--- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt
+++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt
@@ -1,6 +1,7 @@
package com.tangem.domain.yield.supply
import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.yield.supply.models.YieldMarketToken
import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus
@@ -76,7 +77,7 @@ interface YieldSupplyRepository {
suspend fun saveTokenProtocolStatus(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
- yieldSupplyEnterStatus: YieldSupplyEnterStatus,
+ yieldSupplyEnterStatus: YieldSupplyEnterStatus?,
)
/**
@@ -91,4 +92,20 @@ interface YieldSupplyRepository {
* @return the last action intent or null if nothing has been recorded
*/
fun getTokenProtocolStatus(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): YieldSupplyEnterStatus?
+
+ /**
+ * Get the pending status of the yield protocol action for the given wallet and currency, if any.
+ *
+ * Used to determine whether the UI should display an intermediate "processing" state
+ * until the protocol status retrieved from backend reflects the change. The value is
+ * transient (in‑memory only) and is not persisted across app restarts.
+ *
+ * @param userWalletId the wallet to query
+ * @param cryptoCurrencyStatus the currency status to query
+ * @return the pending action intent or null if nothing has been recorded
+ */
+ suspend fun getTokenPendingStatus(
+ userWalletId: UserWalletId,
+ cryptoCurrencyStatus: CryptoCurrencyStatus,
+ ): YieldSupplyEnterStatus?
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingClickIntents.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingClickIntents.kt
index 97e447a0f5..7e79b03b94 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingClickIntents.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingClickIntents.kt
@@ -9,6 +9,7 @@ import com.tangem.features.staking.impl.presentation.state.BalanceState
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
import java.math.BigDecimal
+// TODO split this interface to click intents and other interaction events
@Suppress("TooManyFunctions")
internal interface StakingClickIntents : AmountScreenClickIntents {
@@ -72,5 +73,7 @@ internal interface StakingClickIntents : AmountScreenClickIntents {
fun onActivateTonAccountNotificationClick()
+ fun onActivateTonAccountNotificationShow()
+
fun onActivateTonAccountClick()
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt
index aa4707f395..eebecedbcf 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt
@@ -953,6 +953,11 @@ internal class StakingModel @Inject constructor(
}
override fun onActivateTonAccountNotificationClick() {
+ analyticsEventHandler.send(
+ StakingAnalyticsEvent.UninitializedAddressScreen(
+ token = cryptoCurrencyStatus.currency.symbol,
+ ),
+ )
modelScope.launch {
stateController.update(
ShowTonInitializeBottomSheetTransformer(
@@ -1006,7 +1011,20 @@ internal class StakingModel @Inject constructor(
}
}
+ override fun onActivateTonAccountNotificationShow() {
+ analyticsEventHandler.send(
+ StakingAnalyticsEvent.UninitializedAddress(
+ token = cryptoCurrencyStatus.currency.symbol,
+ ),
+ )
+ }
+
override fun onActivateTonAccountClick() {
+ analyticsEventHandler.send(
+ StakingAnalyticsEvent.ButtonActivate(
+ token = cryptoCurrencyStatus.currency.symbol,
+ ),
+ )
modelScope.launch {
tonAccountInitializeTransaction?.let { transaction ->
sendTransactionUseCase.invoke(
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt
index d7fac733a7..1b90c1dc49 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt
@@ -81,5 +81,7 @@ internal object StakingClickIntentsStub : StakingClickIntents {
override fun onActivateTonAccountNotificationClick() {}
+ override fun onActivateTonAccountNotificationShow() {}
+
override fun onActivateTonAccountClick() {}
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt
index b4daf2050b..66d3c56eac 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt
@@ -295,6 +295,7 @@ internal class AddStakingNotificationsTransformer(
val cryptoCurrencyNetworkIdValue = cryptoCurrencyStatusProvider().currency.network.rawId
if (isTon(cryptoCurrencyNetworkIdValue) && !isAccountInitialized) {
+ prevState.clickIntents.onActivateTonAccountNotificationShow()
add(
StakingNotification.Warning.InitializeTonAccount(
onInitializeClick = prevState.clickIntents::onActivateTonAccountNotificationClick,
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt
index 348a673fd5..0b4b6b742e 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt
@@ -189,6 +189,6 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor(
}
interface ModelCallback {
- fun onResult(sendWithSwapUM: SendWithSwapUM)
+ fun onResult(route: SendWithSwapRoute, sendWithSwapUM: SendWithSwapUM)
}
}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt
index ecbfea1277..8d04b3d804 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt
@@ -425,7 +425,8 @@ internal class SendWithSwapConfirmModel @Inject constructor(
val confirmUM = state.confirmUM
val isReadyToSend = confirmUM is ConfirmUM.Content && !confirmUM.isTransactionInProcess
params.callback.onResult(
- state.copy(
+ route = SendWithSwapRoute.Confirm,
+ sendWithSwapUM = state.copy(
navigationUM = NavigationUM.Content(
title = resourceReference(id = R.string.send_with_swap_confirm_title),
subtitle = null,
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/model/SendWithSwapModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/model/SendWithSwapModel.kt
index 357ffacf9c..3d6968a554 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/model/SendWithSwapModel.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/model/SendWithSwapModel.kt
@@ -116,8 +116,10 @@ internal class SendWithSwapModel @Inject constructor(
uiState.update { it.copy(destinationUM = destinationUM) }
}
- override fun onResult(sendWithSwapUM: SendWithSwapUM) {
- uiState.value = sendWithSwapUM
+ override fun onResult(route: SendWithSwapRoute, sendWithSwapUM: SendWithSwapUM) {
+ if (currentRoute.value == route) {
+ uiState.value = sendWithSwapUM
+ }
}
override fun onNavigationResult(navigationUM: NavigationUM) {
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt
index 108d706b1d..e21b971fe1 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt
@@ -36,7 +36,6 @@ import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
-import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
import com.tangem.lib.crypto.BlockchainUtils.isBitcoin
import com.tangem.utils.extensions.addIf
import com.tangem.utils.extensions.isPositive
@@ -62,7 +61,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
private val onrampSepaAvailableUseCase: OnrampSepaAvailableUseCase,
private val getOnrampCountryUseCase: GetOnrampCountryUseCase,
private val notificationsRepository: NotificationsRepository,
- private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles,
private val accountDependencies: AccountDependencies,
) {
@@ -134,7 +132,8 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
!notificationsRepository.isUserAllowToSubscribeOnPushNotifications(),
)
- addYieldSupplyNotifications(flattenCurrencies)
+ // Remove in first iteration of yield supply feature
+ // addYieldSupplyNotifications(flattenCurrencies)
val hasCriticalOrWarning = any { notification ->
notification is WalletNotification.Critical || notification is WalletNotification.Warning
@@ -319,14 +318,14 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
)
}
- private fun MutableList.addYieldSupplyNotifications(
- flattenCurrencies: Lce>,
- ) {
- addIf(
- element = WalletNotification.Warning.YeildSupplyApprove,
- condition = flattenCurrencies.hasTokensWithActivatedSupplyWithoutApprove(),
- )
- }
+ // private fun MutableList.addYieldSupplyNotifications(
+ // flattenCurrencies: Lce>,
+ // ) {
+ // addIf(
+ // element = WalletNotification.Warning.YeildSupplyApprove,
+ // condition = flattenCurrencies.hasTokensWithActivatedSupplyWithoutApprove(),
+ // )
+ // }
private fun MutableList.addWarningNotifications(
cardTypesResolver: CardTypesResolver?,
@@ -371,13 +370,14 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
return flattenCurrencies.any { it.value is CryptoCurrencyStatus.Unreachable }
}
- private fun Lce>.hasTokensWithActivatedSupplyWithoutApprove(): Boolean {
- val flattenCurrencies = getOrNull(isPartialContentAccepted = false) ?: return false
- val yieldSupplyEnabled = yieldSupplyFeatureToggles.isYieldSupplyFeatureEnabled
- return yieldSupplyEnabled && flattenCurrencies.any {
- it.value.yieldSupplyStatus?.isAllowedToSpend == false
- }
- }
+ // Remove in first iteration of yield supply feature
+ // private fun Lce>.hasTokensWithActivatedSupplyWithoutApprove(): Boolean {
+ // val flattenCurrencies = getOrNull(isPartialContentAccepted = false) ?: return false
+ // val yieldSupplyEnabled = yieldSupplyFeatureToggles.isYieldSupplyFeatureEnabled
+ // return yieldSupplyEnabled && flattenCurrencies.any {
+ // it.value.yieldSupplyStatus?.isAllowedToSpend == false
+ // }
+ // }
private fun MutableList.addRateTheAppNotification(
isReadyToShowRating: Boolean,
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/apy/ui/YieldSupplyApyContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/apy/ui/YieldSupplyApyContent.kt
index 8d419ff256..ad2186300f 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/apy/ui/YieldSupplyApyContent.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/apy/ui/YieldSupplyApyContent.kt
@@ -12,10 +12,12 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
@@ -114,7 +116,10 @@ internal fun YieldSupplyApyContent(
ApyChart(
isChartLoading = isLoading,
chartComponent = chartComponent,
- modifier = Modifier.padding(horizontal = 12.dp),
+ modifier = Modifier
+ .clip(RoundedCornerShape(14.dp))
+ .background(TangemTheme.colors.background.action)
+ .padding(12.dp),
)
SpacerH16()
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt
index fab5e5aa21..a3ec2d930e 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt
@@ -26,6 +26,7 @@ internal sealed class YieldSupplyUM {
val rewardsApy: TextReference,
val onClick: () -> Unit,
val showWarningIcon: Boolean,
+ val showInfoIcon: Boolean,
) : YieldSupplyUM()
@Immutable
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt
index 2360b55d2d..a6ab368dc5 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt
@@ -1,5 +1,6 @@
package com.tangem.features.yield.supply.impl.main.model
+import android.os.SystemClock
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.tangem.common.routing.AppRoute.YieldSupplyPromo
@@ -35,9 +36,9 @@ import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM
import com.tangem.features.yield.supply.impl.main.model.transformers.YieldSupplyTokenStatusSuccessTransformer
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.DelayedWork
-import com.tangem.utils.transformer.update
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
+import com.tangem.utils.transformer.update
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
@@ -46,7 +47,7 @@ import timber.log.Timber
import javax.inject.Inject
import kotlin.properties.Delegates
-@Suppress("LongParameterList")
+@Suppress("LongParameterList", "LargeClass")
@ModelScoped
internal class YieldSupplyModel @Inject constructor(
paramsContainer: ParamsContainer,
@@ -72,6 +73,7 @@ internal class YieldSupplyModel @Inject constructor(
val bottomSheetNavigation: SlotNavigation = SlotNavigation()
+ private val handleNavigation = params.handleNavigation
private val cryptoCurrency = params.cryptoCurrency
var userWallet: UserWallet by Delegates.notNull()
@@ -89,10 +91,17 @@ internal class YieldSupplyModel @Inject constructor(
private var lastYieldSupplyStatus: YieldSupplyStatus? = null
private val fetchCurrencyJobHolder = JobHolder()
+ private var lastStatusCheckTimestamp = 0L
+
init {
checkIfYieldSupplyIsAvailable()
- params.handleNavigation?.let { handle ->
- if (handle) {
+
+ val protocolStatus = yieldSupplyRepository.getTokenProtocolStatus(
+ userWalletId = params.userWalletId,
+ cryptoCurrency = cryptoCurrency,
+ )
+ if (handleNavigation != null && protocolStatus == null) {
+ if (handleNavigation) {
modelScope.launch {
delay(timeMillis = 1000)
bottomSheetNavigation.activate(Unit)
@@ -193,48 +202,88 @@ internal class YieldSupplyModel @Inject constructor(
}
@Suppress("MaximumLineLength")
- private fun onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus: CryptoCurrencyStatus) {
+ private fun onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus: CryptoCurrencyStatus) = modelScope.launch {
val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus
val tokenProtocolStatus = yieldSupplyRepository.getTokenProtocolStatus(
userWallet.walletId,
cryptoCurrency,
)
+ val tokenPendingStatus = yieldSupplyRepository.getTokenPendingStatus(
+ userWallet.walletId,
+ cryptoCurrencyStatus,
+ )
+
val isActive = yieldSupplyStatus?.isActive == true
val isCryptoCurrencyStatusFromCache = cryptoCurrencyStatus.value.sources.networkSource != StatusSource.ACTUAL
val processing = uiState.value is YieldSupplyUM.Processing
Timber.d(
- "currentUiState ${uiState.value.javaClass} \n" +
- "yieldSupplyStatus $yieldSupplyStatus" +
+ "YIELD " +
+ "yieldSupplyStatus $yieldSupplyStatus " +
"tokenProtocolStatus $tokenProtocolStatus " +
+ "tokenPendingStatus $tokenPendingStatus " +
"isActive $isActive " +
"processing $processing " +
"isCryptoCurrencyStatusFromCache $isCryptoCurrencyStatusFromCache",
)
if (isCryptoCurrencyStatusFromCache && processing) {
- return
+ return@launch
}
when {
- !isActive && tokenProtocolStatus == YieldSupplyEnterStatus.Enter -> {
- uiState.update { YieldSupplyUM.Processing.Enter }
- fetchCurrencyWithDelay()
+ tokenProtocolStatus != null && tokenPendingStatus != null -> {
+ showProcessing(tokenPendingStatus)
+ lastStatusCheckTimestamp = 0L
}
- isActive && tokenProtocolStatus == YieldSupplyEnterStatus.Exit -> {
- uiState.update { YieldSupplyUM.Processing.Exit }
- fetchCurrencyWithDelay()
+ tokenProtocolStatus == YieldSupplyEnterStatus.Exit && isActive ||
+ tokenProtocolStatus == YieldSupplyEnterStatus.Enter && !isActive -> {
+ if (lastStatusCheckTimestamp != 0L) {
+ if (SystemClock.elapsedRealtime() - lastStatusCheckTimestamp > MAX_STATUS_CHECK_LIMIT) {
+ loadStatus(cryptoCurrencyStatus)
+ lastStatusCheckTimestamp = 0L
+ } else {
+ showProcessing(tokenProtocolStatus)
+ }
+ } else {
+ showProcessing(tokenProtocolStatus)
+ lastStatusCheckTimestamp = SystemClock.elapsedRealtime()
+ }
}
else -> {
+ loadStatus(cryptoCurrencyStatus)
+ lastStatusCheckTimestamp = 0L
+ }
+ }
+ }
+
+ private fun showProcessing(status: YieldSupplyEnterStatus) {
+ uiState.update {
+ when (status) {
+ YieldSupplyEnterStatus.Enter -> YieldSupplyUM.Processing.Enter
+ YieldSupplyEnterStatus.Exit -> YieldSupplyUM.Processing.Exit
+ }
+ }
+ fetchCurrencyWithDelay()
+ }
+
+ private fun loadStatus(cryptoCurrencyStatus: CryptoCurrencyStatus) {
+ val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus
+ modelScope
+ .launch {
+ yieldSupplyRepository.saveTokenProtocolStatus(
+ userWalletId = userWallet.walletId,
+ cryptoCurrency = cryptoCurrency,
+ yieldSupplyEnterStatus = null,
+ )
sendInfoAboutProtocolStatus(cryptoCurrencyStatus)
- if (isActive) {
+ if (yieldSupplyStatus?.isActive == true) {
loadActiveState(
cryptoCurrencyStatus = cryptoCurrencyStatus,
- yieldSupplyStatus = requireNotNull(yieldSupplyStatus),
+ yieldSupplyStatus = yieldSupplyStatus,
)
} else {
loadTokenStatus()
}
}
- }
}
private fun fetchCurrencyWithDelay() {
@@ -253,8 +302,8 @@ internal class YieldSupplyModel @Inject constructor(
private fun loadActiveState(cryptoCurrencyStatus: CryptoCurrencyStatus, yieldSupplyStatus: YieldSupplyStatus) {
val cryptoCurrencyToken = cryptoCurrency as? CryptoCurrency.Token ?: return
- val showWarningIcon = !yieldSupplyStatus.isAllowedToSpend ||
- cryptoCurrencyStatus.yieldSupplyNotAllAmountSupplied()
+ val showWarningIcon = !yieldSupplyStatus.isAllowedToSpend
+ val showInfoIcon = cryptoCurrencyStatus.yieldSupplyNotAllAmountSupplied()
if (!yieldSupplyStatus.isAllowedToSpend) {
analyticsEventsHandler.send(
YieldSupplyAnalytics.NoticeApproveNeeded(
@@ -282,6 +331,7 @@ internal class YieldSupplyModel @Inject constructor(
),
onClick = ::onActiveClick,
showWarningIcon = showWarningIcon,
+ showInfoIcon = showInfoIcon,
apy = tokenStatus.apy.toString(),
)
}
@@ -298,6 +348,7 @@ internal class YieldSupplyModel @Inject constructor(
rewardsApy = TextReference.EMPTY,
onClick = ::onActiveClick,
showWarningIcon = showWarningIcon,
+ showInfoIcon = showInfoIcon,
apy = "",
)
}
@@ -328,5 +379,6 @@ internal class YieldSupplyModel @Inject constructor(
private companion object {
const val PROCESSING_UPDATE_DELAY = 10_000L
+ const val MAX_STATUS_CHECK_LIMIT = 10_000L
}
}
\ No newline at end of file
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt
index 1cbf8f1cfe..df2c84d279 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt
@@ -149,12 +149,21 @@ private fun SupplyContent(supplyUM: YieldSupplyUM.Content, modifier: Modifier =
)
}
SpacerW8()
- AnimatedVisibility(supplyUM.showWarningIcon) {
- Icon(
- imageVector = ImageVector.vectorResource(R.drawable.ic_alert_triangle_20),
- contentDescription = null,
- tint = TangemTheme.colors.icon.attention,
- )
+ AnimatedContent(
+ targetState = supplyUM,
+ ) { currentState ->
+ when {
+ currentState.showWarningIcon -> Icon(
+ imageVector = ImageVector.vectorResource(R.drawable.ic_alert_triangle_20),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.attention,
+ )
+ currentState.showInfoIcon -> Icon(
+ imageVector = ImageVector.vectorResource(R.drawable.ic_alert_circle_red_20),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.accent,
+ )
+ }
}
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_right_24),
@@ -355,6 +364,7 @@ private class PreviewProvider : PreviewParameterProvider {
onClick = {},
apy = "5.1",
showWarningIcon = false,
+ showInfoIcon = true,
),
YieldSupplyUM.Content(
title = stringReference("Aave lending is active "),
@@ -363,6 +373,7 @@ private class PreviewProvider : PreviewParameterProvider {
onClick = {},
apy = "5.1",
showWarningIcon = true,
+ showInfoIcon = false,
),
YieldSupplyUM.Loading,
YieldSupplyUM.Processing.Enter,
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/promo/ui/YieldSupplyPromoContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/promo/ui/YieldSupplyPromoContent.kt
index 12359bae82..dc7127e226 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/promo/ui/YieldSupplyPromoContent.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/promo/ui/YieldSupplyPromoContent.kt
@@ -4,13 +4,16 @@ import android.content.res.Configuration
import androidx.annotation.DrawableRes
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.shape.CircleShape
import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
+import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
@@ -57,7 +60,7 @@ internal fun YieldSupplyPromoContent(
onClick = clickIntents::onUrlClick,
)
PrimaryButton(
- text = stringResourceSafe(R.string.yield_module_start_earning),
+ text = stringResourceSafe(R.string.common_continue),
onClick = clickIntents::onStartEarningClick,
modifier = Modifier
.padding(
@@ -106,7 +109,7 @@ private fun ColumnScope.Content(yieldSupplyPromoUM: YieldSupplyPromoUM, clickInt
text = yieldSupplyPromoUM.subtitle,
style = LabelStyle.REGULAR,
icon = R.drawable.ic_information_24,
- onIconClick = clickIntents::onApyInfoClick,
+ onClick = clickIntents::onApyInfoClick,
),
)
SpacerH32()
@@ -131,7 +134,11 @@ private fun YieldStatusAppBar(onBackClick: () -> Unit, onHowItWorksClick: () ->
imageVector = ImageVector.vectorResource(R.drawable.ic_back_24),
contentDescription = null,
tint = TangemTheme.colors.icon.primary1,
- modifier = Modifier.clickable(onClick = onBackClick),
+ modifier = Modifier.clickable(
+ onClick = onBackClick,
+ interactionSource = remember { MutableInteractionSource() },
+ indication = ripple(bounded = false),
+ ),
)
SpacerWMax()
Text(
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt
index 070ec52cb7..414cd7a29d 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt
@@ -195,7 +195,7 @@ internal class YieldSupplyActiveModel @Inject constructor(
blockchain = cryptoCurrency.network.name,
),
)
- NotificationUM.Warning.YieldSupplyNotAllAmountSupplied(
+ NotificationUM.Info.YieldSupplyNotAllAmountSupplied(
formattedAmount = formattedAmount,
symbol = cryptoCurrency.symbol,
)
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt
index 0654981fee..f303d4ae1e 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt
@@ -26,7 +26,10 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.notifications.NotificationUM
-import com.tangem.core.ui.components.*
+import com.tangem.core.ui.components.SpacerH4
+import com.tangem.core.ui.components.SpacerH8
+import com.tangem.core.ui.components.SpacerWMax
+import com.tangem.core.ui.components.TextShimmer
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.decompose.ComposableContentComponent
@@ -61,7 +64,7 @@ internal fun YieldSupplyActiveContent(
.padding(12.dp),
) {
CurrentApy(state.apy)
- chartComponent.Content(Modifier.padding(bottom = 12.dp))
+ chartComponent.Content(Modifier)
}
AnimatedVisibility(state.notifications.isNotEmpty()) {
@@ -71,6 +74,11 @@ internal fun YieldSupplyActiveContent(
Notification(
config = notificationUM.config,
containerColor = TangemTheme.colors.background.action,
+ iconTint = if (notificationUM is NotificationUM.Info) {
+ TangemTheme.colors.icon.accent
+ } else {
+ null
+ },
)
}
}
@@ -104,7 +112,7 @@ internal fun YieldSupplyActiveContent(
@Composable
private fun CurrentApy(apy: TextReference?, modifier: Modifier = Modifier) {
- Column(modifier = modifier.padding(vertical = 12.dp)) {
+ Column(modifier = modifier) {
Text(
modifier = Modifier,
text = stringResourceSafe(R.string.yield_module_earn_sheet_current_apy_title),
@@ -156,7 +164,11 @@ private fun YieldSupplyActiveMyFunds(
.clip(RoundedCornerShape(16.dp))
.background(TangemTheme.colors.background.action)
.fillMaxWidth()
- .padding(12.dp),
+ .padding(
+ top = 12.dp,
+ start = 12.dp,
+ end = 12.dp,
+ ),
) {
Text(
text = stringResourceSafe(R.string.yield_module_earn_sheet_my_funds_title),
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt
index ec32b8e52b..f00297a2f9 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt
@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ -91,7 +92,7 @@ internal fun YieldSupplyFeePolicyContent(
YieldSupplyFeeUM.Loading -> null
}
YieldSupplyFeeRow(
- title = resourceReference(R.string.yield_module_fee_policy_sheet_current_fee_title),
+ title = resourceReference(R.string.common_estimated_fee),
value = currentFee,
modifier = Modifier.padding(vertical = 12.dp),
)
@@ -100,6 +101,10 @@ internal fun YieldSupplyFeePolicyContent(
YieldSupplyFeeUM.Error -> stringReference(StringsSigns.DASH_SIGN)
YieldSupplyFeeUM.Loading -> null
}
+ HorizontalDivider(
+ thickness = 0.5.dp,
+ color = TangemTheme.colors.stroke.primary,
+ )
YieldSupplyFeeRow(
title = resourceReference(R.string.yield_module_fee_policy_sheet_max_fee_title),
value = maxFee,
diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt
index e890ae8bc5..95e7c4d6d1 100644
--- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt
+++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt
@@ -144,7 +144,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
val transactionListData = yieldSupplyStartEarningUseCase(
userWalletId = userWallet.walletId,
cryptoCurrencyStatus = cryptoCurrencyStatus,
- maxNetworkFee = maxFee.nativeMaxFee,
+ maxNetworkFee = maxFee.tokenMaxFee,
).getOrNull()
if (transactionListData == null) {
diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml
index 48711f2377..e06f0759db 100644
--- a/gradle/tangem_dependencies.toml
+++ b/gradle/tangem_dependencies.toml
@@ -5,7 +5,7 @@
# https://github.com/tangem/tangem-sdk-android/
# https://github.com/tangem/vico
-tangemBlockchainSdk = "develop-1301"
+tangemBlockchainSdk = "develop-1306"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-564"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt
index 88e9d25480..e60739fd69 100644
--- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt
+++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt
@@ -4,6 +4,7 @@ import com.android.build.gradle.AppExtension
import com.tangem.plugin.configuration.model.AppConfig
import com.tangem.plugin.configuration.model.BuildType
import com.tangem.plugin.configuration.utils.BuildConfigFieldFactory
+import com.tangem.plugin.configuration.utils.VersionNameProvider
import org.gradle.api.Project
import com.android.build.gradle.internal.dsl.BuildType as AndroidBuildType
@@ -29,11 +30,11 @@ private fun AppExtension.configureDefaultConfig(project: Project) {
AppConfig.versionCode
}
- versionName = if (project.hasProperty("versionName")) {
- project.property("versionName") as String
- } else {
- AppConfig.versionName
- }
+ // Get version name from property, git branch, or default config
+ val versionNameProvider = VersionNameProvider(project)
+ versionName = versionNameProvider.getVersionName()
+
+ project.logger.lifecycle("Resolved versionName: $versionName")
buildFeatures.buildConfig = true
diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/AppConfig.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/AppConfig.kt
index 5ddd7ba12d..25a86d101f 100644
--- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/AppConfig.kt
+++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/AppConfig.kt
@@ -3,8 +3,6 @@ package com.tangem.plugin.configuration.model
internal object AppConfig {
const val packageName = "com.tangem.wallet"
const val versionCode = 1
- const val versionName = "1.0.0-SNAPSHOT"
- // const val versionName = "100.0.0-SNAPSHOT" //TODO: [REDACTED_JIRA]
const val minSdkVersion = 24
const val targetSdkVersion = 35
const val compileSdkVersion = 35
diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/utils/VersionNameProvider.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/utils/VersionNameProvider.kt
new file mode 100644
index 0000000000..905d2f12e4
--- /dev/null
+++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/utils/VersionNameProvider.kt
@@ -0,0 +1,105 @@
+package com.tangem.plugin.configuration.utils
+
+import org.gradle.api.Project
+import org.gradle.api.provider.Provider
+
+/**
+ * Provides version name based on current git branch
+ */
+internal class VersionNameProvider(
+ private val project: Project,
+) {
+
+ /**
+ * Get version name for current branch.
+ * If -PversionName is provided, uses that value.
+ * Otherwise, derives version from git branch name.
+ */
+ fun getVersionName(): String {
+ // Check if versionName is provided as gradle property
+ if (project.hasProperty("versionName")) {
+ return project.property("versionName") as String
+ }
+
+ // Get current branch name using Provider API (configuration cache compatible)
+ val currentBranch = getCurrentBranchProvider().get()
+
+ // Try to extract version from branch name (releases/X.Y)
+ val versionFromBranch = extractVersionFromBranch(currentBranch)
+ if (versionFromBranch != null) {
+ return versionFromBranch
+ }
+
+ // For other branches (develop, feature/*), find latest release branch and increment minor
+ val latestReleaseBranch = findLatestReleaseBranch()
+ if (latestReleaseBranch != null) {
+ val versionFromLatest = extractVersionFromBranch(latestReleaseBranch)
+ if (versionFromLatest != null) {
+ return incrementMinorVersion(versionFromLatest)
+ }
+ }
+
+ // Fallback to default if nothing works
+ return "1.0.0-SNAPSHOT"
+ }
+
+ private fun getCurrentBranchProvider(): Provider {
+ return project.providers.exec {
+ commandLine("git", "rev-parse", "--abbrev-ref", "HEAD")
+ }.standardOutput.asText.map { it.trim() }
+ }
+
+ private fun findLatestReleaseBranch(): String? {
+ val scriptPath = project.rootProject.file("tangem-android-tools/CI/shell_scripts/find-latest-release-branch.sh")
+ if (!scriptPath.exists()) {
+ project.logger.warn("Script not found: $scriptPath")
+ return null
+ }
+
+ val currentBranch = getCurrentBranchProvider().get()
+ val outputFile = project.rootProject.file("find-latest-release-branch.output")
+
+ return try {
+ project.providers.exec {
+ commandLine("sh", scriptPath.absolutePath, currentBranch)
+ }.standardOutput.asText.get()
+
+ if (!outputFile.exists()) {
+ project.logger.warn("Script output file not found")
+ return null
+ }
+
+ outputFile.readText().trim().also { result ->
+ project.logger.lifecycle("Found latest release branch: $result")
+ outputFile.delete()
+ }
+ } catch (e: Exception) {
+ project.logger.warn("Failed to execute script: ${e.message}")
+ outputFile.delete()
+ null
+ }
+ }
+
+ private fun extractVersionFromBranch(branch: String): String? {
+ val regex = Regex("""^releases/(\d+)\.(\d+)(?:\.(\d+))?$""")
+ val matchResult = regex.find(branch) ?: return null
+
+ val major = matchResult.groupValues[1]
+ val minor = matchResult.groupValues[2]
+ val patch = matchResult.groupValues[3].ifEmpty { "0" }
+
+ return "$major.$minor.$patch"
+ }
+
+ private fun incrementMinorVersion(version: String): String {
+ val parts = version.split(".")
+ if (parts.size < 2) return version
+
+ val major = parts[0]
+ val minor = parts[1].toIntOrNull() ?: return version
+ val newMinor = minor + 1
+
+ return "$major.$newMinor.0"
+ }
+
+}
\ No newline at end of file