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 3cbec2c309..d98c38a33a 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 @@ -38,7 +38,7 @@ internal class DefaultCurrenciesRepository( ) : CurrenciesRepository { private val demoConfig = DemoConfig() - private val responseCurrenciesFactory = ResponseCryptoCurrenciesFactory(demoConfig) + private val responseCurrenciesFactory = ResponseCryptoCurrenciesFactory() private val cardCurrenciesFactory = CardCryptoCurrenciesFactory(demoConfig) private val userTokensResponseFactory = UserTokensResponseFactory() private val userTokensBackwardCompatibility = UserTokensBackwardCompatibility() @@ -315,6 +315,18 @@ internal class DefaultCurrenciesRepository( private suspend fun fetchTokens(userWallet: UserWallet) { val userWalletId = userWallet.walletId + if (demoConfig.isDemoCardId(userWallet.cardId) && userTokensStore.getSyncOrNull(key = userWalletId) == null) { + userTokensStore.store( + key = userWalletId, + value = userTokensResponseFactory.createUserTokensResponse( + currencies = cardCurrenciesFactory.createDefaultCoinsForMultiCurrencyCard(userWallet.scanResponse), + isGroupedByNetwork = false, + isSortedByBalance = false, + ), + ) + return + } + val response = safeApiCall( call = { tangemTechApi.getUserTokens(userWalletId.stringValue).bind().let { diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt index 37059161f1..fa7d68bd98 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt @@ -35,7 +35,7 @@ internal class DefaultNetworksRepository( private val demoConfig by lazy { DemoConfig() } private val cardCurrenciesFactory by lazy { CardCryptoCurrenciesFactory(demoConfig) } - private val responseCurrenciesFactory by lazy { ResponseCryptoCurrenciesFactory(demoConfig) } + private val responseCurrenciesFactory by lazy { ResponseCryptoCurrenciesFactory() } private val networkStatusFactory by lazy { NetworkStatusFactory() } override fun getNetworkStatusesUpdates( diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt index 3274fb2221..8f29419fc8 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCryptoCurrenciesFactory.kt @@ -4,17 +4,17 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Token import com.tangem.datasource.api.tangemTech.models.UserTokensResponse import com.tangem.domain.common.DerivationStyleProvider +import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.domain.common.extensions.toCoinId import com.tangem.domain.common.extensions.toNetworkId import com.tangem.domain.common.util.derivationStyleProvider -import com.tangem.domain.demo.DemoConfig import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.tokens.model.CryptoCurrency import timber.log.Timber import com.tangem.blockchain.common.Token as SdkToken -internal class ResponseCryptoCurrenciesFactory(private val demoConfig: DemoConfig) { +internal class ResponseCryptoCurrenciesFactory { fun createCurrency( currencyId: CryptoCurrency.ID, @@ -54,7 +54,7 @@ internal class ResponseCryptoCurrenciesFactory(private val demoConfig: DemoConfi val cardDerivationStyleProvider = scanResponse.derivationStyleProvider val card = scanResponse.card - if (demoConfig.isDemoCardId(card.cardId)) { + if (card.isTestCard) { blockchain = blockchain.getTestnetVersion() ?: blockchain } diff --git a/features/tokendetails/impl/build.gradle.kts b/features/tokendetails/impl/build.gradle.kts index c49cb6b805..c8d97e576c 100644 --- a/features/tokendetails/impl/build.gradle.kts +++ b/features/tokendetails/impl/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { /** Domain modules */ implementation(projects.domain.appCurrency) implementation(projects.domain.appCurrency.models) + implementation(projects.domain.demo) implementation(projects.domain.legacy) implementation(projects.domain.models) implementation(projects.domain.settings) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt index 1f15cbf061..2a25900715 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt @@ -3,13 +3,10 @@ package com.tangem.feature.tokendetails.presentation.tokendetails import androidx.compose.ui.graphics.Color import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.components.transactions.state.TxHistoryState +import com.tangem.core.ui.event.consumedEvent import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.res.TangemTheme -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsAppBarMenuConfig -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsTopAppBarConfig -import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenInfoBlockState +import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsPullToRefreshConfig import com.tangem.features.tokendetails.impl.R @@ -108,5 +105,6 @@ internal object TokenDetailsPreviewData { bottomSheetConfig = null, isBalanceHidden = false, isMarketPriceAvailable = false, + event = consumedEvent(), ) } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsState.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsState.kt index b738e3f2a0..15f290adde 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsState.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenDetailsState.kt @@ -4,6 +4,8 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.core.ui.components.transactions.state.TxHistoryState +import com.tangem.core.ui.event.StateEvent +import com.tangem.core.ui.extensions.TextReference import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsPullToRefreshConfig @@ -23,4 +25,5 @@ internal data class TokenDetailsState( val bottomSheetConfig: TangemBottomSheetConfig?, val isBalanceHidden: Boolean, val isMarketPriceAvailable: Boolean, + val event: StateEvent, ) \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt index 23cb6c819b..e92142e90c 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt @@ -2,6 +2,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.components.transactions.state.TxHistoryState +import com.tangem.core.ui.event.consumedEvent import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.networkIconResId import com.tangem.core.ui.res.TangemTheme @@ -54,6 +55,7 @@ internal class TokenDetailsSkeletonStateConverter( bottomSheetConfig = null, isBalanceHidden = true, isMarketPriceAvailable = value.id.rawCurrencyId != null, + event = consumedEvent(), ) } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt index 3c0f5ba562..b8a29d17cb 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt @@ -9,6 +9,9 @@ import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBot import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig import com.tangem.core.ui.components.transactions.state.TxHistoryState +import com.tangem.core.ui.event.consumedEvent +import com.tangem.core.ui.event.triggeredEvent +import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrency @@ -225,4 +228,20 @@ internal class TokenDetailsStateFactory( val state = currentStateProvider() return state.copy(notifications = notificationConverter.removeRentInfo(state)) } + + fun getStateAndTriggerEvent( + state: TokenDetailsState, + errorMessage: TextReference, + setUiState: (TokenDetailsState) -> Unit, + ): TokenDetailsState { + return state.copy( + event = triggeredEvent( + data = errorMessage, + onConsume = { + val currentState = currentStateProvider() + setUiState(currentState.copy(event = consumedEvent())) + }, + ), + ) + } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index d7fda33f38..e5e3b0945e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt @@ -11,10 +11,14 @@ import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.util.fastForEach import androidx.paging.compose.collectAsLazyPagingItems @@ -29,6 +33,10 @@ import com.tangem.core.ui.components.transactions.Transaction import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.components.transactions.txHistoryItems +import com.tangem.core.ui.event.EventEffect +import com.tangem.core.ui.event.StateEvent +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState @@ -46,8 +54,10 @@ import kotlinx.collections.immutable.PersistentList internal fun TokenDetailsScreen(state: TokenDetailsState) { BackHandler(onBack = state.topAppBarConfig.onBackClick) + val snackbarHostState = remember { SnackbarHostState() } Scaffold( topBar = { TokenDetailsTopAppBar(config = state.topAppBarConfig) }, + snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, containerColor = TangemTheme.colors.background.secondary, ) { scaffoldPaddings -> val pullRefreshState = rememberPullRefreshState( @@ -138,17 +148,17 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) { TokenDetailsDialogs(state = state) state.bottomSheetConfig?.let { config -> - if (config.isShow) { - when (config.content) { - is TokenReceiveBottomSheetConfig -> { - TokenReceiveBottomSheet(config = config) - } - is ChooseAddressBottomSheetConfig -> { - ChooseAddressBottomSheet(config = config) - } + when (config.content) { + is TokenReceiveBottomSheetConfig -> { + TokenReceiveBottomSheet(config = config) + } + is ChooseAddressBottomSheetConfig -> { + ChooseAddressBottomSheet(config = config) } } } + + TokenDetailsEventEffect(snackbarHostState = snackbarHostState, event = state.event) } } @@ -169,6 +179,18 @@ private fun PendingTxsBlock( } } +@Composable +internal fun TokenDetailsEventEffect(snackbarHostState: SnackbarHostState, event: StateEvent) { + val resources = LocalContext.current.resources + + EventEffect( + event = event, + onTrigger = { value -> + snackbarHostState.showSnackbar(message = value.resolveReference(resources)) + }, + ) +} + @Preview @Composable private fun Preview_TokenDetailsScreen_LightTheme() { 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 0b4854dc25..d9b9707177 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,10 +11,12 @@ import com.tangem.common.Provider import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel import com.tangem.core.ui.components.transactions.state.TxHistoryState +import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.IsBalanceHiddenUseCase import com.tangem.domain.balancehiding.ListenToFlipsUseCase +import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.tokens.* import com.tangem.domain.tokens.legacy.TradeCryptoAction @@ -33,6 +35,7 @@ import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory +import com.tangem.features.tokendetails.impl.R import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder @@ -65,6 +68,7 @@ internal class TokenDetailsViewModel @Inject constructor( private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase, private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase, private val walletManagersFacade: WalletManagersFacade, + private val isDemoCardUseCase: IsDemoCardUseCase, private val reduxStateHolder: ReduxStateHolder, private val analyticsEventsHandler: AnalyticsEventHandler, savedStateHandle: SavedStateHandle, @@ -225,16 +229,19 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onBuyClick() { analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonBuy(cryptoCurrency.symbol)) - val status = cryptoCurrencyStatus ?: return - viewModelScope.launch(dispatchers.io) { - reduxStateHolder.dispatch( - TradeCryptoAction.New.Buy( - userWallet = getUserWalletUseCase(userWalletId).getOrElse { return@launch }, - cryptoCurrencyStatus = status, - appCurrencyCode = selectedAppCurrencyFlow.value.code, - ), - ) + showErrorIfDemoModeOrElse { + val status = cryptoCurrencyStatus ?: return@showErrorIfDemoModeOrElse + + viewModelScope.launch(dispatchers.io) { + reduxStateHolder.dispatch( + TradeCryptoAction.New.Buy( + userWallet = getUserWalletUseCase(userWalletId).getOrElse { return@launch }, + cryptoCurrencyStatus = status, + appCurrencyCode = selectedAppCurrencyFlow.value.code, + ), + ) + } } } @@ -313,13 +320,16 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onSellClick() { analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonSell(cryptoCurrency.symbol)) - val status = cryptoCurrencyStatus ?: return - reduxStateHolder.dispatch( - TradeCryptoAction.New.Sell( - cryptoCurrencyStatus = status, - appCurrencyCode = selectedAppCurrencyFlow.value.code, - ), - ) + showErrorIfDemoModeOrElse { + val status = cryptoCurrencyStatus ?: return@showErrorIfDemoModeOrElse + + reduxStateHolder.dispatch( + TradeCryptoAction.New.Sell( + cryptoCurrencyStatus = status, + appCurrencyCode = selectedAppCurrencyFlow.value.code, + ), + ) + } } override fun onSwapClick() { @@ -355,6 +365,10 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onExploreClick() { analyticsEventsHandler.send(TokenScreenAnalyticsEvent.ButtonExplore(cryptoCurrency.symbol)) + showErrorIfDemoModeOrElse(action = ::openExplorer) + } + + private fun openExplorer() { viewModelScope.launch(dispatchers.io) { val addresses = walletManagersFacade.getAddress( userWalletId = userWalletId, @@ -375,6 +389,23 @@ internal class TokenDetailsViewModel @Inject constructor( } } + private fun showErrorIfDemoModeOrElse(action: () -> Unit) { + viewModelScope.launch(dispatchers.main) { + val wallet = getUserWalletUseCase(userWalletId = userWalletId).getOrElse { return@launch } + + if (isDemoCardUseCase(cardId = wallet.cardId)) { + uiState = stateFactory.getStateWithClosedBottomSheet() + uiState = stateFactory.getStateAndTriggerEvent( + state = uiState, + errorMessage = resourceReference(id = R.string.alert_demo_feature_disabled), + setUiState = { uiState = it }, + ) + } else { + action() + } + } + } + override fun onAddressTypeSelected(addressModel: AddressModel) { viewModelScope.launch { router.openUrl( 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 b53e790e88..52ba8578cd 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 @@ -130,9 +130,9 @@ internal class WalletViewModel @Inject constructor( private val neverToSuggestRateAppUseCase: NeverToSuggestRateAppUseCase, private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase, private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase, + private val isDemoCardUseCase: IsDemoCardUseCase, wasCardScannedUseCase: WasCardScannedUseCase, isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase, - isDemoCardUseCase: IsDemoCardUseCase, isNeedToBackupUseCase: IsNeedToBackupUseCase, getMissedAddressesCryptoCurrenciesUseCase: GetMissedAddressesCryptoCurrenciesUseCase, // endregion Parameters @@ -608,15 +608,15 @@ internal class WalletViewModel @Inject constructor( event = TokenScreenAnalyticsEvent.ButtonBuy(cryptoCurrencyStatus.currency.symbol), ) - val wallet = getWallet(index = state.walletsListConfig.selectedWalletIndex) - - reduxStateHolder.dispatch( - TradeCryptoAction.New.Buy( - userWallet = wallet, - cryptoCurrencyStatus = cryptoCurrencyStatus, - appCurrencyCode = selectedAppCurrencyFlow.value.code, - ), - ) + showErrorIfDemoModeOrElse { + reduxStateHolder.dispatch( + TradeCryptoAction.New.Buy( + userWallet = getWallet(index = state.walletsListConfig.selectedWalletIndex), + cryptoCurrencyStatus = cryptoCurrencyStatus, + appCurrencyCode = selectedAppCurrencyFlow.value.code, + ), + ) + } } override fun onSwapClick(cryptoCurrencyStatus: CryptoCurrencyStatus) { @@ -755,12 +755,14 @@ internal class WalletViewModel @Inject constructor( event = TokenScreenAnalyticsEvent.ButtonSell(cryptoCurrencyStatus.currency.symbol), ) - reduxStateHolder.dispatch( - TradeCryptoAction.New.Sell( - cryptoCurrencyStatus = cryptoCurrencyStatus, - appCurrencyCode = selectedAppCurrencyFlow.value.code, - ), - ) + showErrorIfDemoModeOrElse { + reduxStateHolder.dispatch( + action = TradeCryptoAction.New.Sell( + cryptoCurrencyStatus = cryptoCurrencyStatus, + appCurrencyCode = selectedAppCurrencyFlow.value.code, + ), + ) + } } override fun onManageTokensClick() { @@ -803,22 +805,39 @@ internal class WalletViewModel @Inject constructor( } override fun onExploreClick() { - viewModelScope.launch(dispatchers.io) { - val wallet = getWallet( - index = requireNotNull(uiState as? WalletState.ContentState).walletsListConfig.selectedWalletIndex, - ) - val currencyStatus = getPrimaryCurrencyStatusUpdatesUseCase(wallet.walletId) - .firstOrNull() - ?.getOrNull() + showErrorIfDemoModeOrElse(action = ::openExplorer) + } - if (currencyStatus != null) { - router.openUrl( - url = getExploreUrlUseCase( - userWalletId = wallet.walletId, - network = currencyStatus.currency.network, - ), - ) - } + private fun openExplorer() { + val state = uiState as? WalletState.ContentState ?: return + + viewModelScope.launch(dispatchers.main) { + val currencyStatus = singleWalletCryptoCurrencyStatus ?: return@launch + + router.openUrl( + url = getExploreUrlUseCase( + userWalletId = getWallet(index = state.walletsListConfig.selectedWalletIndex).walletId, + network = currencyStatus.currency.network, + ), + ) + } + } + + private fun showErrorIfDemoModeOrElse(action: () -> Unit) { + val state = uiState as? WalletState.ContentState ?: return + val cardId = getWallet(index = state.walletsListConfig.selectedWalletIndex).cardId + + if (isDemoCardUseCase(cardId = cardId)) { + uiState = stateFactory.getStateWithClosedBottomSheet() + uiState = stateFactory.getStateAndTriggerEvent( + state = uiState, + event = WalletEvent.ShowError( + text = resourceReference(id = R.string.alert_demo_feature_disabled), + ), + setUiState = { uiState = it }, + ) + } else { + action() } } @@ -934,22 +953,13 @@ internal class WalletViewModel @Inject constructor( } override fun onTransactionClick(txHash: String) { - viewModelScope.launch(dispatchers.io) { - val wallet = getWallet( - index = requireNotNull(uiState as? WalletState.ContentState).walletsListConfig.selectedWalletIndex, + singleWalletCryptoCurrencyStatus?.let { currencyStatus -> + router.openUrl( + url = getExplorerTransactionUrlUseCase( + txHash = txHash, + networkId = currencyStatus.currency.network.id, + ), ) - val currencyStatus = getPrimaryCurrencyStatusUpdatesUseCase(wallet.walletId) - .firstOrNull() - ?.getOrNull() - - if (currencyStatus != null) { - router.openUrl( - url = getExplorerTransactionUrlUseCase( - txHash = txHash, - networkId = currencyStatus.currency.network.id, - ), - ) - } } }