diff --git a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt index df25867d4d..b8046288d6 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt @@ -117,6 +117,22 @@ internal object TokensDomainModule { return GetCryptoCurrencyActionsUseCase(rampStateManager, marketCryptoCurrencyRepository, dispatchers) } + @Provides + @ViewModelScoped + fun provideGetCurrencyStatusByNetworkUseCase( + currenciesRepository: CurrenciesRepository, + quotesRepository: QuotesRepository, + networksRepository: NetworksRepository, + dispatchers: CoroutineDispatcherProvider, + ): GetNetworkCoinStatusUseCase { + return GetNetworkCoinStatusUseCase( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + dispatchers = dispatchers, + ) + } + @Provides @ViewModelScoped fun provideGetCurrenciesUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrenciesUseCase { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 2528753b4e..02068b2149 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -18,9 +18,11 @@ import com.tangem.feature.swap.presentation.SwapFragment import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDebugErrorNotification +import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.redux.AppState +import com.tangem.tap.domain.TapError import com.tangem.tap.domain.tokens.getIconUrl import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE @@ -39,7 +41,10 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import com.tangem.feature.swap.domain.models.domain.Currency as SwapCurrency +@Suppress("LargeClass") class TradeCryptoMiddleware { + + @Suppress("LongMethod", "CyclomaticComplexMethod") fun handle(state: () -> AppState?, action: TradeCryptoAction) { if (DemoHelper.tryHandle(state, action)) return @@ -52,11 +57,10 @@ class TradeCryptoMiddleware { openSwap(currency = store.state.walletState.selectedWalletData?.currency?.toSwapCurrency()) } is TradeCryptoAction.New.Buy -> proceedNewBuyAction(state, action) - TradeCryptoAction.New.Send -> store.dispatch(WalletAction.Send()) is TradeCryptoAction.New.Sell -> proceedNewSellAction(action) - is TradeCryptoAction.New.Swap -> { - openSwap(currency = action.cryptoCurrency.toSwapCurrency()) - } + is TradeCryptoAction.New.Swap -> openSwap(currency = action.cryptoCurrency.toSwapCurrency()) + is TradeCryptoAction.New.SendToken -> handleNewSendToken(action = action) + is TradeCryptoAction.New.SendCoin -> handleNewSendCoin(action = action) } } @@ -301,4 +305,98 @@ class TradeCryptoMiddleware { ) } } + + private fun handleNewSendToken(action: TradeCryptoAction.New.SendToken) { + val cryptoStatus = action.tokenStatus + val currency = cryptoStatus.currency + val blockchain = Blockchain.fromId(currency.network.id.value) + + scope.launch { + val walletManager = store.state.daggerGraphState + .get(DaggerGraphState::walletManagersFacade) + .getOrCreateWalletManager( + userWallet = action.userWallet, + blockchain = blockchain, + derivationPath = blockchain.derivationPath( + style = action.userWallet.scanResponse.derivationStyleProvider.getDerivationStyle(), + ), + ) + + if (walletManager == null) { + val error = TapError.UnsupportedState(stateError = "WalletManager is null") + FirebaseCrashlytics.getInstance().recordException(IllegalStateException(error.stateError)) + store.dispatchErrorNotification(error) + return@launch + } + + val sendableAmounts = walletManager.wallet.amounts.values.filter { it.type is AmountType.Token } + when (currency) { + is CryptoCurrency.Coin -> error("Action.tokenStatus.currency is Coin") + is CryptoCurrency.Token -> { + store.dispatchOnMain( + action = PrepareSendScreen( + walletManager = walletManager, + coinAmount = walletManager.wallet.amounts[AmountType.Coin], + coinRate = action.coinFiatRate, + tokenAmount = sendableAmounts.first(), + tokenRate = cryptoStatus.value.fiatRate, + ), + ) + } + } + + store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Send)) + } + } + + private fun handleNewSendCoin(action: TradeCryptoAction.New.SendCoin) { + val cryptoStatus = action.coinStatus + val currency = cryptoStatus.currency + val blockchain = Blockchain.fromId(currency.network.id.value) + + scope.launch { + val walletManager = store.state.daggerGraphState + .get(DaggerGraphState::walletManagersFacade) + .getOrCreateWalletManager( + userWallet = action.userWallet, + blockchain = blockchain, + derivationPath = blockchain.derivationPath( + style = action.userWallet.scanResponse.derivationStyleProvider.getDerivationStyle(), + ), + ) + + if (walletManager == null) { + val error = TapError.UnsupportedState(stateError = "WalletManager is null") + FirebaseCrashlytics.getInstance().recordException(IllegalStateException(error.stateError)) + store.dispatchErrorNotification(error) + return@launch + } + + val sendableAmounts = walletManager.wallet.amounts.values.filter { it.type == AmountType.Coin } + when (currency) { + is CryptoCurrency.Coin -> { + val amountToSend = sendableAmounts.find { it.currencySymbol == currency.symbol } + + if (amountToSend == null) { + val error = TapError.UnsupportedState(stateError = "Amount to send is null") + FirebaseCrashlytics.getInstance() + .recordException(IllegalStateException(error.stateError)) + store.dispatchErrorNotification(error) + return@launch + } + + store.dispatchOnMain( + action = PrepareSendScreen( + walletManager = walletManager, + coinAmount = amountToSend, + coinRate = cryptoStatus.value.fiatRate, + ), + ) + } + is CryptoCurrency.Token -> error("Action.tokenStatus.currency is Token") + } + + store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Send)) + } + } } \ No newline at end of file diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt index 2563eb0409..0e83c656d4 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt @@ -1,5 +1,6 @@ package com.tangem.data.tokens.repository +import com.tangem.blockchain.common.Blockchain import com.tangem.data.common.cache.CacheRegistry import com.tangem.data.tokens.utils.* import com.tangem.datasource.api.tangemTech.TangemTechApi @@ -7,10 +8,12 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse import com.tangem.datasource.local.token.UserMarketCoinsStore import com.tangem.datasource.local.token.UserTokensStore import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.domain.common.extensions.toNetworkId import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.core.error.DataError import com.tangem.domain.demo.DemoConfig import com.tangem.domain.tokens.models.CryptoCurrency +import com.tangem.domain.tokens.models.Network import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId @@ -190,6 +193,27 @@ internal class DefaultCurrenciesRepository( responseCurrenciesFactory.createCurrency(id, response, userWallet.scanResponse.card) } + override suspend fun getNetworkCoin(userWalletId: UserWalletId, networkId: Network.ID): CryptoCurrency.Coin { + val userWallet = getUserWallet(userWalletId) + ensureIsCorrectUserWallet(userWallet = userWallet, isMultiCurrencyWalletExpected = true) + + fetchTokensIfCacheExpired(userWallet = userWallet, refresh = false) + + val storedTokens = requireNotNull(userTokensStore.getSyncOrNull(userWallet.walletId)) { + "Unable to find tokens response for user wallet with provided ID: $userWalletId" + } + + val storedCoin = storedTokens.tokens.find { it.networkId == Blockchain.fromId(networkId.value).toNetworkId() } + ?: error("Coin in this network $networkId not found") + + val coin = responseCurrenciesFactory.createCurrency( + responseToken = storedCoin, + card = userWallet.scanResponse.card, + ) + + return coin as? CryptoCurrency.Coin ?: error("Unable to create currency") + } + override fun isTokensGrouped(userWalletId: UserWalletId): Flow { return channelFlow { ensureIsCorrectUserWallet(userWalletId, isMultiCurrencyWalletExpected = true) diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCurrenciesFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCurrenciesFactory.kt index f3e7832865..514ef69b10 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCurrenciesFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCurrenciesFactory.kt @@ -28,7 +28,7 @@ internal class ResponseCurrenciesFactory(private val demoConfig: DemoConfig) { return response.tokens.mapNotNull { createCurrency(it, card) } } - private fun createCurrency(responseToken: UserTokensResponse.Token, card: CardDTO): CryptoCurrency? { + fun createCurrency(responseToken: UserTokensResponse.Token, card: CardDTO): CryptoCurrency? { var blockchain = Blockchain.fromNetworkId(responseToken.networkId) if (blockchain == null || blockchain == Blockchain.Unknown) { Timber.e("Unable to find a blockchain with the network ID: ${responseToken.networkId}") diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNetworkCoinStatusUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNetworkCoinStatusUseCase.kt new file mode 100644 index 0000000000..23ecf06a99 --- /dev/null +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetNetworkCoinStatusUseCase.kt @@ -0,0 +1,53 @@ +package com.tangem.domain.tokens + +import arrow.core.Either +import com.tangem.domain.tokens.error.CurrencyStatusError +import com.tangem.domain.tokens.error.mapper.mapToCurrencyError +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.tokens.models.Network +import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations +import com.tangem.domain.tokens.repository.CurrenciesRepository +import com.tangem.domain.tokens.repository.NetworksRepository +import com.tangem.domain.tokens.repository.QuotesRepository +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.* + +class GetNetworkCoinStatusUseCase( + private val currenciesRepository: CurrenciesRepository, + private val quotesRepository: QuotesRepository, + private val networksRepository: NetworksRepository, + private val dispatchers: CoroutineDispatcherProvider, +) { + + operator fun invoke( + userWalletId: UserWalletId, + networkId: Network.ID, + ): Flow> { + return flow { + emitAll( + flow = getCurrency( + userWalletId = userWalletId, + networkId = networkId, + ), + ) + } + .flowOn(dispatchers.io) + } + + private suspend fun getCurrency( + userWalletId: UserWalletId, + networkId: Network.ID, + ): Flow> { + val operations = CurrenciesStatusesOperations( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + userWalletId = userWalletId, + ) + + return operations.getNetworkCoinFlow(networkId).map { maybeCurrency -> + maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError) + } + } +} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/legacy/TradeCryptoAction.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/legacy/TradeCryptoAction.kt index 3ef7c99d04..e9c3430207 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/legacy/TradeCryptoAction.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/legacy/TradeCryptoAction.kt @@ -4,6 +4,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.wallets.models.UserWallet import org.rekotlin.Action +import java.math.BigDecimal sealed class TradeCryptoAction : Action { @@ -36,7 +37,13 @@ sealed class TradeCryptoAction : Action { val appCurrencyCode: String, ) : New() - object Send : New() + data class SendToken( + val userWallet: UserWallet, + val tokenStatus: CryptoCurrencyStatus, + val coinFiatRate: BigDecimal?, + ) : New() + + data class SendCoin(val userWallet: UserWallet, val coinStatus: CryptoCurrencyStatus) : New() data class Swap(val cryptoCurrency: CryptoCurrency) : New() } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt index cb8885e6b5..e72a1769bb 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt @@ -80,6 +80,15 @@ internal class CurrenciesStatusesOperations( return getCurrencyStatusFlow(currency) } + suspend fun getNetworkCoinFlow(networkId: Network.ID): Flow> { + val currency = recover( + block = { getNetworkCoin(networkId) }, + recover = { return flowOf(it.left()) }, + ) + + return getCurrencyStatusFlow(currency) + } + suspend fun getPrimaryCurrencyStatusFlow(): Flow> { val currency = recover( block = { getPrimaryCurrency() }, @@ -177,6 +186,12 @@ internal class CurrenciesStatusesOperations( .bind() } + private suspend fun Raise.getNetworkCoin(networkId: Network.ID): CryptoCurrency { + return Either.catch { currenciesRepository.getNetworkCoin(userWalletId, networkId) } + .mapLeft { Error.DataError(it) } + .bind() + } + private suspend fun Raise.getPrimaryCurrency(): CryptoCurrency { return catch( block = { currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId) }, diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt index 99db8c884a..ce523cb34a 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt @@ -1,6 +1,7 @@ package com.tangem.domain.tokens.repository import com.tangem.domain.tokens.models.CryptoCurrency +import com.tangem.domain.tokens.models.Network import com.tangem.domain.wallets.models.UserWalletId import kotlinx.coroutines.flow.Flow @@ -103,6 +104,14 @@ interface CurrenciesRepository { */ suspend fun getMultiCurrencyWalletCurrency(userWalletId: UserWalletId, id: CryptoCurrency.ID): CryptoCurrency + /** + * Get the coin for a specific network. + * + * @param userWalletId The unique identifier of the user wallet. + * @param networkId The unique identifier of the network. + */ + suspend fun getNetworkCoin(userWalletId: UserWalletId, networkId: Network.ID): CryptoCurrency.Coin + /** * Determines whether the tokens within a specific multi-currency user wallet are grouped. * diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt index 192b8f5afc..8238bc90d6 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt @@ -4,6 +4,7 @@ import arrow.core.Either import arrow.core.getOrElse import com.tangem.domain.core.error.DataError import com.tangem.domain.tokens.models.CryptoCurrency +import com.tangem.domain.tokens.models.Network import com.tangem.domain.wallets.models.UserWalletId import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first @@ -74,6 +75,10 @@ internal class MockCurrenciesRepository( return token } + override suspend fun getNetworkCoin(userWalletId: UserWalletId, networkId: Network.ID): CryptoCurrency.Coin { + TODO("Not yet implemented") + } + override fun isTokensGrouped(userWalletId: UserWalletId): Flow { return isGrouped.map { it.getOrElse { e -> throw e } } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index f1e17d7e44..27b52fe003 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -11,8 +11,9 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase -import com.tangem.domain.tokens.RemoveCurrencyUseCase import com.tangem.domain.tokens.GetCurrencyStatusUpdatesUseCase +import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase +import com.tangem.domain.tokens.RemoveCurrencyUseCase import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.models.CryptoCurrency @@ -48,6 +49,7 @@ internal class TokenDetailsViewModel @Inject constructor( private val getExploreUrlUseCase: GetExploreUrlUseCase, private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase, private val removeCurrencyUseCase: RemoveCurrencyUseCase, + private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase, private val reduxStateHolder: ReduxStateHolder, savedStateHandle: SavedStateHandle, ) : ViewModel(), DefaultLifecycleObserver, TokenDetailsClickIntents { @@ -169,7 +171,40 @@ internal class TokenDetailsViewModel @Inject constructor( } override fun onSendClick() { - reduxStateHolder.dispatch(TradeCryptoAction.New.Send) + val cryptoCurrencyStatus = cryptoCurrencyStatus ?: return + + when (cryptoCurrencyStatus.currency) { + is CryptoCurrency.Coin -> { + reduxStateHolder.dispatch( + action = TradeCryptoAction.New.SendCoin( + userWallet = wallet, + coinStatus = cryptoCurrencyStatus, + ), + ) + } + is CryptoCurrency.Token -> sendToken(status = cryptoCurrencyStatus) + } + } + + private fun sendToken(status: CryptoCurrencyStatus) { + viewModelScope.launch(dispatchers.io) { + getNetworkCoinStatusUseCase( + userWalletId = wallet.walletId, + networkId = status.currency.network.id, + ) + .take(count = 1) + .collectLatest { + it.onRight { coinStatus -> + reduxStateHolder.dispatch( + action = TradeCryptoAction.New.SendToken( + userWallet = wallet, + tokenStatus = status, + coinFiatRate = coinStatus.value.fiatRate, + ), + ) + } + } + } } override fun onReceiveClick() { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/TokenActionsProvider.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/TokenActionsProvider.kt index f9a7dbfc4e..37c3309f8b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/TokenActionsProvider.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/TokenActionsProvider.kt @@ -1,36 +1,32 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory -import com.tangem.common.Provider +import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.common.state.TokenItemState import com.tangem.feature.wallet.presentation.wallet.state.TokenActionButtonConfig -import com.tangem.feature.wallet.presentation.wallet.state.WalletState +import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList /** * Converter from loaded [TokenItemState.Content] to ImmutableList<[TokenActionButtonConfig]> * - * @property currentStateProvider current ui state provider + * @property clickIntents screen click intents * */ -@Suppress("UnusedPrivateMember") -internal class TokenActionsProvider( - private val currentStateProvider: Provider, -) { +internal class TokenActionsProvider(private val clickIntents: WalletClickIntents) { - @Suppress("UnusedPrivateMember") - fun provideActions(tokenId: String): ImmutableList { + fun provideActions(cryptoCurrencyStatus: CryptoCurrencyStatus): ImmutableList { // TODO: [REDACTED_JIRA] - return mockTokenActionButtonConfig().toImmutableList() + return mockTokenActionButtonConfig(cryptoCurrencyStatus).toImmutableList() } - private fun mockTokenActionButtonConfig(): List { + private fun mockTokenActionButtonConfig(cryptoCurrencyStatus: CryptoCurrencyStatus): List { return listOf( TokenActionButtonConfig( text = "Send", iconResId = R.drawable.ic_plus_24, - onClick = {}, + onClick = { clickIntents.onMultiCurrencySendClick(cryptoCurrencyStatus) }, ), TokenActionButtonConfig( text = "Buy", diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletCryptoCurrencyActionsConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletCryptoCurrencyActionsConverter.kt index 38e18cdf52..b4b8f00fbf 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletCryptoCurrencyActionsConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletCryptoCurrencyActionsConverter.kt @@ -40,7 +40,10 @@ internal class WalletCryptoCurrencyActionsConverter( WalletManageButton.Sell(enabled = action.enabled, onClick = clickIntents::onSellClick) } is TokenActionsState.ActionState.Send -> { - WalletManageButton.Send(enabled = action.enabled, onClick = clickIntents::onSendClick) + WalletManageButton.Send( + enabled = action.enabled, + onClick = clickIntents::onSingleCurrencySendClick, + ) } is TokenActionsState.ActionState.Swap -> null } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt index 4fe28bb627..fa22261f52 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt @@ -44,7 +44,7 @@ internal class WalletStateFactory( private val clickIntents: WalletClickIntents, ) { - private val tokenActionsProvider by lazy { TokenActionsProvider(currentStateProvider = currentStateProvider) } + private val tokenActionsProvider by lazy { TokenActionsProvider(clickIntents) } private val skeletonConverter by lazy { WalletSkeletonStateConverter(currentStateProvider, clickIntents) } private val tokenListErrorConverter by lazy { @@ -185,12 +185,12 @@ internal class WalletStateFactory( } } - fun getStateWithTokenActionBottomSheet(tokenId: String): WalletState { + fun getStateWithTokenActionBottomSheet(currencyStatus: CryptoCurrencyStatus): WalletState { return when (val state = currentStateProvider() as WalletState.ContentState) { is WalletMultiCurrencyState.Content -> state.copy( tokenActionsBottomSheet = ActionsBottomSheetConfig( isShow = true, - actions = tokenActionsProvider.provideActions(tokenId = tokenId), + actions = tokenActionsProvider.provideActions(currencyStatus), onDismissRequest = clickIntents::onDismissActionsBottomSheet, ), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt index 02b175aad7..a2e85d00a2 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt @@ -50,7 +50,7 @@ internal class CryptoCurrencyStatusToTokenItemConverter( ) }, onItemClick = { clickIntents.onTokenItemClick(currency) }, - onItemLongClick = { clickIntents.onTokenItemLongClick(currency) }, + onItemLongClick = { clickIntents.onTokenItemLongClick(cryptoCurrencyStatus = this) }, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt index c3ba714c76..34e8f722a8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt @@ -1,6 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels import com.tangem.core.ui.components.transactions.intents.TxHistoryClickIntents +import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId @@ -39,7 +40,7 @@ internal interface WalletClickIntents : TxHistoryClickIntents { fun onTokenItemClick(currency: CryptoCurrency) - fun onTokenItemLongClick(currency: CryptoCurrency) + fun onTokenItemLongClick(cryptoCurrencyStatus: CryptoCurrencyStatus) fun onDismissActionsBottomSheet() @@ -47,7 +48,9 @@ internal interface WalletClickIntents : TxHistoryClickIntents { fun onDeleteClick(userWalletId: UserWalletId) - fun onSendClick() + fun onSingleCurrencySendClick(cryptoCurrencyStatus: CryptoCurrencyStatus? = null) + + fun onMultiCurrencySendClick(cryptoCurrencyStatus: CryptoCurrencyStatus) fun onReceiveClick() diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 4dc7b9293c..5b948416b6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -74,6 +74,7 @@ internal class WalletViewModel @Inject constructor( private val fetchTokenListUseCase: FetchTokenListUseCase, private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase, private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase, + private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase, private val getCardWasScannedUseCase: GetCardWasScannedUseCase, private val isUserAlreadyRateAppUseCase: IsUserAlreadyRateAppUseCase, private val isDemoCardUseCase: IsDemoCardUseCase, @@ -121,7 +122,7 @@ internal class WalletViewModel @Inject constructor( var uiState: WalletState by uiStateHolder(initialState = stateFactory.getInitialState()) private var wallets: List by Delegates.notNull() - private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null + private var singleWalletCryptoCurrencyStatus: CryptoCurrencyStatus? = null private val tokensJobHolder = JobHolder() private val marketPriceJobHolder = JobHolder() @@ -300,7 +301,7 @@ internal class WalletViewModel @Inject constructor( override fun onBuyClick() { val state = uiState as? WalletState.ContentState ?: return - val status = cryptoCurrencyStatus ?: return + val status = singleWalletCryptoCurrencyStatus ?: return val wallet = getWallet(index = state.walletsListConfig.selectedWalletIndex) reduxStateHolder.dispatch( @@ -312,8 +313,48 @@ internal class WalletViewModel @Inject constructor( ) } - override fun onSendClick() { - reduxStateHolder.dispatch(TradeCryptoAction.New.Send) + override fun onSingleCurrencySendClick(cryptoCurrencyStatus: CryptoCurrencyStatus?) { + val state = uiState as? WalletState.ContentState ?: return + + val userWallet = getWallet(index = state.walletsListConfig.selectedWalletIndex) + val coinStatus = if (userWallet.isMultiCurrency) cryptoCurrencyStatus else singleWalletCryptoCurrencyStatus + + reduxStateHolder.dispatch( + action = TradeCryptoAction.New.SendCoin( + userWallet = userWallet, + coinStatus = coinStatus ?: return, + ), + ) + } + + override fun onMultiCurrencySendClick(cryptoCurrencyStatus: CryptoCurrencyStatus) { + if (cryptoCurrencyStatus.currency is CryptoCurrency.Coin) { + onSingleCurrencySendClick(cryptoCurrencyStatus = cryptoCurrencyStatus) + return + } + + val state = uiState as? WalletState.ContentState ?: return + + viewModelScope.launch(dispatchers.io) { + val userWallet = getWallet(index = state.walletsListConfig.selectedWalletIndex) + + getNetworkCoinStatusUseCase( + userWalletId = userWallet.walletId, + networkId = cryptoCurrencyStatus.currency.network.id, + ) + .take(count = 1) + .collectLatest { + it.onRight { coinStatus -> + reduxStateHolder.dispatch( + action = TradeCryptoAction.New.SendToken( + userWallet = getWallet(index = state.walletsListConfig.selectedWalletIndex), + tokenStatus = cryptoCurrencyStatus, + coinFiatRate = coinStatus.value.fiatRate, + ), + ) + } + } + } } override fun onReceiveClick() { @@ -321,7 +362,7 @@ internal class WalletViewModel @Inject constructor( } override fun onSellClick() { - val status = cryptoCurrencyStatus ?: return + val status = singleWalletCryptoCurrencyStatus ?: return reduxStateHolder.dispatch( TradeCryptoAction.New.Sell( @@ -384,10 +425,8 @@ internal class WalletViewModel @Inject constructor( router.openTokenDetails(currency = currency) } - override fun onTokenItemLongClick(currency: CryptoCurrency) { - uiState = stateFactory.getStateWithTokenActionBottomSheet( - tokenId = currency.id.value, - ) + override fun onTokenItemLongClick(cryptoCurrencyStatus: CryptoCurrencyStatus) { + uiState = stateFactory.getStateWithTokenActionBottomSheet(cryptoCurrencyStatus) } override fun onRenameClick(userWalletId: UserWalletId, name: String) { @@ -504,7 +543,7 @@ internal class WalletViewModel @Inject constructor( uiState = stateFactory.getSingleCurrencyLoadedBalanceState(maybeCryptoCurrencyStatus) maybeCryptoCurrencyStatus.onRight { status -> - cryptoCurrencyStatus = status + singleWalletCryptoCurrencyStatus = status updateButtons(userWalletId = userWalletId, currency = status.currency) } }