diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/AmountScreenContent.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/AmountScreenContent.kt index 823ad1ce3d..fdd122631d 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/AmountScreenContent.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/AmountScreenContent.kt @@ -1,6 +1,7 @@ package com.tangem.common.ui.amountScreen import android.content.res.Configuration +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.runtime.Composable @@ -8,13 +9,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.preview.AmountScreenClickIntentsStub import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData import com.tangem.common.ui.amountScreen.ui.amountField import com.tangem.common.ui.amountScreen.ui.amountFieldV2 import com.tangem.common.ui.amountScreen.ui.buttons -import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview /** @@ -29,15 +30,13 @@ fun AmountScreenContent( isBalanceHidden: Boolean, clickIntents: AmountScreenClickIntents, modifier: Modifier = Modifier, + extraContent: (@Composable () -> Unit)? = null, ) { // Do not put fillMaxSize() in here LazyColumn( modifier = modifier - .padding( - start = TangemTheme.dimens.spacing16, - end = TangemTheme.dimens.spacing16, - bottom = TangemTheme.dimens.spacing16, - ), + .padding(horizontal = 16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), ) { if (amountState.isRedesignEnabled) { amountFieldV2( @@ -47,6 +46,11 @@ fun AmountScreenContent( onCurrencyChange = clickIntents::onCurrencyChangeClick, onMaxAmountClick = clickIntents::onMaxValueClick, ) + if (extraContent != null) { + item("EXTRA_CONTENT_KEY") { + extraContent() + } + } } else if (amountState is AmountState.Data) { amountField( amountState = amountState, diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountButtons.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountButtons.kt index 6263c12b93..64d1c8f25c 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountButtons.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountButtons.kt @@ -38,9 +38,7 @@ internal fun LazyListScope.buttons( key = AMOUNT_BUTTONS_KEY, ) { val hapticFeedback = LocalHapticFeedback.current - Row( - modifier = Modifier.padding(top = TangemTheme.dimens.spacing12), - ) { + Row { if (segmentedButtonConfig.isNotEmpty()) { SegmentedButtons( modifier = Modifier diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/BottomFade.kt b/core/ui/src/main/java/com/tangem/core/ui/components/BottomFade.kt index fbb4ae896b..25342ebfdc 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/BottomFade.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/BottomFade.kt @@ -7,6 +7,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import com.tangem.core.ui.res.TangemTheme /** @@ -30,4 +32,30 @@ fun BottomFade(modifier: Modifier = Modifier, backgroundColor: Color = TangemThe ), ), ) +} + +/** + * A composable that draws a fade effect. Used on screens with a list of repeating + * elements and floating button at the bottom of the screen. + */ +@Composable +fun Fade( + modifier: Modifier = Modifier, + backgroundColor: Color = TangemTheme.colors.background.secondary, + height: Dp = 40.dp, +) { + Box( + modifier = modifier + .fillMaxWidth() + .height(height) + .background( + brush = Brush.verticalGradient( + endY = 100f, + colors = listOf( + Color.Transparent, + backgroundColor, + ), + ), + ), + ) } \ No newline at end of file diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt index e8237103f4..f746aacfd4 100644 --- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt +++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/DefaultWalletManagersFacade.kt @@ -502,9 +502,8 @@ internal class DefaultWalletManagersFacade @Inject constructor( ) ?: error("Wallet manager not found") val destination = when (amount.type) { - is AmountType.Token -> estimationFeeAddressFactory.makeAddress(blockchain) is AmountType.TokenYieldSupply -> walletManager.getYieldModuleAddress() - else -> return@withContext null + else -> estimationFeeAddressFactory.makeAddress(blockchain) } val callData = when (val amountType = amount.type) { diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/ui/SendContent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/ui/SendContent.kt index 610020a85c..cd6bfb3235 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/ui/SendContent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/ui/SendContent.kt @@ -1,5 +1,6 @@ package com.tangem.features.send.v2.common.ui +import androidx.compose.animation.* import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable @@ -11,17 +12,22 @@ import com.arkivanov.decompose.extensions.compose.stack.animation.fade import com.arkivanov.decompose.extensions.compose.stack.animation.slide import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation import com.arkivanov.decompose.router.stack.ChildStack +import com.tangem.common.ui.footers.SendingText import com.tangem.common.ui.navigationButtons.NavigationButtonsBlockV2 import com.tangem.common.ui.navigationButtons.NavigationUM +import com.tangem.core.ui.components.Fade import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon import com.tangem.core.ui.decompose.ComposableContentComponent +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.v2.common.CommonSendRoute +import com.tangem.features.send.v2.common.ui.state.ConfirmUM @Composable internal fun SendContent( navigationUM: NavigationUM, + confirmUM: ConfirmUM, stackState: ChildStack, ) { Column( @@ -44,17 +50,35 @@ internal fun SendContent( }, modifier = Modifier.weight(1f), ) { - it.instance.Content(Modifier.weight(1f)) + Box(modifier = Modifier.fillMaxHeight()) { + it.instance.Content(Modifier.fillMaxSize(1f)) + + if (stackState.active.configuration != CommonSendRoute.ConfirmSuccess) { + Fade( + backgroundColor = TangemTheme.colors.background.tertiary, + modifier = Modifier.align(Alignment.BottomCenter), + ) + } + } } if (stackState.active.configuration != CommonSendRoute.ConfirmSuccess) { - NavigationButtonsBlockV2( - navigationUM = navigationUM, - modifier = Modifier.padding( - start = 16.dp, - end = 16.dp, - bottom = 16.dp, - ), - ) + Column { + AnimatedVisibility( + visible = stackState.active.configuration == CommonSendRoute.Confirm, + enter = slideInVertically(initialOffsetY = { it / 2 }) + fadeIn(), + exit = slideOutVertically(targetOffsetY = { it / 2 }) + fadeOut(), + ) { + SendingText(footerText = (confirmUM as? ConfirmUM.Content)?.sendingFooter ?: TextReference.EMPTY) + } + NavigationButtonsBlockV2( + navigationUM = navigationUM, + modifier = Modifier.padding( + start = 16.dp, + end = 16.dp, + bottom = 16.dp, + ), + ) + } } } } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt index 32902cbc72..57b1f464d6 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt @@ -144,6 +144,7 @@ internal class DefaultSendComponent @AssistedInject constructor( ) SendContent( navigationUM = state.navigationUM, + confirmUM = state.confirmUM, stackState = stackState, ) } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/ui/SendConfirmContent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/ui/SendConfirmContent.kt index 7f7c70235b..496c8594ca 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/ui/SendConfirmContent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/ui/SendConfirmContent.kt @@ -13,10 +13,9 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp -import com.tangem.common.ui.footers.SendingText import com.tangem.common.ui.notifications.NotificationUM +import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.components.transactions.TransactionDoneTitle -import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.res.TangemTheme @@ -77,8 +76,10 @@ internal fun SendConfirmContent( isClickDisabled = confirmUM.isSending, ) } + item("SPACER_KEY") { + SpacerH(16.dp) + } } - SendingText(footerText = confirmUM?.sendingFooter ?: TextReference.EMPTY) } } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/success/ui/SendConfirmSuccessContent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/success/ui/SendConfirmSuccessContent.kt index 179b28552f..fbd5a692d6 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/success/ui/SendConfirmSuccessContent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/success/ui/SendConfirmSuccessContent.kt @@ -11,7 +11,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.tangem.common.ui.amountScreen.ui.AmountBlock import com.tangem.common.ui.navigationButtons.NavigationButtonsBlockV2 -import com.tangem.core.ui.components.BottomFade +import com.tangem.core.ui.components.Fade +import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.components.transactions.TransactionDoneTitle import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList @@ -45,54 +46,70 @@ internal fun SendConfirmSuccessContent(sendUM: SendUM, destinationBlockComponent exit = slideOutVertically().plus(fadeOut()), label = "Animate success content", ) { - Box( - modifier = Modifier - .fillMaxSize() - .background(TangemTheme.colors.background.tertiary), - ) { - Column( + Column { + Box( modifier = Modifier - .padding(horizontal = TangemTheme.dimens.spacing16) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(12.dp), + .weight(1f) + .background(TangemTheme.colors.background.tertiary), ) { - if (sendUM.confirmUM is ConfirmUM.Success) { - TransactionDoneTitle( - title = resourceReference(R.string.sent_transaction_sent_title), - subtitle = resourceReference( - R.string.send_date_format, - wrappedList( - sendUM.confirmUM.transactionDate.toTimeFormat(DateTimeFormatters.dateFormatter), - sendUM.confirmUM.transactionDate.toTimeFormat(), - ), - ), - modifier = Modifier.padding(vertical = 12.dp), - ) - } - AmountBlock( - amountState = sendUM.amountUM, - isClickDisabled = true, - isEditingDisabled = true, - onClick = {}, + SuccessContent( + sendUM = sendUM, + destinationBlockComponent = destinationBlockComponent, + modifier = Modifier.fillMaxHeight(), + ) + Fade( + modifier = Modifier.align(Alignment.BottomCenter), + backgroundColor = TangemTheme.colors.background.tertiary, ) - destinationBlockComponent.Content(modifier = Modifier) - FeeBlock(feeSelectorUM = sendUM.feeSelectorUM) - Spacer(Modifier.height(128.dp)) } - BottomFade(Modifier.align(Alignment.BottomCenter), TangemTheme.colors.background.tertiary) NavigationButtonsBlockV2( navigationUM = sendUM.navigationUM, - modifier = Modifier - .align(Alignment.BottomCenter) - .padding( - start = 16.dp, - end = 16.dp, - bottom = 16.dp, - ), + modifier = Modifier.padding( + start = 16.dp, + end = 16.dp, + bottom = 16.dp, + ), ) } } } +@Composable +private fun SuccessContent( + sendUM: SendUM, + destinationBlockComponent: SendDestinationBlockComponent, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .padding(horizontal = 16.dp) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + if (sendUM.confirmUM is ConfirmUM.Success) { + TransactionDoneTitle( + title = resourceReference(R.string.sent_transaction_sent_title), + subtitle = resourceReference( + R.string.send_date_format, + wrappedList( + sendUM.confirmUM.transactionDate.toTimeFormat(DateTimeFormatters.dateFormatter), + sendUM.confirmUM.transactionDate.toTimeFormat(), + ), + ), + modifier = Modifier.padding(vertical = 12.dp), + ) + } + AmountBlock( + amountState = sendUM.amountUM, + isClickDisabled = true, + isEditingDisabled = true, + onClick = {}, + ) + destinationBlockComponent.Content(modifier = Modifier) + FeeBlock(feeSelectorUM = sendUM.feeSelectorUM) + SpacerH(16.dp) + } +} + private const val ANIMATION_DELAY = 600L private val ANIMATION_OFFSET = (-40).dp \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/DefaultNFTSendComponent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/DefaultNFTSendComponent.kt index 0c61f6221e..3b36c566ed 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/DefaultNFTSendComponent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/DefaultNFTSendComponent.kt @@ -124,6 +124,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor( BackHandler(onBack = model::onBackClick) SendContent( navigationUM = state.navigationUM, + confirmUM = state.confirmUM, stackState = stackState, ) } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/ui/NFTSendConfirmContent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/ui/NFTSendConfirmContent.kt index 9ff84edfb4..cfd7cee800 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/ui/NFTSendConfirmContent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/ui/NFTSendConfirmContent.kt @@ -12,11 +12,8 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp -import com.tangem.common.ui.footers.SendingText import com.tangem.common.ui.notifications.NotificationUM -import com.tangem.core.ui.components.SpacerHMax import com.tangem.core.ui.components.transactions.TransactionDoneTitle -import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.res.TangemTheme @@ -49,33 +46,29 @@ internal fun NFTSendConfirmContent( ) { val confirmUM = nftSendUM.confirmUM as? ConfirmUM.Content - Column { - LazyColumn( - modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), - ) { - blocks( - nftSendUM = nftSendUM, - destinationBlockComponent = destinationBlockComponent, - nftDetailsBlockComponent = nftDetailsBlockComponent, - feeBlockComponent = feeBlockComponent, - feeSelectorBlockComponent = feeSelectorBlockComponent, - ) - if (confirmUM != null) { - tapHelp(isDisplay = confirmUM.showTapHelp) - with(notificationsComponent) { - content( - state = notificationsUM, - isClickDisabled = confirmUM.isSending, - ) - } - notifications( - notifications = confirmUM.notifications, + LazyColumn( + modifier = Modifier.padding(horizontal = 16.dp), + ) { + blocks( + nftSendUM = nftSendUM, + destinationBlockComponent = destinationBlockComponent, + nftDetailsBlockComponent = nftDetailsBlockComponent, + feeBlockComponent = feeBlockComponent, + feeSelectorBlockComponent = feeSelectorBlockComponent, + ) + if (confirmUM != null) { + tapHelp(isDisplay = confirmUM.showTapHelp) + with(notificationsComponent) { + content( + state = notificationsUM, isClickDisabled = confirmUM.isSending, ) } + notifications( + notifications = confirmUM.notifications, + isClickDisabled = confirmUM.isSending, + ) } - SpacerHMax() - SendingText(footerText = confirmUM?.sendingFooter ?: TextReference.EMPTY) } } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/success/ui/NFTSendSuccessContent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/success/ui/NFTSendSuccessContent.kt index 5efe65012c..c90b4429e3 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/success/ui/NFTSendSuccessContent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/success/ui/NFTSendSuccessContent.kt @@ -2,16 +2,16 @@ package com.tangem.features.send.v2.sendnft.success.ui import androidx.compose.animation.* import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.tangem.common.ui.navigationButtons.NavigationButtonsBlockV2 -import com.tangem.core.ui.components.BottomFade +import com.tangem.core.ui.components.Fade +import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.components.transactions.TransactionDoneTitle import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList @@ -52,52 +52,67 @@ internal fun NFTSendSuccessContent( label = "Animate success content", modifier = modifier, ) { - Box( - modifier = Modifier - .fillMaxSize() - .background(TangemTheme.colors.background.tertiary), - ) { - Column( + Column { + Box( modifier = Modifier - .padding(horizontal = TangemTheme.dimens.spacing16) - .scrollable( - state = rememberScrollState(), - orientation = Orientation.Vertical, - ), - verticalArrangement = Arrangement.spacedBy(12.dp), + .weight(1f) + .background(TangemTheme.colors.background.tertiary), ) { - if (nftSendUM.confirmUM is ConfirmUM.Success) { - TransactionDoneTitle( - title = resourceReference(R.string.sent_transaction_sent_title), - subtitle = resourceReference( - R.string.send_date_format, - wrappedList( - nftSendUM.confirmUM.transactionDate.toTimeFormat(DateTimeFormatters.dateFormatter), - nftSendUM.confirmUM.transactionDate.toTimeFormat(), - ), - ), - modifier = Modifier.padding(vertical = 12.dp), - ) - } - nftDetailsBlockComponent.Content(modifier = Modifier) - destinationBlockComponent.Content(modifier = Modifier) - FeeBlock(feeSelectorUM = nftSendUM.feeSelectorUM) - Spacer(Modifier.height(128.dp)) + SuccessContent( + nftSendUM = nftSendUM, + nftDetailsBlockComponent = nftDetailsBlockComponent, + destinationBlockComponent = destinationBlockComponent, + modifier = Modifier.fillMaxHeight(), + ) + Fade( + modifier = Modifier.align(Alignment.BottomCenter), + backgroundColor = TangemTheme.colors.background.tertiary, + ) } - BottomFade(Modifier.align(Alignment.BottomCenter), TangemTheme.colors.background.tertiary) NavigationButtonsBlockV2( navigationUM = nftSendUM.navigationUM, - modifier = Modifier - .align(Alignment.BottomCenter) - .padding( - start = 16.dp, - end = 16.dp, - bottom = 16.dp, - ), + modifier = Modifier.padding( + start = 16.dp, + end = 16.dp, + bottom = 16.dp, + ), ) } } } +@Composable +private fun SuccessContent( + nftSendUM: NFTSendUM, + destinationBlockComponent: SendDestinationBlockComponent, + nftDetailsBlockComponent: NFTDetailsBlockComponent, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .padding(horizontal = 16.dp) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + if (nftSendUM.confirmUM is ConfirmUM.Success) { + TransactionDoneTitle( + title = resourceReference(R.string.sent_transaction_sent_title), + subtitle = resourceReference( + R.string.send_date_format, + wrappedList( + nftSendUM.confirmUM.transactionDate.toTimeFormat(DateTimeFormatters.dateFormatter), + nftSendUM.confirmUM.transactionDate.toTimeFormat(), + ), + ), + modifier = Modifier.padding(vertical = 12.dp), + ) + } + nftDetailsBlockComponent.Content(modifier = Modifier) + destinationBlockComponent.Content(modifier = Modifier) + FeeBlock(feeSelectorUM = nftSendUM.feeSelectorUM) + SpacerH(16.dp) + } +} + private const val ANIMATION_DELAY = 600L private val ANIMATION_OFFSET = (-40).dp \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/ui/SendAmountContent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/ui/SendAmountContent.kt index c3fc5fffa3..b72232c3d4 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/ui/SendAmountContent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/ui/SendAmountContent.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.unit.dp import com.tangem.common.ui.amountScreen.AmountScreenContent import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData +import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -39,12 +40,13 @@ fun SendAmountContent( amountState = amountState, isBalanceHidden = isBalanceHidden, clickIntents = clickIntents, + extraContent = { + SendConvertTokenButton( + onConvertToAnother = clickIntents::onConvertToAnotherToken, + ).takeIf { isSendWithSwapAvailable } + }, ) - if (isSendWithSwapAvailable) { - SendConvertTokenButton( - onConvertToAnother = clickIntents::onConvertToAnotherToken, - ) - } + SpacerH(16.dp) } } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/ui/SendDestinationContent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/ui/SendDestinationContent.kt index 841793e7a6..33ae7db50f 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/ui/SendDestinationContent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/ui/SendDestinationContent.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.SpacerH import com.tangem.core.ui.components.containers.FooterContainer import com.tangem.core.ui.components.inputrow.InputRowRecipient import com.tangem.core.ui.extensions.* @@ -52,11 +53,7 @@ internal fun SendDestinationContent( LazyColumn( modifier = Modifier // Do not put fillMaxSize() in here .background(TangemTheme.colors.background.tertiary) - .padding( - start = 16.dp, - end = 16.dp, - bottom = 16.dp, - ), + .padding(horizontal = 16.dp), ) { addressItem( address = address, @@ -106,6 +103,9 @@ internal fun SendDestinationContent( ) }, ) + item("SPACER_KEY") { + SpacerH(16.dp) + } } } diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/SwapAmountContent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/SwapAmountContent.kt index 119255fe91..a53021a6a3 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/SwapAmountContent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/SwapAmountContent.kt @@ -7,7 +7,9 @@ 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.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -24,6 +26,7 @@ import androidx.compose.ui.unit.dp import androidx.constraintlayout.compose.ConstraintLayout import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.ui.AmountFieldV2 +import com.tangem.core.ui.components.SpacerH16 import com.tangem.core.ui.components.SpacerH2 import com.tangem.core.ui.components.TextShimmer import com.tangem.core.ui.components.atoms.text.EllipsisText @@ -44,6 +47,7 @@ import com.tangem.features.swap.v2.impl.amount.ui.preview.SwapAmountClickIntents import com.tangem.features.swap.v2.impl.amount.ui.preview.SwapAmountContentPreview import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM +@Suppress("DestructuringDeclarationWithTooManyEntries") @Composable internal fun SwapAmountContent( amountUM: SwapAmountUM, @@ -53,9 +57,9 @@ internal fun SwapAmountContent( val swapAmountContent = amountUM as? SwapAmountUM.Content val isFixedRate = swapAmountContent?.swapRateType == ExpressRateType.Fixed ConstraintLayout( - modifier = modifier, + modifier = modifier.verticalScroll(rememberScrollState()), ) { - val (amountFromRef, amountToRef, middleButtonRef) = createRefs() + val (amountFromRef, amountToRef, middleButtonRef, spacerRef) = createRefs() SwapAmountBlock( amountFieldUM = amountUM.primaryAmount, selectedAmountType = amountUM.selectedAmountType, @@ -90,6 +94,14 @@ internal fun SwapAmountContent( end.linkTo(parent.end) }, ) + SpacerH16( + modifier = Modifier.constrainAs(spacerRef) { + top.linkTo(amountToRef.bottom) + bottom.linkTo(parent.bottom) + start.linkTo(parent.start) + end.linkTo(parent.end) + }, + ) } } diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/DefaultSendWithSwapComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/DefaultSendWithSwapComponent.kt index 2dd841f3ff..27c689d8a0 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/DefaultSendWithSwapComponent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/DefaultSendWithSwapComponent.kt @@ -17,6 +17,7 @@ import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.model.getOrCreateModel import com.tangem.core.decompose.navigation.inner.InnerRouter +import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.swap.models.R @@ -47,6 +48,7 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor( private val sendDestinationComponentFactory: SendDestinationComponent.Factory, private val confirmComponentFactory: SendWithSwapConfirmComponent.Factory, private val analyticsEventHandler: AnalyticsEventHandler, + private val urlOpener: UrlOpener, ) : SendWithSwapComponent, AppComponentContext by appComponentContext { private val stackNavigation = StackNavigation() @@ -127,7 +129,12 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor( (state.navigationUM as? NavigationUM.Content)?.backIconClick() ?: onChildBack() }, ) - SendWithSwapContent(navigationUM = state.navigationUM, stackState = stackState) + SendWithSwapContent( + navigationUM = state.navigationUM, + confirmUM = state.confirmUM, + stackState = stackState, + onLinkClick = urlOpener::openUrl, + ) } private fun createChild(route: SendWithSwapRoute, childContext: AppComponentContext) = when (route) { diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt index e3cd40b91d..b731648cfe 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt @@ -8,7 +8,6 @@ import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.child import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.model.getOrCreateModel -import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.currency.CryptoCurrency @@ -44,7 +43,6 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor( sendDestinationBlockComponent: SendDestinationBlockComponent.Factory, feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory, sendNotificationsComponentFactory: SendNotificationsComponent.Factory, - private val urlOpener: UrlOpener, ) : ComposableContentComponent, AppComponentContext by appComponentContext { private val model: SendWithSwapConfirmModel = getOrCreateModel(params = params) @@ -162,7 +160,6 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor( sendNotificationsUM = sendNotificationsUM, swapNotificationsComponent = swapNotificationsComponent, swapNotificationsUM = swapNotificationsUM, - onLinkClick = urlOpener::openUrl, modifier = modifier, ) } diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/ui/SendWithSwapConfirmContent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/ui/SendWithSwapConfirmContent.kt index c39df3a68a..1688c9b88a 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/ui/SendWithSwapConfirmContent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/ui/SendWithSwapConfirmContent.kt @@ -8,23 +8,18 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.text.LinkAnnotation -import androidx.compose.ui.text.withLink import androidx.compose.ui.unit.dp -import com.tangem.common.ui.footers.SendingText import com.tangem.common.ui.notifications.NotificationUM import com.tangem.common.ui.notifications.notifications +import com.tangem.core.ui.components.SpacerH16 import com.tangem.core.ui.extensions.* -import com.tangem.core.ui.res.TangemTheme import com.tangem.features.send.v2.api.FeeSelectorBlockComponent import com.tangem.features.send.v2.api.SendNotificationsComponent import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationBlockComponent -import com.tangem.features.swap.v2.impl.R import com.tangem.features.swap.v2.impl.amount.SwapAmountBlockComponent import com.tangem.features.swap.v2.impl.common.entity.ConfirmUM import com.tangem.features.swap.v2.impl.notifications.SwapNotificationsComponent import com.tangem.features.swap.v2.impl.sendviaswap.entity.SendWithSwapUM -import com.tangem.utils.StringsSigns import kotlinx.collections.immutable.ImmutableList @Suppress("LongParameterList") @@ -38,120 +33,44 @@ internal fun SendWithSwapConfirmContent( sendNotificationsUM: ImmutableList, swapNotificationsComponent: SwapNotificationsComponent, swapNotificationsUM: ImmutableList, - onLinkClick: (String) -> Unit, modifier: Modifier = Modifier, ) { val confirmUM = sendWithSwapUM.confirmUM as? ConfirmUM.Content - Column(modifier = modifier) { - LazyColumn( - modifier = Modifier - .weight(1f) - .padding(horizontal = 12.dp), - ) { - item(key = "SendWithSwapBlocks") { - Column( - verticalArrangement = Arrangement.spacedBy(12.dp), - ) { - amountBlockComponent.Content(Modifier) - sendDestinationBlockComponent.Content(Modifier) - feeSelectorBlockComponent.Content(Modifier.clip(RoundedCornerShape(16.dp))) - } + LazyColumn( + modifier = modifier + .padding(horizontal = 12.dp), + ) { + item(key = "SendWithSwapBlocks") { + Column( + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + amountBlockComponent.Content(Modifier) + sendDestinationBlockComponent.Content(Modifier) + feeSelectorBlockComponent.Content(Modifier.clip(RoundedCornerShape(16.dp))) } - if (confirmUM != null) { - // tapHelp(isDisplay = confirmUM.showTapHelp) // todo - with(swapNotificationsComponent) { - content( - state = swapNotificationsUM, - isClickDisabled = confirmUM.isTransactionInProcess, - ) - } - with(sendNotificationsComponent) { - content( - state = sendNotificationsUM, - isClickDisabled = confirmUM.isTransactionInProcess, - ) - } - notifications( - notifications = confirmUM.notifications, + } + if (confirmUM != null) { + // tapHelp(isDisplay = confirmUM.showTapHelp) // todo + with(swapNotificationsComponent) { + content( + state = swapNotificationsUM, isClickDisabled = confirmUM.isTransactionInProcess, ) } - } - val sendFooter = confirmUM?.sendingFooter ?: TextReference.EMPTY - val legalFooter = getAnnotatedStringForLegals(confirmUM?.tosUM, onClick = onLinkClick) - SendingText( - footerText = if (sendFooter != TextReference.EMPTY || legalFooter != TextReference.EMPTY) { - combinedReference(sendFooter, legalFooter) - } else { - TextReference.EMPTY - }, - ) - } -} - -@Composable -private fun getAnnotatedStringForLegals(tosUM: ConfirmUM.Content.TosUM?, onClick: (String) -> Unit): TextReference { - if (tosUM == null) return TextReference.EMPTY - val tos = tosUM.tosLink - val policy = tosUM.policyLink - return if (tos != null && policy != null) { - val tosTitle = tos.title.resolveReference() - val policyTitle = policy.title.resolveReference() - val fullString = stringResourceSafe(id = R.string.express_legal_two_placeholders, tosTitle, policyTitle) - val tosIndex = fullString.indexOf(tosTitle) - val policyIndex = fullString.indexOf(policyTitle) - - annotatedReference { - append(StringsSigns.POINT_SIGN) - appendSpace() - append(fullString.substring(0, tosIndex)) - withLink( - link = LinkAnnotation.Clickable( - tag = "TOS_TAG", - linkInteractionListener = { onClick(tos.link) }, - ), - block = { - appendColored( - text = fullString.substring(tosIndex, tosIndex + tosTitle.length), - color = TangemTheme.colors.text.accent, - ) - }, - ) - append(fullString.substring(tosIndex + tosTitle.length, policyIndex)) - withLink( - link = LinkAnnotation.Clickable( - tag = "POLICY_TAG", - linkInteractionListener = { onClick(policy.link) }, - ), - block = { - appendColored( - text = fullString.substring(policyIndex, policyIndex + policyTitle.length), - color = TangemTheme.colors.text.accent, - ) - }, + with(sendNotificationsComponent) { + content( + state = sendNotificationsUM, + isClickDisabled = confirmUM.isTransactionInProcess, + ) + } + notifications( + notifications = confirmUM.notifications, + isClickDisabled = confirmUM.isTransactionInProcess, ) } - } else { - val legal = requireNotNull(tos ?: policy) { "tos or policy must not be null" } - val legalTitle = legal.title.resolveReference() - val fullString = stringResourceSafe(id = R.string.express_legal_one_placeholder, legalTitle) - val legalIndex = fullString.indexOf(legalTitle) - - annotatedReference { - append(fullString.substring(0, legalIndex)) - withLink( - link = LinkAnnotation.Clickable( - tag = "LEGAL_TAG", - linkInteractionListener = { onClick(legal.link) }, - ), - block = { - appendColored( - text = fullString.substring(legalIndex, legalIndex + legalTitle.length), - color = TangemTheme.colors.text.accent, - ) - }, - ) + item("SPACER_KEY") { + SpacerH16() } } } \ No newline at end of file diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/success/ui/SendWithSwapSuccessContent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/success/ui/SendWithSwapSuccessContent.kt index 86cb77720c..98400f09aa 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/success/ui/SendWithSwapSuccessContent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/success/ui/SendWithSwapSuccessContent.kt @@ -21,7 +21,7 @@ import com.tangem.common.ui.amountScreen.utils.getFiatReference import com.tangem.common.ui.navigationButtons.NavigationButton import com.tangem.common.ui.navigationButtons.NavigationButtonsBlockV2 import com.tangem.common.ui.navigationButtons.NavigationUM -import com.tangem.core.ui.components.BottomFade +import com.tangem.core.ui.components.Fade import com.tangem.core.ui.components.currency.icon.CurrencyIcon import com.tangem.core.ui.components.icons.identicon.IdentIcon import com.tangem.core.ui.components.inputrow.InputRowBestRate @@ -61,59 +61,70 @@ import java.math.BigDecimal internal fun SendWithSwapSuccessContent(sendWithSwapUM: SendWithSwapUM) { if (sendWithSwapUM.navigationUM !is NavigationUM.Content) return + Column { + Box( + modifier = Modifier + .weight(1f) + .background(TangemTheme.colors.background.tertiary), + ) { + SuccessContent( + sendWithSwapUM = sendWithSwapUM, + modifier = Modifier.fillMaxHeight(), + ) + Fade( + modifier = Modifier.align(Alignment.BottomCenter), + backgroundColor = TangemTheme.colors.background.tertiary, + ) + } + NavigationButtonsBlockV2( + navigationUM = sendWithSwapUM.navigationUM, + modifier = Modifier.padding( + start = 16.dp, + end = 16.dp, + bottom = 16.dp, + ), + ) + } +} + +@Composable +private fun SuccessContent(sendWithSwapUM: SendWithSwapUM, modifier: Modifier = Modifier) { val confirmUM = sendWithSwapUM.confirmUM as? ConfirmUM.Success ?: return val amountUM = sendWithSwapUM.amountUM as? SwapAmountUM.Content ?: return val quoteUM = amountUM.selectedQuote as? SwapQuoteUM.Content ?: return val destinationUM = sendWithSwapUM.destinationUM as? DestinationUM.Content ?: return val feeSelectorUM = sendWithSwapUM.feeSelectorUM as? FeeSelectorUM.Content ?: return - Box( - modifier = Modifier - .fillMaxSize() - .background(TangemTheme.colors.background.tertiary), + Column( + modifier = modifier + .padding(horizontal = 16.dp) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(12.dp), ) { - Column( - modifier = Modifier - .padding(horizontal = 16.dp) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(12.dp), - ) { - TransactionDoneTitle( - title = resourceReference(R.string.sent_transaction_sent_title), - subtitle = resourceReference( - id = R.string.send_date_format, - formatArgs = wrappedList( - confirmUM.transactionDate.toTimeFormat(DateTimeFormatters.dateFormatter), - confirmUM.transactionDate.toTimeFormat(), - ), - ), - modifier = Modifier.padding(vertical = 12.dp), - ) - SwapAmountBlock(amountUM = amountUM) - InputRowBestRate( - imageUrl = confirmUM.provider.imageLarge, - title = stringReference(confirmUM.provider.name), - titleExtra = stringReference(confirmUM.provider.type.typeName), - subtitle = quoteUM.rate, - modifier = Modifier - .clip(TangemTheme.shapes.roundedCornersXMedium) - .background(TangemTheme.colors.background.action), - ) - DestinationBlock(destinationUM.addressTextField) - FeeBlock(feeSelectorUM = feeSelectorUM) - Spacer(Modifier.height(128.dp)) - } - BottomFade(Modifier.align(Alignment.BottomCenter), TangemTheme.colors.background.tertiary) - NavigationButtonsBlockV2( - navigationUM = sendWithSwapUM.navigationUM, - modifier = Modifier - .align(Alignment.BottomCenter) - .padding( - start = 16.dp, - end = 16.dp, - bottom = 16.dp, + TransactionDoneTitle( + title = resourceReference(R.string.sent_transaction_sent_title), + subtitle = resourceReference( + id = R.string.send_date_format, + formatArgs = wrappedList( + confirmUM.transactionDate.toTimeFormat(DateTimeFormatters.dateFormatter), + confirmUM.transactionDate.toTimeFormat(), ), + ), + modifier = Modifier.padding(vertical = 12.dp), ) + SwapAmountBlock(amountUM = amountUM) + InputRowBestRate( + imageUrl = confirmUM.provider.imageLarge, + title = stringReference(confirmUM.provider.name), + titleExtra = stringReference(confirmUM.provider.type.typeName), + subtitle = quoteUM.rate, + modifier = Modifier + .clip(TangemTheme.shapes.roundedCornersXMedium) + .background(TangemTheme.colors.background.action), + ) + DestinationBlock(destinationUM.addressTextField) + FeeBlock(feeSelectorUM = feeSelectorUM) + Spacer(Modifier.height(16.dp)) } } diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/ui/SendWithSwapContent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/ui/SendWithSwapContent.kt index 3075a24638..fe0e00831b 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/ui/SendWithSwapContent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/ui/SendWithSwapContent.kt @@ -1,11 +1,14 @@ package com.tangem.features.swap.v2.impl.sendviaswap.ui +import androidx.compose.animation.* import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.LinkAnnotation +import androidx.compose.ui.text.withLink import androidx.compose.ui.unit.dp import com.arkivanov.decompose.extensions.compose.stack.Children import com.arkivanov.decompose.extensions.compose.stack.animation.fade @@ -13,18 +16,25 @@ import com.arkivanov.decompose.extensions.compose.stack.animation.plus import com.arkivanov.decompose.extensions.compose.stack.animation.slide import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation import com.arkivanov.decompose.router.stack.ChildStack +import com.tangem.common.ui.footers.SendingText import com.tangem.common.ui.navigationButtons.NavigationPrimaryButton import com.tangem.common.ui.navigationButtons.NavigationUM +import com.tangem.core.ui.components.Fade import com.tangem.core.ui.components.appbar.AppBarWithBackButton import com.tangem.core.ui.decompose.ComposableContentComponent -import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.swap.v2.impl.R +import com.tangem.features.swap.v2.impl.common.entity.ConfirmUM import com.tangem.features.swap.v2.impl.sendviaswap.SendWithSwapRoute +import com.tangem.utils.StringsSigns @Composable internal fun SendWithSwapContent( navigationUM: NavigationUM, + confirmUM: ConfirmUM, stackState: ChildStack, + onLinkClick: (String) -> Unit, ) { val navigationUM = navigationUM as? NavigationUM.Content ?: return @@ -53,16 +63,109 @@ internal fun SendWithSwapContent( }, modifier = Modifier.weight(1f), ) { - it.instance.Content(Modifier.weight(1f)) + Box(modifier = Modifier.fillMaxHeight()) { + it.instance.Content(Modifier.fillMaxSize(1f)) + + if (stackState.active.configuration != SendWithSwapRoute.Success) { + Fade( + backgroundColor = TangemTheme.colors.background.tertiary, + modifier = Modifier.align(Alignment.BottomCenter), + ) + } + } } if (stackState.active.configuration != SendWithSwapRoute.Success) { - NavigationPrimaryButton( - navigationUM.primaryButton, - modifier = Modifier.padding( - start = 16.dp, - end = 16.dp, - bottom = 16.dp, + Column { + AnimatedVisibility( + visible = stackState.active.configuration == SendWithSwapRoute.Confirm, + enter = slideInVertically(initialOffsetY = { it / 2 }) + fadeIn(), + exit = slideOutVertically(targetOffsetY = { it / 2 }) + fadeOut(), + ) { + val confirmContentUM = confirmUM as? ConfirmUM.Content + val sendFooter = confirmContentUM?.sendingFooter ?: TextReference.EMPTY + val legalFooter = getAnnotatedStringForLegals(confirmContentUM?.tosUM, onClick = onLinkClick) + SendingText( + footerText = if (sendFooter != TextReference.EMPTY || legalFooter != TextReference.EMPTY) { + combinedReference(sendFooter, legalFooter) + } else { + TextReference.EMPTY + }, + ) + } + NavigationPrimaryButton( + navigationUM.primaryButton, + modifier = Modifier.padding( + start = 16.dp, + end = 16.dp, + bottom = 16.dp, + ), + ) + } + } + } +} + +@Composable +private fun getAnnotatedStringForLegals(tosUM: ConfirmUM.Content.TosUM?, onClick: (String) -> Unit): TextReference { + if (tosUM == null) return TextReference.EMPTY + val tos = tosUM.tosLink + val policy = tosUM.policyLink + return if (tos != null && policy != null) { + val tosTitle = tos.title.resolveReference() + val policyTitle = policy.title.resolveReference() + val fullString = stringResourceSafe(id = R.string.express_legal_two_placeholders, tosTitle, policyTitle) + val tosIndex = fullString.indexOf(tosTitle) + val policyIndex = fullString.indexOf(policyTitle) + + annotatedReference { + append(StringsSigns.POINT_SIGN) + appendSpace() + append(fullString.substring(0, tosIndex)) + withLink( + link = LinkAnnotation.Clickable( + tag = "TOS_TAG", + linkInteractionListener = { onClick(tos.link) }, ), + block = { + appendColored( + text = fullString.substring(tosIndex, tosIndex + tosTitle.length), + color = TangemTheme.colors.text.accent, + ) + }, + ) + append(fullString.substring(tosIndex + tosTitle.length, policyIndex)) + withLink( + link = LinkAnnotation.Clickable( + tag = "POLICY_TAG", + linkInteractionListener = { onClick(policy.link) }, + ), + block = { + appendColored( + text = fullString.substring(policyIndex, policyIndex + policyTitle.length), + color = TangemTheme.colors.text.accent, + ) + }, + ) + } + } else { + val legal = requireNotNull(tos ?: policy) { "tos or policy must not be null" } + val legalTitle = legal.title.resolveReference() + val fullString = stringResourceSafe(id = R.string.express_legal_one_placeholder, legalTitle) + val legalIndex = fullString.indexOf(legalTitle) + + annotatedReference { + append(fullString.substring(0, legalIndex)) + withLink( + link = LinkAnnotation.Clickable( + tag = "LEGAL_TAG", + linkInteractionListener = { onClick(legal.link) }, + ), + block = { + appendColored( + text = fullString.substring(legalIndex, legalIndex + legalTitle.length), + color = TangemTheme.colors.text.accent, + ) + }, ) } }