Updated on 2026-08-14

This commit is contained in:
Tangem 2024-01-31 12:13:47 +03:00
parent d995d1dd21
commit 07bf6c376c
20 changed files with 386 additions and 174 deletions

View file

@ -0,0 +1,156 @@
package com.tangem.feature.wallet.presentation.deeplink
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.deeplink.DeepLink
import com.tangem.core.deeplink.DeepLinksRegistry
import com.tangem.core.deeplink.global.BuyCurrencyDeepLink
import com.tangem.core.deeplink.global.SellCurrencyDeepLink
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.tokens.GetCryptoCurrencyUseCase
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.legacy.TradeCryptoAction.TransactionInfo
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.models.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.wallets.models.UserWallet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import javax.inject.Inject
@Suppress("LongParameterList")
internal class WalletDeepLinksHandler @Inject constructor(
private val deepLinksRegistry: DeepLinksRegistry,
private val analyticsEventHandler: AnalyticsEventHandler,
private val getCryptoCurrencyUseCase: GetCryptoCurrencyUseCase,
private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase,
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
private val reduxStateHolder: ReduxStateHolder,
) {
private var deepLinks: List<DeepLink> = emptyList()
fun registerForSingleCurrencyWallets(viewModel: ViewModel, userWallet: UserWallet) {
if (userWallet.isMultiCurrency) {
deepLinksRegistry.unregister(deepLinks)
} else {
if (deepLinks.isEmpty()) {
deepLinks = getDeepLinks(userWallet, viewModel.viewModelScope)
}
deepLinksRegistry.register(deepLinks)
}
viewModel.addCloseable {
deepLinksRegistry.unregister(deepLinks)
}
}
private fun getDeepLinks(userWallet: UserWallet, scope: CoroutineScope): List<DeepLink> {
val sellCurrencyDeepLink = SellCurrencyDeepLink(
onReceive = { data ->
scope.launch {
onSellCurrencyDeepLink(userWallet, data)
}
},
)
val buyCurrencyDeepLink = BuyCurrencyDeepLink(
onReceive = {
scope.launch {
onBuyCurrencyDeepLink(userWallet)
}
},
)
return listOf(sellCurrencyDeepLink, buyCurrencyDeepLink)
}
private suspend fun onSellCurrencyDeepLink(userWallet: UserWallet, data: SellCurrencyDeepLink.Data) {
val cryptoCurrencyStatus = getCryptoCurrencyStatusSyncUseCase(userWallet.walletId)
.getOrNull() ?: return
val feeCurrencyStatus = getFeePaidCryptoCurrencyStatusSyncUseCase(
userWallet.walletId,
cryptoCurrencyStatus,
).getOrNull()
val transactionInfo = data.let {
TransactionInfo(
amount = it.baseCurrencyAmount,
destinationAddress = it.depositWalletAddress,
transactionId = it.transactionId,
)
}
when (cryptoCurrencyStatus.currency) {
is CryptoCurrency.Coin -> sendCoin(
userWallet = userWallet,
cryptoCurrencyStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
)
is CryptoCurrency.Token -> sendToken(
userWallet = userWallet,
cryptoCurrencyStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
)
}
}
private suspend fun onBuyCurrencyDeepLink(userWallet: UserWallet) {
val cryptoCurrency = getCryptoCurrencyUseCase(userWallet.walletId).getOrNull() ?: return
analyticsEventHandler.send(TokenScreenAnalyticsEvent.Bought(cryptoCurrency.symbol))
}
private fun sendCoin(
userWallet: UserWallet,
cryptoCurrencyStatus: CryptoCurrencyStatus,
feeCurrencyStatus: CryptoCurrencyStatus?,
transactionInfo: TransactionInfo,
) {
reduxStateHolder.dispatch(
action = TradeCryptoAction.SendCoin(
userWallet = userWallet,
coinStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
),
)
}
private suspend fun sendToken(
userWallet: UserWallet,
cryptoCurrencyStatus: CryptoCurrencyStatus,
feeCurrencyStatus: CryptoCurrencyStatus?,
transactionInfo: TransactionInfo,
) {
val cryptoCurrency = cryptoCurrencyStatus.currency as? CryptoCurrency.Token ?: return
val coinStatus = getNetworkCoinStatusUseCase(
userWalletId = userWallet.walletId,
networkId = cryptoCurrency.network.id,
derivationPath = cryptoCurrency.network.derivationPath,
isSingleWalletWithTokens = false,
)
.firstOrNull()
?.getOrNull()
?: return
reduxStateHolder.dispatch(
action = TradeCryptoAction.SendToken(
userWallet = userWallet,
tokenCurrency = cryptoCurrency,
tokenFiatRate = cryptoCurrencyStatus.value.fiatRate,
coinFiatRate = coinStatus.value.fiatRate,
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
),
)
}
}

View file

