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 700cd6bdfc..7d8abc0123 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 @@ -93,13 +93,15 @@ internal object TokensDomainModule { networksRepository: NetworksRepository, stakingRepository: StakingRepository, dispatchers: CoroutineDispatcherProvider, + tokensFeatureToggles: TokensFeatureToggles, ): GetCurrencyStatusUpdatesUseCase { return GetCurrencyStatusUpdatesUseCase( - currenciesRepository, - quotesRepository, - networksRepository, - stakingRepository, - dispatchers, + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + stakingRepository = stakingRepository, + dispatchers = dispatchers, + tokensFeatureToggles = tokensFeatureToggles, ) } @@ -131,6 +133,7 @@ internal object TokensDomainModule { currencyChecksRepository: CurrencyChecksRepository, stakingRepository: StakingRepository, dispatchers: CoroutineDispatcherProvider, + tokensFeatureToggles: TokensFeatureToggles, ): GetCurrencyWarningsUseCase { return GetCurrencyWarningsUseCase( walletManagersFacade = walletManagersFacade, @@ -140,6 +143,7 @@ internal object TokensDomainModule { currencyChecksRepository = currencyChecksRepository, stakingRepository = stakingRepository, dispatchers = dispatchers, + tokensFeatureToggles = tokensFeatureToggles, ) } @@ -363,12 +367,14 @@ internal object TokensDomainModule { quotesRepository: QuotesRepository, networksRepository: NetworksRepository, stakingRepository: StakingRepository, + tokensFeatureToggles: TokensFeatureToggles, ): GetWalletTotalBalanceUseCase { return GetWalletTotalBalanceUseCase( currenciesRepository = currenciesRepository, quotesRepository = quotesRepository, networksRepository = networksRepository, stakingRepository = stakingRepository, + tokensFeatureToggles = tokensFeatureToggles, ) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt index e5d163c5ab..c98d04ca29 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/network/DefaultNetworksStatusesStore.kt @@ -46,14 +46,6 @@ internal class DefaultNetworksStatusesStore( if (cachedStatuses.isNotEmpty()) { send(cachedStatuses) - - /** - * Required for storing cache data. - * This will help to recognize networks that are still uploaded. - * - * @see mergeStatuses - */ - storeAll(key = key, values = cachedStatuses) } runtimeDataStore.get(provideStringKey(key)) @@ -118,8 +110,18 @@ internal class DefaultNetworksStatusesStore( return networks.mapNotNullTo(hashSetOf()) { network -> val runtimeStatus = runtimeStatuses.firstOrNull { it.network == network } - if (runtimeStatus == null || runtimeStatus.value is NetworkStatus.Unreachable) { - getCachedStatusIfPossible(cachedStatuses = cachedStatuses, network = network) + if (runtimeStatus == null) { + getCachedStatusIfPossible( + cachedStatuses = cachedStatuses, + network = network, + source = StatusSource.CACHE, + ) + } else if (runtimeStatus.value is NetworkStatus.Unreachable) { + getCachedStatusIfPossible( + cachedStatuses = cachedStatuses, + network = network, + source = StatusSource.ONLY_CACHE, + ) ?: runtimeStatus } else { runtimeStatus @@ -127,12 +129,16 @@ internal class DefaultNetworksStatusesStore( } } - private fun getCachedStatusIfPossible(cachedStatuses: Set, network: Network): NetworkStatus? { + private fun getCachedStatusIfPossible( + cachedStatuses: Set, + network: Network, + source: StatusSource, + ): NetworkStatus? { val cached = cachedStatuses.firstOrNull { it.network == network } ?: return null val updatedCachedStatus = when (val status = cached.value) { - is NetworkStatus.NoAccount -> status.copy(source = StatusSource.ONLY_CACHE) - is NetworkStatus.Verified -> status.copy(source = StatusSource.ONLY_CACHE) + is NetworkStatus.NoAccount -> status.copy(source = source) + is NetworkStatus.Verified -> status.copy(source = source) is NetworkStatus.Unreachable, is NetworkStatus.MissedDerivation, -> null diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt index ccd2264205..623fbe5c1b 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt @@ -59,4 +59,6 @@ sealed class CryptoCurrencyWarning { ) : CryptoCurrencyWarning() data object TokensInBetaWarning : CryptoCurrencyWarning() + + data object UsedOutdatedDataWarning : CryptoCurrencyWarning() } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyStatusUpdatesUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyStatusUpdatesUseCase.kt index f74a62b2d4..603d6bd68c 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyStatusUpdatesUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyStatusUpdatesUseCase.kt @@ -6,6 +6,7 @@ import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.error.mapper.mapToCurrencyError import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository @@ -27,6 +28,7 @@ class GetCurrencyStatusUpdatesUseCase( private val networksRepository: NetworksRepository, private val stakingRepository: StakingRepository, private val dispatchers: CoroutineDispatcherProvider, + private val tokensFeatureToggles: TokensFeatureToggles, ) { /** @@ -58,18 +60,27 @@ class GetCurrencyStatusUpdatesUseCase( currencyId: CryptoCurrency.ID, isSingleWalletWithTokens: Boolean, ): Flow> { - val operations = CurrenciesStatusesOperations( - currenciesRepository = currenciesRepository, - quotesRepository = quotesRepository, - networksRepository = networksRepository, - stakingRepository = stakingRepository, - userWalletId = userWalletId, - ) - - val currencyFlow = if (isSingleWalletWithTokens) { - operations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId) + val currencyFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) { + CurrenciesStatusesCachedOperations( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + stakingRepository = stakingRepository, + ).getCurrencyStatusFlow(userWalletId, currencyId) } else { - operations.getCurrencyStatusFlow(currencyId) + val operations = CurrenciesStatusesOperations( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + stakingRepository = stakingRepository, + userWalletId = userWalletId, + ) + + if (isSingleWalletWithTokens) { + operations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId) + } else { + operations.getCurrencyStatusFlow(currencyId) + } } return currencyFlow.map { maybeCurrency -> maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError) diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt index 111f62b3ce..56b4a16b80 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt @@ -1,10 +1,12 @@ package com.tangem.domain.tokens +import com.tangem.domain.models.StatusSource import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.tokens.model.* import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.domain.tokens.model.warnings.HederaWarnings import com.tangem.domain.tokens.model.warnings.KaspaWarnings +import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrencyChecksRepository @@ -27,6 +29,7 @@ class GetCurrencyWarningsUseCase( private val stakingRepository: StakingRepository, private val dispatchers: CoroutineDispatcherProvider, private val currencyChecksRepository: CurrencyChecksRepository, + private val tokensFeatureToggles: TokensFeatureToggles, ) { suspend operator fun invoke( @@ -36,18 +39,11 @@ class GetCurrencyWarningsUseCase( isSingleWalletWithTokens: Boolean, ): Flow> { val currency = currencyStatus.currency - val operations = CurrenciesStatusesOperations( - currenciesRepository = currenciesRepository, - quotesRepository = quotesRepository, - networksRepository = networksRepository, - stakingRepository = stakingRepository, - userWalletId = userWalletId, - ) + // don't add here notifications that require async requests return combine( getCoinRelatedWarnings( userWalletId = userWalletId, - operations = operations, networkId = currency.network.id, currencyId = currency.id, derivationPath = derivationPath, @@ -74,22 +70,50 @@ class GetCurrencyWarningsUseCase( @Suppress("LongParameterList") private suspend fun getCoinRelatedWarnings( userWalletId: UserWalletId, - operations: CurrenciesStatusesOperations, networkId: Network.ID, currencyId: CryptoCurrency.ID, derivationPath: Network.DerivationPath, isSingleWalletWithTokens: Boolean, ): Flow> { - val currencyFlow = if (isSingleWalletWithTokens) { - operations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId) - } else { - operations.getCurrencyStatusFlow(currencyId) + val cachedOperations by lazy { + CurrenciesStatusesCachedOperations( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + stakingRepository = stakingRepository, + ) } - val networkFlow = if (isSingleWalletWithTokens) { - operations.getNetworkCoinForSingleWalletWithTokenFlow(networkId) - } else { - operations.getNetworkCoinFlow(networkId, derivationPath) + + val lceOperations by lazy { + CurrenciesStatusesOperations( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + stakingRepository = stakingRepository, + userWalletId = userWalletId, + ) } + + val currencyFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) { + cachedOperations.getCurrencyStatusFlow(userWalletId, currencyId) + } else { + if (isSingleWalletWithTokens) { + lceOperations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId) + } else { + lceOperations.getCurrencyStatusFlow(currencyId) + } + } + + val networkFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) { + cachedOperations.getNetworkCoinFlow(userWalletId, networkId, derivationPath) + } else { + if (isSingleWalletWithTokens) { + lceOperations.getNetworkCoinForSingleWalletWithTokenFlow(networkId) + } else { + lceOperations.getNetworkCoinFlow(networkId, derivationPath) + } + } + return combine( currencyFlow.map { it.getOrNull() }, networkFlow.map { it.getOrNull() }, @@ -97,6 +121,7 @@ class GetCurrencyWarningsUseCase( when { tokenStatus != null && coinStatus != null -> { buildList { + getUsedOutdatedDataWarning(tokenStatus)?.let(::add) getIsBetaTokensWarning(tokenStatus.currency)?.let(::add) getFeeWarning( userWalletId = userWalletId, @@ -144,6 +169,10 @@ class GetCurrencyWarningsUseCase( } } + private fun getUsedOutdatedDataWarning(status: CryptoCurrencyStatus): CryptoCurrencyWarning? { + return CryptoCurrencyWarning.UsedOutdatedDataWarning.takeIf { status.value.source == StatusSource.ONLY_CACHE } + } + private fun getIsBetaTokensWarning(currency: CryptoCurrency): CryptoCurrencyWarning? { val isTokenBetaFunctionality = BlockchainUtils.isTokenBetaFunctionality(currency.network.id.value) return if (currency is CryptoCurrency.Token && isTokenBetaFunctionality) { diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt index d76493e741..9bba066cf9 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt @@ -11,6 +11,7 @@ import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.TotalFiatBalance +import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations import com.tangem.domain.tokens.operations.CurrenciesStatusesLceOperations import com.tangem.domain.tokens.operations.TokenListFiatBalanceOperations import com.tangem.domain.tokens.repository.CurrenciesRepository @@ -28,6 +29,7 @@ class GetWalletTotalBalanceUseCase( private val quotesRepository: QuotesRepository, private val networksRepository: NetworksRepository, private val stakingRepository: StakingRepository, + private val tokensFeatureToggles: TokensFeatureToggles, ) { operator fun invoke( @@ -86,13 +88,20 @@ class GetWalletTotalBalanceUseCase( } private fun getStatuses(userWalletId: UserWalletId): LceFlow> { - val operations = CurrenciesStatusesLceOperations( - currenciesRepository = currenciesRepository, - quotesRepository = quotesRepository, - networksRepository = networksRepository, - stakingRepository = stakingRepository, - ) - - return operations.getCurrenciesStatuses(userWalletId) + return if (tokensFeatureToggles.isBalancesCachingEnabled) { + CurrenciesStatusesCachedOperations( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + stakingRepository = stakingRepository, + ).getCurrenciesStatuses(userWalletId) + } else { + CurrenciesStatusesLceOperations( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + stakingRepository = stakingRepository, + ).getCurrenciesStatuses(userWalletId) + } } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesCachedOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesCachedOperations.kt index 70fff8b1da..56a3a8f4dd 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesCachedOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesCachedOperations.kt @@ -1,10 +1,7 @@ package com.tangem.domain.tokens.operations import arrow.core.* -import arrow.core.raise.Raise -import arrow.core.raise.catch -import arrow.core.raise.ensureNotNull -import arrow.core.raise.recover +import arrow.core.raise.* import com.tangem.domain.core.lce.Lce import com.tangem.domain.core.lce.LceFlow import com.tangem.domain.core.lce.lce @@ -15,6 +12,7 @@ import com.tangem.domain.staking.model.stakekit.YieldBalanceList import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.* +import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository import com.tangem.domain.tokens.repository.QuotesRepository @@ -22,6 +20,7 @@ import com.tangem.domain.wallets.models.UserWalletId import kotlinx.coroutines.* import kotlinx.coroutines.flow.* +@Suppress("LargeClass") internal class CurrenciesStatusesCachedOperations( private val currenciesRepository: CurrenciesRepository, private val quotesRepository: QuotesRepository, @@ -36,6 +35,89 @@ internal class CurrenciesStatusesCachedOperations( ) } + suspend fun getCurrencyStatusFlow( + userWalletId: UserWalletId, + currencyId: CryptoCurrency.ID, + includeQuotes: Boolean = true, + ): Flow> { + val currency = recover( + block = { getMultiCurrencyWalletCurrency(userWalletId = userWalletId, currencyId = currencyId) }, + recover = { return flowOf(it.left()) }, + ) + + return getCurrencyStatusFlow(userWalletId = userWalletId, currency = currency, includeQuotes = includeQuotes) + } + + suspend fun getNetworkCoinFlow( + userWalletId: UserWalletId, + networkId: Network.ID, + derivationPath: Network.DerivationPath, + includeQuotes: Boolean = true, + ): Flow> { + val operations = CurrenciesStatusesOperations( + currenciesRepository = currenciesRepository, + quotesRepository = quotesRepository, + networksRepository = networksRepository, + stakingRepository = stakingRepository, + userWalletId = userWalletId, + ) + + val currency = recover( + block = { + with(operations) { getNetworkCoin(networkId, derivationPath) } + }, + recover = { return flowOf(it.left()) }, + ) + + return getCurrencyStatusFlow(userWalletId, currency, includeQuotes) + } + + private fun getCurrencyStatusFlow( + userWalletId: UserWalletId, + currency: CryptoCurrency, + includeQuotes: Boolean = true, + ): Flow> { + val rawCurrencyId = currency.id.rawCurrencyId + + val quoteFlow = if (includeQuotes && rawCurrencyId != null) { + getQuotes(rawCurrencyId) + .map { maybeQuotes -> + maybeQuotes.flatMap { quotes -> + quotes.singleOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }?.right() + ?: Error.EmptyQuotes.left() + } + } + } else { + // don't use emptyFlow() + flow { emit(Error.EmptyQuotes.left()) } + } + + val statusFlow = getNetworksStatuses(userWalletId = userWalletId, network = currency.network) + .map { maybeStatuses -> + maybeStatuses.flatMap { statuses -> + statuses.singleOrNull { it.network == currency.network }?.right() + ?: Error.EmptyNetworksStatuses.left() + } + } + + val yieldBalanceFlow = getYieldBalance(userWalletId = userWalletId, cryptoCurrency = currency) + + return combine(quoteFlow, statusFlow, yieldBalanceFlow) { maybeQuote, maybeNetworkStatus, maybeYieldBalance -> + createCurrencyStatus(currency, maybeQuote, maybeNetworkStatus, maybeYieldBalance) + } + } + + private suspend fun Raise.getMultiCurrencyWalletCurrency( + userWalletId: UserWalletId, + currencyId: CryptoCurrency.ID, + ): CryptoCurrency { + return Either.catch { + currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId = userWalletId, id = currencyId) + } + .mapLeft { Error.DataError(it) } + .bind() + } + private fun transformToCurrenciesStatuses( userWalletId: UserWalletId, currenciesFlow: EitherFlow>, @@ -143,6 +225,30 @@ internal class CurrenciesStatusesCachedOperations( } } + private fun createCurrencyStatus( + currency: CryptoCurrency, + maybeQuote: Either, + maybeNetworkStatus: Either, + maybeYieldBalance: Either?, + ): Either = either { + var quoteRetrievingFailed = false + + val networkStatus = maybeNetworkStatus.bind() + val quote = recover({ maybeQuote.bind() }) { + quoteRetrievingFailed = true + null + } + val yieldBalance = maybeYieldBalance?.getOrNull() + + createCurrencyStatus( + currency = currency, + quote = quote, + networkStatus = networkStatus, + ignoreQuote = quoteRetrievingFailed, + yieldBalance = yieldBalance, + ) + } + private fun findYieldBalanceOrNull( yieldBalances: YieldBalanceList?, currency: CryptoCurrency, @@ -197,6 +303,18 @@ internal class CurrenciesStatusesCachedOperations( .distinctUntilChanged() } + private fun getQuotes(id: CryptoCurrency.RawID): Flow>> { + return quotesRepository.getQuotesUpdates(setOf(id)) + .map, Either>> { it.right() } + .retryWhen { cause, _ -> + emit(Error.DataError(cause).left()) + // adding delay before retry to avoid spam when flow restarted + delay(RETRY_DELAY) + true + } + .distinctUntilChanged() + } + private fun getNetworksStatuses( userWalletId: UserWalletId, networks: NonEmptySet, @@ -212,6 +330,21 @@ internal class CurrenciesStatusesCachedOperations( .distinctUntilChanged() } + private fun getNetworksStatuses( + userWalletId: UserWalletId, + network: Network, + ): EitherFlow> { + return networksRepository.getNetworkStatusesUpdates(userWalletId, setOf(network)) + .map, Either>> { it.right() } + .retryWhen { cause, _ -> + emit(Error.DataError(cause).left()) + // adding delay before retry to avoid spam when flow restarted + delay(RETRY_DELAY) + true + } + .distinctUntilChanged() + } + private fun getYieldBalances( userWalletId: UserWalletId, cryptoCurrencies: List, @@ -227,6 +360,18 @@ internal class CurrenciesStatusesCachedOperations( .distinctUntilChanged() } + private fun getYieldBalance( + userWalletId: UserWalletId, + cryptoCurrency: CryptoCurrency, + ): EitherFlow { + return stakingRepository.getSingleYieldBalanceFlow( + userWalletId = userWalletId, + cryptoCurrency = cryptoCurrency, + ).map> { it.right() } + .catch { emit(Error.DataError(it).left()) } + .onEmpty { emit(Error.EmptyYieldBalances.left()) } + } + private fun getIds(currencies: List): Pair, NonEmptySet> { val currencyIdToNetworkId = currencies.associate { currency -> currency.id to currency.network 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 eb0e4023b1..e6f78479bf 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 @@ -321,7 +321,7 @@ internal class CurrenciesStatusesOperations( .bind() } - private suspend fun Raise.getNetworkCoin( + suspend fun Raise.getNetworkCoin( networkId: Network.ID, derivationPath: Network.DerivationPath, ): CryptoCurrency { 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 index 365f441978..4a6aa779cb 100644 --- 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 @@ -54,6 +54,7 @@ internal class TokenDetailsNotificationsAnalyticsSender( is TokenDetailsNotification.KoinosMana, is TokenDetailsNotification.MigrationMaticToPol, is TokenDetailsNotification.TokensInBeta, + is TokenDetailsNotification.UsedOutdatedData, -> null } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt index abc78abbec..14740adf85 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt @@ -234,4 +234,11 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) { title = resourceReference(id = R.string.beta_mode_warning_title), subtitle = resourceReference(id = R.string.beta_mode_warning_message), ) + + data object UsedOutdatedData : TokenDetailsNotification( + config = NotificationConfig( + subtitle = resourceReference(R.string.warning_some_token_balances_not_updated), + iconResId = R.drawable.ic_error_sync_24, + ), + ) } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt index 1c0e9869ad..3d9269fe05 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt @@ -136,6 +136,7 @@ internal class TokenDetailsNotificationConverter( ) is CryptoCurrencyWarning.MigrationMaticToPol -> MigrationMaticToPol is CryptoCurrencyWarning.TokensInBetaWarning -> TokensInBeta + is CryptoCurrencyWarning.UsedOutdatedDataWarning -> UsedOutdatedData } } 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 f60d8ad078..29775149aa 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 @@ -20,12 +20,12 @@ import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBot import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheet import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig +import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer import com.tangem.core.ui.components.marketprice.MarketPriceBlock import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.components.transactions.txHistoryItems -import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData @@ -96,6 +96,7 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon config = it.config, iconTint = when (it) { is TokenDetailsNotification.Informational -> TangemTheme.colors.icon.accent + is TokenDetailsNotification.UsedOutdatedData -> TangemTheme.colors.text.attention else -> null }, )