Updated on 2026-08-14
This commit is contained in:
parent
99b4c180cc
commit
1a4e8d8f20
11 changed files with 142 additions and 102 deletions
|
|
@ -22,6 +22,10 @@ sealed class TapError(
|
|||
|
||||
object UnknownError : TapError(R.string.send_error_unknown)
|
||||
open class CustomError(val customMessage: String) : TapError(R.string.common_custom_string, listOf(customMessage))
|
||||
data class UnsupportedState(
|
||||
val stateError: String,
|
||||
) : TapError(R.string.common_custom_string, listOf("Unsupported state: $stateError"))
|
||||
|
||||
object ScanCardError : TapError(R.string.scan_card_error)
|
||||
object UnknownBlockchain : TapError(R.string.wallet_error_unsupported_blockchain_subtitle)
|
||||
object NoInternetConnection : TapError(R.string.wallet_notification_no_internet)
|
||||
|
|
@ -38,11 +42,6 @@ sealed class TapError(
|
|||
data class DustAmount(override val args: List<Any>) : TapError(R.string.send_error_dust_amount_format)
|
||||
object DustChange : TapError(R.string.send_error_dust_change)
|
||||
|
||||
data class UnsupportedState(
|
||||
val stateError: String,
|
||||
val customMessage: String = "Unsupported state:",
|
||||
) : TapError(R.string.common_custom_string, listOf("$customMessage $stateError"))
|
||||
|
||||
sealed class WalletManager {
|
||||
object CreationError : CustomError("Can't create wallet manager")
|
||||
class NoAccountError(amountToCreateAccount: String) : CustomError(amountToCreateAccount)
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ data class WalletDataModel(
|
|||
|
||||
data class Unreachable(
|
||||
override val errorMessage: String?,
|
||||
override val amount: BigDecimal = BigDecimal.ZERO,
|
||||
) : Status() {
|
||||
override val isErrorStatus: Boolean = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,10 @@ internal fun List<WalletDataModel>.updateWithMissedDerivation(): List<WalletData
|
|||
internal fun List<WalletDataModel>.updateWithUnreachable(): List<WalletDataModel> {
|
||||
return this.map { walletData ->
|
||||
walletData.copy(
|
||||
status = WalletDataModel.Unreachable(errorMessage = null),
|
||||
status = WalletDataModel.Unreachable(
|
||||
errorMessage = null,
|
||||
amount = walletData.status.amount,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ interface SendScreenActionUi : SendScreenAction
|
|||
object ReleaseSendState : Action
|
||||
|
||||
data class PrepareSendScreen(
|
||||
val walletManager: WalletManager,
|
||||
val coinAmount: Amount?,
|
||||
val coinRate: BigDecimal?,
|
||||
val walletManager: WalletManager?,
|
||||
val tokenAmount: Amount? = null,
|
||||
val tokenRate: BigDecimal? = null,
|
||||
) : SendScreenAction
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ private class EmptyReducer : SendInternalReducer {
|
|||
private class PrepareSendScreenStatesReducer : SendInternalReducer {
|
||||
override fun handle(action: SendScreenAction, sendState: SendState): SendState {
|
||||
val prepareAction = action as PrepareSendScreen
|
||||
val walletManager = action.walletManager!!
|
||||
val walletManager = action.walletManager
|
||||
val amountToExtract = prepareAction.tokenAmount ?: prepareAction.coinAmount!!
|
||||
val decimals = amountToExtract.decimals
|
||||
val feePaidInNetworkCurrency = isFeePaidInNetworkCurrency(walletManager.wallet.blockchain)
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ sealed class WalletAction : Action {
|
|||
val swapAllowed: Boolean,
|
||||
) : DialogAction()
|
||||
|
||||
data class ChooseCurrency(val amounts: List<Amount>?) : DialogAction()
|
||||
data class ChooseCurrency(val amounts: List<Amount>) : DialogAction()
|
||||
data class RussianCardholdersWarningDialog(
|
||||
val dialogData: WalletDialog.RussianCardholdersWarningDialog.Data? = null,
|
||||
) : DialogAction()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.wallet.redux.middlewares
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.common.extensions.guard
|
||||
|
|
@ -129,13 +130,16 @@ class TradeCryptoMiddleware {
|
|||
val selectedWalletData = store.state.walletState.selectedWalletData ?: return
|
||||
|
||||
Analytics.send(Token.ButtonSend(AnalyticsParam.CurrencyType.Currency(selectedWalletData.currency)))
|
||||
val walletManager = store.state.walletState.getWalletManager(selectedWalletData.currency).guard {
|
||||
FirebaseCrashlytics.getInstance().recordException(IllegalStateException("WalletManager is null"))
|
||||
return
|
||||
}
|
||||
|
||||
val walletManager = store.state.walletState.getWalletManager(selectedWalletData.currency)
|
||||
store.dispatchOnMain(
|
||||
PrepareSendScreen(
|
||||
coinAmount = walletManager?.wallet?.amounts?.get(AmountType.Coin),
|
||||
coinRate = selectedWalletData.fiatRate,
|
||||
walletManager = walletManager,
|
||||
coinAmount = walletManager.wallet.amounts[AmountType.Coin],
|
||||
coinRate = selectedWalletData.fiatRate,
|
||||
),
|
||||
)
|
||||
store.dispatchOnMain(
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ class WalletDialogsMiddleware {
|
|||
)
|
||||
}
|
||||
is WalletAction.DialogAction.ChooseCurrency -> {
|
||||
if (action.amounts.isEmpty()) return
|
||||
|
||||
store.dispatchDialogShow(
|
||||
WalletDialog.SelectAmountToSendDialog(
|
||||
amounts = action.amounts,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.features.wallet.redux.middlewares
|
|||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.doOnSuccess
|
||||
|
|
@ -32,7 +33,6 @@ import com.tangem.tap.features.wallet.redux.WalletAction
|
|||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.utils.coroutines.ifActive
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -147,26 +147,76 @@ class WalletMiddleware {
|
|||
store.dispatchOpenUrl(action.exploreUrl)
|
||||
}
|
||||
is WalletAction.Send -> {
|
||||
val walletStore = walletState.getWalletStore(walletState.selectedCurrency)
|
||||
val selectedWalletData = walletState.selectedWalletData
|
||||
val walletManager = walletStore?.walletManager
|
||||
|
||||
if (walletStore == null || walletManager == null || selectedWalletData == null) {
|
||||
val error = TapError.UnsupportedState(
|
||||
"WalletAction.Send: walletStore or selectedWalletData or walletManager is null",
|
||||
)
|
||||
FirebaseCrashlytics.getInstance().recordException(IllegalStateException(error.stateError))
|
||||
store.dispatchErrorNotification(error)
|
||||
return
|
||||
}
|
||||
if (!networkConnectionManager.isOnline) {
|
||||
store.dispatchErrorNotification(TapError.NoInternetConnection)
|
||||
return
|
||||
}
|
||||
val newAction = prepareSendAction(action.amount, store.state.walletState)
|
||||
if (newAction is PrepareSendScreen && newAction.walletManager == null) {
|
||||
store.dispatch(NavigationAction.PopBackTo(screen = AppScreen.Home))
|
||||
FirebaseCrashlytics.getInstance().recordException(
|
||||
IllegalStateException("PrepareSendScreen: walletManager is null"),
|
||||
)
|
||||
store.dispatchToastNotification(R.string.internal_error_wallet_manager_not_found)
|
||||
} else {
|
||||
store.dispatch(newAction)
|
||||
if (newAction is PrepareSendScreen) {
|
||||
store.state.walletState.selectedWalletData?.currency?.let { currency ->
|
||||
Analytics.send(Token.ButtonSend(AnalyticsParam.CurrencyType.Currency(currency)))
|
||||
}
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Send))
|
||||
|
||||
val currency = selectedWalletData.currency
|
||||
val initSendStateAction = if (action.amount == null) {
|
||||
val sendableAmounts = walletManager.wallet.getSendableAmounts()
|
||||
if (sendableAmounts.isEmpty()) {
|
||||
val error = TapError.UnsupportedState("WalletAction.Send: Nothing to send")
|
||||
FirebaseCrashlytics.getInstance().recordException(IllegalStateException(error.stateError))
|
||||
store.dispatchErrorNotification(error)
|
||||
return
|
||||
}
|
||||
|
||||
if (walletState.isMultiwalletAllowed) {
|
||||
val amountToSend = sendableAmounts.find { it.currencySymbol == currency.currencySymbol }
|
||||
if (amountToSend == null) {
|
||||
val error = TapError.UnsupportedState("WalletAction.Send: Amount to send is null")
|
||||
FirebaseCrashlytics.getInstance().recordException(IllegalStateException(error.stateError))
|
||||
store.dispatchErrorNotification(error)
|
||||
return
|
||||
}
|
||||
|
||||
makeInitSendStateActionByCurrency(
|
||||
currency = currency,
|
||||
amount = amountToSend,
|
||||
walletStore = walletStore,
|
||||
walletManager = walletManager,
|
||||
selectedWalletData = selectedWalletData,
|
||||
)
|
||||
} else {
|
||||
val isSingleAmount = sendableAmounts.size == 1
|
||||
if (isSingleAmount) {
|
||||
makeInitSendStateActionByAmount(
|
||||
amount = sendableAmounts.first(),
|
||||
walletStore = walletStore,
|
||||
walletManager = walletManager,
|
||||
selectedWalletData = selectedWalletData,
|
||||
)
|
||||
} else {
|
||||
store.dispatch(WalletAction.DialogAction.ChooseCurrency(sendableAmounts))
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// action.amount received from the ChooseCurrency dialog
|
||||
makeInitSendStateActionByAmount(
|
||||
amount = action.amount,
|
||||
walletManager = walletManager,
|
||||
walletStore = walletStore,
|
||||
selectedWalletData = selectedWalletData,
|
||||
)
|
||||
}
|
||||
|
||||
Analytics.send(Token.ButtonSend(AnalyticsParam.CurrencyType.Currency(currency)))
|
||||
store.dispatch(initSendStateAction)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Send))
|
||||
}
|
||||
is WalletAction.ShowSaveWalletIfNeeded -> {
|
||||
showSaveWalletIfNeeded()
|
||||
|
|
@ -222,6 +272,59 @@ class WalletMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun makeInitSendStateActionByAmount(
|
||||
amount: Amount,
|
||||
walletStore: WalletStoreModel,
|
||||
walletManager: WalletManager,
|
||||
selectedWalletData: WalletDataModel,
|
||||
): PrepareSendScreen = when (amount.type) {
|
||||
AmountType.Coin ->
|
||||
PrepareSendScreen(
|
||||
walletManager = walletManager,
|
||||
coinAmount = amount,
|
||||
coinRate = selectedWalletData.fiatRate,
|
||||
)
|
||||
is AmountType.Token -> {
|
||||
PrepareSendScreen(
|
||||
walletManager = walletManager,
|
||||
coinAmount = walletManager.wallet.amounts[AmountType.Coin],
|
||||
coinRate = walletStore.blockchainWalletData.fiatRate,
|
||||
tokenAmount = amount,
|
||||
tokenRate = selectedWalletData.fiatRate,
|
||||
)
|
||||
}
|
||||
AmountType.Reserve -> {
|
||||
val exception = IllegalStateException("WalletAction.Send: Reserve can't be sent")
|
||||
FirebaseCrashlytics.getInstance().recordException(exception)
|
||||
throw exception
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeInitSendStateActionByCurrency(
|
||||
currency: Currency,
|
||||
amount: Amount,
|
||||
walletStore: WalletStoreModel,
|
||||
walletManager: WalletManager,
|
||||
selectedWalletData: WalletDataModel,
|
||||
): PrepareSendScreen = when (currency) {
|
||||
is Currency.Blockchain -> {
|
||||
PrepareSendScreen(
|
||||
walletManager = walletManager,
|
||||
coinAmount = amount,
|
||||
coinRate = selectedWalletData.fiatRate,
|
||||
)
|
||||
}
|
||||
is Currency.Token -> {
|
||||
PrepareSendScreen(
|
||||
walletManager = walletManager,
|
||||
coinAmount = walletManager.wallet.amounts[AmountType.Coin],
|
||||
coinRate = walletStore.blockchainWalletData.fiatRate,
|
||||
tokenAmount = amount,
|
||||
tokenRate = selectedWalletData.fiatRate,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun changeSelectedWalletAddress(type: AddressType, state: WalletState) {
|
||||
val selectedUserWalletId = userWalletsListManager.selectedUserWalletSync?.walletId.guard {
|
||||
Timber.e("Unable to change selected wallet address, no user wallet selected")
|
||||
|
|
@ -284,72 +387,4 @@ class WalletMiddleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareSendAction(amount: Amount?, state: WalletState?): Action {
|
||||
val selectedWalletData = state?.selectedWalletData
|
||||
val currency = selectedWalletData?.currency
|
||||
val walletStore = state?.getWalletStore(currency)
|
||||
|
||||
return if (amount != null) {
|
||||
if (amount.type is AmountType.Token) {
|
||||
prepareSendActionForToken(amount, selectedWalletData, walletStore)
|
||||
} else {
|
||||
PrepareSendScreen(amount, selectedWalletData?.fiatRate, walletStore?.walletManager)
|
||||
}
|
||||
} else {
|
||||
val amounts = walletStore?.walletManager?.wallet?.getSendableAmounts()
|
||||
if (currency != null && state.isMultiwalletAllowed) {
|
||||
when (currency) {
|
||||
is Currency.Blockchain -> {
|
||||
val amountToSend = amounts?.find { it.currencySymbol == currency.blockchain.currency }
|
||||
?: return WalletAction.DialogAction.ChooseCurrency(amounts)
|
||||
PrepareSendScreen(
|
||||
coinAmount = amountToSend,
|
||||
coinRate = selectedWalletData.fiatRate,
|
||||
walletManager = walletStore.walletManager,
|
||||
)
|
||||
}
|
||||
is Currency.Token -> {
|
||||
val amountToSend = amounts?.find { it.currencySymbol == currency.token.symbol }
|
||||
?: return WalletAction.DialogAction.ChooseCurrency(amounts)
|
||||
prepareSendActionForToken(
|
||||
amount = amountToSend,
|
||||
selectedWalletData = selectedWalletData,
|
||||
walletStore = walletStore,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val amountsSize = amounts?.size ?: 0
|
||||
if (amountsSize > 1) {
|
||||
WalletAction.DialogAction.ChooseCurrency(amounts)
|
||||
} else {
|
||||
val amountToSend = amounts?.first()
|
||||
PrepareSendScreen(
|
||||
coinAmount = amountToSend,
|
||||
coinRate = selectedWalletData?.fiatRate,
|
||||
walletManager = walletStore?.walletManager,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareSendActionForToken(
|
||||
amount: Amount,
|
||||
selectedWalletData: WalletDataModel?,
|
||||
walletStore: WalletStoreModel?,
|
||||
): PrepareSendScreen {
|
||||
val coinRate = walletStore?.blockchainWalletData?.fiatRate
|
||||
val tokenRate = selectedWalletData?.fiatRate
|
||||
val coinAmount = walletStore?.walletManager?.wallet?.amounts?.get(AmountType.Coin)
|
||||
|
||||
return PrepareSendScreen(
|
||||
coinAmount = coinAmount,
|
||||
coinRate = coinRate,
|
||||
walletManager = walletStore?.walletManager,
|
||||
tokenAmount = amount,
|
||||
tokenRate = tokenRate,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import com.tangem.tap.common.redux.StateDialog
|
|||
import com.tangem.wallet.R
|
||||
|
||||
sealed interface WalletDialog : StateDialog {
|
||||
data class SelectAmountToSendDialog(val amounts: List<Amount>?) : WalletDialog
|
||||
data class SelectAmountToSendDialog(val amounts: List<Amount>) : WalletDialog
|
||||
object SignedHashesMultiWalletDialog : WalletDialog
|
||||
data class ChooseTradeActionDialog(
|
||||
val buyAllowed: Boolean,
|
||||
|
|
|
|||
|
|
@ -5,11 +5,7 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.*
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
|
|
@ -55,7 +51,7 @@ class AmountToSendBottomSheetDialog(
|
|||
}
|
||||
}
|
||||
|
||||
class ChooseAmountAdapter : ListAdapter<Amount, ChooseAmountAdapter.AmountViewHolder>(DiffUtilCallback) {
|
||||
private class ChooseAmountAdapter : ListAdapter<Amount, ChooseAmountAdapter.AmountViewHolder>(DiffUtilCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AmountViewHolder {
|
||||
val binding = ItemWalletAmountToSendBinding.inflate(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue