Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-27 13:17:08 +05:00
parent e047c491cf
commit 7d13821e3c
36 changed files with 541 additions and 59 deletions

View file

@ -138,7 +138,7 @@ fun LazyListScope.notifications(
* @param containerColor Color to be used for the background of the notifications.
* @param modifier Optional Modifier for the notifications.
*/
fun LazyListScope.stackedNotifications(
fun LazyListScope.notificationsCarousel(
notifications: ImmutableList<TangemMessageUM>?,
containerColor: Color,
modifier: Modifier = Modifier,
@ -192,7 +192,7 @@ private fun StackedNotifications_Preview(
.background(contentColor)
.padding(16.dp),
) {
stackedNotifications(
notificationsCarousel(
notifications = params,
containerColor = contentColor,
)

View file

@ -48,6 +48,7 @@ import kotlinx.coroutines.flow.map
import javax.inject.Inject
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
@Suppress("LongParameterList", "LargeClass")
@ModelScoped
internal class GetMultiWalletWarningsFactory @Inject constructor(

View file

@ -25,6 +25,7 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.*
import javax.inject.Inject
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
@ModelScoped
@Suppress("LongParameterList")
internal class GetSingleWalletWarningsFactory @Inject constructor(

View file

@ -5,6 +5,7 @@ import com.tangem.common.ui.notifications.NotificationId
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.domain.notifications.repository.NotificationsRepository
import com.tangem.domain.promo.ShouldShowPromoWalletUseCase
import com.tangem.domain.promo.models.PromoId
@ -48,8 +49,11 @@ internal class GetWalletNotificationsCarouselFactory @Inject constructor(
buildList {
addNoteMigrationNotification(userWallet, wallets, clickIntents)
addRateAppNotification(showRateAppPromo, clickIntents)
addOnePlusOnePromoNotification(clickIntents, showOnePlusOnePromo)
addYieldPromoNotification(clickIntents, showYieldPromo)
if (userWallet.isMultiCurrency) {
addOnePlusOnePromoNotification(clickIntents, showOnePlusOnePromo)
addYieldPromoNotification(clickIntents, showYieldPromo)
}
addPushNotification(
shouldShow = showPushesNotification,

View file

@ -13,6 +13,7 @@ import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.domain.wallets.models.SeedPhraseNotificationsStatus
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
import com.tangem.domain.wallets.usecase.SeedPhraseNotificationUseCase
@ -35,7 +36,7 @@ import javax.inject.Inject
*/
@Suppress("LongParameterList")
@ModelScoped
internal class GetWalletWarningsFactory @Inject constructor(
internal class GetWalletNotificationsFactory @Inject constructor(
private val isDemoCardUseCase: IsDemoCardUseCase,
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
private val backupValidator: BackupValidator,
@ -194,7 +195,7 @@ internal class GetWalletWarningsFactory @Inject constructor(
condition = flattenCurrencies.hasUnreachableNetworks(),
)
addCloreMigrationNotification(flattenCurrencies, clickIntents)
addCloreMigrationNotification(userWallet, flattenCurrencies, clickIntents)
addNoAccountWarning(cryptoCurrencyStatus = flattenCurrencies.firstOrNull())
@ -220,13 +221,15 @@ internal class GetWalletWarningsFactory @Inject constructor(
}
private fun MutableList<WalletNotificationUM>.addCloreMigrationNotification(
userWallet: UserWallet,
flattenCurrencies: List<CryptoCurrencyStatus>,
clickIntents: WalletClickIntents,
) {
val cloreCurrency = flattenCurrencies.findCloreCurrency() ?: return
add(
WalletNotificationUM.CloreMigration(
addIf(
condition = userWallet.isMultiCurrency,
element = WalletNotificationUM.CloreMigration(
onStartMigrationClick = { clickIntents.onCloreMigrationClick(cloreCurrency) },
),
)

View file

@ -1,13 +1,11 @@
package com.tangem.feature.wallet.presentation.wallet.loaders
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.ui.DesignFeatureToggles
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.MultiWalletContentLoader
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.SingleWalletContentLoader
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.SingleWalletWithTokenContentLoader
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.WalletContentLoader
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.*
import javax.inject.Inject
@Suppress("LongParameterList")
@ -15,7 +13,9 @@ import javax.inject.Inject
internal class WalletContentLoaderFactory @Inject constructor(
private val multiWalletContentLoaderFactory: MultiWalletContentLoader.Factory,
private val singleWalletWithTokenContentLoaderFactory: SingleWalletWithTokenContentLoader.Factory,
private val singleWalletContentLoaderFactory: SingleWalletContentLoader.Factory,
private val singleWalletContentLoaderLegacyFactory: SingleWalletContentLoaderLegacy.Factory,
private val singleWalletContentLoader: SingleWalletContentLoader.Factory,
private val designFeatureToggles: DesignFeatureToggles,
) {
fun create(userWallet: UserWallet, isRefresh: Boolean = false): WalletContentLoader? {
@ -24,10 +24,18 @@ internal class WalletContentLoaderFactory @Inject constructor(
multiWalletContentLoaderFactory.create(userWallet)
}
userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken() -> {
singleWalletWithTokenContentLoaderFactory.create(userWallet)
if (designFeatureToggles.isRedesignEnabled) {
singleWalletContentLoader.create(userWallet)
} else {
singleWalletWithTokenContentLoaderFactory.create(userWallet)
}
}
userWallet is UserWallet.Cold && !userWallet.isMultiCurrency -> {
singleWalletContentLoaderFactory.create(userWallet, isRefresh)
if (designFeatureToggles.isRedesignEnabled) {
singleWalletContentLoader.create(userWallet)
} else {
singleWalletContentLoaderLegacyFactory.create(userWallet, isRefresh)
}
}
else -> null
}

View file

@ -1,5 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.ui.DesignFeatureToggles
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import dagger.assisted.Assisted
@ -13,15 +14,21 @@ internal class MultiWalletContentLoader @AssistedInject constructor(
private val walletNFTListSubscriberFactory: WalletNFTListSubscriberV2.Factory,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
private val multiWalletWarningsSubscriberFactory: MultiWalletWarningsSubscriber.Factory,
private val walletNotificationsSubscriberFactory: WalletNotificationsSubscriber.Factory,
private val multiWalletActionButtonsSubscriberFactory: MultiWalletActionButtonsSubscriber.Factory,
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
private val designFeatureToggles: DesignFeatureToggles,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> = listOf(
accountListSubscriberFactory.create(userWallet),
walletNFTListSubscriberFactory.create(userWallet),
checkWalletWithFundsSubscriberFactory.create(userWallet),
multiWalletWarningsSubscriberFactory.create(userWallet),
if (designFeatureToggles.isRedesignEnabled) {
walletNotificationsSubscriberFactory.create(userWallet)
} else {
multiWalletWarningsSubscriberFactory.create(userWallet)
},
multiWalletActionButtonsSubscriberFactory.create(userWallet),
tangemPayMainSubscriberFactory.create(userWallet),
)

View file

@ -1,34 +1,33 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import com.tangem.feature.wallet.presentation.wallet.subscribers.CheckWalletWithFundsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletNotificationsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Suppress("LongParameterList")
/**
* This content loader is used for the wallet screen when for single wallets.
* For example - [Note, Twins, Single with token]
*/
internal class SingleWalletContentLoader @AssistedInject constructor(
@Assisted private val userWallet: UserWallet.Cold,
@Assisted private val isRefresh: Boolean,
private val primaryCurrencySubscriberFactory: PrimaryCurrencySubscriber.Factory,
private val singleWalletButtonsSubscriberFactory: SingleWalletButtonsSubscriber.Factory,
private val singleWalletNotificationsSubscriberFactory: SingleWalletNotificationsSubscriber.Factory,
private val singleWalletExpressStatusesSubscriberFactory: SingleWalletExpressStatusesSubscriber.Factory,
private val txHistorySubscriberFactory: TxHistorySubscriber.Factory,
private val walletNotificationsSubscriber: WalletNotificationsSubscriber.Factory,
private val singleWalletSubscriber: SingleWalletSubscriber.Factory,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> = listOf(
primaryCurrencySubscriberFactory.create(userWallet),
singleWalletButtonsSubscriberFactory.create(userWallet),
singleWalletNotificationsSubscriberFactory.create(userWallet),
singleWalletExpressStatusesSubscriberFactory.create(userWallet),
txHistorySubscriberFactory.create(userWallet, isRefresh),
checkWalletWithFundsSubscriberFactory.create(userWallet),
singleWalletSubscriber.create(userWallet = userWallet),
walletNotificationsSubscriber.create(userWallet = userWallet),
checkWalletWithFundsSubscriberFactory.create(userWallet = userWallet),
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold, isRefresh: Boolean): SingleWalletContentLoader
fun create(userWallet: UserWallet.Cold): SingleWalletContentLoader
}
}

View file

@ -0,0 +1,35 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
@Suppress("LongParameterList")
internal class SingleWalletContentLoaderLegacy @AssistedInject constructor(
@Assisted private val userWallet: UserWallet.Cold,
@Assisted private val isRefresh: Boolean,
private val primaryCurrencySubscriberFactory: PrimaryCurrencySubscriber.Factory,
private val singleWalletButtonsSubscriberFactory: SingleWalletButtonsSubscriber.Factory,
private val singleWalletNotificationsSubscriberFactory: SingleWalletNotificationsSubscriber.Factory,
private val singleWalletExpressStatusesSubscriberFactory: SingleWalletExpressStatusesSubscriber.Factory,
private val txHistorySubscriberLegacyFactory: TxHistorySubscriberLegacy.Factory,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> = listOf(
primaryCurrencySubscriberFactory.create(userWallet),
singleWalletButtonsSubscriberFactory.create(userWallet),
singleWalletNotificationsSubscriberFactory.create(userWallet),
singleWalletExpressStatusesSubscriberFactory.create(userWallet),
txHistorySubscriberLegacyFactory.create(userWallet, isRefresh),
checkWalletWithFundsSubscriberFactory.create(userWallet),
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold, isRefresh: Boolean): SingleWalletContentLoaderLegacy
}
}

View file

@ -3,21 +3,22 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.subscribers.CheckWalletWithFundsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenSubscriberLegacy
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
internal class SingleWalletWithTokenContentLoader @AssistedInject constructor(
@Assisted private val userWallet: UserWallet.Cold,
private val singleWalletWithTokenSubscriberFactory: SingleWalletWithTokenSubscriber.Factory,
private val singleWalletWithTokenSubscriberLegacyFactory: SingleWalletWithTokenSubscriberLegacy.Factory,
private val multiWalletWarningsSubscriberFactory: MultiWalletWarningsSubscriber.Factory,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> = listOf(
singleWalletWithTokenSubscriberFactory.create(userWallet),
singleWalletWithTokenSubscriberLegacyFactory.create(userWallet),
multiWalletWarningsSubscriberFactory.create(userWallet),
checkWalletWithFundsSubscriberFactory.create(userWallet),
)

View file

@ -0,0 +1,64 @@
package com.tangem.feature.wallet.presentation.wallet.state.model
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.ds.button.TangemButtonShape
import com.tangem.core.ui.ds.button.TangemButtonState
import com.tangem.core.ui.ds.button.TangemButtonType
import com.tangem.core.ui.ds.button.TangemButtonUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.feature.wallet.impl.R
/**
* Model for action buttons on the wallet card. It contains the button's text, icon, click listener, and enabled state.
*/
@Immutable
internal sealed class WalletActionButtons(
private val text: TextReference,
@DrawableRes private val iconRes: Int,
) {
abstract val onClick: () -> Unit
abstract val isEnabled: Boolean
val buttonUM: TangemButtonUM
get() = TangemButtonUM(
text = text,
iconRes = iconRes,
type = TangemButtonType.Secondary,
shape = TangemButtonShape.Rounded,
onClick = onClick,
isEnabled = isEnabled,
state = if (isEnabled) {
TangemButtonState.Default
} else {
TangemButtonState.Disabled
},
)
data class Buy(
override val onClick: () -> Unit,
override val isEnabled: Boolean,
) : WalletActionButtons(
text = resourceReference(R.string.common_buy),
iconRes = R.drawable.ic_plus_default_24,
)
data class Swap(
override val onClick: () -> Unit,
override val isEnabled: Boolean,
) : WalletActionButtons(
text = resourceReference(R.string.common_swap),
iconRes = R.drawable.ic_exchange_default_24,
)
data class Sell(
override val onClick: () -> Unit,
override val isEnabled: Boolean,
) : WalletActionButtons(
text = resourceReference(R.string.common_sell),
iconRes = R.drawable.ic_dollar_default_24,
)
}

View file

@ -23,6 +23,7 @@ internal class AddWalletTransformer(
override fun transform(prevState: WalletScreenState): WalletScreenState {
return prevState.copy(
wallets = (prevState.wallets + walletLoadingStateFactory.create(userWallet)).toImmutableList(),
wallets2 = (prevState.wallets2 + walletLoadingStateFactory.create2(userWallet)).toImmutableList(),
)
}
}

View file

@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
import kotlinx.collections.immutable.toImmutableList
import timber.log.Timber
@ -13,19 +14,29 @@ internal class DeleteWalletTransformer(
override fun transform(prevState: WalletScreenState): WalletScreenState {
val deletedWalletState = prevState.getDeletedWalletState()
val deletedWalletUM = prevState.getDeletedWalletState2()
if (deletedWalletState == null) {
Timber.e("Wallets does not contain deleted wallet")
return prevState
return when {
deletedWalletUM != null -> prevState.copy(
selectedWalletIndex = selectedWalletIndex,
wallets2 = (prevState.wallets2 - deletedWalletUM).toImmutableList(),
)
deletedWalletState != null -> prevState.copy(
selectedWalletIndex = selectedWalletIndex,
wallets = (prevState.wallets - deletedWalletState).toImmutableList(),
)
else -> {
Timber.e("Wallets does not contain deleted wallet")
prevState
}
}
return prevState.copy(
selectedWalletIndex = selectedWalletIndex,
wallets = (prevState.wallets - deletedWalletState).toImmutableList(),
)
}
private fun WalletScreenState.getDeletedWalletState(): WalletState? {
return wallets.firstOrNull { it.walletCardState.id == deletedWalletId }
}
private fun WalletScreenState.getDeletedWalletState2(): WalletUM? {
return wallets2.firstOrNull { it.walletsBalanceUM.id == deletedWalletId }
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.core.ui.ds.button.TangemButtonUM
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isLocked
@ -9,9 +10,12 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.model.*
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletLoadingStateFactory
import com.tangem.feature.wallet.presentation.wallet.state.utils.createStateByWalletType
import com.tangem.feature.wallet.presentation.wallet.state.utils.isSingleWallet
import com.tangem.utils.extensions.addIf
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentList
internal class InitializeWalletsTransformer(
private val selectedWalletIndex: Int,
@ -42,6 +46,9 @@ internal class InitializeWalletsTransformer(
}
}
.toImmutableList(),
wallets2 = wallets
.map(::createInitState)
.toImmutableList(),
onWalletChange = clickIntents::onWalletChange,
onDismissMarketsTooltip = clickIntents::onDismissMarketsTooltip,
)
@ -79,6 +86,16 @@ internal class InitializeWalletsTransformer(
)
}
private fun createInitState(userWallet: UserWallet): WalletUM {
return if (userWallet.isLocked) {
userWallet.toLockedWalletUM()
} else {
walletLoadingStateFactory.create2(
userWallet = userWallet,
)
}
}
private fun UserWallet.toLockedWalletCardState(): WalletCardState {
return WalletCardState.LockedContent(
id = walletId,
@ -89,6 +106,25 @@ internal class InitializeWalletsTransformer(
)
}
private fun UserWallet.toLockedWalletUM(): WalletUM.Locked {
return WalletUM.Locked(
walletsBalanceUM = WalletBalanceUM.Loading(
id = walletId,
name = name,
),
buttons = createWalletActions(userWallet = this),
type = when (this) {
is UserWallet.Cold -> WalletType.Cold
is UserWallet.Hot -> WalletType.Hot
},
notifications = persistentListOf(
WalletNotificationUM.UnlockWallets(
onClick = clickIntents::onOpenUnlockWalletsBottomSheetClick,
),
),
)
}
private fun createMultiWalletEnabledButtons(userWallet: UserWallet): PersistentList<WalletManageButton> {
val isSingleWalletWithToken = userWallet is UserWallet.Cold &&
userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()
@ -109,4 +145,28 @@ internal class InitializeWalletsTransformer(
WalletManageButton.Sell(enabled = false, dimContent = false, onClick = {}),
)
}
private fun createWalletActions(userWallet: UserWallet): PersistentList<TangemButtonUM> {
return buildList {
add(
WalletActionButtons.Buy(
isEnabled = false,
onClick = {},
).buttonUM,
)
addIf(
condition = !userWallet.isSingleWallet(),
element = WalletActionButtons.Swap(
isEnabled = false,
onClick = {},
).buttonUM,
)
add(
WalletActionButtons.Sell(
isEnabled = false,
onClick = {},
).buttonUM,
)
}.toPersistentList()
}
}

View file

@ -41,6 +41,13 @@ internal class ReinitializeNewWalletTransformer(
),
)
.toImmutableList(),
wallets2 = prevState.wallets2
.filterNot { it.walletsBalanceUM.id == prevWalletId }
.plus(
element = walletLoadingStateFactory.create2(
userWallet = newUserWallet,
),
).toImmutableList(),
)
}
}

View file

@ -28,7 +28,9 @@ internal class ReinitializeWalletTransformer(
}
override fun transform(walletUM: WalletUM): WalletUM {
return walletUM // todo redesign main
return walletLoadingStateFactory.create2(
userWallet = userWallet,
)
}
override fun transform(prevState: WalletState): WalletState {

View file

@ -3,7 +3,9 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentList
import timber.log.Timber
/**
@ -25,8 +27,16 @@ internal class RenameWalletsTransformer(
} else {
walletState
}
}
.toImmutableList(),
}.toImmutableList(),
wallets2 = prevState.wallets2.map { walletUM ->
val renamedWallet = renamedWallets.firstOrNull { it.walletId == walletUM.walletsBalanceUM.id }
if (renamedWallet != null) {
transform(prevState = walletUM, newName = renamedWallet.name)
} else {
walletUM
}
}.toPersistentList(),
)
}
@ -46,4 +56,16 @@ internal class RenameWalletsTransformer(
}
}
}
private fun transform(prevState: WalletUM, newName: String): WalletUM {
return when (prevState) {
is WalletUM.Content -> {
prevState.copy(walletsBalanceUM = prevState.walletsBalanceUM.copySealed(name = newName))
}
is WalletUM.Locked -> {
Timber.e("Impossible to rename wallet in locked state")
prevState
}
}
}
}

View file

@ -11,6 +11,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.converte
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.SingleWalletMarketPriceConverter
import timber.log.Timber
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
internal class SetPrimaryCurrencyTransformer(
private val userWallet: UserWallet,
private val status: CryptoCurrencyStatus,
@ -37,7 +38,7 @@ internal class SetPrimaryCurrencyTransformer(
}
override fun transform(walletUM: WalletUM): WalletUM {
return walletUM // todo redesign main
return walletUM // It will not be used
}
private fun WalletCardState.toLoadedSingleCurrencyState(): WalletCardState {

View file

@ -2,9 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.model.*
import com.tangem.feature.wallet.presentation.wallet.state.utils.enableButtons
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate
@ -35,7 +34,14 @@ internal class SetRefreshStateTransformer(
}
override fun transform(walletUM: WalletUM): WalletUM {
return walletUM // todo redesign main
return when (walletUM) {
is WalletUM.Content -> walletUM.copy(
pullToRefreshConfig = walletUM.pullToRefreshConfig.toUpdatedState(isRefreshing),
tokensListUM = walletUM.tokensListUM.toUpdatedState(),
buttons = walletUM.enableButtons(),
)
is WalletUM.Locked -> walletUM
}
}
private fun PullToRefreshConfig.toUpdatedState(isRefreshing: Boolean): PullToRefreshConfig {
@ -54,6 +60,16 @@ internal class SetRefreshStateTransformer(
}
}
private fun WalletTokensListUM.toUpdatedState(): WalletTokensListUM {
return if (this is WalletTokensListUM.Content && organizeButtonUM != null) {
copy(
organizeButtonUM = organizeButtonUM.copy(isEnabled = !isRefreshing),
)
} else {
this
}
}
private fun PersistentList<WalletManageButton>.toUpdatedState(): PersistentList<WalletManageButton> {
val isButtonsEnabled = !isRefreshing

View file

@ -2,6 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.format.bigdecimal.formatStyled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.card.common.util.getCardsCount
import com.tangem.domain.models.wallet.UserWallet
@ -53,7 +55,9 @@ internal class SetTokenListErrorTransformer(
return when (walletUM) {
is WalletUM.Content -> {
walletUM.copy(
walletsBalanceUM = walletUM.walletsBalanceUM.toLoadedState(),
tokensListUM = WalletTokensListUM.Empty,
buttons = walletUM.disableButtons(),
)
}
is WalletUM.Locked -> {
@ -81,4 +85,20 @@ internal class SetTokenListErrorTransformer(
isBalanceFlickering = false,
)
}
private fun WalletBalanceUM.toLoadedState(): WalletBalanceUM {
return WalletBalanceUM.Content(
id = id,
name = name,
balance = BigDecimal.ZERO.formatStyled {
fiat(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
spanStyleReference = { TangemTheme.typography2.headingRegular28.toSpanStyle() },
)
},
isZeroBalance = true,
isBalanceFlickering = false,
)
}
}

View file

@ -6,6 +6,8 @@ import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.state.model.*
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletBalanceUMTransformer
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletCardStateConverter
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TokenListStateConverter
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.WalletTokensListUMTransformer
@ -49,7 +51,9 @@ internal class SetTokenListTransformer(
return when (walletUM) {
is WalletUM.Content -> {
walletUM.copy(
walletsBalanceUM = walletUM.walletsBalanceUM.toLoadedState2(),
tokensListUM = toLoadedState(),
buttons = walletUM.enableButtons(),
)
}
is WalletUM.Locked -> {
@ -71,6 +75,17 @@ internal class SetTokenListTransformer(
).convert(value = this)
}
private fun WalletBalanceUM.toLoadedState2(): WalletBalanceUM {
val fiatBalance = when (params) {
is TokenConverterParams.Account -> params.accountList.totalFiatBalance
is TokenConverterParams.Wallet -> params.tokenList.totalFiatBalance
}
return MultiWalletBalanceUMTransformer(
fiatBalance = fiatBalance,
appCurrency = appCurrency,
).transform(prevState = this)
}
private fun WalletTokensListState.toLoadedState(): WalletTokensListState {
return TokenListStateConverter(
params = params,

View file

@ -6,8 +6,10 @@ import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletLoadingStateFactory
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentList
import timber.log.Timber
internal class UnlockWalletTransformer(
@ -31,6 +33,18 @@ internal class UnlockWalletTransformer(
if (unlockedWallet == null) state else createLoadingState(state, unlockedWallet)
}
.toImmutableList(),
wallets2 = prevState.wallets2
.map { walletUM ->
val unlockedWallet = getUnlockedWallet(walletUM.walletsBalanceUM.id)
if (unlockedWallet == null) {
walletUM
} else {
createLoadingState2(
walletUM = walletUM,
unlockedWallet = unlockedWallet,
)
}
}.toPersistentList(),
)
}
@ -53,4 +67,16 @@ internal class UnlockWalletTransformer(
}
}
}
private fun createLoadingState2(walletUM: WalletUM, unlockedWallet: UserWallet): WalletUM {
return when (walletUM) {
is WalletUM.Locked -> walletLoadingStateFactory.create2(
userWallet = unlockedWallet,
)
is WalletUM.Content -> {
Timber.e("Impossible to unlock wallet with not locked state")
walletUM
}
}
}
}

View file

@ -0,0 +1,57 @@
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.formatStyled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.TotalFiatBalance
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletBalanceUM
import com.tangem.utils.extensions.isZero
import com.tangem.utils.transformer.Transformer
internal class MultiWalletBalanceUMTransformer(
private val fiatBalance: TotalFiatBalance,
private val appCurrency: AppCurrency,
) : Transformer<WalletBalanceUM> {
override fun transform(prevState: WalletBalanceUM): WalletBalanceUM {
return when (fiatBalance) {
is TotalFiatBalance.Loading -> prevState.toLoadingState()
is TotalFiatBalance.Failed -> prevState.toErrorState()
is TotalFiatBalance.Loaded -> prevState.toWalletCardState(fiatBalance)
}
}
private fun WalletBalanceUM.toLoadingState(): WalletBalanceUM {
return WalletBalanceUM.Loading(
id = id,
name = name,
)
}
private fun WalletBalanceUM.toErrorState(): WalletBalanceUM {
return WalletBalanceUM.Error(
id = id,
name = name,
)
}
private fun WalletBalanceUM.toWalletCardState(fiatBalance: TotalFiatBalance.Loaded): WalletBalanceUM {
return WalletBalanceUM.Content(
id = id,
name = name,
balance = fiatBalance.amount.formatStyled {
fiat(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
spanStyleReference = {
TangemTheme.typography2.headingRegular28.toSpanStyle()
},
)
},
isZeroBalance = fiatBalance.amount.isZero(),
isBalanceFlickering = fiatBalance.source == StatusSource.CACHE,
)
}
}

View file

@ -1,7 +1,9 @@
package com.tangem.feature.wallet.presentation.wallet.state.utils
import com.tangem.core.ui.ds.button.TangemButtonUM
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
@ -13,6 +15,14 @@ internal fun WalletState.MultiCurrency.Content.disableButtons(): PersistentList<
return changeAvailability(enabled = false)
}
internal fun WalletUM.Content.enableButtons(): PersistentList<TangemButtonUM> {
return buttons.map { it.copy(isEnabled = true) }.toPersistentList()
}
internal fun WalletUM.Content.disableButtons(): PersistentList<TangemButtonUM> {
return buttons.map { it.copy(isEnabled = false) }.toPersistentList()
}
private fun WalletState.MultiCurrency.Content.changeAvailability(enabled: Boolean): PersistentList<WalletManageButton> {
return buttons
.map { action ->

View file

@ -17,4 +17,8 @@ internal inline fun UserWallet.createStateByWalletType(
private fun UserWallet.Cold.isWalletWithTokens(): Boolean {
return isMultiCurrency || scanResponse.cardTypesResolver.isSingleWalletWithToken()
}
internal fun UserWallet.isSingleWallet(): Boolean {
return this is UserWallet.Cold && scanResponse.cardTypesResolver.isSingleWallet()
}

View file

@ -4,6 +4,7 @@ import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent.Companion
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.ds.button.TangemButtonUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.wallet.UserWallet
@ -14,9 +15,11 @@ import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.model.*
import com.tangem.utils.extensions.addIf
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.MutableStateFlow
/**
@ -43,6 +46,26 @@ internal class WalletLoadingStateFactory(
}
}
fun create2(userWallet: UserWallet): WalletUM {
return WalletUM.Content(
pullToRefreshConfig = createPullToRefreshConfig(),
walletsBalanceUM = WalletBalanceUM.Loading(
id = userWallet.walletId,
name = userWallet.name,
),
buttons = createWalletActions(userWallet),
notifications = persistentListOf(),
notificationsCarousel = persistentListOf(),
tokensListUM = WalletTokensListUM.Loading,
nftState = WalletNFTItemUM.Hidden,
type = when (userWallet) {
is UserWallet.Cold -> WalletType.Cold
is UserWallet.Hot -> WalletType.Hot
},
tangemPayState = TangemPayState.Empty,
)
}
private fun createLoadingHotWalletContent(userWallet: UserWallet.Hot): WalletState.MultiCurrency.Content {
return WalletState.MultiCurrency.Content(
pullToRefreshConfig = createPullToRefreshConfig(),
@ -144,6 +167,39 @@ internal class WalletLoadingStateFactory(
)
}
private fun createWalletActions(userWallet: UserWallet): PersistentList<TangemButtonUM> {
return buildList {
add(
WalletActionButtons.Buy(
isEnabled = false,
onClick = {
clickIntents.onMultiWalletBuyClick(
userWalletId = userWallet.walletId,
screenType = WALLET_TYPE,
)
},
).buttonUM,
)
addIf(
condition = !userWallet.isSingleWallet(),
element = WalletActionButtons.Swap(
isEnabled = false,
onClick = {
clickIntents.onMultiWalletSwapClick(userWalletId = userWallet.walletId)
},
).buttonUM,
)
add(
WalletActionButtons.Sell(
isEnabled = false,
onClick = {
clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId)
},
).buttonUM,
)
}.toPersistentList()
}
private fun createDimmedButtons(): PersistentList<WalletManageButton> {
return persistentListOf(
WalletManageButton.Receive(

View file

@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.mapNotNull
*
[REDACTED_AUTHOR]
*/
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
internal abstract class BasicSingleWalletSubscriber : BasicWalletSubscriber() {
/** Account ID for the main crypto portfolio of the user wallet */

View file

@ -16,6 +16,7 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
internal class MultiWalletWarningsSubscriber @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val stateController: WalletStateController,

View file

@ -20,6 +20,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onEach
import java.math.BigDecimal
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
internal class PrimaryCurrencySubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,

View file

@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.onEach
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
internal class SingleWalletButtonsSubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,

View file

@ -17,6 +17,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
@Suppress("LongParameterList")
internal class SingleWalletExpressStatusesSubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet,

View file

@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.onEach
/**
[REDACTED_AUTHOR]
*/
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
internal class SingleWalletNotificationsSubscriber @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val stateController: WalletStateController,

View file

@ -0,0 +1,35 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
internal class SingleWalletSubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet.Cold,
override val accountDependencies: AccountDependencies,
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
override val stateController: WalletStateController,
override val clickIntents: WalletClickIntents,
) : BasicAccountListSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<Unit> = combine(
flow = getAccountStatusListFlow(),
flow2 = getAppCurrencyFlow(),
flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet),
flow4 = accountDependencies.isAccountsModeEnabledUseCase(),
transform = ::updateState2,
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold): SingleWalletSubscriber
}
}

View file

@ -12,7 +12,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
internal class SingleWalletWithTokenSubscriber @AssistedInject constructor(
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
internal class SingleWalletWithTokenSubscriberLegacy @AssistedInject constructor(
@Assisted override val userWallet: UserWallet.Cold,
override val accountDependencies: AccountDependencies,
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
@ -30,6 +31,6 @@ internal class SingleWalletWithTokenSubscriber @AssistedInject constructor(
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold): SingleWalletWithTokenSubscriber
fun create(userWallet: UserWallet.Cold): SingleWalletWithTokenSubscriberLegacy
}
}

View file

@ -30,8 +30,9 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
@Suppress("LongParameterList")
internal class TxHistorySubscriber @AssistedInject constructor(
internal class TxHistorySubscriberLegacy @AssistedInject constructor(
@Assisted override val userWallet: UserWallet.Cold,
@Assisted private val isRefresh: Boolean,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
@ -126,6 +127,6 @@ internal class TxHistorySubscriber @AssistedInject constructor(
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet.Cold, isRefresh: Boolean): TxHistorySubscriber
fun create(userWallet: UserWallet.Cold, isRefresh: Boolean): TxHistorySubscriberLegacy
}
}

View file

@ -5,10 +5,13 @@ import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetWalletNotificationsCarouselFactory
import com.tangem.feature.wallet.presentation.wallet.domain.GetWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.domain.GetWalletNotificationsFactory
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetWarningsTransformer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
@ -16,11 +19,11 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
@Suppress("LongParameterList")
internal class MultiWalletWarningsSubscriberV2(
private val userWallet: UserWallet,
internal class WalletNotificationsSubscriber @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntents,
private val getWalletWarningsFactory: GetWalletWarningsFactory,
private val getWalletNotificationsFactory: GetWalletNotificationsFactory,
private val getWalletNotificationsCarouselFactory: GetWalletNotificationsCarouselFactory,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
@ -28,7 +31,7 @@ internal class MultiWalletWarningsSubscriberV2(
override fun create(coroutineScope: CoroutineScope): Flow<ImmutableList<WalletNotificationUM>> {
return combine(
flow = getWalletWarningsFactory.create(userWallet, clickIntents).conflate().distinctUntilChanged(),
flow = getWalletNotificationsFactory.create(userWallet, clickIntents).conflate().distinctUntilChanged(),
flow2 = getWalletNotificationsCarouselFactory.create(userWallet, clickIntents).conflate()
.distinctUntilChanged(),
) { notifications, notificationsCarousel ->
@ -68,4 +71,9 @@ internal class MultiWalletWarningsSubscriberV2(
totalNotifications
}
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): WalletNotificationsSubscriber
}
}