Updated on 2026-08-14
This commit is contained in:
parent
e2ddd446d2
commit
73c1f6988d
6 changed files with 214 additions and 137 deletions
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet.saltPay.rv
|
||||
package com.tangem.tap.common
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet.saltPay
|
||||
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionStatus
|
||||
import com.tangem.tap.features.wallet.models.PendingTransactionType
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class HistoryTransactionData(
|
||||
val transactionData: TransactionData,
|
||||
private val walletAddress: String,
|
||||
) {
|
||||
fun isInProgress(): Boolean = transactionData.status == TransactionStatus.Unconfirmed
|
||||
|
||||
fun getTransactionType(): PendingTransactionType = when {
|
||||
transactionData.sourceAddress.lowercase() == walletAddress.lowercase() -> PendingTransactionType.Outgoing
|
||||
transactionData.destinationAddress.lowercase() == walletAddress.lowercase() -> PendingTransactionType.Incoming
|
||||
else -> PendingTransactionType.Unknown
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
|||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.domain.common.extensions.debounce
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.tap.common.ShimmerData
|
||||
import com.tangem.tap.common.ShimmerRecyclerAdapter
|
||||
import com.tangem.tap.common.extensions.animateVisibility
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
|
||||
|
|
@ -18,9 +20,9 @@ import com.tangem.tap.features.wallet.redux.WalletAction
|
|||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.ui.WalletFragment
|
||||
import com.tangem.tap.features.wallet.ui.wallet.WalletView
|
||||
import com.tangem.tap.features.wallet.ui.wallet.saltPay.rv.ShimmerData
|
||||
import com.tangem.tap.features.wallet.ui.wallet.saltPay.rv.ShimmerRecyclerAdapter
|
||||
import com.tangem.tap.features.wallet.ui.wallet.saltPay.rv.TransactionHistoryAdapter
|
||||
import com.tangem.tap.features.wallet.ui.wallet.saltPay.rv.HistoryItemData
|
||||
import com.tangem.tap.features.wallet.ui.wallet.saltPay.rv.HistoryTransactionData
|
||||
import com.tangem.tap.features.wallet.ui.wallet.saltPay.rv.TxHistoryAdapter
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -85,7 +87,7 @@ class SaltPayWalletView : WalletView() {
|
|||
txWidget.rvTxHistoryShimmer.adapter = adapter
|
||||
txWidget.rvTxHistoryShimmer.addItemDecoration(SpaceItemDecoration.vertical(10F))
|
||||
|
||||
txWidget.rvTxHistory.adapter = TransactionHistoryAdapter()
|
||||
txWidget.rvTxHistory.adapter = TxHistoryAdapter()
|
||||
txWidget.rvTxHistory.addItemDecoration(SpaceItemDecoration.vertical(10F))
|
||||
|
||||
handleTxInit()
|
||||
|
|
@ -147,18 +149,31 @@ class SaltPayWalletView : WalletView() {
|
|||
// val walletAddress = "0xDA94Aae02a4Db0e09E1Cf240E3a0973ba89052cf"
|
||||
when (val result = walletManager.getTransactionHistory(walletAddress, wallet.blockchain, setOf(token))) {
|
||||
is Result.Success -> {
|
||||
val tokensHistory = result.data
|
||||
val dateAssociatedHistory = mutableMapOf<String, MutableList<HistoryTransactionData>>()
|
||||
|
||||
result.data
|
||||
.filter { it.contractAddress == token.contractAddress }
|
||||
.sortedBy { it.date?.timeInMillis ?: 0 }
|
||||
.map { HistoryTransactionData(it, walletAddress) }
|
||||
.sortedByDescending { it.date?.timeInMillis ?: 0 }
|
||||
.forEach {
|
||||
val txData = HistoryTransactionData(it, walletAddress)
|
||||
val list = dateAssociatedHistory[txData.date] ?: mutableListOf()
|
||||
list.add(txData)
|
||||
dateAssociatedHistory[txData.date] = list
|
||||
}
|
||||
|
||||
val dataList = mutableListOf<HistoryItemData>()
|
||||
dateAssociatedHistory.forEach { entry ->
|
||||
dataList.add(HistoryItemData.Date(entry.key))
|
||||
entry.value.forEach { dataList.add(HistoryItemData.TransactionData(it)) }
|
||||
}
|
||||
// .toMutableList().apply { clear() }
|
||||
|
||||
delay(300)
|
||||
withMainContext {
|
||||
if (tokensHistory.isEmpty()) {
|
||||
if (dataList.isEmpty()) {
|
||||
handleTxEmpty()
|
||||
} else {
|
||||
handleTxSuccess(tokensHistory)
|
||||
handleTxSuccess(dataList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -185,7 +200,7 @@ class SaltPayWalletView : WalletView() {
|
|||
txWidget.groupShimmer.show()
|
||||
}
|
||||
|
||||
private fun handleTxSuccess(dataList: List<HistoryTransactionData>) = with(txWidget) {
|
||||
private fun handleTxSuccess(dataList: List<HistoryItemData>) = with(txWidget) {
|
||||
groupShimmer.hide()
|
||||
groupEmpty.hide()
|
||||
groupError.hide()
|
||||
|
|
@ -212,7 +227,7 @@ class SaltPayWalletView : WalletView() {
|
|||
groupError.show()
|
||||
}
|
||||
|
||||
private fun updateTxHistoryWidget(dataList: List<HistoryTransactionData>) = with(txWidget) {
|
||||
(rvTxHistory.adapter as TransactionHistoryAdapter).submitList(dataList)
|
||||
private fun updateTxHistoryWidget(dataList: List<HistoryItemData>) = with(txWidget) {
|
||||
(rvTxHistory.adapter as TxHistoryAdapter).submitList(dataList)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet.saltPay.rv
|
||||
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionStatus
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.tap.common.extensions.toFormattedCurrencyString
|
||||
import com.tangem.tap.features.wallet.models.PendingTransactionType
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class HistoryItemData(
|
||||
val viewType: Int,
|
||||
val itemId: Long,
|
||||
) {
|
||||
data class Date(val date: String) : HistoryItemData(0, date.hashCode().toLong())
|
||||
data class TransactionData(val data: HistoryTransactionData) : HistoryItemData(1, data.hash.hashCode().toLong())
|
||||
}
|
||||
|
||||
data class HistoryTransactionData(
|
||||
private val transactionData: TransactionData,
|
||||
private val walletAddress: String,
|
||||
) {
|
||||
|
||||
val isInProgress: Boolean = transactionData.status == TransactionStatus.Unconfirmed
|
||||
|
||||
val transactionType: PendingTransactionType = when {
|
||||
transactionData.sourceAddress.lowercase() == walletAddress.lowercase() -> PendingTransactionType.Outgoing
|
||||
transactionData.destinationAddress.lowercase() == walletAddress.lowercase() -> PendingTransactionType.Incoming
|
||||
else -> PendingTransactionType.Unknown
|
||||
}
|
||||
|
||||
val hash: String = transactionData.hash?.let {
|
||||
"${it.substring(0..5)}...${it.substring(it.length - 4)}"
|
||||
} ?: ""
|
||||
|
||||
val time: String = transactionData.date?.let {
|
||||
SimpleDateFormat("hh:MM").format(it.time)
|
||||
} ?: "00:00"
|
||||
|
||||
val date: String = calculateDate()
|
||||
|
||||
val txSign: String = when (transactionType) {
|
||||
PendingTransactionType.Incoming -> "+"
|
||||
PendingTransactionType.Outgoing -> "-"
|
||||
PendingTransactionType.Unknown -> ""
|
||||
}
|
||||
|
||||
val amountValue: String = transactionData.amount.value
|
||||
?.toFormattedCurrencyString(8, transactionData.amount.currencySymbol) ?: "0"
|
||||
|
||||
private fun calculateDate(): String {
|
||||
val calendarTx = transactionData.date.guard { return "Unknown" }
|
||||
|
||||
val calendarNow = Calendar.getInstance()
|
||||
val oldDateFormatter = SimpleDateFormat("dd.MM.yyyy")
|
||||
|
||||
val date = if (calendarTx.get(Calendar.YEAR) == calendarNow.get(Calendar.YEAR)) {
|
||||
val dayOfYearTx = calendarTx.get(Calendar.DAY_OF_YEAR)
|
||||
val dayOfYearNow = calendarNow.get(Calendar.DAY_OF_YEAR)
|
||||
when {
|
||||
dayOfYearNow == dayOfYearTx -> "Today"
|
||||
dayOfYearNow - dayOfYearTx == 1 -> "Tomorrow"
|
||||
else -> oldDateFormatter.format(calendarTx.time)
|
||||
}
|
||||
} else {
|
||||
oldDateFormatter.format(calendarTx.time)
|
||||
}
|
||||
|
||||
return date
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet.saltPay.rv
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tangem.tap.common.extensions.getColor
|
||||
import com.tangem.tap.common.extensions.setDrawable
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.extensions.toFormattedCurrencyString
|
||||
import com.tangem.tap.features.wallet.models.PendingTransactionType
|
||||
import com.tangem.tap.features.wallet.ui.wallet.saltPay.HistoryTransactionData
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.ItemSaltPayTxHistoryBinding
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class TransactionHistoryAdapter : ListAdapter<HistoryTransactionData, TransactionItemVH>(DiffUtilCallback) {
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return if (currentList.isEmpty()) 0
|
||||
else currentList[position].transactionData.hash.hashCode().toLong()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionItemVH {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val layout = ItemSaltPayTxHistoryBinding.inflate(inflater, parent, false)
|
||||
return TransactionItemVH(layout)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TransactionItemVH, position: Int) {
|
||||
holder.bind(currentList[position])
|
||||
}
|
||||
|
||||
object DiffUtilCallback : DiffUtil.ItemCallback<HistoryTransactionData>() {
|
||||
override fun areContentsTheSame(
|
||||
oldItem: HistoryTransactionData,
|
||||
newItem: HistoryTransactionData,
|
||||
) = oldItem == newItem
|
||||
|
||||
override fun areItemsTheSame(
|
||||
oldItem: HistoryTransactionData,
|
||||
newItem: HistoryTransactionData,
|
||||
) = oldItem == newItem
|
||||
}
|
||||
}
|
||||
|
||||
internal class TransactionItemVH(
|
||||
private val binding: ItemSaltPayTxHistoryBinding,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(data: HistoryTransactionData) = with(binding) {
|
||||
setupImage(data)
|
||||
setupTitle(data)
|
||||
setupSubtitle(data)
|
||||
setupBalance(data)
|
||||
}
|
||||
|
||||
private fun setupImage(data: HistoryTransactionData) = with(binding) {
|
||||
val drawable = when (data.getTransactionType()) {
|
||||
PendingTransactionType.Incoming -> R.drawable.ic_tx_incoming
|
||||
PendingTransactionType.Outgoing -> R.drawable.ic_tx_outgoing
|
||||
PendingTransactionType.Unknown -> null
|
||||
}
|
||||
drawable?.let { imvTx.setDrawable(it) }
|
||||
|
||||
if (data.isInProgress()) {
|
||||
imvTx.setColorFilter(imvTx.getColor(R.color.icon_attention), PorterDuff.Mode.MULTIPLY)
|
||||
} else {
|
||||
imvTx.clearColorFilter()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupTitle(data: HistoryTransactionData) = with(binding) {
|
||||
val hash = data.transactionData.hash ?: return@with
|
||||
|
||||
val formattedHash = "${hash.substring(0..5)}...${hash.substring(hash.length - 4)}"
|
||||
tvTxHash.text = formattedHash
|
||||
}
|
||||
|
||||
private fun setupSubtitle(data: HistoryTransactionData) = with(binding) {
|
||||
val inProgress = data.isInProgress()
|
||||
tvTxStatus.show(inProgress)
|
||||
tvTxTime.show(!inProgress)
|
||||
|
||||
val time = data.transactionData.date?.timeInMillis.toString() ?: "none"
|
||||
tvTxTime.text = time
|
||||
}
|
||||
|
||||
private fun setupBalance(data: HistoryTransactionData) = with(binding) {
|
||||
val sign = when (data.getTransactionType()) {
|
||||
PendingTransactionType.Incoming -> "+"
|
||||
PendingTransactionType.Outgoing -> "-"
|
||||
PendingTransactionType.Unknown -> ""
|
||||
}
|
||||
val amount = data.transactionData.amount
|
||||
tvTxAmountSign.text = sign
|
||||
tvTxAmountValue.text = amount.value?.toFormattedCurrencyString(8, amount.currencySymbol)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet.saltPay.rv
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tangem.tap.common.extensions.getColor
|
||||
import com.tangem.tap.common.extensions.setDrawable
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.wallet.models.PendingTransactionType
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.ItemSaltPayTxHistoryBinding
|
||||
import com.tangem.wallet.databinding.ItemSaltPayTxHistoryDateBinding
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class TxHistoryAdapter : ListAdapter<HistoryItemData, BaseTxHistoryVH>(DiffUtilCallback) {
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return if (currentList.isEmpty()) 0L
|
||||
else currentList[position].itemId
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseTxHistoryVH {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
|
||||
return when (viewType) {
|
||||
0 -> {
|
||||
val layout = ItemSaltPayTxHistoryDateBinding.inflate(inflater, parent, false)
|
||||
DateItemVH(layout)
|
||||
}
|
||||
1 -> {
|
||||
val layout = ItemSaltPayTxHistoryBinding.inflate(inflater, parent, false)
|
||||
TransactionItemVH(layout)
|
||||
}
|
||||
else -> throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int = currentList[position].viewType
|
||||
|
||||
override fun onBindViewHolder(holder: BaseTxHistoryVH, position: Int) {
|
||||
holder.bind(currentList[position])
|
||||
}
|
||||
|
||||
private object DiffUtilCallback : DiffUtil.ItemCallback<HistoryItemData>() {
|
||||
override fun areContentsTheSame(oldItem: HistoryItemData, newItem: HistoryItemData) = oldItem == newItem
|
||||
override fun areItemsTheSame(oldItem: HistoryItemData, newItem: HistoryItemData) = oldItem == newItem
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class BaseTxHistoryVH(layout: View) : RecyclerView.ViewHolder(layout) {
|
||||
abstract fun bind(data: HistoryItemData)
|
||||
}
|
||||
|
||||
private class DateItemVH(
|
||||
private val binding: ItemSaltPayTxHistoryDateBinding,
|
||||
) : BaseTxHistoryVH(binding.root) {
|
||||
|
||||
override fun bind(data: HistoryItemData) = with(binding) {
|
||||
val vhData = (data as? HistoryItemData.Date)?.date ?: return
|
||||
|
||||
tvTitleDate.text = vhData
|
||||
}
|
||||
}
|
||||
|
||||
private class TransactionItemVH(
|
||||
private val binding: ItemSaltPayTxHistoryBinding,
|
||||
) : BaseTxHistoryVH(binding.root) {
|
||||
|
||||
override fun bind(data: HistoryItemData) {
|
||||
val vhData = (data as? HistoryItemData.TransactionData)?.data ?: return
|
||||
setupImage(vhData)
|
||||
setupTitle(vhData)
|
||||
setupSubtitle(vhData)
|
||||
setupBalance(vhData)
|
||||
}
|
||||
|
||||
private fun setupImage(data: HistoryTransactionData) = with(binding) {
|
||||
val drawable = when (data.transactionType) {
|
||||
PendingTransactionType.Incoming -> R.drawable.ic_tx_incoming
|
||||
PendingTransactionType.Outgoing -> R.drawable.ic_tx_outgoing
|
||||
PendingTransactionType.Unknown -> null
|
||||
}
|
||||
drawable?.let { imvTx.setDrawable(it) }
|
||||
|
||||
if (data.isInProgress) {
|
||||
imvTx.setColorFilter(imvTx.getColor(R.color.icon_attention), PorterDuff.Mode.SRC_ATOP)
|
||||
} else {
|
||||
imvTx.clearColorFilter()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupTitle(data: HistoryTransactionData) = with(binding) {
|
||||
tvTxHash.text = data.hash
|
||||
}
|
||||
|
||||
private fun setupSubtitle(data: HistoryTransactionData) = with(binding) {
|
||||
tvTxStatus.show(data.isInProgress)
|
||||
tvTxTime.show(!data.isInProgress)
|
||||
tvTxTime.text = data.time
|
||||
}
|
||||
|
||||
private fun setupBalance(data: HistoryTransactionData) = with(binding) {
|
||||
tvTxAmountSign.text = data.txSign
|
||||
tvTxAmountValue.text = data.amountValue
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue