Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-24 14:43:38 +05:00
parent 22ad2ddc67
commit 281b5ec956
13 changed files with 371 additions and 20 deletions

View file

@ -206,6 +206,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
childStack = childStack,
)
},
isRedesignEnabled = model.uiState.value.isRedesignEnabled,
),
)
} else {
@ -225,6 +226,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
return if (sendAmount != null && destinationAddress != null &&
feeCryptoCurrencyStatus != null && cryptoCurrencyStatus != null
) {
// TODO Apply new component [REDACTED_TASK_KEY]
SendFeeComponent(
appComponentContext = factoryContext,
params = SendFeeComponentParams.FeeParams(

View file

@ -65,6 +65,7 @@ internal class SendConfirmComponent(
appCurrency = params.appCurrency,
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
predefinedValues = params.predefinedValues,
isRedesignEnabled = model.uiState.value.isRedesignEnabled,
),
onResult = model::onAmountResult,
onClick = model::showEditAmount,

View file

@ -454,6 +454,7 @@ internal class SendConfirmModel @Inject constructor(
}
}
@Suppress("LongMethod")
private fun configConfirmNavigation() {
combine(
flow = uiState,
@ -470,7 +471,11 @@ internal class SendConfirmModel @Inject constructor(
id = R.string.send_summary_title,
formatArgs = wrappedList(params.cryptoCurrencyStatus.currency.name),
),
subtitle = amountUM?.title,
subtitle = if (uiState.value.isRedesignEnabled) {
null
} else {
amountUM?.title
},
backIconRes = R.drawable.ic_close_24,
backIconClick = {
analyticsEventHandler.send(

View file

@ -98,8 +98,13 @@ private fun LazyListScope.blocks(
modifier = Modifier.padding(vertical = 12.dp),
)
}
destinationBlockComponent.Content(modifier = Modifier)
amountBlockComponent.Content(modifier = Modifier)
if (uiState.isRedesignEnabled) {
amountBlockComponent.Content(modifier = Modifier)
destinationBlockComponent.Content(modifier = Modifier)
} else {
destinationBlockComponent.Content(modifier = Modifier)
amountBlockComponent.Content(modifier = Modifier)
}
feeBlockComponent.Content(modifier = Modifier)
}
}

View file

@ -364,5 +364,6 @@ internal class SendModel @Inject constructor(
feeUM = FeeUM.Empty(),
confirmUM = ConfirmUM.Empty,
navigationUM = NavigationUM.Empty,
isRedesignEnabled = sendFeatureToggles.isSendRedesignEnabled,
)
}

View file

@ -12,4 +12,5 @@ internal data class SendUM(
val feeUM: FeeUM,
val confirmUM: ConfirmUM,
val navigationUM: NavigationUM,
val isRedesignEnabled: Boolean,
)

View file

@ -6,6 +6,7 @@ import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.amountScreen.models.AmountState
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.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableContentComponent
@ -37,11 +38,24 @@ internal class SendAmountBlockComponent(
val state by model.uiState.collectAsStateWithLifecycle()
val isClickEnabled by params.blockClickEnableFlow.collectAsStateWithLifecycle()
AmountBlock(
amountState = state,
isClickDisabled = !isClickEnabled,
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
onClick = onClick,
)
if (params.isRedesignEnabled) {
val amountState = state as? AmountState.Data ?: return
AmountBlockV2(
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,
)
}
}
}

View file

@ -18,6 +18,7 @@ internal sealed class SendAmountComponentParams {
abstract val appCurrency: AppCurrency
abstract val cryptoCurrencyStatus: CryptoCurrencyStatus
abstract val predefinedValues: PredefinedValues
abstract val isRedesignEnabled: Boolean
data class AmountParams(
override val state: AmountState,
@ -26,6 +27,7 @@ internal sealed class SendAmountComponentParams {
override val appCurrency: AppCurrency,
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
override val predefinedValues: PredefinedValues,
override val isRedesignEnabled: Boolean,
val callback: ModelCallback,
val currentRoute: Flow<CommonSendRoute.Amount>,
val isBalanceHidingFlow: StateFlow<Boolean>,
@ -40,6 +42,7 @@ internal sealed class SendAmountComponentParams {
override val appCurrency: AppCurrency,
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
override val predefinedValues: PredefinedValues,
override val isRedesignEnabled: Boolean,
val blockClickEnableFlow: StateFlow<Boolean>,
) : SendAmountComponentParams()
}

View file

@ -40,6 +40,7 @@ internal class SendDestinationBlockComponent(
destinationUM = state,
isClickDisabled = !isClickEnabled,
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
isRedesignEnabled = (params.state as? DestinationUM.Content)?.isRedesignEnabled ?: false,
onClick = onClick,
)
}

View file

@ -1,26 +1,38 @@
package com.tangem.features.send.v2.subcomponents.destination.ui
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.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 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.stringResourceSafe
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.DestinationUM
import kotlinx.collections.immutable.toImmutableList
@Composable
internal fun DestinationBlock(
destinationUM: DestinationUM,
isClickDisabled: Boolean,
isEditingDisabled: Boolean,
isRedesignEnabled: Boolean,
onClick: () -> Unit,
) {
if (destinationUM !is DestinationUM.Content) return
@ -33,8 +45,15 @@ internal fun DestinationBlock(
.clickable(enabled = !isClickDisabled && !isEditingDisabled, onClick = onClick)
.padding(TangemTheme.dimens.spacing12),
) {
AddressBlock(destinationUM.addressTextField)
MemoBlock(destinationUM.memoTextField)
if (isRedesignEnabled) {
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),
)
}
}
@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,
),
)
}