Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-14 12:44:16 +05:00
parent c4bbacd9c3
commit d293f60a6d
14 changed files with 60 additions and 13 deletions

View file

@ -10,10 +10,15 @@ package com.tangem.core.ui.components.bottomsheets
data class TangemBottomSheetConfig(
val isShown: Boolean,
val onDismissRequest: () -> Unit,
val dismissOnClickOutside: () -> Boolean = { true },
val content: TangemBottomSheetConfigContent,
) {
companion object {
val Empty = TangemBottomSheetConfig(false, {}, TangemBottomSheetConfigContent.Empty)
val Empty = TangemBottomSheetConfig(
isShown = false,
onDismissRequest = {},
content = TangemBottomSheetConfigContent.Empty,
)
}
}

View file

@ -88,7 +88,17 @@ inline fun <reified T : TangemBottomSheetConfigContent> DefaultModalBottomSheetW
noinline footer: @Composable (BoxScope.(T) -> Unit)?,
) {
var isVisible by remember { mutableStateOf(value = config.isShown) }
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = skipPartiallyExpanded)
val sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = skipPartiallyExpanded,
confirmValueChange = { sheetValue ->
if (config.dismissOnClickOutside().not()) {
// Ignore transitions to hidden (prevents dismiss on outside click/back press)
sheetValue != SheetValue.Hidden
} else {
true
}
},
)
if (isVisible && config.content is T) {
BasicModalBottomSheetWithFooter<T>(

View file

@ -6,7 +6,7 @@ import java.math.BigInteger
import java.math.RoundingMode
private val HUNDRED_PERCENT = 100.toBigInteger() // base 100%
val INCREASE_GAS_LIMIT_FOR_SUPPLY = 112.toBigInteger() // 12% increase
val INCREASE_GAS_LIMIT_FOR_SUPPLY = 120.toBigInteger() // 20% increase
fun Fee.fixFee(cryptoCurrency: CryptoCurrency, gasLimit: BigInteger): Fee = when (this) {
is Fee.Ethereum.Legacy -> copy(

View file

@ -314,9 +314,9 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
val deployFee = txs.first().fee as Fee.Ethereum.EIP1559
val approveFee = txs[1].fee as Fee.Ethereum.EIP1559
val enterFee = txs.last().fee as Fee.Ethereum.EIP1559
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_120))
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_240))
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_360))
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_200))
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_400))
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_600))
}
@Test
@ -353,9 +353,9 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
val deployFee = txs.first().fee as Fee.Ethereum.Legacy
val approveFee = txs[1].fee as Fee.Ethereum.Legacy
val enterFee = txs.last().fee as Fee.Ethereum.Legacy
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_120))
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_240))
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_360))
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_200))
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_400))
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_600))
}
private fun getDeployTx() = uncompiled(

View file

@ -2,6 +2,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.active
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
@ -59,9 +60,10 @@ internal class YieldSupplyActiveEntryComponent(
@Composable
override fun BottomSheet() {
val stackState by innerStack.subscribeAsState()
val isTransactionInProgress by model.isTransactionInProgressFlow.collectAsStateWithLifecycle()
YieldSupplyActiveEntryBottomSheet(
stackState = stackState,
dismissOnClickOutside = { !isTransactionInProgress },
onDismiss = ::dismiss,
)
}

View file

@ -11,6 +11,9 @@ import com.tangem.features.yield.supply.impl.subcomponents.approve.YieldSupplyAp
import com.tangem.features.yield.supply.impl.subcomponents.stopearning.YieldSupplyStopEarningComponent
import com.tangem.utils.TangemBlogUrlBuilder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import javax.inject.Inject
@ModelScoped
@ -25,15 +28,25 @@ internal class YieldSupplyActiveEntryModel @Inject constructor(
private val params = paramsContainer.require<YieldSupplyActiveEntryComponent.Params>()
val isTransactionInProgressFlow: StateFlow<Boolean>
field = MutableStateFlow(false)
override fun onStopEarning() {
router.push(YieldSupplyActiveRoute.Exit)
}
override fun onBackClick() {
router.pop()
if (!isTransactionInProgressFlow.value) {
router.pop()
}
}
override fun onTransactionProgress(inProgress: Boolean) {
isTransactionInProgressFlow.update { inProgress }
}
override fun onTransactionSent() {
isTransactionInProgressFlow.update { false }
params.onDismiss()
}

View file

@ -14,12 +14,14 @@ import com.tangem.features.yield.supply.impl.subcomponents.active.model.YieldSup
@Composable
internal fun YieldSupplyActiveEntryBottomSheet(
stackState: ChildStack<YieldSupplyActiveRoute, ComposableModularContentComponent>,
dismissOnClickOutside: () -> Boolean,
onDismiss: () -> Unit,
) {
TangemModalBottomSheetWithFooter<TangemBottomSheetConfigContent.Empty>(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = onDismiss,
dismissOnClickOutside = dismissOnClickOutside,
content = TangemBottomSheetConfigContent.Empty,
),
containerColor = TangemTheme.colors.background.tertiary,

View file

@ -106,6 +106,7 @@ internal class YieldSupplyApproveComponent(
interface ModelCallback {
fun onBackClick()
fun onTransactionProgress(inProgress: Boolean)
fun onTransactionSent()
}
}

View file

@ -117,6 +117,8 @@ internal class YieldSupplyApproveModel @Inject constructor(
}
fun onClick() {
params.callback.onTransactionProgress(true)
val yieldSupplyFeeUM = uiState.value.yieldSupplyFeeUM as? YieldSupplyFeeUM.Content ?: return
uiState.update(YieldSupplyTransactionInProgressTransformer)
@ -153,6 +155,7 @@ internal class YieldSupplyApproveModel @Inject constructor(
}
},
)
params.callback.onTransactionProgress(false)
},
ifRight = {
val event = AnalyticsParam.TxSentFrom.Earning(

View file

@ -2,6 +2,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.startearning
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
@ -56,9 +57,11 @@ internal class YieldSupplyStartEarningEntryComponent(
@Composable
override fun BottomSheet() {
val stackState by innerStack.subscribeAsState()
val uiState by model.uiState.collectAsStateWithLifecycle()
YieldSupplyStartEarningBottomSheet(
stackState = stackState,
dismissOnClickOutside = { !uiState.isTransactionSending },
onDismiss = ::dismiss,
)
}

View file

@ -8,8 +8,8 @@ import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
import com.tangem.features.yield.supply.impl.subcomponents.feepolicy.YieldSupplyFeePolicyComponent
@ -54,7 +54,9 @@ internal class YieldSupplyStartEarningEntryModel @Inject constructor(
}
override fun onBackClick() {
router.pop()
if (!uiState.value.isTransactionSending) {
router.pop()
}
}
override fun onFeePolicyClick() {

View file

@ -14,12 +14,14 @@ import com.tangem.features.yield.supply.impl.subcomponents.startearning.YieldSup
@Composable
internal fun YieldSupplyStartEarningBottomSheet(
stackState: ChildStack<YieldSupplyStartEarningRoute, ComposableModularContentComponent>,
dismissOnClickOutside: () -> Boolean,
onDismiss: () -> Unit,
) {
TangemModalBottomSheetWithFooter<TangemBottomSheetConfigContent.Empty>(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = onDismiss,
dismissOnClickOutside = dismissOnClickOutside,
content = TangemBottomSheetConfigContent.Empty,
),
containerColor = TangemTheme.colors.background.tertiary,

View file

@ -107,6 +107,7 @@ internal class YieldSupplyStopEarningComponent(
interface ModelCallback {
fun onBackClick()
fun onTransactionProgress(inProgress: Boolean)
fun onTransactionSent()
}
}

View file

@ -126,6 +126,8 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
}
fun onClick() {
params.callback.onTransactionProgress(true)
val yieldSupplyFeeUM = uiState.value.yieldSupplyFeeUM as? YieldSupplyFeeUM.Content ?: return
analytics.send(
YieldSupplyAnalytics.ButtonStopEarning(
@ -163,6 +165,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
}
},
)
params.callback.onTransactionProgress(false)
},
ifRight = {
onStopEarningTransactionSuccess()