Updated on 2026-08-14
This commit is contained in:
parent
22ad2ddc67
commit
281b5ec956
13 changed files with 371 additions and 20 deletions
|
|
@ -0,0 +1,180 @@
|
||||||
|
package com.tangem.common.ui.amountScreen.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.tangem.common.ui.R
|
||||||
|
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||||
|
import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
import com.tangem.core.ui.extensions.resolveReference
|
||||||
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
|
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||||
|
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||||
|
import com.tangem.core.ui.format.bigdecimal.format
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AmountBlockV2(
|
||||||
|
amountState: AmountState,
|
||||||
|
currencyIconState: CurrencyIconState,
|
||||||
|
isClickDisabled: Boolean,
|
||||||
|
isEditingDisabled: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
if (amountState !is AmountState.Data) return
|
||||||
|
val amount = amountState.amountTextField
|
||||||
|
|
||||||
|
val cryptoAmount = amount.cryptoAmount.value?.format {
|
||||||
|
crypto(
|
||||||
|
symbol = "",
|
||||||
|
decimals = amount.cryptoAmount.decimals,
|
||||||
|
)
|
||||||
|
}.orEmpty()
|
||||||
|
|
||||||
|
val fiatAmount = amount.fiatAmount.value.format {
|
||||||
|
fiat(
|
||||||
|
fiatCurrencySymbol = amount.fiatAmount.currencySymbol,
|
||||||
|
fiatCurrencyCode = amountState.appCurrency.code,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val (firstAmount, secondAmount) = if (amount.isFiatValue) {
|
||||||
|
fiatAmount to cryptoAmount
|
||||||
|
} else {
|
||||||
|
cryptoAmount to fiatAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
val title = TextReference.Str(
|
||||||
|
stringResourceSafe(
|
||||||
|
R.string.send_from_wallet_name,
|
||||||
|
amountState.title
|
||||||
|
.resolveReference(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val currencyTitle = amount.cryptoAmount.currencySymbol
|
||||||
|
|
||||||
|
AmountBlockV2(
|
||||||
|
title = title,
|
||||||
|
balance = amountState.availableBalance,
|
||||||
|
currencyTitle = currencyTitle,
|
||||||
|
currencyIconState = currencyIconState,
|
||||||
|
firstAmount = firstAmount,
|
||||||
|
secondAmount = secondAmount,
|
||||||
|
isClickDisabled = isClickDisabled,
|
||||||
|
isEditingDisabled = isEditingDisabled,
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
@Composable
|
||||||
|
internal fun AmountBlockV2(
|
||||||
|
title: TextReference,
|
||||||
|
balance: TextReference,
|
||||||
|
currencyTitle: String,
|
||||||
|
currencyIconState: CurrencyIconState,
|
||||||
|
firstAmount: String,
|
||||||
|
secondAmount: String,
|
||||||
|
isClickDisabled: Boolean,
|
||||||
|
isEditingDisabled: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||||
|
.background(TangemTheme.colors.background.action)
|
||||||
|
.clickable(enabled = !isClickDisabled && !isEditingDisabled, onClick = onClick)
|
||||||
|
.padding(TangemTheme.dimens.spacing16),
|
||||||
|
) {
|
||||||
|
Row {
|
||||||
|
Text(
|
||||||
|
text = title.resolveReference(),
|
||||||
|
style = TangemTheme.typography.body2,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
)
|
||||||
|
Spacer(modifier = modifier.weight(1f))
|
||||||
|
Text(
|
||||||
|
text = balance.resolveReference(),
|
||||||
|
style = TangemTheme.typography.body2,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
modifier = Modifier.padding(top = 8.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = firstAmount,
|
||||||
|
style = TangemTheme.typography.h2,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = secondAmount,
|
||||||
|
style = TangemTheme.typography.body2,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.padding(top = 6.dp),
|
||||||
|
) {
|
||||||
|
CurrencyIcon(
|
||||||
|
state = currencyIconState,
|
||||||
|
modifier = Modifier.padding(horizontal = 14.dp),
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = currencyTitle,
|
||||||
|
style = TangemTheme.typography.subtitle2,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Preview
|
||||||
|
@Preview
|
||||||
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun AmountBlockPreview(@PreviewParameter(AmountBlockV2PreviewProvider::class) value: AmountState) {
|
||||||
|
TangemThemePreview {
|
||||||
|
AmountBlockV2(
|
||||||
|
amountState = value,
|
||||||
|
currencyIconState = CurrencyIconState.Empty(),
|
||||||
|
isClickDisabled = false,
|
||||||
|
isEditingDisabled = false,
|
||||||
|
onClick = {},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AmountBlockV2PreviewProvider : PreviewParameterProvider<AmountState> {
|
||||||
|
override val values: Sequence<AmountState>
|
||||||
|
get() = sequenceOf(
|
||||||
|
AmountStatePreviewData.amountState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
@ -822,6 +822,7 @@
|
||||||
<string name="send_fee_unreachable_error_text">Check your network connection</string>
|
<string name="send_fee_unreachable_error_text">Check your network connection</string>
|
||||||
<string name="send_fee_unreachable_error_title">Network fee info unreachable</string>
|
<string name="send_fee_unreachable_error_title">Network fee info unreachable</string>
|
||||||
<string name="send_from_wallet_android">From</string>
|
<string name="send_from_wallet_android">From</string>
|
||||||
|
<string name="send_from_wallet_name">From %s</string>
|
||||||
<string name="send_gas_limit">Gas limit</string>
|
<string name="send_gas_limit">Gas limit</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_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">Gas price</string>
|
||||||
|
|
@ -829,6 +830,7 @@
|
||||||
<string name="send_max_amount">Max</string>
|
<string name="send_max_amount">Max</string>
|
||||||
<string name="send_max_amount_label">Maximum amount</string>
|
<string name="send_max_amount_label">Maximum amount</string>
|
||||||
<string name="send_max_fee">Fee up to</string>
|
<string name="send_max_fee">Fee up to</string>
|
||||||
|
<string name="send_memo">Memo: %s</string>
|
||||||
<string name="send_memo_destination_tag_error">Invalid Memo</string>
|
<string name="send_memo_destination_tag_error">Invalid Memo</string>
|
||||||
<string name="send_network_fee_warning_title">Network fee coverage</string>
|
<string name="send_network_fee_warning_title">Network fee coverage</string>
|
||||||
<string name="send_nonce">Nonce</string>
|
<string name="send_nonce">Nonce</string>
|
||||||
|
|
@ -879,6 +881,7 @@
|
||||||
<string name="send_summary_transaction_description_suffix_fee_covered">network fee will be covered by using %1$s energy</string>
|
<string name="send_summary_transaction_description_suffix_fee_covered">network fee will be covered by using %1$s energy</string>
|
||||||
<string name="send_summary_transaction_description_suffix_fee_reduced">network fee will be reduced by spending %1$s energy</string>
|
<string name="send_summary_transaction_description_suffix_fee_reduced">network fee will be reduced by spending %1$s energy</string>
|
||||||
<string name="send_summary_transaction_description_suffix_including">including a network fee of %1$s</string>
|
<string name="send_summary_transaction_description_suffix_including">including a network fee of %1$s</string>
|
||||||
|
<string name="send_to_address">To address</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_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_tron_account_activation_error">%1$s is an asset in the Tron network. To calculate the fee and make a transaction you need to deposit some Tron (TRX) in your account.</string>
|
<string name="send_tron_account_activation_error">%1$s is an asset in the Tron network. To calculate the fee and make a transaction you need to deposit some Tron (TRX) in your account.</string>
|
||||||
<string name="send_validation_amount_exceeds_balance">Amount exceeds balance</string>
|
<string name="send_validation_amount_exceeds_balance">Amount exceeds balance</string>
|
||||||
|
|
@ -888,6 +891,7 @@
|
||||||
<string name="send_validation_invalid_fee">Fee exceeds balance</string>
|
<string name="send_validation_invalid_fee">Fee exceeds balance</string>
|
||||||
<string name="send_validation_invalid_total">Total amount exceeds balance</string>
|
<string name="send_validation_invalid_total">Total amount exceeds balance</string>
|
||||||
<string name="send_with_swap_notification_text">Send any token, and we’ll convert it on the way. Your recipient gets exactly what they need—seamlessly.</string>
|
<string name="send_with_swap_notification_text">Send any token, and we’ll convert it on the way. Your recipient gets exactly what they need—seamlessly.</string>
|
||||||
|
<string name="send_with_swap_recipient_amount_text">Will be sent a recipient</string>
|
||||||
<string name="send_with_swap_title">Send with swap</string>
|
<string name="send_with_swap_title">Send with swap</string>
|
||||||
<string name="sent_transaction_sent_title">Transaction sent</string>
|
<string name="sent_transaction_sent_title">Transaction sent</string>
|
||||||
<string name="settings_card_settings_footer">Prepare to scan card or ring you want to set up.</string>
|
<string name="settings_card_settings_footer">Prepare to scan card or ring you want to set up.</string>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="16dp" android:viewportHeight="24" android:viewportWidth="24" android:width="16dp">
|
||||||
android:width="16dp"
|
|
||||||
android:height="17dp"
|
<path android:fillColor="#1E1E1E" android:fillType="evenOdd" android:pathData="M10,3H6C4.343,3 3,4.343 3,6V10.5H5V6C5,5.448 5.448,5 6,5H10V3ZM3,15V18C3,19.657 4.343,21 6,21H10V19H6C5.448,19 5,18.552 5,18V15H19V18C19,18.552 18.552,19 18,19H14V21H18C19.657,21 21,19.657 21,18V15H22V13H2V15H3ZM21,6V10.5H19V6C19,5.448 18.552,5 18,5H14V3H18C19.657,3 21,4.343 21,6Z"/>
|
||||||
android:viewportWidth="16"
|
|
||||||
android:viewportHeight="17">
|
|
||||||
<path
|
|
||||||
android:pathData="M6.666,2.391H4C2.895,2.391 2,3.287 2,4.391V7.391L3.333,7.391V4.391C3.333,4.023 3.631,3.725 4,3.725H6.666V2.391ZM2,10.391V12.391C2,13.496 2.895,14.391 4,14.391H6.666V13.058H4C3.631,13.058 3.333,12.759 3.333,12.391V10.391H12.666V12.391C12.666,12.759 12.368,13.058 12,13.058H9.333V14.391H12C13.104,14.391 14,13.496 14,12.391V10.391H14.666V9.058H1.333V10.391H2ZM14,4.391V7.391H12.666V4.391C12.666,4.023 12.368,3.725 12,3.725H9.333V2.391H12C13.104,2.391 14,3.287 14,4.391Z"
|
|
||||||
android:fillColor="#1E1E1E"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
||||||
childStack = childStack,
|
childStack = childStack,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
isRedesignEnabled = model.uiState.value.isRedesignEnabled,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -225,6 +226,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
||||||
return if (sendAmount != null && destinationAddress != null &&
|
return if (sendAmount != null && destinationAddress != null &&
|
||||||
feeCryptoCurrencyStatus != null && cryptoCurrencyStatus != null
|
feeCryptoCurrencyStatus != null && cryptoCurrencyStatus != null
|
||||||
) {
|
) {
|
||||||
|
// TODO Apply new component [REDACTED_TASK_KEY]
|
||||||
SendFeeComponent(
|
SendFeeComponent(
|
||||||
appComponentContext = factoryContext,
|
appComponentContext = factoryContext,
|
||||||
params = SendFeeComponentParams.FeeParams(
|
params = SendFeeComponentParams.FeeParams(
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ internal class SendConfirmComponent(
|
||||||
appCurrency = params.appCurrency,
|
appCurrency = params.appCurrency,
|
||||||
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
|
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
|
||||||
predefinedValues = params.predefinedValues,
|
predefinedValues = params.predefinedValues,
|
||||||
|
isRedesignEnabled = model.uiState.value.isRedesignEnabled,
|
||||||
),
|
),
|
||||||
onResult = model::onAmountResult,
|
onResult = model::onAmountResult,
|
||||||
onClick = model::showEditAmount,
|
onClick = model::showEditAmount,
|
||||||
|
|
|
||||||
|
|
@ -454,6 +454,7 @@ internal class SendConfirmModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongMethod")
|
||||||
private fun configConfirmNavigation() {
|
private fun configConfirmNavigation() {
|
||||||
combine(
|
combine(
|
||||||
flow = uiState,
|
flow = uiState,
|
||||||
|
|
@ -470,7 +471,11 @@ internal class SendConfirmModel @Inject constructor(
|
||||||
id = R.string.send_summary_title,
|
id = R.string.send_summary_title,
|
||||||
formatArgs = wrappedList(params.cryptoCurrencyStatus.currency.name),
|
formatArgs = wrappedList(params.cryptoCurrencyStatus.currency.name),
|
||||||
),
|
),
|
||||||
subtitle = amountUM?.title,
|
subtitle = if (uiState.value.isRedesignEnabled) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
amountUM?.title
|
||||||
|
},
|
||||||
backIconRes = R.drawable.ic_close_24,
|
backIconRes = R.drawable.ic_close_24,
|
||||||
backIconClick = {
|
backIconClick = {
|
||||||
analyticsEventHandler.send(
|
analyticsEventHandler.send(
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,13 @@ private fun LazyListScope.blocks(
|
||||||
modifier = Modifier.padding(vertical = 12.dp),
|
modifier = Modifier.padding(vertical = 12.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
destinationBlockComponent.Content(modifier = Modifier)
|
if (uiState.isRedesignEnabled) {
|
||||||
amountBlockComponent.Content(modifier = Modifier)
|
amountBlockComponent.Content(modifier = Modifier)
|
||||||
|
destinationBlockComponent.Content(modifier = Modifier)
|
||||||
|
} else {
|
||||||
|
destinationBlockComponent.Content(modifier = Modifier)
|
||||||
|
amountBlockComponent.Content(modifier = Modifier)
|
||||||
|
}
|
||||||
feeBlockComponent.Content(modifier = Modifier)
|
feeBlockComponent.Content(modifier = Modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -364,5 +364,6 @@ internal class SendModel @Inject constructor(
|
||||||
feeUM = FeeUM.Empty(),
|
feeUM = FeeUM.Empty(),
|
||||||
confirmUM = ConfirmUM.Empty,
|
confirmUM = ConfirmUM.Empty,
|
||||||
navigationUM = NavigationUM.Empty,
|
navigationUM = NavigationUM.Empty,
|
||||||
|
isRedesignEnabled = sendFeatureToggles.isSendRedesignEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -12,4 +12,5 @@ internal data class SendUM(
|
||||||
val feeUM: FeeUM,
|
val feeUM: FeeUM,
|
||||||
val confirmUM: ConfirmUM,
|
val confirmUM: ConfirmUM,
|
||||||
val navigationUM: NavigationUM,
|
val navigationUM: NavigationUM,
|
||||||
|
val isRedesignEnabled: Boolean,
|
||||||
)
|
)
|
||||||
|
|
@ -6,6 +6,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||||
import com.tangem.common.ui.amountScreen.ui.AmountBlock
|
import com.tangem.common.ui.amountScreen.ui.AmountBlock
|
||||||
|
import com.tangem.common.ui.amountScreen.ui.AmountBlockV2
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
|
@ -37,11 +38,24 @@ internal class SendAmountBlockComponent(
|
||||||
val state by model.uiState.collectAsStateWithLifecycle()
|
val state by model.uiState.collectAsStateWithLifecycle()
|
||||||
val isClickEnabled by params.blockClickEnableFlow.collectAsStateWithLifecycle()
|
val isClickEnabled by params.blockClickEnableFlow.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
AmountBlock(
|
if (params.isRedesignEnabled) {
|
||||||
amountState = state,
|
val amountState = state as? AmountState.Data ?: return
|
||||||
isClickDisabled = !isClickEnabled,
|
|
||||||
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
|
AmountBlockV2(
|
||||||
onClick = onClick,
|
amountState = state,
|
||||||
)
|
currencyIconState = amountState.tokenIconState,
|
||||||
|
isClickDisabled = !isClickEnabled,
|
||||||
|
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AmountBlock(
|
||||||
|
amountState = state,
|
||||||
|
isClickDisabled = !isClickEnabled,
|
||||||
|
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ internal sealed class SendAmountComponentParams {
|
||||||
abstract val appCurrency: AppCurrency
|
abstract val appCurrency: AppCurrency
|
||||||
abstract val cryptoCurrencyStatus: CryptoCurrencyStatus
|
abstract val cryptoCurrencyStatus: CryptoCurrencyStatus
|
||||||
abstract val predefinedValues: PredefinedValues
|
abstract val predefinedValues: PredefinedValues
|
||||||
|
abstract val isRedesignEnabled: Boolean
|
||||||
|
|
||||||
data class AmountParams(
|
data class AmountParams(
|
||||||
override val state: AmountState,
|
override val state: AmountState,
|
||||||
|
|
@ -26,6 +27,7 @@ internal sealed class SendAmountComponentParams {
|
||||||
override val appCurrency: AppCurrency,
|
override val appCurrency: AppCurrency,
|
||||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||||
override val predefinedValues: PredefinedValues,
|
override val predefinedValues: PredefinedValues,
|
||||||
|
override val isRedesignEnabled: Boolean,
|
||||||
val callback: ModelCallback,
|
val callback: ModelCallback,
|
||||||
val currentRoute: Flow<CommonSendRoute.Amount>,
|
val currentRoute: Flow<CommonSendRoute.Amount>,
|
||||||
val isBalanceHidingFlow: StateFlow<Boolean>,
|
val isBalanceHidingFlow: StateFlow<Boolean>,
|
||||||
|
|
@ -40,6 +42,7 @@ internal sealed class SendAmountComponentParams {
|
||||||
override val appCurrency: AppCurrency,
|
override val appCurrency: AppCurrency,
|
||||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||||
override val predefinedValues: PredefinedValues,
|
override val predefinedValues: PredefinedValues,
|
||||||
|
override val isRedesignEnabled: Boolean,
|
||||||
val blockClickEnableFlow: StateFlow<Boolean>,
|
val blockClickEnableFlow: StateFlow<Boolean>,
|
||||||
) : SendAmountComponentParams()
|
) : SendAmountComponentParams()
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +40,7 @@ internal class SendDestinationBlockComponent(
|
||||||
destinationUM = state,
|
destinationUM = state,
|
||||||
isClickDisabled = !isClickEnabled,
|
isClickDisabled = !isClickEnabled,
|
||||||
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
|
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
|
||||||
|
isRedesignEnabled = (params.state as? DestinationUM.Content)?.isRedesignEnabled ?: false,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,38 @@
|
||||||
package com.tangem.features.send.v2.subcomponents.destination.ui
|
package com.tangem.features.send.v2.subcomponents.destination.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
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.components.icons.identicon.IdentIcon
|
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.extensions.resolveReference
|
||||||
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
import com.tangem.features.send.v2.impl.R
|
||||||
|
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationRecipientListUM
|
||||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationTextFieldUM
|
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationTextFieldUM
|
||||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun DestinationBlock(
|
internal fun DestinationBlock(
|
||||||
destinationUM: DestinationUM,
|
destinationUM: DestinationUM,
|
||||||
isClickDisabled: Boolean,
|
isClickDisabled: Boolean,
|
||||||
isEditingDisabled: Boolean,
|
isEditingDisabled: Boolean,
|
||||||
|
isRedesignEnabled: Boolean,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
if (destinationUM !is DestinationUM.Content) return
|
if (destinationUM !is DestinationUM.Content) return
|
||||||
|
|
@ -33,8 +45,15 @@ internal fun DestinationBlock(
|
||||||
.clickable(enabled = !isClickDisabled && !isEditingDisabled, onClick = onClick)
|
.clickable(enabled = !isClickDisabled && !isEditingDisabled, onClick = onClick)
|
||||||
.padding(TangemTheme.dimens.spacing12),
|
.padding(TangemTheme.dimens.spacing12),
|
||||||
) {
|
) {
|
||||||
AddressBlock(destinationUM.addressTextField)
|
if (isRedesignEnabled) {
|
||||||
MemoBlock(destinationUM.memoTextField)
|
AddressWithMemoBlock(
|
||||||
|
address = destinationUM.addressTextField,
|
||||||
|
memo = destinationUM.memoTextField,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AddressBlock(destinationUM.addressTextField)
|
||||||
|
MemoBlock(destinationUM.memoTextField)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,4 +103,124 @@ private fun MemoBlock(memo: DestinationTextFieldUM.RecipientMemo?) {
|
||||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
|
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun AddressWithMemoBlock(
|
||||||
|
address: DestinationTextFieldUM.RecipientAddress,
|
||||||
|
memo: DestinationTextFieldUM.RecipientMemo?,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResourceSafe(R.string.send_to_address),
|
||||||
|
style = TangemTheme.typography.subtitle2,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24),
|
||||||
|
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
text = address.value,
|
||||||
|
style = TangemTheme.typography.body2,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
)
|
||||||
|
IdentIcon(
|
||||||
|
address = address.value,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(TangemTheme.dimens.size36)
|
||||||
|
.clip(RoundedCornerShape(TangemTheme.dimens.radius18))
|
||||||
|
.background(TangemTheme.colors.background.tertiary),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (memo != null && memo.value.isNotBlank()) {
|
||||||
|
Text(
|
||||||
|
text = stringResourceSafe(R.string.send_memo, memo.value),
|
||||||
|
style = TangemTheme.typography.caption2,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun DestinationBlockPreview(
|
||||||
|
@PreviewParameter(DestinationBlockPreviewProvider::class) state: DestinationUM.Content,
|
||||||
|
) {
|
||||||
|
TangemThemePreview {
|
||||||
|
DestinationBlock(
|
||||||
|
destinationUM = state,
|
||||||
|
isClickDisabled = false,
|
||||||
|
isEditingDisabled = false,
|
||||||
|
isRedesignEnabled = state.isRedesignEnabled,
|
||||||
|
onClick = {},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DestinationBlockPreviewProvider : PreviewParameterProvider<DestinationUM.Content> {
|
||||||
|
override val values: Sequence<DestinationUM.Content>
|
||||||
|
get() = sequenceOf(
|
||||||
|
DestinationUM.Content(
|
||||||
|
isPrimaryButtonEnabled = true,
|
||||||
|
addressTextField = DestinationTextFieldUM.RecipientAddress(
|
||||||
|
value = "0x34B4492A412D84A6E606288f3Bd714b89135D4dE",
|
||||||
|
keyboardOptions = KeyboardOptions.Default,
|
||||||
|
placeholder = TextReference.Str("Enter address"),
|
||||||
|
label = TextReference.Str("Recipient Address"),
|
||||||
|
isError = false,
|
||||||
|
error = null,
|
||||||
|
isValuePasted = false,
|
||||||
|
),
|
||||||
|
memoTextField = DestinationTextFieldUM.RecipientMemo(
|
||||||
|
value = "Test memo for transaction",
|
||||||
|
keyboardOptions = KeyboardOptions.Default,
|
||||||
|
placeholder = TextReference.Str("Enter memo (optional)"),
|
||||||
|
label = TextReference.Str("Memo"),
|
||||||
|
isError = false,
|
||||||
|
error = null,
|
||||||
|
disabledText = TextReference.Str("Memo disabled"),
|
||||||
|
isEnabled = true,
|
||||||
|
isValuePasted = false,
|
||||||
|
),
|
||||||
|
recent = emptyList<DestinationRecipientListUM>().toImmutableList(),
|
||||||
|
wallets = emptyList<DestinationRecipientListUM>().toImmutableList(),
|
||||||
|
networkName = "Ethereum",
|
||||||
|
isValidating = false,
|
||||||
|
isInitialized = true,
|
||||||
|
isRedesignEnabled = false,
|
||||||
|
),
|
||||||
|
DestinationUM.Content(
|
||||||
|
isPrimaryButtonEnabled = true,
|
||||||
|
addressTextField = DestinationTextFieldUM.RecipientAddress(
|
||||||
|
value = "0x34B4492A412D84A6E606288f3Bd714b89135D4dE",
|
||||||
|
keyboardOptions = KeyboardOptions.Default,
|
||||||
|
placeholder = TextReference.Str("Enter address"),
|
||||||
|
label = TextReference.Str("Recipient Address"),
|
||||||
|
isError = false,
|
||||||
|
error = null,
|
||||||
|
isValuePasted = false,
|
||||||
|
),
|
||||||
|
memoTextField = DestinationTextFieldUM.RecipientMemo(
|
||||||
|
value = "Test memo for transaction",
|
||||||
|
keyboardOptions = KeyboardOptions.Default,
|
||||||
|
placeholder = TextReference.Str("Enter memo (optional)"),
|
||||||
|
label = TextReference.Str("Memo"),
|
||||||
|
isError = false,
|
||||||
|
error = null,
|
||||||
|
disabledText = TextReference.Str("Memo disabled"),
|
||||||
|
isEnabled = true,
|
||||||
|
isValuePasted = false,
|
||||||
|
),
|
||||||
|
recent = emptyList<DestinationRecipientListUM>().toImmutableList(),
|
||||||
|
wallets = emptyList<DestinationRecipientListUM>().toImmutableList(),
|
||||||
|
networkName = "Ethereum",
|
||||||
|
isValidating = false,
|
||||||
|
isInitialized = true,
|
||||||
|
isRedesignEnabled = true,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue