Updated on 2026-08-14
This commit is contained in:
parent
b23c147a22
commit
306a9bb0ec
26 changed files with 828 additions and 110 deletions
|
|
@ -57,6 +57,7 @@ import com.tangem.tap.persistence.PreferencesStorage
|
|||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import org.rekotlin.Store
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
|
@ -146,7 +147,12 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
initConfigManager(configLoader, ::initWithConfigDependency)
|
||||
initWarningMessagesManager()
|
||||
|
||||
BlockchainSdkRetrofitBuilder.enableNetworkLogging = LogConfig.network.blockchainSdkNetwork
|
||||
if (LogConfig.network.blockchainSdkNetwork) {
|
||||
BlockchainSdkRetrofitBuilder.interceptors = listOf(
|
||||
HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY },
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
userTokensRepository = UserTokensRepository.init(
|
||||
context = this,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.domain.configurable.config
|
|||
|
||||
import com.tangem.blockchain.common.BlockchainSdkConfig
|
||||
import com.tangem.blockchain.common.BlockchairCredentials
|
||||
import com.tangem.blockchain.common.BlockscoutCredentials
|
||||
import com.tangem.blockchain.common.GetBlockCredentials
|
||||
import com.tangem.blockchain.common.NowNodeCredentials
|
||||
import com.tangem.blockchain.common.QuickNodeCredentials
|
||||
|
|
@ -93,6 +94,10 @@ class ConfigManager {
|
|||
authToken = values.blockchairAuthorizationToken,
|
||||
),
|
||||
blockcypherTokens = values.blockcypherTokens,
|
||||
blockscoutCredentials = BlockscoutCredentials(
|
||||
userName = values.saltPay.blockscoutCredentials.user,
|
||||
password = values.saltPay.blockscoutCredentials.password,
|
||||
),
|
||||
quickNodeSolanaCredentials = QuickNodeCredentials(
|
||||
apiKey = values.quiknodeApiKey,
|
||||
subdomain = values.quiknodeSubdomain,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class FeatureModel(
|
|||
val isCreatingTwinCardsAllowed: Boolean,
|
||||
)
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
class ConfigValueModel(
|
||||
val coinMarketCapKey: String,
|
||||
val mercuryoWidgetId: String,
|
||||
|
|
@ -37,6 +38,7 @@ class ConfigValueModel(
|
|||
val saltPay: SaltPayConfig,
|
||||
val tronGridApiKey: String,
|
||||
val amplitudeApiKey: String,
|
||||
val swapReferrerAccount: SwapReferrerAccount?,
|
||||
)
|
||||
|
||||
data class AppsFlyer(
|
||||
|
|
@ -44,6 +46,11 @@ data class AppsFlyer(
|
|||
val appsFlyerAppID: String,
|
||||
)
|
||||
|
||||
data class SwapReferrerAccount(
|
||||
val address: String,
|
||||
val fee: String,
|
||||
)
|
||||
|
||||
class ConfigModel(
|
||||
val features: FeatureModel?,
|
||||
val configValues: ConfigValueModel?,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ data class SaltPayConfig(
|
|||
val sprinklrAppID: String,
|
||||
val kycProvider: KYCProvider,
|
||||
val credentials: Credentials,
|
||||
val blockscoutCredentials: Credentials,
|
||||
) {
|
||||
companion object {
|
||||
fun stub(): SaltPayConfig {
|
||||
|
|
@ -16,6 +17,7 @@ data class SaltPayConfig(
|
|||
sprinklrAppID = "",
|
||||
kycProvider = KYCProvider("", "", "", ""),
|
||||
credentials = Credentials("", ""),
|
||||
blockscoutCredentials = Credentials("", ""),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ data class WalletState(
|
|||
get() = if (isMultiwalletAllowed || walletsStores.isEmpty() || walletsStores.size > 1) null
|
||||
else walletsStores[0]
|
||||
|
||||
private val primaryWalletManager: WalletManager?
|
||||
val primaryWalletManager: WalletManager?
|
||||
get() = primaryWalletStore?.walletManager
|
||||
|
||||
val primaryWalletData: WalletData?
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ class WalletMiddleware {
|
|||
}
|
||||
is NetworkStateChanged -> {
|
||||
store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline)
|
||||
if (!action.isOnline) return
|
||||
|
||||
val selectedUserWallet = userWalletsListManagerSafe?.selectedUserWalletSync
|
||||
if (selectedUserWallet != null) {
|
||||
scope.launch { globalState.tapWalletManager.loadData(selectedUserWallet) }
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ import com.tangem.tap.features.wallet.redux.WalletAction
|
|||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter
|
||||
import com.tangem.tap.features.wallet.ui.wallet.MultiWalletView
|
||||
import com.tangem.tap.features.wallet.ui.wallet.SaltPayWalletView
|
||||
import com.tangem.tap.features.wallet.ui.wallet.SingleWalletView
|
||||
import com.tangem.tap.features.wallet.ui.wallet.WalletView
|
||||
import com.tangem.tap.features.wallet.ui.wallet.saltPay.SaltPayWalletView
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import com.tangem.wallet.BuildConfig
|
||||
|
|
@ -150,15 +150,18 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
|
||||
when {
|
||||
isSaltPay && (walletView !is SaltPayWalletView) -> {
|
||||
walletView.onViewDestroy()
|
||||
walletView = SaltPayWalletView()
|
||||
walletView.changeWalletView(this, binding)
|
||||
}
|
||||
state.isMultiwalletAllowed && state.primaryWalletData?.currencyData?.status != BalanceStatus.EmptyCard &&
|
||||
walletView !is MultiWalletView -> {
|
||||
walletView.onViewDestroy()
|
||||
walletView = MultiWalletView()
|
||||
walletView.changeWalletView(this, binding)
|
||||
}
|
||||
!state.isMultiwalletAllowed && !isSaltPay && walletView !is SingleWalletView -> {
|
||||
walletView.onViewDestroy()
|
||||
walletView = SingleWalletView()
|
||||
walletView.changeWalletView(this, binding)
|
||||
}
|
||||
|
|
@ -174,7 +177,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
}
|
||||
|
||||
setupNoInternetHandling(state)
|
||||
setupCardImage(state)
|
||||
setupCardImage(state, isSaltPay)
|
||||
|
||||
if (!isSaltPay) showWarningsIfPresent(state.mainWarningsList)
|
||||
|
||||
|
|
@ -183,6 +186,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
if (state.state != ProgressState.Loading &&
|
||||
state.state != ProgressState.Refreshing
|
||||
) {
|
||||
//TODO: blueprint
|
||||
walletView.pullToRefreshListener?.invoke()
|
||||
Analytics.send(Portfolio.Refreshed())
|
||||
store.dispatch(WalletAction.LoadData.Refresh)
|
||||
}
|
||||
|
|
@ -211,9 +216,9 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupCardImage(state: WalletState) {
|
||||
private fun setupCardImage(state: WalletState, isSaltPay: Boolean) {
|
||||
//TODO: SaltPay: remove hardCode
|
||||
if (store.state.globalState.scanResponse?.isSaltPay() == true) {
|
||||
if (isSaltPay) {
|
||||
binding.ivCard.load(R.drawable.img_salt_pay_visa) {
|
||||
scale(Scale.FIT)
|
||||
crossfade(enable = true)
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet
|
||||
|
||||
import com.tangem.domain.common.extensions.debounce
|
||||
import com.tangem.tap.common.extensions.animateVisibility
|
||||
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
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.mainScope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
import com.tangem.wallet.databinding.LayoutSaltPayWalletBinding
|
||||
import org.rekotlin.Action
|
||||
|
||||
class SaltPayWalletView : WalletView() {
|
||||
|
||||
private lateinit var saltPayBinding: LayoutSaltPayWalletBinding
|
||||
private val actionDebouncer = debounce<Action>(500, mainScope) { store.dispatch(it) }
|
||||
|
||||
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
saltPayBinding = binding.lSaltPayWallet
|
||||
setFragment(fragment, binding)
|
||||
onViewCreated()
|
||||
showSaltPayView(binding)
|
||||
}
|
||||
|
||||
private fun showSaltPayView(binding: FragmentWalletBinding) = with(binding) {
|
||||
rvWarningMessages.hide()
|
||||
rvPendingTransaction.hide()
|
||||
rvMultiwallet.hide()
|
||||
tvTwinCardNumber.hide()
|
||||
lCardBalance.root.hide()
|
||||
lSingleWalletBalance.root.hide()
|
||||
lAddress.root.hide()
|
||||
rowButtons.hide()
|
||||
btnAddToken.hide()
|
||||
pbLoadingUserTokens.hide()
|
||||
lSaltPayWallet.root.show()
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
}
|
||||
|
||||
override fun onNewState(state: WalletState) {
|
||||
setupBalanceWidget(state)
|
||||
}
|
||||
|
||||
private fun setupBalanceWidget(state: WalletState) = with(saltPayBinding.lSaltPayBalance) {
|
||||
val tokenData = state.primaryTokenData ?: return@with
|
||||
|
||||
val appCurrency = store.state.globalState.appCurrency
|
||||
val mainProgressState = state.state
|
||||
|
||||
if (mainProgressState == ProgressState.Loading) {
|
||||
veilBalance.veil()
|
||||
veilBalanceCrypto.veil()
|
||||
} else {
|
||||
veilBalanceCrypto.unVeil()
|
||||
}
|
||||
|
||||
tvProcessing.animateVisibility(show = mainProgressState == ProgressState.Error)
|
||||
veilBalanceCrypto.animateVisibility(show = mainProgressState != ProgressState.Error)
|
||||
|
||||
if (tokenData.currencyData.fiatAmount == null) {
|
||||
actionDebouncer(WalletAction.LoadFiatRate())
|
||||
} else {
|
||||
veilBalance.unVeil()
|
||||
tvBalance.text = tokenData.currencyData.fiatAmount.formatAmountAsSpannedString(
|
||||
currencySymbol = appCurrency.symbol,
|
||||
)
|
||||
}
|
||||
|
||||
tvBalanceCrypto.text = tokenData.currencyData.amountFormatted
|
||||
|
||||
tvCurrencyName.text = appCurrency.code
|
||||
tvCurrencyName.setOnClickListener {
|
||||
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
|
||||
}
|
||||
|
||||
btnBuy.show(tokenData.isAvailableToBuy)
|
||||
btnBuy.setOnClickListener {
|
||||
store.dispatch(WalletAction.TradeCryptoAction.Buy(false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,13 @@ import com.tangem.tap.features.wallet.ui.WalletFragment
|
|||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
|
||||
abstract class WalletView {
|
||||
|
||||
//TODO: blueprint
|
||||
var pullToRefreshListener: (() -> Unit)? = null
|
||||
|
||||
protected var fragment: WalletFragment? = null
|
||||
protected var binding: FragmentWalletBinding? = null
|
||||
|
||||
fun setFragment(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
this.fragment = fragment
|
||||
this.binding = binding
|
||||
|
|
@ -17,6 +22,11 @@ abstract class WalletView {
|
|||
binding = null
|
||||
}
|
||||
|
||||
//TODO: blueprint
|
||||
open fun onViewDestroy() {
|
||||
pullToRefreshListener = null
|
||||
}
|
||||
|
||||
open fun onDestroyFragment() {}
|
||||
|
||||
abstract fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet.saltPay
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
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.extensions.animateVisibility
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
||||
import com.tangem.tap.domain.getFirstToken
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
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.mainScope
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
import com.tangem.wallet.databinding.ItemSaltPayTxHistoryShimmerBinding
|
||||
import com.tangem.wallet.databinding.LayoutSaltPayBalanceBinding
|
||||
import com.tangem.wallet.databinding.LayoutSaltPayTxHistoryBinding
|
||||
import com.tangem.wallet.databinding.LayoutSaltPayWalletBinding
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class SaltPayWalletView : WalletView() {
|
||||
|
||||
private lateinit var saltPayBinding: LayoutSaltPayWalletBinding
|
||||
private val actionDebouncer = debounce<Action>(500, mainScope) { store.dispatch(it) }
|
||||
|
||||
private val balanceWidget: LayoutSaltPayBalanceBinding
|
||||
get() = saltPayBinding.lSaltPayBalance
|
||||
|
||||
private val txWidget: LayoutSaltPayTxHistoryBinding
|
||||
get() = saltPayBinding.lSaltPayTxHistory
|
||||
|
||||
private var initialized = AtomicBoolean(false)
|
||||
|
||||
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
saltPayBinding = binding.lSaltPayWallet
|
||||
setFragment(fragment, binding)
|
||||
onViewCreated()
|
||||
showSaltPayView(binding)
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
this.pullToRefreshListener = this::handlePullToRefresh
|
||||
prepareTxRecyclers()
|
||||
}
|
||||
|
||||
private fun showSaltPayView(binding: FragmentWalletBinding) = with(binding) {
|
||||
rvWarningMessages.hide()
|
||||
rvPendingTransaction.hide()
|
||||
rvMultiwallet.hide()
|
||||
tvTwinCardNumber.hide()
|
||||
lCardBalance.root.hide()
|
||||
lSingleWalletBalance.root.hide()
|
||||
lAddress.root.hide()
|
||||
rowButtons.hide()
|
||||
btnAddToken.hide()
|
||||
pbLoadingUserTokens.hide()
|
||||
lSaltPayWallet.root.show()
|
||||
}
|
||||
|
||||
private fun prepareTxRecyclers() {
|
||||
val vhViewFactory: (ViewGroup) -> ViewGroup = {
|
||||
val inflater = LayoutInflater.from(it.context)
|
||||
ItemSaltPayTxHistoryShimmerBinding.inflate(inflater, it, false).root
|
||||
}
|
||||
val adapter = ShimmerRecyclerAdapter(vhViewFactory)
|
||||
txWidget.rvTxHistoryShimmer.adapter = adapter
|
||||
txWidget.rvTxHistoryShimmer.addItemDecoration(SpaceItemDecoration.vertical(10F))
|
||||
|
||||
txWidget.rvTxHistory.adapter = TransactionHistoryAdapter()
|
||||
txWidget.rvTxHistory.addItemDecoration(SpaceItemDecoration.vertical(10F))
|
||||
|
||||
handleTxInit()
|
||||
}
|
||||
|
||||
private fun handlePullToRefresh() {
|
||||
requestTxHistory(store.state.walletState)
|
||||
}
|
||||
|
||||
override fun onNewState(state: WalletState) {
|
||||
if (!initialized.getAndSet(true)) requestTxHistory(state)
|
||||
setupBalanceWidget(state)
|
||||
}
|
||||
|
||||
private fun setupBalanceWidget(state: WalletState) = with(balanceWidget) {
|
||||
val tokenData = state.primaryTokenData ?: return@with
|
||||
|
||||
val appCurrency = store.state.globalState.appCurrency
|
||||
val mainProgressState = state.state
|
||||
|
||||
if (mainProgressState == ProgressState.Loading) {
|
||||
veilBalance.veil()
|
||||
veilBalanceCrypto.veil()
|
||||
} else {
|
||||
veilBalanceCrypto.unVeil()
|
||||
}
|
||||
|
||||
tvUnreachable.animateVisibility(show = mainProgressState == ProgressState.Error)
|
||||
veilBalanceCrypto.animateVisibility(show = mainProgressState != ProgressState.Error)
|
||||
|
||||
if (tokenData.currencyData.fiatAmount == null) {
|
||||
actionDebouncer(WalletAction.LoadFiatRate())
|
||||
} else {
|
||||
veilBalance.unVeil()
|
||||
tvBalance.text = tokenData.currencyData.fiatAmount.formatAmountAsSpannedString(
|
||||
currencySymbol = appCurrency.symbol,
|
||||
)
|
||||
}
|
||||
|
||||
tvBalanceCrypto.text = tokenData.currencyData.amountFormatted
|
||||
|
||||
tvCurrencyName.text = appCurrency.code
|
||||
tvCurrencyName.setOnClickListener {
|
||||
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
|
||||
}
|
||||
|
||||
btnBuy.show(tokenData.isAvailableToBuy)
|
||||
btnBuy.setOnClickListener {
|
||||
store.dispatch(WalletAction.TradeCryptoAction.Buy(false))
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestTxHistory(state: WalletState) {
|
||||
scope.launch {
|
||||
val walletManager = state.primaryWalletManager as? EthereumWalletManager ?: return@launch
|
||||
val wallet = walletManager.wallet
|
||||
val token = wallet.getFirstToken() ?: return@launch
|
||||
// val walletAddress = wallet.address
|
||||
val walletAddress = "0xDA94Aae02a4Db0e09E1Cf240E3a0973ba89052cf"
|
||||
when (val result = walletManager.getTransactionHistory(walletAddress, wallet.blockchain, setOf(token))) {
|
||||
is Result.Success -> {
|
||||
val tokensHistory = result.data
|
||||
.filter { it.contractAddress == token.contractAddress }
|
||||
.sortedBy { it.date?.timeInMillis ?: 0 }
|
||||
.map { HistoryTransactionData(it, walletAddress) }
|
||||
// .toMutableList().apply { clear() }
|
||||
|
||||
delay(300)
|
||||
withMainContext {
|
||||
if (tokensHistory.isEmpty()) {
|
||||
handleTxEmpty()
|
||||
} else {
|
||||
handleTxSuccess(tokensHistory)
|
||||
}
|
||||
}
|
||||
}
|
||||
is Result.Failure -> {
|
||||
delay(300)
|
||||
withMainContext { handleTxError() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleTxInit() = with(txWidget) {
|
||||
(rvTxHistoryShimmer.adapter as? ShimmerRecyclerAdapter)?.submitList(
|
||||
listOf(
|
||||
ShimmerData(),
|
||||
ShimmerData(),
|
||||
ShimmerData(),
|
||||
),
|
||||
)
|
||||
groupEmpty.hide()
|
||||
groupError.hide()
|
||||
groupSuccess.hide()
|
||||
root.beginDelayedTransition()
|
||||
txWidget.groupShimmer.show()
|
||||
}
|
||||
|
||||
private fun handleTxSuccess(dataList: List<HistoryTransactionData>) = with(txWidget) {
|
||||
groupShimmer.hide()
|
||||
groupEmpty.hide()
|
||||
groupError.hide()
|
||||
root.beginDelayedTransition()
|
||||
updateTxHistoryWidget(dataList)
|
||||
groupSuccess.show()
|
||||
}
|
||||
|
||||
private fun handleTxEmpty() = with(txWidget) {
|
||||
groupShimmer.hide()
|
||||
groupError.hide()
|
||||
groupSuccess.hide()
|
||||
root.beginDelayedTransition()
|
||||
updateTxHistoryWidget(emptyList())
|
||||
groupEmpty.show()
|
||||
}
|
||||
|
||||
private fun handleTxError() = with(txWidget) {
|
||||
groupShimmer.hide()
|
||||
groupEmpty.hide()
|
||||
groupSuccess.hide()
|
||||
root.beginDelayedTransition()
|
||||
updateTxHistoryWidget(emptyList())
|
||||
groupError.show()
|
||||
}
|
||||
|
||||
private fun updateTxHistoryWidget(dataList: List<HistoryTransactionData>) = with(txWidget) {
|
||||
(rvTxHistory.adapter as TransactionHistoryAdapter).submitList(dataList)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet.saltPay.rv
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
open class ShimmerRecyclerAdapter(
|
||||
private val viewHolderViewFactory: (ViewGroup) -> ViewGroup,
|
||||
) : ListAdapter<ShimmerData, ShimmerVH>(DiffUtilCallback) {
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return if (currentList.isEmpty()) 0 else currentList[position].hashCode().toLong()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ShimmerVH {
|
||||
return ShimmerVH(viewHolderViewFactory.invoke(parent))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ShimmerVH, position: Int) {}
|
||||
|
||||
object DiffUtilCallback : DiffUtil.ItemCallback<ShimmerData>() {
|
||||
override fun areContentsTheSame(oldItem: ShimmerData, newItem: ShimmerData) = oldItem == newItem
|
||||
override fun areItemsTheSame(oldItem: ShimmerData, newItem: ShimmerData) = oldItem == newItem
|
||||
}
|
||||
}
|
||||
|
||||
class ShimmerVH(viewGroup: ViewGroup) : RecyclerView.ViewHolder(viewGroup)
|
||||
|
||||
data class ShimmerData(private val any: String = "")
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -53,7 +53,6 @@ class UtorgExchangeService(
|
|||
override fun isSellAllowed(): Boolean = false
|
||||
|
||||
override fun availableForBuy(currency: Currency): Boolean {
|
||||
return true
|
||||
if (!isBuyAllowed()) return false
|
||||
|
||||
val foundUtorgCurrency = utorgCurrencies.firstOrNull { utorgCurrency ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue