Updated on 2026-08-14

This commit is contained in:
Tangem 2022-12-29 19:41:26 +04:00
parent 1474d83756
commit 04d22aa092
26 changed files with 201 additions and 55 deletions

View file

@ -133,7 +133,7 @@ class DialogManager : StoreSubscriber<GlobalState> {
is SaltPayDialog.Activation.NoGas -> NoFundsForActivationDialog.create(context)
is SaltPayDialog.Activation.OnError -> RegistrationErrorDialog.create(context, state.dialog)
is WalletDialog.CurrencySelectionDialog -> CurrencySelectionDialog.create(state.dialog, context)
is WalletDialog.ChooseTradeActionDialog -> ChooseTradeActionBottomSheetDialog(context)
is WalletDialog.ChooseTradeActionDialog -> ChooseTradeActionBottomSheetDialog(context, state.dialog)
is WalletDialog.SelectAmountToSendDialog -> AmountToSendBottomSheetDialog(context, state.dialog)
is WalletDialog.SignedHashesMultiWalletDialog -> SignedHashesWarningDialog.create(context)
is WalletDialog.TokensAreLinkedDialog -> SimpleAlertDialog.create(

View file

@ -1,5 +1,6 @@
package com.tangem.tap.common.extensions
import android.os.Bundle
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
@ -7,6 +8,7 @@ import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import com.tangem.common.extensions.VoidCallback
import com.tangem.feature.referral.ReferralFragment
import com.tangem.feature.swap.presentation.SwapFragment
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment
@ -37,10 +39,12 @@ import timber.log.Timber
fun FragmentActivity.openFragment(
screen: AppScreen,
addToBackstack: Boolean,
bundle: Bundle? = null,
fgShareTransition: FragmentShareTransition? = null,
) {
val transaction = this.supportFragmentManager.beginTransaction()
val fragment = fragmentFactory(screen)
fragment.arguments = bundle
fgShareTransition?.apply {
fragment.sharedElementEnterTransition = enterTransitionSet
fragment.sharedElementReturnTransition = exitTransitionSet
@ -117,6 +121,7 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.WalletConnectSessions -> WalletConnectFragment()
AppScreen.QrScan -> QrScanFragment()
AppScreen.ReferralProgram -> ReferralFragment()
AppScreen.Swap -> SwapFragment()
AppScreen.Welcome -> WelcomeFragment()
AppScreen.SaveWallet -> SaveWalletBottomSheetFragment()
AppScreen.WalletSelector -> WalletSelectorBottomSheetFragment()

View file

@ -1,6 +1,7 @@
package com.tangem.tap.common.redux.navigation
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.rekotlin.Action
import java.lang.ref.WeakReference
@ -10,6 +11,7 @@ sealed class NavigationAction : Action {
val screen: AppScreen,
val fragmentShareTransition: FragmentShareTransition? = null,
val addToBackstack: Boolean = true,
val bundle: Bundle? = null,
) : NavigationAction()
data class PopBackTo(

View file

@ -23,6 +23,7 @@ enum class AppScreen(
WalletConnectSessions,
QrScan,
ReferralProgram,
Swap,
Welcome,
SaveWallet(isDialogFragment = true),
WalletSelector(isDialogFragment = true),

View file

@ -161,7 +161,12 @@ sealed class WalletAction : Action {
) : DialogAction()
object SignedHashesMultiWalletDialog : DialogAction()
object ChooseTradeActionDialog : DialogAction()
data class ChooseTradeActionDialog(
val buyAllowed: Boolean,
val sellAllowed: Boolean,
val swapAllowed: Boolean,
) : DialogAction()
data class ChooseCurrency(val amounts: List<Amount>?) : DialogAction()
data class RussianCardholdersWarningDialog(
val dialogData: WalletDialog.RussianCardholdersWarningDialog.Data? = null,
@ -190,6 +195,8 @@ sealed class WalletAction : Action {
val destinationAddress: String,
val transactionId: String,
) : TradeCryptoAction()
object Swap : TradeCryptoAction()
}
data class ChangeSelectedAddress(val type: AddressType) : WalletAction()

View file

@ -329,6 +329,9 @@ data class WalletData(
val isAvailableToSell: Boolean
get() = store.state.globalState.exchangeManager.availableForSell(currency)
val isAvailableToSwap: Boolean
get() = currency.blockchain.isEvm() && currency.coinId != null
fun shouldShowMultipleAddress(): Boolean {
val listOfAddresses = walletAddresses?.list ?: return false
return listOfAddresses.size > 1

View file

@ -1,7 +1,10 @@
package com.tangem.tap.features.wallet.redux.middlewares
import androidx.core.os.bundleOf
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.common.AmountType
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.feature.swap.presentation.SwapFragment
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Token
@ -11,6 +14,7 @@ import com.tangem.tap.common.extensions.dispatchOpenUrl
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.tokens.getIconUrl
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.features.send.redux.PrepareSendScreen
@ -22,6 +26,9 @@ import com.tangem.tap.network.exchangeServices.buyErc20TestnetTokens
import com.tangem.tap.scope
import com.tangem.tap.store
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import com.tangem.feature.swap.domain.models.data.Currency as SwapCurrency
class TradeCryptoMiddleware {
fun handle(state: () -> AppState?, action: WalletAction.TradeCryptoAction) {
@ -32,6 +39,7 @@ class TradeCryptoMiddleware {
is WalletAction.TradeCryptoAction.Sell -> proceedSellAction()
is WalletAction.TradeCryptoAction.SendCrypto -> preconfigureAndOpenSendScreen(action)
is WalletAction.TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId)
is WalletAction.TradeCryptoAction.Swap -> openSwap()
}
}
@ -136,4 +144,33 @@ class TradeCryptoMiddleware {
transactionId = transactionId,
)?.let { store.dispatchOpenUrl(it) }
}
private fun openSwap() {
val currency = store.state.walletState.selectedWalletData?.currency?.toSwapCurrency()
val bundle = bundleOf(SwapFragment.CURRENCY_BUNDLE_KEY to Json.encodeToString(currency))
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Swap, bundle = bundle))
}
private fun Currency.toSwapCurrency(): SwapCurrency {
return when (this) {
is Currency.Blockchain -> {
SwapCurrency.NativeToken(
id = blockchain.id,
name = this.currencyName,
symbol = this.currencySymbol,
networkId = this.blockchain.toNetworkId(),
logoUrl = getIconUrl(this.blockchain.toNetworkId()),
)
}
is Currency.Token -> SwapCurrency.NonNativeToken(
id = this.token.id ?: "",
name = this.currencyName,
symbol = this.currencySymbol,
networkId = this.blockchain.toNetworkId(),
logoUrl = getIconUrl(this.token.id ?: ""),
contractAddress = this.token.contractAddress,
decimalCount = decimals,
)
}
}
}

View file

@ -20,7 +20,13 @@ class WalletDialogsMiddleware {
store.state.walletState.selectedWalletData?.let {
Analytics.send(Token.ButtonExchange(AnalyticsParam.CurrencyType.Currency(it.currency)))
}
store.dispatchDialogShow(WalletDialog.ChooseTradeActionDialog)
store.dispatchDialogShow(
WalletDialog.ChooseTradeActionDialog(
buyAllowed = action.buyAllowed,
sellAllowed = action.sellAllowed,
swapAllowed = action.swapAllowed,
),
)
}
is WalletAction.DialogAction.QrCode -> {
store.dispatchDialogShow(

View file

@ -9,7 +9,12 @@ import com.tangem.wallet.R
sealed interface WalletDialog : StateDialog {
data class SelectAmountToSendDialog(val amounts: List<Amount>?) : WalletDialog
object SignedHashesMultiWalletDialog : WalletDialog
object ChooseTradeActionDialog : WalletDialog
data class ChooseTradeActionDialog(
val buyAllowed: Boolean,
val sellAllowed: Boolean,
val swapAllowed: Boolean,
) : WalletDialog
data class CurrencySelectionDialog(
val currenciesList: List<FiatCurrency>,
val currentAppCurrency: FiatCurrency,
@ -17,7 +22,7 @@ sealed interface WalletDialog : StateDialog {
data class RemoveWalletDialog(
val currencyTitle: String,
val onOk: () -> Unit
val onOk: () -> Unit,
) : WalletDialog {
val messageRes: Int = R.string.token_details_hide_alert_message
val titleRes: Int = R.string.token_details_hide_alert_title
@ -26,7 +31,7 @@ sealed interface WalletDialog : StateDialog {
data class TokensAreLinkedDialog(
val currencyTitle: String,
val currencySymbol: String
val currencySymbol: String,
) : WalletDialog {
val messageRes: Int = R.string.token_details_unable_hide_alert_message
val titleRes: Int = R.string.token_details_unable_hide_alert_title

View file

@ -165,15 +165,6 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
}
private fun setupButtons() = with(binding) {
rowButtons.onBuyClick = {
store.dispatch(WalletAction.TradeCryptoAction.Buy())
}
rowButtons.onSellClick = {
store.dispatch(WalletAction.TradeCryptoAction.Sell)
}
rowButtons.onTradeClick = {
store.dispatch(WalletAction.DialogAction.ChooseTradeActionDialog)
}
rowButtons.onSendClick = {
store.dispatch(WalletAction.Send())
}
@ -273,6 +264,15 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
sellAllowed = selectedWallet.isAvailableToSell,
sendAllowed = selectedWallet.mainButton.enabled,
)
rowButtons.onTradeClick = {
store.dispatch(
WalletAction.DialogAction.ChooseTradeActionDialog(
buyAllowed = selectedWallet.isAvailableToBuy,
sellAllowed = selectedWallet.isAvailableToSell,
swapAllowed = selectedWallet.isAvailableToSwap,
),
)
}
}
private fun handleWarnings(selectedWallet: WalletData) = with(binding) {

View file

@ -4,11 +4,16 @@ import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.tangem.tap.common.extensions.show
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.store
import com.tangem.wallet.databinding.DialogWalletTradeBinding
class ChooseTradeActionBottomSheetDialog(context: Context) : BottomSheetDialog(context) {
class ChooseTradeActionBottomSheetDialog(
context: Context,
private val dialogData: WalletDialog.ChooseTradeActionDialog,
) : BottomSheetDialog(context) {
var binding: DialogWalletTradeBinding? = null
@ -26,13 +31,26 @@ class ChooseTradeActionBottomSheetDialog(context: Context) : BottomSheetDialog(c
store.dispatch(WalletAction.DialogAction.Hide)
}
binding!!.dialogBtnBuy.setOnClickListener {
dismiss()
store.dispatch(WalletAction.TradeCryptoAction.Buy())
}
binding!!.dialogBtnSell.setOnClickListener {
dismiss()
store.dispatch(WalletAction.TradeCryptoAction.Sell)
binding?.let {
with(it)
{
dialogBtnBuy.show(dialogData.buyAllowed)
dialogBtnSell.show(dialogData.sellAllowed)
dialogBtnSwap.show(dialogData.swapAllowed)
dialogBtnBuy.setOnClickListener {
dismiss()
store.dispatch(WalletAction.TradeCryptoAction.Buy())
}
dialogBtnSell.setOnClickListener {
dismiss()
store.dispatch(WalletAction.TradeCryptoAction.Sell)
}
dialogBtnSwap.setOnClickListener {
dismiss()
store.dispatch(WalletAction.TradeCryptoAction.Swap)
}
}
}
}
}

View file

@ -5,6 +5,7 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import androidx.core.view.isVisible
import com.tangem.tap.common.extensions.hide
import com.tangem.wallet.databinding.ViewWalletDetailsButtonsRowBinding
internal class WalletDetailsButtonsRow @JvmOverloads constructor(
@ -39,11 +40,9 @@ internal class WalletDetailsButtonsRow @JvmOverloads constructor(
sendAllowed: Boolean,
) = with(binding) {
containerExchangeButtons.isVisible = exchangeServiceFeatureOn
btnBuy.isVisible = (buyAllowed && !sellAllowed) || (!buyAllowed && !sellAllowed)
btnBuy.isEnabled = buyAllowed
btnSell.isVisible = !buyAllowed && sellAllowed
btnTrade.isVisible = buyAllowed && sellAllowed
btnBuy.hide()
btnSell.hide()
btnTrade.isVisible = exchangeServiceFeatureOn
btnSend.isEnabled = sendAllowed
}
}

View file

@ -134,9 +134,15 @@ class SingleWalletView : WalletView() {
sendAllowed = walletData.mainButton.enabled,
)
rowButtons.onBuyClick = { store.dispatch(WalletAction.TradeCryptoAction.Buy()) }
rowButtons.onSendClick = { store.dispatch(WalletAction.TradeCryptoAction.Sell) }
rowButtons.onTradeClick = { store.dispatch(WalletAction.DialogAction.ChooseTradeActionDialog) }
rowButtons.onTradeClick = {
store.dispatch(
WalletAction.DialogAction.ChooseTradeActionDialog(
buyAllowed = walletData.isAvailableToBuy,
sellAllowed = walletData.isAvailableToSell,
swapAllowed = walletData.isAvailableToSwap,
),
)
}
rowButtons.onSendClick = {
when (walletData.mainButton) {