Updated on 2026-08-14
This commit is contained in:
commit
cd2f5bfeed
14 changed files with 425 additions and 59 deletions
|
|
@ -101,6 +101,7 @@ internal object TokenDetailsPreviewData {
|
|||
),
|
||||
dialogConfig = null,
|
||||
pendingTxs = persistentListOf(),
|
||||
swapTxs = persistentListOf(),
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
bottomSheetConfig = null,
|
||||
isBalanceHidden = false,
|
||||
|
|
|
|||
|
|
@ -2,21 +2,25 @@ 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 com.tangem.feature.swap.domain.models.domain.SwapProvider
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal data class SwapTransactionsState(
|
||||
val txId: String,
|
||||
val providerId: Int,
|
||||
val provider: SwapProvider,
|
||||
val txUrl: String? = null,
|
||||
val rate: BigDecimal,
|
||||
val timestamp: Long,
|
||||
val status: PersistentList<ExchangeStatusState>,
|
||||
val statuses: PersistentList<ExchangeStatusState>,
|
||||
val activeStatus: ExchangeStatus?,
|
||||
val fiatSymbol: String,
|
||||
val notification: ExchangeStatusNotifications? = null,
|
||||
val toCryptoAmount: String,
|
||||
val toCryptoSymbol: String,
|
||||
val toFiatAmount: String,
|
||||
val toCurrencyIcon: TokenIconState,
|
||||
val fromCryptoAmount: String,
|
||||
val fromCryptoSymbol: String,
|
||||
val fromFiatAmount: String,
|
||||
val fromCurrencyIcon: TokenIconState,
|
||||
val onClick: () -> Unit,
|
||||
|
|
@ -25,7 +29,6 @@ internal data class SwapTransactionsState(
|
|||
|
||||
internal class ExchangeStatusState(
|
||||
val status: ExchangeStatus,
|
||||
val text: String,
|
||||
val isActive: Boolean,
|
||||
val isDone: Boolean,
|
||||
)
|
||||
|
|
@ -19,6 +19,7 @@ internal data class TokenDetailsState(
|
|||
val marketPriceBlockState: MarketPriceBlockState,
|
||||
val notifications: ImmutableList<TokenDetailsNotification>,
|
||||
val pendingTxs: PersistentList<TransactionState>,
|
||||
val swapTxs: PersistentList<SwapTransactionsState>,
|
||||
val txHistoryState: TxHistoryState,
|
||||
val dialogConfig: TokenDetailsDialogConfig?,
|
||||
val pullToRefreshConfig: TokenDetailsPullToRefreshConfig,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.components
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
|
||||
@Immutable
|
||||
internal sealed class ExchangeStatusNotifications(val config: NotificationConfig) {
|
||||
|
||||
data class NeedVerification(
|
||||
val onGoToProviderClick: () -> Unit,
|
||||
) : ExchangeStatusNotifications(
|
||||
config = NotificationConfig(
|
||||
title = TextReference.Res(R.string.express_exchange_notification_verification_title),
|
||||
subtitle = TextReference.Res(R.string.express_exchange_notification_verification_text),
|
||||
iconResId = R.drawable.ic_alert_triangle_20,
|
||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
text = TextReference.Res(R.string.express_go_to_provider),
|
||||
onClick = onGoToProviderClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
data class Failed(
|
||||
val onGoToProviderClick: () -> Unit,
|
||||
) : ExchangeStatusNotifications(
|
||||
config = NotificationConfig(
|
||||
title = TextReference.Res(R.string.express_exchange_notification_failed_title),
|
||||
subtitle = TextReference.Res(R.string.express_exchange_notification_failed_text),
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
text = TextReference.Res(R.string.express_go_to_provider),
|
||||
onClick = onGoToProviderClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -45,6 +45,7 @@ internal class TokenDetailsSkeletonStateConverter(
|
|||
marketPriceBlockState = MarketPriceBlockState.Loading(value.symbol),
|
||||
notifications = persistentListOf(),
|
||||
pendingTxs = persistentListOf(),
|
||||
swapTxs = persistentListOf(),
|
||||
txHistoryState = TxHistoryState.Content(
|
||||
contentItems = MutableStateFlow(
|
||||
value = TxHistoryState.getDefaultLoadingTransactions(clickIntents::onExploreClick),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui
|
|||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
|
|
@ -40,6 +42,9 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.T
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsDialogs
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsTopAppBar
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenInfoBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.swapTransactionsItems
|
||||
|
||||
// TODO: Split to blocks [REDACTED_JIRA]
|
||||
@Suppress("LongMethod")
|
||||
|
|
@ -117,6 +122,11 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
|
|||
)
|
||||
}
|
||||
|
||||
swapTransactionsItems(
|
||||
state.swapTxs,
|
||||
itemModifier,
|
||||
)
|
||||
|
||||
txHistoryItems(
|
||||
state = state.txHistoryState,
|
||||
isBalanceHidden = state.isBalanceHidden,
|
||||
|
|
@ -141,6 +151,9 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
|
|||
is ChooseAddressBottomSheetConfig -> {
|
||||
ChooseAddressBottomSheet(config = config)
|
||||
}
|
||||
is ExchangeStatusBottomSheetConfig -> {
|
||||
ExchangeStatusBottomSheet(config = config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import kotlinx.collections.immutable.PersistentList
|
|||
|
||||
@Composable
|
||||
internal fun ExchangeStatusBlock(
|
||||
status: PersistentList<ExchangeStatusState>,
|
||||
statuses: PersistentList<ExchangeStatusState>,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -70,10 +70,10 @@ internal fun ExchangeStatusBlock(
|
|||
}
|
||||
}
|
||||
|
||||
status.forEachIndexed { index, item ->
|
||||
statuses.forEachIndexed { index, item ->
|
||||
ExchangeStatusStep(
|
||||
stepStatus = item,
|
||||
isLast = index == status.lastIndex,
|
||||
isLast = index == statuses.lastIndex,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ private fun ExchangeStatusStepText(stepStatus: ExchangeStatusState) {
|
|||
}
|
||||
|
||||
Text(
|
||||
text = stepStatus.text,
|
||||
text = getStatusText(stepStatus)?.let { stringResource(it) }.orEmpty(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = textColor,
|
||||
modifier = Modifier
|
||||
|
|
@ -206,4 +206,34 @@ private fun ExchangeStepSeparator() {
|
|||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getStatusText(stepStatus: ExchangeStatusState) = when (stepStatus.status) {
|
||||
ExchangeStatus.Failed -> R.string.express_exchange_status_failed
|
||||
ExchangeStatus.Verifying -> if (stepStatus.isDone) {
|
||||
R.string.express_exchange_status_verified
|
||||
} else {
|
||||
R.string.express_exchange_status_verifying
|
||||
}
|
||||
ExchangeStatus.New, ExchangeStatus.Waiting -> if (stepStatus.isDone) {
|
||||
R.string.express_exchange_status_received
|
||||
} else {
|
||||
R.string.express_exchange_status_receiving
|
||||
}
|
||||
ExchangeStatus.Confirming -> if (stepStatus.isDone) {
|
||||
R.string.express_exchange_status_confirmed
|
||||
} else {
|
||||
R.string.express_exchange_status_confirming
|
||||
}
|
||||
ExchangeStatus.Exchanging -> if (stepStatus.isDone) {
|
||||
R.string.express_exchange_status_exchanged
|
||||
} else {
|
||||
R.string.express_exchange_status_exchanging
|
||||
}
|
||||
ExchangeStatus.Sending -> if (stepStatus.isDone) {
|
||||
R.string.express_exchange_status_sent
|
||||
} else {
|
||||
R.string.express_exchange_status_sending
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -15,6 +16,7 @@ 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.components.notifications.Notification
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.utils.toDateFormat
|
||||
|
|
@ -64,17 +66,25 @@ private fun ExchangeStatusBottomSheetContent(content: ExchangeStatusBottomSheetC
|
|||
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",
|
||||
providerName = TextReference.Str(config.provider.name),
|
||||
providerType = TextReference.Str(config.provider.type.name),
|
||||
imageUrl = config.provider.imageLarge,
|
||||
)
|
||||
SpacerH12()
|
||||
ExchangeStatusBlock(
|
||||
status = config.status,
|
||||
statuses = config.statuses,
|
||||
onClick = config.onGoToProviderClick,
|
||||
)
|
||||
AnimatedContent(
|
||||
targetState = config.notification,
|
||||
label = "Exchange Status Notification Change",
|
||||
) {
|
||||
it?.let {
|
||||
SpacerH12()
|
||||
Notification(config = it.config)
|
||||
}
|
||||
}
|
||||
SpacerH24()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@ 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.Dimension
|
||||
import androidx.constraintlayout.compose.Visibility
|
||||
import com.tangem.core.ui.components.atoms.text.EllipsisText
|
||||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||
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
|
||||
|
|
@ -46,11 +49,13 @@ internal fun LazyListScope.swapTransactionsItems(
|
|||
}
|
||||
|
||||
ExchangeStatusItem(
|
||||
providerName = item.providerId.toString(),
|
||||
providerName = item.provider.name,
|
||||
fromTokenIconState = item.fromCurrencyIcon,
|
||||
toTokenIconState = item.toCurrencyIcon,
|
||||
fromAmount = item.fromCryptoAmount,
|
||||
fromSymbol = item.fromCryptoSymbol,
|
||||
toAmount = item.toCryptoAmount,
|
||||
toSymbol = item.toCryptoSymbol,
|
||||
onClick = item.onClick,
|
||||
infoIconRes = iconRes,
|
||||
infoIconTint = tint,
|
||||
|
|
@ -67,7 +72,9 @@ private fun ExchangeStatusItem(
|
|||
fromTokenIconState: TokenIconState,
|
||||
toTokenIconState: TokenIconState,
|
||||
fromAmount: String,
|
||||
fromSymbol: String,
|
||||
toAmount: String,
|
||||
toSymbol: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
@DrawableRes infoIconRes: Int? = null,
|
||||
|
|
@ -104,14 +111,17 @@ private fun ExchangeStatusItem(
|
|||
bottom.linkTo(parent.bottom)
|
||||
},
|
||||
)
|
||||
Text(
|
||||
EllipsisText(
|
||||
text = fromAmount,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
ellipsis = TextEllipsis.OffsetEnd(fromSymbol.length),
|
||||
modifier = Modifier.constrainAs(fromRef) {
|
||||
start.linkTo(fromIconRef.end, padding6)
|
||||
top.linkTo(titleRef.bottom, padding6)
|
||||
end.linkTo(swapIconRef.start)
|
||||
bottom.linkTo(parent.bottom)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
)
|
||||
Icon(
|
||||
|
|
@ -123,6 +133,7 @@ private fun ExchangeStatusItem(
|
|||
.constrainAs(swapIconRef) {
|
||||
start.linkTo(fromRef.end, padding6)
|
||||
top.linkTo(titleRef.bottom, padding6)
|
||||
end.linkTo(toIconRef.start)
|
||||
bottom.linkTo(parent.bottom)
|
||||
},
|
||||
)
|
||||
|
|
@ -134,17 +145,21 @@ private fun ExchangeStatusItem(
|
|||
.constrainAs(toIconRef) {
|
||||
start.linkTo(swapIconRef.end, padding6)
|
||||
top.linkTo(titleRef.bottom, padding6)
|
||||
end.linkTo(toRef.start)
|
||||
bottom.linkTo(parent.bottom)
|
||||
},
|
||||
)
|
||||
Text(
|
||||
EllipsisText(
|
||||
text = toAmount,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
ellipsis = TextEllipsis.OffsetEnd(toSymbol.length),
|
||||
modifier = Modifier.constrainAs(toRef) {
|
||||
start.linkTo(toIconRef.end, padding6)
|
||||
top.linkTo(titleRef.bottom, padding6)
|
||||
end.linkTo(infoIconRef.start, padding6)
|
||||
bottom.linkTo(parent.bottom)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
)
|
||||
Icon(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue