Updated on 2026-08-14

This commit is contained in:
Tangem 2024-03-29 21:14:04 +05:00
commit 78147170d2
14 changed files with 114 additions and 123 deletions

View file

@ -425,7 +425,7 @@
<string name="scan_card_settings_title">Приготовьте свою карту</string>
<string name="send_additional_field_already_included">Уже содержится в введенном адресе</string>
<string name="send_alert_fee_coverage_subract_text">Вычесть</string>
<string name="send_alert_fee_coverage_title">Недостаточно средств для покрытия комиссии сети. Вычесть комиссию из отправляемой сумму?</string>
<string name="send_alert_fee_coverage_title">Недостаточно средств для покрытия комиссии сети. Вычесть комиссию %s из отправляемой сумму?</string>
<string name="send_alert_fee_too_low_text">Вы указали комиссию ниже рекомендуемой, это может привести к задержке исполнения вашей транзакции. Продолжить?</string>
<string name="send_alert_transaction_failed_text">Причина: %1$s\nКод: %2$s</string>
<string name="send_alert_transaction_failed_title">Транзакция не выполнена</string>

View file

@ -421,7 +421,7 @@
<string name="scan_card_settings_title">Get your card ready!</string>
<string name="send_additional_field_already_included">Already included in the entered address</string>
<string name="send_alert_fee_coverage_subract_text">Subtract</string>
<string name="send_alert_fee_coverage_title">Not enough funds to cover the network commission. Subtract the commission from the amount sent?</string>
<string name="send_alert_fee_coverage_title">Not enough funds to cover the network commission. Subtract the commission %s from the amount sent?</string>
<string name="send_alert_fee_too_low_text">You specified a commission below the recommended amount, which could cause a delay in your transaction. Continue?</string>
<string name="send_alert_transaction_failed_text">Reason: %1$s\nCode: %2$s</string>
<string name="send_alert_transaction_failed_title">The transaction is not completed</string>

View file

