Updated on 2026-08-14

This commit is contained in:
Tangem 2024-04-02 15:16:15 +05:00
commit d05b884698
13 changed files with 114 additions and 32 deletions

View file

@ -368,6 +368,7 @@
<string name="organize_tokens_sort_by_balance">По балансу</string>
<string name="organize_tokens_title">Сортировка токенов</string>
<string name="organize_tokens_ungroup">Список</string>
<string name="qr_scanner_camera_denied_gallery_button">Выбрать из галереи</string>
<string name="rate_app_sheet_title">Нравится наше приложение?</string>
<string name="receive_bottom_sheet_warning_message">%1$s (%2$s) в сети %3$s</string>
<string name="receive_bottom_sheet_warning_message_full">Отправляйте только %s на этот адрес. Использование другой сети может привести к утрате средств.</string>
@ -444,17 +445,23 @@
<string name="send_fee_picker_low">Низкая</string>
<string name="send_fee_picker_normal">Нормальная</string>
<string name="send_fee_picker_priority">Приоритетная</string>
<string name="send_fee_unreachable_error_text">Проверьте своё интернет соединение</string>
<string name="send_fee_unreachable_error_title">Информация о комиссии сети недоступна</string>
<string name="send_from_wallet_android">Из</string>
<string name="send_gas_limit">Лимит газа</string>
<string name="send_gas_limit_footer">Это максимальное количество газа, которое будет потрачено на выполнение транзакции или контракта. Лимит газа предотвращает неожиданные или неограниченные расходы при выполнении транзакции.</string>
<string name="send_gas_price">Цена газа</string>
<string name="send_gas_price_footer">Цена газа влияет на скорость транзакции. При сильно низкой, транзакция может быть не обработана.</string>
<string name="send_gas_price_footer">Это стоимость, которую вы готовы заплатить за каждую единицу газа. Чем выше цена газа, тем быстрее ваша транзакция будет обработана.</string>
<string name="send_max_amount">Всё</string>
<string name="send_max_amount_label">Максимальная сумма</string>
<string name="send_max_fee">Комиссия не превысит </string>
<string name="send_max_fee_footer">Максимальная cумма комиссии</string>
<string name="send_max_fee_footer">Комиссия, которая будет взята за вашу транзакцию. Вы можете выставить своё собственное значение.</string>
<string name="send_network_fee_warning_content">Сумма отправки будет уменьшена на %1$s для покрытия выбранного уровня комиссии. Получателю будет отправлено %2$s.</string>
<string name="send_network_fee_warning_title">Покрытие сетевой комиссии</string>
<string name="send_notification_exceed_balance_text">Недостаточно средств для перевода, так как сумма комиссии и сумма перевода в совокупности больше имеющегося баланса</string>
<string name="send_notification_exceed_balance_title">Недостаточно средств</string>
<string name="send_notification_existential_deposit_text">Аккаунт будет удален из блокчейна, если баланс упадет ниже экзистенциального депозита. Пожалуйста, убедитесь, что остаток после отправки будет не менее %s.</string>
<string name="send_notification_existential_deposit_title">Экзистенциальный депозит</string>
<string name="send_notification_fee_too_high_text">Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна.</string>
<string name="send_notification_fee_too_high_title">Установлена высокая комиссия</string>
<string name="send_notification_high_fee_text">Комиссия при переводе всего баланса выше. Для того, чтобы снизить комиссию Вы можете оставить %s.</string>
@ -471,12 +478,18 @@
<string name="send_notification_transaction_limit_text">Из-за ограничений %1$s в одну транзакцию может поместиться только %2$s UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму.</string>
<string name="send_notification_transaction_limit_title">Лимит транзакции</string>
<string name="send_optional_field">Необязательное</string>
<string name="send_qrcode_scan_info">Пожалуйста, совместите свой QR-код с квадратом, чтобы отсканировать его. Убедитесь, что вы сканируете адрес в сети %s.</string>
<string name="send_recent_transactions">Последние</string>
<string name="send_recipient">Получатель</string>
<string name="send_recipient_address_error">Неверный адрес</string>
<string name="send_recipient_address_footer">Убедитесь, что вы отправляете средства на адрес кошелька %s. Ошибки могут привести к потере ваших токенов</string>
<string name="send_recipient_label">Отправить</string>
<string name="send_recipient_memo_footer">Мемо/ Код назначения - это код, разделяющий транзакции к общему получателю в сети криптовалют. Внимание: отсутствие мемо может привести к потере средств.</string>
<string name="send_recipient_wallets_title">Мои кошельки</string>
<string name="send_sending">Отправка</string>
<string name="send_summary_tap_hint">Нажмите на любое поле, чтобы изменить его</string>
<string name="send_summary_title">Отправка %s</string>
<string name="send_summary_transaction_description">Вы отправляете %1$s, включая комиссию сети %2$s</string>
<string name="send_title_currency_format">Отправка %s</string>
<string name="send_total_label">Всего</string>
<string name="send_total_subtitle_asset_format">%1$s и %2$s будет отправлено</string>
@ -484,6 +497,7 @@
<string name="send_total_subtitle_format">%s будет отправлено</string>
<string name="send_transaction_success">Транзакция успешно подписана и отправлена в блокчейн. Баланс будет обновлен через некоторое время</string>
<string name="send_validation_invalid_address">Неверный адрес</string>
<string name="sent_transaction_sent_title">Транзакция отправлена</string>
<string name="story_awe_description">Держите свои криптосбережения в безопасности. Приватные ключи надежно хранятся на карте.</string>
<string name="story_awe_title">Революционный аппаратный кошелек</string>
<string name="story_backup_description">До трех карт с одним кошельком</string>
@ -521,6 +535,11 @@
<string name="toast_balances_hidden">Балансы скрыты</string>
<string name="toast_balances_shown">Балансы показаны</string>
<string name="toast_undo">Отменить</string>
<string name="token_button_unavailability_reason_buy_unavailable">В данный момент покупка монеты %s недоступна. Но мы работаем над её добавлением.”</string>
<string name="token_button_unavailability_reason_empty_balance">У вас нет средств для отправки. Пополните счет, чтобы иметь возможность отправить с него средства.</string>
<string name="token_button_unavailability_reason_no_quotes">Выбранная операция в данный момент недоступна. Попробуйте позже.</string>
<string name="token_button_unavailability_reason_not_exchangeable">Обмен %s не доступен. Но мы работаем над его добавлением.</string>
<string name="token_button_unavailability_reason_sell_unavailable">В данный момент продажа монеты %s недоступна. Но мы работаем над её добавлением.</string>
<string name="token_details_generate_xpub">Сгенерировать XPUB</string>
<string name="token_details_hide_alert_hide">Скрыть</string>
<string name="token_details_hide_alert_message">Вы скрываете токен с главного экрана, но в любой момент сможете добавить его обратно через страницу управления токенами.</string>

