Updated on 2026-08-14
This commit is contained in:
parent
18474637b9
commit
a252e33515
17 changed files with 796 additions and 37 deletions
|
|
@ -13,7 +13,12 @@ dependencies {
|
|||
/* Project - Core */
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.common.ui)
|
||||
|
||||
/* Project - Domain */
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.features.account
|
||||
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.models.account.Account
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
interface AccountSelectorComponent : ComposableBottomSheetComponent {
|
||||
|
||||
data class Params(
|
||||
val onDismiss: () -> Unit,
|
||||
val accountsBalanceFetcher: AccountsBalanceFetcher,
|
||||
val controller: AccountSelectorController,
|
||||
)
|
||||
|
||||
interface Factory {
|
||||
fun create(appComponentContext: AppComponentContext, params: Params): AccountSelectorComponent
|
||||
}
|
||||
}
|
||||
|
||||
interface AccountSelectorController {
|
||||
val selectedAccount: StateFlow<Account?>
|
||||
fun selectAccount(account: Account?)
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.features.account
|
||||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
interface AccountsBalanceFetcher {
|
||||
|
||||
val data: Flow<Data>
|
||||
|
||||
val mode: StateFlow<Mode>
|
||||
fun updateMode(mode: Mode)
|
||||
|
||||
data class Data(
|
||||
val appCurrency: AppCurrency,
|
||||
val isBalanceHidden: Boolean,
|
||||
val balances: Map<UserWallet, Map<Account, AccountBalance>>,
|
||||
)
|
||||
|
||||
data class AccountBalance(
|
||||
val balance: Lce<TokenListError, TotalFiatBalance>,
|
||||
)
|
||||
|
||||
sealed interface Mode {
|
||||
data class All(val onlyMultiCurrency: Boolean) : Mode
|
||||
data class Wallet(val walletId: UserWalletId) : Mode
|
||||
}
|
||||
|
||||
interface Factory {
|
||||
fun create(mode: Mode, scope: CoroutineScope): AccountsBalanceFetcher
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,15 @@ dependencies {
|
|||
/** Domain */
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.account)
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.appCurrency)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.balanceHiding)
|
||||
implementation(projects.domain.balanceHiding.models)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
package com.tangem.features.account.fetcher
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.features.account.AccountsBalanceFetcher
|
||||
import com.tangem.features.account.AccountsBalanceFetcher.*
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
internal class DefaultAccountsBalanceFetcher @AssistedInject constructor(
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getWallets: GetWalletsUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
@Assisted mode: Mode,
|
||||
@Assisted private val scope: CoroutineScope,
|
||||
) : AccountsBalanceFetcher {
|
||||
|
||||
private val _mode = MutableStateFlow(mode)
|
||||
private val _data = MutableSharedFlow<Data>(
|
||||
replay = 1,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
)
|
||||
|
||||
override val data: Flow<Data>
|
||||
get() = _data.distinctUntilChanged()
|
||||
override val mode: StateFlow<Mode>
|
||||
get() = _mode
|
||||
|
||||
init {
|
||||
_mode.flatMapLatest(::combineUseCases)
|
||||
.flowOn(dispatchers.default)
|
||||
.onEach { _data.emit(it) }
|
||||
.launchIn(scope)
|
||||
}
|
||||
|
||||
override fun updateMode(mode: Mode) {
|
||||
_mode.value = mode
|
||||
}
|
||||
|
||||
private fun combineUseCases(mode: Mode) = combine(
|
||||
flow = getWallets()
|
||||
.map { it.filterWallets(mode) }
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { wallets -> balancesForWallets(wallets) },
|
||||
flow2 = appCurrencyFlow(),
|
||||
flow3 = balanceHidingFlow(),
|
||||
) { balances, appCurrency, isBalanceHiding ->
|
||||
Data(
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHiding,
|
||||
balances = balances,
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<UserWallet>.filterWallets(mode: Mode): List<UserWallet> = this.filter { wallet ->
|
||||
when (mode) {
|
||||
is Mode.All -> if (mode.onlyMultiCurrency) wallet.isMultiCurrency else true
|
||||
is Mode.Wallet -> wallet.walletId == mode.walletId
|
||||
}
|
||||
}
|
||||
|
||||
private fun balancesForWallets(wallets: List<UserWallet>): Flow<Map<UserWallet, Map<Account, AccountBalance>>> =
|
||||
wallets.asFlow()
|
||||
.map { walletAccountsBalancesFlow(it) }
|
||||
.mapLatest { accountsBalances -> combine(accountsBalances) { pairs -> pairs.toMap() } }
|
||||
.flattenConcat()
|
||||
|
||||
private fun walletAccountsBalancesFlow(wallet: UserWallet): Flow<Pair<UserWallet, Map<Account, AccountBalance>>> =
|
||||
walletAccounts(wallet)
|
||||
.distinctUntilChanged()
|
||||
.map { list -> list.map(::accountBalanceFlow) }
|
||||
.mapLatest { balanceFlows -> combine(balanceFlows) { balances -> balances.toMap() } }
|
||||
.flattenConcat()
|
||||
.map { accountBalance -> wallet to accountBalance }
|
||||
|
||||
private fun walletAccounts(wallet: UserWallet): Flow<List<Account>> = flow {
|
||||
// todo account load accounts
|
||||
val accounts: List<Account> = Account.CryptoPortfolio
|
||||
.createMainAccount(wallet.walletId)
|
||||
.let(::listOf)
|
||||
emit(accounts)
|
||||
}
|
||||
|
||||
private fun accountBalanceFlow(account: Account): Flow<Pair<Account, AccountBalance>> = flow {
|
||||
// todo account load balance
|
||||
val balance = AccountBalance(balance = Lce.Content(TotalFiatBalance.Loading))
|
||||
emit(account to balance)
|
||||
}
|
||||
|
||||
private fun appCurrencyFlow(): Flow<AppCurrency> {
|
||||
return getSelectedAppCurrencyUseCase()
|
||||
.map { it.getOrElse { AppCurrency.Default } }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun balanceHidingFlow(): Flow<Boolean> {
|
||||
return getBalanceHidingSettingsUseCase()
|
||||
.map { it.isBalanceHidden }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : AccountsBalanceFetcher.Factory {
|
||||
override fun create(mode: Mode, scope: CoroutineScope): DefaultAccountsBalanceFetcher
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package com.tangem.features.account.selector
|
||||
|
||||
import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter
|
||||
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.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.core.utils.getOrElse
|
||||
import com.tangem.domain.models.TotalFiatBalance
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.isLocked
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.features.account.AccountSelectorComponent
|
||||
import com.tangem.features.account.AccountsBalanceFetcher
|
||||
import com.tangem.features.account.selector.entity.AccountSelectorItemUM
|
||||
import com.tangem.features.account.selector.entity.AccountSelectorUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class AccountSelectorModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<AccountSelectorComponent.Params>()
|
||||
private val balanceFetcher get() = params.accountsBalanceFetcher
|
||||
private val selectorController get() = params.controller
|
||||
|
||||
internal val state: StateFlow<AccountSelectorUM>
|
||||
field = MutableStateFlow<AccountSelectorUM>(emptyState())
|
||||
|
||||
init {
|
||||
balanceFetcher.data
|
||||
.map { data ->
|
||||
AccountSelectorUM(
|
||||
isSingleWallet = balanceFetcher.mode.value is AccountsBalanceFetcher.Mode.Wallet,
|
||||
items = buildUiList(data).toImmutableList(),
|
||||
)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun buildUiList(data: AccountsBalanceFetcher.Data) = buildList {
|
||||
fun Account.accountItemState(balance: Lce<TokenListError, TotalFiatBalance>): TokenItemState {
|
||||
val totalFiatBalance = balance.getOrElse(
|
||||
ifError = { TotalFiatBalance.Failed },
|
||||
ifLoading = { TotalFiatBalance.Loading },
|
||||
)
|
||||
return when (this) {
|
||||
is Account.CryptoPortfolio -> AccountCryptoPortfolioItemStateConverter(
|
||||
appCurrency = data.appCurrency,
|
||||
account = this,
|
||||
onItemClick = { selectorController.selectAccount(it) },
|
||||
).convert(totalFiatBalance)
|
||||
}
|
||||
}
|
||||
|
||||
data.balances.forEach { wallet, accounts ->
|
||||
if (wallet.isLocked) return@forEach
|
||||
AccountSelectorItemUM.Wallet(
|
||||
id = wallet.walletId.stringValue,
|
||||
name = stringReference(wallet.name),
|
||||
).let(::add)
|
||||
|
||||
accounts.forEach { account, balance ->
|
||||
AccountSelectorItemUM.Account(
|
||||
account = account.accountItemState(balance.balance),
|
||||
isBalanceHidden = data.isBalanceHidden,
|
||||
).let(::add)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun emptyState() = AccountSelectorUM(
|
||||
items = persistentListOf(),
|
||||
balanceFetcher.mode.value is AccountsBalanceFetcher.Mode.Wallet,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package com.tangem.features.account.selector
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
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.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.account.AccountSelectorComponent
|
||||
import com.tangem.features.account.impl.R
|
||||
import com.tangem.features.account.selector.ui.AccountSelectorContent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultAccountSelectorComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: AccountSelectorComponent.Params,
|
||||
) : AppComponentContext by appComponentContext, AccountSelectorComponent {
|
||||
|
||||
private val model: AccountSelectorModel = getOrCreateModel(params)
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onBack = ::dismiss,
|
||||
containerColor = TangemTheme.colors.background.primary,
|
||||
title = {
|
||||
TangemModalBottomSheetTitle(
|
||||
title = resourceReference(R.string.common_choose_wallet),
|
||||
startIconRes = R.drawable.ic_back_24,
|
||||
onStartClick = ::dismiss,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
AccountSelectorContent(
|
||||
state = state,
|
||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : AccountSelectorComponent.Factory {
|
||||
override fun create(
|
||||
appComponentContext: AppComponentContext,
|
||||
params: AccountSelectorComponent.Params,
|
||||
): DefaultAccountSelectorComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.features.account.selector
|
||||
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.features.account.AccountSelectorController
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultAccountSelectorController @Inject constructor() : AccountSelectorController {
|
||||
|
||||
private val _selectedAccount: MutableStateFlow<Account?> = MutableStateFlow(null)
|
||||
override val selectedAccount: StateFlow<Account?> get() = _selectedAccount
|
||||
|
||||
override fun selectAccount(account: Account?) {
|
||||
_selectedAccount.update { account }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.features.account.selector.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class AccountSelectorUM(
|
||||
val items: ImmutableList<AccountSelectorItemUM>,
|
||||
val isSingleWallet: Boolean,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
sealed interface AccountSelectorItemUM {
|
||||
val id: String
|
||||
|
||||
data class Wallet(
|
||||
override val id: String,
|
||||
val name: TextReference,
|
||||
) : AccountSelectorItemUM
|
||||
|
||||
data class Account(
|
||||
val account: TokenItemState,
|
||||
val isBalanceHidden: Boolean,
|
||||
) : AccountSelectorItemUM {
|
||||
override val id: String = account.id
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.tangem.features.account.selector.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
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.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.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.account.impl.R
|
||||
import com.tangem.features.account.selector.entity.AccountSelectorUM
|
||||
|
||||
@Composable
|
||||
internal fun AccountSelectorBS(state: AccountSelectorUM, onDismiss: () -> Unit, modifier: Modifier = Modifier) {
|
||||
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = onDismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onBack = onDismiss,
|
||||
scrollableContent = false,
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
title = {
|
||||
TangemModalBottomSheetTitle(
|
||||
title = resourceReference(R.string.common_choose_account),
|
||||
startIconRes = R.drawable.ic_back_24,
|
||||
onStartClick = onDismiss,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
AccountSelectorContent(
|
||||
state = state,
|
||||
contentPadding = PaddingValues(bottom = 16.dp),
|
||||
modifier = modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(AccountSelectorPreviewStateProvider::class) params: AccountSelectorUM) {
|
||||
TangemThemePreview {
|
||||
AccountSelectorBS(
|
||||
state = params,
|
||||
onDismiss = {},
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
package com.tangem.features.account.selector.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
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.core.ui.components.token.AccountItemPreviewData
|
||||
import com.tangem.core.ui.components.token.TokenItem
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.account.selector.entity.AccountSelectorItemUM
|
||||
import com.tangem.features.account.selector.entity.AccountSelectorUM
|
||||
import com.tangem.features.account.selector.ui.AccountSelectorPreviewData.firstList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.util.UUID
|
||||
|
||||
@Composable
|
||||
internal fun AccountSelectorContent(
|
||||
state: AccountSelectorUM,
|
||||
modifier: Modifier = Modifier,
|
||||
contentPadding: PaddingValues = PaddingValues(),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
val items = state.items
|
||||
itemsIndexed(
|
||||
items = items,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
val previewItem = items.getOrNull(index.dec())
|
||||
val offsetModifier = when {
|
||||
previewItem == null -> Modifier
|
||||
state.isSingleWallet -> Modifier.padding(
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
item is AccountSelectorItemUM.Wallet -> Modifier.padding(
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
else -> Modifier.padding(
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
)
|
||||
}
|
||||
|
||||
when (item) {
|
||||
is AccountSelectorItemUM.Account -> TokenItem(
|
||||
state = item.account,
|
||||
isBalanceHidden = item.isBalanceHidden,
|
||||
modifier = offsetModifier
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
|
||||
.background(color = TangemTheme.colors.background.primary),
|
||||
)
|
||||
is AccountSelectorItemUM.Wallet -> WalletNameRow(
|
||||
model = item,
|
||||
modifier = offsetModifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WalletNameRow(model: AccountSelectorItemUM.Wallet, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = model.name.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun AccountSelectorContentPreview(
|
||||
@PreviewParameter(AccountSelectorPreviewStateProvider::class) params: AccountSelectorUM,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
AccountSelectorContent(
|
||||
state = params,
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal object AccountSelectorPreviewData {
|
||||
val firstList
|
||||
get() = buildList {
|
||||
AccountSelectorItemUM.Wallet(
|
||||
id = UUID.randomUUID().toString(),
|
||||
name = stringReference("Tangem 2.0"),
|
||||
).let(::add)
|
||||
AccountItemPreviewData.accountItem
|
||||
.let { AccountSelectorItemUM.Account(it, false) }
|
||||
.let(::add)
|
||||
AccountItemPreviewData.accountItem.copy(iconState = AccountItemPreviewData.accountLetterIcon)
|
||||
.let { AccountSelectorItemUM.Account(it, false) }
|
||||
.let(::add)
|
||||
AccountSelectorItemUM.Wallet(
|
||||
id = UUID.randomUUID().toString(),
|
||||
name = stringReference("Tangem White"),
|
||||
).let(::add)
|
||||
AccountItemPreviewData.accountItem.copy(iconState = AccountItemPreviewData.accountLetterIcon)
|
||||
.let { AccountSelectorItemUM.Account(it, false) }
|
||||
.let(::add)
|
||||
}
|
||||
}
|
||||
|
||||
internal class AccountSelectorPreviewStateProvider : CollectionPreviewParameterProvider<AccountSelectorUM>(
|
||||
buildList {
|
||||
val secondList = listOf(
|
||||
AccountItemPreviewData.accountItem,
|
||||
AccountItemPreviewData.accountItem.copy(iconState = AccountItemPreviewData.accountLetterIcon),
|
||||
).map { AccountSelectorItemUM.Account(it, false) }
|
||||
|
||||
val first = AccountSelectorUM(
|
||||
items = firstList.toImmutableList(),
|
||||
isSingleWallet = false,
|
||||
)
|
||||
val second = AccountSelectorUM(
|
||||
items = secondList.toImmutableList(),
|
||||
isSingleWallet = true,
|
||||
)
|
||||
add(first)
|
||||
add(second)
|
||||
},
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue