diff --git a/app/src/main/res/layout/layout_single_wallet_balance.xml b/app/src/main/res/layout/layout_single_wallet_balance.xml
index c3a75693bc..d3c6de4ff3 100644
--- a/app/src/main/res/layout/layout_single_wallet_balance.xml
+++ b/app/src/main/res/layout/layout_single_wallet_balance.xml
@@ -21,7 +21,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
- android:text="@string/onboarding_balance_title"
+ android:text="@string/common_balance_title"
android:textColor="@color/text_tertiary"
android:textSize="14sp"
android:textStyle="bold"
diff --git a/app/src/main/res/layout/view_onboarding_tv_balance.xml b/app/src/main/res/layout/view_onboarding_tv_balance.xml
index f421e4d992..f84e954980 100644
--- a/app/src/main/res/layout/view_onboarding_tv_balance.xml
+++ b/app/src/main/res/layout/view_onboarding_tv_balance.xml
@@ -12,7 +12,7 @@
android:elevation="0dp"
android:fontFamily="sans-serif-medium"
android:letterSpacing="0.036"
- android:text="@string/onboarding_balance_title"
+ android:text="@string/common_balance_title"
android:textAllCaps="true"
android:textColor="@color/text_secondary"
android:textSize="14sp"
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 857c2f4ff1..325b697ba9 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -192,6 +192,11 @@
Недоступен для обмена с %s
Провайдеры проводят транзакции, обеспечивая плавный и эффективный обмен токенами
Выберите провайдера
+ Чтобы узнать причину, посетите сайт провайдера
+ Операция не выполнена провайдером
+ Посетите сайт провайдера для проверки
+ Провайдер: требуется верификация
+ Провайдер
Лучший курс
Требуется разрешение
Информация ниже не является обязательной. Вы можете стереть её, если хотите.
@@ -266,7 +271,7 @@
Введенные коды доступа не совпадают
Вы добавили одну резервную карту. После того, как процесс будет завершен, Вы больше не сможете добавить карт. Если у Вас есть еще одна карта, добавьте ее в резервную копию. Хотите продолжить?
Процесс резервного копирования почти завершен. Вы не можете выйти из него сейчас.
- Баланс
+ Баланс
Добавить резервную карту
Сканировать карту #%d
Создать резервную копию
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 b80f9ce410..0b9c4e90a9 100644
--- a/core/res/src/main/res/values-zh-rTW/strings.xml
+++ b/core/res/src/main/res/values-zh-rTW/strings.xml
@@ -178,7 +178,7 @@
輸入的訪問密碼與初始訪問密碼不匹配
您已添加一張備用卡。備份過程完成後,您將無法添加更多備份卡。如果您還有一張卡,請將其添加到備份中。您想繼續備份過程嗎?
備份過程已部分完成。你現在不能退出
- 餘額
+ 餘額
添加備用卡
掃描卡片 #%d
立即備份
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 6bd6a2445a..e88c410260 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -192,7 +192,30 @@
Unavailable for swap from %s
Providers facilitate transactions, ensuring smooth and efficient token exchanges
Choose Provider
- Best Rate
+ Estimated amount
+ Visit provider’s website to see why
+ Operation failed by provider
+ Visit provider’s website for verification
+ Provider: Verification needed
+ Confirmed
+ Confirming
+ Exchanged
+ Exchanging
+ Failed
+ Deposit received
+ Awaiting deposit
+ Sending to you
+ Sent
+ Provider-sourced data. Estimated amount subject to change.
+ Exchange status
+ Verified
+ Verification required
+ Fetching best rates...
+ Floating rate
+ Go to provider
+ Provider
+ Best rate
+ Exchange by %s
Permission Needed
The following information is optional. You can erase it if you don\'t want to share it.
Tell us what functions you are missing, and we will try to help you.
@@ -267,7 +290,7 @@
Entered access code didn\'t match the initial access code
You\'ve added one backup card. When backup process is finished you can\'t add more backup cards. If you have one more card, add it to backup. Do you like to continue the backup process?
The backup process is partly complete. You can\'t exit it now.
- Balance
+ Balance
Add a backup card
Scan the card #%d
Backup now
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt
index 2d9d85b164..5278a24911 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt
@@ -6,6 +6,7 @@ import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SheetState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.*
+import androidx.compose.ui.graphics.Color
import com.tangem.core.ui.res.TangemTheme
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
@@ -20,6 +21,7 @@ import kotlinx.coroutines.launch
@Composable
inline fun TangemBottomSheet(
config: TangemBottomSheetConfig,
+ color: Color = TangemTheme.colors.background.primary,
crossinline content: @Composable ColumnScope.(T) -> Unit,
) {
var isVisible by remember { mutableStateOf(value = config.isShow) }
@@ -29,9 +31,9 @@ inline fun TangemBottomSheet(
ModalBottomSheet(
onDismissRequest = config.onDismissRequest,
sheetState = sheetState,
- containerColor = TangemTheme.colors.background.primary,
+ containerColor = color,
shape = TangemTheme.shapes.bottomSheetLarge,
- dragHandle = { TangemBottomSheetDraggableHeader() },
+ dragHandle = { TangemBottomSheetDraggableHeader(color) },
) {
content(config.content)
}
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowApprox.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowApprox.kt
new file mode 100644
index 0000000000..3b085833a3
--- /dev/null
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowApprox.kt
@@ -0,0 +1,150 @@
+package com.tangem.core.ui.components.inputrow
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.tooling.preview.Preview
+import com.tangem.core.ui.R
+import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
+import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
+import com.tangem.core.ui.components.inputrow.inner.DividerContainer
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.resolveReference
+import com.tangem.core.ui.res.TangemTheme
+
+/**
+ * [Input Row Approx](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=2207-810&mode=design&t=fM1ZU6zQF6g3CaTv-4)
+ *
+ * @param leftIcon left token state
+ * @param leftTitle left token title
+ * @param leftSubtitle left token subtitle
+ * @param rightIcon right token state
+ * @param rightTitle right token title
+ * @param rightSubtitle right token subtitle
+ * @param modifier composable modifier
+ * @param showDivider show divider
+ */
+@Suppress("LongParameterList")
+@Composable
+fun InputRowApprox(
+ leftIcon: TokenIconState,
+ leftTitle: TextReference,
+ leftSubtitle: TextReference,
+ rightIcon: TokenIconState,
+ rightTitle: TextReference,
+ rightSubtitle: TextReference,
+ modifier: Modifier = Modifier,
+ showDivider: Boolean = false,
+) {
+ DividerContainer(
+ showDivider = showDivider,
+ modifier = modifier,
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier
+ .padding(TangemTheme.dimens.spacing12)
+ .fillMaxWidth(),
+ ) {
+ InputRowApproxItem(
+ iconState = leftIcon,
+ title = leftTitle,
+ subtitle = leftSubtitle,
+ )
+ Icon(
+ painter = painterResource(id = R.drawable.ic_approx_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.text.tertiary,
+ modifier = Modifier
+ .padding(
+ horizontal = TangemTheme.dimens.spacing8,
+ vertical = TangemTheme.dimens.spacing10,
+ ),
+ )
+ InputRowApproxItem(
+ iconState = rightIcon,
+ title = rightTitle,
+ subtitle = rightSubtitle,
+ )
+ }
+ }
+}
+
+@Composable
+private fun InputRowApproxItem(
+ iconState: TokenIconState,
+ title: TextReference,
+ subtitle: TextReference,
+ modifier: Modifier = Modifier,
+) {
+ Row(
+ modifier = modifier,
+ ) {
+ TokenIcon(
+ state = iconState,
+ modifier = Modifier
+ .size(TangemTheme.dimens.size36),
+ )
+ Column(
+ modifier = Modifier
+ .padding(
+ start = TangemTheme.dimens.spacing12,
+ ),
+ ) {
+ Text(
+ text = title.resolveReference(),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.primary1,
+ )
+ Text(
+ text = subtitle.resolveReference(),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ modifier = Modifier
+ .padding(top = TangemTheme.dimens.spacing2),
+ )
+ }
+ }
+}
+
+//region Preview
+@Preview
+@Composable
+private fun InputRowApproxPreview_Light() {
+ TangemTheme {
+ InputRowApprox(
+ leftIcon = TokenIconState.Loading,
+ leftTitle = TextReference.Str("Left title"),
+ leftSubtitle = TextReference.Str("Left subtitle"),
+ rightIcon = TokenIconState.Loading,
+ rightTitle = TextReference.Str("Right title"),
+ rightSubtitle = TextReference.Str("Right subtitle"),
+ modifier = Modifier
+ .background(TangemTheme.colors.background.action),
+ )
+ }
+}
+
+@Preview
+@Composable
+private fun InputRowApproxPreview_Dark() {
+ TangemTheme(isDark = true) {
+ InputRowApprox(
+ leftIcon = TokenIconState.Loading,
+ leftTitle = TextReference.Str("Left title"),
+ leftSubtitle = TextReference.Str("Left subtitle"),
+ rightIcon = TokenIconState.Loading,
+ rightTitle = TextReference.Str("Right title"),
+ rightSubtitle = TextReference.Str("Right subtitle"),
+ modifier = Modifier
+ .background(TangemTheme.colors.background.action),
+ )
+ }
+}
+//endregion
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowBestRate.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowBestRate.kt
new file mode 100644
index 0000000000..620e3346cf
--- /dev/null
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowBestRate.kt
@@ -0,0 +1,221 @@
+package com.tangem.core.ui.components.inputrow
+
+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.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.ripple.rememberRipple
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import coil.compose.SubcomposeAsyncImage
+import coil.request.ImageRequest
+import com.tangem.core.ui.R
+import com.tangem.core.ui.components.SpacerWMax
+import com.tangem.core.ui.components.currency.tokenicon.LoadingIcon
+import com.tangem.core.ui.components.inputrow.inner.DividerContainer
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.resolveReference
+import com.tangem.core.ui.res.TangemTheme
+
+/**
+ * [Input Row Best Rate](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=2100-889&mode=dev)
+ *
+ * @param imageUrl image source url
+ * @param title title
+ * @param titleExtra title extra
+ * @param subtitle subtitle
+ * @param modifier composable modifier
+ * @param showTag show tag
+ * @param showDivider show divider
+ * @param onIconClick icon click
+ */
+@Composable
+fun InputRowBestRate(
+ imageUrl: String,
+ title: TextReference,
+ titleExtra: TextReference,
+ subtitle: TextReference,
+ modifier: Modifier = Modifier,
+ showTag: Boolean = false,
+ showDivider: Boolean = false,
+ onIconClick: (() -> Unit)? = null,
+) {
+ DividerContainer(
+ showDivider = showDivider,
+ modifier = modifier,
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .padding(TangemTheme.dimens.spacing12),
+ ) {
+ InnerIcon(imageUrl = imageUrl)
+ Column(
+ modifier = Modifier
+ .padding(start = TangemTheme.dimens.spacing12),
+ ) {
+ InnerTitle(
+ title = title,
+ titleExtra = titleExtra,
+ showTag = showTag,
+ )
+ Text(
+ text = subtitle.resolveReference(),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.tertiary,
+ modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
+ )
+ }
+ SpacerWMax()
+ onIconClick?.let {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_chevron_right_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.informative,
+ modifier = Modifier
+ .padding(vertical = TangemTheme.dimens.spacing10)
+ .clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = rememberRipple(bounded = false),
+ onClick = onIconClick,
+ ),
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun InnerTitle(title: TextReference, titleExtra: TextReference, showTag: Boolean = false) {
+ Row {
+ Text(
+ text = title.resolveReference(),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.primary1,
+ )
+ Text(
+ text = titleExtra.resolveReference(),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ modifier = Modifier
+ .padding(start = TangemTheme.dimens.spacing4),
+ )
+ if (showTag) {
+ Text(
+ text = stringResource(R.string.express_provider_best_rate),
+ style = TangemTheme.typography.caption1,
+ color = TangemTheme.colors.icon.accent,
+ modifier = Modifier
+ .padding(start = TangemTheme.dimens.spacing4)
+ .background(
+ color = TangemTheme.colors.icon.accent.copy(alpha = 0.1f),
+ shape = RoundedCornerShape(TangemTheme.dimens.radius20),
+ )
+ .padding(horizontal = TangemTheme.dimens.spacing6),
+ )
+ }
+ }
+}
+
+@Composable
+private fun InnerIcon(imageUrl: String) {
+ SubcomposeAsyncImage(
+ modifier = Modifier.size(TangemTheme.dimens.size40),
+ model = ImageRequest.Builder(context = LocalContext.current)
+ .data(imageUrl)
+ .crossfade(enable = true)
+ .allowHardware(enable = false)
+ .build(),
+ loading = { LoadingIcon() },
+ error = {
+ Box(
+ modifier = Modifier
+ .background(
+ color = TangemTheme.colors.background.tertiary,
+ shape = CircleShape,
+ ),
+ )
+ },
+ contentDescription = null,
+ )
+}
+
+//region preview
+@Preview
+@Composable
+private fun InputRowBestRatePreview_Light(
+ @PreviewParameter(InputRowBestRatePreviewDataProvider::class) data: InputRowBestRatePreviewData,
+) {
+ TangemTheme {
+ InputRowBestRate(
+ imageUrl = "",
+ title = data.title,
+ titleExtra = data.titleExtra,
+ subtitle = data.subtitle,
+ showTag = data.showTag,
+ onIconClick = data.iconClick,
+ modifier = Modifier
+ .background(TangemTheme.colors.background.action),
+ )
+ }
+}
+
+@Preview
+@Composable
+private fun InputRowBestRatePreview_Dark(
+ @PreviewParameter(InputRowBestRatePreviewDataProvider::class) data: InputRowBestRatePreviewData,
+) {
+ TangemTheme(isDark = true) {
+ InputRowBestRate(
+ imageUrl = "",
+ title = data.title,
+ titleExtra = data.titleExtra,
+ subtitle = data.subtitle,
+ showTag = data.showTag,
+ onIconClick = data.iconClick,
+ modifier = Modifier
+ .background(TangemTheme.colors.background.action),
+ )
+ }
+}
+
+private data class InputRowBestRatePreviewData(
+ val title: TextReference,
+ val titleExtra: TextReference,
+ val showTag: Boolean,
+ val subtitle: TextReference,
+ val iconClick: (() -> Unit)?,
+)
+
+private class InputRowBestRatePreviewDataProvider : PreviewParameterProvider {
+ override val values: Sequence
+ get() = sequenceOf(
+ InputRowBestRatePreviewData(
+ title = TextReference.Str("1inch"),
+ titleExtra = TextReference.Str("DEX"),
+ subtitle = TextReference.Str("0,64554846 DAI ≈ 1 MATIC "),
+ showTag = true,
+ iconClick = {},
+ ),
+ InputRowBestRatePreviewData(
+ title = TextReference.Str("ChangeNow"),
+ titleExtra = TextReference.Str("CEX"),
+ subtitle = TextReference.Str("0,64554846 DAI ≈ 1 MATIC "),
+ showTag = false,
+ iconClick = null,
+ ),
+ )
+}
+//endregion
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt
index 2fc319885d..e68dfd96a0 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt
@@ -41,6 +41,7 @@ data class TangemDimens internal constructor(
val size0: Dp = 0.dp,
val size0_5: Dp = 0.5.dp,
val size1: Dp = 1.dp,
+ val size1_5: Dp = 1.5.dp,
val size2: Dp = 2.dp,
val size4: Dp = 4.dp,
val size5: Dp = 5.dp,
diff --git a/core/ui/src/main/res/drawable/ic_alert_triangle_20.xml b/core/ui/src/main/res/drawable/ic_alert_triangle_20.xml
new file mode 100644
index 0000000000..dfe1b75e71
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_alert_triangle_20.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_approx_24.xml b/core/ui/src/main/res/drawable/ic_approx_24.xml
new file mode 100644
index 0000000000..30eb78ec9d
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_approx_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_exclamation_24.xml b/core/ui/src/main/res/drawable/ic_exclamation_24.xml
new file mode 100644
index 0000000000..d7d5bdca87
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_exclamation_24.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_forward_24.xml b/core/ui/src/main/res/drawable/ic_forward_24.xml
new file mode 100644
index 0000000000..1a35b84bfb
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_forward_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/ExchangeStatus.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/ExchangeStatus.kt
new file mode 100644
index 0000000000..a74e8fbb6a
--- /dev/null
+++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/ExchangeStatus.kt
@@ -0,0 +1,20 @@
+package com.tangem.feature.swap.domain.models.domain
+
+data class ExchangeStatusModel(
+ val providerId: Int,
+ val status: ExchangeStatus? = null,
+ val txId: String? = null,
+ val txUrl: String? = null,
+)
+
+enum class ExchangeStatus {
+ New,
+ Waiting,
+ Confirming,
+ Verifying,
+ Exchanging,
+ Failed,
+ Sending,
+ Finished,
+ Refunded,
+}
\ No newline at end of file
diff --git a/features/tokendetails/impl/build.gradle.kts b/features/tokendetails/impl/build.gradle.kts
index bc5b2cda79..c19e3f3577 100644
--- a/features/tokendetails/impl/build.gradle.kts
+++ b/features/tokendetails/impl/build.gradle.kts
@@ -28,6 +28,7 @@ dependencies {
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.compose.ui.utils)
+ implementation(deps.compose.constraintLayout)
implementation(deps.arrow.core)
implementation(deps.jodatime)
@@ -68,4 +69,5 @@ dependencies {
/** Feature Apis */
implementation(projects.features.tokendetails.api)
implementation(projects.features.send.api)
+ implementation(projects.features.swap.domain)
}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/SwapTransactionsState.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/SwapTransactionsState.kt
new file mode 100644
index 0000000000..8b4fb5c8a5
--- /dev/null
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/SwapTransactionsState.kt
@@ -0,0 +1,31 @@
+package com.tangem.feature.tokendetails.presentation.tokendetails.state
+
+import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
+import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
+import kotlinx.collections.immutable.PersistentList
+import java.math.BigDecimal
+
+internal data class SwapTransactionsState(
+ val txId: String,
+ val providerId: Int,
+ val txUrl: String? = null,
+ val rate: BigDecimal,
+ val timestamp: Long,
+ val status: PersistentList,
+ val activeStatus: ExchangeStatus?,
+ val toCryptoAmount: String,
+ val toFiatAmount: String,
+ val toCurrencyIcon: TokenIconState,
+ val fromCryptoAmount: String,
+ val fromFiatAmount: String,
+ val fromCurrencyIcon: TokenIconState,
+ val onClick: () -> Unit,
+ val onGoToProviderClick: () -> Unit,
+)
+
+internal class ExchangeStatusState(
+ val status: ExchangeStatus,
+ val text: String,
+ val isActive: Boolean,
+ val isDone: Boolean,
+)
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsBalanceBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsBalanceBlock.kt
index 8280f9aeab..f9911ae521 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsBalanceBlock.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenDetailsBalanceBlock.kt
@@ -39,7 +39,7 @@ internal fun TokenDetailsBalanceBlock(
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
),
- text = stringResource(id = R.string.onboarding_balance_title),
+ text = stringResource(id = R.string.common_balance_title),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.subtitle2,
maxLines = 1,
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeEstimate.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeEstimate.kt
new file mode 100644
index 0000000000..c33b4fc290
--- /dev/null
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeEstimate.kt
@@ -0,0 +1,67 @@
+package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.stringResource
+import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
+import com.tangem.core.ui.components.inputrow.InputRowApprox
+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.tokendetails.impl.R
+
+@Suppress("LongParameterList")
+@Composable
+internal fun ExchangeEstimate(
+ timestamp: TextReference,
+ fromTokenIconState: TokenIconState,
+ toTokenIconState: TokenIconState,
+ fromCryptoAmount: TextReference,
+ toCryptoAmount: TextReference,
+ fromFiatAmount: TextReference,
+ toFiatAmount: TextReference,
+ modifier: Modifier = Modifier,
+) {
+ Column(
+ modifier = modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action),
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(
+ start = TangemTheme.dimens.spacing12,
+ end = TangemTheme.dimens.spacing12,
+ top = TangemTheme.dimens.spacing14,
+ bottom = TangemTheme.dimens.spacing2,
+ ),
+ ) {
+ Text(
+ text = stringResource(id = R.string.express_estimated_amount),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+ Text(
+ text = timestamp.resolveReference(),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+ }
+ InputRowApprox(
+ leftIcon = fromTokenIconState,
+ leftTitle = fromCryptoAmount,
+ leftSubtitle = fromFiatAmount,
+ rightIcon = toTokenIconState,
+ rightTitle = toCryptoAmount,
+ rightSubtitle = toFiatAmount,
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeProvider.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeProvider.kt
new file mode 100644
index 0000000000..26c7393a85
--- /dev/null
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeProvider.kt
@@ -0,0 +1,41 @@
+package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.stringResource
+import com.tangem.core.ui.R
+import com.tangem.core.ui.components.inputrow.InputRowBestRate
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.res.TangemTheme
+
+@Composable
+internal fun ExchangeProvider(providerName: TextReference, providerType: TextReference, imageUrl: String) {
+ Column(
+ modifier = Modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action),
+ ) {
+ Text(
+ text = stringResource(id = R.string.express_provider),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ modifier = Modifier
+ .padding(
+ start = TangemTheme.dimens.spacing12,
+ end = TangemTheme.dimens.spacing12,
+ top = TangemTheme.dimens.spacing12,
+ ),
+ )
+ InputRowBestRate(
+ imageUrl = imageUrl,
+ title = providerName,
+ titleExtra = providerType,
+ subtitle = TextReference.Res(R.string.express_floating_rate),
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBlock.kt
new file mode 100644
index 0000000000..a583d1cb56
--- /dev/null
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBlock.kt
@@ -0,0 +1,209 @@
+package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange
+
+import androidx.annotation.DrawableRes
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.CircularProgressIndicator
+import androidx.compose.material.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import com.tangem.core.ui.components.SpacerWMax
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
+import com.tangem.feature.tokendetails.presentation.tokendetails.state.ExchangeStatusState
+import com.tangem.features.tokendetails.impl.R
+import kotlinx.collections.immutable.PersistentList
+
+@Composable
+internal fun ExchangeStatusBlock(
+ status: PersistentList,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Column(
+ modifier = modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action)
+ .padding(
+ vertical = TangemTheme.dimens.spacing14,
+ horizontal = TangemTheme.dimens.spacing12,
+ ),
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .padding(bottom = TangemTheme.dimens.spacing16),
+ ) {
+ Text(
+ text = stringResource(id = R.string.common_balance_title),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+ SpacerWMax()
+ Row(
+ modifier = Modifier.clickable { onClick() },
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_arrow_top_right_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.informative,
+ modifier = Modifier
+ .size(TangemTheme.dimens.spacing16)
+ .padding(end = TangemTheme.dimens.spacing2),
+ )
+ Text(
+ text = stringResource(id = R.string.express_go_to_provider),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+ }
+ }
+
+ status.forEachIndexed { index, item ->
+ ExchangeStatusStep(
+ stepStatus = item,
+ isLast = index == status.lastIndex,
+ )
+ }
+ }
+}
+
+@Composable
+private fun ExchangeStatusStep(
+ stepStatus: ExchangeStatusState,
+ modifier: Modifier = Modifier,
+ isLast: Boolean = false,
+) {
+ Row(modifier = modifier) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ AnimatedContent(
+ targetState = stepStatus,
+ label = "Exchange Step Change Success",
+ modifier = Modifier
+ .size(TangemTheme.dimens.size20),
+ ) {
+ when {
+ it.status == ExchangeStatus.Failed && !it.isDone -> ExchangeStepWaringOrError(
+ iconRes = R.drawable.ic_close_24,
+ color = TangemTheme.colors.icon.warning,
+ )
+ it.status == ExchangeStatus.Verifying && !it.isDone -> ExchangeStepWaringOrError(
+ iconRes = R.drawable.ic_exclamation_24,
+ color = TangemTheme.colors.icon.attention,
+ )
+ it.isDone -> ExchangeStepSuccess()
+ it.isActive -> ExchangeStepInProgress()
+ else -> ExchangeStepDefault()
+ }
+ }
+ if (!isLast) {
+ ExchangeStepSeparator()
+ }
+ }
+ ExchangeStatusStepText(stepStatus)
+ }
+}
+
+@Composable
+private fun ExchangeStatusStepText(stepStatus: ExchangeStatusState) {
+ val textColor = when {
+ stepStatus.status == ExchangeStatus.Failed && !stepStatus.isDone -> TangemTheme.colors.icon.warning
+ stepStatus.status == ExchangeStatus.Verifying && !stepStatus.isDone -> TangemTheme.colors.icon.attention
+ stepStatus.isDone -> TangemTheme.colors.text.primary1
+ !stepStatus.isActive -> TangemTheme.colors.text.disabled
+ else -> TangemTheme.colors.text.primary1
+ }
+
+ Text(
+ text = stepStatus.text,
+ style = TangemTheme.typography.body2,
+ color = textColor,
+ modifier = Modifier
+ .padding(start = TangemTheme.dimens.spacing12),
+ )
+}
+
+@Composable
+private fun ExchangeStepDefault() {
+ Box(
+ modifier = Modifier
+ .border(
+ width = TangemTheme.dimens.size1_5,
+ color = TangemTheme.colors.field.focused,
+ shape = CircleShape,
+ )
+ .padding(TangemTheme.dimens.spacing2),
+ )
+}
+
+@Composable
+private fun ExchangeStepSuccess() {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_check_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.primary1,
+ modifier = Modifier
+ .border(
+ width = TangemTheme.dimens.size1_5,
+ color = TangemTheme.colors.field.focused,
+ shape = CircleShape,
+ )
+ .padding(TangemTheme.dimens.spacing2),
+ )
+}
+
+@Composable
+private fun ExchangeStepWaringOrError(color: Color, @DrawableRes iconRes: Int) {
+ Icon(
+ painter = painterResource(id = iconRes),
+ contentDescription = null,
+ tint = color,
+ modifier = Modifier
+ .border(
+ width = TangemTheme.dimens.size1_5,
+ color = color,
+ shape = CircleShape,
+ )
+ .padding(TangemTheme.dimens.spacing2),
+ )
+}
+
+@Composable
+private fun ExchangeStepInProgress() {
+ CircularProgressIndicator(
+ color = TangemTheme.colors.icon.primary1,
+ strokeWidth = TangemTheme.dimens.size2,
+ modifier = Modifier
+ .padding(TangemTheme.dimens.spacing2)
+ .size(TangemTheme.dimens.size14),
+ )
+}
+
+@Composable
+private fun ExchangeStepSeparator() {
+ Box(
+ modifier = Modifier
+ .padding(vertical = TangemTheme.dimens.spacing2)
+ .size(
+ width = TangemTheme.dimens.size1_5,
+ height = TangemTheme.dimens.size10,
+ )
+ .background(
+ color = TangemTheme.colors.field.focused,
+ shape = CircleShape,
+ ),
+ )
+}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBottomSheet.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBottomSheet.kt
new file mode 100644
index 0000000000..5705f00a63
--- /dev/null
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusBottomSheet.kt
@@ -0,0 +1,84 @@
+package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment.Companion.CenterHorizontally
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import com.tangem.core.ui.R
+import com.tangem.core.ui.components.SpacerH10
+import com.tangem.core.ui.components.SpacerH12
+import com.tangem.core.ui.components.SpacerH16
+import com.tangem.core.ui.components.SpacerH24
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
+import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.utils.toDateFormat
+import com.tangem.core.ui.utils.toTimeFormat
+import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
+
+@Composable
+internal fun ExchangeStatusBottomSheet(config: TangemBottomSheetConfig) {
+ TangemBottomSheet(
+ config = config,
+ color = TangemTheme.colors.background.tertiary,
+ ) { content: ExchangeStatusBottomSheetConfig ->
+ ExchangeStatusBottomSheetContent(content = content)
+ }
+}
+
+@Composable
+private fun ExchangeStatusBottomSheetContent(content: ExchangeStatusBottomSheetConfig) {
+ val config = content.value
+ Column(
+ modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
+ ) {
+ SpacerH10()
+ Text(
+ text = stringResource(id = R.string.express_exchange_status_title),
+ style = TangemTheme.typography.subtitle1,
+ color = TangemTheme.colors.text.primary1,
+ modifier = Modifier.align(CenterHorizontally),
+ )
+ SpacerH10()
+ Text(
+ text = stringResource(id = R.string.express_exchange_status_subtitle),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.secondary,
+ modifier = Modifier
+ .align(CenterHorizontally),
+ )
+ SpacerH16()
+ val timestamp = config.timestamp
+ ExchangeEstimate(
+ timestamp = TextReference.Str("${timestamp.toDateFormat()}, ${timestamp.toTimeFormat()}"),
+ fromTokenIconState = config.fromCurrencyIcon,
+ toTokenIconState = config.toCurrencyIcon,
+ fromCryptoAmount = TextReference.Str(config.fromCryptoAmount),
+ toCryptoAmount = TextReference.Str(config.toCryptoAmount),
+ fromFiatAmount = TextReference.Str(config.fromFiatAmount),
+ toFiatAmount = TextReference.Str(config.toFiatAmount),
+ )
+ SpacerH12()
+ // todo replace with real provider data
+ ExchangeProvider(
+ providerName = TextReference.Str(config.providerId.toString()),
+ providerType = TextReference.Str("CEX"),
+ imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/changenow_512.png",
+ )
+ SpacerH12()
+ ExchangeStatusBlock(
+ status = config.status,
+ onClick = config.onGoToProviderClick,
+ )
+ SpacerH24()
+ }
+}
+
+internal data class ExchangeStatusBottomSheetConfig(
+ val value: SwapTransactionsState,
+) : TangemBottomSheetConfigContent
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusItems.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusItems.kt
new file mode 100644
index 0000000000..95ac42480e
--- /dev/null
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/exchange/ExchangeStatusItems.kt
@@ -0,0 +1,180 @@
+package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange
+
+import androidx.annotation.DrawableRes
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyListScope
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.constraintlayout.compose.ConstraintLayout
+import androidx.constraintlayout.compose.Visibility
+import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
+import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
+import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
+import com.tangem.features.tokendetails.impl.R
+import kotlinx.collections.immutable.PersistentList
+
+@OptIn(ExperimentalFoundationApi::class)
+internal fun LazyListScope.swapTransactionsItems(
+ swapTxs: PersistentList,
+ modifier: Modifier = Modifier,
+) {
+ if (swapTxs.isNotEmpty()) {
+ items(
+ count = swapTxs.size,
+ key = { swapTxs[it].txId },
+ contentType = { swapTxs[it]::class.java },
+ ) {
+ val item = swapTxs[it]
+
+ val (iconRes, tint) = when (item.activeStatus) {
+ ExchangeStatus.Verifying -> R.drawable.ic_alert_triangle_20 to TangemTheme.colors.icon.attention
+ ExchangeStatus.Failed -> R.drawable.ic_alert_circle_24 to TangemTheme.colors.icon.warning
+ else -> null to null
+ }
+
+ ExchangeStatusItem(
+ providerName = item.providerId.toString(),
+ fromTokenIconState = item.fromCurrencyIcon,
+ toTokenIconState = item.toCurrencyIcon,
+ fromAmount = item.fromCryptoAmount,
+ toAmount = item.toCryptoAmount,
+ onClick = item.onClick,
+ infoIconRes = iconRes,
+ infoIconTint = tint,
+ modifier = modifier.animateItemPlacement(),
+ )
+ }
+ }
+}
+
+@Suppress("DestructuringDeclarationWithTooManyEntries", "LongMethod", "LongParameterList")
+@Composable
+private fun ExchangeStatusItem(
+ providerName: String,
+ fromTokenIconState: TokenIconState,
+ toTokenIconState: TokenIconState,
+ fromAmount: String,
+ toAmount: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ @DrawableRes infoIconRes: Int? = null,
+ infoIconTint: Color? = null,
+) {
+ ConstraintLayout(
+ modifier = modifier
+ .fillMaxWidth()
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action)
+ .clickable { onClick() }
+ .padding(TangemTheme.dimens.spacing12),
+ ) {
+ val (titleRef, iconRef, infoIconRef, swapIconRef, fromRef, toRef, fromIconRef, toIconRef) = createRefs()
+ val padding6 = TangemTheme.dimens.spacing6
+
+ Text(
+ text = stringResource(id = R.string.express_exchange_by, providerName),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ modifier = Modifier.constrainAs(titleRef) {
+ start.linkTo(parent.start)
+ top.linkTo(parent.top)
+ },
+ )
+ TokenIcon(
+ state = fromTokenIconState,
+ shouldDisplayNetwork = false,
+ modifier = Modifier
+ .size(TangemTheme.dimens.size20)
+ .constrainAs(fromIconRef) {
+ start.linkTo(parent.start)
+ top.linkTo(titleRef.bottom, padding6)
+ bottom.linkTo(parent.bottom)
+ },
+ )
+ Text(
+ text = fromAmount,
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.primary1,
+ modifier = Modifier.constrainAs(fromRef) {
+ start.linkTo(fromIconRef.end, padding6)
+ top.linkTo(titleRef.bottom, padding6)
+ bottom.linkTo(parent.bottom)
+ },
+ )
+ Icon(
+ painter = painterResource(id = R.drawable.ic_forward_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.informative,
+ modifier = Modifier
+ .size(TangemTheme.dimens.size12)
+ .constrainAs(swapIconRef) {
+ start.linkTo(fromRef.end, padding6)
+ top.linkTo(titleRef.bottom, padding6)
+ bottom.linkTo(parent.bottom)
+ },
+ )
+ TokenIcon(
+ state = toTokenIconState,
+ shouldDisplayNetwork = false,
+ modifier = Modifier
+ .size(TangemTheme.dimens.size20)
+ .constrainAs(toIconRef) {
+ start.linkTo(swapIconRef.end, padding6)
+ top.linkTo(titleRef.bottom, padding6)
+ bottom.linkTo(parent.bottom)
+ },
+ )
+ Text(
+ text = toAmount,
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.primary1,
+ modifier = Modifier.constrainAs(toRef) {
+ start.linkTo(toIconRef.end, padding6)
+ top.linkTo(titleRef.bottom, padding6)
+ bottom.linkTo(parent.bottom)
+ },
+ )
+ Icon(
+ painter = painterResource(id = infoIconRes ?: R.drawable.ic_alert_triangle_20),
+ contentDescription = null,
+ tint = infoIconTint ?: TangemTheme.colors.icon.informative,
+ modifier = Modifier
+ .size(TangemTheme.dimens.size20)
+ .constrainAs(infoIconRef) {
+ top.linkTo(parent.top)
+ bottom.linkTo(parent.bottom)
+ end.linkTo(iconRef.start)
+ visibility = if (infoIconRes == null) {
+ Visibility.Gone
+ } else {
+ Visibility.Visible
+ }
+ },
+ )
+ Icon(
+ painter = painterResource(id = R.drawable.ic_chevron_right_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.informative,
+ modifier = Modifier
+ .size(TangemTheme.dimens.size24)
+ .constrainAs(iconRef) {
+ end.linkTo(parent.end)
+ top.linkTo(parent.top)
+ bottom.linkTo(parent.bottom)
+ },
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
index b1496b2e0c..55cb6c48be 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
@@ -475,4 +475,35 @@ internal class TokenDetailsViewModel @Inject constructor(
override fun onCloseRentInfoNotification() {
uiState = stateFactory.getStateWithRemovedRentNotification()
}
-}
\ No newline at end of file
+}
+
+//
+// val text = when (stepStatus.status) {
+// ExchangeStatus.Failed -> stringResource(id = R.string.express_exchange_status_failed)
+// ExchangeStatus.Verifying -> if (stepStatus.isDone) {
+// stringResource(id = R.string.express_exchange_status_verified)
+// } else {
+// stringResource(id = R.string.express_exchange_status_verifying)
+// }
+// ExchangeStatus.New, ExchangeStatus.Waiting -> if (stepStatus.isDone) {
+// stringResource(id = R.string.express_exchange_status_received)
+// } else {
+// stringResource(id = R.string.express_exchange_status_receiving)
+// }
+// ExchangeStatus.Confirming -> if (stepStatus.isDone) {
+// stringResource(id = R.string.express_exchange_status_confirmed)
+// } else {
+// stringResource(id = R.string.express_exchange_status_confirming)
+// }
+// ExchangeStatus.Exchanging -> if (stepStatus.isDone) {
+// stringResource(id = R.string.express_exchange_status_exchanged)
+// } else {
+// stringResource(id = R.string.express_exchange_status_exchanging)
+// }
+// ExchangeStatus.Sending -> if (stepStatus.isDone) {
+// stringResource(id = R.string.express_exchange_status_sent)
+// } else {
+// stringResource(id = R.string.express_exchange_status_sending)
+// }
+// else -> ""
+// }
\ No newline at end of file