Updated on 2026-08-14
This commit is contained in:
parent
6796e868c6
commit
ef389a6735
22 changed files with 867 additions and 36 deletions
|
|
@ -89,6 +89,12 @@
|
|||
<string name="common_exchange">Обменять</string>
|
||||
<string name="common_explore_transaction_history">Посмотреть историю транзакций</string>
|
||||
<string name="common_explorer">Обозреватель</string>
|
||||
<string name="common_fee_selector_title">Скорость и комиссия</string>
|
||||
<string name="common_fee_selector_footer">Сетевые комиссии за транзакции используются для поддержки безопасности сети, поощрения валидаторов, выделения ресурсов и определения приоритета транзакции.</string>
|
||||
<string name="common_fee_selector_option_slow">Медленно</string>
|
||||
<string name="common_fee_selector_option_market">По рынку</string>
|
||||
<string name="common_fee_selector_option_fast">Быстро</string>
|
||||
<string name="common_fee_selector_option_custom">Свое</string>
|
||||
<string name="common_generate_addresses">Сгенерировать адреса</string>
|
||||
<string name="common_import">Импортировать</string>
|
||||
<string name="common_like">Нравится</string>
|
||||
|
|
@ -100,6 +106,7 @@
|
|||
<string name="common_no_data">Нет данных</string>
|
||||
<string name="common_ok">OK</string>
|
||||
<string name="common_origin_card">Основная карта</string>
|
||||
<string name="common_paste">Вставить</string>
|
||||
<string name="common_receive">Получить</string>
|
||||
<string name="common_reject">Отклонить</string>
|
||||
<string name="common_reload">Перезагрузить</string>
|
||||
|
|
@ -384,19 +391,52 @@
|
|||
<string name="scan_card_settings_message">Отсканируйте карту, чтобы изменить ее настройки. Изменения затронут только ту карту, которую вы отсканировали, и не повлияют на другие карты, привязанные к вашему кошельку.</string>
|
||||
<string name="scan_card_settings_title">Приготовьте свою карту</string>
|
||||
<string name="send_amount_label">Сумма</string>
|
||||
<string name="send_amount_substract">Вычесть из суммы отправки</string>
|
||||
<string name="send_amount_substract_footer">Сумма к получению %1$s</string>
|
||||
<string name="send_destination_hint_address">Адрес</string>
|
||||
<string name="send_destination_tag_field">Код назначения</string>
|
||||
<string name="send_datetime_formatter">%1$s в %2$s</string>
|
||||
<string name="send_enter_address_field">Введите адрес</string>
|
||||
<string name="send_error_address_same_as_wallet">Адрес совпадает с адресом кошелька</string>
|
||||
<string name="send_extras_error_invalid_destination_tag">Недопустимый Tag. Он не будет добавлен в транзакцию.</string>
|
||||
<string name="send_extras_error_invalid_memo">Недопустимый Memo. Он не будет добавлен в транзакцию.</string>
|
||||
<string name="send_extras_hint_destination_tag">Tag</string>
|
||||
<string name="send_extras_hint_memo">Memo</string>
|
||||
<string name="send_recent_transactions">Последние</string>
|
||||
<string name="send_recipient_address_footer">Убедитесь, что вы отправляете средства на адрес кошелька %1$s. Ошибки могут привести к потере ваших токенов.</string>
|
||||
<string name="send_recipient_memo_footer">Мемо/Код назначения - это код, разделяющий транзакции к общему получателю в сети криптовалют. Внимание: отсутствие мемо может привести к потере средств.</string>
|
||||
<string name="send_fee_include_description">Включая комиссию</string>
|
||||
<string name="send_fee_label">Комиссия</string>
|
||||
<string name="send_fee_picker_low">Низкая</string>
|
||||
<string name="send_fee_picker_normal">Нормальная</string>
|
||||
<string name="send_fee_picker_priority">Приоритетная</string>
|
||||
<string name="send_gas_price">Цена газа</string>
|
||||
<string name="send_gas_price_footer">Цена газа влияет на скорость транзакции. При сильно низкой, транзакция может быть не обработана.</string>
|
||||
<string name="send_gas_limit">Лимит газа</string>
|
||||
<string name="send_max_amount_label">Максимальная сумма</string>
|
||||
<string name="send_max_amount">Всё</string>
|
||||
<string name="send_max_fee_footer">Максимальная cумма комиссии</string>
|
||||
<string name="send_max_fee">Комиссия не превысит</string>
|
||||
<string name="send_network_fee_title">Сетевая комиссия</string>
|
||||
<string name="send_network_fee_warning_title">Покрытие сетевой комиссии</string>
|
||||
<string name="send_network_fee_warning_content">Сумма отправки будет уменьшена для покрытия выбранного уровня комиссии</string>
|
||||
<string name="send_notification_transaction_delay_text">Обратите внимание, что при определенных параметрах комиссии возможны задержки по вашей транзакции</string>
|
||||
<string name="send_notification_exceed_balance_title">Недостаточно средств</string>
|
||||
<string name="send_notification_exceed_balance_text">Недостаточно средств для перевода, так как сумма комиссии и сумма перевода в совокупности больше имеющегося баланса.</string>
|
||||
<string name="send_notification_invalid_amount_title">Недопустимая сумма</string>
|
||||
<string name="send_notification_invalid_amount_text">Включенная комиссия превышает сумму перевода, что приводит к отрицательному значению.</string>
|
||||
<string name="send_notification_invalid_minimum_amount_text">Минимальная сумма отправки - %1$s. Пожалуйста, убедитесь, что остаток после отправки также не будет меньше %1$s.</string>
|
||||
<string name="send_notification_invalid_reserve_amount_title">Сумма резерва не может быть менее %1$s.</string>
|
||||
<string name="send_notification_top_up_text">Пожалуйста, пополните свой баланс, чтобы продолжить.</string>
|
||||
<string name="send_notification_high_fee_title">Увеличение комиссии</string>
|
||||
<string name="send_notification_high_fee_text">Комиссия при переводе всего баланса выше. Для того, чтобы снизить комиссию Вы можете оставить 0.01.</string>
|
||||
<string name="send_notification_exceed_fee_title">Комиссия превышает баланс</string>
|
||||
<string name="send_notification_exceed_fee_text">Размер комиссии превышает баланс сети. Для продолжения необходимо пополнить баланс сети.</string>
|
||||
<string name="send_notification_transaction_delay_title">Возможны задержки по транзакции</string>
|
||||
<string name="send_optional_field">Необязательное</string>
|
||||
<string name="send_qrcode_scan_amount_alert_title">QR код содержит информацию о сумме отправки равной %s</string>
|
||||
<string name="send_recipient">Получатель</string>
|
||||
<string name="send_recipient_wallets_title">Мои кошельки</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>
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@
|
|||
<string name="common_exchange">Exchange</string>
|
||||
<string name="common_explore_transaction_history">Explore transaction history</string>
|
||||
<string name="common_explorer">Explorer</string>
|
||||
<string name="common_fee_selector_title">Speed and fee</string>
|
||||
<string name="common_fee_selector_footer">Network transaction fees are used to support network security, incentivize validators, allocate resources, and determine transaction priority</string>
|
||||
<string name="common_fee_selector_option_slow">Slow</string>
|
||||
<string name="common_fee_selector_option_market">Market</string>
|
||||
<string name="common_fee_selector_option_fast">Fast</string>
|
||||
<string name="common_fee_selector_option_custom">Custom</string>
|
||||
<string name="common_generate_addresses">Generate addresses</string>
|
||||
<string name="common_import">Import</string>
|
||||
<string name="common_learn_and_earn">Learn & Earn</string>
|
||||
|
|
@ -99,6 +105,7 @@
|
|||
<string name="common_no_data">No data</string>
|
||||
<string name="common_ok">OK</string>
|
||||
<string name="common_origin_card">Primary Card</string>
|
||||
<string name="common_paste">Paste</string>
|
||||
<string name="common_receive">Receive</string>
|
||||
<string name="common_reject">Reject</string>
|
||||
<string name="common_reload">Reload</string>
|
||||
|
|
@ -383,20 +390,64 @@
|
|||
<string name="scan_card_settings_message">Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet.</string>
|
||||
<string name="scan_card_settings_title">Get your card ready!</string>
|
||||
<string name="send_amount_label">Amount</string>
|
||||
<string name="send_amount_substract">Subtract from send amount</string>
|
||||
<string name="send_amount_substract_footer">The recipient will receive %1$s</string>
|
||||
<string name="send_destination_hint_address">Address</string>
|
||||
<string name="send_destination_tag_field">Destination Tag</string>
|
||||
<string name="send_datetime_formatter">%1$s at %2$s</string>
|
||||
<string name="send_enter_address_field">Enter address</string>
|
||||
<string name="send_error_address_same_as_wallet">Address is the same as wallet address</string>
|
||||
<string name="send_extras_error_invalid_destination_tag">Invalid Tag. It won\'t be added to the transaction.</string>
|
||||
<string name="send_extras_error_invalid_memo">Invalid Memo. It won\'t be added to the transaction.</string>
|
||||
<string name="send_extras_hint_destination_tag">Tag</string>
|
||||
<string name="send_extras_hint_memo">Memo</string>
|
||||
<string name="send_insufficient_funds">Insufficient funds for transfer</string>
|
||||
<string name="send_fee_include_description">Include fee</string>
|
||||
<string name="send_fee_label">Fee</string>
|
||||
<string name="send_fee_picker_low">Low</string>
|
||||
<string name="send_fee_picker_normal">Normal</string>
|
||||
<string name="send_fee_picker_priority">Priority</string>
|
||||
<string name="send_fee_unreachable_error_title">Network fee info unreachable</string>
|
||||
<string name="send_fee_unreachable_error_text">Check your network connection</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_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_max_amount_label">Maximum amount</string>
|
||||
<string name="send_max_amount">Max</string>
|
||||
<string name="send_max_fee_footer">Maximum fee amount</string>
|
||||
<string name="send_max_fee">Max fee</string>
|
||||
<string name="send_memo_destination_tag_error">Numbers only for Destination Tag</string>
|
||||
<string name="send_network_fee_title">Network fee</string>
|
||||
<string name="send_network_fee_warning_title">Network fee coverage</string>
|
||||
<string name="send_network_fee_warning_content">Sending amount will be reduced to cover the selected fee level</string>
|
||||
<string name="send_notification_transaction_delay_text">Kindly be aware that your transaction may experience delays under specific fee settings</string>
|
||||
<string name="send_notification_exceed_balance_title">Total exceeds balance</string>
|
||||
<string name="send_notification_exceed_balance_text">Insufficient funds for the transfer, as the total of the fee and transfer amount exceeds the existing balance.</string>
|
||||
<string name="send_notification_invalid_amount_title">Invalid amount</string>
|
||||
<string name="send_notification_invalid_amount_text">The included commission exceeds the transfer amount, leading to a negative value.</string>
|
||||
<string name="send_notification_invalid_minimum_amount_text">The minimum sending amount is %1$s. Please ensure that the remaining balance after sending will not be less than %1$s.</string>
|
||||
<string name="send_notification_invalid_reserve_amount_title">The balance amount must be at least %1$s.</string>
|
||||
<string name="send_notification_invalid_reserve_amount_text">Please top up your balance to continue.</string>
|
||||
<string name="send_notification_high_fee_title">Fee is increased</string>
|
||||
<string name="send_notification_high_fee_text">The fee for transferring the entire balance is higher. To reduce the commission, you can leave 0.01.</string>
|
||||
<string name="send_notification_exceed_fee_title">Fee exceeds balance</string>
|
||||
<string name="send_notification_exceed_fee_text">The commission fee exceeds the network balance. To continue, it is necessary to replenish the network balance.</string>
|
||||
<string name="send_notification_transaction_delay_title">Transaction delays are possible</string>
|
||||
<string name="send_optional_field">Optional</string>
|
||||
<string name="send_qrcode_scan_info">Please align your QR code with the square to scan it. Ensure you scan %s network address.</string>
|
||||
<string name="send_qrcode_scan_address_success">Recipient’s address scanned</string>
|
||||
<string name="send_qrcode_scan_memo_success">Sending amount was changed</string>
|
||||
<string name="send_qrcode_scan_amount_alert_title">QR code contains information about the sending amount equal to %s</string>
|
||||
<string name="send_qrcode_scan_amount_alert_text">Change the entered amount?</string>
|
||||
<string name="send_qrcode_alert_change">Change</string>
|
||||
<string name="send_qrcode_alert_decline">Decline</string>
|
||||
<string name="send_recent_transactions">Recent</string>
|
||||
<string name="send_recipient">Recipient</string>
|
||||
<string name="send_recipient_address_error">Not a valid address</string>
|
||||
<string name="send_recipient_wallets_title">My wallets</string>
|
||||
<string name="send_recipient_address_footer">Ensure that you are sending funds to an %1$s wallet address. Errors may result in the loss of your tokens.</string>
|
||||
<string name="send_recipient_memo_footer">A Memo/Destination Tag is a unique ID for differentiating transactions sent to the same recipient on the same network. Caution: Omitting a memo may lead to misplaced funds.</string>
|
||||
<string name="send_title_currency_format">Sending %s</string>
|
||||
<string name="send_total_label">Total</string>
|
||||
<string name="send_total_subtitle_asset_format">%1$s and %2$s will be sent</string>
|
||||
|
|
@ -404,7 +455,6 @@
|
|||
<string name="send_total_subtitle_format">%s will be sent</string>
|
||||
<string name="send_transaction_success">Transaction has been successfully signed and sent to the blockchain node. Wallet balance will be updated in a while</string>
|
||||
<string name="send_validation_invalid_address">Invalid address</string>
|
||||
<string name="send_insufficient_funds">Insufficient funds for transfer</string>
|
||||
<string name="shop_buy_now">Buy now</string>
|
||||
<string name="shop_i_have_a_promo_code">I have a promo code…</string>
|
||||
<string name="shop_one_wallet">Tangem Wallet</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
package com.tangem.core.ui.components.icons.identicon
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.floor
|
||||
|
||||
/**
|
||||
* Ident icon. Blockies algorithm.
|
||||
* @see [Blockies](https://github.com/ethereum/blockies)
|
||||
*
|
||||
* @param address Address to generate the ident icon
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
internal data class Blockies(
|
||||
val address: String,
|
||||
) {
|
||||
|
||||
val primaryColor: Int
|
||||
val backgroundColor: Int
|
||||
val spotColor: Int
|
||||
val data: MutableList<Float>
|
||||
|
||||
init {
|
||||
val seed = seedFromAddress(address)
|
||||
// IMPORTANT! Color generation is based on the seed, thus ORDER is important.
|
||||
primaryColor = colorFromSeed(seed)
|
||||
backgroundColor = colorFromSeed(seed)
|
||||
spotColor = colorFromSeed(seed)
|
||||
data = dataFromSeed(seed)
|
||||
}
|
||||
|
||||
private fun seedFromAddress(address: String): MutableList<Long> {
|
||||
val seed = MutableList(SIZE) { DEFAULT_VALUE_L }
|
||||
address.indices.forEach { index ->
|
||||
seed[index % HALF_SIZE] =
|
||||
(seed[index % HALF_SIZE] shl 5) - seed[index % HALF_SIZE] + Character.codePointAt(address, index)
|
||||
}
|
||||
|
||||
// Important cast to preserve JavaScript type behavior
|
||||
seed.indices.map { seed[it] = seed[it].toInt().toLong() }
|
||||
return seed
|
||||
}
|
||||
|
||||
private fun colorFromSeed(seed: MutableList<Long>): Int {
|
||||
val h = floor(nextSeed(seed) * DEGREE_CIRCLE_F)
|
||||
val s = nextSeed(seed) * SATURATION_MAX + SATURATION_MIN
|
||||
val l = (nextSeed(seed) + nextSeed(seed) + nextSeed(seed) + nextSeed(seed)) * PROBABILITY_LIGHTNESS
|
||||
return toRgb(h, s, l)
|
||||
}
|
||||
|
||||
private fun nextSeed(seed: MutableList<Long>): Float {
|
||||
val t = (seed[0] xor (seed[0] shl 11)).toInt()
|
||||
seed[0] = seed[1]
|
||||
seed[1] = seed[2]
|
||||
seed[2] = seed[3]
|
||||
seed[3] = seed[3] xor (seed[3] shr 19) xor t.toLong() xor (t shr 8).toLong()
|
||||
|
||||
return abs(seed[3]).toFloat() / Integer.MAX_VALUE
|
||||
}
|
||||
|
||||
private fun dataFromSeed(seed: MutableList<Long>) = MutableList(SIZE * SIZE) { DEFAULT_VALUE_F }.apply {
|
||||
(0 until SIZE).forEach { row ->
|
||||
(0 until HALF_SIZE).forEach { column ->
|
||||
val value = floor(nextSeed(seed) * PROBABILITY_COLOR)
|
||||
this[row * SIZE + column] = value
|
||||
this[(row + 1) * SIZE - column - 1] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun toRgb(paramH: Float, paramS: Float, paramL: Float): Int {
|
||||
val h = paramH % DEGREE_CIRCLE_F / DEGREE_CIRCLE_F
|
||||
val s = paramS / PERCENT_MAX
|
||||
val l = paramL / PERCENT_MAX
|
||||
|
||||
val q = if (l < 0.5) l * (1 + s) else l + s - s * l
|
||||
val p = 2 * l - q
|
||||
|
||||
val r = hueToRGB(p, q, h + 1f / 3f).coerceIn(0f, 1f)
|
||||
val g = hueToRGB(p, q, h).coerceIn(0f, 1f)
|
||||
val b = hueToRGB(p, q, h - 1f / 3f).coerceIn(0f, 1f)
|
||||
|
||||
val red = (r * HEX_COLOR_MAX).toInt()
|
||||
val green = (g * HEX_COLOR_MAX).toInt()
|
||||
val blue = (b * HEX_COLOR_MAX).toInt()
|
||||
return RGB_ALPHA_PART shl RGB_R_PART or (red shl RGB_G_PART) or (green shl RGB_B_PART) or blue
|
||||
}
|
||||
|
||||
private fun hueToRGB(p: Float, q: Float, h: Float): Float {
|
||||
var hue = h
|
||||
if (hue < 0) hue += 1f
|
||||
if (hue > 1) hue -= 1f
|
||||
if (6 * hue < 1) return p + (q - p) * 6f * hue
|
||||
if (2 * hue < 1) return q
|
||||
|
||||
return if (3 * hue < 2) p + (q - p) * 6f * (2f / 3f - hue) else p
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val SIZE = 8
|
||||
private const val HALF_SIZE = SIZE / 2
|
||||
private const val DEFAULT_VALUE_L = 0L
|
||||
private const val DEFAULT_VALUE_F = 0f
|
||||
private const val DEGREE_CIRCLE_F = 360.0f
|
||||
private const val HEX_COLOR_MAX = 255
|
||||
private const val PERCENT_MAX = 100f
|
||||
private const val SATURATION_MIN = 40f
|
||||
private const val SATURATION_MAX = 60f
|
||||
private const val PROBABILITY_LIGHTNESS = 25f
|
||||
private const val PROBABILITY_COLOR = 2.3f
|
||||
private const val RGB_ALPHA_PART = 0xFF
|
||||
private const val RGB_R_PART = 24
|
||||
private const val RGB_G_PART = 16
|
||||
private const val RGB_B_PART = 8
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package com.tangem.core.ui.components.icons.identicon
|
||||
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.compose.ui.text.toLowerCase
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.res.LocalIsInDarkTheme
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
private const val GAP_WIDTH = 1f
|
||||
private const val ALPHA = 0.9f
|
||||
|
||||
/**
|
||||
* Ident icon
|
||||
*
|
||||
* @param address to generate ident icon from
|
||||
* @param modifier to apply to ident icon
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
fun IdentIcon(address: String, modifier: Modifier = Modifier) {
|
||||
if (address.isBlank()) {
|
||||
Box(modifier = modifier)
|
||||
} else {
|
||||
val blockies = Blockies(address.toLowerCase(Locale.current))
|
||||
Canvas(
|
||||
modifier = modifier
|
||||
.then(
|
||||
if (LocalIsInDarkTheme.current) {
|
||||
Modifier.alpha(ALPHA)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
),
|
||||
) {
|
||||
val cellWidth = size.width / Blockies.SIZE
|
||||
blockies.data.forEachIndexed { index, item ->
|
||||
val y = index / Blockies.SIZE
|
||||
val x = index % Blockies.SIZE
|
||||
val colorInt = when (item) {
|
||||
1f -> blockies.primaryColor
|
||||
2f -> blockies.spotColor
|
||||
else -> blockies.backgroundColor
|
||||
}
|
||||
drawRect(
|
||||
color = Color(colorInt),
|
||||
topLeft = Offset(x * cellWidth, y * cellWidth),
|
||||
size = Size(cellWidth + GAP_WIDTH, cellWidth + GAP_WIDTH),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//region preview
|
||||
@Preview
|
||||
@Composable
|
||||
private fun IdentIconPreview_Light() {
|
||||
TangemTheme {
|
||||
IdentIcon(
|
||||
address = "0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359",
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size40),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun IdentIconPreview_Dark() {
|
||||
TangemTheme(isDark = true) {
|
||||
IdentIcon(
|
||||
address = "0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359",
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size40),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
|
@ -31,6 +31,7 @@ data class TangemDimens internal constructor(
|
|||
val radius14: Dp = 14.dp,
|
||||
val radius16: Dp = 16.dp,
|
||||
val radius18: Dp = 18.dp,
|
||||
val radius20: Dp = 20.dp,
|
||||
val radius24: Dp = 24.dp,
|
||||
val radius26: Dp = 26.dp,
|
||||
val radius28: Dp = 28.dp,
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
|||
import com.tangem.core.ui.components.SystemBarsEffect
|
||||
import com.tangem.core.ui.screen.ComposeBottomSheetFragment
|
||||
import com.tangem.core.ui.theme.AppThemeModeHolder
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.send.ui.SendScreen
|
||||
import com.tangem.features.send.impl.presentation.send.viewmodel.SendViewModel
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.ui.SendScreen
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.state
|
||||
package com.tangem.features.send.impl.presentation.state
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.Provider
|
||||
|
|
@ -7,9 +7,10 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.send.impl.presentation.send.state.fields.SendAmountFieldChangeConverter
|
||||
import com.tangem.features.send.impl.presentation.send.state.fields.SendAmountFieldConverter
|
||||
import com.tangem.features.send.impl.presentation.send.viewmodel.SendClickIntents
|
||||
import com.tangem.features.send.impl.presentation.state.amount.SendAmountStateConverter
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldChangeConverter
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldConverter
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
|
||||
internal class SendStateFactory(
|
||||
private val clickIntents: SendClickIntents,
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
package com.tangem.features.send.impl.presentation.send.state
|
||||
package com.tangem.features.send.impl.presentation.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.impl.presentation.send.state.fields.SendTextField
|
||||
import com.tangem.features.send.impl.presentation.send.viewmodel.SendClickIntents
|
||||
import com.tangem.features.send.impl.presentation.state.amount.SendAmountSegmentedButtonsConfig
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
||||
/**
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.state
|
||||
package com.tangem.features.send.impl.presentation.state.amount
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.state
|
||||
package com.tangem.features.send.impl.presentation.state.amount
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.Provider
|
||||
|
|
@ -10,8 +10,9 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.send.impl.presentation.send.state.fields.SendAmountFieldConverter
|
||||
import com.tangem.features.send.impl.presentation.send.viewmodel.SendClickIntents
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldConverter
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.features.send.impl.presentation.send.state.fields
|
||||
package com.tangem.features.send.impl.presentation.state.fields
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.text.DecimalFormatSymbols
|
||||
import java.text.NumberFormat
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package com.tangem.features.send.impl.presentation.send.state.fields
|
||||
package com.tangem.features.send.impl.presentation.state.fields
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.features.send.impl.presentation.send.viewmodel.SendClickIntents
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.text.NumberFormat
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.state.fields
|
||||
package com.tangem.features.send.impl.presentation.state.fields
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.ui
|
||||
package com.tangem.features.send.impl.presentation.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
|
@ -18,9 +18,9 @@ import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
|
|||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendAmountSegmentedButtonsConfig
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.send.ui.amount.AmountFieldContainer
|
||||
import com.tangem.features.send.impl.presentation.state.amount.SendAmountSegmentedButtonsConfig
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.ui.amount.AmountFieldContainer
|
||||
|
||||
@Composable
|
||||
internal fun SendAmountContent(amountState: SendUiState.Content.AmountState) {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.ui
|
||||
package com.tangem.features.send.impl.presentation.ui
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
|
|
@ -18,7 +18,7 @@ import com.tangem.core.ui.R
|
|||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
|
||||
@Composable
|
||||
internal fun SendNavigationButtons(uiState: SendUiState.Content) {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.ui
|
||||
package com.tangem.features.send.impl.presentation.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
|
|
@ -13,7 +13,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetDraggableHeader
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
|
||||
@Composable
|
||||
internal fun SendScreen(uiState: SendUiState.Content) {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.ui.amount
|
||||
package com.tangem.features.send.impl.presentation.ui.amount
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
|
|
@ -27,7 +27,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.presentation.send.state.fields.SendTextField
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
|
||||
@Composable
|
||||
internal fun ColumnScope.AmountField(
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.ui.amount
|
||||
package com.tangem.features.send.impl.presentation.ui.amount
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
|
@ -13,7 +13,7 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
|
||||
@Composable
|
||||
internal fun AmountFieldContainer(amountState: SendUiState.Content.AmountState, modifier: Modifier = Modifier) {
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
package com.tangem.features.send.impl.presentation.ui.recipient
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.MiddleEllipsisText
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.R
|
||||
|
||||
/**
|
||||
* Row item with title and subtitle
|
||||
*
|
||||
* @param title title
|
||||
* @param subtitle subtitle
|
||||
* @param onClick click listener
|
||||
* @param modifier modifier
|
||||
* @param subtitleIconRes icon
|
||||
*/
|
||||
@Composable
|
||||
fun ListItemWithIcon(
|
||||
title: String,
|
||||
subtitle: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
@DrawableRes subtitleIconRes: Int? = null,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable { onClick() }
|
||||
.padding(
|
||||
vertical = TangemTheme.dimens.spacing8,
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
) {
|
||||
IdentIcon(
|
||||
address = title,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size40)
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius20)),
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
top = TangemTheme.dimens.spacing2,
|
||||
bottom = TangemTheme.dimens.spacing2,
|
||||
),
|
||||
) {
|
||||
MiddleEllipsisText(
|
||||
text = title,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Justify,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
Row {
|
||||
subtitleIconRes?.let { iconRes ->
|
||||
Icon(
|
||||
painter = painterResource(id = iconRes),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size16)
|
||||
.background(TangemTheme.colors.background.tertiary, CircleShape)
|
||||
.padding(TangemTheme.dimens.spacing3),
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = subtitle,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
modifier = Modifier
|
||||
.then(
|
||||
if (subtitleIconRes != null) {
|
||||
Modifier.padding(start = TangemTheme.dimens.spacing4)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region preview
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ListItemWithIconPreview_Light(
|
||||
@PreviewParameter(ListItemWithIconPreviewProvider::class) config: ListItemWithIconPreviewConfig,
|
||||
) {
|
||||
TangemTheme {
|
||||
ListItemWithIcon(
|
||||
title = config.title,
|
||||
subtitle = config.subtitle,
|
||||
subtitleIconRes = config.iconRes,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ListItemWithIconPreview_Dark(
|
||||
@PreviewParameter(ListItemWithIconPreviewProvider::class) config: ListItemWithIconPreviewConfig,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
ListItemWithIcon(
|
||||
title = config.title,
|
||||
subtitle = config.subtitle,
|
||||
subtitleIconRes = config.iconRes,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private data class ListItemWithIconPreviewConfig(
|
||||
val title: String,
|
||||
val subtitle: String,
|
||||
val iconRes: Int? = null,
|
||||
)
|
||||
|
||||
private class ListItemWithIconPreviewProvider : CollectionPreviewParameterProvider<ListItemWithIconPreviewConfig>(
|
||||
collection = listOf(
|
||||
ListItemWithIconPreviewConfig(
|
||||
title = "0x34B4492A412D84A6E606288f3Bd714b89135D4dE",
|
||||
subtitle = "Wallet",
|
||||
iconRes = R.drawable.ic_arrow_down_24,
|
||||
),
|
||||
ListItemWithIconPreviewConfig(
|
||||
title = "0x34B4492A412D84A6E606288f3Bd714b89135D4dE",
|
||||
subtitle = "Wallet",
|
||||
),
|
||||
),
|
||||
)
|
||||
//endregion
|
||||
|
|
@ -0,0 +1,380 @@
|
|||
package com.tangem.features.send.impl.presentation.ui.recipient
|
||||
|
||||
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.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.tangem.core.ui.components.SpacerH8
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun TextFieldWithPasteAndIcon(
|
||||
value: String,
|
||||
placeholder: TextReference,
|
||||
label: TextReference,
|
||||
onValueChange: (String) -> Unit,
|
||||
onPasteClick: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
footer: String? = null,
|
||||
singleLine: Boolean = false,
|
||||
) {
|
||||
FooterContainer(modifier, footer) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = TangemTheme.colors.background.action,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = label.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing12,
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
)
|
||||
Row {
|
||||
IdentIcon(
|
||||
address = value,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
bottom = TangemTheme.dimens.spacing10,
|
||||
)
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius20))
|
||||
.size(TangemTheme.dimens.size40)
|
||||
.background(TangemTheme.colors.background.tertiary),
|
||||
)
|
||||
SimpleTextField(
|
||||
value = value,
|
||||
placeholder = placeholder,
|
||||
onValueChange = onValueChange,
|
||||
singleLine = singleLine,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
bottom = TangemTheme.dimens.spacing10,
|
||||
)
|
||||
.weight(1f)
|
||||
.align(CenterVertically),
|
||||
)
|
||||
PasteButton(
|
||||
isPasteButtonVisible = value.isBlank(),
|
||||
onClick = onPasteClick,
|
||||
modifier = Modifier
|
||||
.align(CenterVertically)
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing4,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun TextFieldWithPaste(
|
||||
value: String,
|
||||
placeholder: TextReference,
|
||||
label: TextReference,
|
||||
onValueChange: (String) -> Unit,
|
||||
onPasteClick: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
footer: String? = null,
|
||||
) {
|
||||
FooterContainer(modifier, footer) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.background.action,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
Text(
|
||||
text = label.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
SimpleTextField(
|
||||
value = value,
|
||||
placeholder = placeholder,
|
||||
onValueChange = onValueChange,
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing6),
|
||||
)
|
||||
}
|
||||
PasteButton(
|
||||
isPasteButtonVisible = value.isBlank(),
|
||||
onClick = onPasteClick,
|
||||
modifier = Modifier
|
||||
.align(CenterVertically)
|
||||
.padding(end = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun TextFieldWithInfo(
|
||||
value: String,
|
||||
label: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
info: TextReference? = null,
|
||||
footer: String? = null,
|
||||
) {
|
||||
FooterContainer(
|
||||
footer = footer,
|
||||
footerTopPadding = TangemTheme.dimens.spacing6,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = TangemTheme.colors.background.action,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
)
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
bottom = TangemTheme.dimens.spacing14,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = label,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
Row {
|
||||
SimpleTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing6)
|
||||
.weight(1f),
|
||||
)
|
||||
info?.let {
|
||||
Text(
|
||||
text = it.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier
|
||||
.padding(start = TangemTheme.dimens.spacing8)
|
||||
.align(Alignment.Bottom),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FooterContainer(
|
||||
modifier: Modifier = Modifier,
|
||||
footer: String? = null,
|
||||
footerTopPadding: Dp = TangemTheme.dimens.spacing8,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
content()
|
||||
footer?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier
|
||||
.padding(top = footerTopPadding),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PasteButton(isPasteButtonVisible: Boolean, onClick: (String) -> Unit, modifier: Modifier = Modifier) {
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
|
||||
if (isPasteButtonVisible) {
|
||||
Box(modifier = modifier) {
|
||||
Text(
|
||||
text = "Paste",
|
||||
style = TangemTheme.typography.button,
|
||||
color = TangemTheme.colors.text.primary2,
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.button.primary,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
)
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing10,
|
||||
vertical = TangemTheme.dimens.spacing2,
|
||||
)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(radius = TangemTheme.dimens.radius8),
|
||||
onClick = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
onClick(
|
||||
clipboardManager
|
||||
.getText()
|
||||
?.toString()
|
||||
.orEmpty(),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_close_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = stringResource(R.string.common_close),
|
||||
modifier = modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(radius = TangemTheme.dimens.radius10),
|
||||
onClick = { onClick("") },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SimpleTextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
placeholder: TextReference? = null,
|
||||
singleLine: Boolean = false,
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
BasicTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
textStyle = TangemTheme.typography.body2,
|
||||
cursorBrush = SolidColor(TangemTheme.colors.text.primary1),
|
||||
singleLine = singleLine,
|
||||
decorationBox = { textValue ->
|
||||
Box {
|
||||
if (value.isBlank() && placeholder != null) {
|
||||
Text(
|
||||
text = placeholder.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.disabled,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
textValue()
|
||||
}
|
||||
},
|
||||
modifier = modifier
|
||||
.focusRequester(focusRequester),
|
||||
)
|
||||
}
|
||||
|
||||
//region preview
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TextFieldPreview_Light() {
|
||||
TangemTheme {
|
||||
Column {
|
||||
TextFieldWithPaste(
|
||||
value = "",
|
||||
label = TextReference.Res(R.string.send_recipient),
|
||||
placeholder = TextReference.Res(R.string.send_enter_address_field),
|
||||
onValueChange = {},
|
||||
onPasteClick = {},
|
||||
)
|
||||
SpacerH8()
|
||||
TextFieldWithPasteAndIcon(
|
||||
value = "",
|
||||
label = TextReference.Res(R.string.send_extras_hint_memo),
|
||||
placeholder = TextReference.Res(R.string.send_optional_field),
|
||||
onValueChange = {},
|
||||
onPasteClick = {},
|
||||
)
|
||||
SpacerH8()
|
||||
TextFieldWithInfo(
|
||||
value = "Text",
|
||||
label = stringResource(R.string.send_extras_hint_memo),
|
||||
info = TextReference.Res(R.string.send_optional_field),
|
||||
footer = stringResource(R.string.send_max_fee),
|
||||
onValueChange = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TextFieldPreview_Dark() {
|
||||
TangemTheme(isDark = true) {
|
||||
Column {
|
||||
TextFieldWithPaste(
|
||||
value = "",
|
||||
label = TextReference.Res(R.string.send_recipient),
|
||||
placeholder = TextReference.Res(R.string.send_enter_address_field),
|
||||
onValueChange = {},
|
||||
onPasteClick = {},
|
||||
)
|
||||
SpacerH8()
|
||||
TextFieldWithPasteAndIcon(
|
||||
value = "",
|
||||
label = TextReference.Res(R.string.send_extras_hint_memo),
|
||||
placeholder = TextReference.Res(R.string.send_optional_field),
|
||||
onValueChange = {},
|
||||
onPasteClick = {},
|
||||
)
|
||||
SpacerH8()
|
||||
TextFieldWithInfo(
|
||||
value = "Text",
|
||||
label = stringResource(R.string.send_extras_hint_memo),
|
||||
info = TextReference.Res(R.string.send_optional_field),
|
||||
footer = stringResource(R.string.send_max_fee),
|
||||
onValueChange = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.viewmodel
|
||||
package com.tangem.features.send.impl.presentation.viewmodel
|
||||
|
||||
interface SendClickIntents {
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.impl.presentation.send.viewmodel
|
||||
package com.tangem.features.send.impl.presentation.viewmodel
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
|
@ -14,8 +14,8 @@ import com.tangem.domain.wallets.models.UserWallet
|
|||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendStateFactory
|
||||
import com.tangem.features.send.impl.presentation.send.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.state.SendStateFactory
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
Loading…
Add table
Add a link
Reference in a new issue