diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 3871825936..26d5547fcb 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -2197,6 +2197,8 @@ Missing backup This card has been previously used for transactions. If received from an untrusted source, consider withdrawing all funds. If it\'s your card, no action is required. Card has already signed transactions + Will be updated as soon as possible + Missing some token balances Your review keeps us motivated to make Tangem Wallet even better Enjoying Tangem? You must associate your token before receiving tokens diff --git a/core/ui/src/main/res/drawable/ic_error_sync_default_32.xml b/core/ui/src/main/res/drawable/ic_error_sync_default_32.xml new file mode 100644 index 0000000000..f1ec26b229 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_error_sync_default_32.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/ui/src/main/res/drawable/ic_warning_default_32.xml b/core/ui/src/main/res/drawable/ic_warning_default_32.xml new file mode 100644 index 0000000000..49ca5427e6 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_warning_default_32.xml @@ -0,0 +1,9 @@ + + + diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateNotificationsTransformer.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateNotificationsTransformer.kt index 49918ddbca..c292623e56 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateNotificationsTransformer.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateNotificationsTransformer.kt @@ -1,5 +1,6 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer +import com.tangem.blockchain.common.Blockchain import com.tangem.core.ui.R import com.tangem.core.ui.ds.button.TangemButtonType import com.tangem.core.ui.ds.image.TangemIconUM @@ -10,6 +11,8 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.core.ui.format.bigdecimal.shorted +import com.tangem.core.ui.res.TangemTheme import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.domain.tokens.model.warnings.DynamicAddressesWarnings @@ -17,30 +20,36 @@ import com.tangem.domain.tokens.model.warnings.HederaWarnings import com.tangem.domain.tokens.model.warnings.KaspaWarnings import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM +import com.tangem.utils.logging.TangemLogger import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList +import java.math.BigDecimal import com.tangem.core.res.R as CoreResR +@Suppress("LargeClass") internal class UpdateNotificationsTransformer( private val warnings: Set, private val clickIntents: TokenDetailsClickIntents, ) : Transformer { override fun transform(prevState: TokenDetailsUM): TokenDetailsUM { - val notifications = warnings.mapNotNull(::mapWarning).toImmutableList() + val notifications = warnings.map(::mapWarning).toImmutableList() return prevState.copy(notifications = notifications) } - @Suppress("LongMethod") - private fun mapWarning(warning: CryptoCurrencyWarning): TangemMessageUM? { + @Suppress("LongMethod", "CyclomaticComplexMethod") + private fun mapWarning(warning: CryptoCurrencyWarning): TangemMessageUM { return when (warning) { is CryptoCurrencyWarning.SomeNetworksUnreachable -> TangemMessageUM( id = "networks_unreachable", title = resourceReference(CoreResR.string.warning_network_unreachable_title), subtitle = resourceReference(CoreResR.string.warning_network_unreachable_message), messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.status.attention }, + ), ) is CryptoCurrencyWarning.BalanceNotEnoughForFee -> createFeeWarning( FeeWarningParams( @@ -50,6 +59,7 @@ internal class UpdateNotificationsTransformer( feeCurrencyName = warning.coinCurrency.name, feeCurrencySymbol = warning.coinCurrency.symbol, buyCurrency = warning.coinCurrency, + iconResId = R.drawable.ic_attention_default_24, ), ) is CryptoCurrencyWarning.CustomTokenNotEnoughForFee -> createFeeWarning( @@ -60,6 +70,7 @@ internal class UpdateNotificationsTransformer( feeCurrencyName = warning.feeCurrencyName, feeCurrencySymbol = warning.feeCurrencySymbol, buyCurrency = warning.feeCurrency, + iconResId = R.drawable.ic_attention_default_24, ), ) is CryptoCurrencyWarning.BeaconChainShutdown -> TangemMessageUM( @@ -67,18 +78,24 @@ internal class UpdateNotificationsTransformer( title = resourceReference(CoreResR.string.warning_beacon_chain_retirement_title), subtitle = resourceReference(CoreResR.string.warning_beacon_chain_retirement_content), messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.status.attention }, + ), ) is HederaWarnings.AssociateWarning -> TangemMessageUM( id = "hedera_associate", title = resourceReference(CoreResR.string.warning_hedera_missing_token_association_title), subtitle = resourceReference(CoreResR.string.warning_hedera_missing_token_association_message_brief), messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), buttonsUM = persistentListOf( TangemMessageButtonUM( text = resourceReference(CoreResR.string.warning_hedera_missing_token_association_button_title), - type = TangemButtonType.Primary, + type = TangemButtonType.PrimaryInverse, onClick = clickIntents::onAssociateClick, ), ), @@ -94,11 +111,14 @@ internal class UpdateNotificationsTransformer( ), ), messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), buttonsUM = persistentListOf( TangemMessageButtonUM( text = resourceReference(CoreResR.string.warning_hedera_missing_token_association_button_title), - type = TangemButtonType.Primary, + type = TangemButtonType.PrimaryInverse, onClick = clickIntents::onAssociateClick, ), ), @@ -114,11 +134,14 @@ internal class UpdateNotificationsTransformer( ), ), messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), buttonsUM = persistentListOf( TangemMessageButtonUM( text = resourceReference(CoreResR.string.warning_token_trustline_button_title), - type = TangemButtonType.Primary, + type = TangemButtonType.PrimaryInverse, onClick = clickIntents::onOpenTrustlineClick, ), ), @@ -133,34 +156,51 @@ internal class UpdateNotificationsTransformer( warning.currencySymbol, ), ), - messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + messageEffect = TangemMessageEffect.Warning, + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), buttonsUM = persistentListOf( + TangemMessageButtonUM( + text = resourceReference(CoreResR.string.common_cancel), + type = TangemButtonType.Secondary, + onClick = clickIntents::onDismissIncompleteTransactionClick, + ), TangemMessageButtonUM( text = resourceReference(CoreResR.string.alert_button_try_again), type = TangemButtonType.Primary, + tangemIconUM = TangemIconUM.Icon( + R.drawable.ic_tangem_24, + tintReference = { TangemTheme.colors2.graphic.neutral.primaryInverted }, + ), onClick = clickIntents::onRetryIncompleteTransactionClick, ), ), - onCloseClick = clickIntents::onDismissIncompleteTransactionClick, ) is CryptoCurrencyWarning.MigrationMaticToPol -> TangemMessageUM( id = "migration_matic_pol", title = resourceReference(CoreResR.string.warning_matic_migration_title), subtitle = resourceReference(CoreResR.string.warning_matic_migration_message), messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.status.attention }, + ), ) is CryptoCurrencyWarning.MigrationClore -> TangemMessageUM( id = "migration_clore", title = resourceReference(CoreResR.string.warning_clore_migration_title), subtitle = resourceReference(CoreResR.string.warning_clore_migration_description), - messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + messageEffect = TangemMessageEffect.Warning, + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), buttonsUM = persistentListOf( TangemMessageButtonUM( text = resourceReference(CoreResR.string.warning_clore_migration_button), - type = TangemButtonType.Primary, + type = TangemButtonType.PrimaryInverse, onClick = clickIntents::onCloreMigrationClick, ), ), @@ -170,23 +210,114 @@ internal class UpdateNotificationsTransformer( title = resourceReference(CoreResR.string.dynamic_addresses_notification_funds_found_title), subtitle = resourceReference(CoreResR.string.dynamic_addresses_notification_funds_found_description), messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.status.attention }, + ), buttonsUM = persistentListOf( TangemMessageButtonUM( text = resourceReference(CoreResR.string.common_learn_more), - type = TangemButtonType.Primary, + type = TangemButtonType.PrimaryInverse, onClick = clickIntents::onDynamicAddressesFundsFoundLearnMoreClick, ), ), ) - // Non-warning types — skip for redesign - is CryptoCurrencyWarning.ExistentialDeposit, - is CryptoCurrencyWarning.Rent, - is CryptoCurrencyWarning.SomeNetworksNoAccount, - is CryptoCurrencyWarning.TopUpWithoutReserve, - is CryptoCurrencyWarning.FeeResourceInfo, - is CryptoCurrencyWarning.UsedOutdatedDataWarning, - -> null + is CryptoCurrencyWarning.ExistentialDeposit -> TangemMessageUM( + id = "existential_deposit", + title = resourceReference(CoreResR.string.warning_existential_deposit_title), + subtitle = resourceReference( + CoreResR.string.warning_existential_deposit_message, + wrappedList(warning.currencyName, warning.edStringValueWithSymbol), + ), + messageEffect = TangemMessageEffect.None, + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_warning_default_32, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), + ) + is CryptoCurrencyWarning.Rent -> TangemMessageUM( + id = "rent_info", + title = resourceReference(CoreResR.string.warning_rent_fee_title), + subtitle = resourceReference( + CoreResR.string.warning_solana_rent_fee_message, + wrappedList( + warning.rent, + warning.exemptionAmount.format { crypto(warning.cryptoCurrency) }, + ), + ), + messageEffect = TangemMessageEffect.None, + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_warning_default_32, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), + buttonsUM = persistentListOf( + TangemMessageButtonUM( + text = resourceReference(CoreResR.string.common_later), + type = TangemButtonType.Secondary, + onClick = clickIntents::onCloseRentInfoNotification, + ), + ), + ) + is CryptoCurrencyWarning.SomeNetworksNoAccount -> TangemMessageUM( + id = "networks_no_account", + title = resourceReference(CoreResR.string.warning_no_account_title), + subtitle = resourceReference( + CoreResR.string.no_account_generic, + wrappedList( + warning.amountCurrency.network.name, + warning.amountToCreateAccount.format { + crypto(symbol = "", decimals = warning.amountCurrency.decimals) + }.trim(), + warning.amountCurrency.network.currencySymbol, + ), + ), + messageEffect = TangemMessageEffect.None, + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_warning_default_32, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), + ) + is CryptoCurrencyWarning.TopUpWithoutReserve -> TangemMessageUM( + id = "top_up_without_reserve", + title = resourceReference(CoreResR.string.warning_no_account_title), + subtitle = resourceReference(CoreResR.string.no_account_send_to_create), + messageEffect = TangemMessageEffect.None, + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_warning_default_32, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), + ) + is CryptoCurrencyWarning.FeeResourceInfo -> TangemMessageUM( + id = "fee_resource_info", + title = resourceReference(CoreResR.string.koinos_mana_level_title), + subtitle = resourceReference( + CoreResR.string.koinos_mana_level_description, + wrappedList( + formatMana(warning.amount), + warning.maxAmount?.let(::formatMana) ?: run { + TangemLogger.e( + "FeeResource maxAmount cannot be null in Koinos. Check KoinosWalletManager", + ) + "" + }, + ), + ), + messageEffect = TangemMessageEffect.None, + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_warning_default_32, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), + ) + is CryptoCurrencyWarning.UsedOutdatedDataWarning -> TangemMessageUM( + id = "used_outdated_data", + title = resourceReference(CoreResR.string.warning_outdated_data_title), + subtitle = resourceReference(CoreResR.string.warning_outdated_data_message), + messageEffect = TangemMessageEffect.None, + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_error_sync_default_32, + tintReference = { TangemTheme.colors2.graphic.status.attention }, + ), + ) } } @@ -198,7 +329,7 @@ internal class UpdateNotificationsTransformer( CoreResR.string.common_buy_currency, wrappedList(params.feeCurrencySymbol), ), - type = TangemButtonType.Primary, + type = TangemButtonType.PrimaryInverse, onClick = { clickIntents.onBuyCoinClick(params.buyCurrency) }, ), ) @@ -223,17 +354,25 @@ internal class UpdateNotificationsTransformer( ), ), messageEffect = TangemMessageEffect.None, - iconUM = TangemIconUM.Icon(R.drawable.ic_attention_default_24), + iconUM = TangemIconUM.Icon( + iconRes = params.iconResId, + tintReference = { TangemTheme.colors2.graphic.neutral.primary }, + ), buttonsUM = buttons, ) } - private data class FeeWarningParams( - val id: String, - val currency: CryptoCurrency, - val networkName: String, - val feeCurrencyName: String, - val feeCurrencySymbol: String, - val buyCurrency: CryptoCurrency?, - ) -} \ No newline at end of file + private fun formatMana(amount: BigDecimal): String { + return amount.format { crypto(symbol = "", decimals = Blockchain.Koinos.decimals()).shorted() } + } +} + +private data class FeeWarningParams( + val id: String, + val currency: CryptoCurrency, + val networkName: String, + val feeCurrencyName: String, + val feeCurrencySymbol: String, + val buyCurrency: CryptoCurrency?, + val iconResId: Int, +) \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index 87a2b542dd..08b7dced0e 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 @@ -45,7 +45,6 @@ import com.tangem.core.ui.components.haze.hazeSourceTangem import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.themedColor -import com.tangem.core.ui.res.LocalRootBackgroundColor import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign import com.tangem.domain.models.account.CryptoPortfolioIcon @@ -86,14 +85,14 @@ internal fun TokenDetailsScreen( val statusBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getTop(this).toDp() } val topBarTotalHeight = TopBarHeight + statusBarHeight - val rootBackground by LocalRootBackgroundColor.current + val rootBackground = TangemTheme.colors2.surface.level2 var marketBlockHeight by remember { mutableStateOf(0.dp) } val effectiveBottomPadding = marketBlockHeight + TangemTheme.dimens2.x4 Box( modifier = modifier .fillMaxSize() - .background(TangemTheme.colors2.surface.level2), + .background(rootBackground), ) { Box( modifier = Modifier diff --git a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateNotificationsTransformerTest.kt b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateNotificationsTransformerTest.kt index 19d4cea5ca..b87755d855 100644 --- a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateNotificationsTransformerTest.kt +++ b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/transformer/UpdateNotificationsTransformerTest.kt @@ -223,7 +223,7 @@ class UpdateNotificationsTransformerTest { } @Test - fun `GIVEN KaspaIncompleteTransaction WHEN transform THEN notification with button and close is created`() { + fun `GIVEN KaspaIncompleteTransaction WHEN transform THEN notification with cancel and try again buttons is created`() { // GIVEN val currency: CryptoCurrency = mockk(relaxed = true) val transformer = createTransformer( @@ -243,16 +243,17 @@ class UpdateNotificationsTransformerTest { // THEN assertThat(result.notifications).hasSize(1) assertThat(result.notifications.first().id).isEqualTo("kaspa_incomplete") - assertThat(result.notifications.first().buttonsUM).hasSize(1) - assertThat(result.notifications.first().onCloseClick).isNotNull() + assertThat(result.notifications.first().buttonsUM).hasSize(2) + assertThat(result.notifications.first().onCloseClick).isNull() + assertThat(result.notifications.first().messageEffect).isEqualTo(TangemMessageEffect.Warning) } // endregion - // region Skipped warnings + // region Newly added warnings @Test - fun `GIVEN ExistentialDeposit WHEN transform THEN notification is skipped`() { + fun `GIVEN ExistentialDeposit WHEN transform THEN notification with id existential_deposit is created`() { // GIVEN val transformer = createTransformer( warnings = setOf( @@ -267,11 +268,13 @@ class UpdateNotificationsTransformerTest { val result = transformer.transform(initialState()) // THEN - assertThat(result.notifications).isEmpty() + assertThat(result.notifications).hasSize(1) + assertThat(result.notifications.first().id).isEqualTo("existential_deposit") + assertThat(result.notifications.first().buttonsUM).isEmpty() } @Test - fun `GIVEN Rent WHEN transform THEN notification is skipped`() { + fun `GIVEN Rent WHEN transform THEN notification with id rent_info and later button is created`() { // GIVEN val transformer = createTransformer( warnings = setOf( @@ -287,11 +290,120 @@ class UpdateNotificationsTransformerTest { val result = transformer.transform(initialState()) // THEN - assertThat(result.notifications).isEmpty() + assertThat(result.notifications).hasSize(1) + assertThat(result.notifications.first().id).isEqualTo("rent_info") + assertThat(result.notifications.first().onCloseClick).isNull() + assertThat(result.notifications.first().buttonsUM).hasSize(1) } @Test - fun `GIVEN UsedOutdatedDataWarning WHEN transform THEN notification is skipped`() { + fun `GIVEN Rent WHEN later clicked THEN onCloseRentInfoNotification is called`() { + // GIVEN + val transformer = createTransformer( + warnings = setOf( + CryptoCurrencyWarning.Rent( + rent = BigDecimal("0.00001"), + exemptionAmount = BigDecimal("0.01"), + cryptoCurrency = mockk(relaxed = true), + ), + ), + ) + + // WHEN + val result = transformer.transform(initialState()) + result.notifications.first().buttonsUM.first().onClick() + + // THEN + verify(exactly = 1) { clickIntents.onCloseRentInfoNotification() } + } + + @Test + fun `GIVEN SomeNetworksNoAccount WHEN transform THEN notification with id networks_no_account is created`() { + // GIVEN + val amountCurrency: CryptoCurrency = mockk(relaxed = true) { + io.mockk.every { decimals } returns 7 + io.mockk.every { network } returns mockk(relaxed = true) { + io.mockk.every { name } returns "Stellar" + io.mockk.every { currencySymbol } returns "XLM" + } + } + val transformer = createTransformer( + warnings = setOf( + CryptoCurrencyWarning.SomeNetworksNoAccount( + amountToCreateAccount = BigDecimal("1.0"), + amountCurrency = amountCurrency, + ), + ), + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + assertThat(result.notifications).hasSize(1) + assertThat(result.notifications.first().id).isEqualTo("networks_no_account") + assertThat(result.notifications.first().buttonsUM).isEmpty() + } + + @Test + fun `GIVEN TopUpWithoutReserve WHEN transform THEN notification with id top_up_without_reserve is created`() { + // GIVEN + val transformer = createTransformer( + warnings = setOf(CryptoCurrencyWarning.TopUpWithoutReserve), + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + assertThat(result.notifications).hasSize(1) + assertThat(result.notifications.first().id).isEqualTo("top_up_without_reserve") + assertThat(result.notifications.first().buttonsUM).isEmpty() + } + + @Test + fun `GIVEN FeeResourceInfo WHEN transform THEN notification with id fee_resource_info is created`() { + // GIVEN + val transformer = createTransformer( + warnings = setOf( + CryptoCurrencyWarning.FeeResourceInfo( + amount = BigDecimal("50.0"), + maxAmount = BigDecimal("100.0"), + ), + ), + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + assertThat(result.notifications).hasSize(1) + assertThat(result.notifications.first().id).isEqualTo("fee_resource_info") + assertThat(result.notifications.first().buttonsUM).isEmpty() + } + + @Test + fun `GIVEN FeeResourceInfo with null maxAmount WHEN transform THEN notification is still created`() { + // GIVEN + val transformer = createTransformer( + warnings = setOf( + CryptoCurrencyWarning.FeeResourceInfo( + amount = BigDecimal("50.0"), + maxAmount = null, + ), + ), + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + assertThat(result.notifications).hasSize(1) + assertThat(result.notifications.first().id).isEqualTo("fee_resource_info") + } + + @Test + fun `GIVEN UsedOutdatedDataWarning WHEN transform THEN notification with id used_outdated_data is created`() { // GIVEN val transformer = createTransformer( warnings = setOf(CryptoCurrencyWarning.UsedOutdatedDataWarning), @@ -301,7 +413,8 @@ class UpdateNotificationsTransformerTest { val result = transformer.transform(initialState()) // THEN - assertThat(result.notifications).isEmpty() + assertThat(result.notifications).hasSize(1) + assertThat(result.notifications.first().id).isEqualTo("used_outdated_data") } // endregion @@ -309,7 +422,7 @@ class UpdateNotificationsTransformerTest { // region Message effect @Test - fun `GIVEN any mapped warning WHEN transform THEN messageEffect is None`() { + fun `GIVEN SomeNetworksUnreachable WHEN transform THEN messageEffect is None`() { // GIVEN val transformer = createTransformer( warnings = setOf(CryptoCurrencyWarning.SomeNetworksUnreachable), @@ -322,6 +435,20 @@ class UpdateNotificationsTransformerTest { assertThat(result.notifications.first().messageEffect).isEqualTo(TangemMessageEffect.None) } + @Test + fun `GIVEN MigrationClore WHEN transform THEN messageEffect is Warning`() { + // GIVEN + val transformer = createTransformer( + warnings = setOf(CryptoCurrencyWarning.MigrationClore), + ) + + // WHEN + val result = transformer.transform(initialState()) + + // THEN + assertThat(result.notifications.first().messageEffect).isEqualTo(TangemMessageEffect.Warning) + } + // endregion // region Icon @@ -345,7 +472,7 @@ class UpdateNotificationsTransformerTest { // region Multiple warnings @Test - fun `GIVEN multiple warnings with some skipped WHEN transform THEN only mapped warnings are in notifications`() { + fun `GIVEN multiple warnings WHEN transform THEN all are mapped to notifications`() { // GIVEN val transformer = createTransformer( warnings = setOf( @@ -360,10 +487,12 @@ class UpdateNotificationsTransformerTest { val result = transformer.transform(initialState()) // THEN - assertThat(result.notifications).hasSize(2) + assertThat(result.notifications).hasSize(4) assertThat(result.notifications.map { it.id }).containsExactly( "networks_unreachable", "beacon_chain_shutdown", + "used_outdated_data", + "top_up_without_reserve", ) } @@ -410,7 +539,29 @@ class UpdateNotificationsTransformerTest { } @Test - fun `GIVEN KaspaIncompleteTransaction WHEN retry clicked THEN onRetryIncompleteTransactionClick is called`() { + fun `GIVEN KaspaIncompleteTransaction WHEN try again clicked THEN onRetryIncompleteTransactionClick is called`() { + // GIVEN + val transformer = createTransformer( + warnings = setOf( + KaspaWarnings.IncompleteTransaction( + currency = mockk(relaxed = true), + amount = BigDecimal("100"), + currencySymbol = "KAS", + currencyDecimals = 8, + ), + ), + ) + + // WHEN + val result = transformer.transform(initialState()) + result.notifications.first().buttonsUM[1].onClick() + + // THEN + verify(exactly = 1) { clickIntents.onRetryIncompleteTransactionClick() } + } + + @Test + fun `GIVEN KaspaIncompleteTransaction WHEN cancel clicked THEN onDismissIncompleteTransactionClick is called`() { // GIVEN val transformer = createTransformer( warnings = setOf( @@ -427,28 +578,6 @@ class UpdateNotificationsTransformerTest { val result = transformer.transform(initialState()) result.notifications.first().buttonsUM.first().onClick() - // THEN - verify(exactly = 1) { clickIntents.onRetryIncompleteTransactionClick() } - } - - @Test - fun `GIVEN KaspaIncompleteTransaction WHEN close clicked THEN onDismissIncompleteTransactionClick is called`() { - // GIVEN - val transformer = createTransformer( - warnings = setOf( - KaspaWarnings.IncompleteTransaction( - currency = mockk(relaxed = true), - amount = BigDecimal("100"), - currencySymbol = "KAS", - currencyDecimals = 8, - ), - ), - ) - - // WHEN - val result = transformer.transform(initialState()) - result.notifications.first().onCloseClick!!.invoke() - // THEN verify(exactly = 1) { clickIntents.onDismissIncompleteTransactionClick() } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt index aa6679cd47..5a0df5c3ec 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt @@ -50,8 +50,8 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t data object UsedOutdatedData : WalletNotificationUM( messageUM = TangemMessageUM( id = "UsedOutdatedDataNotification", - title = stringReference("Missing some token balances"), // todo redesign main lokalise - subtitle = stringReference("Will be updated as soon as possible"), // todo redesign main lokalise + title = resourceReference(com.tangem.core.res.R.string.warning_outdated_data_title), + subtitle = resourceReference(com.tangem.core.res.R.string.warning_outdated_data_message), iconUM = TangemIconUM.Icon( iconRes = R.drawable.ic_error_sync_default_24, tintReference = { TangemTheme.colors2.graphic.status.attention }, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/converter/YieldSupplyToEarnBlockConverter.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/converter/YieldSupplyToEarnBlockConverter.kt index dd93e5a6aa..2dbde67434 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/converter/YieldSupplyToEarnBlockConverter.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/converter/YieldSupplyToEarnBlockConverter.kt @@ -54,11 +54,7 @@ internal class YieldSupplyToEarnBlockConverter : Converter