Updated on 2026-08-14

This commit is contained in:
Tangem 2023-11-27 18:37:48 +03:00
parent 1e19ce06b8
commit 5ce498df75
15 changed files with 222 additions and 237 deletions

View file

@ -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"

View file

@ -13,6 +13,7 @@
<string name="common_save_changes">Änderungen speichern</string>
<string name="common_send">Absenden</string>
<string name="common_success">Erfolg</string>
<string name="common_fee_label">Gebühr</string>
<string name="details_manage_security_access_code">Zugangscode</string>
<string name="details_manage_security_access_code_description">Sie müssen den richtigen Zugangscode eingeben, bevor Sie die Karte scannen.</string>
<string name="details_manage_security_long_tap">Langes Tippen</string>
@ -40,7 +41,6 @@
<string name="send_extras_hint_destination_tag">Tag</string>
<string name="send_extras_hint_memo">Memo</string>
<string name="send_fee_include_description">inkl. Gebühr</string>
<string name="send_fee_label">Gebühr</string>
<string name="send_fee_picker_low">Niedrig</string>
<string name="send_fee_picker_normal">Normal</string>
<string name="send_fee_picker_priority">Priorität</string>

View file

@ -13,6 +13,7 @@
<string name="common_save_changes">Sauvegarder les modifications</string>
<string name="common_send">Envoyer</string>
<string name="common_success">Avec succès</string>
<string name="common_fee_label">Commissions</string>
<string name="details_manage_security_access_code">Code d\'accès</string>
<string name="details_manage_security_access_code_description">Vous devrez entrer le mot de passe correct avant de scanner la carte</string>
<string name="details_manage_security_long_tap">Tenez la carte fermement</string>
@ -40,7 +41,6 @@
<string name="send_extras_hint_destination_tag">Tag</string>
<string name="send_extras_hint_memo">Memo</string>
<string name="send_fee_include_description">Inclure les commissions</string>
<string name="send_fee_label">Commissions</string>
<string name="send_fee_picker_low">Bas</string>
<string name="send_fee_picker_normal">Normal</string>
<string name="send_fee_picker_priority">Priorité</string>

View file

@ -13,6 +13,7 @@
<string name="common_save_changes">Mantieni le modifiche</string>
<string name="common_send">Invia</string>
<string name="common_success">Con successo</string>
<string name="common_fee_label">Commissione</string>
<string name="details_manage_security_access_code">Codice di accesso</string>
<string name="details_manage_security_access_code_description">Prima di scansionare la carta sarà necessario inserire il codice di accesso corretto</string>
<string name="details_manage_security_long_tap">Mantenimento della carta</string>
@ -40,7 +41,6 @@
<string name="send_extras_hint_destination_tag">Tag</string>
<string name="send_extras_hint_memo">Memo</string>
<string name="send_fee_include_description">Includi commissione</string>
<string name="send_fee_label">Commissione</string>
<string name="send_fee_picker_low">Insufficiente</string>
<string name="send_fee_picker_normal">Normale</string>
<string name="send_fee_picker_priority">Prioritario</string>

View file

@ -126,6 +126,7 @@
<string name="common_submit">Отправить</string>
<string name="common_success">Успешно</string>
<string name="common_swap">Обмен</string>
<string name="common_fee_label">Комиссия</string>
<string name="common_terms_and_conditions">условия участия</string>
<string name="common_transaction_failed">Ошибка транзакции</string>
<string name="common_transactions">Транзакции</string>
@ -423,7 +424,6 @@
<string name="send_extras_hint_destination_tag">Tag</string>
<string name="send_extras_hint_memo">Memo</string>
<string name="send_fee_include_description">Включая комиссию</string>
<string name="send_fee_label">Комиссия</string>
<string name="send_fee_picker_low">Низкая</string>
<string name="send_fee_picker_normal">Нормальная</string>
<string name="send_fee_picker_priority">Приоритетная</string>

View file

@ -90,6 +90,7 @@
<string name="common_submit">提交</string>
<string name="common_success">成功</string>
<string name="common_swap">交換</string>
<string name="common_fee_label">費用</string>
<string name="common_terms_and_conditions">條款和條件</string>
<string name="common_transactions">交易</string>
<string name="common_understand">我了解</string>
@ -294,7 +295,6 @@
<string name="send_extras_hint_destination_tag">Tag</string>
<string name="send_extras_hint_memo">Memo</string>
<string name="send_fee_include_description">包含費用</string>
<string name="send_fee_label">費用</string>
<string name="send_fee_picker_low"></string>
<string name="send_fee_picker_normal">正常</string>
<string name="send_fee_picker_priority">優先</string>

View file

@ -125,6 +125,7 @@
<string name="common_submit">Submit</string>
<string name="common_success">Success</string>
<string name="common_swap">Swap</string>
<string name="common_fee_label">Fee</string>
<string name="common_terms_and_conditions">terms and conditions</string>
<string name="common_transaction_failed">Transaction failed</string>
<string name="common_transactions">Transactions</string>
@ -438,7 +439,6 @@
<string name="send_extras_hint_memo">Memo</string>
<string name="send_insufficient_funds">Insufficient funds for transfer</string>
<string name="send_fee_include_description">Include fee</string>
<string name="send_fee_label">Fee</string>
<string name="send_fee_picker_low">Low</string>
<string name="send_fee_picker_normal">Normal</string>
<string name="send_fee_picker_priority">Priority</string>
@ -536,6 +536,8 @@
<string name="swapping_permission_unlimited">Unlimited</string>
<string name="swapping_success_view_explorer_button_title">View in Explorer</string>
<string name="swapping_success_view_title">In progress</string>
<string name="swapping_success_from_title">You swap</string>
<string name="swapping_success_to_title">You receive</string>
<string name="swapping_swap_action">Swap</string>
<string name="swapping_swap_of_to">Swap of %s to</string>
<string name="swapping_tangem_fee_disclaimer">Quotes include an additional Tangem commission of %s. This helps us deliver a top-of-the-line product.</string>

View file

@ -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 <a href =
* "https://www.figma.com/file/Vs6SkVsFnUPsSCNwlnVf5U/Android-%E2%80%93-UI?node-id=1123%3A3863&t=wwR84h5IsMaMsDhq-1"
* >Figma component</a>
*/
@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

View file

@ -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?,

View file

@ -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,
)

View file

@ -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<AppCurrency>,
) {
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,
),
)

View file

@ -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,
)
}

View file

@ -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,
)

View file

@ -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

View file

@ -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)
}