@ -45,6 +45,7 @@ fun AppBarWithBackButtonAndIconContent(
) {
Row(
modifier = modifier
.height(TangemTheme.dimens.size56)
.background(color = backgroundColor)
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing16),

View file

@ -59,10 +59,12 @@ internal sealed class SendAlertState {
}
data class FeeCoverage(
val amount: String,
override val onConfirmClick: (() -> Unit),
) : SendAlertState() {
override val title: TextReference? = null
override val message: TextReference = resourceReference(id = R.string.send_alert_fee_coverage_title)
override val message: TextReference =
resourceReference(id = R.string.send_alert_fee_coverage_title, wrappedList(amount))
override val confirmButtonText: TextReference =
resourceReference(id = R.string.send_alert_fee_coverage_subract_text)
}

View file

@ -3,6 +3,7 @@ package com.tangem.features.send.impl.presentation.state
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.event.triggeredEvent
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.transaction.error.SendTransactionError
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
import com.tangem.features.send.impl.presentation.state.fee.FeeStateFactory
@ -45,10 +46,17 @@ internal class SendEventStateFactory(
fun getFeeCoverageAlert(onConsume: () -> Unit): SendUiState {
val state = currentStateProvider()
val amount = state.feeState?.fee?.amount ?: return state
val feeAmount = BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = amount.value,
cryptoCurrency = state.cryptoCurrencySymbol,
decimals = amount.decimals,
)
return state.copy(
event = triggeredEvent(
data = SendEvent.ShowAlert(
SendAlertState.FeeCoverage(
amount = feeAmount,
onConfirmClick = clickIntents::onSubtractSelect,
),
),

View file

@ -95,6 +95,11 @@ internal sealed class SendNotification(val config: NotificationConfig) {
)
},
)
data class ExistentialDeposit(val deposit: String) : Error(
title = resourceReference(R.string.send_notification_existential_deposit_title),
subtitle = resourceReference(R.string.send_notification_existential_deposit_text, wrappedList(deposit)),
)
}
sealed class Warning(
@ -125,11 +130,6 @@ internal sealed class SendNotification(val config: NotificationConfig) {
onCloseClick = onCloseClick,
)
data class ExistentialDeposit(val deposit: String) : Warning(
title = resourceReference(R.string.send_notification_existential_deposit_title),
subtitle = resourceReference(R.string.send_notification_existential_deposit_text, wrappedList(deposit)),
)
data object FeeTooLow : Warning(
title = resourceReference(id = R.string.send_notification_transaction_delay_title),
subtitle = resourceReference(id = R.string.send_notification_transaction_delay_text),

View file

@ -105,6 +105,6 @@ enum class SendUiStateType {
None,
Recipient,
Amount,
Fee,
Send,
Fee,
}

View file

@ -213,7 +213,7 @@ internal class SendNotificationFactory(
)
if (currencyDeposit != null && currencyDeposit > spendingAmount) {
add(
SendNotification.Warning.ExistentialDeposit(
SendNotification.Error.ExistentialDeposit(
BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = currencyDeposit,
cryptoCurrency = cryptoCurrency,

View file

@ -1,19 +1,14 @@
package com.tangem.features.send.impl.presentation.ui.amount
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.presentation.state.SendNotification
import com.tangem.features.send.impl.presentation.state.SendStates
import com.tangem.features.send.impl.presentation.ui.common.notifications
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import kotlinx.collections.immutable.ImmutableList
@Composable
internal fun SendAmountContent(
@ -35,29 +30,4 @@ internal fun SendAmountContent(
)
notifications(amountState.notifications)
}
}
@OptIn(ExperimentalFoundationApi::class)
internal fun LazyListScope.notifications(configs: ImmutableList<SendNotification>, modifier: Modifier = Modifier) {
items(
items = configs,
key = { it::class.java },
contentType = { it::class.java },
itemContent = {
val bottomPadding = if (it == configs.last()) TangemTheme.dimens.spacing12 else TangemTheme.dimens.spacing0
Notification(
config = it.config,
modifier = modifier
.animateItemPlacement()
.padding(
top = TangemTheme.dimens.spacing12,
bottom = bottomPadding,
),
containerColor = when (it) {
is SendNotification.Warning.NetworkFeeUnreachable -> TangemTheme.colors.background.action
else -> TangemTheme.colors.button.disabled
},
)
},
)
}

View file

@ -0,0 +1,58 @@
package com.tangem.features.send.impl.presentation.ui.common
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.presentation.state.SendNotification
import kotlinx.collections.immutable.ImmutableList
@OptIn(ExperimentalFoundationApi::class)
internal fun LazyListScope.notifications(
notifications: ImmutableList<SendNotification>,
modifier: Modifier = Modifier,
hasPaddingAbove: Boolean = false,
) {
itemsIndexed(
items = notifications,
key = { _, item -> item::class.java },
contentType = { _, item -> item::class.java },
itemContent = { i, item ->
val bottomPadding = if (i == notifications.lastIndex) {
TangemTheme.dimens.spacing12
} else {
TangemTheme.dimens.spacing0
}
val topPadding = if (i == 0 && hasPaddingAbove) {
TangemTheme.dimens.spacing0
} else {
TangemTheme.dimens.spacing12
}
Notification(
config = item.config,
modifier = modifier
.padding(
top = topPadding,
bottom = bottomPadding,
)
.animateItemPlacement(),
containerColor = when (item) {
is SendNotification.Error.ExceedsBalance,
is SendNotification.Warning.NetworkFeeUnreachable,
is SendNotification.Warning.HighFeeError,
-> TangemTheme.colors.background.action
else -> TangemTheme.colors.button.disabled
},
iconTint = when (item) {
is SendNotification.Error.ExceedsBalance,
is SendNotification.Warning,
-> null
is SendNotification.Error -> TangemTheme.colors.icon.warning
},
)
},
)
}

View file

@ -1,9 +1,10 @@
package com.tangem.features.send.impl.presentation.ui.fee
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.inputrow.InputRowEnterAmount
@ -24,6 +25,8 @@ internal fun SendCustomFeeEthereum(
AnimatedVisibility(
visible = selectedFee == FeeType.Custom && customValues.isNotEmpty(),
label = "Custom Fee Selected Animation",
enter = expandVertically().plus(fadeIn()),
exit = shrinkVertically().plus(fadeOut()),
) {
Column(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
@ -31,8 +34,14 @@ internal fun SendCustomFeeEthereum(
) {
repeat(customValues.size) { index ->
val value = customValues[index]
val bottomPadding = if (index == customValues.lastIndex) {
TangemTheme.dimens.spacing12
} else {
TangemTheme.dimens.spacing0
}
FooterContainer(
footer = value.footer.resolveReference(),
modifier = Modifier.padding(bottom = bottomPadding),
) {
if (value.label != null) {
InputRowEnterInfoAmount(

View file

@ -7,16 +7,14 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.presentation.state.SendNotification
import com.tangem.features.send.impl.presentation.state.SendStates
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
import com.tangem.features.send.impl.presentation.state.fee.FeeType
import com.tangem.features.send.impl.presentation.ui.common.notifications
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import kotlinx.collections.immutable.ImmutableList
private const val FEE_SELECTOR_KEY = "FEE_SELECTOR_KEY"
private const val FEE_CUSTOM_KEY = "FEE_CUSTOM_KEY"
@ -24,7 +22,8 @@ private const val FEE_CUSTOM_KEY = "FEE_CUSTOM_KEY"
@Composable
internal fun SendSpeedAndFeeContent(state: SendStates.FeeState?, clickIntents: SendClickIntents) {
if (state == null) return
val feeSendState = state.feeSelectorState
val feeSendState = state.feeSelectorState as? FeeSelectorState.Content
val isCustomSelected = feeSendState?.selectedFee == FeeType.Custom
val notifications = state.notifications
LazyColumn(
modifier = Modifier
@ -35,8 +34,10 @@ internal fun SendSpeedAndFeeContent(state: SendStates.FeeState?, clickIntents: S
),
) {
feeSelector(state, clickIntents)
customFee(feeSendState)
notifications(notifications)
if (feeSendState != null) {
customFee(feeSendState)
}
notifications(notifications = notifications, hasPaddingAbove = isCustomSelected)
}
}
@ -54,45 +55,18 @@ private fun LazyListScope.feeSelector(state: SendStates.FeeState, clickIntents:
}
@OptIn(ExperimentalFoundationApi::class)
private fun LazyListScope.notifications(configs: ImmutableList<SendNotification>, modifier: Modifier = Modifier) {
items(
items = configs,
key = { it::class.java },
contentType = { it::class.java },
itemContent = {
val bottomPadding = if (it == configs.last()) TangemTheme.dimens.spacing12 else TangemTheme.dimens.spacing0
Notification(
config = it.config,
modifier = modifier
.padding(
top = TangemTheme.dimens.spacing12,
bottom = bottomPadding,
)
.animateItemPlacement(),
containerColor = when (it) {
is SendNotification.Warning.NetworkFeeUnreachable -> TangemTheme.colors.background.action
else -> TangemTheme.colors.button.disabled
},
)
},
)
}
@OptIn(ExperimentalFoundationApi::class)
internal fun LazyListScope.customFee(feeSendState: FeeSelectorState, modifier: Modifier = Modifier) {
if (feeSendState is FeeSelectorState.Content) {
item(
key = FEE_CUSTOM_KEY,
) {
SendCustomFeeEthereum(
customValues = feeSendState.customValues,
selectedFee = feeSendState.selectedFee,
modifier = modifier
.fillMaxWidth()
.animateItemPlacement()
.background(TangemTheme.colors.background.tertiary)
.padding(top = TangemTheme.dimens.spacing12),
)
}
internal fun LazyListScope.customFee(feeSendState: FeeSelectorState.Content, modifier: Modifier = Modifier) {
item(
key = FEE_CUSTOM_KEY,
) {
SendCustomFeeEthereum(
customValues = feeSendState.customValues,
selectedFee = feeSendState.selectedFee,
modifier = modifier
.fillMaxWidth()
.animateItemPlacement()
.background(TangemTheme.colors.background.tertiary)
.padding(top = TangemTheme.dimens.spacing12),
)
}
}

View file

@ -61,7 +61,6 @@ internal fun SendRecipientContent(uiState: SendStates.RecipientState?, clickInte
isLoading = isValidating,
error = address.error,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing4)
.background(
color = TangemTheme.colors.background.action,
shape = TangemTheme.shapes.roundedCornersXMedium,

View file

@ -7,7 +7,6 @@ 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.items
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -18,13 +17,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.R
import com.tangem.features.send.impl.presentation.state.SendNotification
import com.tangem.features.send.impl.presentation.state.SendUiState
import kotlinx.collections.immutable.ImmutableList
import com.tangem.features.send.impl.presentation.ui.common.notifications
import kotlinx.coroutines.delay
private const val TAP_HELP_KEY = "TAP_HELP_KEY"
@ -39,7 +36,6 @@ internal fun SendContent(uiState: SendUiState) {
modifier = Modifier
.fillMaxSize()
.padding(horizontal = TangemTheme.dimens.spacing16),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
blocks(uiState)
tapHelp(isDisplay = sendState.showTapHelp)
@ -109,7 +105,8 @@ private fun LazyListScope.tapHelp(isDisplay: Boolean, modifier: Modifier = Modif
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.fillMaxWidth()
.animateItemPlacement(),
.animateItemPlacement()
.padding(top = TangemTheme.dimens.spacing20),
) {
val background = TangemTheme.colors.button.secondary
Icon(
@ -133,31 +130,4 @@ private fun LazyListScope.tapHelp(isDisplay: Boolean, modifier: Modifier = Modif
}
}
}
}
@OptIn(ExperimentalFoundationApi::class)
internal fun LazyListScope.notifications(configs: ImmutableList<SendNotification>, modifier: Modifier = Modifier) {
items(
items = configs,
key = { it::class.java },
contentType = { it::class.java },
itemContent = {
Notification(
config = it.config,
modifier = modifier.animateItemPlacement(),
containerColor = when (it) {
is SendNotification.Error.ExceedsBalance,
is SendNotification.Warning.HighFeeError,
-> TangemTheme.colors.background.action
else -> TangemTheme.colors.button.disabled
},
iconTint = when (it) {
is SendNotification.Error.ExceedsBalance,
is SendNotification.Warning,
-> null
is SendNotification.Error -> TangemTheme.colors.icon.warning
},
)
},
)
}