@ -609,7 +609,7 @@ internal class WalletViewModel @Inject constructor(
showErrorIfDemoModeOrElse {
reduxStateHolder.dispatch(
TradeCryptoAction.New.Buy(
TradeCryptoAction.Buy(
userWallet = getWallet(index = state.walletsListConfig.selectedWalletIndex),
cryptoCurrencyStatus = cryptoCurrencyStatus,
appCurrencyCode = selectedAppCurrencyFlow.value.code,
@ -623,7 +623,7 @@ internal class WalletViewModel @Inject constructor(
event = TokenScreenAnalyticsEvent.ButtonExchange(cryptoCurrencyStatus.currency.symbol),
)
reduxStateHolder.dispatch(TradeCryptoAction.New.Swap(cryptoCurrencyStatus.currency))
reduxStateHolder.dispatch(TradeCryptoAction.Swap(cryptoCurrencyStatus.currency))
}
override fun onSingleCurrencySendClick(cryptoCurrencyStatus: CryptoCurrencyStatus?) {
@ -641,7 +641,7 @@ internal class WalletViewModel @Inject constructor(
val maybeFeeCurrencyStatus =
getFeePaidCryptoCurrencyStatusSyncUseCase(userWallet.walletId, coinStatus).getOrNull()
reduxStateHolder.dispatch(
action = TradeCryptoAction.New.SendCoin(
action = TradeCryptoAction.SendCoin(
userWallet = userWallet,
coinStatus = coinStatus,
feeCurrencyStatus = maybeFeeCurrencyStatus,
@ -665,7 +665,7 @@ internal class WalletViewModel @Inject constructor(
is CryptoCurrency.Coin -> {
uiState = stateFactory.getStateWithClosedBottomSheet()
reduxStateHolder.dispatch(
action = TradeCryptoAction.New.SendCoin(
action = TradeCryptoAction.SendCoin(
userWallet = userWallet,
coinStatus = cryptoCurrencyStatus,
feeCurrencyStatus = maybeFeeCurrencyStatus,
@ -694,7 +694,7 @@ internal class WalletViewModel @Inject constructor(
it.onRight { coinStatus ->
uiState = stateFactory.getStateWithClosedBottomSheet()
reduxStateHolder.dispatchWithMain(
action = TradeCryptoAction.New.SendToken(
action = TradeCryptoAction.SendToken(
userWallet = userWallet,
tokenCurrency = requireNotNull(cryptoCurrencyStatus.currency as? CryptoCurrency.Token),
tokenFiatRate = cryptoCurrencyStatus.value.fiatRate,
@ -772,7 +772,7 @@ internal class WalletViewModel @Inject constructor(
showErrorIfDemoModeOrElse {
reduxStateHolder.dispatch(
action = TradeCryptoAction.New.Sell(
action = TradeCryptoAction.Sell(
cryptoCurrencyStatus = cryptoCurrencyStatus,
appCurrencyCode = selectedAppCurrencyFlow.value.code,
),

View file

@ -13,6 +13,7 @@ import com.tangem.domain.walletconnect.WalletConnectActions
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.feature.wallet.presentation.deeplink.WalletDeepLinksHandler
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.SelectedWalletAnalyticsSender
@ -57,6 +58,7 @@ internal class WalletViewModelV2 @Inject constructor(
private val reduxStateHolder: ReduxStateHolder,
private val screenLifecycleProvider: ScreenLifecycleProvider,
private val selectedWalletAnalyticsSender: SelectedWalletAnalyticsSender,
private val walletDeepLinksHandler: WalletDeepLinksHandler,
) : ViewModel() {
val uiState: StateFlow<WalletScreenState> = stateHolder.uiState
@ -157,6 +159,11 @@ internal class WalletViewModelV2 @Inject constructor(
selectedWalletAnalyticsSender.send(selectedWallet)
}
walletDeepLinksHandler.registerForSingleCurrencyWallets(
viewModel = this,
userWallet = selectedWallet,
)
}
.flowOn(dispatchers.main)
.launchIn(viewModelScope)

View file

@ -110,7 +110,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
feeCurrencyStatus: CryptoCurrencyStatus?,
) {
reduxStateHolder.dispatch(
action = TradeCryptoAction.New.SendCoin(
action = TradeCryptoAction.SendCoin(
userWallet = userWallet,
coinStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
@ -135,7 +135,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
.collectLatest {
it.onRight { coinStatus ->
reduxStateHolder.dispatch(
action = TradeCryptoAction.New.SendToken(
action = TradeCryptoAction.SendToken(
userWallet = userWallet,
tokenCurrency = cryptoCurrency,
tokenFiatRate = cryptoCurrencyStatus.fiatRate,
@ -281,7 +281,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
showErrorIfDemoModeOrElse {
viewModelScope.launch(dispatchers.main) {
reduxStateHolder.dispatch(
action = TradeCryptoAction.New.Sell(
action = TradeCryptoAction.Sell(
cryptoCurrencyStatus = cryptoCurrencyStatus,
appCurrencyCode = getSelectedAppCurrencyUseCase.unwrap().code,
),
@ -300,7 +300,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
showErrorIfDemoModeOrElse {
viewModelScope.launch(dispatchers.main) {
reduxStateHolder.dispatch(
TradeCryptoAction.New.Buy(
TradeCryptoAction.Buy(
userWallet = userWallet,
cryptoCurrencyStatus = cryptoCurrencyStatus,
appCurrencyCode = getSelectedAppCurrencyUseCase.unwrap().code,
@ -315,7 +315,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
event = TokenScreenAnalyticsEvent.ButtonExchange(cryptoCurrencyStatus.currency.symbol),
)
reduxStateHolder.dispatch(TradeCryptoAction.New.Swap(cryptoCurrencyStatus.currency))
reduxStateHolder.dispatch(TradeCryptoAction.Swap(cryptoCurrencyStatus.currency))
}
override fun onExploreClick() {