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 4606659408..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 @@ -186,7 +186,6 @@ internal class DefaultNetworksRepository( is UpdateWalletManagerResult.NoAccount, -> Unit is UpdateWalletManagerResult.Unreachable, - is UpdateWalletManagerResult.UnreachableWithoutAddresses, is UpdateWalletManagerResult.MissedDerivation, -> { Timber.w( diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkStatusFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkStatusFactory.kt index 9170ad03aa..1fa432ab89 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkStatusFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkStatusFactory.kt @@ -19,9 +19,8 @@ internal class NetworkStatusFactory { network = network, value = when (result) { is UpdateWalletManagerResult.MissedDerivation -> NetworkStatus.MissedDerivation - is UpdateWalletManagerResult.UnreachableWithoutAddresses -> NetworkStatus.UnreachableWithoutAddresses is UpdateWalletManagerResult.Unreachable -> NetworkStatus.Unreachable( - address = getNetworkAddress(result.selectedAddress, result.addresses), + address = getNetworkAddressOrNull(result.selectedAddress, result.addresses), ) is UpdateWalletManagerResult.NoAccount -> NetworkStatus.NoAccount( address = getNetworkAddress(result.selectedAddress, result.addresses), @@ -96,6 +95,14 @@ internal class NetworkStatusFactory { return transactions.mapTo(hashSetOf()) { it.txHistoryItem } } + private fun getNetworkAddressOrNull(selectedAddress: String?, availableAddresses: Set
?): NetworkAddress? { + if (selectedAddress == null || availableAddresses == null) { + return null + } + + return getNetworkAddress(selectedAddress, availableAddresses) + } + private fun getNetworkAddress(selectedAddress: String, availableAddresses: Set
): NetworkAddress { val defaultAddress = availableAddresses .firstOrNull { it.value == selectedAddress } diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt index 8844494bfb..87850c1161 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt @@ -132,7 +132,7 @@ class DefaultWalletManagersFacade( val walletManager = getOrCreateWalletManager(userWalletId, blockchain, derivationPath) if (walletManager == null || blockchain == Blockchain.Unknown) { Timber.w("Unable to get a wallet manager for blockchain: $blockchain") - return UpdateWalletManagerResult.UnreachableWithoutAddresses + return UpdateWalletManagerResult.Unreachable() } return getLastWalletManagerResult(walletManager) @@ -246,7 +246,7 @@ class DefaultWalletManagersFacade( ) if (walletManager == null || blockchain == Blockchain.Unknown) { Timber.w("Unable to create or find a wallet manager for blockchain: $blockchain") - return UpdateWalletManagerResult.UnreachableWithoutAddresses + return UpdateWalletManagerResult.Unreachable() } updateWalletManagerTokensIfNeeded(walletManager, extraTokens) diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/UpdateWalletManagerResult.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/UpdateWalletManagerResult.kt index b13e23c8ec..8ea8b9ab29 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/UpdateWalletManagerResult.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/UpdateWalletManagerResult.kt @@ -6,11 +6,9 @@ sealed class UpdateWalletManagerResult { object MissedDerivation : UpdateWalletManagerResult() - object UnreachableWithoutAddresses : UpdateWalletManagerResult() - data class Unreachable( - val selectedAddress: String, - val addresses: Set
, + val selectedAddress: String? = null, + val addresses: Set
? = null, ) : UpdateWalletManagerResult() data class Verified( diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt index 670c5339a8..58eaf3cff6 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt @@ -50,8 +50,6 @@ data class CryptoCurrencyStatus( /** Represents the Loading state of a cryptocurrency, typically while fetching its details. */ object Loading : Status(isError = false) - object UnreachableWithoutAddresses : Status(isError = true) - /** * Represents a state where the cryptocurrency is not reachable. * @@ -62,7 +60,7 @@ data class CryptoCurrencyStatus( data class Unreachable( override val priceChange: BigDecimal?, override val fiatRate: BigDecimal?, - override val networkAddress: NetworkAddress, + override val networkAddress: NetworkAddress?, ) : Status(isError = true) /** Represents a state where the cryptocurrency's network amount not found. */ diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/NetworkStatus.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/NetworkStatus.kt index 230f59d531..60fdf9e7b8 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/NetworkStatus.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/NetworkStatus.kt @@ -21,14 +21,12 @@ data class NetworkStatus( */ sealed class Status - object UnreachableWithoutAddresses : Status() - /** * Represents the state where the network is unreachable. * * @property address Network addresses. */ - data class Unreachable(val address: NetworkAddress) : Status() + data class Unreachable(val address: NetworkAddress?) : Status() /** * Represents the state where a derivation has been missed. diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt index 7c4e946f3a..b02828d2c3 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt @@ -16,7 +16,6 @@ internal class CurrencyStatusOperations( return when (val status = networkStatus?.value) { null -> CryptoCurrencyStatus.Loading is NetworkStatus.MissedDerivation -> createMissedDerivationStatus() - is NetworkStatus.UnreachableWithoutAddresses -> CryptoCurrencyStatus.UnreachableWithoutAddresses is NetworkStatus.Unreachable -> createUnreachableStatus(status) is NetworkStatus.NoAccount -> createNoAccountStatus(status) is NetworkStatus.Verified -> createStatus(status) diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt index 4009263f5e..78db26e8a0 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt @@ -22,7 +22,6 @@ internal class TokenListFiatBalanceOperations( } is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, is CryptoCurrencyStatus.NoAmount, is CryptoCurrencyStatus.NoQuote, -> { diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt index 3641133165..0f03851309 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt @@ -45,7 +45,7 @@ internal object MockNetworks { val networkStatus1 = NetworkStatus( network = network1, - value = NetworkStatus.UnreachableWithoutAddresses, + value = NetworkStatus.Unreachable(address = null), ) val networkStatus2 = NetworkStatus( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsAnalyticsEvent.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsAnalyticsEvent.kt new file mode 100644 index 0000000000..8c5f6c268f --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsAnalyticsEvent.kt @@ -0,0 +1,27 @@ +package com.tangem.feature.tokendetails.presentation.tokendetails.analytics + +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.utils.toAnalyticsParams + +internal open class TokenDetailsAnalyticsEvent( + event: String, + params: Map = mapOf(), +) : AnalyticsEvent(category = "Token", event, params) { + + open class Notice( + event: String, + params: Map = mapOf(), + ) : TokenDetailsAnalyticsEvent(event = "Notice - $event", params) { + + class NetworkUnreachable(currency: CryptoCurrency) : Notice( + event = "Network Unreachable", + params = currency.toAnalyticsParams(), + ) + + class NotEnoughFee(currency: CryptoCurrency) : Notice( + event = "Not Enough Fee", + params = currency.toAnalyticsParams(), + ) + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsCurrencyStatusAnalyticsSender.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsCurrencyStatusAnalyticsSender.kt new file mode 100644 index 0000000000..9a17d9be3a --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsCurrencyStatusAnalyticsSender.kt @@ -0,0 +1,38 @@ +package com.tangem.feature.tokendetails.presentation.tokendetails.analytics + +import arrow.core.Either +import arrow.core.getOrElse +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.domain.tokens.error.CurrencyStatusError +import com.tangem.domain.tokens.model.CryptoCurrencyStatus + +internal class TokenDetailsCurrencyStatusAnalyticsSender( + private val analyticsEventHandler: AnalyticsEventHandler, +) { + + fun send(maybeCurrencyStatus: Either) { + val currencyStatus = maybeCurrencyStatus.getOrElse { return } + val event = getEvent(currencyStatus) + + if (event != null) { + analyticsEventHandler.send(event) + } + } + + private fun getEvent(currencyStatus: CryptoCurrencyStatus): AnalyticsEvent? { + return when (currencyStatus.value) { + is CryptoCurrencyStatus.Custom, + is CryptoCurrencyStatus.Loaded, + is CryptoCurrencyStatus.Loading, + is CryptoCurrencyStatus.MissedDerivation, + is CryptoCurrencyStatus.NoAccount, + is CryptoCurrencyStatus.NoAmount, + is CryptoCurrencyStatus.NoQuote, + -> null + is CryptoCurrencyStatus.Unreachable -> TokenDetailsAnalyticsEvent.Notice.NetworkUnreachable( + currency = currencyStatus.currency, + ) + } + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt new file mode 100644 index 0000000000..78a69221f1 --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt @@ -0,0 +1,45 @@ +package com.tangem.feature.tokendetails.presentation.tokendetails.analytics + +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState +import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification + +internal class TokenDetailsNotificationsAnalyticsSender( + private val cryptoCurrency: CryptoCurrency, + private val analyticsEventHandler: AnalyticsEventHandler, +) { + + fun send(displayedUiState: TokenDetailsState, newNotifications: List) { + if (newNotifications.isEmpty()) return + if (displayedUiState.pullToRefreshConfig.isRefreshing) return + + val eventsFromNewWarnings = getEvents(newNotifications) + val eventsFromDisplayedWarnings = getEvents(displayedUiState.notifications) + val eventsToSend = eventsFromNewWarnings.filter { it !in eventsFromDisplayedWarnings } + + eventsToSend.forEach { event -> + analyticsEventHandler.send(event) + } + } + + private fun getEvents(notifications: List): Set { + return notifications.mapNotNullTo(mutableSetOf(), ::getEvent) + } + + private fun getEvent(notification: TokenDetailsNotification): AnalyticsEvent? { + return when (notification) { + is TokenDetailsNotification.NetworkFee -> TokenDetailsAnalyticsEvent.Notice.NotEnoughFee( + currency = cryptoCurrency, + ) + is TokenDetailsNotification.NetworksUnreachable, + is TokenDetailsNotification.ExistentialDeposit, + is TokenDetailsNotification.HasPendingTransactions, + is TokenDetailsNotification.NetworksNoAccount, + is TokenDetailsNotification.RentInfo, + is TokenDetailsNotification.SwapPromo, + -> null + } + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/utils/CryptoCurrencyMapper.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/utils/CryptoCurrencyMapper.kt new file mode 100644 index 0000000000..d63835def0 --- /dev/null +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/utils/CryptoCurrencyMapper.kt @@ -0,0 +1,10 @@ +package com.tangem.feature.tokendetails.presentation.tokendetails.analytics.utils + +import com.tangem.domain.tokens.model.CryptoCurrency + +internal fun CryptoCurrency.toAnalyticsParams(): Map { + return mapOf( + "Token" to symbol, + "Blockchain" to network.currencySymbol, + ) +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt index 06b073e5cd..142947657c 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt @@ -78,7 +78,6 @@ internal class TokenDetailsLoadedBalanceConverter( is CryptoCurrencyStatus.Loading -> TokenDetailsBalanceBlockState.Loading(currentState.actionButtons) is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, is CryptoCurrencyStatus.NoAmount, -> TokenDetailsBalanceBlockState.Error(currentState.actionButtons) } @@ -102,7 +101,6 @@ internal class TokenDetailsLoadedBalanceConverter( is CryptoCurrencyStatus.Custom, is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, is CryptoCurrencyStatus.NoAmount, -> status.toContentConfig(currencySymbol) } 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 c3d7fce391..cf03f55529 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 @@ -40,6 +40,8 @@ import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.feature.swap.domain.SwapTransactionRepository import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter +import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsCurrencyStatusAnalyticsSender +import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsNotificationsAnalyticsSender import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory @@ -57,7 +59,6 @@ import kotlinx.coroutines.launch import timber.log.Timber import java.math.BigDecimal import javax.inject.Inject -import kotlin.properties.Delegates @Suppress("LongParameterList", "LargeClass", "TooManyFunctions") @HiltViewModel @@ -95,7 +96,7 @@ internal class TokenDetailsViewModel @Inject constructor( private val cryptoCurrency: CryptoCurrency = savedStateHandle[TokenDetailsRouter.CRYPTO_CURRENCY_KEY] ?: error("This screen can't open without `CryptoCurrency`") - var router by Delegates.notNull() + lateinit var router: InnerTokenDetailsRouter private val marketPriceJobHolder = JobHolder() private val refreshStateJobHolder = JobHolder() @@ -115,7 +116,7 @@ internal class TokenDetailsViewModel @Inject constructor( decimals = cryptoCurrency.decimals, ) - private val exchangeStatusFactory by lazy { + private val exchangeStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) { ExchangeStatusFactory( swapTransactionRepository = swapTransactionRepository, swapRepository = swapRepository, @@ -132,6 +133,17 @@ internal class TokenDetailsViewModel @Inject constructor( ) } + private val notificationsAnalyticsSender by lazy(mode = LazyThreadSafetyMode.NONE) { + TokenDetailsNotificationsAnalyticsSender( + cryptoCurrency = cryptoCurrency, + analyticsEventHandler = analyticsEventsHandler, + ) + } + + private val currencyStatusAnalyticsSender by lazy(mode = LazyThreadSafetyMode.NONE) { + TokenDetailsCurrencyStatusAnalyticsSender(analyticsEventsHandler) + } + var uiState: TokenDetailsState by mutableStateOf(stateFactory.getInitialState(cryptoCurrency)) private set @@ -188,7 +200,11 @@ internal class TokenDetailsViewModel @Inject constructor( isSingleWalletWithTokens = wallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(), ) .distinctUntilChanged() - .onEach { uiState = stateFactory.getStateWithNotifications(it) } + .onEach { + val updatedState = stateFactory.getStateWithNotifications(it) + notificationsAnalyticsSender.send(uiState, updatedState.notifications) + uiState = updatedState + } .launchIn(viewModelScope) .saveIn(warningsJobHolder) } @@ -203,13 +219,14 @@ internal class TokenDetailsViewModel @Inject constructor( isSingleWalletWithTokens = wallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(), ) .distinctUntilChanged() - .onEach { either -> - uiState = stateFactory.getCurrencyLoadedBalanceState(either) - either.onRight { status -> + .onEach { maybeCurrencyStatus -> + uiState = stateFactory.getCurrencyLoadedBalanceState(maybeCurrencyStatus) + maybeCurrencyStatus.onRight { status -> cryptoCurrencyStatus = status updateButtons(userWalletId = userWalletId, currencyStatus = status) updateWarnings(status) } + currencyStatusAnalyticsSender.send(maybeCurrencyStatus) } .flowOn(dispatchers.io) .launchIn(viewModelScope) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index 8807297f9f..fa60d699bf 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -56,6 +56,7 @@ internal class DefaultWalletRouter( if (walletFeatureToggles.isWalletsScrollingPreviewEnabled) { val viewModel = hiltViewModel().apply { setWalletRouter(router = this@DefaultWalletRouter) + subscribeToLifecycle(LocalLifecycleOwner.current) } WalletScreenV2(state = viewModel.uiState.collectAsStateWithLifecycle().value) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt index b540cf8dc7..8ddb6b3b90 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt @@ -12,6 +12,7 @@ import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.Basic import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState +import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider import dagger.hilt.android.scopes.ViewModelScoped import java.math.BigDecimal import javax.inject.Inject @@ -20,9 +21,11 @@ import javax.inject.Inject internal class TokenListAnalyticsSender @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, private val checkIsWalletToppedUpUseCase: CheckIsWalletToppedUpUseCase, + private val screenLifecycleProvider: ScreenLifecycleProvider, ) { suspend fun send(displayedUiState: WalletState?, userWallet: UserWallet, tokenList: TokenList) { + if (screenLifecycleProvider.isBackground) return if (displayedUiState == null || displayedUiState.pullToRefreshConfig.isRefreshing) return if (tokenList.totalFiatBalance is TokenList.FiatBalance.Loading) return @@ -117,8 +120,7 @@ internal class TokenListAnalyticsSender @Inject constructor( private fun sendUnreachableNetworksEventIfNeeded(currenciesStatuses: List) { val hasUnreachableCurrencies = currenciesStatuses.any { - it.value is CryptoCurrencyStatus.Unreachable || - it.value is CryptoCurrencyStatus.UnreachableWithoutAddresses + it.value is CryptoCurrencyStatus.Unreachable } if (hasUnreachableCurrencies) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt index d0b54d53e8..d28b7fdc06 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt @@ -5,15 +5,18 @@ import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState +import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider import dagger.hilt.android.scopes.ViewModelScoped import javax.inject.Inject @ViewModelScoped internal class WalletWarningsAnalyticsSender @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, + private val screenLifecycleProvider: ScreenLifecycleProvider, ) { fun send(displayedUiState: WalletState?, newWarnings: List) { + if (screenLifecycleProvider.isBackground) return if (newWarnings.isEmpty()) return if (displayedUiState == null || displayedUiState.pullToRefreshConfig.isRefreshing) return diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt index 91a922a474..75ce18f490 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt @@ -73,7 +73,6 @@ internal class WalletSingleCurrencyLoadedBalanceConverter( is CryptoCurrencyStatus.Custom, is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, is CryptoCurrencyStatus.NoQuote, -> MarketPriceBlockState.Error(currencySymbol) } @@ -117,7 +116,6 @@ internal class WalletSingleCurrencyLoadedBalanceConverter( is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Custom, is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, -> { WalletCardState.Error( id = selectedWallet.id, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/SingleWalletCardStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/SingleWalletCardStateConverter.kt index 9d443c6db9..e54cf09dfa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/SingleWalletCardStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/SingleWalletCardStateConverter.kt @@ -21,7 +21,6 @@ internal class SingleWalletCardStateConverter( is CryptoCurrencyStatus.Custom, is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, -> value.toErrorState() is CryptoCurrencyStatus.NoQuote, is CryptoCurrencyStatus.Loaded, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/SingleWalletMarketPriceConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/SingleWalletMarketPriceConverter.kt index cbd1666996..1f1237f976 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/SingleWalletMarketPriceConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/SingleWalletMarketPriceConverter.kt @@ -25,7 +25,6 @@ internal class SingleWalletMarketPriceConverter( is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.NoQuote, is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, -> MarketPriceBlockState.Error(value.currencySymbol) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/TokenItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/TokenItemStateConverter.kt index fad1edda6b..e3b9517efb 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/TokenItemStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/TokenItemStateConverter.kt @@ -28,7 +28,6 @@ internal class TokenItemStateConverter( -> value.mapToTokenItemState() is CryptoCurrencyStatus.MissedDerivation -> value.mapToNoAddressTokenItemState() is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, is CryptoCurrencyStatus.NoAmount, -> value.mapToUnreachableTokenItemState() } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/VisaWalletCardStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/VisaWalletCardStateConverter.kt index 87e613c872..56766efc40 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/VisaWalletCardStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state2/transformers/converter/VisaWalletCardStateConverter.kt @@ -22,7 +22,6 @@ internal class VisaWalletCardStateConverter( is CryptoCurrencyStatus.Custom, is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, -> value.toErrorState() is CryptoCurrencyStatus.NoQuote, is CryptoCurrencyStatus.Loaded, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriber.kt index 46f32dceff..de0c3f2634 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/PrimaryCurrencySubscriber.kt @@ -73,7 +73,6 @@ internal class PrimaryCurrencySubscriber( -> createCardBalanceState(fiatAmount) is CryptoCurrencyStatus.NoQuote -> AnalyticsParam.CardBalanceState.NoRate is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, -> AnalyticsParam.CardBalanceState.BlockchainError is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Loading, 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 10be1a3537..e9ef5cc769 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 @@ -28,7 +28,6 @@ internal class CryptoCurrencyStatusToTokenItemConverter( -> value.mapToTokenItemState() is CryptoCurrencyStatus.MissedDerivation -> value.mapToNoAddressTokenItemState() is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, is CryptoCurrencyStatus.NoAmount, -> value.mapToUnreachableTokenItemState() } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/ScreenLifecycleProvider.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/ScreenLifecycleProvider.kt new file mode 100644 index 0000000000..5ebccf6c11 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/ScreenLifecycleProvider.kt @@ -0,0 +1,21 @@ +package com.tangem.feature.wallet.presentation.wallet.utils + +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import dagger.hilt.android.scopes.ViewModelScoped +import javax.inject.Inject + +@ViewModelScoped +internal class ScreenLifecycleProvider @Inject constructor() : DefaultLifecycleObserver { + + var isBackground: Boolean = true + private set + + override fun onResume(owner: LifecycleOwner) { + isBackground = false + } + + override fun onPause(owner: LifecycleOwner) { + isBackground = true + } +} \ No newline at end of file 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 4489a20d4c..e2b21cc95f 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 @@ -1231,7 +1231,6 @@ internal class WalletViewModel @Inject constructor( } is CryptoCurrencyStatus.NoQuote -> AnalyticsParam.CardBalanceState.NoRate is CryptoCurrencyStatus.Unreachable, - is CryptoCurrencyStatus.UnreachableWithoutAddresses, -> AnalyticsParam.CardBalanceState.BlockchainError is CryptoCurrencyStatus.MissedDerivation, is CryptoCurrencyStatus.Loading, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModelV2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModelV2.kt index c9e4978821..fed5c1dc6e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModelV2.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModelV2.kt @@ -1,5 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.tangem.core.analytics.api.AnalyticsEventHandler @@ -21,6 +22,7 @@ import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateControlle import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState import com.tangem.feature.wallet.presentation.wallet.state2.transformers.* import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletEventSender +import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2 import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -33,7 +35,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject -import kotlin.properties.Delegates @Suppress("LongParameterList") @HiltViewModel @@ -53,11 +54,12 @@ internal class WalletViewModelV2 @Inject constructor( analyticsEventsHandler: AnalyticsEventHandler, private val dispatchers: CoroutineDispatcherProvider, private val reduxStateHolder: ReduxStateHolder, + private val screenLifecycleProvider: ScreenLifecycleProvider, ) : ViewModel() { val uiState: StateFlow = stateHolder.uiState - private var router: InnerWalletRouter by Delegates.notNull() + private lateinit var router: InnerWalletRouter private var walletsUpdateJobHolder: JobHolder = JobHolder() init { @@ -75,6 +77,10 @@ internal class WalletViewModelV2 @Inject constructor( clickIntents.initialize(router, viewModelScope) } + fun subscribeToLifecycle(lifecycleOwner: LifecycleOwner) { + lifecycleOwner.lifecycle.addObserver(screenLifecycleProvider) + } + override fun onCleared() { super.onCleared() stateHolder.clear()