Updated on 2026-08-14

This commit is contained in:
Tangem 2022-08-19 10:22:28 +03:00
commit c255d59373
19 changed files with 181 additions and 173 deletions

View file

@ -51,11 +51,10 @@ suspend fun WalletManager.safeUpdate(): Result<Wallet> = try {
fun WalletManager?.getToUpUrl(): String? {
val globalState = store.state.globalState
val exchangeManager = globalState.exchangeManager ?: return null
val wallet = this?.wallet ?: return null
val defaultAddress = wallet.address
return exchangeManager.getUrl(
return globalState.exchangeManager.getUrl(
action = CurrencyExchangeManager.Action.Buy,
blockchain = wallet.blockchain,
cryptoCurrencyName = wallet.blockchain.currency,

View file

@ -0,0 +1,8 @@
package com.tangem.tap.common.feature
/**
[REDACTED_AUTHOR]
*/
interface Feature {
fun featureIsSwitchedOn():Boolean
}

View file

@ -25,7 +25,7 @@ data class GlobalState(
val appCurrency: FiatCurrency = FiatCurrency.Default,
val scanCardFailsCounter: Int = 0,
val dialog: StateDialog? = null,
val exchangeManager: CurrencyExchangeManager? = null,
val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(),
val resources: AndroidResources = AndroidResources(),
val analyticsHandlers: AnalyticsHandler? = null,
val userCountryCode: String? = null,

View file

@ -26,7 +26,7 @@ data class OnboardingNoteState(
get() = steps.indexOf(currentStep)
val isBuyAllowed: Boolean by ReadOnlyProperty<Any, Boolean> { _, _ ->
store.state.globalState.exchangeManager?.availableForBuy(walletBalance.currency) ?: false
store.state.globalState.exchangeManager.availableForBuy(walletBalance.currency)
}
}

View file

@ -56,7 +56,7 @@ data class TwinCardsState(
get() = currentStep == TwinCardsStep.CreateSecondWallet || currentStep == TwinCardsStep.CreateThirdWallet
val isBuyAllowed: Boolean by ReadOnlyProperty<Any, Boolean> { _, _ ->
store.state.globalState.exchangeManager?.availableForBuy(walletBalance.currency) ?: false
store.state.globalState.exchangeManager.availableForBuy(walletBalance.currency)
}
}

View file

@ -7,9 +7,6 @@ import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.address.AddressType
import com.tangem.common.extensions.isZero
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.extensions.toCoinId
import com.tangem.domain.features.addCustomToken.CustomCurrency
import com.tangem.tap.common.entities.Button
import com.tangem.tap.common.extensions.toQrCode
import com.tangem.tap.common.redux.global.CryptoCurrencyName
@ -17,12 +14,18 @@ import com.tangem.tap.common.toggleWidget.WidgetState
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
import com.tangem.tap.features.wallet.models.*
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.PendingTransaction
import com.tangem.tap.features.wallet.models.TotalBalance
import com.tangem.tap.features.wallet.models.WalletRent
import com.tangem.tap.features.wallet.models.WalletWarning
import com.tangem.tap.features.wallet.models.hasPendingTransactions
import com.tangem.tap.features.wallet.models.hasSendableAmounts
import com.tangem.tap.features.wallet.models.isSendableAmount
import com.tangem.tap.features.wallet.redux.reducers.calculateTotalFiatAmount
import com.tangem.tap.features.wallet.redux.reducers.findProgressState
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
import com.tangem.tap.store
import org.rekotlin.StateType
import java.math.BigDecimal
@ -48,21 +51,15 @@ data class WalletState(
// if you do not delegate - the application crashes on startup,
// because twinCardsState has not been created yet
val twinCardsState: TwinCardsState by ReadOnlyProperty<Any, TwinCardsState> { thisRef, property ->
val twinCardsState: TwinCardsState by ReadOnlyProperty<Any, TwinCardsState> { _, _ ->
store.state.twinCardsState
}
val isTangemTwins: Boolean
get() = store.state.globalState.scanResponse?.isTangemTwins() == true
val primaryWallet: WalletData? = wallets.firstOrNull()
?.walletsData?.firstOrNull()
val primaryWalletManager: WalletManager? =
if (wallets.isNotEmpty()) wallets[0].walletManager else null
val shouldShowDetails: Boolean =
primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain
val isExchangeServiceFeatureOn: Boolean
get() = store.state.globalState.exchangeManager.featureIsSwitchedOn()
val blockchains: List<Blockchain>
get() = wallets.mapNotNull { it.walletManager?.wallet?.blockchain }
@ -76,6 +73,14 @@ data class WalletState(
val walletManagers: List<WalletManager>
get() = wallets.mapNotNull { it.walletManager }
val primaryWallet: WalletData? = wallets.firstOrNull()?.walletsData?.firstOrNull()
val primaryWalletManager: WalletManager? = if (wallets.isNotEmpty()) wallets[0].walletManager else null
val shouldShowDetails: Boolean =
primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain
fun getWalletManager(currency: Currency?): WalletManager? {
if (currency?.blockchain == null) return null
return getWalletStore(currency)?.walletManager
@ -248,32 +253,6 @@ data class WalletState(
return updatedWallets + remainingWallets
}
fun updateTradeCryptoState(
exchangeManager: CurrencyExchangeManager?,
walletData: WalletData
): WalletData {
return walletData.copy(
tradeCryptoState = TradeCryptoState.from(
exchangeManager,
walletData
)
)
}
fun updateTradeCryptoState(
exchangeManager: CurrencyExchangeManager?,
walletDataList: List<WalletData>
): List<WalletData> {
return walletDataList.map {
it.copy(
tradeCryptoState = TradeCryptoState.from(
exchangeManager,
it
)
)
}
}
private fun updateTotalBalance(): WalletState {
val walletsData = this.wallets
.flatMap(WalletStore::walletsData)
@ -352,39 +331,24 @@ data class Artwork(
}
}
data class TradeCryptoState(
val isAvailableToSell: () -> Boolean = { false },
val isAvailableToBuy: () -> Boolean = { false },
) {
companion object {
fun from(
exchangeManager: CurrencyExchangeManager?,
walletData: WalletData
): TradeCryptoState {
val exchanger = exchangeManager ?: return walletData.tradeCryptoState
val currency = walletData.currency
return TradeCryptoState(
isAvailableToSell = { exchanger.availableForSell(currency) },
isAvailableToBuy = { exchanger.availableForBuy(currency) },
)
}
}
}
data class WalletData(
val pendingTransactions: List<PendingTransaction> = emptyList(),
val hashesCountVerified: Boolean? = null,
val walletAddresses: WalletAddresses? = null,
val currencyData: BalanceWidgetData = BalanceWidgetData(),
val updatingWallet: Boolean = false,
val tradeCryptoState: TradeCryptoState = TradeCryptoState(),
val fiatRateString: String? = null,
val fiatRate: BigDecimal? = null,
val mainButton: WalletMainButton = WalletMainButton.SendButton(false),
val currency: Currency,
val walletRent: WalletRent? = null,
) {
val isAvailableToBuy: Boolean
get() = store.state.globalState.exchangeManager.availableForBuy(currency)
val isAvailableToSell: Boolean
get() = store.state.globalState.exchangeManager.availableForSell(currency)
fun shouldShowMultipleAddress(): Boolean {
val listOfAddresses = walletAddresses?.list ?: return false
return listOfAddresses.size > 1

View file

@ -37,20 +37,18 @@ class TradeCryptoMiddleware {
action: WalletAction.TradeCryptoAction.Buy,
) {
if (action.checkUserLocation && state()?.globalState?.userCountryCode == RUSSIA_COUNTRY_CODE) {
store.dispatchOnMain(
WalletAction.DialogAction.RussianCardholdersWarningDialog
)
store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog)
return
}
val selectedWalletData = store.state.walletState.getSelectedWalletData() ?: return
val exchangeManager = store.state.globalState.exchangeManager ?: return
val card = store.state.globalState.scanResponse?.card ?: return
val appCurrency = store.state.globalState.appCurrency
val addresses = selectedWalletData.walletAddresses?.list.orEmpty()
if (addresses.isEmpty()) return
val exchangeManager = store.state.globalState.exchangeManager
val appCurrency = store.state.globalState.appCurrency
val currency = selectedWalletData.currency
if (currency is Currency.Token && currency.blockchain.isTestnet()) {
@ -81,15 +79,13 @@ class TradeCryptoMiddleware {
private fun proceedSellAction() {
val selectedWalletData = store.state.walletState.getSelectedWalletData() ?: return
val exchangeManager = store.state.globalState.exchangeManager ?: return
val appCurrency = store.state.globalState.appCurrency
val appCurrency = store.state.globalState.appCurrency
val addresses = selectedWalletData.walletAddresses?.list.orEmpty()
if (addresses.isEmpty()) return
val currency = selectedWalletData.currency
exchangeManager.getUrl(
store.state.globalState.exchangeManager.getUrl(
action = CurrencyExchangeManager.Action.Sell,
blockchain = currency.blockchain,
cryptoCurrencyName = currency.currencySymbol,
@ -100,8 +96,8 @@ class TradeCryptoMiddleware {
private fun preconfigureAndOpenSendScreen(action: WalletAction.TradeCryptoAction.SendCrypto) {
val selectedWalletData = store.state.walletState.getSelectedWalletData() ?: return
val walletManager =
store.state.walletState.getWalletManager(selectedWalletData.currency)
val walletManager = store.state.walletState.getWalletManager(selectedWalletData.currency)
store.dispatchOnMain(PrepareSendScreen(
coinAmount = walletManager?.wallet?.amounts?.get(AmountType.Coin),
coinRate = selectedWalletData.fiatRate,
@ -116,11 +112,10 @@ class TradeCryptoMiddleware {
}
private fun openReceiptUrl(transactionId: String) {
val exchangeManager = store.state.globalState.exchangeManager ?: return
store.dispatchOnMain(NavigationAction.PopBackTo())
exchangeManager.getSellCryptoReceiptUrl(CurrencyExchangeManager.Action.Sell, transactionId)?.let {
store.dispatchOnMain(NavigationAction.OpenUrl(it))
}
store.state.globalState.exchangeManager.getSellCryptoReceiptUrl(
action = CurrencyExchangeManager.Action.Sell,
transactionId = transactionId,
)?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) }
}
}

View file

@ -13,7 +13,9 @@ import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.filterByToken
import com.tangem.tap.features.wallet.models.getPendingTransactions
import com.tangem.tap.features.wallet.models.removeUnknownTransactions
import com.tangem.tap.features.wallet.redux.*
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletMainButton
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
@ -38,8 +40,6 @@ class OnWalletLoadedReducer {
val walletData = walletState.getWalletData(blockchainNetwork) ?: return walletState
val fiatCurrency = store.state.globalState.appCurrency
val exchangeManager = store.state.globalState.exchangeManager
val coinAmountValue = wallet.amounts[AmountType.Coin]?.value
val formattedAmount = coinAmountValue?.toFormattedCurrencyString(
wallet.blockchain.decimals(),
@ -71,7 +71,6 @@ class OnWalletLoadedReducer {
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
mainButton = WalletMainButton.SendButton(isCoinSendButtonEnabled),
currency = Currency.fromBlockchainNetwork(blockchainNetwork),
tradeCryptoState = TradeCryptoState.from(exchangeManager, walletData),
)
val tokens = wallet.getTokens().mapNotNull { token ->
@ -104,7 +103,6 @@ class OnWalletLoadedReducer {
),
pendingTransactions = tokenPendingTransactions.removeUnknownTransactions(),
mainButton = WalletMainButton.SendButton(isTokenSendButtonEnabled),
tradeCryptoState = TradeCryptoState.from(exchangeManager, tokenWalletData),
)
}
val newWallets = tokens + newWalletData
@ -118,8 +116,6 @@ class OnWalletLoadedReducer {
if (wallet.blockchain != walletState.primaryBlockchain) return walletState
val fiatCurrencyName = store.state.globalState.appCurrency.code
val exchangeManager = store.state.globalState.exchangeManager
val token = wallet.getFirstToken()
val tokenData = if (token != null) {
val tokenAmount = wallet.getTokenAmount(token)
@ -167,7 +163,6 @@ class OnWalletLoadedReducer {
),
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
mainButton = WalletMainButton.SendButton(sendButtonEnabled),
tradeCryptoState = TradeCryptoState.from(exchangeManager, walletState.primaryWallet),
)
val wallets = listOfNotNull(walletData)
val updatedStore = walletState.getWalletStore(walletData?.currency)?.updateWallets(wallets)

View file

@ -6,7 +6,11 @@ import com.tangem.blockchain.common.Wallet
import com.tangem.common.extensions.mapNotNullValues
import com.tangem.domain.common.TwinCardNumber
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.extensions.toFiatRateString
import com.tangem.tap.common.extensions.toFiatString
import com.tangem.tap.common.extensions.toFiatValue
import com.tangem.tap.common.extensions.toFormattedCurrencyString
import com.tangem.tap.common.extensions.toFormattedFiatValue
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.extensions.getArtworkUrl
@ -14,10 +18,18 @@ import com.tangem.tap.domain.getFirstToken
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.WalletRent
import com.tangem.tap.features.wallet.redux.*
import com.tangem.tap.features.wallet.redux.AddressData
import com.tangem.tap.features.wallet.redux.Artwork
import com.tangem.tap.features.wallet.redux.ErrorType
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletAddresses
import com.tangem.tap.features.wallet.redux.WalletData
import com.tangem.tap.features.wallet.redux.WalletMainButton
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.redux.WalletStore
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
import com.tangem.tap.store
import org.rekotlin.Action
import java.math.BigDecimal
@ -35,7 +47,6 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
if (action !is WalletAction) return state.walletState
val exchangeManager = store.state.globalState.exchangeManager
var newState = state.walletState
when (action) {
@ -144,10 +155,6 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
currencySymbol = walletData.currencyData.currencySymbol,
),
mainButton = WalletMainButton.SendButton(false),
tradeCryptoState = TradeCryptoState.from(
exchangeManager,
walletData
)
)
}
)
@ -171,13 +178,9 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
currencySymbol = wallet.currencyData.currencySymbol,
),
mainButton = WalletMainButton.SendButton(false),
tradeCryptoState = TradeCryptoState.from(exchangeManager, wallet)
)
}
val wallets = newState.updateTradeCryptoState(
exchangeManager,
newState.replaceSomeWallets(newWallets)
)
val wallets = newState.replaceSomeWallets(newWallets)
val walletStore = newState.getWalletStore(action.blockchain)?.updateWallets(wallets)
newState = newState.updateWalletStore(walletStore)
}
@ -210,14 +213,9 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
)
)
}
var updatedWalletStore = newState.getWalletStore(action.blockchain)
val updatedWalletStore = newState.getWalletStore(action.blockchain)
?.updateWallets(listOfNotNull(walletData))
updatedWalletStore =
updatedWalletStore?.updateWallets(
newState.updateTradeCryptoState(exchangeManager, updatedWalletStore.walletsData)
)
newState = newState.updateWalletStore(updatedWalletStore)
}
@ -248,11 +246,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
)
)
}
val updatedWallets =
newState.updateTradeCryptoState(
exchangeManager,
walletStore!!.updateWallets(listOfNotNull(newWalletData) + tokenWallets).walletsData
)
val updatedWallets = walletStore!!.updateWallets(listOfNotNull(newWalletData) + tokenWallets).walletsData
newState = newState.updateWalletsData(updatedWallets)

View file

@ -140,7 +140,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
setupAddressCard(selectedWallet)
setupNoInternetHandling(state)
setupBalanceData(selectedWallet.currencyData)
setupButtons(selectedWallet)
setupButtons(selectedWallet, state.isExchangeServiceFeatureOn)
handleCurrencyIcon(selectedWallet)
handleWarnings(selectedWallet)
@ -186,7 +186,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
)
}
private fun setupButtons(selectedWallet: WalletData) = with(binding) {
private fun setupButtons(selectedWallet: WalletData, isExchangeServiceFeatureOn: Boolean) = with(binding) {
lWalletDetails.btnCopy.setOnClickListener {
selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString ->
store.dispatch(WalletAction.CopyAddress(addressString, requireContext()))
@ -199,8 +199,9 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
}
rowButtons.updateButtonsVisibility(
buyAllowed = selectedWallet.tradeCryptoState.isAvailableToBuy(),
sellAllowed = selectedWallet.tradeCryptoState.isAvailableToSell(),
exchangeServiceFeatureOn = isExchangeServiceFeatureOn,
buyAllowed = selectedWallet.isAvailableToBuy,
sellAllowed = selectedWallet.isAvailableToSell,
sendAllowed = selectedWallet.mainButton.enabled,
)
}

View file

@ -35,14 +35,21 @@ internal class WalletDetailsButtonsRow @JvmOverloads constructor(
}
fun updateButtonsVisibility(
exchangeServiceFeatureOn: Boolean,
buyAllowed: Boolean,
sellAllowed: Boolean,
sendAllowed: Boolean,
) = with(binding) {
btnBuy.isVisible = (buyAllowed && !sellAllowed) || (!buyAllowed && !sellAllowed)
btnBuy.isEnabled = buyAllowed
btnSell.isVisible = !buyAllowed && sellAllowed
btnTrade.isVisible = buyAllowed && sellAllowed
if (exchangeServiceFeatureOn) {
btnBuy.isVisible = (buyAllowed && !sellAllowed) || (!buyAllowed && !sellAllowed)
btnBuy.isEnabled = buyAllowed
btnSell.isVisible = !buyAllowed && sellAllowed
btnTrade.isVisible = buyAllowed && sellAllowed
} else {
btnBuy.isVisible = false
btnSell.isVisible = false
btnTrade.isVisible = false
}
btnSend.isEnabled = sendAllowed
}
}

View file

@ -58,7 +58,7 @@ class SingleWalletView : WalletView() {
state.primaryWallet ?: return
setupTwinCards(state.twinCardsState, binding)
setupButtons(state.primaryWallet, binding)
setupButtons(state.primaryWallet, binding, state.isExchangeServiceFeatureOn)
setupAddressCard(state.primaryWallet, binding)
showPendingTransactionsIfPresent(state.primaryWallet.pendingTransactions)
setupBalance(state, state.primaryWallet)
@ -97,18 +97,23 @@ class SingleWalletView : WalletView() {
}
}
private fun setupButtons(state: WalletData, binding: FragmentWalletBinding) = with(binding) {
setupRowButtons(state, rowButtons)
private fun setupButtons(
walletData: WalletData,
binding: FragmentWalletBinding,
isExchangeServiceFeatureEnabled: Boolean,
) = with(binding) {
setupRowButtons(walletData, rowButtons, isExchangeServiceFeatureEnabled)
lAddress.btnCopy.setOnClickListener {
state.walletAddresses?.selectedAddress?.address?.let { addressString ->
walletData.walletAddresses?.selectedAddress?.address?.let { addressString ->
store.dispatch(WalletAction.CopyAddress(addressString, fragment!!.requireContext()))
}
}
lAddress.btnShowQr.setOnClickListener {
state.walletAddresses?.selectedAddress?.let { selectedAddress ->
walletData.walletAddresses?.selectedAddress?.let { selectedAddress ->
store.dispatch(
WalletAction.DialogAction.QrCode(
currency = state.currency,
currency = walletData.currency,
selectedAddress = selectedAddress,
),
)
@ -116,13 +121,16 @@ class SingleWalletView : WalletView() {
}
}
private fun setupRowButtons(state: WalletData, rowButtons: WalletDetailsButtonsRow) {
val allowedToBuy = state.tradeCryptoState.isAvailableToBuy()
val allowedToSell = state.tradeCryptoState.isAvailableToSell()
private fun setupRowButtons(
walletData: WalletData,
rowButtons: WalletDetailsButtonsRow,
isExchangeServiceFeatureEnabled: Boolean,
) {
rowButtons.updateButtonsVisibility(
buyAllowed = allowedToBuy,
sellAllowed = allowedToSell,
sendAllowed = state.mainButton.enabled,
exchangeServiceFeatureOn = isExchangeServiceFeatureEnabled,
buyAllowed = walletData.isAvailableToBuy,
sellAllowed = walletData.isAvailableToSell,
sendAllowed = walletData.mainButton.enabled,
)
rowButtons.onBuyClick = { store.dispatch(WalletAction.TradeCryptoAction.Buy()) }
@ -130,7 +138,7 @@ class SingleWalletView : WalletView() {
rowButtons.onTradeClick = { store.dispatch(WalletAction.DialogAction.ChooseTradeActionDialog) }
rowButtons.onSendClick = {
when (state.mainButton) {
when (walletData.mainButton) {
is WalletMainButton.SendButton -> store.dispatch(WalletAction.Send())
is WalletMainButton.CreateWalletButton -> store.dispatch(WalletAction.CreateWallet)
}

View file

@ -12,11 +12,17 @@ class CardExchangeRules(
val cardProvider: () -> Card?,
) : ExchangeRules {
override fun featureIsSwitchedOn(): Boolean {
val card = cardProvider() ?: return false
return !card.isStart2Coin
}
override fun isBuyAllowed(): Boolean {
val card = cardProvider() ?: return false
return when {
card.isDemoCard() -> false
card.isDemoCard() -> true
card.isStart2Coin -> false
else -> true
}
@ -36,7 +42,7 @@ class CardExchangeRules(
val card = cardProvider() ?: return false
return when {
card.isDemoCard() -> false
card.isDemoCard() -> true
card.isStart2Coin -> false
else -> true
}

View file

@ -26,6 +26,8 @@ class CurrencyExchangeManager(
private val primaryRules: ExchangeRules,
) : ExchangeService, ExchangeUrlBuilder {
override fun featureIsSwitchedOn(): Boolean = primaryRules.featureIsSwitchedOn()
override suspend fun update() {
buyService.update()
sellService.update()
@ -74,6 +76,14 @@ class CurrencyExchangeManager(
}
enum class Action { Buy, Sell }
companion object {
fun dummy(): CurrencyExchangeManager = CurrencyExchangeManager(
buyService = ExchangeService.dummy(),
sellService = ExchangeService.dummy(),
primaryRules = ExchangeRules.dummy(),
)
}
}
suspend fun CurrencyExchangeManager.buyErc20TestnetTokens(

View file

@ -1,19 +1,44 @@
package com.tangem.tap.network.exchangeServices
import com.tangem.blockchain.common.Blockchain
import com.tangem.tap.common.feature.Feature
import com.tangem.tap.features.wallet.models.Currency
interface ExchangeService: ExchangeRules {
suspend fun update()
}
interface ExchangeRules {
interface Exchanger {
fun isBuyAllowed(): Boolean
fun isSellAllowed(): Boolean
fun availableForBuy(currency: Currency):Boolean
fun availableForSell(currency: Currency):Boolean
}
interface ExchangeService: Feature, Exchanger {
suspend fun update()
companion object {
fun dummy(): ExchangeService = object : ExchangeService {
override fun featureIsSwitchedOn(): Boolean = false
override suspend fun update() {}
override fun isBuyAllowed(): Boolean = false
override fun isSellAllowed(): Boolean = false
override fun availableForBuy(currency: Currency): Boolean = false
override fun availableForSell(currency: Currency): Boolean = false
}
}
}
interface ExchangeRules: Feature, Exchanger {
companion object {
fun dummy(): ExchangeRules = object : ExchangeRules {
override fun featureIsSwitchedOn(): Boolean = false
override fun isBuyAllowed(): Boolean = false
override fun isSellAllowed(): Boolean = false
override fun availableForBuy(currency: Currency): Boolean = false
override fun availableForSell(currency: Currency): Boolean = false
}
}
}
interface ExchangeUrlBuilder {
fun getUrl(
action: CurrencyExchangeManager.Action,

View file

@ -4,15 +4,6 @@ import com.squareup.moshi.Json
import retrofit2.http.GET
import retrofit2.http.Path
/**
[REDACTED_AUTHOR]
*/
private val CurrenciesUrl = "https://api.mercuryo.io/v1.6/lib/currencies"
interface MercuryoApi {

View file

@ -28,6 +28,8 @@ class MercuryoService(
private val blockchainsAvailableToBuy = mutableListOf<Blockchain>()
private val tokensAvailableToBy = mutableMapOf<String, MutableList<Blockchain>>()
override fun featureIsSwitchedOn(): Boolean = true
override suspend fun update() {
when (val result = performRequest { api.currencies(apiVersion) }) {
is Result.Success -> {
@ -130,6 +132,7 @@ class MercuryoService(
private fun blockchainFromCurrencyName(currencyName: String): Blockchain? = when (currencyName) {
"BNB" -> Blockchain.BSC
"ETH" -> Blockchain.Ethereum
"ADA" -> Blockchain.CardanoShelley
else -> Blockchain.values().find { it.currency.lowercase() == currencyName.lowercase() }
}
}

View file

@ -29,6 +29,8 @@ class MoonPayService(
private var status: MoonPayStatus? = null
override fun featureIsSwitchedOn(): Boolean = true
override suspend fun update() {
withIOContext {
performRequest {

View file

@ -47,7 +47,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingBottom="32dp">
android:paddingBottom="92dp">
<ImageView
android:id="@+id/iv_card"
@ -93,6 +93,17 @@
app:barrierDirection="bottom"
app:constraint_referenced_ids="iv_card,tv_twin_card_number" />
<include
android:id="@+id/l_wallet_backup_warning"
layout="@layout/layout_wallet_backup_warning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/rv_warning_messages" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_warning_messages"
android:layout_width="match_parent"
@ -105,17 +116,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier" />
<include
android:id="@+id/l_wallet_backup_warning"
layout="@layout/layout_wallet_backup_warning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/rv_warning_messages" />
<include
android:id="@+id/l_card_total_balance"
layout="@layout/layout_card_total_balance"
@ -176,16 +176,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" />
<com.tangem.tap.features.wallet.ui.view.WalletDetailsButtonsRow
android:id="@+id/row_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_add_token"
style="@style/BaseTapButton"
@ -207,4 +197,14 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.tangem.tap.features.wallet.ui.view.WalletDetailsButtonsRow
android:id="@+id/row_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="32dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>