Updated on 2026-08-14
This commit is contained in:
parent
b92bb00c7f
commit
5e6bf6aaae
14 changed files with 172 additions and 109 deletions
|
|
@ -7,7 +7,6 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.features.account.PortfolioFetcher
|
||||
import com.tangem.features.account.PortfolioFetcher.*
|
||||
|
|
@ -23,7 +22,6 @@ import kotlinx.coroutines.flow.*
|
|||
internal class DefaultPortfolioFetcher @AssistedInject constructor(
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase,
|
||||
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
|
||||
private val getWallets: GetWalletsUseCase,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
|
|
@ -80,14 +78,8 @@ internal class DefaultPortfolioFetcher @AssistedInject constructor(
|
|||
return combine(balanceFlows) { pairs -> pairs.toMap() }
|
||||
}
|
||||
|
||||
private fun walletAccountsBalancesFlow(wallet: UserWallet): Flow<Pair<UserWallet, PortfolioBalance>> = combine(
|
||||
flow = accountStatusListFlow(wallet),
|
||||
flow2 = getWalletTotalBalanceUseCase(wallet.walletId),
|
||||
transform = { accountStatusList, walletBalance ->
|
||||
val portfolioBalance = PortfolioBalance(walletBalance, accountStatusList)
|
||||
wallet to portfolioBalance
|
||||
},
|
||||
)
|
||||
private fun walletAccountsBalancesFlow(wallet: UserWallet): Flow<Pair<UserWallet, PortfolioBalance>> =
|
||||
accountStatusListFlow(wallet).map { wallet to PortfolioBalance(wallet, it) }
|
||||
|
||||
private fun accountStatusListFlow(wallet: UserWallet): Flow<AccountStatusList> =
|
||||
singleAccountStatusListSupplier(SingleAccountStatusListProducer.Params(wallet.walletId))
|
||||
|
|
|
|||
|
|
@ -31,13 +31,13 @@ internal class DefaultPortfolioSelectorComponent @AssistedInject constructor(
|
|||
.stateIn(componentScope, SharingStarted.Lazily, model.state.value.title)
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss()
|
||||
params.bsCallback?.onDismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
PortfolioSelectorBS(state, onDismiss = ::dismiss)
|
||||
PortfolioSelectorBS(state = state, onDismiss = ::dismiss, onBack = { params.bsCallback?.onBack() })
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -4,23 +4,33 @@ import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
|||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.features.account.PortfolioSelectorController
|
||||
import com.tangem.features.account.PortfolioFetcher
|
||||
import kotlinx.coroutines.flow.*
|
||||
import com.tangem.features.account.PortfolioSelectorController
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultPortfolioSelectorController @Inject constructor(
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
) : PortfolioSelectorController {
|
||||
|
||||
private val _selectedAccount: MutableStateFlow<AccountId?> = MutableStateFlow(null)
|
||||
private val _selectedAccount: MutableSharedFlow<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 selectedAccount: StateFlow<AccountId?> get() = _selectedAccount
|
||||
override val isEnabled: MutableStateFlow<(UserWallet, AccountStatus) -> Boolean> = MutableStateFlow { _, _ -> true }
|
||||
|
||||
override fun selectAccount(accountId: AccountId?) {
|
||||
_selectedAccount.update { accountId }
|
||||
_selectedAccount.tryEmit(accountId)
|
||||
}
|
||||
|
||||
override fun selectedAccountWithData(portfolioFetcher: PortfolioFetcher): Flow<Pair<UserWallet, AccountStatus>?> =
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import com.tangem.operations.attestation.ArtworkSize
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -45,9 +44,11 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
init {
|
||||
combine(
|
||||
flow = isAccountsModeEnabledUseCase(),
|
||||
flow2 = loadBalanceWithArtwork(),
|
||||
transform = { isAccountsMode, (portfolioData, artworks) ->
|
||||
val uiList = buildUiList(isAccountsMode, portfolioData, artworks)
|
||||
flow2 = balanceFetcher.data,
|
||||
flow3 = walletImageFetcher.allWallets(ArtworkSize.SMALL),
|
||||
flow4 = selectorController.isEnabled,
|
||||
transform = { isAccountsMode, portfolioData, artworks, isEnabled ->
|
||||
val uiList = buildUiList(isAccountsMode, portfolioData, artworks, isEnabled)
|
||||
val title = when (isAccountsMode) {
|
||||
true -> resourceReference(R.string.common_choose_account)
|
||||
false -> resourceReference(R.string.common_choose_wallet)
|
||||
|
|
@ -66,24 +67,25 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
isAccountsMode: Boolean,
|
||||
portfolioData: PortfolioFetcher.Data,
|
||||
artworks: Map<UserWalletId, UserWalletItemUM.ImageState>,
|
||||
isEnabled: (UserWallet, AccountStatus) -> Boolean,
|
||||
): List<PortfolioSelectorItemUM> = when (isAccountsMode) {
|
||||
true -> buildAccountsList(portfolioData, artworks)
|
||||
false -> buildWalletList(portfolioData, artworks)
|
||||
true -> buildAccountsList(portfolioData, artworks, isEnabled)
|
||||
false -> buildWalletList(portfolioData, artworks, isEnabled)
|
||||
}
|
||||
|
||||
private fun buildWalletList(
|
||||
portfolioData: PortfolioFetcher.Data,
|
||||
artworks: Map<UserWalletId, UserWalletItemUM.ImageState>,
|
||||
isEnabled: (UserWallet, AccountStatus) -> Boolean,
|
||||
): List<PortfolioSelectorItemUM> = buildList {
|
||||
val appCurrency = portfolioData.appCurrency
|
||||
val isBalanceHidden = portfolioData.isBalanceHidden
|
||||
val lockedWallets = mutableListOf<PortfolioSelectorItemUM>()
|
||||
portfolioData.balances.forEach { wallet, portfolio ->
|
||||
val balance = portfolio.walletBalance.getOrNull()
|
||||
val balance = portfolio.walletBalance
|
||||
val walletItemUM = UserWalletItemUMConverter(
|
||||
onClick = {
|
||||
// todo account
|
||||
// selectorController.selectAccount(portfolio.accountsBalance.mainAccount)
|
||||
selectorController.selectAccount(portfolio.accountsBalance.mainAccount.account.accountId)
|
||||
},
|
||||
appCurrency = appCurrency,
|
||||
balance = balance,
|
||||
|
|
@ -92,7 +94,10 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
isAuthMode = false,
|
||||
).convert(wallet)
|
||||
if (walletItemUM.isEnabled) {
|
||||
add(PortfolioSelectorItemUM.Portfolio(walletItemUM))
|
||||
val isEnabledByFeature = isEnabled(wallet, portfolio.accountsBalance.mainAccount)
|
||||
val finalWalletItemUM =
|
||||
if (isEnabledByFeature) walletItemUM else walletItemUM.copy(isEnabled = false)
|
||||
add(PortfolioSelectorItemUM.Portfolio(finalWalletItemUM))
|
||||
} else {
|
||||
lockedWallets.add(PortfolioSelectorItemUM.Portfolio(walletItemUM))
|
||||
}
|
||||
|
|
@ -110,16 +115,16 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
private fun buildAccountsList(
|
||||
portfolioData: PortfolioFetcher.Data,
|
||||
artworks: Map<UserWalletId, UserWalletItemUM.ImageState>,
|
||||
isEnabled: (UserWallet, AccountStatus) -> Boolean,
|
||||
): List<PortfolioSelectorItemUM> = buildList {
|
||||
val appCurrency = portfolioData.appCurrency
|
||||
val isBalanceHidden = portfolioData.isBalanceHidden
|
||||
val lockedWallets = mutableListOf<PortfolioSelectorItemUM>()
|
||||
portfolioData.balances.forEach { wallet, portfolio ->
|
||||
val balance = portfolio.walletBalance.getOrNull()
|
||||
val balance = portfolio.walletBalance
|
||||
val walletItemUM = UserWalletItemUMConverter(
|
||||
onClick = {
|
||||
// todo account
|
||||
// selectorController.selectAccount(portfolio.accountsBalance.mainAccount)
|
||||
selectorController.selectAccount(portfolio.accountsBalance.mainAccount.account.accountId)
|
||||
},
|
||||
appCurrency = appCurrency,
|
||||
balance = balance,
|
||||
|
|
@ -138,8 +143,8 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
)
|
||||
add(walletTitle)
|
||||
|
||||
add(PortfolioSelectorItemUM.Portfolio(walletItemUM))
|
||||
portfolio.accountsBalance.accountStatuses.forEach { accountStatus ->
|
||||
val isEnabledByFeature = isEnabled(wallet, accountStatus)
|
||||
val account = accountStatus.account
|
||||
val accountBalance = when (accountStatus) {
|
||||
is AccountStatus.CryptoPortfolio -> accountStatus.tokenList.totalFiatBalance
|
||||
|
|
@ -148,6 +153,7 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
onClick = { selectorController.selectAccount(account.accountId) },
|
||||
appCurrency = appCurrency,
|
||||
accountBalance = accountBalance,
|
||||
isEnabled = isEnabledByFeature,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
).convert(account)
|
||||
add(PortfolioSelectorItemUM.Portfolio(accountItemUM))
|
||||
|
|
@ -163,22 +169,6 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun loadBalanceWithArtwork():
|
||||
Flow<Pair<PortfolioFetcher.Data, Map<UserWalletId, UserWalletItemUM.ImageState>>> {
|
||||
val wallets = Channel<Set<UserWallet>>()
|
||||
val portfolioFlow = balanceFetcher.data
|
||||
.onEach { wallets.trySend(it.balances.keys) }
|
||||
|
||||
val artworksFlow = wallets.receiveAsFlow()
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { walletImageFetcher.walletsImage(wallets = it, size = ArtworkSize.SMALL) }
|
||||
|
||||
return combine(
|
||||
flow = portfolioFlow,
|
||||
flow2 = artworksFlow,
|
||||
) { portfolioData, artworks -> portfolioData to artworks }
|
||||
}
|
||||
|
||||
private fun emptyState() = PortfolioSelectorUM(
|
||||
items = persistentListOf(),
|
||||
title = TextReference.EMPTY,
|
||||
|
|
|
|||
|
|
@ -19,21 +19,26 @@ import com.tangem.features.account.impl.R
|
|||
import com.tangem.features.account.selector.entity.PortfolioSelectorUM
|
||||
|
||||
@Composable
|
||||
internal fun PortfolioSelectorBS(state: PortfolioSelectorUM, onDismiss: () -> Unit, modifier: Modifier = Modifier) {
|
||||
internal fun PortfolioSelectorBS(
|
||||
state: PortfolioSelectorUM,
|
||||
onDismiss: () -> Unit,
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = onDismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onBack = onDismiss,
|
||||
onBack = onBack,
|
||||
scrollableContent = false,
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
title = {
|
||||
TangemModalBottomSheetTitle(
|
||||
title = state.title,
|
||||
startIconRes = R.drawable.ic_back_24,
|
||||
onStartClick = onDismiss,
|
||||
onStartClick = onBack,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
|
|
@ -54,7 +59,8 @@ private fun Preview(@PreviewParameter(PortfolioSelectorPreviewStateProvider::cla
|
|||
PortfolioSelectorBS(
|
||||
state = params,
|
||||
onDismiss = {},
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
|
||||
modifier = Modifier,
|
||||
onBack = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,10 @@ package com.tangem.features.account.selector.ui
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
|
|
@ -18,9 +20,10 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.common.ui.account.AccountIconPreviewData
|
||||
import com.tangem.common.ui.userwallet.UserWalletItem
|
||||
import com.tangem.common.ui.userwallet.UserWalletItemRow
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM.ImageState
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -66,12 +69,16 @@ internal fun PortfolioSelectorContent(
|
|||
}
|
||||
|
||||
when (item) {
|
||||
is PortfolioSelectorItemUM.Portfolio -> UserWalletItem(
|
||||
is PortfolioSelectorItemUM.Portfolio -> UserWalletItemRow(
|
||||
state = item.item,
|
||||
modifier = offsetModifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.size68)
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
|
||||
.background(color = TangemTheme.colors.background.primary)
|
||||
.let { if (!item.item.isEnabled) it.alpha(DISABLED_WALLET_ALPHA) else it },
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable(enabled = item.item.isEnabled, onClick = item.item.onClick)
|
||||
.padding(all = TangemTheme.dimens.spacing12)
|
||||
.conditional(!item.item.isEnabled) { alpha(DISABLED_WALLET_ALPHA) },
|
||||
)
|
||||
is PortfolioSelectorItemUM.GroupTitle -> WalletNameRow(
|
||||
model = item,
|
||||
|
|
@ -103,7 +110,7 @@ private fun Preview(@PreviewParameter(PortfolioSelectorPreviewStateProvider::cla
|
|||
TangemThemePreview {
|
||||
PortfolioSelectorContent(
|
||||
state = params,
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.tertiary),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -127,6 +134,9 @@ internal object PortfolioSelectorPreviewData {
|
|||
),
|
||||
)
|
||||
|
||||
private val lockedAccountItem: UserWalletItemUM
|
||||
get() = accountItem.copy(isEnabled = false)
|
||||
|
||||
private val walletItem: UserWalletItemUM
|
||||
get() = UserWalletItemUM(
|
||||
id = UserWalletId(UUID.randomUUID().toString().encodeToByteArray()),
|
||||
|
|
@ -150,7 +160,7 @@ internal object PortfolioSelectorPreviewData {
|
|||
accountItem
|
||||
.let { PortfolioSelectorItemUM.Portfolio(it) }
|
||||
.let(::add)
|
||||
accountItem
|
||||
lockedAccountItem
|
||||
.let { PortfolioSelectorItemUM.Portfolio(it) }
|
||||
.let(::add)
|
||||
PortfolioSelectorItemUM.GroupTitle(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue