Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-28 14:08:01 +03:00
commit 06a915a0f4
2186 changed files with 101417 additions and 36593 deletions

View file

@ -11,16 +11,22 @@ android {
dependencies {
// region Kotlin
api(deps.kotlin.coroutines)
api(deps.kotlin.immutable.collections)
api(deps.kotlin.serialization.core)
// endregion
/* Project - Domain */
implementation(projects.domain.models)
implementation(projects.domain.markets)
implementation(projects.domain.account)
api(projects.domain.account)
api(projects.domain.appCurrency.models)
api(projects.domain.markets.models)
api(projects.domain.models)
/* Project - Core */
implementation(projects.core.decompose)
implementation(projects.core.ui)
api(projects.core.decompose)
api(projects.core.ui)
/* Compose */
implementation(deps.compose.runtime)
implementation(deps.kotlin.immutable.collections)
}

View file

@ -10,6 +10,7 @@ import com.tangem.domain.models.wallet.UserWallet
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
/**
* How to use
@ -32,6 +33,16 @@ interface PortfolioSelectorComponent : ComposableBottomSheetComponent, Composabl
val portfolioFetcher: PortfolioFetcher,
val controller: PortfolioSelectorController,
val bsCallback: BottomSheetCallback? = null,
val settings: Settings = Settings(),
)
/**
* @param isWalletSelectionOnly when `true`, the selector always shows a flat wallet list and ignores the global
* accounts mode (no account grouping).
*/
data class Settings(
val isWalletSelectionOnly: Boolean = false,
val isMultiChoice: Boolean = false,
)
interface BottomSheetCallback {
@ -49,8 +60,12 @@ interface PortfolioSelectorComponent : ComposableBottomSheetComponent, Composabl
*/
interface PortfolioSelectorController {
val isAccountMode: Flow<Boolean>
val selectedAccount: Flow<AccountId?>
val selectedAccountSync: AccountId?
val selectedAccounts: Flow<Set<AccountId>>
val selectedAccount: Flow<AccountId?> get() = selectedAccounts.map { it.firstOrNull() }
val selectedAccountsSync: Set<AccountId>
val selectedAccountSync: AccountId? get() = selectedAccountsSync.firstOrNull()
/**
* for some Feature specific filtering
@ -59,8 +74,15 @@ interface PortfolioSelectorController {
val isEnabled: MutableStateFlow<(UserWallet, AccountStatus) -> Boolean>
suspend fun isAccountModeSync(): Boolean
fun selectAccount(accountId: AccountId?)
fun selectAccount(accountIds: Set<AccountId>)
fun selectAccount(accountId: AccountId?) = selectAccount(accountId?.let { setOf(it) }.orEmpty())
fun selectedAccountsWithData(
portfolioFetcher: PortfolioFetcher,
): Flow<Set<Pair<UserWallet, AccountStatus.CryptoPortfolio>>>
fun selectedAccountWithData(
portfolioFetcher: PortfolioFetcher,
): Flow<Pair<UserWallet, AccountStatus.CryptoPortfolio>?>
): Flow<Pair<UserWallet, AccountStatus.CryptoPortfolio>?> =
selectedAccountsWithData(portfolioFetcher).map { it.firstOrNull() }
}

View file

@ -12,70 +12,70 @@ android {
}
dependencies {
/** Api */
implementation(projects.features.commonFeatures.api)
implementation(projects.features.wallet.api)
implementation(projects.features.tokenRecieve.api)
api(projects.features.commonFeatures.api)
api(projects.features.tokenRecieve.api)
api(projects.features.wallet.api)
/** Core modules */
implementation(projects.core.analytics)
api(projects.core.analytics)
api(projects.core.decompose)
api(projects.core.ui)
api(projects.core.utils)
implementation(projects.core.analytics.models)
implementation(projects.core.utils)
implementation(projects.core.ui)
implementation(projects.core.error)
implementation(projects.core.res)
implementation(projects.core.decompose)
implementation(projects.core.navigation)
implementation(projects.core.datasource)
implementation(projects.core.pagination)
/** Domain */
implementation(projects.domain.models)
api(projects.domain.account.status)
api(projects.domain.appCurrency)
api(projects.domain.appCurrency.models)
api(projects.domain.balanceHiding)
api(projects.domain.manageTokens)
api(projects.domain.markets)
api(projects.domain.markets.models)
api(projects.domain.models)
api(projects.domain.transaction)
api(projects.domain.wallets)
implementation(projects.domain.account)
implementation(projects.domain.account.status)
implementation(projects.domain.card)
implementation(projects.domain.core)
implementation(projects.domain.appCurrency)
implementation(projects.domain.appCurrency.models)
implementation(projects.domain.markets)
implementation(projects.domain.transaction)
implementation(projects.domain.tokens)
implementation(projects.domain.tokens.models)
implementation(projects.domain.manageTokens)
implementation(projects.domain.manageTokens.models)
implementation(projects.domain.balanceHiding)
implementation(projects.domain.balanceHiding.models)
implementation(projects.domain.wallets)
implementation(projects.domain.wallets.models)
implementation(projects.domain.yieldSupply.models)
/** Tangem libraries */
implementation(tangemDeps.card.core)
implementation(tangemDeps.blockchain)
/** Common */
implementation(projects.common.ui)
api(projects.common.routing)
api(projects.common.ui)
api(projects.common.uiMarkets)
implementation(projects.common)
implementation(projects.common.uiCharts)
implementation(projects.common.uiMarkets)
implementation(projects.common.routing)
/** Libs */
implementation(projects.libs.blockchainSdk)
api(projects.libs.blockchainSdk)
implementation(projects.libs.crypto)
/** AndroidX libraries */
implementation(deps.androidx.core.ktx)
implementation(deps.androidx.appCompat)
implementation(deps.lifecycle.runtime.ktx)
/** Compose libraries */
api(deps.compose.animation)
api(deps.compose.foundation)
implementation(deps.compose.material3)
implementation(deps.compose.animation)
implementation(deps.compose.foundation)
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.compose.coil)
implementation(deps.decompose.ext.compose)
implementation(deps.androidx.activity.compose)
/** Other libraries */
api(deps.kotlin.coroutines)
api(deps.kotlin.immutable.collections)
implementation(deps.arrow.core)
implementation(deps.kotlin.immutable.collections)
implementation(deps.haze)
implementation(deps.kotlin.serialization)
implementation(deps.lifecycle.compose)
implementation(deps.firebase.crashlytics)
/** DI */
@ -84,5 +84,4 @@ dependencies {
testImplementation(projects.common.test)
testImplementation(projects.test.core)
testImplementation(projects.test.mock)
}

View file

@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import com.arkivanov.decompose.router.stack.ChildStack
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.features.commonfeatures.impl.addtoportfolio.model.AddToPortfolioRoutes
import com.tangem.features.commonfeatures.impl.userportfolio.model.UserPortfolioUM
@ -16,19 +15,11 @@ internal fun AddToPortfolioBottomSheetSwitch(
userPortfolioState: State<UserPortfolioUM?>? = null,
onAddFromUserPortfolioClick: (() -> Unit)? = null,
) {
if (LocalRedesignEnabled.current) {
AddToPortfolioBottomSheetV2(
childStack = childStack,
onBack = onBack,
onDismiss = onDismiss,
userPortfolioState = userPortfolioState,
onAddFromUserPortfolioClick = onAddFromUserPortfolioClick,
)
} else {
AddToPortfolioBottomSheet(
childStack = childStack,
onBack = onBack,
onDismiss = onDismiss,
)
}
AddToPortfolioBottomSheetV2(
childStack = childStack,
onBack = onBack,
onDismiss = onDismiss,
userPortfolioState = userPortfolioState,
onAddFromUserPortfolioClick = onAddFromUserPortfolioClick,
)
}

View file

@ -3,13 +3,11 @@ package com.tangem.features.commonfeatures.impl.addtoportfolio
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.addtoken.AddTokenContent
import com.tangem.common.ui.addtoken.AddTokenContentV2
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedNetwork
import com.tangem.features.commonfeatures.api.addtoportfolio.SelectedPortfolio
@ -31,17 +29,10 @@ internal class AddTokenComponent @AssistedInject constructor(
override fun Content(modifier: Modifier) {
val state = model.uiState.collectAsStateWithLifecycle()
val um = state.value ?: return
if (LocalRedesignEnabled.current) {
AddTokenContentV2(
modifier = modifier,
state = um,
)
} else {
AddTokenContent(
modifier = modifier,
state = um,
)
}
AddTokenContentV2(
modifier = modifier,
state = um,
)
}
data class Params(

View file

@ -13,7 +13,6 @@ import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.DesignFeatureToggles
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.ToastMessage
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
@ -56,7 +55,6 @@ internal class AddToPortfolioModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
val portfolioSelectorController: PortfolioSelectorController,
private val designFeatureToggles: DesignFeatureToggles,
private val callbackDelegate: AddToPortfolioCallbackDelegate,
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCaseV2,
private val getTokenMarketCryptoCurrency: GetTokenMarketCryptoCurrency,
@ -182,9 +180,9 @@ internal class AddToPortfolioModel @Inject constructor(
setupPortfolioSelector(initialData, launchMode)
val shouldShowUserPortfolio = designFeatureToggles.isRedesignEnabled &&
val shouldShowUserPortfolio =
launchMode is AddToPortfolioManager.LaunchMode.ViaUserPortfolio &&
initialData.hasAnyAddedCurrency(tokenMarketParams.id)
initialData.hasAnyAddedCurrency(tokenMarketParams.id)
if (shouldShowUserPortfolio) {
// suspend, must prepare UM before navigate to UserPortfolio
@ -200,11 +198,7 @@ internal class AddToPortfolioModel @Inject constructor(
AddToPortfolioManager.LaunchMode.Preselected -> null
is AddToPortfolioManager.LaunchMode.ViaUserPortfolio,
AddToPortfolioManager.LaunchMode.DirectAdd,
-> if (designFeatureToggles.isRedesignEnabled) {
getInitialSelection(initialData)
} else {
null
}
-> getInitialSelection(initialData)
}
val firstSelectedPortfolioFlow: Flow<SelectedPortfolio> =
@ -272,15 +266,11 @@ internal class AddToPortfolioModel @Inject constructor(
callbackDelegate.onChangePortfolioClick.receiveAsFlow()
.onEach {
middleNavigationJob?.cancel()
middleNavigationJob = if (designFeatureToggles.isRedesignEnabled) {
changePortfolioNavigationNewFlow(
data = initialData,
orderedNetworks = paramsSnapshot.networks,
tokenParams = tokenMarketParams,
)
} else {
changePortfolioNavigationFlow(initialData)
}.launchIn(this)
middleNavigationJob = changePortfolioNavigationNewFlow(
data = initialData,
orderedNetworks = paramsSnapshot.networks,
tokenParams = tokenMarketParams,
).launchIn(this)
logAccountSelector(isAccountMode)
navigation.pushNew(AddToPortfolioRoutes.PortfolioSelector)
}
@ -369,33 +359,6 @@ internal class AddToPortfolioModel @Inject constructor(
}
}
private fun changePortfolioNavigationFlow(data: AvailableToAddData): Flow<Unit> = flow {
val selectedPortfolioValue = selectedPortfolio.first()
val selectedAccount = selectedPortfolioValue.account.account.account.accountId
portfolioSelectorController.selectAccount(selectedAccount)
val changedPortfolio = setupPortfolioFlow(data)
.drop(1)
.onEach { portfolio ->
val isSingleAvailableNetwork = portfolio.account.isSingleNetwork
if (isSingleAvailableNetwork) {
val singleNetwork = portfolio.account.availableToAddNetworks.first()
callbackDelegate.onNetworkSelected.send(singleNetwork)
} else {
navigation.pushNew(routeToNetworkSelector(portfolio))
}
}
val changedNetwork = setupNetworkFlow(changedPortfolio)
combine(
flow = changedPortfolio,
flow2 = changedNetwork,
transform = { newPortfolio, newNetwork ->
selectedPortfolio.tryEmit(newPortfolio)
selectedNetwork.tryEmit(newNetwork)
navigation.popToFirst()
},
).collect { emit(it) }
}
private fun changePortfolioNavigationNewFlow(
data: AvailableToAddData,
orderedNetworks: List<TokenMarketInfo.Network>,
@ -432,7 +395,7 @@ internal class AddToPortfolioModel @Inject constructor(
currency = addedToken.currency,
accountId = selectedPortfolio.account.account.account.accountId,
).onEach { state ->
val requestedQuickActions = toQuickActions(state.states, designFeatureToggles.isRedesignEnabled)
val requestedQuickActions = toQuickActions(state.states)
when {
requestedQuickActions.isNotEmpty() -> {
timerJob.cancel()

View file

@ -10,7 +10,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -36,7 +35,6 @@ import com.tangem.core.ui.ds.row.TangemRowContainer
import com.tangem.core.ui.ds.row.TangemRowLayoutId
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.TangemThemePreviewRedesign
@ -49,17 +47,10 @@ private const val DISABLED_ALPHA = 0.4f
@Composable
internal fun ChooseNetworkContent(state: ChooseNetworkUM, modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
ChooseNetworkContentV2(
state = state,
modifier = modifier,
)
} else {
ChooseNetworkContentV1(
state = state,
modifier = modifier,
)
}
ChooseNetworkContentV2(
state = state,
modifier = modifier,
)
}
@Composable
@ -227,11 +218,9 @@ private fun Preview(@PreviewParameter(ChooseNetworkContentProvider::class) conte
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun PreviewV2(@PreviewParameter(ChooseNetworkContentProvider::class) content: ChooseNetworkUM) {
TangemThemePreviewRedesign {
CompositionLocalProvider(LocalRedesignEnabled provides true) {
ChooseNetworkContent(
state = content,
)
}
ChooseNetworkContent(
state = content,
)
}
}

View file

@ -204,6 +204,8 @@ internal class ChooseTokenListItemConverter(
val paymentCurrency: CryptoCurrencyStatus = when (val status = this.value) {
is PaymentAccountStatusValue.Error,
is PaymentAccountStatusValue.IssuingCard,
is PaymentAccountStatusValue.AwaitingPlanSelection,
is PaymentAccountStatusValue.Inactive,
PaymentAccountStatusValue.NotCreated,
is PaymentAccountStatusValue.UnderReview,
PaymentAccountStatusValue.Loading,

View file

@ -75,10 +75,9 @@ import com.tangem.core.ui.ds.row.token.TangemTokenRow
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
import com.tangem.core.ui.ds.row.token.internal.TokenRowTitle
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.test.BuyTokenScreenTestTags
import com.tangem.core.ui.utils.ProvideSharedTransitionScope
import com.tangem.core.ui.utils.TangemSharedTransitionLayout
@ -136,13 +135,7 @@ private val ChooseTokenFullUM.isEmptyState: Boolean
internal fun ChooseTokenScreen(state: ChooseTokenFullUM, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.background(
color = if (LocalRedesignEnabled.current) {
TangemTheme.colors2.surface.level2
} else {
TangemTheme.colors.background.secondary
},
)
.background(color = TangemTheme.colors2.surface.level2)
.fillMaxSize()
.imePadding(),
horizontalAlignment = Alignment.CenterHorizontally,
@ -807,13 +800,7 @@ private fun LazyListScope.emptyTokensList(modifier: Modifier = Modifier) {
item("EmptyTokensList") {
Box(
modifier = modifier
.background(
color = if (LocalRedesignEnabled.current) {
TangemTheme.colors2.surface.level2
} else {
TangemTheme.colors.background.secondary
},
)
.background(color = TangemTheme.colors2.surface.level2)
.fillParentMaxSize(),
) {
Column(modifier = Modifier.align(Alignment.Center)) {
@ -844,13 +831,7 @@ private fun LazyListScope.tokensNotFound(modifier: Modifier = Modifier) {
item("TokensNotFound") {
Box(
modifier = modifier
.background(
color = if (LocalRedesignEnabled.current) {
TangemTheme.colors2.surface.level2
} else {
TangemTheme.colors.background.secondary
},
)
.background(color = TangemTheme.colors2.surface.level2)
.fillParentMaxSize(),
) {
Text(
@ -870,7 +851,7 @@ private fun LazyListScope.tokensNotFound(modifier: Modifier = Modifier) {
@Preview
@Composable
private fun TokenScreenPreview(@PreviewParameter(ChooseTokenScreenPreviewProvider::class) state: ChooseTokenFullUM) {
TangemThemePreview {
TangemThemePreviewRedesign {
ChooseTokenScreen(
state = state,
modifier = Modifier,

View file

@ -1,6 +1,9 @@
package com.tangem.features.commonfeatures.impl.managefunds
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@ -11,6 +14,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.markets.action.TokenActionsContext
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.child
import com.tangem.core.decompose.model.getOrCreateModel
@ -22,14 +26,13 @@ import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemeRedesign
import com.tangem.core.ui.test.BaseBottomSheetTestTags
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
import com.tangem.features.commonfeatures.impl.R
import com.tangem.features.commonfeatures.impl.managefunds.model.ManageFundsModel
import com.tangem.features.commonfeatures.impl.managefunds.model.uiSpec
import com.tangem.common.ui.markets.action.TokenActionsContext
import com.tangem.features.commonfeatures.impl.tokenactions.TokenActionsComponent
import com.tangem.features.commonfeatures.impl.userportfolio.UserPortfolioComponent
import com.tangem.features.commonfeatures.impl.R
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -140,6 +143,8 @@ internal class DefaultManageFundsComponent @AssistedInject constructor(
AnimatedContent(
targetState = route,
modifier = animatedContentModifier,
transitionSpec = { fadeIn().togetherWith(fadeOut()) },
contentKey = { route -> route::class },
label = "ManageFundsContentAnimation",
) { animatedRoute ->
ManageFundsRouteContent(

View file

@ -9,10 +9,8 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.bottomsheets.LocalTangemBottomSheetContentBottomInset
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorBS
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorContent
import com.tangem.features.commonfeatures.impl.portfolioselector.ui.PortfolioSelectorContentV2
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@ -48,19 +46,11 @@ internal class DefaultPortfolioSelectorComponent @AssistedInject constructor(
override fun Content(modifier: Modifier) {
val state by model.state.collectAsStateWithLifecycle()
val listBottomPadding = PaddingValues(bottom = LocalTangemBottomSheetContentBottomInset.current)
if (LocalRedesignEnabled.current) {
PortfolioSelectorContentV2(
state = state,
modifier = modifier,
contentPadding = listBottomPadding,
)
} else {
PortfolioSelectorContent(
state = state,
modifier = modifier,
contentPadding = listBottomPadding,
)
}
PortfolioSelectorContentV2(
state = state,
modifier = modifier,
contentPadding = listBottomPadding,
)
}
@AssistedFactory

View file

@ -18,38 +18,38 @@ internal class DefaultPortfolioSelectorController @Inject constructor(
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
) : PortfolioSelectorController {
private val _selectedAccount: MutableSharedFlow<AccountId?> = MutableSharedFlow(
private val _selectedAccount: MutableSharedFlow<Set<AccountId>> = MutableSharedFlow(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
override val isAccountMode: Flow<Boolean> by lazy { isAccountsModeEnabledUseCase() }
// without StateFlow and distinctUntilChanged to allow reselect and correct navigation
override val selectedAccount: Flow<AccountId?> get() = _selectedAccount
override val selectedAccountSync: AccountId? get() = _selectedAccount.replayCache.firstOrNull()
override val selectedAccounts: Flow<Set<AccountId>> get() = _selectedAccount
override val selectedAccountsSync: Set<AccountId> get() = _selectedAccount.replayCache.firstOrNull().orEmpty()
override val isEnabled: MutableStateFlow<(UserWallet, AccountStatus) -> Boolean> = MutableStateFlow { _, _ -> true }
override suspend fun isAccountModeSync(): Boolean = isAccountsModeEnabledUseCase.invokeSync()
override fun selectAccount(accountId: AccountId?) {
_selectedAccount.tryEmit(accountId)
override fun selectAccount(accountIds: Set<AccountId>) {
_selectedAccount.tryEmit(accountIds)
}
override fun selectedAccountWithData(
override fun selectedAccountsWithData(
portfolioFetcher: PortfolioFetcher,
): Flow<Pair<UserWallet, AccountStatus.CryptoPortfolio>?> = combine(
): Flow<Set<Pair<UserWallet, AccountStatus.CryptoPortfolio>>> = combine(
flow = _selectedAccount,
flow2 = portfolioFetcher.data,
transform = { accountId, data ->
accountId ?: return@combine null
var result: Pair<UserWallet, AccountStatus.CryptoPortfolio>? = null
transform = { accountIds, data ->
val result = mutableSetOf<Pair<UserWallet, AccountStatus.CryptoPortfolio>>()
data.balances.forEach { wallet, balance ->
val accountStatuses = balance.accountsBalance.accountStatuses
data.balances.forEach { (_, balance) ->
val accounts = balance.accountsBalance.accountStatuses
.filterCryptoPortfolio()
.find { accountId == it.account.accountId }
if (accountStatuses != null) result = balance.userWallet to accountStatuses
.filterTo(mutableSetOf()) { it.account.accountId in accountIds }
.map { balance.userWallet to it }
result.addAll(accounts)
}
return@combine result

View file

@ -21,6 +21,7 @@ import com.tangem.domain.wallets.usecase.GetWalletIconUseCase
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioFetcher
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
import com.tangem.features.commonfeatures.impl.R
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorButtonUM
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorItemUM
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorUM
import com.tangem.features.wallet.utils.UserWalletImageFetcher
@ -48,31 +49,36 @@ internal class PortfolioSelectorModel @Inject constructor(
internal val state: StateFlow<PortfolioSelectorUM>
field = MutableStateFlow<PortfolioSelectorUM>(emptyState())
init {
val selectedAccountState = selectorController.selectedAccount
.stateIn(modelScope, started = SharingStarted.Eagerly, initialValue = null)
private val innerSelectedAccounts = MutableStateFlow(selectorController.selectedAccountsSync)
init {
combine(
flow = isAccountsModeEnabledUseCase(),
flow2 = balanceFetcher.data,
flow3 = walletImageFetcher.allWallets(ArtworkSize.SMALL),
flow4 = selectorController.isEnabled,
flow5 = selectedAccountState,
flow5 = innerSelectedAccounts,
transform = { isAccountsMode, portfolioData, artworks, isEnabled, selectedAccount ->
val isAccountsModeEffective = isAccountsMode && !params.settings.isWalletSelectionOnly
val uiList = buildUiList(
isAccountsMode = isAccountsMode,
isAccountsMode = isAccountsModeEffective,
portfolioData = portfolioData,
artworks = artworks,
isEnabled = isEnabled,
selectedAccount = selectedAccount,
)
val title = when (isAccountsMode) {
val title = when (isAccountsModeEffective) {
true -> resourceReference(R.string.common_choose_account)
false -> resourceReference(R.string.common_choose_wallet)
}
val button = PortfolioSelectorButtonUM(
text = resourceReference(R.string.common_apply),
onClick = { onApplyClick() },
)
state.value = PortfolioSelectorUM(
title = title,
items = uiList.toImmutableList(),
button = button.takeIf { params.settings.isMultiChoice },
)
},
)
@ -85,7 +91,7 @@ internal class PortfolioSelectorModel @Inject constructor(
portfolioData: PortfolioFetcher.Data,
artworks: Map<UserWalletId, UserWalletItemUM.ImageState>,
isEnabled: (UserWallet, AccountStatus) -> Boolean,
selectedAccount: AccountId?,
selectedAccount: Set<AccountId>,
): List<PortfolioSelectorItemUM> = when (isAccountsMode) {
true -> buildAccountsList(
portfolioData = portfolioData,
@ -105,7 +111,7 @@ internal class PortfolioSelectorModel @Inject constructor(
portfolioData: PortfolioFetcher.Data,
artworks: Map<UserWalletId, UserWalletItemUM.ImageState>,
isEnabled: (UserWallet, AccountStatus) -> Boolean,
selectedAccount: AccountId?,
selectedAccount: Set<AccountId>,
): List<PortfolioSelectorItemUM> = buildList {
val appCurrency = portfolioData.appCurrency
val isBalanceHidden = portfolioData.isBalanceHidden
@ -113,25 +119,29 @@ internal class PortfolioSelectorModel @Inject constructor(
portfolioData.balances.forEach { (_, portfolio) ->
val balance = portfolio.walletBalance
val wallet = portfolio.userWallet
val mainAccount = portfolio.accountsBalance.mainAccount
val isSelected = mainAccount.accountId in selectedAccount
val endIcon = if (isSelected) {
UserWalletItemUM.EndIcon.Checkmark
} else {
UserWalletItemUM.EndIcon.None
}
val walletItemUM = UserWalletItemUMConverter(
onClick = {
selectorController.selectAccount(portfolio.accountsBalance.mainAccount.account.accountId)
},
onClick = { onWalletSelected(wallet.walletId, portfolioData, false) },
appCurrency = appCurrency,
balance = balance,
isBalanceHidden = isBalanceHidden,
artwork = artworks[wallet.walletId],
isAuthMode = false,
endIcon = endIcon,
mode = UserWalletItemUMConverter.InfoField.Tokens(
tokensCount = portfolio.accountsBalance.flattenCurrencies().size,
),
).convert(wallet)
if (walletItemUM.isEnabled) {
val mainAccount = portfolio.accountsBalance.mainAccount
val isEnabledByFeature = isEnabled(wallet, mainAccount)
val finalWalletItemUM =
if (isEnabledByFeature) walletItemUM else walletItemUM.copy(isEnabled = false)
val isSelected = mainAccount.isSelected(selectedAccount)
add(PortfolioSelectorItemUM.Portfolio(finalWalletItemUM, isSelected))
} else {
lockedWallets.add(PortfolioSelectorItemUM.Portfolio(walletItemUM, isSelected = false))
@ -147,7 +157,7 @@ internal class PortfolioSelectorModel @Inject constructor(
portfolioData: PortfolioFetcher.Data,
artworks: Map<UserWalletId, UserWalletItemUM.ImageState>,
isEnabled: (UserWallet, AccountStatus) -> Boolean,
selectedAccount: AccountId?,
selectedAccount: Set<AccountId>,
): List<PortfolioSelectorItemUM> = buildList {
val appCurrency = portfolioData.appCurrency
val isBalanceHidden = portfolioData.isBalanceHidden
@ -157,7 +167,7 @@ internal class PortfolioSelectorModel @Inject constructor(
val wallet = portfolio.userWallet
val walletItemUM = UserWalletItemUMConverter(
onClick = {
selectorController.selectAccount(portfolio.accountsBalance.mainAccount.account.accountId)
onAccountSelected(portfolio.accountsBalance.mainAccount.account.accountId)
},
appCurrency = appCurrency,
balance = balance,
@ -175,9 +185,13 @@ internal class PortfolioSelectorModel @Inject constructor(
is PortfolioFetcher.Mode.Wallet -> Unit
is PortfolioFetcher.Mode.All -> {
if (portfolioData.balances.size > 1) {
val isAllSelected = portfolio.accountsBalance.accountStatuses
.all { accountStatus -> accountStatus.account.accountId in selectedAccount }
val walletTitle = PortfolioSelectorItemUM.GroupTitle(
id = "GroupTitle ${wallet.walletId.stringValue}",
name = stringReference(wallet.name),
isSelected = isAllSelected,
onClick = { onWalletSelected(wallet.walletId, portfolioData, true) },
deviceIcon = walletIconUMConverter.convert(getWalletIconUseCase(wallet)),
)
@ -190,14 +204,20 @@ internal class PortfolioSelectorModel @Inject constructor(
val isEnabledByFeature = isEnabled(wallet, accountStatus)
val account = accountStatus.account
val accountBalance = accountStatus.tokenList.totalFiatBalance
val isSelected = accountStatus.accountId in selectedAccount
val endIcon = if (isSelected) {
UserWalletItemUM.EndIcon.Checkmark
} else {
UserWalletItemUM.EndIcon.None
}
val accountItemUM = AccountPortfolioItemUMConverter(
onClick = { selectorController.selectAccount(account.accountId) },
onClick = { onAccountSelected(account.accountId) },
appCurrency = appCurrency,
accountBalance = accountBalance,
isEnabled = isEnabledByFeature,
endIcon = endIcon,
isBalanceHidden = isBalanceHidden,
).convert(account)
val isSelected = accountStatus.isSelected(selectedAccount)
add(PortfolioSelectorItemUM.Portfolio(accountItemUM, isSelected))
}
}
@ -206,11 +226,64 @@ internal class PortfolioSelectorModel @Inject constructor(
}
}
private fun onAccountSelected(accountId: AccountId) {
if (params.settings.isMultiChoice) {
innerSelectedAccounts.update { selected ->
if (accountId in selected) {
selected - accountId
} else {
selected + accountId
}
}
} else {
selectorController.selectAccount(accountId)
}
}
// only isMultiChoice branch
private fun onWalletSelected(
walletId: UserWalletId,
portfolioData: PortfolioFetcher.Data,
isAccountMode: Boolean,
) {
if (params.settings.isMultiChoice) {
val portfolio = portfolioData.balances[walletId] ?: return
innerSelectedAccounts.update { selected ->
val isAllSelected = if (isAccountMode) {
portfolio.accountsBalance.accountStatuses
.all { accountStatus -> accountStatus.account.accountId in selected }
} else {
portfolio.accountsBalance.mainAccount.account.accountId in selected
}
val walletAccounts = if (isAccountMode) {
portfolio.accountsBalance.accountStatuses
.mapTo(mutableSetOf()) { it.account.accountId }
} else {
mutableSetOf(portfolio.accountsBalance.mainAccount.account.accountId)
}
if (isAllSelected) {
selected - walletAccounts
} else {
selected + walletAccounts
}
}
} else {
portfolioData.balances[walletId]?.accountsBalance?.mainAccount?.account?.accountId
?.let { accountId -> selectorController.selectAccount(accountId) }
}
}
private fun onApplyClick() {
selectorController.selectAccount(innerSelectedAccounts.value)
}
private fun createLockedWallets(wallets: List<PortfolioSelectorItemUM>): List<PortfolioSelectorItemUM> {
val lockedWalletsTitle = PortfolioSelectorItemUM.GroupTitle(
id = "lockedWalletsTitleId",
name = resourceReference(R.string.common_locked_wallets),
deviceIcon = DeviceIconUM.Stub(cardsCount = 1),
isSelected = false,
onClick = {},
)
return listOf(lockedWalletsTitle) + wallets
@ -221,5 +294,6 @@ internal class PortfolioSelectorModel @Inject constructor(
private fun emptyState() = PortfolioSelectorUM(
items = persistentListOf(),
title = TextReference.EMPTY,
button = null,
)
}

View file

@ -9,6 +9,12 @@ import kotlinx.collections.immutable.ImmutableList
data class PortfolioSelectorUM(
val title: TextReference,
val items: ImmutableList<PortfolioSelectorItemUM>,
val button: PortfolioSelectorButtonUM?,
)
data class PortfolioSelectorButtonUM(
val text: TextReference,
val onClick: () -> Unit,
)
@Immutable
@ -19,6 +25,8 @@ sealed interface PortfolioSelectorItemUM {
override val id: String,
val name: TextReference,
val deviceIcon: DeviceIconUM,
val isSelected: Boolean,
val onClick: () -> Unit,
) : PortfolioSelectorItemUM
data class Portfolio(

View file

@ -4,20 +4,18 @@ import android.content.res.Configuration
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetType
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.features.commonfeatures.impl.R
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorUM
@Composable
@ -27,36 +25,29 @@ internal fun PortfolioSelectorBS(
onBack: () -> Unit,
modifier: Modifier = Modifier,
) {
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = onDismiss,
content = TangemBottomSheetConfigContent.Empty,
),
onBack = onBack,
scrollableContent = false,
containerColor = TangemTheme.colors.background.tertiary,
containerColor = TangemTheme.colors3.bg.primary,
type = TangemBottomSheetType.Modal,
title = {
TangemModalBottomSheetTitle(
TangemTopNavigation(
title = state.title,
startIconRes = R.drawable.ic_back_24,
onStartClick = onBack,
contentAlign = TangemTopNavigation.ContentAlign.Center,
blurBackground = false,
onClose = onDismiss,
)
},
content = {
if (LocalRedesignEnabled.current) {
PortfolioSelectorContentV2(
state = state,
contentPadding = PaddingValues(bottom = 16.dp),
modifier = modifier.padding(horizontal = 16.dp),
)
} else {
PortfolioSelectorContent(
state = state,
contentPadding = PaddingValues(bottom = 16.dp),
modifier = modifier.padding(horizontal = 16.dp),
)
}
PortfolioSelectorContentV2(
state = state,
contentPadding = PaddingValues(bottom = 16.dp),
modifier = modifier.padding(horizontal = 16.dp),
)
},
)
}
@ -80,13 +71,11 @@ private fun Preview(@PreviewParameter(PortfolioSelectorPreviewStateProvider::cla
@Composable
private fun PreviewV2(@PreviewParameter(PortfolioSelectorPreviewStateProvider::class) params: PortfolioSelectorUM) {
TangemThemePreviewRedesign {
CompositionLocalProvider(LocalRedesignEnabled provides true) {
PortfolioSelectorBS(
state = params,
onDismiss = {},
modifier = Modifier,
onBack = {},
)
}
PortfolioSelectorBS(
state = params,
onDismiss = {},
modifier = Modifier,
onBack = {},
)
}
}

View file

@ -37,6 +37,7 @@ import com.tangem.core.ui.res.LocalCanScrollBackward
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.commonfeatures.impl.R
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorButtonUM
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorItemUM
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorUM
import kotlinx.collections.immutable.toImmutableList
@ -168,12 +169,19 @@ internal object PortfolioSelectorPreviewData {
private val lockedWalletItem: UserWalletItemUM
get() = walletItem.copy(isEnabled = false)
val button = PortfolioSelectorButtonUM(
text = resourceReference(R.string.common_apply),
onClick = { },
)
val firstList
get() = listOf(
PortfolioSelectorItemUM.GroupTitle(
id = UUID.randomUUID().toString(),
name = stringReference("Tangem 2.0"),
deviceIcon = DeviceIconUM.Stub(cardsCount = 2),
isSelected = false,
onClick = {},
),
PortfolioSelectorItemUM.Portfolio(accountItem, false),
PortfolioSelectorItemUM.Portfolio(lockedAccountItem, false),
@ -181,6 +189,8 @@ internal object PortfolioSelectorPreviewData {
id = UUID.randomUUID().toString(),
name = stringReference("Tangem White"),
deviceIcon = DeviceIconUM.Stub(cardsCount = 1),
isSelected = false,
onClick = {},
),
PortfolioSelectorItemUM.Portfolio(accountItem, true),
)
@ -191,6 +201,8 @@ internal object PortfolioSelectorPreviewData {
id = UUID.randomUUID().toString(),
name = resourceReference(R.string.common_locked_wallets),
deviceIcon = DeviceIconUM.Stub(cardsCount = 1),
isSelected = false,
onClick = {},
),
PortfolioSelectorItemUM.Portfolio(lockedWalletItem, false),
PortfolioSelectorItemUM.Portfolio(lockedWalletItem, false),
@ -209,6 +221,8 @@ internal object PortfolioSelectorPreviewData {
id = UUID.randomUUID().toString(),
name = resourceReference(R.string.common_locked_wallets),
deviceIcon = DeviceIconUM.Stub(cardsCount = 1),
isSelected = false,
onClick = {},
),
PortfolioSelectorItemUM.Portfolio(lockedWalletItem, false),
PortfolioSelectorItemUM.Portfolio(lockedWalletItem, false),
@ -220,18 +234,22 @@ internal class PortfolioSelectorPreviewStateProvider : CollectionPreviewParamete
PortfolioSelectorUM(
title = resourceReference(R.string.common_choose_account),
items = PortfolioSelectorPreviewData.firstList.toImmutableList(),
button = null,
),
PortfolioSelectorUM(
title = resourceReference(R.string.common_choose_account),
items = PortfolioSelectorPreviewData.secondList.toImmutableList(),
button = PortfolioSelectorPreviewData.button,
),
PortfolioSelectorUM(
title = resourceReference(R.string.common_choose_wallet),
items = PortfolioSelectorPreviewData.walletList.toImmutableList(),
button = null,
),
PortfolioSelectorUM(
title = resourceReference(R.string.common_choose_wallet),
items = PortfolioSelectorPreviewData.lockedWalletList.toImmutableList(),
button = PortfolioSelectorPreviewData.button,
),
),
)

View file

@ -32,7 +32,6 @@ import com.tangem.core.ui.ds.row.TangemRowLayoutId
import com.tangem.core.ui.extensions.conditional
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.LocalCanScrollBackward
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.features.commonfeatures.impl.portfolioselector.entity.PortfolioSelectorItemUM
@ -218,16 +217,14 @@ private fun WalletNameRow(model: PortfolioSelectorItemUM.GroupTitle, modifier: M
@Composable
private fun Preview(@PreviewParameter(PortfolioSelectorPreviewStateProvider::class) params: PortfolioSelectorUM) {
TangemThemePreviewRedesign {
CompositionLocalProvider(LocalRedesignEnabled provides true) {
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
PortfolioSelectorContentV2(
state = params,
modifier = Modifier.background(color = TangemTheme.colors.background.tertiary),
)
}
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
PortfolioSelectorContentV2(
state = params,
modifier = Modifier.background(color = TangemTheme.colors.background.tertiary),
)
}
}
}

View file

@ -17,11 +17,9 @@ import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.domain.models.TokenReceiveConfig
import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
import com.tangem.features.commonfeatures.impl.tokenactions.model.TokenActionsModel
import com.tangem.features.commonfeatures.impl.tokenactions.ui.TokenActionsContent
import com.tangem.features.commonfeatures.impl.tokenactions.ui.TokenActionsContentV2
import com.tangem.features.tokenreceive.TokenReceiveComponent
import dagger.assisted.Assisted
@ -49,17 +47,10 @@ internal class TokenActionsComponent @AssistedInject constructor(
val state = model.uiState.collectAsStateWithLifecycle()
val bottomSheet by bottomSheetSlot.subscribeAsState()
val tokenActionsUM = state.value ?: return
if (LocalRedesignEnabled.current || params.isRedesignForced) {
TokenActionsContentV2(
modifier = modifier,
state = tokenActionsUM,
)
} else {
TokenActionsContent(
modifier = modifier,
state = tokenActionsUM,
)
}
TokenActionsContentV2(
modifier = modifier,
state = tokenActionsUM,
)
bottomSheet.child?.instance?.BottomSheet()
}

View file

@ -15,7 +15,6 @@ import com.tangem.features.commonfeatures.api.tokenactions.BottomAction
import com.tangem.common.ui.userwallet.converter.WalletIconUMConverter
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.ui.DesignFeatureToggles
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.ds.badge.TangemBadgeIconPosition
import com.tangem.core.ui.ds.badge.TangemBadgeShape
@ -41,7 +40,6 @@ import javax.inject.Inject
@ModelScoped
internal class TokenActionsUiBuilder @Inject constructor(
paramsContainer: ParamsContainer,
private val designFeatureToggles: DesignFeatureToggles,
private val getWalletIconUseCase: GetWalletIconUseCase,
private val getWalletsUseCase: GetWalletsUseCase,
private val walletIconUMConverter: WalletIconUMConverter,
@ -55,51 +53,12 @@ internal class TokenActionsUiBuilder @Inject constructor(
isBalanceHidden: Boolean,
bottomAction: BottomAction,
): TokenActionsUM {
return if (designFeatureToggles.isRedesignEnabled || params.isRedesignForced) {
buildV2(
cryptoCurrencyData = cryptoCurrencyData,
tokenActionsHandler = tokenActionsHandler,
appCurrency = appCurrency,
isBalanceHidden = isBalanceHidden,
bottomAction = bottomAction,
)
} else {
buildV1(
cryptoCurrencyData = cryptoCurrencyData,
tokenActionsHandler = tokenActionsHandler,
bottomAction = bottomAction,
)
}
}
private fun buildV1(
cryptoCurrencyData: CryptoCurrencyData,
tokenActionsHandler: TokenActionsHandler,
bottomAction: BottomAction,
): TokenActionsUM {
val status = cryptoCurrencyData.status
val tokenUM = TokenItemState.Content(
id = status.currency.id.value,
iconState = CryptoCurrencyToIconStateConverter().convert(status.currency),
titleState = TokenItemState.TitleState.Content(stringReference(status.currency.name)),
fiatAmountState = null,
subtitle2State = null,
subtitleState = TokenItemState.SubtitleState.TextContent(stringReference(status.currency.symbol)),
onItemClick = null,
onItemLongClick = null,
)
return TokenActionsUM(
token = tokenUM,
quickActions = quickActions(
cryptoData = cryptoCurrencyData,
tokenActionsHandler = tokenActionsHandler,
isRedesignEnabled = false,
context = params.context,
),
bottomActionText = bottomActionText(bottomAction),
onBottomActionClick = {
params.callbacks.onBottomActionClick(bottomAction)
},
return buildV2(
cryptoCurrencyData = cryptoCurrencyData,
tokenActionsHandler = tokenActionsHandler,
appCurrency = appCurrency,
isBalanceHidden = isBalanceHidden,
bottomAction = bottomAction,
)
}
@ -126,7 +85,6 @@ internal class TokenActionsUiBuilder @Inject constructor(
quickActions = quickActions(
cryptoData = cryptoCurrencyData,
tokenActionsHandler = tokenActionsHandler,
isRedesignEnabled = true,
context = params.context,
),
bottomActionText = bottomActionText(bottomAction),

View file

@ -3,10 +3,8 @@ package com.tangem.features.commonfeatures.impl.tokenactions.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
@ -119,8 +117,8 @@ private fun QuickActionsList(state: TokenActionsUM, modifier: Modifier = Modifie
}
AnimatedVisibility(
visibleState = transitionState,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically(),
enter = fadeIn(),
exit = fadeOut(),
) {
val actionModifier = when (actionUM) {
is QuickActionUM.V1.Buy, is QuickActionUM.V2.Buy ->
@ -231,17 +229,15 @@ private fun WalletPortfolioRow(name: TextReference, deviceIcon: DeviceIconUM, mo
@Composable
private fun Preview(@PreviewParameter(TokenActionsContentPreviewProviderV2::class) state: TokenActionsUM) {
TangemThemePreviewRedesign {
CompositionLocalProvider(LocalRedesignEnabled provides true) {
Box(
modifier = Modifier
.fillMaxWidth()
.background(TangemTheme.colors2.surface.level2)
.padding(horizontal = 16.dp),
) {
TokenActionsContentV2(
state = state,
)
}
Box(
modifier = Modifier
.fillMaxWidth()
.background(TangemTheme.colors2.surface.level2)
.padding(horizontal = 16.dp),
) {
TokenActionsContentV2(
state = state,
)
}
}
}