From 306a9bb0ec861ee126114af373378970ed7f3cf5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 15 Feb 2023 17:14:00 +0300 Subject: [PATCH] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- .../java/com/tangem/tap/TapApplication.kt | 8 +- .../configurable/config/ConfigManager.kt | 5 + .../domain/configurable/config/JsonModels.kt | 7 + .../products/wallet/saltPay/SaltPayConfig.kt | 2 + .../tap/features/wallet/redux/WalletState.kt | 2 +- .../redux/middlewares/WalletMiddleware.kt | 2 + .../tap/features/wallet/ui/WalletFragment.kt | 13 +- .../wallet/ui/wallet/SaltPayWalletView.kt | 88 ------- .../features/wallet/ui/wallet/WalletView.kt | 10 + .../wallet/saltPay/HistoryTransactionData.kt | 21 ++ .../ui/wallet/saltPay/SaltPayWalletView.kt | 218 ++++++++++++++++++ .../saltPay/rv/ShimmerRecyclerAdapter.kt | 33 +++ .../saltPay/rv/TransactionHistoryAdapter.kt | 103 +++++++++ .../utorg/UtorgExchangeService.kt | 1 - app/src/main/res/drawable/ic_accept_coin.xml | 57 +++++ app/src/main/res/drawable/ic_tx_explore.xml | 9 + app/src/main/res/drawable/ic_tx_incoming.xml | 14 ++ app/src/main/res/drawable/ic_tx_outgoing.xml | 14 ++ .../res/layout/item_salt_pay_tx_history.xml | 89 +++++++ .../layout/item_salt_pay_tx_history_date.xml | 9 + .../item_salt_pay_tx_history_shimmer.xml | 60 +++++ .../res/layout/layout_salt_pay_balance.xml | 21 +- .../res/layout/layout_salt_pay_tx_history.xml | 136 +++++++++++ .../res/layout/layout_salt_pay_wallet.xml | 10 + buildSrc/src/main/java/Versions.kt | 4 +- 26 files changed, 828 insertions(+), 110 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SaltPayWalletView.kt create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/HistoryTransactionData.kt create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/rv/ShimmerRecyclerAdapter.kt create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/rv/TransactionHistoryAdapter.kt create mode 100644 app/src/main/res/drawable/ic_accept_coin.xml create mode 100644 app/src/main/res/drawable/ic_tx_explore.xml create mode 100644 app/src/main/res/drawable/ic_tx_incoming.xml create mode 100644 app/src/main/res/drawable/ic_tx_outgoing.xml create mode 100644 app/src/main/res/layout/item_salt_pay_tx_history.xml create mode 100644 app/src/main/res/layout/item_salt_pay_tx_history_date.xml create mode 100644 app/src/main/res/layout/item_salt_pay_tx_history_shimmer.xml create mode 100644 app/src/main/res/layout/layout_salt_pay_tx_history.xml diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 2b8aa19f58..f5f6ac9548 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 2b8aa19f58e17a78015629943d49df0da0b4fd4b +Subproject commit f5f6ac954894ef66331db8fe383b9773feb69ef4 diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 78cf3956f2..097ee1994f 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -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, diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt index 2b661de566..a45fc5c289 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt @@ -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, diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/JsonModels.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/JsonModels.kt index defa61e170..4de75aae58 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/JsonModels.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/JsonModels.kt @@ -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?, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt index 412087154d..9a0b4e1f64 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt @@ -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("", ""), ) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 1b2a47181a..7e37e27a5a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -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? diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index b49a33c1f1..f75992fe2b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -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) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 85de69de54..31f63630c1 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -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 { + 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(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)) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/WalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/WalletView.kt index d7d7cbb405..6bcdb961e5 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/WalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/WalletView.kt @@ -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) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/HistoryTransactionData.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/HistoryTransactionData.kt new file mode 100644 index 0000000000..50b80f0b37 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/HistoryTransactionData.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt new file mode 100644 index 0000000000..2a05484270 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/SaltPayWalletView.kt @@ -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(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) = 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) = with(txWidget) { + (rvTxHistory.adapter as TransactionHistoryAdapter).submitList(dataList) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/rv/ShimmerRecyclerAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/rv/ShimmerRecyclerAdapter.kt new file mode 100644 index 0000000000..fc59d49155 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/rv/ShimmerRecyclerAdapter.kt @@ -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(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() { + 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 = "") \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/rv/TransactionHistoryAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/rv/TransactionHistoryAdapter.kt new file mode 100644 index 0000000000..bc5f923aff --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/saltPay/rv/TransactionHistoryAdapter.kt @@ -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(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() { + 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) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/UtorgExchangeService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/UtorgExchangeService.kt index 21c8c48424..820751a14b 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/UtorgExchangeService.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/utorg/UtorgExchangeService.kt @@ -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 -> diff --git a/app/src/main/res/drawable/ic_accept_coin.xml b/app/src/main/res/drawable/ic_accept_coin.xml new file mode 100644 index 0000000000..6df78b4b77 --- /dev/null +++ b/app/src/main/res/drawable/ic_accept_coin.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_tx_explore.xml b/app/src/main/res/drawable/ic_tx_explore.xml new file mode 100644 index 0000000000..0c0c7403f5 --- /dev/null +++ b/app/src/main/res/drawable/ic_tx_explore.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tx_incoming.xml b/app/src/main/res/drawable/ic_tx_incoming.xml new file mode 100644 index 0000000000..1f8d16c0ff --- /dev/null +++ b/app/src/main/res/drawable/ic_tx_incoming.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_tx_outgoing.xml b/app/src/main/res/drawable/ic_tx_outgoing.xml new file mode 100644 index 0000000000..e6b391e594 --- /dev/null +++ b/app/src/main/res/drawable/ic_tx_outgoing.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/layout/item_salt_pay_tx_history.xml b/app/src/main/res/layout/item_salt_pay_tx_history.xml new file mode 100644 index 0000000000..bde605f95d --- /dev/null +++ b/app/src/main/res/layout/item_salt_pay_tx_history.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_salt_pay_tx_history_date.xml b/app/src/main/res/layout/item_salt_pay_tx_history_date.xml new file mode 100644 index 0000000000..8e45e44e0f --- /dev/null +++ b/app/src/main/res/layout/item_salt_pay_tx_history_date.xml @@ -0,0 +1,9 @@ + + diff --git a/app/src/main/res/layout/item_salt_pay_tx_history_shimmer.xml b/app/src/main/res/layout/item_salt_pay_tx_history_shimmer.xml new file mode 100644 index 0000000000..72aff47fa0 --- /dev/null +++ b/app/src/main/res/layout/item_salt_pay_tx_history_shimmer.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_salt_pay_balance.xml b/app/src/main/res/layout/layout_salt_pay_balance.xml index ff1772d79b..cdf2d00c6a 100644 --- a/app/src/main/res/layout/layout_salt_pay_balance.xml +++ b/app/src/main/res/layout/layout_salt_pay_balance.xml @@ -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 @@ @@ -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" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_salt_pay_wallet.xml b/app/src/main/res/layout/layout_salt_pay_wallet.xml index c27f1b8c8a..4712e76937 100644 --- a/app/src/main/res/layout/layout_salt_pay_wallet.xml +++ b/app/src/main/res/layout/layout_salt_pay_wallet.xml @@ -19,4 +19,14 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + diff --git a/buildSrc/src/main/java/Versions.kt b/buildSrc/src/main/java/Versions.kt index 3ea750baf4..3fd7975b23 100644 --- a/buildSrc/src/main/java/Versions.kt +++ b/buildSrc/src/main/java/Versions.kt @@ -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