Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-30 14:08:26 +03:00
parent 07304621a9
commit 4afbb72f6d
8 changed files with 48 additions and 27 deletions

View file

@ -42,6 +42,7 @@ enum class ApproveType(val text: TextReference) {
data class ApprovePermissionButton(
val isEnabled: Boolean,
val isLoading: Boolean = false,
val isHoldToConfirm: Boolean = false,
val onClick: () -> Unit,
)

View file

@ -15,6 +15,7 @@ interface GiveApprovalComponent : ComposableBottomSheetComponent {
val amount: String,
val spenderAddress: String,
val subtitle: TextReference,
val isHoldToConfirm: Boolean = false,
val callback: Callback,
)

View file

@ -86,6 +86,7 @@ internal class DefaultGiveApprovalComponent @AssistedInject constructor(
walletInteractionIcon = uiState.walletInteractionIcon,
isApproveEnabled = uiState.isApproveButtonEnabled,
isApproveLoading = uiState.isApproveLoading,
isHoldToConfirm = uiState.isHoldToConfirm,
onApproveClick = model::onApproveClick,
onCancelClick = model::onCancelClick,
onOpenLearnMoreAboutApproveClick = model::onOpenLearnMoreAboutApproveClick,

View file

@ -76,6 +76,7 @@ internal class GiveApprovalModel @Inject constructor(
walletInteractionIcon = walletInterationIcon(userWallet),
isApproveButtonEnabled = false,
isApproveLoading = false,
isHoldToConfirm = params.isHoldToConfirm,
),
)

View file

@ -11,4 +11,5 @@ internal data class GiveApprovalUM(
@DrawableRes val walletInteractionIcon: Int?,
val isApproveButtonEnabled: Boolean,
val isApproveLoading: Boolean,
val isHoldToConfirm: Boolean = false,
)

View file

@ -48,6 +48,7 @@ internal fun GiveApprovalContent(
walletInteractionIcon: Int?,
isApproveEnabled: Boolean,
isApproveLoading: Boolean,
isHoldToConfirm: Boolean,
onApproveClick: () -> Unit,
onCancelClick: () -> Unit,
onOpenLearnMoreAboutApproveClick: () -> Unit,
@ -81,16 +82,28 @@ internal fun GiveApprovalContent(
SpacerH(height = TangemTheme.dimens.spacing20)
PrimaryButtonIconEnd(
text = stringResourceSafe(id = CommonUiR.string.common_approve),
iconResId = walletInteractionIcon,
showProgress = isApproveLoading,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing16),
onClick = onApproveClick,
enabled = isApproveEnabled,
)
if (isHoldToConfirm) {
HoldToConfirmButton(
text = stringResourceSafe(id = CommonUiR.string.common_approve),
enabled = isApproveEnabled,
isLoading = isApproveLoading,
onConfirm = onApproveClick,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing16),
)
} else {
PrimaryButtonIconEnd(
text = stringResourceSafe(id = CommonUiR.string.common_approve),
iconResId = walletInteractionIcon,
showProgress = isApproveLoading,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing16),
onClick = onApproveClick,
enabled = isApproveEnabled,
)
}
SpacerH12()
@ -309,6 +322,7 @@ private fun GiveApprovalContentPreview(
walletInteractionIcon = params.walletInteractionIcon,
isApproveEnabled = params.isApproveEnabled,
isApproveLoading = params.isApproveLoading,
isHoldToConfirm = false,
onApproveClick = {},
onCancelClick = {},
onOpenLearnMoreAboutApproveClick = {},

View file

@ -1497,6 +1497,7 @@ internal class StakingModel @Inject constructor(
id = R.string.give_permission_staking_subtitle,
formatArgs = wrappedList(cryptoCurrencyStatus.currency.symbol),
),
isHoldToConfirm = value.shouldShowHoldToConfirmButton,
callback = approvalCallback,
)
}

View file

@ -44,8 +44,10 @@ internal class SetButtonsStateTransformer(
val isConfirmation = prevState.currentStep == StakingStep.Confirmation
val isInProgress = innerConfirmState == InnerConfirmationStakingState.IN_PROGRESS
val isCompleted = innerConfirmState == InnerConfirmationStakingState.COMPLETED
val isApprovalRequired = prevState.isApprovalRequired()
val isHoldToConfirm = prevState.shouldShowHoldToConfirmButton && isConfirmation && !isCompleted
val isHoldToConfirm = prevState.shouldShowHoldToConfirmButton &&
isConfirmation && !isCompleted && !isApprovalRequired
val isIconVisible = isConfirmation && !isCompleted && !isHoldToConfirm
val isPrimaryButtonDisabled = prevState.isPrimaryButtonDisabled()
return NavigationButton(
@ -114,14 +116,9 @@ internal class SetButtonsStateTransformer(
private fun StakingUiState.getConfirmationButtonText(): TextReference {
val confirmationState = confirmationState as? StakingStates.ConfirmationState.Data
?: return resourceReference(R.string.common_close)
val amountState = amountState as? AmountState.Data
?: return resourceReference(R.string.common_close)
if (actionType is StakingActionCommonType.Enter) {
val amount = amountState.amountTextField.cryptoAmount.value.orZero()
if (confirmationState.isApprovalNeeded && confirmationState.allowance < amount) {
return resourceReference(R.string.give_permission_title)
}
if (isApprovalRequired()) {
return resourceReference(R.string.give_permission_title)
}
return getBaseActionText(confirmationState)
@ -151,18 +148,13 @@ internal class SetButtonsStateTransformer(
private fun StakingUiState.onConfirmationClick() {
val confirmationState = confirmationState as? StakingStates.ConfirmationState.Data
val amountState = amountState as? AmountState.Data
if (confirmationState != null && amountState != null) {
if (confirmationState != null) {
if (confirmationState.innerState == InnerConfirmationStakingState.COMPLETED) {
clickIntents.onNextClick()
} else if (isApprovalRequired()) {
clickIntents.showApprovalBottomSheet()
} else {
val amount = amountState.amountTextField.cryptoAmount.value.orZero()
val isEnterAction = actionType is StakingActionCommonType.Enter
if (isEnterAction && confirmationState.isApprovalNeeded && confirmationState.allowance < amount) {
clickIntents.showApprovalBottomSheet()
} else {
clickIntents.onActionClick()
}
clickIntents.onActionClick()
}
} else {
clickIntents.onBackClick()
@ -177,6 +169,15 @@ internal class SetButtonsStateTransformer(
return !hasNotStaking && isCardano && currentStep == StakingStep.InitialInfo
}
private fun StakingUiState.isApprovalRequired(): Boolean {
val confirmState = confirmationState as? StakingStates.ConfirmationState.Data ?: return false
val amountState = amountState as? AmountState.Data ?: return false
val amount = amountState.amountTextField.cryptoAmount.value.orZero()
return actionType is StakingActionCommonType.Enter &&
confirmState.isApprovalNeeded &&
confirmState.allowance < amount
}
private fun StakingUiState.isButtonEnabled(): Boolean {
return when (currentStep) {
StakingStep.InitialInfo -> initialInfoState.isPrimaryButtonEnabled