Updated on 2026-08-14
This commit is contained in:
parent
7fee3c6d3b
commit
70dd41a680
19 changed files with 594 additions and 184 deletions
|
|
@ -41,7 +41,10 @@ internal class DefaultPortfolioFetcher @AssistedInject constructor(
|
|||
get() = _mode
|
||||
|
||||
init {
|
||||
_mode.flatMapLatest(::combineUseCases)
|
||||
_mode
|
||||
// reset cache if mode(StateFlow) changed
|
||||
.onEach { _data.resetReplayCache() }
|
||||
.flatMapLatest(::combineUseCases)
|
||||
.flowOn(dispatchers.default)
|
||||
.onEach { _data.emit(it) }
|
||||
.launchIn(scope)
|
||||
|
|
|
|||
|
|
@ -147,11 +147,17 @@ internal class PortfolioSelectorModel @Inject constructor(
|
|||
return@forEach
|
||||
}
|
||||
|
||||
val walletTitle = PortfolioSelectorItemUM.GroupTitle(
|
||||
id = "GroupTitle ${wallet.walletId.stringValue}",
|
||||
name = stringReference(wallet.name),
|
||||
)
|
||||
add(walletTitle)
|
||||
when (balanceFetcher.mode.value) {
|
||||
// for Wallet mode expected single portfolioData.balances
|
||||
is PortfolioFetcher.Mode.Wallet -> Unit
|
||||
is PortfolioFetcher.Mode.All -> {
|
||||
val walletTitle = PortfolioSelectorItemUM.GroupTitle(
|
||||
id = "GroupTitle ${wallet.walletId.stringValue}",
|
||||
name = stringReference(wallet.name),
|
||||
)
|
||||
add(walletTitle)
|
||||
}
|
||||
}
|
||||
|
||||
portfolio.accountsBalance.accountStatuses.forEach { accountStatus ->
|
||||
val isEnabledByFeature = isEnabled(wallet, accountStatus)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ android {
|
|||
|
||||
dependencies {
|
||||
/** Api */
|
||||
implementation(projects.features.account.api)
|
||||
implementation(projects.features.nft.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
|
||||
|
|
@ -28,6 +29,8 @@ dependencies {
|
|||
implementation(projects.core.datasource)
|
||||
|
||||
/** Domain modules */
|
||||
implementation(projects.domain.account)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
implementation(projects.domain.appCurrency)
|
||||
implementation(projects.domain.models)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,20 @@
|
|||
package com.tangem.features.nft.collections.entity
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal sealed interface NFTCollectionItem {
|
||||
val id: String
|
||||
}
|
||||
|
||||
internal data class NFTCollectionPortfolioUM(
|
||||
override val id: String,
|
||||
val title: AccountTitleUM,
|
||||
) : NFTCollectionItem
|
||||
|
||||
internal data class NFTCollectionUM(
|
||||
val id: String,
|
||||
override val id: String,
|
||||
val name: String,
|
||||
@DrawableRes val networkIconId: Int,
|
||||
val logoUrl: String?,
|
||||
|
|
@ -12,4 +22,4 @@ internal data class NFTCollectionUM(
|
|||
val assets: NFTCollectionAssetsListUM,
|
||||
val isExpanded: Boolean,
|
||||
val onExpandClick: () -> Unit,
|
||||
)
|
||||
) : NFTCollectionItem
|
||||
|
|
@ -23,7 +23,7 @@ internal sealed class NFTCollectionsUM {
|
|||
|
||||
data class Content(
|
||||
val search: SearchBarUM,
|
||||
val collections: ImmutableList<NFTCollectionUM>,
|
||||
val collections: ImmutableList<NFTCollectionItem>,
|
||||
val warnings: ImmutableList<NFTCollectionsWarningUM>,
|
||||
val onReceiveClick: () -> Unit,
|
||||
) : NFTCollectionsUM()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.nft.collections.entity.transformer
|
||||
|
||||
import com.tangem.domain.nft.models.NFTCollection
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionUM
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsStateUM
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
|
@ -21,7 +22,7 @@ internal class ChangeCollectionExpandedStateTransformer(
|
|||
is NFTCollectionsUM.Content -> prevState.content.copy(
|
||||
collections = prevState.content.collections.map {
|
||||
val collectionId = collection.collectionIdProvider()
|
||||
if (it.id == collectionId) {
|
||||
if (it.id == collectionId && it is NFTCollectionUM) {
|
||||
if (!it.isExpanded) {
|
||||
onFirstExpanded()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
package com.tangem.features.nft.collections.entity.transformer
|
||||
|
||||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.nft.models.*
|
||||
import com.tangem.features.nft.collections.entity.*
|
||||
import com.tangem.features.nft.impl.R
|
||||
|
|
@ -16,6 +19,8 @@ import kotlinx.collections.immutable.toPersistentList
|
|||
@Suppress("LongParameterList")
|
||||
internal class UpdateDataStateTransformer(
|
||||
private val nftCollections: List<NFTCollections>,
|
||||
private val walletNFTCollections: WalletNFTCollections? = null,
|
||||
private val isAccountMode: Boolean = false,
|
||||
private val onReceiveClick: () -> Unit,
|
||||
private val onRetryClick: () -> Unit,
|
||||
private val onExpandCollectionClick: (NFTCollection) -> Unit,
|
||||
|
|
@ -25,7 +30,9 @@ internal class UpdateDataStateTransformer(
|
|||
private val collectionIdProvider: NFTCollection.() -> String,
|
||||
) : Transformer<NFTCollectionsStateUM> {
|
||||
|
||||
@Suppress("CyclomaticComplexMethod")
|
||||
override fun transform(prevState: NFTCollectionsStateUM): NFTCollectionsStateUM {
|
||||
val nftCollections = walletNFTCollections?.flattenCollections ?: this.nftCollections
|
||||
val hasQuery = !(prevState.content as? NFTCollectionsUM.Content)?.search?.query.isNullOrEmpty()
|
||||
val content = when {
|
||||
!hasQuery && nftCollections.allCollectionsFailed() ->
|
||||
|
|
@ -66,16 +73,45 @@ internal class UpdateDataStateTransformer(
|
|||
} else {
|
||||
initialSearchBarFactory()
|
||||
},
|
||||
collections = nftCollections
|
||||
collections = walletNFTCollections
|
||||
?.let { createCollections(it) }
|
||||
?: createNFTsUM(nftCollections).toPersistentList(),
|
||||
warnings = transformNotifications(),
|
||||
onReceiveClick = onReceiveClick,
|
||||
)
|
||||
|
||||
private fun NFTCollectionsStateUM.createCollections(walletNFTCollections: WalletNFTCollections) =
|
||||
if (isAccountMode) {
|
||||
val result = mutableListOf<NFTCollectionItem>()
|
||||
walletNFTCollections.collections.forEach { (account, nfts) ->
|
||||
if (nfts.isEmpty()) return@forEach
|
||||
result.add(account.toAccountPortfolioUM())
|
||||
result.addAll(createNFTsUM(nfts))
|
||||
}
|
||||
result.toPersistentList()
|
||||
} else {
|
||||
val mainAccountCollection = walletNFTCollections.collections.values.firstOrNull() ?: listOf()
|
||||
createNFTsUM(mainAccountCollection).toPersistentList()
|
||||
}
|
||||
|
||||
private fun Account.toAccountPortfolioUM(): NFTCollectionPortfolioUM = NFTCollectionPortfolioUM(
|
||||
id = this.accountId.value,
|
||||
title = AccountTitleUM.Account(
|
||||
prefixText = TextReference.EMPTY,
|
||||
name = this.accountName.toUM().value,
|
||||
icon = when (this) {
|
||||
is Account.CryptoPortfolio -> this.icon.toUM()
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
private fun NFTCollectionsStateUM.createNFTsUM(nftCollections: List<NFTCollections>): Sequence<NFTCollectionUM> =
|
||||
nftCollections
|
||||
.map { it.content }
|
||||
.asSequence()
|
||||
.filterIsInstance<NFTCollections.Content.Collections>()
|
||||
.map { it.collections.orEmpty().transform(this) }
|
||||
.flatten()
|
||||
.toPersistentList(),
|
||||
warnings = transformNotifications(),
|
||||
onReceiveClick = onReceiveClick,
|
||||
)
|
||||
|
||||
private fun List<NFTCollection>.transform(state: NFTCollectionsStateUM): ImmutableList<NFTCollectionUM> = map {
|
||||
NFTCollectionUM(
|
||||
|
|
@ -97,6 +133,8 @@ internal class UpdateDataStateTransformer(
|
|||
}.toPersistentList()
|
||||
|
||||
private fun transformNotifications(): ImmutableList<NFTCollectionsWarningUM> = buildList {
|
||||
val nftCollections = walletNFTCollections?.flattenCollections
|
||||
?: this@UpdateDataStateTransformer.nftCollections
|
||||
if (nftCollections.anyCollectionFailed()) {
|
||||
add(
|
||||
NFTCollectionsWarningUM(
|
||||
|
|
@ -152,6 +190,7 @@ internal class UpdateDataStateTransformer(
|
|||
private fun NFTCollection.isExpanded(state: NFTCollectionsStateUM): Boolean =
|
||||
(state.content as? NFTCollectionsUM.Content)
|
||||
?.collections
|
||||
?.filterIsInstance<NFTCollectionUM>()
|
||||
?.firstOrNull { it.id == this.collectionIdProvider() }
|
||||
?.isExpanded
|
||||
?: false
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfi
|
|||
import com.tangem.core.ui.components.fields.InputManager
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.nft.FetchNFTCollectionAssetsUseCase
|
||||
import com.tangem.domain.nft.GetNFTCollectionsUseCase
|
||||
import com.tangem.domain.nft.RefreshAllNFTUseCase
|
||||
|
|
@ -31,6 +33,8 @@ internal class NFTCollectionsModel @Inject constructor(
|
|||
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
|
||||
private val fetchNFTCollectionAssetsUseCase: FetchNFTCollectionAssetsUseCase,
|
||||
private val refreshAllNFTUseCase: RefreshAllNFTUseCase,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -62,7 +66,11 @@ internal class NFTCollectionsModel @Inject constructor(
|
|||
}
|
||||
|
||||
init {
|
||||
subscribeToNFTCollections()
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
subscribeToNFTCollectionsNew()
|
||||
} else {
|
||||
subscribeToNFTCollections()
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeToNFTCollections() {
|
||||
|
|
@ -91,6 +99,38 @@ internal class NFTCollectionsModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeToNFTCollectionsNew() {
|
||||
combine(
|
||||
flow = getNFTCollectionsUseCase.invokeForAccounts(params.userWalletId),
|
||||
flow2 = searchManager.query.distinctUntilChanged(),
|
||||
flow3 = isAccountsModeEnabledUseCase(),
|
||||
) { nftCollections, query, isAccountMode ->
|
||||
val filteredNFTs = nftCollections.collections
|
||||
.mapValues { (_, nfts) -> nfts.filter(query) }
|
||||
|
||||
_state.update {
|
||||
UpdateDataStateTransformer(
|
||||
nftCollections = listOf(),
|
||||
isAccountMode = isAccountMode,
|
||||
walletNFTCollections = nftCollections.copy(collections = filteredNFTs),
|
||||
onReceiveClick = {
|
||||
params.onReceiveClick()
|
||||
},
|
||||
onRetryClick = ::onRefresh,
|
||||
onExpandCollectionClick = ::onExpandCollectionClick,
|
||||
onRetryAssetsClick = ::onRetryAssetsClick,
|
||||
onAssetClick = { asset, collection ->
|
||||
params.onAssetClick(asset, collection)
|
||||
},
|
||||
initialSearchBarFactory = ::getInitialSearchBar,
|
||||
collectionIdProvider = collectionIdProvider,
|
||||
).transform(it)
|
||||
}
|
||||
}
|
||||
.onStart { onRefresh() }
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun List<NFTCollections>.filter(query: String): List<NFTCollections> = map {
|
||||
it.copy(
|
||||
content = when (val content = it.content) {
|
||||
|
|
|
|||
|
|
@ -8,30 +8,38 @@ import androidx.compose.foundation.layout.*
|
|||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import androidx.compose.ui.util.fastForEachIndexed
|
||||
import com.tangem.common.ui.account.AccountIconPreviewData
|
||||
import com.tangem.common.ui.account.AccountTitle
|
||||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.UnableToLoadData
|
||||
import com.tangem.core.ui.components.fields.SearchBar
|
||||
import com.tangem.core.ui.components.fields.TangemSearchBarDefaults
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.*
|
||||
import com.tangem.features.nft.impl.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.util.UUID
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
|
|
@ -89,41 +97,24 @@ internal fun NFTCollectionsContent(content: NFTCollectionsUM.Content, modifier:
|
|||
.padding(
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
bottom = bottomPadding,
|
||||
)
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
),
|
||||
// .clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
// .background(TangemTheme.colors.background.primary),
|
||||
state = listState,
|
||||
) {
|
||||
content.collections.fastForEach { collection ->
|
||||
item(key = collection.id) {
|
||||
NFTCollection(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
state = collection,
|
||||
content.collections.fastForEachIndexed { index, item ->
|
||||
val previousItem = content.collections.getOrNull(index.dec())
|
||||
val nextItem = content.collections.getOrNull(index.inc())
|
||||
when (item) {
|
||||
is NFTCollectionPortfolioUM -> nftPortfolioItem(
|
||||
item = item,
|
||||
shape = getRoundShape(item, previousItem, nextItem),
|
||||
)
|
||||
is NFTCollectionUM -> nftCollectionItem(
|
||||
collection = item,
|
||||
shape = getRoundShape(item, previousItem, nextItem),
|
||||
isNextItemNFTCollection = nextItem is NFTCollectionUM,
|
||||
)
|
||||
}
|
||||
when (val assets = collection.assets) {
|
||||
is NFTCollectionAssetsListUM.Init -> Unit
|
||||
is NFTCollectionAssetsListUM.Loading -> {
|
||||
assetsListLoading(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
expanded = collection.isExpanded,
|
||||
)
|
||||
}
|
||||
is NFTCollectionAssetsListUM.Failed -> {
|
||||
assetsListFailed(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
expanded = collection.isExpanded,
|
||||
)
|
||||
}
|
||||
is NFTCollectionAssetsListUM.Content -> {
|
||||
assetsListContent(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
expanded = collection.isExpanded,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,9 +130,94 @@ internal fun NFTCollectionsContent(content: NFTCollectionsUM.Content, modifier:
|
|||
}
|
||||
}
|
||||
|
||||
private fun getRoundShape(
|
||||
item: NFTCollectionItem,
|
||||
previousItem: NFTCollectionItem?,
|
||||
nextItem: NFTCollectionItem?,
|
||||
): RoundedCornerShape {
|
||||
val radius = 16.dp
|
||||
val topRound = RoundedCornerShape(topStart = radius, topEnd = radius)
|
||||
val bottomRound = RoundedCornerShape(bottomStart = radius, bottomEnd = radius)
|
||||
val allRound = RoundedCornerShape(size = radius)
|
||||
return when (item) {
|
||||
is NFTCollectionPortfolioUM -> topRound
|
||||
is NFTCollectionUM -> when {
|
||||
previousItem == null && nextItem == null -> allRound
|
||||
previousItem == null && nextItem is NFTCollectionUM -> topRound
|
||||
previousItem != null && nextItem !is NFTCollectionUM -> bottomRound
|
||||
else -> RoundedCornerShape(0.dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.nftPortfolioItem(item: NFTCollectionPortfolioUM, shape: RoundedCornerShape) {
|
||||
item(item.id) {
|
||||
AccountTitle(
|
||||
textColor = TangemTheme.colors.text.primary1,
|
||||
textStyle = TangemTheme.typography.caption1,
|
||||
accountTitleUM = item.title,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp)
|
||||
.clip(shape)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(start = 12.dp, end = 12.dp, top = 12.dp, bottom = 8.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.nftCollectionItem(
|
||||
collection: NFTCollectionUM,
|
||||
shape: RoundedCornerShape,
|
||||
isNextItemNFTCollection: Boolean,
|
||||
) {
|
||||
item(key = collection.id) {
|
||||
val itemShape = if (collection.isExpanded) {
|
||||
shape.copy(bottomEnd = CornerSize(0.dp), bottomStart = CornerSize(0.dp))
|
||||
} else {
|
||||
shape
|
||||
}
|
||||
NFTCollection(
|
||||
modifier = Modifier
|
||||
.clip(itemShape)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.fillMaxWidth(),
|
||||
state = collection,
|
||||
)
|
||||
}
|
||||
when (val assets = collection.assets) {
|
||||
is NFTCollectionAssetsListUM.Init -> Unit
|
||||
is NFTCollectionAssetsListUM.Loading -> {
|
||||
assetsListLoading(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
expanded = collection.isExpanded,
|
||||
isNextItemNFTCollection = isNextItemNFTCollection,
|
||||
)
|
||||
}
|
||||
is NFTCollectionAssetsListUM.Failed -> {
|
||||
assetsListFailed(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
expanded = collection.isExpanded,
|
||||
isNextItemNFTCollection = isNextItemNFTCollection,
|
||||
)
|
||||
}
|
||||
is NFTCollectionAssetsListUM.Content -> {
|
||||
assetsListContent(
|
||||
collectionId = collection.id,
|
||||
content = assets,
|
||||
expanded = collection.isExpanded,
|
||||
isNextItemNFTCollection = isNextItemNFTCollection,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.assetsListLoading(
|
||||
collectionId: String,
|
||||
content: NFTCollectionAssetsListUM.Loading,
|
||||
isNextItemNFTCollection: Boolean,
|
||||
expanded: Boolean,
|
||||
) {
|
||||
val itemsCount = content.itemsCount
|
||||
|
|
@ -164,6 +240,8 @@ private fun LazyListScope.assetsListLoading(
|
|||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(assetsShape(isNextItemNFTCollection))
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(TangemTheme.dimens.spacing6),
|
||||
) {
|
||||
NFTCollectionAssetLoading(
|
||||
|
|
@ -193,6 +271,7 @@ private fun LazyListScope.assetsListLoading(
|
|||
private fun LazyListScope.assetsListFailed(
|
||||
collectionId: String,
|
||||
content: NFTCollectionAssetsListUM.Failed,
|
||||
isNextItemNFTCollection: Boolean,
|
||||
expanded: Boolean,
|
||||
) {
|
||||
item(
|
||||
|
|
@ -206,6 +285,8 @@ private fun LazyListScope.assetsListFailed(
|
|||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(assetsShape(isNextItemNFTCollection))
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.height(TangemTheme.dimens.size142),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
|
|
@ -220,6 +301,7 @@ private fun LazyListScope.assetsListFailed(
|
|||
private fun LazyListScope.assetsListContent(
|
||||
collectionId: String,
|
||||
content: NFTCollectionAssetsListUM.Content,
|
||||
isNextItemNFTCollection: Boolean,
|
||||
expanded: Boolean,
|
||||
) {
|
||||
val items = content.items
|
||||
|
|
@ -244,6 +326,10 @@ private fun LazyListScope.assetsListContent(
|
|||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.conditional(rowIndex.inc() == rowCount) {
|
||||
clip(assetsShape(isNextItemNFTCollection))
|
||||
}
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.fillMaxWidth()
|
||||
.padding(TangemTheme.dimens.spacing6),
|
||||
) {
|
||||
|
|
@ -277,105 +363,150 @@ private fun LazyListScope.assetsListContent(
|
|||
}
|
||||
}
|
||||
|
||||
private fun assetsShape(isNextItemNFTCollection: Boolean): Shape = if (isNextItemNFTCollection) {
|
||||
RoundedCornerShape(0.dp)
|
||||
} else {
|
||||
RoundedCornerShape(bottomStart = 16.dp, bottomEnd = 16.dp)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_NFTCollectionsContent() {
|
||||
private fun Preview_NFTCollectionsContent(@PreviewParameter(PreviewProvider::class) state: NFTCollectionsUM.Content) {
|
||||
TangemThemePreview {
|
||||
NFTCollectionsContent(
|
||||
content = NFTCollectionsUM.Content(
|
||||
search = SearchBarUM(
|
||||
placeholderText = resourceReference(R.string.common_search),
|
||||
query = "",
|
||||
onQueryChange = {},
|
||||
isActive = false,
|
||||
onActiveChange = { },
|
||||
content = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class PreviewProvider : PreviewParameterProvider<NFTCollectionsUM.Content> {
|
||||
|
||||
val search
|
||||
get() = SearchBarUM(
|
||||
placeholderText = resourceReference(R.string.common_search),
|
||||
query = "",
|
||||
onQueryChange = {},
|
||||
isActive = false,
|
||||
onActiveChange = { },
|
||||
)
|
||||
|
||||
val warnings
|
||||
get() = persistentListOf(
|
||||
NFTCollectionsWarningUM(
|
||||
id = "loading troubles",
|
||||
config = NotificationConfig(
|
||||
title = TextReference.Res(R.string.nft_collections_warning_title),
|
||||
subtitle = TextReference.Res(R.string.nft_collections_warning_subtitle),
|
||||
iconResId = R.drawable.ic_alert_triangle_20,
|
||||
),
|
||||
collections = persistentListOf(
|
||||
NFTCollectionUM(
|
||||
),
|
||||
)
|
||||
|
||||
val collection
|
||||
get() = NFTCollectionUM(
|
||||
id = UUID.randomUUID().toString(),
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Content(persistentListOf()),
|
||||
isExpanded = false,
|
||||
onExpandClick = { },
|
||||
)
|
||||
|
||||
val collectionLoading
|
||||
get() = collection.copy(
|
||||
assets = NFTCollectionAssetsListUM.Loading(
|
||||
itemsCount = 1,
|
||||
),
|
||||
isExpanded = true,
|
||||
)
|
||||
|
||||
val collectionFailed
|
||||
get() = collection.copy(
|
||||
assets = NFTCollectionAssetsListUM.Failed(
|
||||
onRetryClick = { },
|
||||
),
|
||||
isExpanded = true,
|
||||
)
|
||||
|
||||
val collectionContent
|
||||
get() = collection.copy(
|
||||
assets = NFTCollectionAssetsListUM.Content(
|
||||
items = persistentListOf(
|
||||
NFTCollectionAssetUM(
|
||||
id = "item1",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Content(persistentListOf()),
|
||||
isExpanded = false,
|
||||
onExpandClick = { },
|
||||
name = "Nethers #0854",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Content(
|
||||
price = stringReference("0.05 ETH"),
|
||||
),
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionUM(
|
||||
NFTCollectionAssetUM(
|
||||
id = "item2",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Loading(
|
||||
itemsCount = 1,
|
||||
),
|
||||
isExpanded = true,
|
||||
onExpandClick = { },
|
||||
name = "Nethers #0855",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Loading,
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionUM(
|
||||
NFTCollectionAssetUM(
|
||||
id = "item3",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Failed(
|
||||
onRetryClick = { },
|
||||
),
|
||||
isExpanded = true,
|
||||
onExpandClick = { },
|
||||
),
|
||||
NFTCollectionUM(
|
||||
id = "item4",
|
||||
name = "Nethers",
|
||||
logoUrl = "",
|
||||
networkIconId = R.drawable.img_eth_22,
|
||||
description = TextReference.Str("3 items"),
|
||||
assets = NFTCollectionAssetsListUM.Content(
|
||||
items = persistentListOf(
|
||||
NFTCollectionAssetUM(
|
||||
id = "item1",
|
||||
name = "Nethers #0854",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Content(
|
||||
price = stringReference("0.05 ETH"),
|
||||
),
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionAssetUM(
|
||||
id = "item2",
|
||||
name = "Nethers #0855",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Loading,
|
||||
onItemClick = { },
|
||||
),
|
||||
NFTCollectionAssetUM(
|
||||
id = "item3",
|
||||
name = "Nethers #0856",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Failed,
|
||||
onItemClick = { },
|
||||
),
|
||||
),
|
||||
),
|
||||
isExpanded = true,
|
||||
onExpandClick = { },
|
||||
name = "Nethers #0856",
|
||||
imageUrl = "img",
|
||||
price = NFTSalePriceUM.Failed,
|
||||
onItemClick = { },
|
||||
),
|
||||
),
|
||||
warnings = persistentListOf(
|
||||
NFTCollectionsWarningUM(
|
||||
id = "loading troubles",
|
||||
config = NotificationConfig(
|
||||
title = TextReference.Res(R.string.nft_collections_warning_title),
|
||||
subtitle = TextReference.Res(R.string.nft_collections_warning_subtitle),
|
||||
iconResId = R.drawable.ic_alert_triangle_20,
|
||||
),
|
||||
),
|
||||
),
|
||||
isExpanded = true,
|
||||
)
|
||||
|
||||
val accountHeader
|
||||
get() = NFTCollectionPortfolioUM(
|
||||
title = AccountTitleUM.Account(
|
||||
icon = AccountIconPreviewData.randomAccountIcon(),
|
||||
name = stringReference("Main Account"),
|
||||
prefixText = TextReference.EMPTY,
|
||||
),
|
||||
id = UUID.randomUUID().toString(),
|
||||
)
|
||||
|
||||
override val values: Sequence<NFTCollectionsUM.Content>
|
||||
get() = sequenceOf(
|
||||
NFTCollectionsUM.Content(
|
||||
search = search,
|
||||
collections = persistentListOf(
|
||||
collection,
|
||||
collectionLoading,
|
||||
collectionFailed,
|
||||
collectionContent,
|
||||
),
|
||||
warnings = warnings,
|
||||
onReceiveClick = { },
|
||||
),
|
||||
NFTCollectionsUM.Content(
|
||||
search = search,
|
||||
collections = persistentListOf(
|
||||
accountHeader,
|
||||
collection,
|
||||
accountHeader,
|
||||
collectionContent,
|
||||
collection,
|
||||
),
|
||||
warnings = warnings,
|
||||
onReceiveClick = { },
|
||||
),
|
||||
NFTCollectionsUM.Content(
|
||||
search = search,
|
||||
collections = persistentListOf(
|
||||
collectionContent,
|
||||
collection,
|
||||
),
|
||||
warnings = warnings,
|
||||
onReceiveClick = { },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,12 @@ import androidx.activity.compose.BackHandler
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
|
|
@ -13,7 +18,13 @@ import com.arkivanov.decompose.value.subscribe
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.models.PortfolioId
|
||||
import com.tangem.features.account.PortfolioFetcher
|
||||
import com.tangem.features.account.PortfolioSelectorComponent
|
||||
import com.tangem.features.account.PortfolioSelectorController
|
||||
import com.tangem.features.nft.collections.NFTCollectionsComponent
|
||||
import com.tangem.features.nft.common.ui.NFTContent
|
||||
import com.tangem.features.nft.component.NFTComponent
|
||||
|
|
@ -23,20 +34,26 @@ import com.tangem.features.nft.entity.NFTSendSuccessListener
|
|||
import com.tangem.features.nft.receive.NFTReceiveComponent
|
||||
import com.tangem.features.nft.traits.NFTAssetTraitsComponent
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultNFTComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: NFTComponent.Params,
|
||||
private val nftDetailsInfoComponentFactory: NFTDetailsInfoComponent.Factory,
|
||||
nftSendSuccessListener: NFTSendSuccessListener,
|
||||
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
|
||||
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
|
||||
private val portfolioSelectorController: PortfolioSelectorController,
|
||||
portfolioFetcherFactory: PortfolioFetcher.Factory,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
) : NFTComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val stackNavigation = StackNavigation<NFTRoute>()
|
||||
|
|
@ -48,6 +65,26 @@ internal class DefaultNFTComponent @AssistedInject constructor(
|
|||
|
||||
private val initialRoute: NFTRoute = NFTRoute.Collections(params.userWalletId)
|
||||
private val currentRoute = MutableStateFlow(initialRoute)
|
||||
private val onReceiveClickJob = JobHolder()
|
||||
private val portfolioFetcher: PortfolioFetcher? = if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
portfolioFetcherFactory.create(
|
||||
mode = PortfolioFetcher.Mode.Wallet(params.userWalletId),
|
||||
scope = componentScope,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
private val bottomSheetNavigation: SlotNavigation<Unit> = SlotNavigation()
|
||||
private val portfolioSelectorCallback = object : PortfolioSelectorComponent.BottomSheetCallback {
|
||||
override val onDismiss: () -> Unit = { bottomSheetNavigation.dismiss() }
|
||||
override val onBack: () -> Unit = { bottomSheetNavigation.dismiss() }
|
||||
}
|
||||
private val bottomSheetSlot = childSlot(
|
||||
source = bottomSheetNavigation,
|
||||
serializer = Unit.serializer(),
|
||||
handleBackButton = false,
|
||||
childFactory = { configuration, context -> bottomSheetChild(context) },
|
||||
)
|
||||
|
||||
private val childStack = childStack(
|
||||
key = "sendInnerStack",
|
||||
|
|
@ -90,6 +127,8 @@ internal class DefaultNFTComponent @AssistedInject constructor(
|
|||
NFTContent(
|
||||
stackState = stackState,
|
||||
)
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
private fun createChild(route: NFTRoute, factoryContext: AppComponentContext) = when (route) {
|
||||
|
|
@ -108,11 +147,15 @@ internal class DefaultNFTComponent @AssistedInject constructor(
|
|||
userWalletId = route.userWalletId,
|
||||
onBackClick = ::onChildBack,
|
||||
onReceiveClick = {
|
||||
innerRouter.push(
|
||||
NFTRoute.Receive(
|
||||
userWalletId = route.userWalletId,
|
||||
),
|
||||
)
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
onReceiveClick(route)
|
||||
} else {
|
||||
innerRouter.push(
|
||||
NFTRoute.Receive(
|
||||
portfolioId = PortfolioId(route.userWalletId),
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
onAssetClick = { asset, collection ->
|
||||
innerRouter.push(
|
||||
|
|
@ -126,14 +169,31 @@ internal class DefaultNFTComponent @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
|
||||
private fun onReceiveClick(route: NFTRoute.Collections) = componentScope.launch {
|
||||
val portfolioFetcher = requireNotNull(portfolioFetcher)
|
||||
portfolioSelectorController.selectAccount(null)
|
||||
portfolioFetcher.updateMode(mode = PortfolioFetcher.Mode.Wallet(route.userWalletId))
|
||||
val portfolioData = portfolioFetcher.data.first()
|
||||
if (portfolioData.isSingleChoice) {
|
||||
val mainAccountId = portfolioData.balances.values.first()
|
||||
.accountsBalance.mainAccount.account.accountId
|
||||
innerRouter.push(NFTRoute.Receive(portfolioId = PortfolioId(mainAccountId)))
|
||||
} else {
|
||||
bottomSheetNavigation.activate(Unit)
|
||||
val selectedAccountId = portfolioSelectorController.selectedAccount
|
||||
.filterNotNull().first()
|
||||
bottomSheetNavigation.dismiss()
|
||||
innerRouter.push(NFTRoute.Receive(portfolioId = PortfolioId(selectedAccountId)))
|
||||
}
|
||||
}.saveIn(onReceiveClickJob)
|
||||
|
||||
private fun getReceiveComponent(
|
||||
factoryContext: AppComponentContext,
|
||||
route: NFTRoute.Receive,
|
||||
): ComposableContentComponent = NFTReceiveComponent(
|
||||
context = factoryContext,
|
||||
params = NFTReceiveComponent.Params(
|
||||
userWalletId = route.userWalletId,
|
||||
walletName = params.walletName,
|
||||
portfolioId = route.portfolioId,
|
||||
onBackClick = ::onChildBack,
|
||||
),
|
||||
tokenReceiveComponentFactory = tokenReceiveComponentFactory,
|
||||
|
|
@ -181,6 +241,16 @@ internal class DefaultNFTComponent @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun bottomSheetChild(componentContext: ComponentContext): ComposableBottomSheetComponent =
|
||||
portfolioSelectorComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = PortfolioSelectorComponent.Params(
|
||||
portfolioFetcher = portfolioFetcher!!,
|
||||
controller = portfolioSelectorController,
|
||||
bsCallback = portfolioSelectorCallback,
|
||||
),
|
||||
)
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : NFTComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: NFTComponent.Params): DefaultNFTComponent
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.nft.common
|
||||
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.domain.models.PortfolioId
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.nft.models.NFTCollection
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
|
@ -15,7 +16,7 @@ internal sealed class NFTRoute : Route {
|
|||
|
||||
@Serializable
|
||||
data class Receive(
|
||||
val userWalletId: UserWalletId,
|
||||
val portfolioId: PortfolioId,
|
||||
) : NFTRoute()
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.PortfolioId
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.features.nft.receive.model.NFTReceiveModel
|
||||
import com.tangem.features.nft.receive.ui.NFTReceive
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
|
|
@ -57,8 +57,7 @@ internal class NFTReceiveComponent @AssistedInject constructor(
|
|||
)
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val walletName: String,
|
||||
val portfolioId: PortfolioId,
|
||||
val onBackClick: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.nft.receive.model
|
|||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
|
|
@ -11,19 +12,28 @@ import com.tangem.core.navigation.share.ShareManager
|
|||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.components.fields.InputManager
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.account.producer.SingleAccountProducer
|
||||
import com.tangem.domain.account.supplier.SingleAccountSupplier
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.models.PortfolioId
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.models.network.NetworkStatus
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.nft.FilterNFTAvailableNetworksUseCase
|
||||
import com.tangem.domain.nft.GetNFTCurrencyUseCase
|
||||
import com.tangem.domain.nft.GetNFTNetworkStatusUseCase
|
||||
import com.tangem.domain.nft.GetNFTNetworksUseCase
|
||||
import com.tangem.domain.nft.analytics.NFTAnalyticsEvent
|
||||
import com.tangem.domain.transaction.usecase.ReceiveAddressesFactory
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.features.nft.impl.R
|
||||
import com.tangem.features.nft.receive.NFTReceiveComponent
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
|
|
@ -53,6 +63,9 @@ internal class NFTReceiveModel @Inject constructor(
|
|||
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
|
||||
private val getNFTCurrencyUseCase: GetNFTCurrencyUseCase,
|
||||
private val receiveAddressesFactory: ReceiveAddressesFactory,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val singleAccountSupplier: SingleAccountSupplier,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -63,10 +76,7 @@ internal class NFTReceiveModel @Inject constructor(
|
|||
private val _state = MutableStateFlow(
|
||||
value = NFTReceiveUM(
|
||||
onBackClick = params.onBackClick,
|
||||
appBarSubtitle = resourceReference(
|
||||
R.string.hot_crypto_add_token_subtitle,
|
||||
formatArgs = wrappedList(params.walletName),
|
||||
),
|
||||
appBarSubtitle = TextReference.EMPTY,
|
||||
search = getInitialSearchBar(),
|
||||
networks = NFTReceiveUM.Networks.Content(
|
||||
availableItems = persistentListOf(),
|
||||
|
|
@ -81,11 +91,44 @@ internal class NFTReceiveModel @Inject constructor(
|
|||
init {
|
||||
analyticsEventHandler.send(NFTAnalyticsEvent.Receive.ScreenOpened)
|
||||
subscribeToNFTAvailableNetworks()
|
||||
loadPortfolioName()
|
||||
}
|
||||
|
||||
private fun loadPortfolioName() = modelScope.launch(dispatchers.default) {
|
||||
val appBarSubtitle = when (val portfolioId = params.portfolioId) {
|
||||
is PortfolioId.Wallet -> loadWalletName(portfolioId.userWalletId)
|
||||
is PortfolioId.Account -> if (isAccountsModeEnabledUseCase.invokeSync()) {
|
||||
loadAccountName(portfolioId.accountId)
|
||||
} else {
|
||||
loadWalletName(portfolioId.userWalletId)
|
||||
}
|
||||
}
|
||||
_state.update { it.copy(appBarSubtitle = appBarSubtitle) }
|
||||
}
|
||||
|
||||
private fun loadWalletName(userWalletId: UserWalletId): TextReference {
|
||||
return getUserWalletUseCase(userWalletId)
|
||||
.map { it.name }
|
||||
.getOrNull()
|
||||
?.let { createAppBarSubtitle(stringReference(it)) }
|
||||
?: TextReference.EMPTY
|
||||
}
|
||||
|
||||
private suspend fun loadAccountName(accountId: AccountId): TextReference {
|
||||
return singleAccountSupplier
|
||||
.getSyncOrNull(SingleAccountProducer.Params(accountId))
|
||||
?.let { createAppBarSubtitle(it.accountName.toUM().value) }
|
||||
?: TextReference.EMPTY
|
||||
}
|
||||
|
||||
private fun createAppBarSubtitle(text: TextReference) = resourceReference(
|
||||
R.string.hot_crypto_add_token_subtitle,
|
||||
formatArgs = wrappedList(text),
|
||||
)
|
||||
|
||||
private fun subscribeToNFTAvailableNetworks() {
|
||||
combine(
|
||||
flow = getNFTNetworksUseCase(params.userWalletId),
|
||||
flow = getNFTNetworksUseCase(params.portfolioId),
|
||||
flow2 = searchManager.query.distinctUntilChanged(),
|
||||
) { networks, query ->
|
||||
filterNFTAvailableNetworksUseCase(networks, query)
|
||||
|
|
@ -98,6 +141,7 @@ internal class NFTReceiveModel @Inject constructor(
|
|||
).transform(it)
|
||||
}
|
||||
}
|
||||
.flowOn(dispatchers.default)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +188,7 @@ internal class NFTReceiveModel @Inject constructor(
|
|||
analyticsEventHandler.send(NFTAnalyticsEvent.Receive.BlockchainChosen(network.name))
|
||||
|
||||
val networkStatus = getNFTNetworkStatusUseCase.invoke(
|
||||
userWalletId = params.userWalletId,
|
||||
userWalletId = params.portfolioId.userWalletId,
|
||||
network = network,
|
||||
) ?: return@launch
|
||||
|
||||
|
|
@ -191,7 +235,7 @@ internal class NFTReceiveModel @Inject constructor(
|
|||
private suspend fun configureReceiveAddresses(addresses: NetworkAddress, network: Network): TokenReceiveConfig {
|
||||
val cryptoCurrency = getNFTCurrencyUseCase.invoke(network)
|
||||
return receiveAddressesFactory.createForNft(
|
||||
userWalletId = params.userWalletId,
|
||||
userWalletId = params.portfolioId.userWalletId,
|
||||
addresses = addresses,
|
||||
network = network,
|
||||
nft = cryptoCurrency,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ internal class ExpandedAccountsHolder @Inject constructor(
|
|||
fun expandedAccounts(userWallet: UserWallet): Flow<Set<AccountId>> = channelFlow {
|
||||
walletAccounts(userWallet)
|
||||
.onEach { accountList ->
|
||||
val isSingleAccount = accountList.totalAccounts == 1
|
||||
val isSingleAccount = accountList.accounts.size == 1
|
||||
val defaultExpanded = when {
|
||||
isSingleAccount -> setOf(accountList.mainAccount.accountId)
|
||||
else -> setOf()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue