Updated on 2026-08-14
This commit is contained in:
parent
4eead599f3
commit
f65dcebf65
23 changed files with 267 additions and 450 deletions
|
|
@ -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()),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = {},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue