Updated on 2026-08-14
This commit is contained in:
parent
a54c3ce6ea
commit
b0e07c0258
23 changed files with 406 additions and 887 deletions
|
|
@ -1,12 +1,42 @@
|
|||
package com.tangem.common.ui.expressStatus
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
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.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.tooling.preview.Preview
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressLinkUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateIconUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateInfoUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
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.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.isNullOrEmpty
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
fun LazyListScope.expressTransactionsItems(
|
||||
expressTxs: PersistentList<ExpressTransactionStateUM>,
|
||||
|
|
@ -19,28 +49,170 @@ fun LazyListScope.expressTransactionsItems(
|
|||
) { index ->
|
||||
val itemInfo = expressTxs[index].info
|
||||
val (iconRes, tint) = when (itemInfo.iconState) {
|
||||
ExpressTransactionStateIconUM.Warning -> {
|
||||
R.drawable.ic_alert_triangle_20 to TangemTheme.colors.icon.attention
|
||||
}
|
||||
ExpressTransactionStateIconUM.Error -> {
|
||||
R.drawable.ic_alert_circle_24 to TangemTheme.colors.icon.warning
|
||||
}
|
||||
ExpressTransactionStateIconUM.Warning ->
|
||||
R.drawable.ic_attention_default_24 to TangemTheme.colors2.graphic.status.attention
|
||||
ExpressTransactionStateIconUM.Error ->
|
||||
R.drawable.ic_alert_circle_24 to TangemTheme.colors2.graphic.status.warning
|
||||
ExpressTransactionStateIconUM.None -> null to null
|
||||
}
|
||||
|
||||
ExpressStatusItem(
|
||||
title = itemInfo.title,
|
||||
fromTokenIconState = itemInfo.fromCurrencyIcon,
|
||||
toTokenIconState = itemInfo.toCurrencyIcon,
|
||||
fromAmount = itemInfo.fromAmount,
|
||||
fromSymbol = itemInfo.fromAmountSymbol,
|
||||
toAmount = itemInfo.toAmount,
|
||||
toSymbol = itemInfo.toAmountSymbol,
|
||||
subtitle = itemInfo.subtitle,
|
||||
onClick = itemInfo.onClick,
|
||||
ExpressTransactionItem(
|
||||
state = expressTxs[index],
|
||||
infoIconRes = iconRes,
|
||||
infoIconTint = tint,
|
||||
modifier = modifier.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ExpressTransactionItem(
|
||||
state: ExpressTransactionStateUM,
|
||||
infoIconRes: Int?,
|
||||
infoIconTint: Color?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val info = state.info
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors2.surface.level3)
|
||||
.clickable(onClick = info.onClick)
|
||||
.padding(TangemTheme.dimens2.x4),
|
||||
) {
|
||||
TitleRow(
|
||||
title = info.title.resolveReference(),
|
||||
infoIconRes = infoIconRes,
|
||||
infoIconTint = infoIconTint,
|
||||
)
|
||||
if (!info.subtitle.isNullOrEmpty()) {
|
||||
Text(
|
||||
text = info.subtitle.resolveReference(),
|
||||
style = TangemTheme.typography2.captionRegular13,
|
||||
color = TangemTheme.colors3.text.tertiary,
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.size(TangemTheme.dimens2.x3))
|
||||
AmountsRow(info = info)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TitleRow(title: String, infoIconRes: Int?, infoIconTint: Color?) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = title,
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
if (infoIconRes != null && infoIconTint != null) {
|
||||
Icon(
|
||||
painter = painterResource(infoIconRes),
|
||||
contentDescription = null,
|
||||
tint = infoIconTint,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x3),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AmountsRow(info: ExpressTransactionStateInfoUM) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1_5),
|
||||
) {
|
||||
CurrencyIcon(
|
||||
state = info.fromCurrencyIcon,
|
||||
shouldDisplayNetwork = false,
|
||||
modifier = Modifier.size(TangemTheme.dimens.size18),
|
||||
)
|
||||
EllipsisText(
|
||||
text = info.fromAmount.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
ellipsis = TextEllipsis.OffsetEnd(info.fromAmountSymbol.length),
|
||||
modifier = Modifier.weight(weight = 1f, fill = false),
|
||||
)
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_forward_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors3.icon.tertiary,
|
||||
modifier = Modifier.size(TangemTheme.dimens.size18),
|
||||
)
|
||||
CurrencyIcon(
|
||||
state = info.toCurrencyIcon,
|
||||
shouldDisplayNetwork = false,
|
||||
modifier = Modifier.size(TangemTheme.dimens.size18),
|
||||
)
|
||||
EllipsisText(
|
||||
text = info.toAmount.resolveReference(),
|
||||
style = TangemTheme.typography2.bodyMedium16,
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
ellipsis = TextEllipsis.OffsetEnd(info.toAmountSymbol.length),
|
||||
modifier = Modifier.weight(weight = 1f, fill = false),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun ExpressTransactionItemPreview() {
|
||||
TangemThemePreviewRedesign {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
modifier = Modifier.padding(TangemTheme.dimens2.x4),
|
||||
) {
|
||||
ExpressTransactionItem(
|
||||
state = PreviewExpressTransactionState,
|
||||
infoIconRes = null,
|
||||
infoIconTint = null,
|
||||
)
|
||||
ExpressTransactionItem(
|
||||
state = PreviewExpressTransactionState,
|
||||
infoIconRes = R.drawable.ic_attention_default_24,
|
||||
infoIconTint = TangemTheme.colors2.graphic.status.attention,
|
||||
)
|
||||
ExpressTransactionItem(
|
||||
state = PreviewExpressTransactionState,
|
||||
infoIconRes = R.drawable.ic_alert_circle_24,
|
||||
infoIconTint = TangemTheme.colors2.graphic.status.warning,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val PreviewExpressTransactionState: ExpressTransactionStateUM = object : ExpressTransactionStateUM {
|
||||
override val info = ExpressTransactionStateInfoUM(
|
||||
title = stringReference("Exchange by ChangeHero"),
|
||||
status = ExpressStatusUM(
|
||||
title = stringReference(""),
|
||||
link = ExpressLinkUM.Empty,
|
||||
statuses = persistentListOf(),
|
||||
),
|
||||
notification = null,
|
||||
txId = "preview",
|
||||
txExternalId = null,
|
||||
txExternalUrl = null,
|
||||
timestamp = 0L,
|
||||
timestampFormatted = stringReference(""),
|
||||
timestampAgoFormatted = stringReference("Confirming ~ 59 min ago"),
|
||||
activeStatus = stringReference(""),
|
||||
onGoToProviderClick = {},
|
||||
onClick = {},
|
||||
onDisposeExpressStatus = {},
|
||||
iconState = ExpressTransactionStateIconUM.None,
|
||||
toAmount = stringReference("0,11441958 BTC"),
|
||||
toFiatAmount = null,
|
||||
toAmountSymbol = "BTC",
|
||||
toCurrencyIcon = CurrencyIconState.Loading,
|
||||
fromAmount = stringReference("100 SOL"),
|
||||
fromFiatAmount = null,
|
||||
fromAmountSymbol = "SOL",
|
||||
fromCurrencyIcon = CurrencyIconState.Loading,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tangem.common.ui.expressStatus
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateIconUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
||||
fun LazyListScope.expressTransactionsItemsLegacy(
|
||||
expressTxs: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
items(
|
||||
count = expressTxs.size,
|
||||
key = { index -> expressTxs[index].info.txId },
|
||||
contentType = { index -> expressTxs[index]::class.java },
|
||||
) { index ->
|
||||
val itemInfo = expressTxs[index].info
|
||||
val (iconRes, tint) = when (itemInfo.iconState) {
|
||||
ExpressTransactionStateIconUM.Warning -> {
|
||||
R.drawable.ic_alert_triangle_20 to TangemTheme.colors.icon.attention
|
||||
}
|
||||
ExpressTransactionStateIconUM.Error -> {
|
||||
R.drawable.ic_alert_circle_24 to TangemTheme.colors.icon.warning
|
||||
}
|
||||
ExpressTransactionStateIconUM.None -> null to null
|
||||
}
|
||||
|
||||
ExpressStatusItem(
|
||||
title = itemInfo.title,
|
||||
fromTokenIconState = itemInfo.fromCurrencyIcon,
|
||||
toTokenIconState = itemInfo.toCurrencyIcon,
|
||||
fromAmount = itemInfo.fromAmount,
|
||||
fromSymbol = itemInfo.fromAmountSymbol,
|
||||
toAmount = itemInfo.toAmount,
|
||||
toSymbol = itemInfo.toAmountSymbol,
|
||||
subtitle = itemInfo.subtitle,
|
||||
onClick = itemInfo.onClick,
|
||||
infoIconRes = iconRes,
|
||||
infoIconTint = tint,
|
||||
modifier = modifier.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,11 @@ internal class EmptyExpressTransactionsComponent(
|
|||
|
||||
override val state: StateFlow<ExpressTransactionsBlockState> = MutableStateFlow(getInitialState())
|
||||
|
||||
override fun LazyListScope.expressTransactionsContentLegacy(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) {}
|
||||
|
||||
override fun LazyListScope.expressTransactionsContent(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@ internal class PreviewEmptyExpressTransactionsComponent : ExpressTransactionsCom
|
|||
|
||||
override val state: StateFlow<ExpressTransactionsBlockState> = MutableStateFlow(getInitialState())
|
||||
|
||||
override fun LazyListScope.expressTransactionsContentLegacy(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) {}
|
||||
|
||||
override fun LazyListScope.expressTransactionsContent(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ internal fun TangemPayDetailsScreen(
|
|||
}
|
||||
if (state.accountDeactivatedNotificationConfig == null) {
|
||||
with(expressTransactionsComponent) {
|
||||
expressTransactionsContent(
|
||||
expressTransactionsContentLegacy(
|
||||
state = expressState.transactionsToDisplay,
|
||||
modifier = modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ interface ExpressTransactionsComponent {
|
|||
|
||||
val state: StateFlow<ExpressTransactionsBlockState>
|
||||
|
||||
fun LazyListScope.expressTransactionsContentLegacy(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
)
|
||||
|
||||
fun LazyListScope.expressTransactionsContent(state: PersistentList<ExpressTransactionStateUM>, modifier: Modifier)
|
||||
|
||||
data class Params(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ interface ExpressTransactionsEventListener {
|
|||
suspend fun send(event: ExpressTransactionsEvent)
|
||||
}
|
||||
|
||||
enum class ExpressTransactionsEvent {
|
||||
Update, Clear
|
||||
sealed interface ExpressTransactionsEvent {
|
||||
data object Update : ExpressTransactionsEvent
|
||||
data object Clear : ExpressTransactionsEvent
|
||||
data class OpenTx(val txId: String) : ExpressTransactionsEvent
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import com.arkivanov.decompose.ComponentContext
|
|||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.arkivanov.essenty.lifecycle.subscribe
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
|
|
@ -26,6 +25,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.CloreMigrationBottomSheetComponent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.DynamicAddressesBottomSheetComponent
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.tokendetails.ExpressTransactionsComponent
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
|
|
@ -41,6 +41,7 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
@Assisted params: TokenDetailsComponent.Params,
|
||||
tokenMarketBlockComponentFactory: TokenMarketBlockComponent.Factory,
|
||||
txHistoryComponentFactory: TxHistoryComponent.Factory,
|
||||
expressTransactionsComponentFactory: ExpressTransactionsComponent.Factory,
|
||||
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
|
||||
private val yieldSupplyWarningComponentFactory: YieldSupplyDepositedWarningComponent.Factory,
|
||||
yieldSupplyComponentFactory: YieldSupplyComponent.Factory,
|
||||
|
|
@ -56,6 +57,14 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
|
||||
private val expressTransactionsComponent = expressTransactionsComponentFactory.create(
|
||||
context = child("expressTransactionsComponent"),
|
||||
params = ExpressTransactionsComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = params.currency,
|
||||
),
|
||||
)
|
||||
|
||||
private val bottomSheetSlot = childSlot(
|
||||
source = model.bottomSheetNavigation,
|
||||
serializer = TokenDetailsBottomSheetConfig.serializer(),
|
||||
|
|
@ -63,13 +72,6 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
childFactory = ::bottomSheetChild,
|
||||
)
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
onPause = model::onPause,
|
||||
onResume = model::onResume,
|
||||
)
|
||||
}
|
||||
|
||||
private val tokenMarketBlockComponent = params.currency.toTokenMarketParam()?.let { tokenMarketParams ->
|
||||
tokenMarketBlockComponentFactory.create(
|
||||
appComponentContext = child("tokenMarketBlockComponent"),
|
||||
|
|
@ -100,6 +102,7 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
yieldSupplyComponent = yieldSupplyComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
expressTransactionsComponent = expressTransactionsComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
|
|
@ -109,6 +112,7 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
yieldSupplyComponent = yieldSupplyComponent,
|
||||
expressTransactionsComponent = expressTransactionsComponent,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package com.tangem.feature.tokendetails.presentation
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.essenty.lifecycle.subscribe
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItems
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItemsLegacy
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
|
|
@ -25,6 +27,20 @@ internal class DefaultExpressTransactionsComponent @AssistedInject constructor(
|
|||
private val model: ExpressTransactionsModel = getOrCreateModel(params = params)
|
||||
override val state: StateFlow<ExpressTransactionsBlockState> = model.uiState
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
onPause = model::onPause,
|
||||
onResume = model::onResume,
|
||||
)
|
||||
}
|
||||
|
||||
override fun LazyListScope.expressTransactionsContentLegacy(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
expressTransactionsItemsLegacy(expressTxs = state, modifier = modifier)
|
||||
}
|
||||
|
||||
override fun LazyListScope.expressTransactionsContent(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
|
|
|
|||
|
|
@ -169,10 +169,7 @@ internal object TokenDetailsPreviewData {
|
|||
marketPriceBlockState = marketPriceLoading,
|
||||
stakingBlocksState = stakingLoadingBlock,
|
||||
notifications = persistentListOf(),
|
||||
expressTxs = persistentListOf(),
|
||||
expressTxsToDisplay = persistentListOf(),
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
bottomSheetConfig = null,
|
||||
isBalanceHidden = false,
|
||||
isMarketPriceAvailable = false,
|
||||
)
|
||||
|
|
@ -193,10 +190,7 @@ internal object TokenDetailsPreviewData {
|
|||
),
|
||||
stakingBlocksState = stakingAvailableBlock,
|
||||
notifications = persistentListOf(),
|
||||
expressTxs = persistentListOf(),
|
||||
expressTxsToDisplay = persistentListOf(),
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
bottomSheetConfig = null,
|
||||
isBalanceHidden = false,
|
||||
isMarketPriceAvailable = true,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.ExpressStateFactory
|
||||
|
|
@ -51,6 +52,7 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
private val router: InnerTokenDetailsRouter,
|
||||
private val getAccountCryptoCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
|
||||
private val expressTransactionsEventListener: ExpressTransactionsEventListener,
|
||||
private val updateDelayedNetworkStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
) : Model(), ExpressTransactionsClickIntents {
|
||||
|
||||
private val params = paramsContainer.require<ExpressTransactionsComponent.Params>()
|
||||
|
|
@ -67,7 +69,7 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
private var account: Account.CryptoPortfolio? = null
|
||||
private val expressTxStatusTaskScheduler = SingleTaskScheduler<PersistentList<ExpressTransactionStateUM>>()
|
||||
|
||||
private val waitForFirstExpressStatusEmmit = MutableStateFlow(false)
|
||||
private val waitForFirstExpressStatusEmit = MutableStateFlow(false)
|
||||
|
||||
private val currentStateProvider: Provider<ExpressTransactionsBlockState> = Provider { internalUiState.value }
|
||||
|
||||
|
|
@ -97,6 +99,14 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
subscribeOnExpressTransactionsUpdates()
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
clear()
|
||||
}
|
||||
|
||||
override fun onExpressTransactionClick(txId: String) {
|
||||
val expressTxState = internalUiState.value.transactionsToDisplay.firstOrNull { it.info.txId == txId }
|
||||
?: return
|
||||
|
|
@ -155,7 +165,7 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
override fun onDismissBottomSheet() {
|
||||
when (val bsContent = internalUiState.value.bottomSheetSlot?.config?.content) {
|
||||
is ExpressStatusBottomSheetConfig -> {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
modelScope.launch(dispatchers.mainImmediate) {
|
||||
expressStatusFactory.removeTransactionOnBottomSheetClosed(bsContent.value)
|
||||
}
|
||||
}
|
||||
|
|
@ -174,11 +184,19 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
when (event) {
|
||||
ExpressTransactionsEvent.Update -> subscribeOnExpressTransactionsUpdates()
|
||||
ExpressTransactionsEvent.Clear -> clear()
|
||||
is ExpressTransactionsEvent.OpenTx -> openTxOnFirstEmit(event.txId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openTxOnFirstEmit(txId: String) {
|
||||
modelScope.launch {
|
||||
waitForFirstExpressStatusEmit.first { it }
|
||||
onExpressTransactionClick(txId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnCurrencyStatusUpdates() {
|
||||
getAccountCryptoCurrencyStatusUseCase(userWalletId, cryptoCurrency)
|
||||
.onEach { account = it.account }
|
||||
|
|
@ -193,11 +211,11 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
expressTxStatusTaskScheduler.cancelTask()
|
||||
expressStatusFactory.getExpressStatuses()
|
||||
.distinctUntilChanged()
|
||||
.onEach { waitForFirstExpressStatusEmmit.value = true }
|
||||
.onEach { waitForFirstExpressStatusEmit.value = true }
|
||||
.onEach { expressTxs ->
|
||||
internalUiState.value = expressStatusFactory.getStateWithUpdatedExpressTxs(
|
||||
expressTxs = expressTxs,
|
||||
updateBalance = { /* no-op */ },
|
||||
updateBalance = ::updateNetworkToSwapBalance,
|
||||
)
|
||||
expressTxStatusTaskScheduler.scheduleTask(
|
||||
scope = modelScope,
|
||||
|
|
@ -217,7 +235,7 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
onSuccess = { updatedTxs ->
|
||||
internalUiState.value = expressStatusFactory.getStateWithUpdatedExpressTxs(
|
||||
expressTxs = updatedTxs,
|
||||
updateBalance = { /* no-op */ },
|
||||
updateBalance = ::updateNetworkToSwapBalance,
|
||||
)
|
||||
},
|
||||
onError = { /* no-op */ },
|
||||
|
|
@ -229,6 +247,15 @@ internal class ExpressTransactionsModel @Inject constructor(
|
|||
.saveIn(expressTxJobHolder)
|
||||
}
|
||||
|
||||
private fun updateNetworkToSwapBalance(toCryptoCurrency: CryptoCurrency) {
|
||||
modelScope.launch {
|
||||
updateDelayedNetworkStatusUseCase(
|
||||
userWalletId = userWalletId,
|
||||
network = toCryptoCurrency.network,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSelectedAppCurrencyFlow(): StateFlow<AppCurrency> {
|
||||
return getSelectedAppCurrencyUseCase()
|
||||
.map { maybeAppCurrency ->
|
||||
|
|
|
|||
|
|
@ -68,14 +68,6 @@ interface TokenDetailsClickIntents {
|
|||
|
||||
fun onBalanceSelect(config: TokenBalanceSegmentedButtonConfig)
|
||||
|
||||
fun onGoToRefundedTokenClick(cryptoCurrency: CryptoCurrency)
|
||||
|
||||
fun onOpenUrlClick(url: String)
|
||||
|
||||
fun onConfirmDisposeExpressStatus()
|
||||
|
||||
fun onDisposeExpressStatus()
|
||||
|
||||
fun onYieldInfoClick()
|
||||
|
||||
// region Clore migration
|
||||
|
|
@ -174,14 +166,6 @@ internal class EmptyTokenDetailsClickIntents : TokenDetailsClickIntents {
|
|||
return null
|
||||
}
|
||||
|
||||
override fun onGoToRefundedTokenClick(cryptoCurrency: CryptoCurrency) { /* no op */ }
|
||||
|
||||
override fun onOpenUrlClick(url: String) { /* no op */ }
|
||||
|
||||
override fun onConfirmDisposeExpressStatus() { /* no op */ }
|
||||
|
||||
override fun onDisposeExpressStatus() { /* no op */ }
|
||||
|
||||
// region Clore migration
|
||||
// TODO: Remove after 2025-04-01 when Clore migration ends ([REDACTED_TASK_KEY])
|
||||
|
||||
|
|
|
|||
|
|
@ -70,20 +70,4 @@ internal class TokenDetailsDialogFactory @Inject constructor(
|
|||
fun showError(text: TextReference) {
|
||||
uiMessageSender.send(DialogMessage(message = text))
|
||||
}
|
||||
|
||||
fun showConfirmHideExpressStatus(onConfirm: () -> Unit) {
|
||||
uiMessageSender.send(
|
||||
DialogMessage(
|
||||
title = resourceReference(R.string.express_status_hide_dialog_title),
|
||||
message = resourceReference(R.string.express_status_hide_dialog_text),
|
||||
firstActionBuilder = {
|
||||
EventMessageAction(
|
||||
title = resourceReference(R.string.common_hide),
|
||||
onClick = onConfirm,
|
||||
)
|
||||
},
|
||||
secondActionBuilder = { cancelAction() },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -14,13 +14,10 @@ import com.tangem.domain.dynamicaddresses.DynamicAddressesFeatureToggles
|
|||
import com.tangem.domain.dynamicaddresses.DynamicAddressesSupportedBlockchains
|
||||
import com.tangem.domain.dynamicaddresses.IsXpubSupportedUseCase
|
||||
import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository
|
||||
import com.tangem.common.TangemBlogUrlBuilder
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.bottomsheet.receive.AddressModel
|
||||
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.event.OfframpAnalyticsEvent
|
||||
|
|
@ -104,7 +101,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDeta
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsStateController
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.TokenDetailsExpressStatusFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.InitializeWithCryptoCurrencyTransformer
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.SetBalanceLoadingTransformer
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.SetBalanceTransformer
|
||||
|
|
@ -113,6 +109,8 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.transform
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.UpdateStakingNotificationTransformer
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.UpdateNotificationsTransformer
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.UpdateTopBarMenuTransformer
|
||||
import com.tangem.features.tokendetails.ExpressTransactionsEvent
|
||||
import com.tangem.features.tokendetails.ExpressTransactionsEventListener
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter
|
||||
|
|
@ -121,7 +119,6 @@ import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
|||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.*
|
||||
import com.tangem.utils.extensions.isZero
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
|
|
@ -144,7 +141,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase,
|
||||
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
private val shouldShowPromoTokenUseCase: ShouldShowPromoTokenUseCase,
|
||||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
private val getExtendedPublicKeyForCurrencyUseCase: GetExtendedPublicKeyForCurrencyUseCase,
|
||||
private val getStakingEntryInfoUseCase: GetStakingEntryInfoUseCase,
|
||||
private val getStakingAvailabilityUseCase: GetStakingAvailabilityUseCase,
|
||||
|
|
@ -161,8 +157,8 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val clipboardManager: ClipboardManager,
|
||||
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
|
||||
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
|
||||
private val expressTransactionsEventListener: ExpressTransactionsEventListener,
|
||||
paramsContainer: ParamsContainer,
|
||||
tokenDetailsExpressStatusFactory: TokenDetailsExpressStatusFactory.Factory,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val appRouter: AppRouter,
|
||||
private val router: InnerTokenDetailsRouter,
|
||||
|
|
@ -189,7 +185,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val redesignStateController: TokenDetailsStateController,
|
||||
) : Model(),
|
||||
TokenDetailsClickIntents,
|
||||
ExpressTransactionsClickIntents,
|
||||
YieldSupplyDepositedWarningComponent.ModelCallback {
|
||||
|
||||
private val params = paramsContainer.require<TokenDetailsComponent.Params>()
|
||||
|
|
@ -202,7 +197,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val marketPriceJobHolder = JobHolder()
|
||||
private val refreshStateJobHolder = JobHolder()
|
||||
private val warningsJobHolder = JobHolder()
|
||||
private val expressTxJobHolder = JobHolder()
|
||||
private val buttonsJobHolder = JobHolder()
|
||||
private val stakingJobHolder = JobHolder()
|
||||
private val yieldSupplyBalanceJobHolder = JobHolder()
|
||||
|
|
@ -213,10 +207,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null
|
||||
private var account: Account.CryptoPortfolio? = null
|
||||
private var isBalanceLoadedEventSent = false
|
||||
private val expressTxStatusTaskScheduler = SingleTaskScheduler<PersistentList<ExpressTransactionStateUM>>()
|
||||
|
||||
/** Transaction id to check for status */
|
||||
private val waitForFirstExpressStatusEmmit = MutableStateFlow(false)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TokenDetailsBottomSheetConfig> = SlotNavigation()
|
||||
|
||||
|
|
@ -267,17 +257,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
// endregion Dynamic Addresses
|
||||
|
||||
private val expressStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
tokenDetailsExpressStatusFactory.create(
|
||||
clickIntents = this,
|
||||
appCurrencyProvider = Provider { selectedAppCurrencyFlow.value },
|
||||
currentStateProvider = Provider { uiState.value },
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
)
|
||||
}
|
||||
|
||||
private val notificationsAnalyticsSender by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
TokenDetailsNotificationsAnalyticsSender(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
|
|
@ -299,21 +278,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
handleNavigationParam()
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
expressTxStatusTaskScheduler.cancelTask()
|
||||
expressTxJobHolder.cancel()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
expressTxStatusTaskScheduler.cancelTask()
|
||||
expressTxJobHolder.cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun initButtons() {
|
||||
// we need also init buttons before start all loading to avoid buttons blocking
|
||||
modelScope.launch {
|
||||
|
|
@ -335,7 +299,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
|
||||
private fun updateContent() {
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
}
|
||||
|
||||
private fun handleBalanceHiding() {
|
||||
|
|
@ -426,40 +389,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
.saveIn(marketPriceJobHolder)
|
||||
}
|
||||
|
||||
private fun subscribeOnExpressTransactionsUpdates() {
|
||||
expressTxStatusTaskScheduler.cancelTask()
|
||||
expressStatusFactory.getExpressStatuses()
|
||||
.distinctUntilChanged()
|
||||
.onEach { waitForFirstExpressStatusEmmit.value = true }
|
||||
.onEach { expressTxs ->
|
||||
uiState.value = expressStatusFactory.getStateWithUpdatedExpressTxs(
|
||||
expressTxs = expressTxs,
|
||||
updateBalance = ::updateNetworkToSwapBalance,
|
||||
)
|
||||
expressTxStatusTaskScheduler.scheduleTask(
|
||||
scope = modelScope,
|
||||
task = PeriodicTask(
|
||||
delay = EXPRESS_STATUS_UPDATE_DELAY,
|
||||
task = {
|
||||
runSuspendCatching {
|
||||
expressStatusFactory.getUpdatedExpressStatuses(uiState.value.expressTxs)
|
||||
}
|
||||
},
|
||||
onSuccess = { updatedTxs ->
|
||||
uiState.value = expressStatusFactory.getStateWithUpdatedExpressTxs(
|
||||
updatedTxs,
|
||||
::updateNetworkToSwapBalance,
|
||||
)
|
||||
},
|
||||
onError = { /* no-op */ },
|
||||
),
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(modelScope)
|
||||
.saveIn(expressTxJobHolder)
|
||||
}
|
||||
|
||||
private fun subscribeOnYieldSupplyBalanceIfActive(status: CryptoCurrencyStatus) {
|
||||
if (status.value.yieldSupplyStatus?.isActive == true) {
|
||||
if (yieldSupplyBalanceJobHolder.isActive && status.value.sources.networkSource != StatusSource.ACTUAL) {
|
||||
|
|
@ -480,15 +409,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateNetworkToSwapBalance(toCryptoCurrency: CryptoCurrency) {
|
||||
modelScope.launch {
|
||||
updateDelayedCurrencyStatusUseCase(
|
||||
userWalletId = userWalletId,
|
||||
network = toCryptoCurrency.network,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTxHistory() {
|
||||
modelScope.launch { txHistoryContentUpdateEmitter.triggerUpdate() }
|
||||
}
|
||||
|
|
@ -922,52 +842,17 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
},
|
||||
async {
|
||||
updateTxHistory()
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
expressTransactionsEventListener.send(ExpressTransactionsEvent.Update)
|
||||
},
|
||||
).awaitAll()
|
||||
uiState.value = stateFactory.getRefreshedState()
|
||||
}.saveIn(refreshStateJobHolder)
|
||||
}
|
||||
|
||||
override fun onDismissBottomSheet() {
|
||||
when (val bsContent = uiState.value.bottomSheetConfig?.content) {
|
||||
is ExpressStatusBottomSheetConfig -> {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
expressStatusFactory.removeTransactionOnBottomSheetClosed(bsContent.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
uiState.value = stateFactory.getStateWithClosedBottomSheet()
|
||||
}
|
||||
|
||||
override fun onCloseRentInfoNotification() {
|
||||
uiState.value = stateFactory.getStateWithRemovedRentNotification()
|
||||
}
|
||||
|
||||
override fun onExpressTransactionClick(txId: String) {
|
||||
val expressTxState = uiState.value.expressTxsToDisplay.firstOrNull { it.info.txId == txId }
|
||||
?: return
|
||||
uiState.value = expressStatusFactory.getStateWithExpressStatusBottomSheet(expressTxState)
|
||||
}
|
||||
|
||||
override fun onGoToProviderClick(url: String) {
|
||||
router.openUrl(url)
|
||||
}
|
||||
|
||||
override fun onGoToRefundedTokenClick(cryptoCurrency: CryptoCurrency) {
|
||||
router.openTokenDetails(userWalletId, cryptoCurrency)
|
||||
}
|
||||
|
||||
override fun onOpenUrlClick(url: String) {
|
||||
router.openUrl(url)
|
||||
}
|
||||
|
||||
override fun onReadAboutCrossChainBridgesClick() {
|
||||
modelScope.launch {
|
||||
router.openUrl(TangemBlogUrlBuilder.build(TangemBlogUrlBuilder.Post.AboutCrossChainBridges))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSwapPromoDismiss(promoId: PromoId) {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
shouldShowPromoTokenUseCase.neverToShow(promoId)
|
||||
|
|
@ -1161,23 +1046,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
uiState.value = stateFactory.getStateWithUpdatedBalanceSegmentedButtonConfig(config)
|
||||
}
|
||||
|
||||
override fun onConfirmDisposeExpressStatus() {
|
||||
dialogFactory.showConfirmHideExpressStatus(onConfirm = ::onDisposeExpressStatus)
|
||||
}
|
||||
|
||||
override fun onDisposeExpressStatus() {
|
||||
val bottomSheetState = uiState.value.bottomSheetConfig?.content
|
||||
if (bottomSheetState is ExpressStatusBottomSheetConfig) {
|
||||
modelScope.launch {
|
||||
expressStatusFactory.removeTransactionOnBottomSheetClosed(
|
||||
expressState = bottomSheetState.value,
|
||||
isForceDispose = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
uiState.value = stateFactory.getStateWithClosedBottomSheet()
|
||||
}
|
||||
|
||||
override fun onYieldInfoClick() {
|
||||
analyticsEventsHandler.send(
|
||||
YieldSupplyAnalytics.EarnedFundsInfo(
|
||||
|
|
@ -1226,11 +1094,8 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun checkForActionUpdates() {
|
||||
combine(
|
||||
tokenDetailsDeepLinkActionListener.tokenDetailsActionFlow,
|
||||
waitForFirstExpressStatusEmmit.filter { it },
|
||||
) { transactionId, _ -> transactionId }
|
||||
.onEach(::onExpressTransactionClick)
|
||||
tokenDetailsDeepLinkActionListener.tokenDetailsActionFlow
|
||||
.onEach { txId -> expressTransactionsEventListener.send(ExpressTransactionsEvent.OpenTx(txId)) }
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
|
|
@ -1519,7 +1384,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
)
|
||||
|
||||
private companion object {
|
||||
const val EXPRESS_STATUS_UPDATE_DELAY = 10_000L
|
||||
const val BASE_DERIVATION_NODE_COUNT = 5
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,9 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state
|
||||
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
||||
internal data class TokenDetailsState(
|
||||
val topAppBarConfig: TokenDetailsTopAppBarConfig,
|
||||
|
|
@ -15,10 +12,7 @@ internal data class TokenDetailsState(
|
|||
val marketPriceBlockState: MarketPriceBlockState,
|
||||
val stakingBlocksState: StakingBlockUM?,
|
||||
val notifications: ImmutableList<TokenDetailsNotification>,
|
||||
val expressTxsToDisplay: PersistentList<ExpressTransactionStateUM>,
|
||||
val expressTxs: PersistentList<ExpressTransactionStateUM>,
|
||||
val pullToRefreshConfig: PullToRefreshConfig,
|
||||
val bottomSheetConfig: TangemBottomSheetConfig?,
|
||||
val isBalanceHidden: Boolean,
|
||||
val isMarketPriceAvailable: Boolean,
|
||||
)
|
||||
|
|
@ -63,10 +63,7 @@ internal class TokenDetailsSkeletonStateConverter(
|
|||
marketPriceBlockState = MarketPriceBlockState.Loading(value.symbol),
|
||||
stakingBlocksState = StakingBlockUM.Loading(iconState).takeIf { isSupportedInMobileApp },
|
||||
notifications = persistentListOf(),
|
||||
expressTxs = persistentListOf(),
|
||||
expressTxsToDisplay = persistentListOf(),
|
||||
pullToRefreshConfig = createPullToRefresh(),
|
||||
bottomSheetConfig = null,
|
||||
isBalanceHidden = true,
|
||||
isMarketPriceAvailable = value.id.rawCurrencyId != null,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -123,13 +123,6 @@ internal class TokenDetailsStateFactory(
|
|||
return refreshStateConverter.convert(false)
|
||||
}
|
||||
|
||||
fun getStateWithClosedBottomSheet(): TokenDetailsState {
|
||||
val state = currentStateProvider()
|
||||
return state.copy(
|
||||
bottomSheetConfig = state.bottomSheetConfig?.copy(isShown = false),
|
||||
)
|
||||
}
|
||||
|
||||
fun getStateWithUpdatedHidden(isBalanceHidden: Boolean): TokenDetailsState {
|
||||
val currentState = currentStateProvider()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,254 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.datasource.local.swap.ExpressAnalyticsStatus
|
||||
import com.tangem.datasource.local.swap.SwapTransactionStatusStore
|
||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.quote.QuoteStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.quotes.QuotesRepository
|
||||
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.feature.swap.domain.SwapTransactionRepository
|
||||
import com.tangem.feature.swap.domain.api.SwapRepository
|
||||
import com.tangem.feature.swap.domain.models.domain.*
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsSwapTransactionsStateConverter
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokenDetailsExchangeStatusFactory @AssistedInject constructor(
|
||||
private val swapTransactionRepository: SwapTransactionRepository,
|
||||
private val swapRepository: SwapRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
|
||||
private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
|
||||
private val swapTransactionStatusStore: SwapTransactionStatusStore,
|
||||
private val analyticsEventsHandler: AnalyticsEventHandler,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
@Assisted private val clickIntents: ExpressTransactionsClickIntents,
|
||||
@Assisted private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
@Assisted private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted private val cryptoCurrency: CryptoCurrency,
|
||||
) {
|
||||
|
||||
private val swapTransactionsStateConverter by lazy {
|
||||
TokenDetailsSwapTransactionsStateConverter(
|
||||
clickIntents = clickIntents,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
analyticsEventsHandler = analyticsEventsHandler,
|
||||
)
|
||||
}
|
||||
|
||||
operator fun invoke(): Flow<PersistentList<ExchangeUM>> {
|
||||
return swapTransactionRepository.getTransactions(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
).conflate()
|
||||
.map { savedTransactions ->
|
||||
val quotes = savedTransactions
|
||||
?.flatMap { setOf(it.fromCryptoCurrency.id, it.toCryptoCurrency.id) }
|
||||
?.toSet()
|
||||
?.getQuotesOrEmpty()
|
||||
.orEmpty()
|
||||
|
||||
getExchangeStatusState(
|
||||
savedTransactions = savedTransactions,
|
||||
quoteStatuses = quotes,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun removeTransactionOnBottomSheetClosed(isForceDispose: Boolean = false) {
|
||||
val state = currentStateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig?.content as? ExpressStatusBottomSheetConfig ?: return
|
||||
val selectedTx = bottomSheetConfig.value as? ExchangeUM ?: return
|
||||
|
||||
val shouldDispose = selectedTx.activeStatus?.isAutoDisposable == true || isForceDispose
|
||||
if (shouldDispose) {
|
||||
swapTransactionRepository.removeTransaction(
|
||||
userWalletId = userWallet.walletId,
|
||||
txId = selectedTx.info.txId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateSwapTxStatus(swapTx: ExchangeUM): ExchangeUM {
|
||||
return if (swapTx.activeStatus?.isTerminal == true) {
|
||||
swapTx
|
||||
} else {
|
||||
val statusModel = getExchangeStatus(swapTx.info.txId, swapTx.provider, swapTx.fromUserWalletId)
|
||||
|
||||
if (statusModel != null) {
|
||||
swapTransactionsStateConverter.updateTxStatus(
|
||||
tx = swapTx,
|
||||
statusModel = statusModel,
|
||||
)
|
||||
} else {
|
||||
swapTx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getExchangeStatus(
|
||||
txId: String,
|
||||
provider: SwapProvider,
|
||||
fromUserWalletId: UserWalletId,
|
||||
): ExchangeStatusModel? {
|
||||
val fromUserWallet = getUserWalletUseCase(fromUserWalletId).getOrElse { error ->
|
||||
TangemLogger.e("Couldn't find userWallet: $error")
|
||||
return null
|
||||
}
|
||||
return swapRepository.getExchangeStatus(
|
||||
userWallet = fromUserWallet,
|
||||
userWalletId = fromUserWalletId,
|
||||
txId = txId,
|
||||
).fold(
|
||||
ifLeft = { null },
|
||||
ifRight = { statusModel ->
|
||||
sendStatusUpdateAnalytics(statusModel, provider)
|
||||
|
||||
val accountId = getAccountCurrencyStatusUseCase.invokeSync(
|
||||
userWalletId = fromUserWalletId,
|
||||
currency = cryptoCurrency,
|
||||
)
|
||||
.map { it.account.accountId }
|
||||
.getOrNull()
|
||||
|
||||
val refundTokenCurrency = if (accountId != null) {
|
||||
addRefundCurrencyIfNeeded(
|
||||
accountId = accountId,
|
||||
status = statusModel,
|
||||
type = provider.type,
|
||||
)
|
||||
} else {
|
||||
TangemLogger.e("Account ID is null, cannot add refund currency ${cryptoCurrency.id}")
|
||||
null
|
||||
}
|
||||
|
||||
swapTransactionRepository.storeTransactionState(
|
||||
txId = txId,
|
||||
status = statusModel,
|
||||
accountWithCurrency = if (refundTokenCurrency != null) {
|
||||
Pair(accountId, refundTokenCurrency)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
statusModel.copy(refundCurrency = refundTokenCurrency)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun sendStatusUpdateAnalytics(statusModel: ExchangeStatusModel, provider: SwapProvider) {
|
||||
val txId = statusModel.txId ?: return
|
||||
val status = toAnalyticStatus(statusModel.status) ?: return
|
||||
val savedStatus = swapTransactionStatusStore.getTransactionStatus(txId)
|
||||
|
||||
if (savedStatus != status) {
|
||||
analyticsEventsHandler.send(
|
||||
TokenExchangeAnalyticsEvent.CexTxStatusChanged(cryptoCurrency.symbol, status.value, provider.name),
|
||||
)
|
||||
swapTransactionStatusStore.setTransactionStatus(txId, status)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun addRefundCurrencyIfNeeded(
|
||||
accountId: AccountId,
|
||||
status: ExchangeStatusModel?,
|
||||
type: ExchangeProviderType,
|
||||
): CryptoCurrency? {
|
||||
status ?: return null
|
||||
if (type != ExchangeProviderType.DEX_BRIDGE) return null
|
||||
val refundNetwork = status.refundNetwork
|
||||
val refundContractAddress = status.refundContractAddress
|
||||
|
||||
if (refundNetwork == null || refundContractAddress == null) return null
|
||||
|
||||
return manageCryptoCurrenciesUseCase.add(
|
||||
accountId = accountId,
|
||||
contractAddress = refundContractAddress,
|
||||
networkId = refundNetwork,
|
||||
)
|
||||
.onLeft { TangemLogger.e("Error", it) }
|
||||
.getOrNull()
|
||||
}
|
||||
|
||||
private fun getExchangeStatusState(
|
||||
savedTransactions: List<SavedSwapTransactionListModel>?,
|
||||
quoteStatuses: Set<QuoteStatus>,
|
||||
): PersistentList<ExchangeUM> {
|
||||
if (savedTransactions == null) {
|
||||
return persistentListOf()
|
||||
}
|
||||
|
||||
return swapTransactionsStateConverter.convert(
|
||||
savedTransactions = savedTransactions,
|
||||
quoteStatuses = quoteStatuses,
|
||||
)
|
||||
}
|
||||
|
||||
private fun toAnalyticStatus(status: ExchangeStatus?): ExpressAnalyticsStatus? {
|
||||
return when (status) {
|
||||
ExchangeStatus.New,
|
||||
ExchangeStatus.Waiting,
|
||||
ExchangeStatus.Sending,
|
||||
ExchangeStatus.Confirming,
|
||||
ExchangeStatus.Exchanging,
|
||||
-> ExpressAnalyticsStatus.InProgress
|
||||
ExchangeStatus.WaitingTxHash -> ExpressAnalyticsStatus.WaitingTxHash
|
||||
ExchangeStatus.Verifying -> ExpressAnalyticsStatus.KYC
|
||||
ExchangeStatus.Failed -> ExpressAnalyticsStatus.Fail
|
||||
ExchangeStatus.TxFailed -> ExpressAnalyticsStatus.FailTx
|
||||
ExchangeStatus.Finished -> ExpressAnalyticsStatus.Done
|
||||
ExchangeStatus.Refunded -> ExpressAnalyticsStatus.Refunded
|
||||
ExchangeStatus.Cancelled -> ExpressAnalyticsStatus.Cancelled
|
||||
ExchangeStatus.Unknown -> ExpressAnalyticsStatus.Unknown
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Set<CryptoCurrency.ID>.getQuotesOrEmpty(): Set<QuoteStatus> {
|
||||
val rawIds = mapNotNull { it.rawCurrencyId }.toSet()
|
||||
|
||||
return try {
|
||||
quotesRepository.getMultiQuoteSyncOrNull(currenciesIds = rawIds).orEmpty()
|
||||
} catch (exception: CancellationException) {
|
||||
throw exception
|
||||
} catch (ignore: Exception) {
|
||||
emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(
|
||||
clickIntents: ExpressTransactionsClickIntents,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
currentStateProvider: Provider<TokenDetailsState>,
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): TokenDetailsExchangeStatusFactory
|
||||
}
|
||||
}
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express
|
||||
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
|
||||
import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent
|
||||
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokenDetailsExpressStatusFactory @AssistedInject constructor(
|
||||
@Assisted private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
@Assisted private val clickIntents: ExpressTransactionsClickIntents,
|
||||
@Assisted private val cryptoCurrency: CryptoCurrency,
|
||||
@Assisted appCurrencyProvider: Provider<AppCurrency>,
|
||||
@Assisted userWallet: UserWallet,
|
||||
@Assisted cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventsHandler: AnalyticsEventHandler,
|
||||
tokenDetailsOnrampStatusFactory: TokenDetailsOnrampStatusFactory.Factory,
|
||||
tokenDetailsExchangeStatusFactory: TokenDetailsExchangeStatusFactory.Factory,
|
||||
) {
|
||||
|
||||
private val exchangeStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
tokenDetailsExchangeStatusFactory.create(
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
currentStateProvider = currentStateProvider,
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
)
|
||||
}
|
||||
|
||||
private val onrampStatusFactory by lazy(LazyThreadSafetyMode.NONE) {
|
||||
tokenDetailsOnrampStatusFactory.create(
|
||||
currentStateProvider = currentStateProvider,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
clickIntents = clickIntents,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
userWallet = userWallet,
|
||||
)
|
||||
}
|
||||
|
||||
fun getExpressStatuses(): Flow<PersistentList<ExpressTransactionStateUM>> = combine(
|
||||
flow = exchangeStatusFactory(),
|
||||
flow2 = onrampStatusFactory(),
|
||||
) { maybeExchange, maybeOnramp ->
|
||||
persistentListOf(maybeOnramp, maybeExchange)
|
||||
.flatten()
|
||||
.sortedByDescending { it.info.timestamp }
|
||||
.toPersistentList()
|
||||
}
|
||||
|
||||
suspend fun getUpdatedExpressStatuses(expressTxs: PersistentList<ExpressTransactionStateUM>) =
|
||||
withContext(dispatchers.io) {
|
||||
expressTxs.map { tx ->
|
||||
async {
|
||||
when (tx) {
|
||||
is ExchangeUM -> exchangeStatusFactory.updateSwapTxStatus(tx)
|
||||
is ExpressTransactionStateUM.OnrampUM -> onrampStatusFactory.updateOnrmapTxStatus(tx)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}.awaitAll()
|
||||
.filterNotNull()
|
||||
.toPersistentList()
|
||||
}
|
||||
|
||||
fun getStateWithUpdatedExpressTxs(
|
||||
expressTxs: PersistentList<ExpressTransactionStateUM>,
|
||||
updateBalance: (CryptoCurrency) -> Unit,
|
||||
): TokenDetailsState {
|
||||
val state = currentStateProvider()
|
||||
val config = state.bottomSheetConfig
|
||||
val expressBottomSheet = config?.content as? ExpressStatusBottomSheetConfig
|
||||
val currentTx = expressTxs.firstOrNull { it.info.txId == expressBottomSheet?.value?.info?.txId }
|
||||
if (currentTx is ExchangeUM && currentTx.activeStatus == ExchangeStatus.Finished) {
|
||||
updateBalance(currentTx.toCryptoCurrency)
|
||||
}
|
||||
val expressTxsToDisplay = expressTxs.filterNot { txs ->
|
||||
when (txs) {
|
||||
is ExpressTransactionStateUM.OnrampUM -> txs.activeStatus.isHidden
|
||||
else -> false
|
||||
}
|
||||
}.toPersistentList()
|
||||
return state.copy(
|
||||
expressTxs = expressTxs,
|
||||
expressTxsToDisplay = expressTxsToDisplay,
|
||||
bottomSheetConfig = currentTx?.let(::updateStateWithExpressStatusBottomSheet) ?: config,
|
||||
)
|
||||
}
|
||||
|
||||
fun getStateWithExpressStatusBottomSheet(expressState: ExpressTransactionStateUM): TokenDetailsState {
|
||||
val analyticEvents = when (expressState) {
|
||||
is ExchangeUM -> listOfNotNull(
|
||||
TokenExchangeAnalyticsEvent.CexTxStatusOpened(
|
||||
token = cryptoCurrency.symbol,
|
||||
provider = expressState.provider.name,
|
||||
),
|
||||
maybeGetLongTimeExchangeNotificationShowEvent(
|
||||
expressState = expressState,
|
||||
currentStateNotification = null,
|
||||
isBottomSheetShown = true,
|
||||
),
|
||||
)
|
||||
is ExpressTransactionStateUM.OnrampUM -> listOf(
|
||||
TokenOnrampAnalyticsEvent.OnrampStatusOpened(
|
||||
tokenSymbol = cryptoCurrency.symbol,
|
||||
provider = expressState.providerName,
|
||||
fiatCurrency = expressState.fromCurrencyCode,
|
||||
),
|
||||
)
|
||||
else -> return currentStateProvider()
|
||||
}
|
||||
|
||||
analyticEvents.forEach { analyticsEventsHandler.send(it) }
|
||||
|
||||
return currentStateProvider().copy(
|
||||
bottomSheetConfig = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = clickIntents::onDismissBottomSheet,
|
||||
content = ExpressStatusBottomSheetConfig(
|
||||
value = expressState,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun updateStateWithExpressStatusBottomSheet(expressState: ExpressTransactionStateUM): TangemBottomSheetConfig? {
|
||||
val state = currentStateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig
|
||||
val currentConfig = bottomSheetConfig?.content as? ExpressStatusBottomSheetConfig ?: return bottomSheetConfig
|
||||
|
||||
maybeGetLongTimeExchangeNotificationShowEvent(
|
||||
expressState = expressState,
|
||||
currentStateNotification = (currentConfig.value as? ExchangeUM)?.notification,
|
||||
isBottomSheetShown = bottomSheetConfig.isShown,
|
||||
)?.let { analyticsEventsHandler.send(it) }
|
||||
|
||||
return bottomSheetConfig.copy(
|
||||
content = if (currentConfig.value != expressState) {
|
||||
ExpressStatusBottomSheetConfig(expressState)
|
||||
} else {
|
||||
currentConfig
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun removeTransactionOnBottomSheetClosed(
|
||||
expressState: ExpressTransactionStateUM,
|
||||
isForceDispose: Boolean = false,
|
||||
) {
|
||||
when (expressState) {
|
||||
is ExchangeUM -> exchangeStatusFactory.removeTransactionOnBottomSheetClosed(isForceDispose)
|
||||
is ExpressTransactionStateUM.OnrampUM -> onrampStatusFactory.removeTransactionOnBottomSheetClosed(
|
||||
isForceDispose,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun maybeGetLongTimeExchangeNotificationShowEvent(
|
||||
expressState: ExpressTransactionStateUM,
|
||||
currentStateNotification: ExchangeStatusNotification?,
|
||||
isBottomSheetShown: Boolean,
|
||||
): TokenScreenAnalyticsEvent? {
|
||||
val newState = expressState as? ExchangeUM
|
||||
val newStateNotification = newState?.notification
|
||||
return if (currentStateNotification !is ExchangeStatusNotification.LongTimeExchange &&
|
||||
newStateNotification is ExchangeStatusNotification.LongTimeExchange &&
|
||||
isBottomSheetShown
|
||||
) {
|
||||
TokenExchangeAnalyticsEvent.LongTimeTransaction(
|
||||
token = cryptoCurrency.symbol,
|
||||
provider = newState.provider.name,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
@Suppress("LongParameterList")
|
||||
fun create(
|
||||
clickIntents: ExpressTransactionsClickIntents,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
currentStateProvider: Provider<TokenDetailsState>,
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
): TokenDetailsExpressStatusFactory
|
||||
}
|
||||
}
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express
|
||||
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.datasource.local.swap.ExpressAnalyticsStatus
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.onramp.GetOnrampStatusUseCase
|
||||
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
|
||||
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
|
||||
import com.tangem.domain.onramp.OnrampUpdateTransactionStatusUseCase
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.model.OnrampStatus.Status.*
|
||||
import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTransactionsClickIntents
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsOnrampTransactionStateConverter
|
||||
import com.tangem.utils.Provider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokenDetailsOnrampStatusFactory @AssistedInject constructor(
|
||||
private val getOnrampTransactionsUseCase: GetOnrampTransactionsUseCase,
|
||||
private val getOnrampStatusUseCase: GetOnrampStatusUseCase,
|
||||
private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
|
||||
private val onrampUpdateTransactionStatusUseCase: OnrampUpdateTransactionStatusUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
@Assisted private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
@Assisted private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
@Assisted private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
@Assisted private val clickIntents: ExpressTransactionsClickIntents,
|
||||
@Assisted private val cryptoCurrency: CryptoCurrency,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
) {
|
||||
|
||||
private val onrampTransactionStateConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
TokenDetailsOnrampTransactionStateConverter(
|
||||
clickIntents = clickIntents,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
)
|
||||
}
|
||||
|
||||
operator fun invoke(): Flow<List<ExpressTransactionStateUM.OnrampUM>> {
|
||||
return getOnrampTransactionsUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
).map { maybeTransaction ->
|
||||
maybeTransaction.fold(
|
||||
ifRight = { onrampTxs ->
|
||||
val transactions = onrampTransactionStateConverter.convertList(onrampTxs)
|
||||
transactions.clearHiddenTerminal()
|
||||
transactions
|
||||
},
|
||||
ifLeft = { persistentListOf() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun removeTransactionOnBottomSheetClosed(isForceDispose: Boolean) {
|
||||
val state = currentStateProvider()
|
||||
val bottomSheetConfig = state.bottomSheetConfig?.content as? ExpressStatusBottomSheetConfig ?: return
|
||||
val selectedTx = bottomSheetConfig.value as? ExpressTransactionStateUM.OnrampUM ?: return
|
||||
|
||||
if (selectedTx.activeStatus.isAutoDisposable || isForceDispose) {
|
||||
onrampRemoveTransactionUseCase(txId = selectedTx.info.txId)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateOnrmapTxStatus(onrampTx: ExpressTransactionStateUM.OnrampUM): ExpressTransactionStateUM.OnrampUM {
|
||||
return if (onrampTx.activeStatus.isTerminal) {
|
||||
onrampTx
|
||||
} else {
|
||||
getOnrampStatusUseCase(userWallet = userWallet, onrampTx.info.txId).fold(
|
||||
ifLeft = { error ->
|
||||
TangemLogger.e("Couldn't update onramp status. $error")
|
||||
onrampTx
|
||||
},
|
||||
ifRight = { statusModel ->
|
||||
sendStatusUpdateAnalytics(onrampTx, statusModel)
|
||||
onrampTx.copy(
|
||||
activeStatus = statusModel.status,
|
||||
info = onrampTx.info.copy(
|
||||
txExternalId = statusModel.externalTxId,
|
||||
txExternalUrl = statusModel.externalTxUrl,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun List<ExpressTransactionStateUM.OnrampUM>.clearHiddenTerminal() {
|
||||
this.filter { it.activeStatus.isHidden && it.activeStatus.isTerminal }
|
||||
.forEach { onrampRemoveTransactionUseCase(txId = it.info.txId) }
|
||||
}
|
||||
|
||||
private suspend fun sendStatusUpdateAnalytics(
|
||||
onrampTx: ExpressTransactionStateUM.OnrampUM,
|
||||
statusModel: OnrampStatus,
|
||||
) {
|
||||
val txId = statusModel.txId
|
||||
val status = toAnalyticStatus(statusModel.status) ?: return
|
||||
|
||||
if (statusModel.status != onrampTx.activeStatus) {
|
||||
analyticsEventHandler.send(
|
||||
TokenOnrampAnalyticsEvent.OnrampStatusChanged(
|
||||
tokenSymbol = cryptoCurrency.symbol,
|
||||
status = status.name,
|
||||
provider = onrampTx.providerName,
|
||||
fiatCurrency = onrampTx.fromCurrencyCode,
|
||||
),
|
||||
)
|
||||
onrampUpdateTransactionStatusUseCase(
|
||||
txId = txId,
|
||||
externalTxUrl = statusModel.externalTxUrl.orEmpty(),
|
||||
externalTxId = statusModel.externalTxId.orEmpty(),
|
||||
status = statusModel.status,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun toAnalyticStatus(status: OnrampStatus.Status?): ExpressAnalyticsStatus? {
|
||||
return when (status) {
|
||||
Expired,
|
||||
Paused,
|
||||
-> ExpressAnalyticsStatus.Cancelled
|
||||
Created,
|
||||
WaitingForPayment,
|
||||
PaymentProcessing,
|
||||
Paid,
|
||||
Sending,
|
||||
RefundInProgress,
|
||||
-> ExpressAnalyticsStatus.InProgress
|
||||
Verifying -> ExpressAnalyticsStatus.KYC
|
||||
Failed -> ExpressAnalyticsStatus.Fail
|
||||
Finished -> ExpressAnalyticsStatus.Done
|
||||
Refunded -> ExpressAnalyticsStatus.Refunded
|
||||
null -> null
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(
|
||||
currentStateProvider: Provider<TokenDetailsState>,
|
||||
cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
clickIntents: ExpressTransactionsClickIntents,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
userWallet: UserWallet,
|
||||
): TokenDetailsOnrampStatusFactory
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,6 @@ import androidx.compose.foundation.lazy.LazyListState
|
|||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import com.tangem.common.ui.earn.EarnBlock
|
||||
import com.tangem.common.ui.notifications.notifications
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
|
@ -31,12 +30,13 @@ import androidx.compose.ui.graphics.Brush
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.account.AccountIconUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState
|
||||
import com.tangem.core.ui.components.BottomFade
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
|
|
@ -60,12 +60,14 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDeta
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsBalanceBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsBalanceBlockHeight
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.tokendetails.ExpressTransactionsComponent
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
import com.tangem.features.txhistory.entity.TxHistoryItemsUM
|
||||
import com.tangem.features.txhistory.entity.TxHistoryUM
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
||||
import dev.chrisbanes.haze.HazeProgressive
|
||||
import dev.chrisbanes.haze.HazeTint
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
|
@ -79,8 +81,10 @@ internal fun TokenDetailsScreen(
|
|||
tokenMarketBlockComponent: TokenMarketBlockComponent?,
|
||||
yieldSupplyComponent: YieldSupplyComponent,
|
||||
txHistoryComponent: TxHistoryComponent,
|
||||
expressTransactionsComponent: ExpressTransactionsComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val expressState by expressTransactionsComponent.state.collectAsStateWithLifecycle()
|
||||
val statusBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getTop(this).toDp() }
|
||||
val partialCollapsedHeight = TopBarHeight + statusBarHeight
|
||||
val expandedHeight = TokenDetailsBalanceBlockHeight + partialCollapsedHeight
|
||||
|
|
@ -95,9 +99,6 @@ internal fun TokenDetailsScreen(
|
|||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
val fadeFloorHeight = TangemTheme.dimens.size100 + bottomBarHeight
|
||||
val effectiveBottomPadding = maxOf(partialCollapsedHeight + marketBlockHeight, fadeFloorHeight)
|
||||
val notificationModifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens2.x4)
|
||||
|
||||
Box(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
|
|
@ -124,12 +125,13 @@ internal fun TokenDetailsScreen(
|
|||
tokenDetailsUM = tokenDetailsUM,
|
||||
yieldSupplyComponent = yieldSupplyComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
expressTransactionsComponent = expressTransactionsComponent,
|
||||
expressTransactionsToDisplay = expressState.transactionsToDisplay,
|
||||
rootBackground = rootBackground,
|
||||
bottomContentPadding = effectiveBottomPadding,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.nestedScroll(behavior.nestedScrollConnection),
|
||||
itemModifier = notificationModifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -148,6 +150,8 @@ internal fun TokenDetailsScreen(
|
|||
onHeightChange = { marketBlockHeight = it },
|
||||
)
|
||||
}
|
||||
|
||||
expressState.bottomSheetSlot?.content()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -207,18 +211,27 @@ private fun BoxScope.TokenDetailsMarketBlockOverlay(
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun TokenDetailsBody(
|
||||
tokenDetailsUM: TokenDetailsUM,
|
||||
yieldSupplyComponent: YieldSupplyComponent,
|
||||
txHistoryComponent: TxHistoryComponent,
|
||||
expressTransactionsComponent: ExpressTransactionsComponent,
|
||||
expressTransactionsToDisplay: PersistentList<ExpressTransactionStateUM>,
|
||||
rootBackground: Color,
|
||||
bottomContentPadding: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
itemModifier: Modifier = Modifier,
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
val txHistoryState by txHistoryComponent.txHistoryState.collectAsStateWithLifecycle()
|
||||
val itemModifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens2.x4)
|
||||
|
||||
val expressTransactionModifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = TangemTheme.dimens2.x4, end = TangemTheme.dimens2.x4, top = TangemTheme.dimens2.x4)
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
|
|
@ -241,6 +254,12 @@ private fun TokenDetailsBody(
|
|||
item(key = "yield_supply_block") {
|
||||
yieldSupplyComponent.Content(modifier = itemModifier.padding(vertical = TangemTheme.dimens2.x2))
|
||||
}
|
||||
with(expressTransactionsComponent) {
|
||||
expressTransactionsContent(
|
||||
state = expressTransactionsToDisplay,
|
||||
modifier = expressTransactionModifier,
|
||||
)
|
||||
}
|
||||
with(txHistoryComponent) {
|
||||
txHistoryContent(listState = listState, state = txHistoryState)
|
||||
}
|
||||
|
|
@ -307,7 +326,28 @@ private fun TokenDetailsScreen_Preview() {
|
|||
|
||||
override fun LazyListScope.txHistoryContent(listState: LazyListState, state: TxHistoryItemsUM) = Unit
|
||||
},
|
||||
expressTransactionsComponent = PreviewExpressTransactionsComponent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val PreviewExpressTransactionsComponent = object : ExpressTransactionsComponent {
|
||||
override val state: StateFlow<ExpressTransactionsBlockState> = MutableStateFlow(
|
||||
ExpressTransactionsBlockState(
|
||||
transactions = persistentListOf(),
|
||||
transactionsToDisplay = persistentListOf(),
|
||||
bottomSheetSlot = null,
|
||||
),
|
||||
)
|
||||
|
||||
override fun LazyListScope.expressTransactionsContentLegacy(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) = Unit
|
||||
|
||||
override fun LazyListScope.expressTransactionsContent(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) = Unit
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -14,8 +14,8 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItems
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlock
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
|
|
@ -30,13 +30,15 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.component
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsBalanceBlockLegacy
|
||||
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.express.ExpressStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.TokenStakingBlockLegacy
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.tokendetails.ExpressTransactionsComponent
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
import com.tangem.features.txhistory.entity.TxHistoryItemsUM
|
||||
import com.tangem.features.txhistory.entity.TxHistoryUM
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
|
|
@ -48,6 +50,7 @@ internal fun TokenDetailsScreenLegacy(
|
|||
tokenMarketBlockComponent: TokenMarketBlockComponent?,
|
||||
txHistoryComponent: TxHistoryComponent,
|
||||
yieldSupplyComponent: YieldSupplyComponent,
|
||||
expressTransactionsComponent: ExpressTransactionsComponent,
|
||||
) {
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
|
|
@ -58,6 +61,7 @@ internal fun TokenDetailsScreenLegacy(
|
|||
) { scaffoldPaddings ->
|
||||
val listState = rememberLazyListState()
|
||||
val txHistoryComponentState by txHistoryComponent.legacyTxHistoryState.collectAsStateWithLifecycle()
|
||||
val expressState by expressTransactionsComponent.state.collectAsStateWithLifecycle()
|
||||
val betweenItemsPadding = TangemTheme.dimens.spacing12
|
||||
val horizontalPadding = TangemTheme.dimens.spacing16
|
||||
val itemModifier = Modifier
|
||||
|
|
@ -147,10 +151,12 @@ internal fun TokenDetailsScreenLegacy(
|
|||
yieldSupplyComponent.Content(modifier = itemModifier)
|
||||
}
|
||||
|
||||
expressTransactionsItems(
|
||||
expressTxs = state.expressTxsToDisplay,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
with(expressTransactionsComponent) {
|
||||
expressTransactionsContentLegacy(
|
||||
state = expressState.transactionsToDisplay,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
}
|
||||
|
||||
with(txHistoryComponent) {
|
||||
txHistoryContentLegacy(listState = listState, state = txHistoryComponentState)
|
||||
|
|
@ -158,11 +164,7 @@ internal fun TokenDetailsScreenLegacy(
|
|||
}
|
||||
}
|
||||
|
||||
state.bottomSheetConfig?.let { config ->
|
||||
if (config.content is ExpressStatusBottomSheetConfig) {
|
||||
ExpressStatusBottomSheet(config = config)
|
||||
}
|
||||
}
|
||||
expressState.bottomSheetSlot?.content()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,10 +197,31 @@ private fun TokenDetailsScreenPreview(
|
|||
override fun Content(modifier: Modifier) {
|
||||
}
|
||||
},
|
||||
expressTransactionsComponent = PreviewExpressTransactionsComponent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val PreviewExpressTransactionsComponent = object : ExpressTransactionsComponent {
|
||||
override val state: StateFlow<ExpressTransactionsBlockState> = MutableStateFlow(
|
||||
ExpressTransactionsBlockState(
|
||||
transactions = persistentListOf(),
|
||||
transactionsToDisplay = persistentListOf(),
|
||||
bottomSheetSlot = null,
|
||||
),
|
||||
)
|
||||
|
||||
override fun LazyListScope.expressTransactionsContentLegacy(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) = Unit
|
||||
|
||||
override fun LazyListScope.expressTransactionsContent(
|
||||
state: PersistentList<ExpressTransactionStateUM>,
|
||||
modifier: Modifier,
|
||||
) = Unit
|
||||
}
|
||||
|
||||
private class TokenDetailsScreenParameterProvider : CollectionPreviewParameterProvider<TokenDetailsState>(
|
||||
collection = listOf(
|
||||
TokenDetailsPreviewData.tokenDetailsState_1,
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheet
|
|||
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheet
|
||||
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItems
|
||||
import com.tangem.common.ui.expressStatus.expressTransactionsItemsLegacy
|
||||
import com.tangem.core.ui.components.atoms.handComposableComponentHeight
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheetDraggableHeaderLegacy
|
||||
|
|
@ -236,7 +236,7 @@ private fun WalletContent(
|
|||
marketPriceBlock(state = marketPriceBlockState, modifier = itemModifier)
|
||||
}
|
||||
if (walletState is WalletState.SingleCurrency.Content) {
|
||||
expressTransactionsItems(
|
||||
expressTransactionsItemsLegacy(
|
||||
expressTxs = walletState.expressTxsToDisplay,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue