Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-08 11:38:02 +03:00
parent 4eead599f3
commit f65dcebf65
23 changed files with 267 additions and 450 deletions

View file

@ -15,6 +15,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
@ -30,6 +31,7 @@ import com.tangem.core.ui.components.transactions.state.TransactionState.Content
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import java.util.UUID
@ -46,6 +48,7 @@ import java.util.UUID
[REDACTED_AUTHOR]
*/
@Composable
@Suppress("LongMethod")
fun Transaction(state: TransactionState, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
Surface(
modifier = modifier
@ -76,10 +79,15 @@ fun Transaction(state: TransactionState, isBalanceHidden: Boolean, modifier: Mod
Title(
state = state,
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing12)
.padding(
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing6,
)
.constrainAs(titleItem) {
start.linkTo(iconItem.end)
end.linkTo(amountItem.start)
top.linkTo(iconItem.top)
width = Dimension.fillToConstraints
},
)
@ -173,11 +181,16 @@ private fun Icon(state: TransactionState, modifier: Modifier = Modifier) {
private fun Title(state: TransactionState, modifier: Modifier = Modifier) {
when (state) {
is TransactionState.Content -> {
Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing6)) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing6),
) {
Text(
text = state.title.resolveReference(),
color = TangemTheme.colors.text.primary1,
style = TangemTheme.typography.subtitle2,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
if (state.status is Status.Unconfirmed) {
@ -266,7 +279,7 @@ private fun Timestamp(state: TransactionState, modifier: Modifier = Modifier) {
when (state) {
is TransactionState.Content -> {
Text(
text = state.timestamp,
text = state.time,
modifier = modifier,
textAlign = TextAlign.End,
color = TangemTheme.colors.text.tertiary,
@ -321,89 +334,109 @@ private class TransactionItemStateProvider : CollectionPreviewParameterProvider<
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "-0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = Status.Confirmed,
direction = Direction.OUTGOING,
iconRes = R.drawable.ic_arrow_up_24,
title = resourceReference(R.string.common_transfer),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "+0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = Status.Unconfirmed,
direction = Direction.INCOMING,
iconRes = R.drawable.ic_arrow_down_24,
title = resourceReference(R.string.common_transfer),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "+0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = Status.Unconfirmed,
direction = Direction.OUTGOING,
iconRes = R.drawable.ic_doc_24,
title = resourceReference(R.string.common_approval),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "+0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = Status.Failed,
direction = Direction.OUTGOING,
iconRes = R.drawable.ic_doc_24,
title = resourceReference(R.string.common_approval),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "+0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = Status.Confirmed,
direction = Direction.OUTGOING,
iconRes = R.drawable.ic_doc_24,
title = resourceReference(R.string.common_approval),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "+0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = Status.Unconfirmed,
direction = Direction.INCOMING,
iconRes = R.drawable.ic_arrow_down_24,
title = resourceReference(R.string.common_swap),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "+0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = Status.Confirmed,
direction = Direction.INCOMING,
iconRes = R.drawable.ic_doc_24,
title = TextReference.Str("Submit"),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "+0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = Status.Confirmed,
direction = Direction.OUTGOING,
iconRes = R.drawable.ic_arrow_up_24,
title = TextReference.Str("Submit"),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "0.625 USDT",
time = "€0.50",
status = Status.Confirmed,
direction = Direction.OUTGOING,
iconRes = R.drawable.ic_arrow_up_24,
title = TextReference.Str("Unlimint Banking Cards Sandbox London"),
subtitle = stringReference(value = "8:41 • authorized"),
timestamp = 0L,
onClick = {},
),
TransactionState.Loading(txHash = UUID.randomUUID().toString()),

View file

@ -25,13 +25,14 @@ sealed interface TransactionState {
data class Content(
override val txHash: String,
val amount: String,
val timestamp: String,
val time: String,
val status: Status,
val direction: Direction,
val onClick: () -> Unit,
@DrawableRes val iconRes: Int,
val title: TextReference,
val subtitle: TextReference,
val timestamp: Long,
) : TransactionState {
sealed class Status {

View file

@ -12,7 +12,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsPendingTxToTransactionStateConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryTransactionStateConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
@ -29,7 +29,7 @@ internal class TokenDetailsLoadedBalanceConverter(
) : Converter<Either<CurrencyStatusError, CryptoCurrencyStatus>, TokenDetailsState> {
private val txHistoryItemConverter by lazy {
TokenDetailsPendingTxToTransactionStateConverter(symbol, decimals, clickIntents)
TokenDetailsTxHistoryTransactionStateConverter(symbol, decimals, clickIntents)
}
override fun convert(value: Either<CurrencyStatusError, CryptoCurrencyStatus>): TokenDetailsState {

View file

@ -1,109 +0,0 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
// FIXME: Refactoring needed
/** Same as [TokenDetailsTxHistoryTransactionStateConverter] but with other timestamp format */
internal class TokenDetailsPendingTxToTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,
) : Converter<TxHistoryItem, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState {
return createTransactionStateItem(item = value)
}
private fun createTransactionStateItem(item: TxHistoryItem): TransactionState {
return TransactionState.Content(
txHash = item.txHash,
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.extractDirection(),
iconRes = item.extractIcon(),
title = item.extractTitle(),
subtitle = item.extractSubtitle(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
)
}
private fun TxHistoryItem.extractIcon(): Int = if (status == TxHistoryItem.TransactionStatus.Failed) {
R.drawable.ic_close_24
} else {
when (type) {
is TxHistoryItem.TransactionType.Approve -> R.drawable.ic_doc_24
is TxHistoryItem.TransactionType.Operation,
is TxHistoryItem.TransactionType.Swap,
is TxHistoryItem.TransactionType.Transfer,
is TxHistoryItem.TransactionType.UnknownOperation,
-> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24
}
}
private fun TxHistoryItem.extractTitle(): TextReference = when (val type = type) {
is TxHistoryItem.TransactionType.Approve -> resourceReference(R.string.common_approval)
is TxHistoryItem.TransactionType.Operation -> stringReference(type.name)
is TxHistoryItem.TransactionType.Swap -> resourceReference(R.string.common_swap)
is TxHistoryItem.TransactionType.Transfer -> resourceReference(R.string.common_transfer)
is TxHistoryItem.TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation)
}
private fun TxHistoryItem.extractSubtitle(): TextReference =
when (val interactionAddress = interactionAddressType) {
is TxHistoryItem.InteractionAddressType.Contract -> resourceReference(
id = R.string.transaction_history_contract_address,
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
is TxHistoryItem.InteractionAddressType.Multiple -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)),
)
is TxHistoryItem.InteractionAddressType.User -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
}
private fun TxHistoryItem.TransactionStatus.tiUiStatus() = when (this) {
TxHistoryItem.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
TxHistoryItem.TransactionStatus.Failed -> TransactionState.Content.Status.Failed
TxHistoryItem.TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed
}
private fun Long.toTimeFormat(): String {
return DateTimeFormatters.formatTime(time = DateTime(this, DateTimeZone.getDefault()))
}
private fun TxHistoryItem.extractDirection() =
if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING
private fun TxHistoryItem.getAmount(): String {
val prefix = when (status) {
TxHistoryItem.TransactionStatus.Failed -> ""
else -> if (isOutgoing) "-" else "+"
}
return prefix + amount.toFormattedCurrencyString(currency = symbol, decimals = decimals)
}
}

View file

@ -5,7 +5,6 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistoryItemState
import com.tangem.core.ui.utils.toDateFormat
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
@ -52,8 +51,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter(
terminalSeparatorType = TerminalSeparatorType.SOURCE_COMPLETE,
item = TxHistoryItemState.Title(clickIntents::onExploreClick),
)
.insertGroupTitle() // method uses the raw timestamp
.formatTransactionsTimestamp() // method formats the timestamp
.insertGroupTitle()
}
}
.launchIn(CoroutineScope(Dispatchers.IO))
@ -94,28 +92,10 @@ internal class TokenDetailsTxHistoryItemFlowConverter(
}
}
/**
* Map the [PagingData] to format the [TxHistoryItemState] timestamp
*/
private fun PagingData<TxHistoryItemState>.formatTransactionsTimestamp(): PagingData<TxHistoryItemState> {
return map { txHistoryItemState ->
if (txHistoryItemState is TxHistoryItemState.Transaction &&
txHistoryItemState.state is TransactionState.Content
) {
val txContent = txHistoryItemState.state as TransactionState.Content
txHistoryItemState.copy(
state = txContent.copy(timestamp = txContent.timestamp.toLong().toTimeFormat()),
)
} else {
txHistoryItemState
}
}
}
private fun TxHistoryItemState?.getTimestamp(): Long? {
return if (this is TxHistoryItemState.Transaction && this.state is TransactionState.Content) {
val txContent = this.state as TransactionState.Content
requireNotNull(txContent.timestamp.toLongOrNull()) { "Timestamp must be Long type" }
txContent.timestamp
} else {
null
}

View file

@ -6,6 +6,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
import com.tangem.features.tokendetails.impl.R
@ -13,8 +14,6 @@ import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString
// FIXME: Refactoring needed
/** Same as [TokenDetailsPendingTxToTransactionStateConverter] but with other timestamp format */
internal class TokenDetailsTxHistoryTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
@ -30,12 +29,13 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
return TransactionState.Content(
txHash = item.txHash,
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
time = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.extractDirection(),
iconRes = item.extractIcon(),
title = item.extractTitle(),
subtitle = item.extractSubtitle(),
timestamp = item.timestampInMillis,
onClick = { clickIntents.onTransactionClick(item.txHash) },
)
}
@ -87,14 +87,6 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
private fun TxHistoryItem.extractDirection() = if (isOutgoing) Direction.OUTGOING else Direction.INCOMING
/**
* Get timestamp without formatting.
* It's life hack that help us to add transaction's group title to flow.
*
* @see [convert]
*/
private fun TxHistoryItem.getRawTimestamp() = this.timestampInMillis.toString()
private fun TxHistoryItem.TransactionStatus.tiUiStatus() = when (this) {
TxHistoryItem.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
TxHistoryItem.TransactionStatus.Failed -> TransactionState.Content.Status.Failed

View file

@ -426,12 +426,13 @@ internal object WalletPreviewData {
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "-0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = TransactionState.Content.Status.Unconfirmed,
direction = TransactionState.Content.Direction.OUTGOING,
iconRes = com.tangem.core.ui.R.drawable.ic_arrow_up_24,
title = resourceReference(com.tangem.core.ui.R.string.common_transfer),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
),
@ -443,12 +444,13 @@ internal object WalletPreviewData {
TransactionState.Content(
txHash = UUID.randomUUID().toString(),
amount = "-0.500913 BTC",
timestamp = "8:41",
time = "8:41",
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.OUTGOING,
iconRes = com.tangem.core.ui.R.drawable.ic_arrow_up_24,
title = resourceReference(com.tangem.core.ui.R.string.common_transfer),
subtitle = TextReference.Str("33BddS...ga2B"),
timestamp = 0L,
onClick = {},
),
),

View file

@ -1,46 +1,32 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.visa.GetVisaCurrencyUseCase
import com.tangem.domain.visa.GetVisaTxHistoryUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.TxHistorySubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.VisaWalletBalancesAndLimitsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.VisaWalletSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@Suppress("LongParameterList")
internal class VisaWalletContentLoader(
private val userWallet: UserWallet,
private val clickIntents: WalletClickIntentsV2,
private val isRefresh: Boolean,
private val stateHolder: WalletStateController,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val stateController: WalletStateController,
private val getVisaTxHistoryUseCase: GetVisaTxHistoryUseCase,
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> {
return listOf(
VisaWalletBalancesAndLimitsSubscriber(
VisaWalletSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
stateController = stateController,
isRefresh = isRefresh,
getVisaCurrencyUseCase = getVisaCurrencyUseCase,
getVisaTxHistoryUseCase = getVisaTxHistoryUseCase,
clickIntents = clickIntents,
),
TxHistorySubscriber(
userWallet = userWallet,
isRefresh = isRefresh,
stateHolder = stateHolder,
clickIntents = clickIntents,
getPrimaryCurrencyStatusUpdatesUseCase = getPrimaryCurrencyStatusUpdatesUseCase,
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
txHistoryItemsUseCase = txHistoryItemsUseCase,
),
)
}
}

View file

@ -1,9 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.visa.GetVisaCurrencyUseCase
import com.tangem.domain.visa.GetVisaTxHistoryUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@ -11,13 +9,10 @@ import dagger.hilt.android.scopes.ViewModelScoped
import javax.inject.Inject
@ViewModelScoped
@Suppress("LongParameterList")
internal class VisaWalletContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateController,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
private val getVisaTxHistoryUseCase: GetVisaTxHistoryUseCase,
) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntentsV2, isRefresh: Boolean): WalletContentLoader {
@ -25,11 +20,9 @@ internal class VisaWalletContentLoaderFactory @Inject constructor(
userWallet = userWallet,
clickIntents = clickIntents,
isRefresh = isRefresh,
stateHolder = stateHolder,
getPrimaryCurrencyStatusUpdatesUseCase = getPrimaryCurrencyStatusUpdatesUseCase,
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
txHistoryItemsUseCase = txHistoryItemsUseCase,
stateController = stateHolder,
getVisaCurrencyUseCase = getVisaCurrencyUseCase,
getVisaTxHistoryUseCase = getVisaTxHistoryUseCase,
)
}
}

View file

@ -32,7 +32,7 @@ internal class WalletLoadingTxHistoryConverter(
private val txHistoryItemConverter by lazy {
val blockchain = currentCardTypeResolverProvider().getBlockchain()
WalletPendingTxToTransactionStateConverter(
WalletTxHistoryTransactionStateConverter(
symbol = blockchain.currency,
decimals = blockchain.decimals(),
clickIntents = clickIntents,

View file

@ -1,109 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
// FIXME: Refactoring needed
/** Same as [WalletTxHistoryTransactionStateConverter] but with other timestamp format */
internal class WalletPendingTxToTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
private val clickIntents: WalletClickIntents,
) : Converter<TxHistoryItem, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState {
return createTransactionStateItem(item = value)
}
private fun createTransactionStateItem(item: TxHistoryItem): TransactionState {
return TransactionState.Content(
txHash = item.txHash,
amount = item.getAmount(),
timestamp = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.extractDirection(),
iconRes = item.extractIcon(),
title = item.extractTitle(),
subtitle = item.extractSubtitle(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
)
}
private fun TxHistoryItem.extractIcon(): Int = if (status == TxHistoryItem.TransactionStatus.Failed) {
R.drawable.ic_close_24
} else {
when (type) {
is TxHistoryItem.TransactionType.Approve -> R.drawable.ic_doc_24
is TxHistoryItem.TransactionType.Operation,
is TxHistoryItem.TransactionType.Swap,
is TxHistoryItem.TransactionType.Transfer,
is TxHistoryItem.TransactionType.UnknownOperation,
-> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24
}
}
private fun TxHistoryItem.extractTitle(): TextReference = when (val type = type) {
is TxHistoryItem.TransactionType.Approve -> resourceReference(R.string.common_approval)
is TxHistoryItem.TransactionType.Operation -> stringReference(type.name)
is TxHistoryItem.TransactionType.Swap -> resourceReference(R.string.common_swap)
is TxHistoryItem.TransactionType.Transfer -> resourceReference(R.string.common_transfer)
is TxHistoryItem.TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation)
}
private fun TxHistoryItem.extractSubtitle(): TextReference =
when (val interactionAddress = interactionAddressType) {
is TxHistoryItem.InteractionAddressType.Contract -> resourceReference(
id = R.string.transaction_history_contract_address,
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
is TxHistoryItem.InteractionAddressType.Multiple -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)),
)
is TxHistoryItem.InteractionAddressType.User -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
}
private fun TxHistoryItem.TransactionStatus.tiUiStatus() = when (this) {
TxHistoryItem.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
TxHistoryItem.TransactionStatus.Failed -> TransactionState.Content.Status.Failed
TxHistoryItem.TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed
}
private fun Long.toTimeFormat(): String {
return DateTimeFormatters.formatTime(time = DateTime(this, DateTimeZone.getDefault()))
}
private fun TxHistoryItem.extractDirection() =
if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING
private fun TxHistoryItem.getAmount(): String {
val prefix = when (status) {
TxHistoryItem.TransactionStatus.Failed -> ""
else -> if (isOutgoing) "-" else "+"
}
return prefix + amount.toFormattedCurrencyString(currency = symbol, decimals = decimals)
}
}

View file

@ -64,8 +64,7 @@ internal class WalletTxHistoryItemFlowConverter(
terminalSeparatorType = TerminalSeparatorType.SOURCE_COMPLETE,
item = TxHistoryItemState.Title(clickIntents::onExploreClick),
)
.insertGroupTitle() // method uses the raw timestamp
.formatTransactionsTimestamp() // method formats the timestamp
.insertGroupTitle()
}
}
.launchIn(CoroutineScope(Dispatchers.IO))
@ -103,28 +102,10 @@ internal class WalletTxHistoryItemFlowConverter(
}
}
/**
* Map the [PagingData] to format the [TxHistoryItemState] timestamp
*/
private fun PagingData<TxHistoryItemState>.formatTransactionsTimestamp(): PagingData<TxHistoryItemState> {
return map { txHistoryItemState ->
if (txHistoryItemState is TxHistoryItemState.Transaction &&
txHistoryItemState.state is TransactionState.Content
) {
val txContent = txHistoryItemState.state as TransactionState.Content
txHistoryItemState.copy(
state = txContent.copy(timestamp = txContent.timestamp.toTimeFormat()),
)
} else {
txHistoryItemState
}
}
}
private fun TxHistoryItemState?.getTimestamp(): Long? {
return if (this is TxHistoryItemState.Transaction && this.state is TransactionState.Content) {
val txContent = this.state as TransactionState.Content
requireNotNull(txContent.timestamp.toLongOrNull()) { "Timestamp must be Long type" }
txContent.timestamp
} else {
null
}
@ -147,8 +128,4 @@ internal class WalletTxHistoryItemFlowConverter(
DateTimeFormatters.formatDate(date = localDate)
}
}
private fun String.toTimeFormat(): String {
return DateTimeFormatters.formatTime(time = DateTime(this.toLong(), DateTimeZone.getDefault()))
}
}

View file

@ -5,6 +5,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
@ -12,8 +13,6 @@ import com.tangem.utils.converter.Converter
import com.tangem.utils.toBriefAddressFormat
import com.tangem.utils.toFormattedCurrencyString
// FIXME: Refactoring needed
/** Same as [WalletPendingTxToTransactionStateConverter] but with other timestamp format */
internal class WalletTxHistoryTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
@ -29,12 +28,13 @@ internal class WalletTxHistoryTransactionStateConverter(
return TransactionState.Content(
txHash = item.txHash,
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
time = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.extractDirection(),
iconRes = item.extractIcon(),
title = item.extractTitle(),
subtitle = item.extractSubtitle(),
timestamp = item.timestampInMillis,
onClick = { clickIntents.onTransactionClick(item.txHash) },
)
}
@ -87,14 +87,6 @@ internal class WalletTxHistoryTransactionStateConverter(
private fun TxHistoryItem.extractDirection() =
if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING
/**
* Get timestamp without formatting.
* It's life hack that help us to add transaction's group title to flow.
*
* @see [convert]
*/
private fun TxHistoryItem.getRawTimestamp() = this.timestampInMillis.toString()
private fun TxHistoryItem.TransactionStatus.tiUiStatus() = when (this) {
TxHistoryItem.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
TxHistoryItem.TransactionStatus.Failed -> TransactionState.Content.Status.Failed

View file

@ -26,12 +26,14 @@ internal class SetBalancesAndLimitsTransformer(
val visaCurrency = maybeVisaCurrency.getOrElse {
return state.copy(
walletCardState = getErrorWalletCardState(state.walletCardState),
depositButtonState = state.depositButtonState.copy(isEnabled = false),
balancesAndLimitBlockState = BalancesAndLimitsBlockState.Error,
)
}
state.copy(
walletCardState = getContentWalletCardState(state.walletCardState, visaCurrency),
depositButtonState = state.depositButtonState.copy(isEnabled = true),
balancesAndLimitBlockState = getContentBlockState(visaCurrency),
)
}

View file

@ -1,8 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import androidx.paging.PagingData
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.TxHistoryItemFlowConverter
@ -11,8 +11,8 @@ import kotlinx.coroutines.flow.Flow
import timber.log.Timber
internal class SetTxHistoryItemsTransformer(
private val userWallet: UserWallet,
private val flow: Flow<PagingData<TxHistoryItem>>,
userWallet: UserWallet,
private val flow: Flow<PagingData<TransactionState>>,
private val clickIntents: WalletClickIntentsV2,
) : WalletStateTransformer(userWallet.walletId) {
@ -39,7 +39,6 @@ internal class SetTxHistoryItemsTransformer(
private fun TxHistoryState.toContentState(): TxHistoryState {
val converter = TxHistoryItemFlowConverter(
userWallet = userWallet,
currentState = this,
clickIntents = clickIntents,
)

View file

@ -5,10 +5,6 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistoryItemState
import com.tangem.core.ui.utils.toDateFormat
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import com.tangem.utils.converter.Converter
import kotlinx.coroutines.CoroutineScope
@ -19,21 +15,11 @@ import java.util.UUID
private val scope = CoroutineScope(Dispatchers.IO)
internal class TxHistoryItemFlowConverter(
private val userWallet: UserWallet,
private val currentState: TxHistoryState,
private val clickIntents: WalletClickIntentsV2,
) : Converter<Flow<PagingData<TxHistoryItem>>, TxHistoryState?> {
) : Converter<Flow<PagingData<TransactionState>>, TxHistoryState?> {
private val txHistoryItemConverter by lazy {
val blockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain()
TxHistoryItemStateConverter(
symbol = blockchain.currency,
decimals = blockchain.decimals(),
clickIntents = clickIntents,
)
}
override fun convert(value: Flow<PagingData<TxHistoryItem>>): TxHistoryState {
override fun convert(value: Flow<PagingData<TransactionState>>): TxHistoryState {
val txHistoryContent = currentState as? TxHistoryState.Content
?: TxHistoryState.Content(contentItems = MutableStateFlow(PagingData.empty()))
@ -43,16 +29,14 @@ internal class TxHistoryItemFlowConverter(
.onEach { txHistoryStatePagingData ->
txHistoryContent.contentItems.update {
txHistoryStatePagingData
.map<TxHistoryItem, TxHistoryItemState> { item ->
// [createTransactionState] returns timestamp without formatting
TxHistoryItemState.Transaction(state = createTransactionState(item))
.map<TransactionState, TxHistoryItemState> { item ->
TxHistoryItemState.Transaction(item)
}
.insertHeaderItem(
terminalSeparatorType = TerminalSeparatorType.SOURCE_COMPLETE,
item = TxHistoryItemState.Title(clickIntents::onExploreClick),
)
.insertGroupTitle() // method uses the raw timestamp
.formatTransactionsTimestamp() // method formats the timestamp
.insertGroupTitle()
}
}
.cachedIn(scope)
@ -61,10 +45,6 @@ internal class TxHistoryItemFlowConverter(
return txHistoryContent
}
private fun createTransactionState(item: TxHistoryItem): TransactionState {
return txHistoryItemConverter.convert(value = item)
}
private fun PagingData<TxHistoryItemState>.insertGroupTitle(): PagingData<TxHistoryItemState> {
return insertSeparators(terminalSeparatorType = TerminalSeparatorType.SOURCE_COMPLETE) { before, after ->
// Use raw timestamp to get date
@ -88,28 +68,11 @@ internal class TxHistoryItemFlowConverter(
}
}
/**
* Map the [PagingData] to format the [TxHistoryItemState] timestamp
*/
private fun PagingData<TxHistoryItemState>.formatTransactionsTimestamp(): PagingData<TxHistoryItemState> {
return map { txHistoryItemState ->
if (txHistoryItemState is TxHistoryItemState.Transaction &&
txHistoryItemState.state is TransactionState.Content
) {
val txContent = txHistoryItemState.state as TransactionState.Content
txHistoryItemState.copy(
state = txContent.copy(timestamp = txContent.timestamp.toLong().toTimeFormat()),
)
} else {
txHistoryItemState
}
}
}
private fun TxHistoryItemState?.getTimestamp(): Long? {
return if (this is TxHistoryItemState.Transaction && this.state is TransactionState.Content) {
val txContent = this.state as TransactionState.Content
requireNotNull(txContent.timestamp.toLongOrNull()) { "Timestamp must be Long type" }
txContent.timestamp
} else {
null
}

View file

@ -5,6 +5,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@ -27,13 +28,14 @@ internal class TxHistoryItemStateConverter(
return TransactionState.Content(
txHash = item.txHash,
amount = item.getAmount(),
timestamp = item.getRawTimestamp(),
time = item.timestampInMillis.toTimeFormat(),
status = item.status.tiUiStatus(),
direction = item.extractDirection(),
iconRes = item.extractIcon(),
title = item.extractTitle(),
subtitle = item.extractSubtitle(),
onClick = { clickIntents.onTransactionClick(item.txHash) },
timestamp = item.timestampInMillis,
onClick = { clickIntents.onVisaTransactionClick(item.txHash) },
)
}
@ -85,14 +87,6 @@ internal class TxHistoryItemStateConverter(
private fun TxHistoryItem.extractDirection() =
if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING
/**
* Get timestamp without formatting.
* It's life hack that help us to add transaction's group title to flow.
*
* @see [convert]
*/
private fun TxHistoryItem.getRawTimestamp() = this.timestampInMillis.toString()
private fun TxHistoryItem.TransactionStatus.tiUiStatus() = when (this) {
TxHistoryItem.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
TxHistoryItem.TransactionStatus.Failed -> TransactionState.Content.Status.Failed

View file

@ -0,0 +1,46 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.domain.visa.model.VisaCurrency
import com.tangem.domain.visa.model.VisaTxHistoryItem
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.VisaWalletIntents
import com.tangem.utils.converter.Converter
import org.joda.time.DateTimeZone
internal class VisaTxHistoryItemStateConverter(
private val visaCurrency: VisaCurrency,
private val clickIntents: VisaWalletIntents,
) : Converter<VisaTxHistoryItem, TransactionState> {
override fun convert(value: VisaTxHistoryItem): TransactionState {
val localDate = value.date.withZone(DateTimeZone.getDefault())
val time = DateTimeFormatters.formatTime(time = localDate)
val subtitle = "$time${value.status}"
return TransactionState.Content(
txHash = value.id,
amount = BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = value.amount,
cryptoCurrency = visaCurrency.symbol,
decimals = visaCurrency.decimals,
),
// Show tx fiat amount instead of tx time
time = BigDecimalFormatter.formatFiatAmount(
fiatAmount = value.fiatAmount,
fiatCurrencyCode = value.fiatCurrency.currencyCode,
fiatCurrencySymbol = value.fiatCurrency.symbol,
),
status = TransactionState.Content.Status.Confirmed,
direction = TransactionState.Content.Direction.INCOMING,
iconRes = R.drawable.ic_arrow_up_24,
title = stringReference(value = value.merchantName ?: "Unknown merchant"),
subtitle = stringReference(subtitle),
timestamp = localDate.millis,
onClick = { clickIntents.onVisaTransactionClick(value.id) },
)
}
}

View file

@ -2,8 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.map
import arrow.core.Either
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
@ -15,12 +15,16 @@ import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.*
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.TxHistoryItemStateConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
typealias MaybeTxHistoryCount = Either<TxHistoryStateError, Int>
typealias MaybeTxHistoryItems = Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>
@ -37,24 +41,6 @@ internal class TxHistorySubscriber(
) : WalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<PagingData<TxHistoryItem>> {
// TODO: [REDACTED_JIRA]
if (userWallet.scanResponse.cardTypesResolver.isVisaWallet()) {
return flow {
stateHolder.update(
object : WalletStateTransformer(userWallet.walletId) {
override fun transform(prevState: WalletState): WalletState {
return when (prevState) {
is WalletState.Visa.Content -> prevState.copy(
txHistoryState = TxHistoryState.Empty(onExploreClick = {}),
)
else -> prevState
}
}
},
)
}
}
return flow {
getPrimaryCurrencyStatusUpdatesUseCase.collectLatest(userWalletId = userWallet.walletId) { status ->
val maybeTxHistoryItemCount = txHistoryItemsCountUseCase(
@ -109,10 +95,19 @@ internal class TxHistorySubscriber(
clickIntents = clickIntents,
)
},
ifRight = {
ifRight = { itemsFlow ->
val blockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain()
val itemConverter = TxHistoryItemStateConverter(
symbol = blockchain.currency,
decimals = blockchain.decimals(),
clickIntents = clickIntents,
)
SetTxHistoryItemsTransformer(
userWallet = userWallet,
flow = it,
flow = itemsFlow.map { items ->
items.map(itemConverter::convert)
},
clickIntents = clickIntents,
)
},

View file

@ -1,32 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.visa.GetVisaCurrencyUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetBalancesAndLimitsTransformer
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
@Suppress("LongParameterList")
internal class VisaWalletBalancesAndLimitsSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val isRefresh: Boolean,
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
private val clickIntents: WalletClickIntentsV2,
) : WalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<*> {
return flow<Any> {
stateHolder.update(
SetBalancesAndLimitsTransformer(
userWallet = userWallet,
maybeVisaCurrency = getVisaCurrencyUseCase(userWallet.walletId, isRefresh),
clickIntents = clickIntents,
),
)
}
}
}

View file

@ -0,0 +1,105 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.map
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.domain.txhistory.models.TxHistoryListError
import com.tangem.domain.visa.GetVisaCurrencyUseCase
import com.tangem.domain.visa.GetVisaTxHistoryUseCase
import com.tangem.domain.visa.model.VisaCurrency
import com.tangem.domain.visa.model.VisaTxHistoryItem
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetBalancesAndLimitsTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.VisaTxHistoryItemStateConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import timber.log.Timber
internal class VisaWalletSubscriber(
private val userWallet: UserWallet,
private val stateController: WalletStateController,
private val isRefresh: Boolean,
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
private val getVisaTxHistoryUseCase: GetVisaTxHistoryUseCase,
private val clickIntents: WalletClickIntentsV2,
) : WalletSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<*> {
return flow<Any> {
setLoadingTxHistoryState()
val maybeCurrency = getVisaCurrencyUseCase(userWallet.walletId, isRefresh)
setLoadedCurrencyState(maybeCurrency)
val currency = maybeCurrency.getOrElse {
setFailedTxHistoryState(it)
return@flow
}
val txHistoryItemsFlow = getVisaTxHistoryUseCase(userWallet.walletId, isRefresh = isRefresh)
.map { maybeTxHistoryItems ->
maybeTxHistoryItems.getOrElse {
Timber.e(it, "Failed to load tx history for wallet ${userWallet.walletId}")
throw it
}
}
.catch { setFailedTxHistoryState(it) }
.cachedIn(coroutineScope)
setLoadedTxHistoryState(txHistoryItemsFlow, currency)
}
}
private fun setLoadedCurrencyState(maybeCurrency: Either<Throwable, VisaCurrency>) {
stateController.update(
SetBalancesAndLimitsTransformer(
userWallet = userWallet,
maybeVisaCurrency = maybeCurrency,
clickIntents = clickIntents,
),
)
}
private fun setLoadingTxHistoryState() {
stateController.update(
SetTxHistoryCountTransformer(
userWalletId = userWallet.walletId,
transactionsCount = 10,
clickIntents = clickIntents,
),
)
}
private fun setFailedTxHistoryState(it: Throwable) {
stateController.update(
SetTxHistoryItemsErrorTransformer(
userWalletId = userWallet.walletId,
error = TxHistoryListError.DataError(it),
clickIntents = clickIntents,
),
)
}
private fun setLoadedTxHistoryState(itemsFlow: Flow<PagingData<VisaTxHistoryItem>>, currency: VisaCurrency) {
val itemConverter = VisaTxHistoryItemStateConverter(currency, clickIntents)
stateController.update(
SetTxHistoryItemsTransformer(
userWallet = userWallet,
flow = itemsFlow.map { items ->
items.map(itemConverter::convert)
},
clickIntents = clickIntents,
),
)
}
}

View file

@ -30,6 +30,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.ActionsBottomSheetCon
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state2.model.*
import com.tangem.feature.wallet.presentation.wallet.state2.model.holder.TxHistoryStateHolder
import com.tangem.feature.wallet.presentation.wallet.ui.components.TokenActionsBottomSheet
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
import com.tangem.feature.wallet.presentation.wallet.ui.components.common.*
@ -92,7 +93,7 @@ private fun WalletContent(
BaseScaffold(state = state, selectedWallet = selectedWallet, snackbarHostState = snackbarHostState) {
val movableItemModifier = Modifier.changeWalletAnimator(walletsListState)
val lazyTxHistoryItems = (selectedWallet as? WalletState.SingleCurrency)?.let { walletState ->
val lazyTxHistoryItems = (selectedWallet as? TxHistoryStateHolder)?.let { walletState ->
(walletState.txHistoryState as? TxHistoryState.Content)?.contentItems?.collectAsLazyPagingItems()
}

View file

@ -23,6 +23,8 @@ internal interface VisaWalletIntents {
fun onDepositClick()
fun onBalancesAndLimitsClick()
fun onVisaTransactionClick(id: String)
}
@ViewModelScoped
@ -93,4 +95,8 @@ internal class VisaWalletIntentsImplementor @Inject constructor(
null
}
}
override fun onVisaTransactionClick(id: String) {
// TODO: Implement [REDACTED_JIRA]
}
}