View file

@ -444,13 +444,13 @@
<string name="send_fee_unreachable_error_title">Network fee info unreachable</string>
<string name="send_from_wallet_android">From</string>
<string name="send_gas_limit">Gas limit</string>
<string name="send_gas_limit_footer">Gas Limit is auto-calculated; raise it during network congestion</string>
<string name="send_gas_limit_footer">This is the maximum amount of gas that will be spent to complete a transaction or contract. A gas limit prevents unexpected or unlimited charges when executing a transaction.</string>
<string name="send_gas_price">Gas price</string>
<string name="send_gas_price_footer">Gas Price affects transaction speed. If it\'s too low, the transaction might not be processed</string>
<string name="send_gas_price_footer">This is the cost you are willing to pay for each unit of gas. The higher the gas price, the faster your transaction will be processed.</string>
<string name="send_max_amount">Max</string>
<string name="send_max_amount_label">Maximum amount</string>
<string name="send_max_fee">Max fee</string>
<string name="send_max_fee_footer">Maximum fee amount</string>
<string name="send_max_fee_footer">The fee that will be charged for your transaction. You can set your own value.</string>
<string name="send_memo_destination_tag_error">Numbers only for Destination Tag</string>
<string name="send_network_fee_warning_content">Sending amount will be reduced by %1$s to cover the selected commission level. The recipient will get %2$s.</string>
<string name="send_network_fee_warning_title">Network fee coverage</string>
@ -532,6 +532,11 @@
<string name="toast_balances_hidden">Balances hidden</string>
<string name="toast_balances_shown">Balances shown</string>
<string name="toast_undo">Undo</string>
<string name="token_button_unavailability_reason_buy_unavailable">The purchase of the %s is currently unavailable. But we are working on adding it.</string>
<string name="token_button_unavailability_reason_empty_balance">You do not have funds to send. Top up your account to be able to send funds from it.</string>
<string name="token_button_unavailability_reason_no_quotes">This operation is currently unavailable. Please try again later.</string>
<string name="token_button_unavailability_reason_not_exchangeable">%s swap is not available. But we are working on adding it.</string>
<string name="token_button_unavailability_reason_sell_unavailable">Sell of the %s coin is currently unavailable. But we are working on adding it.</string>
<string name="token_details_generate_xpub">Generate XPUB</string>
<string name="token_details_hide_alert_hide">Hide</string>
<string name="token_details_hide_alert_message">You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page.</string>

View file

@ -125,6 +125,7 @@ data class TangemDimens internal constructor(
val spacing56: Dp = 56.dp,
val spacing60: Dp = 60.dp,
val spacing70: Dp = 70.dp,
val spacing72: Dp = 72.dp,
val spacing76: Dp = 76.dp,
val spacing80: Dp = 80.dp,
val spacing92: Dp = 92.dp,

View file

@ -31,13 +31,17 @@ import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.state.SendUiStateType
@Composable
internal fun SendNavigationButtons(uiState: SendUiState, currentState: SendUiCurrentScreen) {
internal fun SendNavigationButtons(
uiState: SendUiState,
currentState: SendUiCurrentScreen,
modifier: Modifier = Modifier,
) {
val sendState = uiState.sendState ?: return
val isSuccess = sendState.isSuccess
val isSendingState = currentState.type == SendUiStateType.Send && !isSuccess
val isSentState = currentState.type == SendUiStateType.Send && isSuccess
Column(
modifier = Modifier
modifier = modifier
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,

View file

@ -74,13 +74,17 @@ internal fun SendScreen(uiState: SendUiState, currentStateFlow: StateFlow<SendUi
backgroundColor = TangemTheme.colors.background.tertiary,
modifier = Modifier.height(TangemTheme.dimens.size56),
)
SendScreenContent(
uiState = uiState,
currentState = currentState.value,
modifier = Modifier
.weight(1f),
)
SendNavigationButtons(uiState, currentState.value)
Box(modifier = Modifier.weight(1f)) {
SendScreenContent(
uiState = uiState,
currentState = currentState.value,
)
SendNavigationButtons(
uiState = uiState,
currentState = currentState.value,
modifier = Modifier.align(Alignment.BottomCenter),
)
}
}
SendEventEffect(

View file

@ -3,8 +3,7 @@ package com.tangem.features.send.impl.presentation.ui.amount
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.BottomCenter
@ -22,15 +21,15 @@ import com.tangem.core.ui.utils.rememberDecimalFormat
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
@Composable
internal fun AmountField(sendField: SendTextField.AmountField, isFiat: Boolean, isEnabled: Boolean) {
internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolean) {
val decimalFormat = rememberDecimalFormat()
val (primaryValue, secondaryValue) = if (isFiat) {
val (primaryValue, secondaryValue) = if (sendField.isFiatValue) {
sendField.fiatValue to sendField.value
} else {
sendField.value to sendField.fiatValue
}
val (primaryAmount, secondaryAmount) = if (isFiat) {
val (primaryAmount, secondaryAmount) = if (sendField.isFiatValue) {
sendField.fiatAmount to sendField.cryptoAmount
} else {
sendField.cryptoAmount to sendField.fiatAmount
@ -48,13 +47,15 @@ internal fun AmountField(sendField: SendTextField.AmountField, isFiat: Boolean,
textAlign = TextAlign.Center,
),
isEnabled = isEnabled,
isAutoResize = true,
placeholderAlignment = TopCenter,
modifier = Modifier
.padding(
top = TangemTheme.dimens.spacing24,
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
),
)
.requiredHeightIn(min = TangemTheme.dimens.size32),
)
Box(

View file

@ -62,7 +62,6 @@ internal fun LazyListScope.amountField(
)
AmountField(
sendField = amountState.amountTextField,
isFiat = amountState.amountTextField.isFiatValue,
isEnabled = !amountState.isFeeLoading,
)
}

View file

@ -5,8 +5,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.impl.presentation.state.SendStates
import com.tangem.features.send.impl.presentation.state.previewdata.AmountStatePreviewData
import com.tangem.features.send.impl.presentation.state.previewdata.SendClickIntentsStub
import com.tangem.features.send.impl.presentation.ui.common.notifications
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
@ -30,4 +35,41 @@ internal fun SendAmountContent(
)
notifications(amountState.notifications)
}
}
}
// region Preview
@Preview
@Composable
private fun AmountFieldPreview_Light(
@PreviewParameter(AmountFieldPreviewProvider::class) amountState: SendStates.AmountState,
) {
TangemTheme {
SendAmountContent(
amountState = amountState,
isBalanceHiding = false,
clickIntents = SendClickIntentsStub,
)
}
}
@Preview
@Composable
private fun AmountFieldPreview_Dark(
@PreviewParameter(AmountFieldPreviewProvider::class) amountState: SendStates.AmountState,
) {
TangemTheme(isDark = true) {
SendAmountContent(
amountState = amountState,
isBalanceHiding = false,
clickIntents = SendClickIntentsStub,
)
}
}
private class AmountFieldPreviewProvider : PreviewParameterProvider<SendStates.AmountState> {
override val values: Sequence<SendStates.AmountState>
get() = sequenceOf(
AmountStatePreviewData.amountState,
)
}
// endregion

View file

@ -22,7 +22,7 @@ internal fun LazyListScope.notifications(
contentType = { _, item -> item::class.java },
itemContent = { i, item ->
val bottomPadding = if (i == notifications.lastIndex) {
TangemTheme.dimens.spacing12
TangemTheme.dimens.spacing72
} else {
TangemTheme.dimens.spacing0
}

View file

@ -20,6 +20,7 @@ import kotlinx.collections.immutable.ImmutableList
internal fun SendCustomFeeEthereum(
customValues: ImmutableList<SendTextField.CustomFee>,
selectedFee: FeeType,
hasNotifications: Boolean,
modifier: Modifier = Modifier,
) {
AnimatedVisibility(
@ -34,8 +35,8 @@ internal fun SendCustomFeeEthereum(
) {
repeat(customValues.size) { index ->
val value = customValues[index]
val bottomPadding = if (index == customValues.lastIndex) {
TangemTheme.dimens.spacing12
val bottomPadding = if (index == customValues.lastIndex && !hasNotifications) {
TangemTheme.dimens.spacing72
} else {
TangemTheme.dimens.spacing0
}

View file

@ -23,8 +23,9 @@ private const val FEE_CUSTOM_KEY = "FEE_CUSTOM_KEY"
internal fun SendSpeedAndFeeContent(state: SendStates.FeeState?, clickIntents: SendClickIntents) {
if (state == null) return
val feeSendState = state.feeSelectorState as? FeeSelectorState.Content
val isCustomSelected = feeSendState?.selectedFee == FeeType.Custom
val notifications = state.notifications
val isCustomSelected = feeSendState?.selectedFee == FeeType.Custom
val hasNotifications = notifications.isNotEmpty()
LazyColumn(
modifier = Modifier
.fillMaxSize()
@ -35,7 +36,7 @@ internal fun SendSpeedAndFeeContent(state: SendStates.FeeState?, clickIntents: S
) {
feeSelector(state, clickIntents)
if (feeSendState != null) {
customFee(feeSendState)
customFee(feeSendState = feeSendState, hasNotifications = hasNotifications)
}
notifications(notifications = notifications, hasPaddingAbove = isCustomSelected)
}
@ -55,13 +56,18 @@ private fun LazyListScope.feeSelector(state: SendStates.FeeState, clickIntents:
}
@OptIn(ExperimentalFoundationApi::class)
internal fun LazyListScope.customFee(feeSendState: FeeSelectorState.Content, modifier: Modifier = Modifier) {
internal fun LazyListScope.customFee(
feeSendState: FeeSelectorState.Content,
hasNotifications: Boolean,
modifier: Modifier = Modifier,
) {
item(
key = FEE_CUSTOM_KEY,
) {
SendCustomFeeEthereum(
customValues = feeSendState.customValues,
selectedFee = feeSendState.selectedFee,
hasNotifications = hasNotifications,
modifier = modifier
.fillMaxWidth()
.animateItemPlacement()

View file

@ -163,11 +163,11 @@ private fun FeeSelectorState.Content.getAmount(feeType: FeeType): Amount? {
private fun FeeSelectorState.Content?.getDividerAndVisibility(feeType: FeeType): Pair<Boolean, Boolean> {
val hasCustomValues = !this?.customValues.isNullOrEmpty()
val isNotSingle = this?.fees !is TransactionFee.Single
val isSingle = this?.fees is TransactionFee.Single
val isLoaded = this?.fees != null
return when (feeType) {
FeeType.Slow -> true to isNotSingle
FeeType.Market -> isNotSingle to isSingle
FeeType.Market -> isNotSingle to isLoaded
FeeType.Fast -> hasCustomValues to isNotSingle
FeeType.Custom -> false to isNotSingle
FeeType.Custom -> false to hasCustomValues
}
}

View file

@ -182,7 +182,7 @@ private fun LazyListScope.listItem(
.then(
if (isLast && index == list.lastIndex) {
Modifier
.padding(bottom = TangemTheme.dimens.spacing12)
.padding(bottom = TangemTheme.dimens.spacing72)
.clip(
shape = RoundedCornerShape(
bottomStart = TangemTheme.dimens.radius16,