Updated on 2026-08-14
This commit is contained in:
parent
9aa840f892
commit
b654ab08a7
15 changed files with 204 additions and 36 deletions
|
|
@ -39,6 +39,23 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) {
|
|||
),
|
||||
)
|
||||
|
||||
data class SwapPromo(
|
||||
val onSwapClick: () -> Unit,
|
||||
val onCloseClick: () -> Unit,
|
||||
) : TokenDetailsNotification(
|
||||
config = NotificationConfig(
|
||||
title = resourceReference(id = R.string.token_swap_promotion_title),
|
||||
subtitle = resourceReference(id = R.string.token_swap_promotion_message),
|
||||
iconResId = R.drawable.ic_swap_promo_34,
|
||||
backgroundResId = R.drawable.img_swap_promo_banner_background,
|
||||
onCloseClick = onCloseClick,
|
||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
text = resourceReference(id = com.tangem.core.ui.R.string.token_swap_promotion_button),
|
||||
onClick = onSwapClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
object NetworksUnreachable : Warning(
|
||||
title = resourceReference(R.string.warning_network_unreachable_title),
|
||||
subtitle = resourceReference(R.string.warning_network_unreachable_message),
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ internal class TokenDetailsNotificationConverter(
|
|||
is CryptoCurrencyWarning.HasPendingTransactions -> TokenDetailsNotification.HasPendingTransactions(
|
||||
coinSymbol = warning.blockchainSymbol,
|
||||
)
|
||||
is CryptoCurrencyWarning.SwapPromo -> TokenDetailsNotification.SwapPromo(
|
||||
onSwapClick = clickIntents::onSwapClick,
|
||||
onCloseClick = clickIntents::onSwapPromoDismiss,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBotto
|
|||
import com.tangem.core.ui.components.marketprice.MarketPriceBlock
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.notifications.NotificationWithBackground
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.core.ui.components.transactions.txHistoryItems
|
||||
import com.tangem.core.ui.event.EventEffect
|
||||
|
|
@ -104,14 +105,21 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
|
|||
key = { it::class.java },
|
||||
contentType = { it.config::class.java },
|
||||
itemContent = {
|
||||
Notification(
|
||||
modifier = itemModifier.animateItemPlacement(),
|
||||
config = it.config,
|
||||
iconTint = when (it) {
|
||||
is TokenDetailsNotification.Warning -> null
|
||||
is TokenDetailsNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
},
|
||||
)
|
||||
if (it is TokenDetailsNotification.SwapPromo) {
|
||||
NotificationWithBackground(
|
||||
config = it.config,
|
||||
modifier = itemModifier.animateItemPlacement(),
|
||||
)
|
||||
} else {
|
||||
Notification(
|
||||
modifier = itemModifier.animateItemPlacement(),
|
||||
config = it.config,
|
||||
iconTint = when (it) {
|
||||
is TokenDetailsNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
if (state.isMarketPriceAvailable) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels
|
|||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
interface TokenDetailsClickIntents {
|
||||
|
||||
fun onBackClick()
|
||||
|
|
@ -42,4 +43,6 @@ interface TokenDetailsClickIntents {
|
|||
fun onSwapTransactionClick(txId: String)
|
||||
|
||||
fun onGoToProviderClick(url: String)
|
||||
|
||||
fun onSwapPromoDismiss()
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
|||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.settings.ShouldShowSwapPromoTokenUseCase
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -35,8 +36,8 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.feature.swap.domain.api.SwapRepository
|
||||
import com.tangem.feature.swap.domain.SwapTransactionRepository
|
||||
import com.tangem.feature.swap.domain.api.SwapRepository
|
||||
import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
|
|
@ -74,6 +75,7 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase,
|
||||
private val shouldShowSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase,
|
||||
private val swapRepository: SwapRepository,
|
||||
private val swapTransactionRepository: SwapTransactionRepository,
|
||||
private val swapTransactionStatusStore: SwapTransactionStatusStore,
|
||||
|
|
@ -547,6 +549,12 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
router.openUrl(url)
|
||||
}
|
||||
|
||||
override fun onSwapPromoDismiss() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
shouldShowSwapPromoTokenUseCase.neverToShow()
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val EXCHANGE_STATUS_UPDATE_DELAY = 10_000L
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,4 +166,16 @@ sealed class WalletNotification(val config: NotificationConfig) {
|
|||
onCloseClick = onCloseClick,
|
||||
),
|
||||
)
|
||||
|
||||
data class SwapPromo(
|
||||
val onCloseClick: () -> Unit,
|
||||
) : WalletNotification(
|
||||
config = NotificationConfig(
|
||||
title = resourceReference(id = R.string.main_swap_promotion_title),
|
||||
subtitle = resourceReference(id = R.string.main_swap_promotion_message),
|
||||
iconResId = R.drawable.ic_swap_promo_34,
|
||||
backgroundResId = R.drawable.img_swap_promo_banner_background,
|
||||
onCloseClick = onCloseClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.lazy.LazyListScope
|
|||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.notifications.NotificationWithBackground
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -24,17 +25,24 @@ internal fun LazyListScope.notifications(configs: ImmutableList<WalletNotificati
|
|||
key = { it::class.java },
|
||||
contentType = { it::class.java },
|
||||
itemContent = {
|
||||
Notification(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
iconTint = when (it) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
|
||||
is WalletNotification.Warning -> null
|
||||
},
|
||||
)
|
||||
if (it is WalletNotification.SwapPromo) {
|
||||
NotificationWithBackground(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
)
|
||||
} else {
|
||||
Notification(
|
||||
config = it.config,
|
||||
modifier = modifier.animateItemPlacement(),
|
||||
iconTint = when (it) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -72,4 +72,6 @@ internal interface WalletClickIntents {
|
|||
fun onExploreClick()
|
||||
|
||||
fun onTransactionClick(txHash: String)
|
||||
|
||||
fun onCloseSwapPromoNotificationClick()
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import com.tangem.domain.common.CardTypesResolver
|
|||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.settings.ShouldShowSwapPromoWalletUseCase
|
||||
import com.tangem.domain.tokens.GetMissedAddressesCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.error.GetCurrenciesError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -26,16 +27,21 @@ import kotlinx.coroutines.flow.flowOf
|
|||
* @property isDemoCardUseCase use case that checks if card is demo
|
||||
* @property isReadyToShowRateAppUseCase use case that checks if card is user already rate app
|
||||
* @property isNeedToBackupUseCase use case that checks if wallet need backup cards
|
||||
* @property getMissedAddressCryptoCurrenciesUseCase use case that gets missed address crypto currencies
|
||||
* @property hasSingleWalletSignedHashesUseCase use case that checks if single wallet signed hashes
|
||||
* @property shouldShowSwapPromoWalletUseCase use case that checks if should show swap promo
|
||||
* @property clickIntents screen click intents
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
internal class WalletNotificationsListFactory(
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
private val getMissedAddressCryptoCurrenciesUseCase: GetMissedAddressesCryptoCurrenciesUseCase,
|
||||
private val hasSingleWalletSignedHashesUseCase: HasSingleWalletSignedHashesUseCase,
|
||||
private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) {
|
||||
|
||||
|
|
@ -51,9 +57,12 @@ internal class WalletNotificationsListFactory(
|
|||
flow2 = isReadyToShowRateAppUseCase().conflate(),
|
||||
flow3 = isNeedToBackupUseCase(selectedWallet.walletId).conflate(),
|
||||
flow4 = getMissedAddressCryptoCurrenciesUseCase(selectedWallet.walletId).conflate(),
|
||||
) { hasSignedHashes, isReadyToShowRating, isNeedToBackup, maybeMissedAddressCurrencies ->
|
||||
flow5 = shouldShowSwapPromoWalletUseCase().conflate(),
|
||||
) { hasSignedHashes, isReadyToShowRating, isNeedToBackup, maybeMissedAddressCurrencies, isShowSwapPromo ->
|
||||
readyForRateAppNotification = true
|
||||
buildList {
|
||||
addSwapPromoNotification(isShowSwapPromo, cardTypesResolver)
|
||||
|
||||
addCriticalNotifications(cardTypesResolver)
|
||||
|
||||
addInformationalNotifications(cardTypesResolver, maybeMissedAddressCurrencies)
|
||||
|
|
@ -77,6 +86,18 @@ internal class WalletNotificationsListFactory(
|
|||
}
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addSwapPromoNotification(
|
||||
showSwapPromo: Boolean,
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotification.SwapPromo(
|
||||
clickIntents::onCloseSwapPromoNotificationClick,
|
||||
),
|
||||
condition = showSwapPromo && cardTypesResolver.isMultiwalletAllowed(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addCriticalNotifications(cardTypesResolver: CardTypesResolver) {
|
||||
addIf(
|
||||
element = WalletNotification.Critical.DevCard,
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val scanCardToUnlockWalletUseCase: ScanCardToUnlockWalletClickHandler,
|
||||
private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase,
|
||||
isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
getMissedAddressesCryptoCurrenciesUseCase: GetMissedAddressesCryptoCurrenciesUseCase,
|
||||
|
|
@ -146,6 +147,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
isNeedToBackupUseCase = isNeedToBackupUseCase,
|
||||
getMissedAddressCryptoCurrenciesUseCase = getMissedAddressesCryptoCurrenciesUseCase,
|
||||
hasSingleWalletSignedHashesUseCase = hasSingleWalletSignedHashesUseCase,
|
||||
shouldShowSwapPromoWalletUseCase = shouldShowSwapPromoWalletUseCase,
|
||||
clickIntents = this,
|
||||
)
|
||||
|
||||
|
|
@ -774,6 +776,12 @@ internal class WalletViewModel @Inject constructor(
|
|||
refreshSingleCurrencyContent(selectedWalletIndex)
|
||||
}
|
||||
|
||||
override fun onCloseSwapPromoNotificationClick() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
shouldShowSwapPromoWalletUseCase.neverToShow()
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: refreshSingleCurrencyContent mustn't update the TxHistory and Buttons. It only must fetch primary
|
||||
// currency. Now it not works because GetPrimaryCurrency's subscriber uses .distinctUntilChanged()
|
||||
private fun refreshSingleCurrencyContent(walletIndex: Int) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue