Updated on 2026-08-14

This commit is contained in:
Tangem 2023-10-16 15:00:18 +03:00
parent 4ed210cd90
commit 1d0028f8b9
7 changed files with 133 additions and 110 deletions

View file

@ -10,46 +10,31 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.features.tokendetails.impl.R
@Immutable
internal sealed class TokenDetailsNotification {
internal sealed class TokenDetailsNotification(val config: NotificationConfig) {
abstract val config: NotificationConfig
sealed class Warning(
title: TextReference,
subtitle: TextReference,
iconResId: Int = R.drawable.img_attention_20,
buttonsState: NotificationConfig.ButtonsState? = null,
) : TokenDetailsNotification(
config = NotificationConfig(
title = title,
subtitle = subtitle,
iconResId = iconResId,
buttonsState = buttonsState,
),
) {
sealed class Informational : TokenDetailsNotification()
sealed class Warning : TokenDetailsNotification()
data class RentInfo(
private val rentInfo: CryptoCurrencyWarning.Rent,
private val onCloseClick: () -> Unit,
) : Warning() {
override val config = NotificationConfig(
title = TextReference.Res(R.string.warning_rent_fee_title),
subtitle = TextReference.Res(
id = R.string.warning_solana_rent_fee_message,
formatArgs = wrappedList(rentInfo.rent, rentInfo.exemptionAmount),
),
iconResId = R.drawable.img_attention_20,
onCloseClick = onCloseClick,
object NetworksUnreachable : Warning(
title = resourceReference(R.string.warning_network_unreachable_title),
subtitle = resourceReference(R.string.warning_network_unreachable_message),
)
}
data class ExistentialDeposit(
private val existentialInfo: CryptoCurrencyWarning.ExistentialDeposit,
) : Informational() {
override val config = NotificationConfig(
title = resourceReference(R.string.warning_existential_deposit_title),
subtitle = TextReference.Res(
id = R.string.warning_existential_deposit_message,
formatArgs = wrappedList(existentialInfo.currencyName, existentialInfo.edStringValueWithSymbol),
),
iconResId = R.drawable.ic_alert_circle_24,
)
}
data class NetworkFee(
private val feeInfo: CryptoCurrencyWarning.BalanceNotEnoughForFee,
private val onBuyClick: () -> Unit,
) : Warning() {
override val config = NotificationConfig(
data class NetworkFee(
private val feeInfo: CryptoCurrencyWarning.BalanceNotEnoughForFee,
private val onBuyClick: () -> Unit,
) : Warning(
title = TextReference.Res(
id = R.string.warning_send_blocked_funds_for_fee_title,
formatArgs = wrappedList(feeInfo.blockchainFullName),
@ -75,22 +60,46 @@ internal sealed class TokenDetailsNotification {
)
}
object NetworksUnreachable : Warning() {
override val config = NotificationConfig(
title = resourceReference(R.string.warning_network_unreachable_title),
subtitle = resourceReference(R.string.warning_network_unreachable_message),
iconResId = R.drawable.img_attention_20,
sealed class Informational(
title: TextReference,
subtitle: TextReference,
onCloseClick: (() -> Unit)? = null,
) : TokenDetailsNotification(
config = NotificationConfig(
title = title,
subtitle = subtitle,
iconResId = R.drawable.ic_alert_circle_24,
onCloseClick = onCloseClick,
),
) {
data class RentInfo(
private val rentInfo: CryptoCurrencyWarning.Rent,
private val onCloseClick: () -> Unit,
) : Informational(
title = TextReference.Res(R.string.warning_rent_fee_title),
subtitle = TextReference.Res(
id = R.string.warning_solana_rent_fee_message,
formatArgs = wrappedList(rentInfo.rent, rentInfo.exemptionAmount),
),
onCloseClick = onCloseClick,
)
}
class NetworksNoAccount(val network: String, val symbol: String, val amount: String) : Informational() {
override val config = NotificationConfig(
data class ExistentialDeposit(
private val existentialInfo: CryptoCurrencyWarning.ExistentialDeposit,
) : Informational(
title = resourceReference(R.string.warning_existential_deposit_title),
subtitle = TextReference.Res(
id = R.string.warning_existential_deposit_message,
formatArgs = wrappedList(existentialInfo.currencyName, existentialInfo.edStringValueWithSymbol),
),
)
class NetworksNoAccount(val network: String, val symbol: String, val amount: String) : Informational(
title = resourceReference(R.string.warning_no_account_title),
subtitle = resourceReference(
R.string.no_account_generic,
wrappedList(network, amount, symbol),
),
iconResId = R.drawable.ic_alert_circle_24,
)
}
}

View file

@ -40,7 +40,7 @@ internal class TokenDetailsLoadedBalanceConverter(
return state.copy(
tokenBalanceBlockState = TokenDetailsBalanceBlockState.Error(state.tokenBalanceBlockState.actionButtons),
marketPriceBlockState = MarketPriceBlockState.Error(state.marketPriceBlockState.currencySymbol),
notifications = persistentListOf(TokenDetailsNotification.NetworksUnreachable),
notifications = persistentListOf(TokenDetailsNotification.Warning.NetworksUnreachable),
)
}

View file

@ -19,25 +19,25 @@ internal class TokenDetailsNotificationConverter(
fun removeRentInfo(currentState: TokenDetailsState): ImmutableList<TokenDetailsNotification> {
val newNotifications = currentState.notifications.toMutableList()
newNotifications.removeBy { it is TokenDetailsNotification.RentInfo }
newNotifications.removeBy { it is TokenDetailsNotification.Informational.RentInfo }
return newNotifications.toImmutableList()
}
private fun mapToNotification(warning: CryptoCurrencyWarning): TokenDetailsNotification {
return when (warning) {
is CryptoCurrencyWarning.BalanceNotEnoughForFee -> TokenDetailsNotification.NetworkFee(
is CryptoCurrencyWarning.BalanceNotEnoughForFee -> TokenDetailsNotification.Warning.NetworkFee(
feeInfo = warning,
onBuyClick = clickIntents::onBuyClick,
)
is CryptoCurrencyWarning.ExistentialDeposit -> TokenDetailsNotification.ExistentialDeposit(
is CryptoCurrencyWarning.ExistentialDeposit -> TokenDetailsNotification.Informational.ExistentialDeposit(
existentialInfo = warning,
)
is CryptoCurrencyWarning.Rent -> TokenDetailsNotification.RentInfo(
is CryptoCurrencyWarning.Rent -> TokenDetailsNotification.Informational.RentInfo(
rentInfo = warning,
onCloseClick = clickIntents::onCloseRentInfoNotification,
)
CryptoCurrencyWarning.SomeNetworksUnreachable -> TokenDetailsNotification.NetworksUnreachable
is CryptoCurrencyWarning.SomeNetworksNoAccount -> TokenDetailsNotification.NetworksNoAccount(
CryptoCurrencyWarning.SomeNetworksUnreachable -> TokenDetailsNotification.Warning.NetworksUnreachable
is CryptoCurrencyWarning.SomeNetworksNoAccount -> TokenDetailsNotification.Informational.NetworksNoAccount(
network = warning.amountCurrency.name,
amount = warning.amountToCreateAccount.toString(),
symbol = warning.amountCurrency.symbol,

View file

@ -382,7 +382,7 @@ internal object WalletPreviewData {
),
notifications = persistentListOf(
WalletNotification.Critical.DevCard,
WalletNotification.MissingAddresses(missingAddressesCount = 0, onGenerateClick = {}),
WalletNotification.Informational.MissingAddresses(missingAddressesCount = 0, onGenerateClick = {}),
WalletNotification.Warning.NetworksUnreachable,
),
bottomSheetConfig = bottomSheet,

View file

@ -31,16 +31,6 @@ sealed class WalletNotification(val config: NotificationConfig) {
subtitle = resourceReference(id = R.string.warning_developer_card_message),
)
object DemoCard : Critical(
title = resourceReference(id = R.string.warning_demo_mode_title),
subtitle = resourceReference(id = R.string.warning_demo_mode_message),
)
object TestNetCard : Critical(
title = resourceReference(id = R.string.warning_testnet_card_title),
subtitle = resourceReference(id = R.string.warning_testnet_card_message),
)
object FailedCardValidation : Critical(
title = resourceReference(id = R.string.warning_failed_to_verify_card_title),
subtitle = resourceReference(id = R.string.warning_failed_to_verify_card_message),
@ -96,35 +86,53 @@ sealed class WalletNotification(val config: NotificationConfig) {
subtitle = resourceReference(id = R.string.warning_number_of_signed_hashes_incorrect_message),
onCloseClick = onCloseClick,
)
object TestNetCard : Warning(
title = resourceReference(id = R.string.warning_testnet_card_title),
subtitle = resourceReference(id = R.string.warning_testnet_card_message),
)
}
data class MissingAddresses(val missingAddressesCount: Int, val onGenerateClick: () -> Unit) : WalletNotification(
sealed class Informational(
title: TextReference,
subtitle: TextReference,
buttonsState: NotificationConfig.ButtonsState? = null,
) : WalletNotification(
config = NotificationConfig(
title = title,
subtitle = subtitle,
iconResId = R.drawable.ic_alert_circle_24,
buttonsState = buttonsState,
),
) {
data class MissingAddresses(val missingAddressesCount: Int, val onGenerateClick: () -> Unit) : Informational(
title = resourceReference(id = R.string.warning_missing_derivation_title),
subtitle = pluralReference(
id = R.plurals.warning_missing_derivation_message,
count = missingAddressesCount,
formatArgs = wrappedList(missingAddressesCount),
),
iconResId = R.drawable.ic_alert_circle_24,
buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig(
text = resourceReference(id = R.string.common_generate_addresses),
iconResId = R.drawable.ic_tangem_24,
onClick = onGenerateClick,
),
),
)
)
data class NoAccount(val network: String, val symbol: String, val amount: String) : WalletNotification(
config = NotificationConfig(
data class NoAccount(val network: String, val symbol: String, val amount: String) : Informational(
title = resourceReference(id = R.string.warning_no_account_title),
subtitle = resourceReference(
id = R.string.no_account_generic,
wrappedList(network, amount, symbol),
),
iconResId = R.drawable.ic_alert_circle_24,
),
)
)
object DemoCard : Informational(
title = resourceReference(id = R.string.warning_demo_mode_title),
subtitle = resourceReference(id = R.string.warning_demo_mode_message),
)
}
data class UnlockWallets(val onClick: () -> Unit) : WalletNotification(
config = NotificationConfig(

View file

@ -29,10 +29,9 @@ internal fun LazyListScope.notifications(configs: ImmutableList<WalletNotificati
modifier = modifier.animateItemPlacement(),
iconTint = when (it) {
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
is WalletNotification.MissingAddresses -> TangemTheme.colors.icon.accent
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
is WalletNotification.NoAccount -> TangemTheme.colors.icon.accent
is WalletNotification.Warning -> null
},
)

View file

@ -47,11 +47,11 @@ internal class WalletNotificationsListFactory(
buildList {
addCriticalNotifications(cardTypesResolver)
addMissingAddressesNotification(cryptoCurrencyList)
addRateTheAppNotification(isReadyToShowRating)
addInformationalNotifications(cardTypesResolver, cryptoCurrencyList)
addWarningNotifications(cardTypesResolver, cryptoCurrencyList, wasCardScanned, isNeedToBackup)
addRateTheAppNotification(isReadyToShowRating)
}.toImmutableList()
}
}
@ -62,16 +62,6 @@ internal class WalletNotificationsListFactory(
condition = !cardTypesResolver.isReleaseFirmwareType(),
)
addIf(
element = WalletNotification.Critical.DemoCard,
condition = isDemoCardUseCase(cardId = cardTypesResolver.getCardId()),
)
addIf(
element = WalletNotification.Critical.TestNetCard,
condition = cardTypesResolver.isTestCard(),
)
addIf(
element = WalletNotification.Critical.FailedCardValidation,
condition = cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.isAttestationFailed(),
@ -85,28 +75,6 @@ internal class WalletNotificationsListFactory(
}
}
private fun MutableList<WalletNotification>.addMissingAddressesNotification(
cryptoCurrencyList: List<CryptoCurrencyStatus>,
) {
val missedAddressCurrencies = cryptoCurrencyList.getMissedAddressCurrencies()
addIf(
element = WalletNotification.MissingAddresses(
missingAddressesCount = missedAddressCurrencies.count(),
onGenerateClick = {
clickIntents.onGenerateMissedAddressesClick(missedAddressCurrencies = missedAddressCurrencies)
},
),
condition = missedAddressCurrencies.isNotEmpty(),
)
}
private fun List<CryptoCurrencyStatus>.getMissedAddressCurrencies(): List<CryptoCurrency> {
return this
.filter { it.value is CryptoCurrencyStatus.MissedDerivation }
.map(CryptoCurrencyStatus::currency)
}
private fun MutableList<WalletNotification>.addRateTheAppNotification(isReadyToShowRating: Boolean) {
addIf(
element = WalletNotification.RateApp(
@ -131,6 +99,11 @@ internal class WalletNotificationsListFactory(
condition = isNeedToBackup,
)
addIf(
element = WalletNotification.Warning.TestNetCard,
condition = cardTypesResolver.isTestCard(),
)
val isDemo = isDemoCardUseCase(cardId = cardTypesResolver.getCardId())
if (cardTypesResolver.isMultiwalletAllowed()) {
addIf(
@ -158,10 +131,44 @@ internal class WalletNotificationsListFactory(
}
}
private fun MutableList<WalletNotification>.addInformationalNotifications(
cardTypesResolver: CardTypesResolver,
cryptoCurrencyList: List<CryptoCurrencyStatus>,
) {
addIf(
element = WalletNotification.Informational.DemoCard,
condition = isDemoCardUseCase(cardId = cardTypesResolver.getCardId()),
)
addMissingAddressesNotification(cryptoCurrencyList)
}
private fun MutableList<WalletNotification>.addIf(element: WalletNotification, condition: Boolean) {
if (condition) add(element = element)
}
private fun MutableList<WalletNotification>.addMissingAddressesNotification(
cryptoCurrencyList: List<CryptoCurrencyStatus>,
) {
val missedAddressCurrencies = cryptoCurrencyList.getMissedAddressCurrencies()
addIf(
element = WalletNotification.Informational.MissingAddresses(
missingAddressesCount = missedAddressCurrencies.count(),
onGenerateClick = {
clickIntents.onGenerateMissedAddressesClick(missedAddressCurrencies = missedAddressCurrencies)
},
),
condition = missedAddressCurrencies.isNotEmpty(),
)
}
private fun List<CryptoCurrencyStatus>.getMissedAddressCurrencies(): List<CryptoCurrency> {
return this
.filter { it.value is CryptoCurrencyStatus.MissedDerivation }
.map(CryptoCurrencyStatus::currency)
}
private fun List<CryptoCurrencyStatus>.hasUnreachableNetworks(): Boolean {
return any { it.value is CryptoCurrencyStatus.Unreachable }
}
@ -172,7 +179,7 @@ internal class WalletNotificationsListFactory(
val amountToCreateAccount = (noAccountNetwork.value as? CryptoCurrencyStatus.NoAccount)
?.amountToCreateAccount.toString()
add(
element = WalletNotification.NoAccount(
element = WalletNotification.Informational.NoAccount(
network = noAccountNetwork.currency.name,
amount = amountToCreateAccount,
symbol = noAccountNetwork.currency.symbol,