From 9d798cdd6de1380b013e954545b289e7fcb27a3f Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2025 16:33:53 +0500 Subject: [PATCH 1/7] Updated on 2026-08-14 --- .../ui/components/buttons/actions/Actions.kt | 18 +---- .../ui/components/icons/badge/DotBadge.kt | 22 ++++++ .../impl/model/PortfolioTokenUMConverter.kt | 36 ++++----- .../impl/ui/PortfolioQuickActions.kt | 78 ++++++++++++------- .../preview/PreviewMyPortfolioUMProvider.kt | 7 +- .../portfolio/impl/ui/state/QuickActionUM.kt | 18 +++-- 6 files changed, 105 insertions(+), 74 deletions(-) create mode 100644 core/ui/src/main/java/com/tangem/core/ui/components/icons/badge/DotBadge.kt diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt index 63807a2a7d..77f984d3c8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt @@ -18,9 +18,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow @@ -30,9 +28,9 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.tangem.core.ui.R +import com.tangem.core.ui.components.icons.badge.drawBadge import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resolveReference -import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -225,20 +223,6 @@ fun getTextColor(config: ActionButtonConfig): Color { } } -private fun DrawScope.drawBadge(containerColor: Color) { - val width = size.width - drawCircle( - color = containerColor, - center = Offset(x = width - 2.dp.toPx(), y = 2.dp.toPx()), - radius = 5.dp.toPx(), - ) - drawCircle( - color = TangemColorPalette.Azure, - center = Offset(x = width - 2.dp.toPx(), y = 2.dp.toPx()), - radius = 3.dp.toPx(), - ) -} - @Preview(group = "RoundedActionButton", showBackground = true) @Preview(group = "RoundedActionButton", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/icons/badge/DotBadge.kt b/core/ui/src/main/java/com/tangem/core/ui/components/icons/badge/DotBadge.kt new file mode 100644 index 0000000000..e25b5c333a --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/icons/badge/DotBadge.kt @@ -0,0 +1,22 @@ +package com.tangem.core.ui.components.icons.badge + +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.res.TangemColorPalette + +fun DrawScope.drawBadge(containerColor: Color, offset: Dp = 2.dp) { + val width = size.width + drawCircle( + color = containerColor, + center = Offset(x = width - offset.toPx(), y = offset.toPx()), + radius = 5.dp.toPx(), + ) + drawCircle( + color = TangemColorPalette.Azure, + center = Offset(x = width - offset.toPx(), y = offset.toPx()), + radius = 3.dp.toPx(), + ) +} \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/PortfolioTokenUMConverter.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/PortfolioTokenUMConverter.kt index 946fcbdd07..6f1fe73641 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/PortfolioTokenUMConverter.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/PortfolioTokenUMConverter.kt @@ -48,33 +48,14 @@ internal class PortfolioTokenUMConverter( private fun quickActions(cryptoData: PortfolioData.CryptoCurrencyData): PortfolioTokenUM.QuickActions { return PortfolioTokenUM.QuickActions( - actions = listOfNotNull( - QuickActionUM.Buy.takeIf { - cryptoData.actions.any { - it is TokenActionsState.ActionState.Buy && - it.unavailabilityReason == ScenarioUnavailabilityReason.None - } - }, - QuickActionUM.Exchange.takeIf { - cryptoData.actions.any { - it is TokenActionsState.ActionState.Swap && - it.unavailabilityReason == ScenarioUnavailabilityReason.None - } - }, - QuickActionUM.Receive.takeIf { - cryptoData.actions.any { - it is TokenActionsState.ActionState.Receive && - it.unavailabilityReason == ScenarioUnavailabilityReason.None - } - }, - ).toImmutableList(), + actions = toQuickActions(cryptoData.actions), onQuickActionClick = { when (it) { QuickActionUM.Buy -> tokenActionsHandler.handle( action = TokenActionsBSContentUM.Action.Buy, cryptoCurrencyData = cryptoData, ) - QuickActionUM.Exchange -> tokenActionsHandler.handle( + is QuickActionUM.Exchange -> tokenActionsHandler.handle( action = TokenActionsBSContentUM.Action.Exchange, cryptoCurrencyData = cryptoData, ) @@ -94,4 +75,17 @@ internal class PortfolioTokenUMConverter( }, ) } + + private fun toQuickActions(actions: List) = buildList { + actions.forEach { action -> + if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) { + when (action) { + is TokenActionsState.ActionState.Buy -> QuickActionUM.Buy + is TokenActionsState.ActionState.Swap -> QuickActionUM.Exchange(showBadge = action.showBadge) + is TokenActionsState.ActionState.Receive -> QuickActionUM.Receive + else -> null + }?.let(::add) + } + } + }.toImmutableList() } \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/PortfolioQuickActions.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/PortfolioQuickActions.kt index ba5ff99531..e945b00c26 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/PortfolioQuickActions.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/PortfolioQuickActions.kt @@ -4,7 +4,10 @@ import android.content.res.Configuration import androidx.compose.animation.* import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring -import androidx.compose.foundation.* +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button @@ -13,6 +16,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalLayoutDirection @@ -22,6 +26,7 @@ import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach import com.tangem.core.ui.components.SpacerH4 +import com.tangem.core.ui.components.icons.badge.drawBadge import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.haptic.TangemHapticEffect import com.tangem.core.ui.res.LocalHapticManager @@ -29,7 +34,7 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.markets.portfolio.impl.ui.state.QuickActionUM import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.persistentListOf @Composable internal fun PortfolioQuickActions( @@ -59,7 +64,6 @@ internal fun PortfolioQuickActions( } } -@OptIn(ExperimentalAnimationApi::class) @Composable private fun AnimatedVisibilityScope.LineSeparator(modifier: Modifier = Modifier) { val lineColor = TangemTheme.colors.stroke.primary @@ -99,7 +103,7 @@ private fun AnimatedVisibilityScope.LineSeparator(modifier: Modifier = Modifier) } } -@OptIn(ExperimentalAnimationApi::class, ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class) @Composable private fun AnimatedVisibilityScope.QuickActionItem( state: QuickActionUM, @@ -131,27 +135,7 @@ private fun AnimatedVisibilityScope.QuickActionItem( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing18), ) { - Box( - Modifier - .animateEnterExit( - enter = scaleIn(), - exit = scaleOut(), - ) - .background( - color = TangemTheme.colors.button.secondary, - shape = CircleShape, - ) - .size(TangemTheme.dimens.size32), - contentAlignment = Alignment.Center, - ) { - Icon( - modifier = Modifier - .requiredSize(TangemTheme.dimens.size16), - imageVector = ImageVector.vectorResource(id = state.icon), - contentDescription = null, - tint = TangemTheme.colors.button.primary, - ) - } + QuickActionIcon(state) Column( modifier = Modifier .animateEnterExit( @@ -174,6 +158,38 @@ private fun AnimatedVisibilityScope.QuickActionItem( } } +@Composable +private fun AnimatedVisibilityScope.QuickActionIcon(state: QuickActionUM) { + val containerColor = TangemTheme.colors.background.action + Box( + Modifier + .animateEnterExit( + enter = scaleIn(), + exit = scaleOut(), + ) + .background( + color = TangemTheme.colors.button.secondary, + shape = CircleShape, + ) + .size(TangemTheme.dimens.size32) + .drawWithContent { + drawContent() + if (state is QuickActionUM.Exchange && state.showBadge) { + drawBadge(containerColor = containerColor, offset = 4.dp) + } + }, + contentAlignment = Alignment.Center, + ) { + Icon( + modifier = Modifier + .requiredSize(TangemTheme.dimens.size16), + imageVector = ImageVector.vectorResource(id = state.icon), + contentDescription = null, + tint = TangemTheme.colors.button.primary, + ) + } +} + @Preview @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -197,7 +213,11 @@ private fun Preview() { modifier = Modifier.background(color = TangemTheme.colors.background.action), ) { PortfolioQuickActions( - actions = QuickActionUM.entries.toImmutableList(), + actions = persistentListOf( + QuickActionUM.Buy, + QuickActionUM.Exchange(showBadge = true), + QuickActionUM.Receive, + ), isVisible = isVisible, onActionClick = {}, onActionLongClick = {}, @@ -214,7 +234,11 @@ private fun PreviewRtl() { TangemThemePreview(rtl = true) { Box(modifier = Modifier.background(color = TangemTheme.colors.background.action)) { PortfolioQuickActions( - actions = QuickActionUM.entries.toImmutableList(), + actions = persistentListOf( + QuickActionUM.Buy, + QuickActionUM.Exchange(showBadge = true), + QuickActionUM.Receive, + ), isVisible = true, onActionClick = {}, onActionLongClick = {}, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewMyPortfolioUMProvider.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewMyPortfolioUMProvider.kt index 79177f24a4..d1171dc444 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewMyPortfolioUMProvider.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewMyPortfolioUMProvider.kt @@ -10,7 +10,6 @@ import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM import com.tangem.features.markets.portfolio.impl.ui.state.PortfolioTokenUM import com.tangem.features.markets.portfolio.impl.ui.state.QuickActionUM import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider { @@ -61,7 +60,11 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider Date: Wed, 26 Feb 2025 11:39:48 +0400 Subject: [PATCH 2/7] Updated on 2026-08-14 --- .../converter/UserWalletItemUMConverter.kt | 5 ++-- .../domain/tokens/FetchTokenListUseCase.kt | 8 ++++++ .../tokens/GetWalletTotalBalanceUseCase.kt | 26 ++++++++++++------- .../CachedCurrenciesStatusesOperations.kt | 10 +++++-- .../details/model/UserWalletListModel.kt | 6 ++--- .../details/utils/UserWalletsFetcher.kt | 7 +++-- .../model/AddToPortfolioBSContentUMFactory.kt | 1 - .../intents/WalletWarningsClickIntents.kt | 6 ++++- 8 files changed, 45 insertions(+), 24 deletions(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/UserWalletItemUMConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/UserWalletItemUMConverter.kt index e3ee5ae7a0..24fc6cd8b2 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/UserWalletItemUMConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/userwallet/converter/UserWalletItemUMConverter.kt @@ -9,6 +9,7 @@ import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.common.util.getCardsCount +import com.tangem.domain.models.StatusSource import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId @@ -20,7 +21,6 @@ import com.tangem.utils.converter.Converter * @property onClick lambda be invoked when item is clicked * @property appCurrency selected app currency * @property balance wallet balance - * @property isLoading wallet loading state * @property isBalanceHidden wallet balance is hidden * [REDACTED_AUTHOR] @@ -29,7 +29,6 @@ class UserWalletItemUMConverter( private val onClick: (UserWalletId) -> Unit, private val appCurrency: AppCurrency? = null, private val balance: TotalFiatBalance? = null, - private val isLoading: Boolean = true, private val isBalanceHidden: Boolean = false, private val endIcon: UserWalletItemUM.EndIcon = UserWalletItemUM.EndIcon.None, ) : Converter { @@ -75,7 +74,7 @@ class UserWalletItemUMConverter( UserWalletItemUM.Balance.Loaded( value = formattedAmount, - isFlickering = isLoading, + isFlickering = balance.source == StatusSource.CACHE, ) } else { UserWalletItemUM.Balance.Failed diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchTokenListUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchTokenListUseCase.kt index eafad782ed..408c4e81ca 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchTokenListUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchTokenListUseCase.kt @@ -49,6 +49,14 @@ class FetchTokenListUseCase( ): Either = either { val currencies = fetchCurrencies(userWalletId, refresh = mode.refreshCurrencies) + invoke(userWalletId = userWalletId, currencies = currencies, mode = mode) + } + + suspend operator fun invoke( + userWalletId: UserWalletId, + currencies: List, + mode: RefreshMode = RefreshMode.NONE, + ): Either = either { coroutineScope { val fetchStatuses = async { fetchNetworksStatuses( 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 5f874b7419..8b6ba7ade2 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 @@ -13,10 +13,8 @@ import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.domain.tokens.operations.BaseCurrenciesStatusesOperations import com.tangem.domain.tokens.operations.TokenListFiatBalanceOperations import com.tangem.domain.wallets.models.UserWalletId -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.transformLatest import timber.log.Timber class GetWalletTotalBalanceUseCase( @@ -54,20 +52,28 @@ class GetWalletTotalBalanceUseCase( } } - @OptIn(ExperimentalCoroutinesApi::class) operator fun invoke(userWalletId: UserWalletId): LceFlow { - return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId) - .transformLatest { maybeStatuses -> - val balance = createBalance(maybeStatuses) - - emit(balance) - } + return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId).map(::createBalance) } private fun createBalance( maybeStatuses: Lce>, ): Lce = lce { - val statuses = maybeStatuses.bind() + val statuses = when (maybeStatuses) { + is Lce.Content -> maybeStatuses.content + is Lce.Error -> raise(maybeStatuses) + is Lce.Loading -> { + val content = maybeStatuses.partialContent + + if (content == null) { + isLoading.set(true) + + raise(lceLoading()) + } else { + content + } + } + } val operations = TokenListFiatBalanceOperations( currencies = ensureNotNull(statuses.toNonEmptyListOrNull()) { lceLoading() }, diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt index cd0a3639c9..969e56d6ef 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt @@ -7,6 +7,7 @@ import com.tangem.domain.core.lce.LceFlow import com.tangem.domain.core.lce.lce import com.tangem.domain.core.lce.lceFlow import com.tangem.domain.core.utils.EitherFlow +import com.tangem.domain.core.utils.lceError import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.staking.model.stakekit.YieldBalanceList import com.tangem.domain.staking.repositories.StakingRepository @@ -45,9 +46,14 @@ class CachedCurrenciesStatusesOperations( ): LceFlow> = lceFlow { currenciesFlow.flatMapLatest { maybeCurrencies -> val isUpdating = MutableStateFlow(value = true) - val nonEmptyCurrencies = maybeCurrencies.bind().toNonEmptyListOrNull() - ensureNotNull(nonEmptyCurrencies) { TokenListError.EmptyTokens } + val nonEmptyCurrencies = maybeCurrencies + .getOrElse { return@flatMapLatest flowOf(it.lceError()) } + .toNonEmptyListOrNull() + + if (nonEmptyCurrencies.isNullOrEmpty()) { + return@flatMapLatest flowOf(TokenListError.EmptyTokens.lceError()) + } // This is only 'true' when the flow here is empty, such as during initial loading if (isLoading.get()) { diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt index ef9905ff46..d7cc987538 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt @@ -40,9 +40,9 @@ internal class UserWalletListModel @Inject constructor( init { combine( - userWalletsFetcher.userWallets, - shouldSaveUserWalletsUseCase(), - isWalletSavingInProgress, + flow = userWalletsFetcher.userWallets, + flow2 = shouldSaveUserWalletsUseCase(), + flow3 = isWalletSavingInProgress, transform = ::updateState, ).launchIn(modelScope) } diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt index c9115930ec..4fce54d271 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletsFetcher.kt @@ -49,9 +49,9 @@ internal class UserWalletsFetcher @Inject constructor( emit(uiModels) combine( - getSelectedAppCurrencyUseCase().distinctUntilChanged(), - getBalanceHidingSettingsUseCase().distinctUntilChanged(), - getWalletTotalBalanceUseCase(wallets.map(UserWallet::walletId)).distinctUntilChanged(), + flow = getSelectedAppCurrencyUseCase().distinctUntilChanged(), + flow2 = getBalanceHidingSettingsUseCase().distinctUntilChanged(), + flow3 = getWalletTotalBalanceUseCase(wallets.map(UserWallet::walletId)).distinctUntilChanged(), ) { maybeAppCurrency, balanceHidingSettings, maybeBalances -> val models = createUiModels( wallets = wallets, @@ -99,7 +99,6 @@ internal class UserWalletsFetcher @Inject constructor( appCurrency = appCurrency, balance = balance, isBalanceHidden = balanceHidingSettings.isBalanceHidden, - isLoading = maybeBalances.isLoading(), ) .convert(userWallet) } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/AddToPortfolioBSContentUMFactory.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/AddToPortfolioBSContentUMFactory.kt index 5f82c6c481..aecd1f943e 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/AddToPortfolioBSContentUMFactory.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/AddToPortfolioBSContentUMFactory.kt @@ -127,7 +127,6 @@ internal class AddToPortfolioBSContentUMFactory( }, appCurrency = portfolioData.appCurrency, balance = balance?.getOrNull(), - isLoading = balance?.isLoading() == true, isBalanceHidden = portfolioData.isBalanceHidden, endIcon = if (userWallet.walletId == selectedWalletId) { UserWalletItemUM.EndIcon.Checkmark diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt index 115c9535ab..b3dc26a447 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt @@ -147,7 +147,11 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( ).fold( ifLeft = { Timber.e(it, "Failed to derive public keys") }, ifRight = { - fetchTokenListUseCase(userWallet.walletId, mode = RefreshMode.SKIP_CURRENCIES).onLeft { + fetchTokenListUseCase( + userWalletId = userWallet.walletId, + mode = RefreshMode.SKIP_CURRENCIES, + currencies = missedAddressCurrencies, + ).onLeft { Timber.e("Unable to refresh token list: $it") } }, From 49f104939491f4dd998842fb7d238c3261f30883 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 12:30:59 +0400 Subject: [PATCH 3/7] Updated on 2026-08-14 --- .../tokens/model/analytics/TokenScreenAnalyticsEvent.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenScreenAnalyticsEvent.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenScreenAnalyticsEvent.kt index 767dfd45ab..dcea766313 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenScreenAnalyticsEvent.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/TokenScreenAnalyticsEvent.kt @@ -90,7 +90,7 @@ sealed class TokenScreenAnalyticsEvent( ) class NoticeActionInactive(token: String, tokenAction: TokenAction, reason: String) : TokenScreenAnalyticsEvent( - "Notice - Action Inactive", + event = "Notice - Action Inactive", params = buildMap { put("Token", token) put("Action", tokenAction.action) @@ -112,6 +112,7 @@ sealed class TokenScreenAnalyticsEvent( private const val UNAVAILABLE = "Unavailable" private const val EMPTY = "Empty" private const val PENDING = "Pending" + private const val CACHING = "Caching" fun ScenarioUnavailabilityReason.toReasonAnalyticsText(): String { return when (this) { @@ -123,9 +124,9 @@ sealed class TokenScreenAnalyticsEvent( -> UNAVAILABLE is ScenarioUnavailabilityReason.EmptyBalance -> EMPTY is ScenarioUnavailabilityReason.PendingTransaction -> PENDING + ScenarioUnavailabilityReason.UsedOutdatedData -> CACHING ScenarioUnavailabilityReason.None, ScenarioUnavailabilityReason.Unreachable, - ScenarioUnavailabilityReason.UsedOutdatedData, -> "" } } From cf1f3c8b300a101aae09b89f7c4c9ed243f74a07 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 11:50:53 +0300 Subject: [PATCH 4/7] Updated on 2026-08-14 --- .../src/main/assets/configs/feature_toggles_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index ba2bb626ea..cd7443d27d 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -29,7 +29,7 @@ }, { "name": "SWAP_STORIES_ENABLED", - "version": "undefined" + "version": "5.21.0" }, { "name": "VISA_ONBOARDING_ENABLED", From 8459eb743b50563b9d075d6dd7390f7e73bf2c0a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 15:43:23 +0500 Subject: [PATCH 5/7] Updated on 2026-08-14 --- .../tangem/tap/features/main/MainViewModel.kt | 32 +++++++++++++------ .../data/promo/DefaultPromoRepository.kt | 6 ++-- .../domain/promo/GetStoryContentUseCase.kt | 4 +-- .../tangem/domain/promo/PromoRepository.kt | 2 +- .../stories/impl/analytics/StoriesEvents.kt | 11 ------- .../stories/impl/model/StoriesModel.kt | 12 ------- .../feature/swap/analytics/StoriesEvents.kt | 2 -- .../tangem/feature/swap/model/SwapModel.kt | 15 +-------- 8 files changed, 30 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt index a21fee2f05..143a8d92a4 100644 --- a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt @@ -29,6 +29,7 @@ import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase import com.tangem.domain.staking.FetchStakingTokensUseCase import com.tangem.domain.wallets.legacy.UserWalletsListManager +import com.tangem.feature.swap.analytics.StoriesEvents import com.tangem.features.onramp.OnrampFeatureToggles import com.tangem.features.swap.SwapFeatureToggles import com.tangem.tap.common.extensions.setContext @@ -300,19 +301,32 @@ internal class MainViewModel @Inject constructor( private fun preloadImages() { try { viewModelScope.launch { - val swapStories = if (swapFeatureToggles.isPromoStoriesEnabled) { - getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id) - .getOrNull() - } else { - null - } + if (swapFeatureToggles.isPromoStoriesEnabled) { + val swapStories = getStoryContentUseCase.invokeSync( + id = StoryContentIds.STORY_FIRST_TIME_SWAP.id, + refresh = true, + ).getOrNull() - val storiesImages = swapStories?.getImageUrls() - // try to preload images for stories - storiesImages?.forEach(imagePreloader::preload) + if (swapStories == null) { + analyticsEventHandler.send( + StoriesEvents.Error( + type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType, + ), + ) + } else { + val storiesImages = swapStories.getImageUrls() + // try to preload images for stories + storiesImages.forEach(imagePreloader::preload) + } + } } } catch (ex: Exception) { Timber.e(ex.message) + analyticsEventHandler.send( + StoriesEvents.Error( + type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType, + ), + ) } } } \ No newline at end of file diff --git a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt index 1e0f94e8f0..5b14b75e9a 100644 --- a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt +++ b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt @@ -44,15 +44,15 @@ internal class DefaultPromoRepository( } override fun getStoryById(id: String): Flow = isReadyToShowStories(id).mapLatest { - getStoryByIdSync(id) + getStoryByIdSync(id = id, refresh = false) } - override suspend fun getStoryByIdSync(id: String): StoryContent? = withContext(dispatchers.io) { + override suspend fun getStoryByIdSync(id: String, refresh: Boolean): StoryContent? = withContext(dispatchers.io) { if (!isReadyToShowStoriesSync(id)) return@withContext null val storedPromo = promoStoriesStore.getSyncOrNull(storyId = id) // Get last stored promo by id if possible or get from network - val story = if (storedPromo == null) { + val story = if (storedPromo == null && refresh) { val storyContent = runCatching { // Important to return withTimeoutOrNull(STORIES_LOAD_DELAY) { diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/GetStoryContentUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/GetStoryContentUseCase.kt index 1964bb9b6e..786f1e9552 100644 --- a/domain/promo/src/main/java/com/tangem/domain/promo/GetStoryContentUseCase.kt +++ b/domain/promo/src/main/java/com/tangem/domain/promo/GetStoryContentUseCase.kt @@ -18,7 +18,7 @@ class GetStoryContentUseCase( .catch { emit(it.left()) } .onEmpty { emit(null.right()) } - suspend fun invokeSync(id: String): Either = Either.catch { - promoRepository.getStoryByIdSync(id) + suspend fun invokeSync(id: String, refresh: Boolean = false): Either = Either.catch { + promoRepository.getStoryByIdSync(id, refresh) } } \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/PromoRepository.kt b/domain/promo/src/main/java/com/tangem/domain/promo/PromoRepository.kt index d785801863..4db7b9bf87 100644 --- a/domain/promo/src/main/java/com/tangem/domain/promo/PromoRepository.kt +++ b/domain/promo/src/main/java/com/tangem/domain/promo/PromoRepository.kt @@ -18,7 +18,7 @@ interface PromoRepository { // region Stories fun getStoryById(id: String): Flow - suspend fun getStoryByIdSync(id: String): StoryContent? + suspend fun getStoryByIdSync(id: String, refresh: Boolean): StoryContent? fun isReadyToShowStories(storyId: String): Flow diff --git a/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/analytics/StoriesEvents.kt b/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/analytics/StoriesEvents.kt index bfab83d626..54644cf01f 100644 --- a/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/analytics/StoriesEvents.kt +++ b/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/analytics/StoriesEvents.kt @@ -19,15 +19,4 @@ sealed class StoriesEvents( WATCHED to watchCount, ), ) - - data class Error( - val source: String, - val type: String, - ) : StoriesEvents( - event = "Error", - params = mapOf( - AnalyticsParam.SOURCE to source, - AnalyticsParam.TYPE to type, - ), - ) } \ No newline at end of file diff --git a/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/model/StoriesModel.kt b/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/model/StoriesModel.kt index c47bd9c1b6..1d3c2f06b6 100644 --- a/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/model/StoriesModel.kt +++ b/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/model/StoriesModel.kt @@ -53,22 +53,10 @@ internal class StoriesModel @Inject constructor( getStoryContentUseCase.invokeSync(params.storyId).fold( ifLeft = { Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}") - analyticsEventHandler.send( - StoriesEvents.Error( - source = params.screenSource, - type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType, - ), - ) openScreen(hideStories = false) // Fallback to target screen }, ifRight = { swapStory -> if (swapStory == null) { - analyticsEventHandler.send( - StoriesEvents.Error( - source = params.screenSource, - type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType, - ), - ) openScreen(hideStories = false) // Fallback to target screen } else { _state.update { diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/StoriesEvents.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/StoriesEvents.kt index 6123fa2876..b7f89e9288 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/StoriesEvents.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/StoriesEvents.kt @@ -21,12 +21,10 @@ sealed class StoriesEvents( ) data class Error( - val source: String, val type: String, ) : StoriesEvents( event = "Error", params = mapOf( - AnalyticsParam.SOURCE to source, AnalyticsParam.TYPE to type, ), ) diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt index 1207f32248..f5a23e89f8 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt @@ -82,7 +82,6 @@ internal class SwapModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val blockchainInteractor: BlockchainInteractor, private val analyticsEventHandler: AnalyticsEventHandler, - private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase, private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase, @@ -96,6 +95,7 @@ internal class SwapModel @Inject constructor( private val shouldShowStoriesUseCase: ShouldShowStoriesUseCase, private val getStoryContentUseCase: GetStoryContentUseCase, private val featureToggles: SwapFeatureToggles, + getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, swapInteractorFactory: SwapInteractor.Factory, private val urlOpener: UrlOpener, router: AppRouter, @@ -278,23 +278,10 @@ internal class SwapModel @Inject constructor( getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id).fold( ifLeft = { Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}") - analyticsEventHandler.send( - StoriesEvents.Error( - source = params.screenSource, - type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType, - ), - ) }, ifRight = { story -> if (story != null) { uiState = stateBuilder.createStoriesState(uiState, story) - } else { - analyticsEventHandler.send( - StoriesEvents.Error( - source = params.screenSource, - type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType, - ), - ) } }, ) From e8000f1e83dd777a371b1f50d1bea359d8cc86cc Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 14:06:51 +0300 Subject: [PATCH 6/7] Updated on 2026-08-14 --- .../java/com/tangem/data/onramp/DefaultHotCryptoRepository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultHotCryptoRepository.kt b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultHotCryptoRepository.kt index 1844c1e6c5..86807b4905 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultHotCryptoRepository.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultHotCryptoRepository.kt @@ -144,10 +144,10 @@ internal class DefaultHotCryptoRepository( return copy( tokens = this.tokens + .applyTokensIdMigrations() .filter { hotToken -> !tokens.hasAlreadyAdded(hotToken) && userWallet.canHandleHotCrypto(hotToken) - } - .applyTokensIdMigrations(), + }, ) } From 441648dc3e405eb7533325017f8514a767e03c7a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Feb 2025 13:38:44 +0400 Subject: [PATCH 7/7] Updated on 2026-08-14 --- .../tangem/common/ui/tokens/TokenActionsUtils.kt | 2 +- core/res/src/main/res/values-de/strings.xml | 15 ++++++++++++++- core/res/src/main/res/values-ja/strings.xml | 12 +++++++++++- core/res/src/main/res/values-ru/strings.xml | 4 ++++ core/res/src/main/res/values-uk-rUA/strings.xml | 1 + core/res/src/main/res/values/strings.xml | 9 +++++++-- 6 files changed, 38 insertions(+), 5 deletions(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenActionsUtils.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenActionsUtils.kt index f5d2e66df6..baf5001db7 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenActionsUtils.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenActionsUtils.kt @@ -43,7 +43,7 @@ fun ScenarioUnavailabilityReason.getUnavailabilityReasonText(): TextReference { id = R.string.warning_receive_blocked_hedera_token_association_required_message, ) ScenarioUnavailabilityReason.UsedOutdatedData -> { - resourceReference(id = R.string.token_button_unavailability_reason_out_od_date_balance) + resourceReference(id = R.string.token_button_unavailability_reason_out_of_date_balance) } ScenarioUnavailabilityReason.None -> { throw IllegalArgumentException("The unavailability reason must be other than None") diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index ecef79cb21..e4e17b8896 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -271,6 +271,8 @@ Getauscht von %s Besuche die Website des Anbieters, um dein Geld zurückzuerhalten Fehler beim Vorgang durch Anbieter + Dein Wechsel dauert länger als erwartet. Wende Dich für Hilfe bitte an den Support Deines Anbieters. + Lange Transaktionszeit Der Transaktionsbetrag wurde aufgrund von OKX- oder Bridge-Regeln in %1$s auf deine Wallet zurückerstattet. %2$s Der Betrag wurde in %1$s (%2$s Netzwerk) zurückerstattet. Besuche die Website des Anbieters zur Überprüfung @@ -813,6 +815,10 @@ Niedriges Stakingguthaben Für erneutes Staking sind mindestens %1$s %2$s erforderlich. Bitte lade Dein Guthaben auf. Nicht genug %s + Unzureichendes Guthaben zum Staking + Für das erneute staken sind mindestens 3 ADA erforderlich. Bitte lade Dein Guthaben auf. + Nicht genug ADA + Der für das Staking erforderliche Mindestbetrag muss 5 ADA überschreiten. Bitte lade Dein Guthaben auf, um mit dem Staking zu beginnen. Aufgrund von Netzwerkproblemen ist Staking derzeit nicht verfügbar. Bitte versuche es später erneut. Wenn Du im %1$s -Netzwerk mit einem neuen Validator stakest, werden alle zuvor eingesetzten Gelder automatisch an diesen Validator übertragen. Reinvestiert Deine verdienten Prämien in Deinen Einsatzbetrag und erhöht so den potenziellen Gewinn. @@ -880,6 +886,8 @@ Lerne Tangem kennen Tausche, kaufen Sie NFTs, vergebe Kredite und tätige Einlagen bei mehr als 100 verschiedenen dezentralen Diensten Web 3.0-kompatibel + Zum Fortfahren ist eine eingehende Transaktion von mindestens %1$s erforderlich + Unzureichende Mittel Das Netzwerk erhebt eine Token-Genehmigungsgebühr, um zu überprüfen, ob Sie die Verwendung Ihres Tokens für den Swap genehmigen. Tausche mehr Token zu besseren Kursen direkt in deiner Brieftasche. Neuer Swap-Anbieter verfügbar! @@ -918,6 +926,7 @@ Du hast kein Guthaben um dies zu Verkaufen. Lade dein Konto auf, um Geld von dort zu verkaufen. Du hast kein Guthaben zum Versenden. Lade dein Konto auf, um Geld von dort aus senden zu können. Das Tauschen von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen. + Der angezeigte Kontostand kann aufgrund der Zwischenspeicherung veraltet sein. Der Verkauf von Geldmitteln ist möglich, sobald die ausstehende(n) Transaktion(en) im %s -Netzwerk abgeschlossen ist/sind. Die Geldsendung wird verfügbar, sobald die ausstehende(n) Transaktion(en) im Netzwerk %s abgeschlossen ist/sind. Der Verkauf von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen. @@ -978,6 +987,9 @@ Wallet umbenennen Alle freischalten Alle mit %s freischalten + Freischalten + Scanne Deine Karte, um den Zugriff freizuschalten + Benötigte Freischaltung Blockchain ist nicht erreichbar. Versuche es später nochmal Karte oder Ring scannen Dieses Wallet wurde bereits früher aktiviert. \n Wenn dies nicht von Dir durchgeführt wurde, wende Dich bitte an den Support. \n Tangem verkauft niemals Wallets zusammen mit vorgenerierten Zugangscodes. @@ -1092,7 +1104,7 @@ Du musst deinen Token zuordnen, bevor du Token erhalten kannst Netzmietgebühr erforderlich Handlungsbedarf - Hast Du innerhalb von 7 Tagen nach dem Erstellen einer Wallet per App oder E-Mail Kontakt zum Support aufgenommen? Wenn ja oder wenn Du Dir nicht sicher bist, befolge die Anweisungen und führe diese vollständig aus. + Hast Du innerhalb von 7 Tagen nach der Erstellung Ihres Wallets über die App Kontakt zum Support aufgenommen? Wenn ja oder wenn Du Dir nicht sicher bist, klicke auf „Ja“ und folge den Anweisungen. Vielen Dank! Alles erledigt! Keine weiteren Maßnahmen erforderlich. Sie werden jetzt auf die offizielle Tangem-Website weitergeleitet. Bitte lesen und befolgen Sie dort die Anweisungen. Hast Du das Tangem-Supportteam schon einmal direkt über diese Anwendung kontaktiert? @@ -1107,6 +1119,7 @@ Einige Token-Guthaben konnten nicht aktualisiert werden Dies ist eine Testnet-Karte. Sie kann keine Transaktionen verarbeiten und sollte nur zu Test- und Entwicklungszwecken verwendet werden. Nur für Testzwecke + Der Kontostand ist möglicherweise veraltet. Aktualisiere bittre die Seite. Verwerfen Du hast eine unterbrochene Sicherung. Möchtest du diese fortsetzen? Ja, fortsetzen diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 9535f46439..a89e339efe 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -805,6 +805,10 @@ ステーキング残高が低いです 再ステーキングには最低%1$s %2$sが必要です。残高を補充してください。 %sが足りません + ステーキングのための残高が不足しています + リステーキングには最低3ADA が必要です。残高を補充してください。 + ADAが不足しています + ステーキングに必要な最小金額は5ADAを超える必要があります。ステーキングを開始するには残高を補充してください。 ネットワークの状態により、現在ステーキングはご利用いただけません。しばらくしてからもう一度お試しください。 新しいバリデーターを使用して%1$sネットワークにステーキングすると、以前にステーキングされた資金がすべてこのバリデーターに自動的に転送されます。 獲得した報酬をステーキングに再投資し、潜在的な収益を増やします。 @@ -872,6 +876,8 @@ Tangemのご紹介 100種類以上の分散型サービスで、NFTの交換・購入や、借入・預金を行うことができます。 Web3.0対応 + 続行するには少なくとも%1$sの受信取引が必要です + 残高不足 ネットワークは、あなたがトークンのスワップを承認していることを確認するために、トークン承認手数料を請求します。 より多くのトークンをより良いレートで、ウォレット内にて直接交換します。 新しいスワッププロバイダーが利用可能になりました! @@ -910,6 +916,7 @@ 売却できる資金がありません。アカウントに入金して、売却できるようにしてください。 送金する資金がありません。アカウントに入金して、送金できるようにしてください。 %sのスワップは、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。 + 表示残高はキャッシュにより古くなっている可能性があります。 %sネットワーク上の保留中の取引が完了すると、資金の売却が可能になります。 ネットワーク%s内の保留中の取引が完了すると、送金が可能になります。 %sの売却は、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。 @@ -970,6 +977,9 @@ ウォレット名の変更 すべてのロックを解除 %sですべてをロック解除 + ロック解除 + カードをスキャンしてアクセスロックを解除する + ロック解除が必要 ブロックチェーンにアクセスできません。後でもう一度お試しください。 カードまたはリングをスキャン このウォレットはすでに有効化されています。\nあなたが行ったのでない場合は、サポートに連絡してください。\nTangemは、事前に生成されたアクセスコードと一緒にウォレットを販売することはありません。 @@ -1083,7 +1093,7 @@ トークンを受け取る前に、トークンを関連付ける必要があります。 ネットワーク使用料が必要です 対応が必要です - ウォレットを作成してから7日以内にアプリまたはEメール経由でサポートに連絡しましたか?連絡したか不明な場合は、手順に従って完了してください。 + ウォレットの作成後、7日以内にアプリ経由でサポートに連絡しましたか?連絡した場合、あるいは連絡したかわからない場合は、「はい」をクリックして指示に従ってください。 ありがとうございます。準備完了です。これ以上の操作は必要ありません。 Tangemの公式ウェブサイトに移動します。そちらの指示に従ってください。 このアプリ経由でTangemサポートチームに直接連絡したことがありますか? diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 04c5129fac..e7e9bccc89 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -694,6 +694,7 @@ Отсканируйте карту или кольцо, чтобы изменить ее настройки. Изменения затронут только ту карту или кольцо, которые вы отсканировали, и не повлияют на другие устройства, привязанные к вашему кошельку. Приготовьте свой Tangem! Уведомление безопасности + Да На вашем балансе недостаточно средств для продажи криптовалюты. Пожалуйста, пополните нужный актив, чтобы продолжить. Недостаточно средств Продажа криптовалюты в вашем регионе временно недоступна. Мы активно работаем над тем, чтобы добавить эту возможность. Следите за нашими новостями! @@ -897,6 +898,8 @@ Встречайте Tangem Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах Поддержка Web 3.0 + Для отправки требуется входящая транзакция на сумму не менее %1$s + Недостаточно средств Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для обмена. Обменивайте больше токенов по лучшим курсам прямо в вашем кошельке. Новый провайдер обмена! @@ -1110,6 +1113,7 @@ Нравится Tangem? Вам необходимо провести ассоциацию токена для того, чтобы иметь возможность принимать его Необходима плата за аренду сети + Вы обращались в службу поддержки через приложение в течение 7 дней после создания кошелька? Если обращались или не уверены, нажмите «Да» и следуйте инструкциям. Спасибо! Всё в порядке! Дальнейшие действия не требуются. Вы будете перенаправлены на официальный сайт Tangem. Пожалуйста, прочитайте и выполните указанные там инструкции. Вы когда-либо обращались в службу поддержки Tangem напрямую из этого приложения? diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index 016834185c..eaaa71beea 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -1111,6 +1111,7 @@ Подобається Tangem? Вам необхідно провести асоціацію токена, щоб мати можливість приймати його Необхідна плата за оренду мережі + Чи зверталися в службу підтримки через додаток протягом 7 днів після створення гаманця? Якщо зверталися або не впевнені, натисніть «Так» і дотримуйтесь інструкцій. Дякуємо! Все добре! Подальших дій не потрібно. Ви будете перенаправлені на офіційний сайт Tangem. Будь ласка, прочитайте та виконайте вказані там інструкції. Ви коли-небудь зверталися до служби підтримки Tangem безпосередньо з цього додатку? diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 15e6dcf94d..258318407d 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -886,6 +886,8 @@ Meet Tangem Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services Web 3.0 Compatible + An incoming transaction of at least %1$s is required to proceed + Insufficient funds The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap. Exchange more tokens at better rates directly in your wallet. New Swap Provider Available! @@ -924,7 +926,7 @@ You do not have funds to sell. Top up your account to be able to sell funds from it. You do not have funds to send. Top up your account to be able to send funds from it. Swapping %s is not supported by current providers, but we are working to add more options. - The displayed balance might be outdated due to caching. + The displayed balance might be outdated due to caching. Selling funds will be available once the pending transaction(s) on the %s network is complete. Sending funds will be available once the pending transaction(s) in network %s is complete Selling %s is not supported by current providers, but we are working to add more options. @@ -985,6 +987,9 @@ Rename wallet Unlock all Unlock all with %s + Unlock + Scan your card to unlock access + Needed unlock Blockchain is unreachable. Try later Scan card or ring This wallet has already been activated earlier.\nIf it was not done by you, please contact support.\nTangem never sells wallets along with pre-generated access codes. @@ -1099,7 +1104,7 @@ You must associate your token before receiving tokens Network rent fee required Action required - Did you contact support via the app or email within 7 days of creating a wallet? If you did or are unsure, follow and complete the instructions. + Did you contact support via the app within 7 days of creating your wallet? If yes, or if you\'re unsure, click \'Yes\' and follow the instructions. Thank you! All set! No further actions required. You will now be redirected to the official Tangem website. Please read and follow instructions there. Have you ever contacted the Tangem support team directly through this application?