Updated on 2026-08-14
This commit is contained in:
parent
b23c147a22
commit
306a9bb0ec
26 changed files with 828 additions and 110 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 2b8aa19f58e17a78015629943d49df0da0b4fd4b
|
||||
Subproject commit f5f6ac954894ef66331db8fe383b9773feb69ef4
|
||||
|
|
@ -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 ->
|
||||
|
|
|
|||
57
app/src/main/res/drawable/ic_accept_coin.xml
Normal file
57
app/src/main/res/drawable/ic_accept_coin.xml
Normal file
File diff suppressed because one or more lines are too long
9
app/src/main/res/drawable/ic_tx_explore.xml
Normal file
9
app/src/main/res/drawable/ic_tx_explore.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:pathData="M4.833,13.167L7.5,7.5L13.167,4.833L10.5,10.5L4.833,13.167ZM9,8.25C8.801,8.25 8.61,8.329 8.47,8.47C8.329,8.61 8.25,8.801 8.25,9C8.25,9.199 8.329,9.39 8.47,9.53C8.61,9.671 8.801,9.75 9,9.75C9.199,9.75 9.39,9.671 9.53,9.53C9.671,9.39 9.75,9.199 9.75,9C9.75,8.801 9.671,8.61 9.53,8.47C9.39,8.329 9.199,8.25 9,8.25ZM9,0.667C10.094,0.667 11.178,0.882 12.189,1.301C13.2,1.72 14.119,2.334 14.892,3.107C15.666,3.881 16.28,4.8 16.699,5.811C17.118,6.822 17.333,7.906 17.333,9C17.333,11.21 16.455,13.33 14.892,14.892C13.33,16.455 11.21,17.333 9,17.333C7.906,17.333 6.822,17.118 5.811,16.699C4.8,16.28 3.881,15.666 3.107,14.892C1.545,13.33 0.667,11.21 0.667,9C0.667,6.79 1.545,4.67 3.107,3.107C4.67,1.545 6.79,0.667 9,0.667ZM9,2.333C7.232,2.333 5.536,3.036 4.286,4.286C3.036,5.536 2.333,7.232 2.333,9C2.333,10.768 3.036,12.464 4.286,13.714C5.536,14.964 7.232,15.667 9,15.667C10.768,15.667 12.464,14.964 13.714,13.714C14.964,12.464 15.667,10.768 15.667,9C15.667,7.232 14.964,5.536 13.714,4.286C12.464,3.036 10.768,2.333 9,2.333Z"
|
||||
android:fillColor="#B0B0B0"/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_tx_incoming.xml
Normal file
14
app/src/main/res/drawable/ic_tx_incoming.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0"
|
||||
android:strokeAlpha="0.12"
|
||||
android:fillColor="#B0B0B0"
|
||||
android:fillAlpha="0.12"/>
|
||||
<path
|
||||
android:pathData="M19.08,12.08L21.08,12.08V24.08L26.58,18.58L28,20L20.08,27.92L12.16,20L13.58,18.58L19.08,24.08L19.08,12.08Z"
|
||||
android:fillColor="#C9C9C9"/>
|
||||
</vector>
|
||||
14
app/src/main/res/drawable/ic_tx_outgoing.xml
Normal file
14
app/src/main/res/drawable/ic_tx_outgoing.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0"
|
||||
android:strokeAlpha="0.12"
|
||||
android:fillColor="#B0B0B0"
|
||||
android:fillAlpha="0.12"/>
|
||||
<path
|
||||
android:pathData="M21.08,27.92H19.08L19.08,15.92L13.58,21.42L12.16,20L20.08,12.08L28,20L26.58,21.42L21.08,15.92V27.92Z"
|
||||
android:fillColor="#C9C9C9"/>
|
||||
</vector>
|
||||
89
app/src/main/res/layout/item_salt_pay_tx_history.xml
Normal file
89
app/src/main/res/layout/item_salt_pay_tx_history.xml
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/imv_tx"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@drawable/ic_tx_incoming" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tx_hash"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="68dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:letterSpacing="0.01"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/text_primary_1"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tv_tx_amount_sign"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="33BdfSkjandfjkajksjjkgkajsbga2B" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tx_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:letterSpacing="0.03"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_tx_hash"
|
||||
tools:text="12:43" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tx_status"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:ellipsize="end"
|
||||
android:letterSpacing="0.03"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/text_attention"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tv_tx_amount_sign"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_tx_hash"
|
||||
tools:text="In progress..." />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tx_amount_sign"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:letterSpacing="0.02"
|
||||
android:textColor="@color/text_primary_1"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/tv_tx_amount_value"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tv_tx_amount_value"
|
||||
app:layout_constraintTop_toTopOf="@+id/tv_tx_amount_value"
|
||||
tools:text="+" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tx_amount_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:letterSpacing="0.02"
|
||||
android:textColor="@color/text_primary_1"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="443" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/tv_title_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:letterSpacing="0.02"
|
||||
android:textColor="@color/text_tertiary"
|
||||
tools:text="Today" />
|
||||
60
app/src/main/res/layout/item_salt_pay_tx_history_shimmer.xml
Normal file
60
app/src/main/res/layout/item_salt_pay_tx_history_shimmer.xml
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.skydoves.androidveil.VeilLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:veilLayout_baseColor="@color/lightGray0"
|
||||
app:veilLayout_highlightColor="@color/lightGray1"
|
||||
app:veilLayout_radius="4dp"
|
||||
app:veilLayout_shimmerEnable="true"
|
||||
app:veilLayout_veiled="true"
|
||||
tools:veilLayout_veiled="false">
|
||||
|
||||
<!--android:background="@drawable/rectangle_twin_background"-->
|
||||
<!--android:backgroundTint="@color/text_attention"-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/imv_tx"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/tv_tx_hash"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="68dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tv_tx_amount"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/tv_tx_time"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_tx_hash" />
|
||||
|
||||
<View
|
||||
android:id="@+id/tv_tx_amount"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.skydoves.androidveil.VeilLayout>
|
||||
|
|
@ -21,12 +21,10 @@
|
|||
android:id="@+id/tv_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/onboarding_balance_title"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_currency_name"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
|
@ -34,8 +32,8 @@
|
|||
android:id="@+id/veil_balance"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_processing"
|
||||
android:layout_marginTop="6dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_unreachable"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_title"
|
||||
|
|
@ -65,7 +63,7 @@
|
|||
android:id="@+id/veil_balance_crypto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginTop="6dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/veil_balance"
|
||||
app:veilLayout_baseColor="@color/lightGray0"
|
||||
|
|
@ -81,7 +79,6 @@
|
|||
android:id="@+id/tv_balance_crypto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="2dp"
|
||||
android:maxLines="1"
|
||||
android:minWidth="152dp"
|
||||
android:textColor="@color/text_tertiary"
|
||||
|
|
@ -92,14 +89,14 @@
|
|||
</com.skydoves.androidveil.VeilLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_processing"
|
||||
android:id="@+id/tv_unreachable"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/wallet_balance_blockchain_unreachable"
|
||||
android:textColor="@color/warning"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/veil_balance" />
|
||||
|
||||
|
|
@ -108,7 +105,7 @@
|
|||
style="@style/BaseSaltPayButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="76dp"
|
||||
android:text="@string/wallet_button_buy"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_add"
|
||||
|
|
@ -116,7 +113,7 @@
|
|||
app:iconTint="@color/selector_saltpay_btn_text"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/veil_balance_crypto"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_title"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
|
|
|
|||
136
app/src/main/res/layout/layout_salt_pay_tx_history.xml
Normal file
136
app/src/main/res/layout/layout_salt_pay_tx_history.xml
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/card_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="12dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:clipToPadding="false"
|
||||
android:minHeight="272dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_tx_history_shimmer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="42dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:listitem="@layout/item_salt_pay_tx_history_shimmer" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title_tx"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:letterSpacing="0.01"
|
||||
android:text="Transactions"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title_explore"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:drawableLeft="@drawable/ic_tx_explore"
|
||||
android:drawablePadding="4dp"
|
||||
android:letterSpacing="0.01"
|
||||
android:text="Explore"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/imv_tx_list_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tv_tx_list_empty"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:srcCompat="@drawable/ic_accept_coin" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tx_list_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="You don't have any transactions yet"
|
||||
android:textColor="@color/text_tertiary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imv_tx_list_empty" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tx_list_error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="Failed to load transactions"
|
||||
android:textColor="@color/text_tertiary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_tx_history"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="42dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:listitem="@layout/item_salt_pay_tx_history" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group_shimmer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:constraint_referenced_ids="rv_tx_history_shimmer" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:constraint_referenced_ids="imv_tx_list_empty, tv_tx_list_empty" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group_error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:constraint_referenced_ids="tv_tx_list_error" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group_success"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:constraint_referenced_ids="rv_tx_history" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
@ -19,4 +19,14 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<include
|
||||
android:id="@+id/l_salt_pay_tx_history"
|
||||
layout="@layout/layout_salt_pay_tx_history"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/l_salt_pay_balance" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ object Versions {
|
|||
// endregion Other libraries
|
||||
|
||||
// region Tangem
|
||||
const val tangemBlockchainSdk = "develop-152-hotfix-4.0.1-156"
|
||||
// const val tangemBlockchainSdk = "0.0.1"
|
||||
// const val tangemBlockchainSdk = "develop-152-hotfix-4.0.1-156"
|
||||
const val tangemBlockchainSdk = "0.0.1"
|
||||
|
||||
const val tangemCardSdk = "develop-179-hotfix-4.0.1-189"
|
||||
// endregion Tangem
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue