Updated on 2026-08-14
This commit is contained in:
commit
edec3fcdff
391 changed files with 10988 additions and 3221 deletions
|
|
@ -365,7 +365,12 @@ internal class WalletModel @Inject constructor(
|
|||
value = info,
|
||||
onClickIssue = ::issueOrder,
|
||||
onClickKyc = innerWalletRouter::openTangemPayOnboarding,
|
||||
openDetails = innerWalletRouter::openTangemPayDetails,
|
||||
openDetails = { config ->
|
||||
innerWalletRouter.openTangemPayDetails(
|
||||
userWalletId = stateHolder.getSelectedWalletId(),
|
||||
config = config,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import com.tangem.core.ui.haptic.TangemHapticEffect
|
|||
import com.tangem.core.ui.haptic.VibratorHapticManager
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||
import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.extenstions.unwrap
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
|
|
@ -157,7 +157,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
private val removeCurrencyUseCase: RemoveCurrencyUseCase,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
|
||||
private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase,
|
||||
private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
|
||||
) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents {
|
||||
|
||||
override fun onSendClick(
|
||||
|
|
@ -360,7 +360,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
return@launch
|
||||
}
|
||||
|
||||
saveCryptoCurrenciesUseCase(accountId = accountId, remove = cryptoCurrencyStatus.currency)
|
||||
manageCryptoCurrenciesUseCase(accountId = accountId, remove = cryptoCurrencyStatus.currency)
|
||||
} else {
|
||||
removeCurrencyUseCase(userWalletId, cryptoCurrencyStatus.currency)
|
||||
}
|
||||
|
|
@ -507,7 +507,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
appRouter.push(
|
||||
AppRoute.Staking(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
yieldId = yield?.id ?: return@launch,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -106,6 +106,28 @@ internal object WalletScreenPreviewData {
|
|||
),
|
||||
)
|
||||
|
||||
private val emptyPortfolioContentState = WalletTokensListState.ContentState.PortfolioContent(
|
||||
items = persistentListOf(
|
||||
TokensListItemUM.Portfolio(
|
||||
tokens = textContentTokensState.items.filterIsInstance<PortfolioTokensListItemUM>().toPersistentList(),
|
||||
isExpanded = false,
|
||||
isCollapsable = true,
|
||||
tokenItemUM = AccountItemPreviewData.accountItem
|
||||
.copy(iconState = AccountItemPreviewData.accountLetterIcon),
|
||||
),
|
||||
TokensListItemUM.Portfolio(
|
||||
tokens = persistentListOf(),
|
||||
isExpanded = true,
|
||||
isCollapsable = true,
|
||||
tokenItemUM = AccountItemPreviewData.accountItem,
|
||||
),
|
||||
),
|
||||
organizeTokensButtonConfig = WalletTokensListState.OrganizeTokensButtonConfig(
|
||||
isEnabled = true,
|
||||
onClick = {},
|
||||
),
|
||||
)
|
||||
|
||||
private val noteLockedCard by lazy {
|
||||
WalletCardState.LockedContent(
|
||||
id = UserWalletId(stringValue = "1"),
|
||||
|
|
@ -208,4 +230,12 @@ internal object WalletScreenPreviewData {
|
|||
multiWalletState.copy(tokensListState = portfolioContentState),
|
||||
),
|
||||
)
|
||||
|
||||
internal val accountScreenWithEmptyTokensState =
|
||||
walletScreenState.copy(
|
||||
wallets = persistentListOf(
|
||||
singleWalletLockedState,
|
||||
multiWalletState.copy(tokensListState = emptyPortfolioContentState),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -109,8 +109,8 @@ internal class DefaultWalletRouter @Inject constructor(
|
|||
router.push(AppRoute.TangemPayOnboarding(AppRoute.TangemPayOnboarding.Mode.ContinueOnboarding))
|
||||
}
|
||||
|
||||
override fun openTangemPayDetails(config: TangemPayDetailsConfig) {
|
||||
router.push(AppRoute.TangemPayDetails(config))
|
||||
override fun openTangemPayDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig) {
|
||||
router.push(AppRoute.TangemPayDetails(userWalletId = userWalletId, config = config))
|
||||
}
|
||||
|
||||
override fun openYieldSupplyBottomSheet(
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ internal interface InnerWalletRouter {
|
|||
|
||||
fun openTangemPayOnboarding()
|
||||
|
||||
fun openTangemPayDetails(config: TangemPayDetailsConfig)
|
||||
fun openTangemPayDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig)
|
||||
|
||||
/** Open BS abput yield supply active and all money deposited in AAVE */
|
||||
fun openYieldSupplyBottomSheet(
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ internal class TokenListStateConverter(
|
|||
appCurrency = appCurrency,
|
||||
account = account,
|
||||
onItemClick = onItemClick,
|
||||
priceChangeLce = this.priceChangeLce,
|
||||
)
|
||||
val accountItem = converter.convert(tokenList.totalFiatBalance)
|
||||
val tokenConverter = tokenStatusConverter(account.accountId)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ import com.tangem.core.ui.utils.moveTo
|
|||
import com.tangem.core.ui.utils.toPx
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.preview.WalletScreenPreviewData.accountScreenState
|
||||
import com.tangem.feature.wallet.presentation.common.preview.WalletScreenPreviewData.accountScreenWithEmptyTokensState
|
||||
import com.tangem.feature.wallet.presentation.common.preview.WalletScreenPreviewData.walletScreenState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.holder.TxHistoryStateHolder
|
||||
|
|
@ -142,6 +143,7 @@ private fun WalletContent(
|
|||
*/
|
||||
val selectedWalletIndex by remember(state.selectedWalletIndex) { mutableIntStateOf(state.selectedWalletIndex) }
|
||||
val selectedWallet = state.wallets.getOrElse(selectedWalletIndex) { state.wallets[state.selectedWalletIndex] }
|
||||
val selectedWalletChanged = rememberChangedOnce(selectedWalletIndex)
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
|
|
@ -239,6 +241,7 @@ private fun WalletContent(
|
|||
|
||||
contentItems(
|
||||
state = selectedWallet,
|
||||
selectedWalletChanged = selectedWalletChanged,
|
||||
txHistoryItems = txHistoryItems,
|
||||
isBalanceHidden = state.isHidingMode,
|
||||
modifier = movableItemModifier,
|
||||
|
|
@ -289,6 +292,14 @@ private fun WalletContent(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberChangedOnce(selectedWalletIndex: Int): Boolean {
|
||||
var prev by remember { mutableIntStateOf(selectedWalletIndex) }
|
||||
val changed = prev != selectedWalletIndex
|
||||
SideEffect { prev = selectedWalletIndex }
|
||||
return changed
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList", "LongMethod", "CyclomaticComplexMethod")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -743,6 +754,7 @@ private class WalletScreenPreviewProvider : PreviewParameterProvider<WalletScree
|
|||
walletScreenState,
|
||||
walletScreenState.copy(selectedWalletIndex = 1),
|
||||
accountScreenState.copy(selectedWalletIndex = 1),
|
||||
accountScreenWithEmptyTokensState.copy(selectedWalletIndex = 1),
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -22,10 +22,11 @@ internal fun LazyListScope.contentItems(
|
|||
txHistoryItems: LazyPagingItems<TxHistoryState.TxHistoryItemState>?,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
selectedWalletChanged: Boolean,
|
||||
) {
|
||||
when (state) {
|
||||
is WalletState.MultiCurrency -> {
|
||||
tokensListItems(state.tokensListState, modifier, isBalanceHidden)
|
||||
tokensListItems(state.tokensListState, modifier, isBalanceHidden, selectedWalletChanged)
|
||||
}
|
||||
is WalletState.SingleCurrency -> {
|
||||
txHistoryItems(state.txHistoryState, txHistoryItems, isBalanceHidden, modifier)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ internal fun LazyListScope.portfolioContentItems(
|
|||
items: ImmutableList<TokensListItemUM.Portfolio>,
|
||||
modifier: Modifier = Modifier,
|
||||
isBalanceHidden: Boolean,
|
||||
selectedWalletChanged: Boolean,
|
||||
) {
|
||||
items.forEachIndexed { index, item ->
|
||||
portfolioTokensList(
|
||||
|
|
@ -34,6 +35,7 @@ internal fun LazyListScope.portfolioContentItems(
|
|||
modifier = modifier,
|
||||
portfolioIndex = index,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
selectedWalletChanged = selectedWalletChanged,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +45,7 @@ internal fun LazyListScope.portfolioTokensList(
|
|||
modifier: Modifier,
|
||||
portfolioIndex: Int,
|
||||
isBalanceHidden: Boolean,
|
||||
selectedWalletChanged: Boolean,
|
||||
) {
|
||||
val tokens = portfolio.tokens
|
||||
val isExpanded = portfolio.isExpanded
|
||||
|
|
@ -52,8 +55,28 @@ internal fun LazyListScope.portfolioTokensList(
|
|||
modifier = modifier,
|
||||
portfolioIndex = portfolioIndex,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
selectedWalletChanged = selectedWalletChanged,
|
||||
)
|
||||
if (!isExpanded) return
|
||||
if (tokens.isEmpty()) {
|
||||
item(
|
||||
key = "$NON_CONTENT_TOKENS_LIST_KEY account-${portfolio.id}",
|
||||
contentType = "$NON_CONTENT_TOKENS_LIST_KEY account-${portfolio.id}",
|
||||
) {
|
||||
NonContentItemContent(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.roundedShapeItemDecoration(
|
||||
radius = TangemTheme.dimens.radius14,
|
||||
currentIndex = 1,
|
||||
lastIndex = 1,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
)
|
||||
.padding(vertical = TangemTheme.dimens.spacing28),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
itemsIndexed(
|
||||
items = tokens,
|
||||
key = { _, item -> item.id },
|
||||
|
|
@ -63,13 +86,14 @@ internal fun LazyListScope.portfolioTokensList(
|
|||
val lastIndex = tokens.lastIndex.inc()
|
||||
val isPreview = LocalInspectionMode.current
|
||||
val appear = remember {
|
||||
MutableTransitionState(isPreview).apply { targetState = true }
|
||||
MutableTransitionState(selectedWalletChanged || isPreview).apply { targetState = true }
|
||||
}
|
||||
SlideInItemVisibility(
|
||||
modifier = modifier
|
||||
.testModifier(indexWithHeader)
|
||||
.animateItem()
|
||||
.roundedShapeItemDecoration(
|
||||
radius = TangemTheme.dimens.radius14,
|
||||
currentIndex = indexWithHeader,
|
||||
lastIndex = lastIndex,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
|
|
@ -92,10 +116,17 @@ private fun LazyListScope.portfolioItem(
|
|||
modifier: Modifier,
|
||||
portfolioIndex: Int,
|
||||
isBalanceHidden: Boolean,
|
||||
selectedWalletChanged: Boolean,
|
||||
) {
|
||||
val tokens = portfolio.tokens
|
||||
val isExpanded = portfolio.isExpanded
|
||||
|
||||
val lastIndex = when {
|
||||
isExpanded && tokens.isEmpty() -> 1
|
||||
isExpanded -> tokens.lastIndex.inc()
|
||||
else -> 0
|
||||
}
|
||||
|
||||
item(
|
||||
key = "account-${portfolio.id}-isExpanded$isExpanded",
|
||||
contentType = "account-isExpanded$isExpanded",
|
||||
|
|
@ -105,27 +136,24 @@ private fun LazyListScope.portfolioItem(
|
|||
.animateItem()
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = 0,
|
||||
lastIndex = if (isExpanded) tokens.lastIndex.inc() else 0,
|
||||
radius = TangemTheme.dimens.radius14,
|
||||
lastIndex = lastIndex,
|
||||
backgroundColor = TangemTheme.colors.background.primary,
|
||||
)
|
||||
val isPreview = LocalInspectionMode.current
|
||||
val appear = remember {
|
||||
MutableTransitionState(isPreview).apply { targetState = true }
|
||||
MutableTransitionState(selectedWalletChanged || isPreview || tokens.isEmpty())
|
||||
.apply { targetState = true }
|
||||
}
|
||||
if (isExpanded) {
|
||||
SlideInItemVisibility(
|
||||
modifier = anchorModifier,
|
||||
visibleState = appear,
|
||||
) {
|
||||
val modifier = if (portfolio.tokens.isEmpty()) {
|
||||
Modifier.padding(vertical = 8.dp)
|
||||
} else {
|
||||
Modifier.padding(top = 8.dp)
|
||||
}
|
||||
PortfolioListItem(
|
||||
state = portfolio,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = modifier,
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import androidx.compose.foundation.lazy.LazyListScope
|
|||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
|
|
@ -25,7 +26,7 @@ import com.tangem.feature.wallet.impl.R
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
private const val NON_CONTENT_TOKENS_LIST_KEY = "NON_CONTENT_TOKENS_LIST"
|
||||
internal const val NON_CONTENT_TOKENS_LIST_KEY = "NON_CONTENT_TOKENS_LIST"
|
||||
|
||||
/**
|
||||
* LazyList extension for [WalletTokensListState]
|
||||
|
|
@ -39,12 +40,14 @@ internal fun LazyListScope.tokensListItems(
|
|||
state: WalletTokensListState,
|
||||
modifier: Modifier = Modifier,
|
||||
isBalanceHidden: Boolean,
|
||||
selectedWalletChanged: Boolean,
|
||||
) {
|
||||
when (state) {
|
||||
is WalletTokensListState.ContentState.PortfolioContent -> portfolioContentItems(
|
||||
items = state.items,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
modifier = modifier,
|
||||
selectedWalletChanged = selectedWalletChanged,
|
||||
)
|
||||
is WalletTokensListState.ContentState.Content,
|
||||
is WalletTokensListState.ContentState.Loading,
|
||||
|
|
@ -89,27 +92,34 @@ private fun LazyListScope.nonContentItem(modifier: Modifier = Modifier) {
|
|||
key = NON_CONTENT_TOKENS_LIST_KEY,
|
||||
contentType = NON_CONTENT_TOKENS_LIST_KEY,
|
||||
) {
|
||||
Column(
|
||||
NonContentItemContent(
|
||||
modifier = modifier
|
||||
.animateItem(fadeInSpec = null, fadeOutSpec = null)
|
||||
.padding(top = TangemTheme.dimens.spacing96),
|
||||
verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing16),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_empty_64),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(size = TangemTheme.dimens.size64),
|
||||
tint = TangemTheme.colors.icon.inactive,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.main_empty_tokens_list_message),
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing48),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
@Composable
|
||||
internal fun NonContentItemContent(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing16),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_empty_64),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(size = TangemTheme.dimens.size64),
|
||||
tint = TangemTheme.colors.icon.inactive,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.main_empty_tokens_list_message),
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing48),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.feature.wallet.utils
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.ui.userwallet.converter.ArtworkUMConverter
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.ui.components.artwork.ArtworkUM
|
||||
|
|
@ -47,12 +46,11 @@ class DefaultUserWalletImageFetcher @Inject constructor(
|
|||
|
||||
override fun walletImage(walletId: UserWalletId, size: ArtworkSize): Flow<UserWalletItemUM.ImageState> =
|
||||
getUserWalletUseCase.invokeFlow(walletId)
|
||||
.transform { either ->
|
||||
if (either.isLeft()) {
|
||||
emit(UserWalletItemUM.ImageState.Loading)
|
||||
} else if (either is Either.Right) {
|
||||
emitAll(walletImage(either.value, size))
|
||||
}
|
||||
.transform {
|
||||
it.fold(
|
||||
ifLeft = { emit(UserWalletItemUM.ImageState.Loading) },
|
||||
ifRight = { wallet -> emitAll(walletImage(wallet, size)) },
|
||||
)
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue