diff --git a/app/src/main/res/layout/layout_send_receipt.xml b/app/src/main/res/layout/layout_send_receipt.xml
index 4a8fab6816..97e7afbb0f 100644
--- a/app/src/main/res/layout/layout_send_receipt.xml
+++ b/app/src/main/res/layout/layout_send_receipt.xml
@@ -33,7 +33,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:text="@string/send_fee_label"
+ android:text="@string/common_fee_label"
android:textColor="@color/text_tertiary"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml
index 3bc3defd6d..ddbf073872 100644
--- a/core/res/src/main/res/values-de/strings.xml
+++ b/core/res/src/main/res/values-de/strings.xml
@@ -13,6 +13,7 @@
Änderungen speichern
Absenden
Erfolg
+ Gebühr
Zugangscode
Sie müssen den richtigen Zugangscode eingeben, bevor Sie die Karte scannen.
Langes Tippen
@@ -40,7 +41,6 @@
Tag
Memo
inkl. Gebühr
- Gebühr
Niedrig
Normal
Priorität
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index 097c597e6e..9ac49cb6d8 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -13,6 +13,7 @@
Sauvegarder les modifications
Envoyer
Avec succès
+ Commissions
Code d\'accès
Vous devrez entrer le mot de passe correct avant de scanner la carte
Tenez la carte fermement
@@ -40,7 +41,6 @@
Tag
Memo
Inclure les commissions
- Commissions
Bas
Normal
Priorité
diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml
index aa5a2b3d47..f673e3bf38 100644
--- a/core/res/src/main/res/values-it/strings.xml
+++ b/core/res/src/main/res/values-it/strings.xml
@@ -13,6 +13,7 @@
Mantieni le modifiche
Invia
Con successo
+ Commissione
Codice di accesso
Prima di scansionare la carta sarà necessario inserire il codice di accesso corretto
Mantenimento della carta
@@ -40,7 +41,6 @@
Tag
Memo
Includi commissione
- Commissione
Insufficiente
Normale
Prioritario
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 3473a16427..77fd07304f 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -126,6 +126,7 @@
Отправить
Успешно
Обмен
+ Комиссия
условия участия
Ошибка транзакции
Транзакции
@@ -423,7 +424,6 @@
Tag
Memo
Включая комиссию
- Комиссия
Низкая
Нормальная
Приоритетная
diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml
index 0b9c4e90a9..f595e68773 100644
--- a/core/res/src/main/res/values-zh-rTW/strings.xml
+++ b/core/res/src/main/res/values-zh-rTW/strings.xml
@@ -90,6 +90,7 @@
提交
成功
交換
+ 費用
條款和條件
交易
我了解
@@ -294,7 +295,6 @@
Tag
Memo
包含費用
- 費用
低
正常
優先
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index e88c410260..ffc1858e33 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -125,6 +125,7 @@
Submit
Success
Swap
+ Fee
terms and conditions
Transaction failed
Transactions
@@ -438,7 +439,6 @@
Memo
Insufficient funds for transfer
Include fee
- Fee
Low
Normal
Priority
@@ -536,6 +536,8 @@
Unlimited
View in Explorer
In progress
+ You swap
+ You receive
Swap
Swap of %s to
Quotes include an additional Tangem commission of %s. This helps us deliver a top-of-the-line product.
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt b/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt
deleted file mode 100644
index c5c3feabc1..0000000000
--- a/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt
+++ /dev/null
@@ -1,181 +0,0 @@
-package com.tangem.core.ui.components
-
-import androidx.annotation.DrawableRes
-import androidx.annotation.StringRes
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.Icon
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import com.tangem.core.ui.R
-import com.tangem.core.ui.res.TangemTheme
-
-/**
- * Screen for showing result
- *
- * @param resultMessage message to show
- * @param title title to show
- * @param resultColor color which will tint the round icon of the result
- * @param icon icon to show in the middle of the round icon
- * @param secondaryButtonIcon icon to show in the secondary button
- * @param secondaryButtonText label of the secondary button
- * @param onSecondaryButtonClick action on clicking secondary button
- * @param onButtonClick action on clicking "Done" button
- *
- * @see Figma component
- */
-@Composable
-fun ResultScreenContent(
- resultMessage: AnnotatedString,
- onButtonClick: () -> Unit,
- modifier: Modifier = Modifier,
- @StringRes title: Int = R.string.common_success,
- resultColor: Color = TangemTheme.colors.icon.accent,
- @DrawableRes icon: Int = R.drawable.ic_check_24,
- @DrawableRes secondaryButtonIcon: Int? = null,
- @StringRes secondaryButtonText: Int? = null,
- onSecondaryButtonClick: (() -> Unit)? = null,
-) {
- Column(
- modifier = modifier
- .fillMaxSize()
- .verticalScroll(rememberScrollState())
- .background(TangemTheme.colors.background.secondary)
- .padding(
- horizontal = TangemTheme.dimens.spacing16,
- vertical = TangemTheme.dimens.spacing32,
- ),
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.Center,
- ) {
- SpacerHHalf()
- SuccessImage(resultColor = resultColor, icon = icon)
- SpacerH50()
- Text(
- text = stringResource(id = title),
- style = TangemTheme.typography.h2,
- color = TangemTheme.colors.text.primary1,
- textAlign = TextAlign.Center,
- modifier = Modifier.fillMaxWidth(),
- )
- SpacerH12()
- Text(
- text = resultMessage,
- style = TangemTheme.typography.subtitle1,
- color = TangemTheme.colors.text.secondary,
- textAlign = TextAlign.Center,
- modifier = Modifier.fillMaxWidth(),
- )
- SpacerHHalf()
- if (onSecondaryButtonClick != null && secondaryButtonText != null) {
- SecondaryButtonForResultScreen(
- secondaryButtonText = secondaryButtonText,
- secondaryButtonIcon = secondaryButtonIcon,
- onSecondaryButtonClick = onSecondaryButtonClick,
- )
- SpacerH12()
- }
- PrimaryButton(
- text = stringResource(id = R.string.common_close),
- modifier = Modifier
- .fillMaxWidth(),
- onClick = { onButtonClick() },
- )
- }
-}
-
-@Composable
-fun SuccessImage(resultColor: Color, @DrawableRes icon: Int) {
- Box(
- modifier = Modifier
- .background(
- color = resultColor.copy(alpha = 0.2f),
- shape = CircleShape,
- ),
- contentAlignment = Alignment.Center,
- ) {
- Box(
- modifier = Modifier
- .padding(TangemTheme.dimens.spacing24)
- .background(
- color = resultColor,
- shape = CircleShape,
- )
- .height(TangemTheme.dimens.size93)
- .width(TangemTheme.dimens.size93),
- contentAlignment = Alignment.Center,
- ) {
- Icon(
- painter = painterResource(id = icon),
- contentDescription = null,
- tint = TangemTheme.colors.icon.primary2,
- modifier = Modifier.size(TangemTheme.dimens.size40),
- )
- }
- }
-}
-
-@Composable
-private fun SecondaryButtonForResultScreen(
- @StringRes secondaryButtonText: Int,
- onSecondaryButtonClick: () -> Unit,
- @DrawableRes secondaryButtonIcon: Int? = null,
-) {
- if (secondaryButtonIcon != null) {
- SecondaryButtonIconStart(
- text = stringResource(id = secondaryButtonText),
- iconResId = secondaryButtonIcon,
- onClick = onSecondaryButtonClick,
- modifier = Modifier.fillMaxWidth(),
- )
- } else {
- SecondaryButton(
- text = stringResource(id = secondaryButtonText),
- onClick = onSecondaryButtonClick,
- modifier = Modifier.fillMaxWidth(),
- )
- }
-}
-
-// region preview
-
-@Composable
-private fun SuccessScreenPreview() {
- ResultScreenContent(
- resultMessage = AnnotatedString("Swap of 1 000 DAI to 1 131,46 MATIC"),
- secondaryButtonText = R.string.swapping_success_view_explorer_button_title,
- onSecondaryButtonClick = {},
- onButtonClick = {},
- )
-}
-
-@Preview(showBackground = true)
-@Composable
-private fun Preview_SuccessScreenContent_InLightTheme() {
- TangemTheme(isDark = false) {
- SuccessScreenPreview()
- }
-}
-
-@Preview(showBackground = true)
-@Composable
-private fun Preview_SuccessScreenContent_InDarkTheme() {
- TangemTheme(isDark = true) {
- SuccessScreenPreview()
- }
-}
-
-// endregion preview
\ No newline at end of file
diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt
index a685079175..21724f8e9e 100644
--- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt
+++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt
@@ -5,6 +5,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.components.states.Item
import com.tangem.core.ui.components.states.SelectableItemsState
+import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.feature.swap.domain.models.ui.TxFee
import com.tangem.feature.swap.models.states.FeeItemState
import com.tangem.feature.swap.models.states.ProviderState
@@ -44,6 +45,7 @@ sealed class SwapCardState {
data class SwapCardData(
val type: TransactionCardType,
val amountEquivalent: String?,
+ val token: CryptoCurrencyStatus?,
val coinId: String?,
val amountTextFieldValue: TextFieldValue?,
val tokenIconUrl: String?,
diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt
index 56dc3525a8..640c4809d3 100644
--- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt
+++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt
@@ -1,7 +1,20 @@
package com.tangem.feature.swap.models
+import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.feature.swap.domain.models.domain.SwapProvider
+
data class SwapSuccessStateHolder(
- val fromTokenAmount: String,
- val toTokenAmount: String,
+ val timestamp: Long,
+ val txUrl: String,
+ val fee: TextReference,
+ val rate: TextReference,
+ val selectedProvider: SwapProvider,
+ val fromTokenAmount: TextReference,
+ val toTokenAmount: TextReference,
+ val fromTokenFiatAmount: TextReference,
+ val toTokenFiatAmount: TextReference,
+ val fromTokenIconState: TokenIconState?,
+ val toTokenIconState: TokenIconState?,
val onSecondaryButtonClick: () -> Unit,
)
\ No newline at end of file
diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt
index b6a1ec961e..6e30057199 100644
--- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt
+++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt
@@ -4,6 +4,7 @@ import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import com.tangem.common.Provider
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
+import com.tangem.core.ui.components.currency.tokenicon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
@@ -22,6 +23,7 @@ import com.tangem.feature.swap.domain.models.ui.*
import com.tangem.feature.swap.models.*
import com.tangem.feature.swap.models.states.*
import com.tangem.feature.swap.presentation.R
+import com.tangem.feature.swap.viewmodels.SwapProcessDataState
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import java.math.BigDecimal
@@ -37,6 +39,8 @@ internal class StateBuilder(
private val appCurrencyProvider: Provider,
) {
+ private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
+
private val tokensDataConverter = TokensDataConverter(
onSearchEntered = actions.onSearchEntered,
onTokenSelected = actions.onTokenSelected,
@@ -52,6 +56,7 @@ internal class StateBuilder(
type = TransactionCardType.SendCard(actions.onAmountChanged, actions.onAmountSelected),
amountEquivalent = null,
amountTextFieldValue = null,
+ token = null,
tokenIconUrl = initialCurrency.iconUrl,
tokenCurrency = initialCurrency.symbol,
coinId = initialCurrency.network.backendId,
@@ -65,6 +70,7 @@ internal class StateBuilder(
amountEquivalent = null,
tokenIconUrl = "",
tokenCurrency = "",
+ token = null,
amountTextFieldValue = null,
canSelectAnotherToken = false,
balance = "",
@@ -98,6 +104,7 @@ internal class StateBuilder(
text = "0",
),
amountEquivalent = "0 ${appCurrencyProvider.invoke().symbol}",
+ token = fromToken,
tokenIconUrl = uiStateHolder.sendCardData.tokenIconUrl,
coinId = uiStateHolder.sendCardData.coinId,
isNotNativeToken = uiStateHolder.sendCardData.isNotNativeToken,
@@ -148,6 +155,7 @@ internal class StateBuilder(
type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard),
amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue,
amountEquivalent = null,
+ token = uiStateHolder.sendCardData.token,
tokenIconUrl = fromToken.iconUrl,
tokenCurrency = fromToken.symbol,
coinId = fromToken.network.backendId,
@@ -160,6 +168,7 @@ internal class StateBuilder(
type = TransactionCardType.ReceiveCard(),
amountTextFieldValue = null,
amountEquivalent = null,
+ token = uiStateHolder.receiveCardData.token,
tokenIconUrl = toToken.iconUrl,
tokenCurrency = toToken.symbol,
coinId = toToken.network.backendId,
@@ -225,6 +234,7 @@ internal class StateBuilder(
type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard),
amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue,
amountEquivalent = getFormattedFiatAmount(quoteModel.fromTokenInfo.amountFiat),
+ token = fromCurrencyStatus,
tokenIconUrl = uiStateHolder.sendCardData.tokenIconUrl,
coinId = fromCurrencyStatus.currency.network.backendId,
isNotNativeToken = uiStateHolder.sendCardData.isNotNativeToken,
@@ -237,6 +247,7 @@ internal class StateBuilder(
type = TransactionCardType.ReceiveCard(),
amountTextFieldValue = TextFieldValue(quoteModel.toTokenInfo.tokenAmount.formatToUIRepresentation()),
amountEquivalent = getFormattedFiatAmount(quoteModel.toTokenInfo.amountFiat),
+ token = toCurrencyStatus,
tokenIconUrl = uiStateHolder.receiveCardData.tokenIconUrl,
coinId = toCurrencyStatus.currency.network.backendId,
isNotNativeToken = uiStateHolder.receiveCardData.isNotNativeToken,
@@ -282,6 +293,7 @@ internal class StateBuilder(
type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard),
amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue,
amountEquivalent = emptyAmountState.zeroAmountEquivalent,
+ token = uiStateHolder.sendCardData.token,
tokenIconUrl = uiStateHolder.sendCardData.tokenIconUrl,
coinId = uiStateHolder.sendCardData.coinId,
isNotNativeToken = uiStateHolder.sendCardData.isNotNativeToken,
@@ -294,6 +306,7 @@ internal class StateBuilder(
type = TransactionCardType.ReceiveCard(),
amountTextFieldValue = TextFieldValue("0"),
amountEquivalent = emptyAmountState.zeroAmountEquivalent,
+ token = uiStateHolder.receiveCardData.token,
tokenIconUrl = uiStateHolder.receiveCardData.tokenIconUrl,
coinId = uiStateHolder.receiveCardData.coinId,
isNotNativeToken = uiStateHolder.receiveCardData.isNotNativeToken,
@@ -434,12 +447,38 @@ internal class StateBuilder(
fun createSuccessState(
uiState: SwapStateHolder,
txState: TxState.TxSent,
+ dataState: SwapProcessDataState,
+ txUrl: String,
onSecondaryBtnClick: () -> Unit,
): SwapStateHolder {
+ val fromToken = requireNotNull(uiState.sendCardData as? SwapCardState.SwapCardData)
+ val toToken = requireNotNull(uiState.receiveCardData as? SwapCardState.SwapCardData)
+ val fromTokenIconState = fromToken.token?.let(iconStateConverter::convert)
+ val toTokenIconState = toToken.token?.let(iconStateConverter::convert)
+ val fee = uiState.fee as? FeeItemState.Content ?: return uiState
+ val fromCryptoCurrencyStatus = requireNotNull(fromToken.token)
+ val toCryptoCurrencyStatus = requireNotNull(toToken.token)
+ val rate = txState.toAmount?.toBigDecimal()?.divide(
+ txState.fromAmount?.toBigDecimal(),
+ toCryptoCurrencyStatus.currency.decimals,
+ RoundingMode.HALF_UP,
+ )
+ val fromCurrencySymbol = fromCryptoCurrencyStatus.currency.symbol
+ val toCurrencySymbol = toCryptoCurrencyStatus.currency.symbol
+
return uiState.copy(
successState = SwapSuccessStateHolder(
- fromTokenAmount = txState.fromAmount ?: "",
- toTokenAmount = txState.toAmount ?: "",
+ timestamp = System.currentTimeMillis(),
+ txUrl = txUrl,
+ selectedProvider = requireNotNull(dataState.selectedProvider),
+ fee = TextReference.Str("${fee.amountCrypto} ${fee.symbolCrypto} (${fee.amountFiatFormatted})"),
+ rate = TextReference.Str("1 $fromCurrencySymbol ≈ $rate $toCurrencySymbol"),
+ fromTokenAmount = TextReference.Str("${txState.fromAmount.orEmpty()} ${fromToken.tokenCurrency}}"),
+ toTokenAmount = TextReference.Str("${txState.toAmount.orEmpty()} ${toToken.tokenCurrency}}"),
+ fromTokenFiatAmount = TextReference.Str(fromToken.amountEquivalent.orEmpty()),
+ toTokenFiatAmount = TextReference.Str(toToken.amountEquivalent.orEmpty()),
+ fromTokenIconState = fromTokenIconState,
+ toTokenIconState = toTokenIconState,
onSecondaryButtonClick = onSecondaryBtnClick,
),
)
diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheet.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheet.kt
index 724c3e44d8..39ecc48a11 100644
--- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheet.kt
+++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheet.kt
@@ -272,7 +272,7 @@ private fun DropdownSelector(
@Composable
private fun FeeItem(fee: String) {
InformationItem(
- subtitle = stringResource(id = R.string.send_fee_label),
+ subtitle = stringResource(id = R.string.common_fee_label),
value = fee,
)
}
diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt
index 8d81d961db..bf382cbc41 100644
--- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt
+++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt
@@ -336,6 +336,7 @@ private val sendCard = SwapCardState.SwapCardData(
canSelectAnotherToken = false,
balance = "123",
coinId = "",
+ token = null,
isBalanceHidden = false,
)
@@ -349,6 +350,7 @@ private val receiveCard = SwapCardState.SwapCardData(
canSelectAnotherToken = true,
balance = "33333",
coinId = "",
+ token = null,
isBalanceHidden = false,
)
diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt
index a05fbdb29b..909239af13 100644
--- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt
+++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt
@@ -1,18 +1,29 @@
package com.tangem.feature.swap.ui
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.systemBarsPadding
+import androidx.annotation.StringRes
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.hapticfeedback.HapticFeedbackType
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.SpanStyle
-import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.tooling.preview.Preview
-import com.tangem.core.ui.components.ResultScreenContent
+import com.tangem.core.ui.components.*
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
+import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
+import com.tangem.core.ui.components.inputrow.InputRowBestRate
+import com.tangem.core.ui.components.inputrow.InputRowDefault
+import com.tangem.core.ui.components.inputrow.InputRowImage
+import com.tangem.core.ui.components.transactions.TransactionDoneTitle
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.shareText
import com.tangem.core.ui.res.TangemTheme
+import com.tangem.feature.swap.domain.models.domain.ExchangeProviderType
+import com.tangem.feature.swap.domain.models.domain.SwapProvider
import com.tangem.feature.swap.models.SwapSuccessStateHolder
import com.tangem.feature.swap.presentation.R
@@ -21,41 +32,117 @@ fun SwapSuccessScreen(state: SwapSuccessStateHolder, onBack: () -> Unit) {
Scaffold(
modifier = Modifier.systemBarsPadding(),
content = { padding ->
- ResultScreenContent(
- resultMessage = makeSuccessMessage(
- fromTokenAmount = state.fromTokenAmount,
- toTokenAmount = state.toTokenAmount,
- ),
- resultColor = TangemTheme.colors.icon.attention,
- onButtonClick = onBack,
- icon = R.drawable.ic_clock_24,
- secondaryButtonIcon = R.drawable.ic_arrow_top_right_24,
- onSecondaryButtonClick = state.onSecondaryButtonClick,
- secondaryButtonText = R.string.swapping_success_view_explorer_button_title,
- title = R.string.swapping_success_view_title,
- modifier = Modifier.padding(padding),
- )
+ SwapSuccessScreenContent(padding = padding, state = state)
},
topBar = {
AppBarWithBackButton(
- text = stringResource(R.string.common_swap),
onBackClick = onBack,
iconRes = R.drawable.ic_close_24,
)
},
+ bottomBar = {
+ SwapSuccessScreenButtons(
+ textRes = R.string.common_close,
+ txUrl = state.txUrl,
+ onExploreClick = state.onSecondaryButtonClick,
+ onDoneClick = onBack,
+ )
+ },
)
}
@Composable
-private fun makeSuccessMessage(fromTokenAmount: String, toTokenAmount: String): AnnotatedString {
- val swapToString = stringResource(id = R.string.swapping_swap_of_to, fromTokenAmount)
- val message = "$swapToString\n$toTokenAmount"
- return buildAnnotatedString {
- append(message)
- addStyle(
- style = SpanStyle(color = TangemTheme.colors.text.accent),
- start = message.indexOf(toTokenAmount),
- end = message.length,
+private fun SwapSuccessScreenContent(state: SwapSuccessStateHolder, padding: PaddingValues) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(padding)
+ .background(TangemTheme.colors.background.secondary)
+ .padding(horizontal = TangemTheme.dimens.spacing16),
+ ) {
+ TransactionDoneTitle(titleRes = R.string.swapping_success_view_title, date = 0L)
+ SpacerH16()
+ InputRowImage(
+ title = TextReference.Res(R.string.swapping_success_from_title),
+ subtitle = state.fromTokenAmount,
+ caption = state.fromTokenFiatAmount,
+ tokenIconState = state.fromTokenIconState ?: TokenIconState.Loading,
+ modifier = Modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action),
+ )
+ SpacerH16()
+ InputRowImage(
+ title = TextReference.Res(R.string.swapping_success_to_title),
+ subtitle = state.toTokenAmount,
+ caption = state.toTokenFiatAmount,
+ tokenIconState = state.toTokenIconState ?: TokenIconState.Loading,
+ modifier = Modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action),
+ )
+ SpacerH16()
+ InputRowBestRate(
+ imageUrl = state.selectedProvider.imageLarge,
+ title = TextReference.Str(state.selectedProvider.name),
+ titleExtra = TextReference.Str(state.selectedProvider.type.name),
+ subtitle = state.rate,
+ modifier = Modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action),
+ )
+ SpacerH16()
+ InputRowDefault(
+ title = TextReference.Res(R.string.common_fee_label),
+ text = state.fee,
+ modifier = Modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action),
+ )
+ }
+}
+
+@Composable
+private fun SwapSuccessScreenButtons(
+ @StringRes textRes: Int,
+ txUrl: String,
+ onExploreClick: () -> Unit,
+ onDoneClick: () -> Unit,
+) {
+ val hapticFeedback = LocalHapticFeedback.current
+ val context = LocalContext.current
+
+ Column(
+ modifier = Modifier
+ .background(TangemTheme.colors.background.secondary)
+ .padding(TangemTheme.dimens.spacing16),
+ ) {
+ if (txUrl.isNotBlank()) {
+ Row {
+ SecondaryButtonIconStart(
+ text = stringResource(id = com.tangem.core.ui.R.string.common_explore),
+ iconResId = com.tangem.core.ui.R.drawable.ic_web_24,
+ onClick = onExploreClick,
+ modifier = Modifier.weight(1f),
+ )
+ SpacerW12()
+ SecondaryButtonIconStart(
+ text = stringResource(id = com.tangem.core.ui.R.string.common_share),
+ iconResId = com.tangem.core.ui.R.drawable.ic_share_24,
+ onClick = {
+ hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
+ context.shareText(txUrl)
+ },
+ modifier = Modifier.weight(1f),
+ )
+ }
+ SpacerH12()
+ }
+ PrimaryButton(
+ text = stringResource(id = textRes),
+ enabled = true,
+ onClick = onDoneClick,
+ modifier = Modifier.fillMaxWidth(),
)
}
}
@@ -63,9 +150,25 @@ private fun makeSuccessMessage(fromTokenAmount: String, toTokenAmount: String):
// region preview
private val state = SwapSuccessStateHolder(
- fromTokenAmount = "1 000 DAI",
- toTokenAmount = "1 131,46 MATIC",
-) {}
+ timestamp = 0L,
+ txUrl = "https://www.google.com/#q=nam",
+ fee = TextReference.Str("1 000 DAI ~ 1 000 MATIC"),
+ selectedProvider = SwapProvider(
+ providerId = "1inch",
+ rateTypes = listOf(),
+ name = "1inch",
+ type = ExchangeProviderType.DEX,
+ imageLarge = "",
+ ),
+ fromTokenAmount = TextReference.Str("1 000 DAI"),
+ toTokenAmount = TextReference.Str("1 000 MATIC"),
+ fromTokenFiatAmount = TextReference.Str("1 000 $"),
+ toTokenFiatAmount = TextReference.Str("1 000 $"),
+ fromTokenIconState = TokenIconState.Loading,
+ toTokenIconState = TokenIconState.Loading,
+ rate = TextReference.Str("1 000 DAI ~ 1 000 MATIC"),
+ onSecondaryButtonClick = {},
+)
@Preview(showBackground = true)
@Composable
diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt
index 41287a8bc6..76e960107b 100644
--- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt
+++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt
@@ -351,17 +351,22 @@ internal class SwapViewModel @Inject constructor(
.onSuccess {
when (it) {
is TxState.TxSent -> {
- uiState = stateBuilder.createSuccessState(uiState, it) {
- val txHash = it.txAddress
- if (txHash.isNotEmpty()) {
- swapRouter.openUrl(
- blockchainInteractor.getExplorerTransactionLink(
- networkId = dataState.networkId,
- txAddress = it.txAddress,
- ),
- )
- }
- }
+ val url = blockchainInteractor.getExplorerTransactionLink(
+ networkId = dataState.networkId,
+ txAddress = it.txAddress,
+ )
+ uiState = stateBuilder.createSuccessState(
+ uiState = uiState,
+ txState = it,
+ dataState = dataState,
+ txUrl = url,
+ onSecondaryBtnClick = {
+ val txHash = it.txAddress
+ if (txHash.isNotEmpty()) {
+ swapRouter.openUrl(url)
+ }
+ },
+ )
analyticsEventHandler.send(SwapEvents.SwapInProgressScreen)
swapRouter.openScreen(SwapNavScreen.Success)
}