Updated on 2026-08-14

This commit is contained in:
Tangem 2023-08-01 15:25:12 +08:00
parent 3ff771e48b
commit 160153bfa3
28 changed files with 913 additions and 368 deletions

View file

@ -31,6 +31,7 @@ dependencies {
implementation(project(":domain:wallets:models"))
implementation(projects.domain.settings)
implementation(projects.domain.tokens)
implementation(projects.domain.txhistory)
implementation(project(":common"))
implementation(project(":core:analytics"))
@ -43,11 +44,13 @@ dependencies {
implementation(project(":core:utils"))
implementation(project(":libs:crypto"))
implementation(project(":libs:auth"))
implementation(project(":data:source:preferences"))
implementation(projects.data.card)
implementation(projects.data.common)
implementation(projects.data.settings)
implementation(projects.data.tokens)
implementation(projects.data.common)
implementation(projects.data.txhistory)
/** Features */
implementation(project(":features:onboarding"))

View file

@ -0,0 +1,28 @@
package com.tangem.tap.di.domain
import com.tangem.domain.tokens.*
import com.tangem.domain.txhistory.repository.TxHistoryRepository
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.android.scopes.ViewModelScoped
@Module
@InstallIn(ViewModelComponent::class)
internal object TxHistoryDomainModule {
@Provides
@ViewModelScoped
fun provideGetTxHistoryItemsCountUseCase(txHistoryRepository: TxHistoryRepository): GetTxHistoryItemsCountUseCase {
return GetTxHistoryItemsCountUseCase(repository = txHistoryRepository)
}
@Provides
@ViewModelScoped
fun provideGetTxHistoryItemsUseCase(txHistoryRepository: TxHistoryRepository): GetTxHistoryItemsUseCase {
return GetTxHistoryItemsUseCase(repository = txHistoryRepository)
}
}

View file

@ -12,12 +12,12 @@ class GetTxHistoryItemsCountUseCase(private val repository: TxHistoryRepository)
return either {
catch(
block = { repository.getTxHistoryItemsCount(networkId, derivationPath) },
catch = { e ->
catch = { throwable ->
raise(
when (e) {
is TxHistoryStateError.TxHistoryNotImplemented -> e
is TxHistoryStateError.EmptyTxHistories -> e
else -> TxHistoryStateError.DataError(e)
when (throwable) {
is TxHistoryStateError.TxHistoryNotImplemented -> throwable
is TxHistoryStateError.EmptyTxHistories -> throwable
else -> TxHistoryStateError.DataError(throwable)
},
)
},

View file

@ -2,17 +2,12 @@ package com.tangem.domain.txhistory.usecase
import androidx.paging.PagingData
import arrow.core.Either
import arrow.core.left
import arrow.core.raise.Raise
import arrow.core.raise.recover
import arrow.core.right
import arrow.core.raise.either
import com.tangem.domain.txhistory.error.TxHistoryListError
import com.tangem.domain.txhistory.model.TxHistoryItem
import com.tangem.domain.txhistory.repository.TxHistoryRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collect
private const val DEFAULT_PAGE_SIZE = 20
@ -21,29 +16,11 @@ class GetTxHistoryItemsUseCase(private val repository: TxHistoryRepository) {
operator fun invoke(
networkId: String,
pageSize: Int = DEFAULT_PAGE_SIZE,
): Flow<Either<TxHistoryListError,
PagingData<TxHistoryItem>,>,> {
return channelFlow {
recover(
block = {
getTxHistoryItems(
networkId = networkId,
pageSize = pageSize,
).collect { items ->
send(items.right())
}
},
recover = { error -> send(error.left()) },
)
): Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>> {
return either {
repository
.getTxHistoryItems(networkId = networkId, pageSize = pageSize)
.catch { raise(TxHistoryListError.DataError(it)) }
}
}
private fun Raise<TxHistoryListError>.getTxHistoryItems(
networkId: String,
pageSize: Int,
): Flow<PagingData<TxHistoryItem>> {
return repository
.getTxHistoryItems(networkId = networkId, pageSize = pageSize)
.catch { raise(TxHistoryListError.DataError(it)) }
}
}

View file

@ -12,18 +12,19 @@ dependencies {
implementation(deps.material)
/** Compose */
implementation(deps.compose.accompanist.systemUiController)
implementation(deps.compose.coil)
implementation(deps.compose.constraintLayout)
implementation(deps.compose.material)
implementation(deps.compose.foundation)
implementation(deps.compose.material)
implementation(deps.compose.material3)
implementation(deps.compose.navigation)
implementation(deps.compose.navigation.hilt)
implementation(deps.compose.paging)
implementation(deps.compose.reorderable)
implementation(deps.compose.shimmer)
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.compose.shimmer)
implementation(deps.compose.accompanist.systemUiController)
implementation(deps.compose.reorderable)
/** Other libraries */
implementation(deps.arrow.core)
@ -50,6 +51,7 @@ dependencies {
implementation(projects.domain.models)
implementation(projects.domain.settings)
implementation(projects.domain.tokens)
implementation(projects.domain.txhistory)
implementation(projects.domain.wallets)
implementation(projects.domain.wallets.models)

View file

@ -1,5 +1,6 @@
package com.tangem.feature.wallet.presentation.common
import androidx.paging.PagingData
import com.tangem.core.ui.R
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.marketprice.PriceChangeConfig
@ -11,8 +12,11 @@ import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensListState
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.*
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.flowOf
import java.util.UUID
internal object WalletPreviewData {
@ -221,54 +225,57 @@ internal object WalletPreviewData {
onBackClick = {},
topBarConfig = walletTopBarConfig,
walletsListConfig = walletListConfig,
contentItems = persistentListOf(
WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle("Bitcoin"),
WalletContentItemState.MultiCurrencyItem.Token(
tokenItemVisibleState.copy(
id = "token_1",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
WalletContentItemState.MultiCurrencyItem.Token(
tokenItemVisibleState.copy(
id = "token_2",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
WalletContentItemState.MultiCurrencyItem.Token(
tokenItemVisibleState.copy(
id = "token_3",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
WalletContentItemState.MultiCurrencyItem.Token(
tokenItemVisibleState.copy(
id = "token_4",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle("Ethereum"),
WalletContentItemState.MultiCurrencyItem.Token(
tokenItemVisibleState.copy(
id = "token_5",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
tokensListState = WalletTokensListState.Content(
persistentListOf(
WalletTokensListState.TokensListItemState.NetworkGroupTitle("Bitcoin"),
WalletTokensListState.TokensListItemState.Token(
tokenItemVisibleState.copy(
id = "token_1",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
WalletTokensListState.TokensListItemState.Token(
tokenItemVisibleState.copy(
id = "token_2",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
WalletTokensListState.TokensListItemState.Token(
tokenItemVisibleState.copy(
id = "token_3",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
WalletTokensListState.TokensListItemState.Token(
tokenItemVisibleState.copy(
id = "token_4",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
WalletTokensListState.TokensListItemState.NetworkGroupTitle("Ethereum"),
WalletTokensListState.TokensListItemState.Token(
tokenItemVisibleState.copy(
id = "token_5",
name = "Ethereum",
tokenIconResId = R.drawable.img_eth_22,
networkIconResId = null,
amount = "1,89340821 ETH",
),
),
),
onOrganizeTokensClick = {},
),
pullToRefreshConfig = WalletPullToRefreshConfig(
isRefreshing = false,
@ -281,32 +288,12 @@ internal object WalletPreviewData {
WalletNotification.ScanCard(onClick = {}),
),
bottomSheet = bottomSheet,
onOrganizeTokensClick = {},
)
val singleWalletScreenState = WalletStateHolder.SingleCurrencyContent(
onBackClick = {},
topBarConfig = walletTopBarConfig,
walletsListConfig = walletListConfig,
contentItems = persistentListOf(
WalletContentItemState.SingleCurrencyItem.Title(onExploreClick = {}),
WalletContentItemState.SingleCurrencyItem.GroupTitle("Today"),
WalletContentItemState.SingleCurrencyItem.Transaction(
TransactionState.Sending(
address = "33BddS...ga2B",
amount = "-0.500913 BTC",
timestamp = "8:41",
),
),
WalletContentItemState.SingleCurrencyItem.GroupTitle("Yesterday"),
WalletContentItemState.SingleCurrencyItem.Transaction(
TransactionState.Sending(
address = "33BddS...ga2B",
amount = "-0.500913 BTC",
timestamp = "8:41",
),
),
),
pullToRefreshConfig = WalletPullToRefreshConfig(
isRefreshing = false,
onRefresh = {},
@ -322,5 +309,30 @@ internal object WalletPreviewData {
type = PriceChangeConfig.Type.UP,
),
),
txHistoryState = WalletTxHistoryState.Content(
flowOf(
PagingData.from(
listOf(
WalletTxHistoryState.TxHistoryItemState.Title(onExploreClick = {}),
WalletTxHistoryState.TxHistoryItemState.GroupTitle("Today"),
WalletTxHistoryState.TxHistoryItemState.Transaction(
TransactionState.Sending(
address = "33BddS...ga2B",
amount = "-0.500913 BTC",
timestamp = "8:41",
),
),
WalletTxHistoryState.TxHistoryItemState.GroupTitle("Yesterday"),
WalletTxHistoryState.TxHistoryItemState.Transaction(
TransactionState.Sending(
address = "33BddS...ga2B",
amount = "-0.500913 BTC",
timestamp = "8:41",
),
),
),
),
),
),
)
}

View file

@ -1,57 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.state
import com.tangem.core.ui.components.transactions.TransactionState
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
/**
* Wallet screen content item state
*
[REDACTED_AUTHOR]
*/
internal sealed interface WalletContentItemState {
/** Multi currency wallet content state */
sealed interface MultiCurrencyItem : WalletContentItemState {
/**
* Network group title item
*
* @property networkName network name
*/
data class NetworkGroupTitle(val networkName: String) : MultiCurrencyItem
/**
* Token item
*
* @property state token item state
*/
data class Token(val state: TokenItemState) : MultiCurrencyItem
}
/** Single currency wallet content state */
sealed interface SingleCurrencyItem : WalletContentItemState {
/**
* Title item
*
* @property onExploreClick lambda be invoke when explore button was clicked
*/
data class Title(val onExploreClick: () -> Unit) : SingleCurrencyItem
/**
* Group title item
*
* @property title title
*/
data class GroupTitle(val title: String) : SingleCurrencyItem
/**
* Transaction item
*
* @property state transaction state
*/
data class Transaction(val state: TransactionState) : SingleCurrencyItem
}
object Loading : WalletContentItemState
}

View file

@ -3,6 +3,9 @@ package com.tangem.feature.wallet.presentation.wallet.state
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletLockedContentState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@ -13,7 +16,6 @@ import kotlinx.collections.immutable.persistentListOf
* @property topBarConfig top bar config
* @property walletsListConfig wallets list config
* @property pullToRefreshConfig pull to refresh config
* @property contentItems content items
* @property notifications notifications
*
[REDACTED_AUTHOR]
@ -23,7 +25,6 @@ internal sealed class WalletStateHolder(
open val topBarConfig: WalletTopBarConfig,
open val walletsListConfig: WalletsListConfig,
open val pullToRefreshConfig: WalletPullToRefreshConfig,
open val contentItems: ImmutableList<WalletContentItemState>,
open val notifications: ImmutableList<WalletNotification>,
open val bottomSheet: WalletBottomSheetConfig? = null,
) {
@ -33,7 +34,6 @@ internal sealed class WalletStateHolder(
topBarConfig: WalletTopBarConfig = this.topBarConfig,
walletsListConfig: WalletsListConfig = this.walletsListConfig,
pullToRefreshConfig: WalletPullToRefreshConfig = this.pullToRefreshConfig,
contentItems: ImmutableList<WalletContentItemState> = this.contentItems,
notifications: ImmutableList<WalletNotification> = this.notifications,
bottomSheet: WalletBottomSheetConfig? = this.bottomSheet,
): WalletStateHolder {
@ -43,7 +43,6 @@ internal sealed class WalletStateHolder(
topBarConfig = topBarConfig,
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
contentItems = contentItems as ImmutableList<WalletContentItemState.MultiCurrencyItem>,
notifications = notifications,
bottomSheet = bottomSheet,
)
@ -52,7 +51,6 @@ internal sealed class WalletStateHolder(
topBarConfig = topBarConfig,
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
contentItems = contentItems as ImmutableList<WalletContentItemState.SingleCurrencyItem>,
notifications = notifications,
bottomSheet = bottomSheet,
)
@ -73,27 +71,24 @@ internal sealed class WalletStateHolder(
* @property topBarConfig top bar config
* @property walletsListConfig wallets list config
* @property pullToRefreshConfig pull to refresh config
* @property contentItems content items
* @property tokensListState token list state
* @property notifications notifications
* @property onOrganizeTokensClick lambda be invoked when organize tokens button is clicked
*/
data class MultiCurrencyContent(
override val onBackClick: () -> Unit,
override val topBarConfig: WalletTopBarConfig,
override val walletsListConfig: WalletsListConfig,
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val contentItems: ImmutableList<WalletContentItemState.MultiCurrencyItem>,
override val notifications: ImmutableList<WalletNotification>,
override val bottomSheet: WalletBottomSheetConfig? = null,
val onOrganizeTokensClick: () -> Unit,
val tokensListState: WalletTokensListState,
) : WalletStateHolder(
onBackClick = onBackClick,
topBarConfig = topBarConfig,
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
contentItems = contentItems,
bottomSheet = bottomSheet,
notifications = notifications,
bottomSheet = bottomSheet,
)
/**
@ -103,27 +98,26 @@ internal sealed class WalletStateHolder(
* @property topBarConfig top bar config
* @property walletsListConfig wallets list config
* @property pullToRefreshConfig pull to refresh config
* @property contentItems content items
* @property notifications notifications
* @property buttons manage buttons
* @property marketPriceBlockState market price block state
* @property txHistoryState transactions history state
*/
data class SingleCurrencyContent(
override val onBackClick: () -> Unit,
override val topBarConfig: WalletTopBarConfig,
override val walletsListConfig: WalletsListConfig,
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val contentItems: ImmutableList<WalletContentItemState.SingleCurrencyItem>,
override val notifications: ImmutableList<WalletNotification>,
override val bottomSheet: WalletBottomSheetConfig? = null,
val buttons: ImmutableList<ActionButtonConfig>,
val marketPriceBlockState: MarketPriceBlockState,
val txHistoryState: WalletTxHistoryState,
) : WalletStateHolder(
onBackClick = onBackClick,
topBarConfig = topBarConfig,
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
contentItems = contentItems,
notifications = notifications,
bottomSheet = bottomSheet,
)
@ -134,6 +128,8 @@ internal sealed class WalletStateHolder(
* @property onBackClick lambda be invoked when back button is clicked
* @property topBarConfig top bar config
* @property walletsListConfig wallets list config
* @property pullToRefreshConfig pull to refresh config
* @property lockedContentState locked content state
* @property onUnlockWalletsNotificationClick lambda be invoked when unlock wallets notification is clicked
* @property onBottomSheetDismissRequest lambda be invoked when bottom sheet is dismissed
* @property onUnlockClick lambda be invoked when unlock button is clicked
@ -144,6 +140,7 @@ internal sealed class WalletStateHolder(
override val topBarConfig: WalletTopBarConfig,
override val walletsListConfig: WalletsListConfig,
override val pullToRefreshConfig: WalletPullToRefreshConfig,
val lockedContentState: WalletLockedContentState,
val onUnlockWalletsNotificationClick: () -> Unit,
val onBottomSheetDismissRequest: () -> Unit,
val onUnlockClick: () -> Unit,
@ -153,7 +150,6 @@ internal sealed class WalletStateHolder(
topBarConfig = topBarConfig,
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
contentItems = persistentListOf(WalletContentItemState.Loading),
notifications = persistentListOf(WalletNotification.UnlockWallets(onUnlockWalletsNotificationClick)),
bottomSheet = WalletBottomSheetConfig(
isShow = false,
@ -186,7 +182,6 @@ internal sealed class WalletStateHolder(
onWalletChange = {},
),
pullToRefreshConfig = WalletPullToRefreshConfig(isRefreshing = false, onRefresh = {}),
contentItems = persistentListOf(WalletContentItemState.Loading),
notifications = persistentListOf(),
bottomSheet = null,
)

View file

@ -0,0 +1,9 @@
package com.tangem.feature.wallet.presentation.wallet.state.content
/**
* Wallet locked content state.
* It allows to divide the locked content of multi-currency and single-currency wallets.
*
[REDACTED_AUTHOR]
*/
internal sealed interface WalletLockedContentState

View file

@ -0,0 +1,60 @@
package com.tangem.feature.wallet.presentation.wallet.state.content
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
/**
* Wallet tokens list state
*
* @property items content items
* @property onOrganizeTokensClick lambda be invoked when organize tokens button is clicked
*
[REDACTED_AUTHOR]
*/
// TODO: Finalize strings [REDACTED_JIRA]
internal sealed class WalletTokensListState(
open val items: ImmutableList<TokensListItemState>,
open val onOrganizeTokensClick: (() -> Unit)?,
) {
/**
* Content state
*
* @property items content items
* @property onOrganizeTokensClick lambda be invoked when organize tokens button is clicked
*/
data class Content(
override val items: ImmutableList<TokensListItemState>,
override val onOrganizeTokensClick: (() -> Unit)?,
) : WalletTokensListState(items, onOrganizeTokensClick)
/** Locked content state */
object Locked :
WalletTokensListState(
items = persistentListOf(
TokensListItemState.NetworkGroupTitle(networkName = "Tokens"),
TokensListItemState.Token(state = TokenItemState.Loading),
),
onOrganizeTokensClick = null,
),
WalletLockedContentState
/** Tokens list item state */
sealed interface TokensListItemState {
/**
* Network group title item
*
* @property networkName network name
*/
data class NetworkGroupTitle(val networkName: String) : TokensListItemState
/**
* Token item
*
* @property state token item state
*/
data class Token(val state: TokenItemState) : TokensListItemState
}
}

View file

@ -0,0 +1,92 @@
package com.tangem.feature.wallet.presentation.wallet.state.content
import androidx.paging.PagingData
import com.tangem.core.ui.components.transactions.TransactionState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
/**
* Wallet transaction history state
*
[REDACTED_AUTHOR]
*/
internal sealed interface WalletTxHistoryState {
/**
* Wallet transaction history state with content
*
* @property items content items
*/
sealed class ContentItemsState(open val items: Flow<PagingData<TxHistoryItemState>>) : WalletTxHistoryState
/**
* Content state
*
* @property items content items
*/
data class Content(override val items: Flow<PagingData<TxHistoryItemState>>) : ContentItemsState(items)
/**
* Empty state
*
* @property onBuyClick lambda be invoke when buy button was clicked
*/
data class Empty(val onBuyClick: () -> Unit) : WalletTxHistoryState
/**
* Not supported tx history state
*
* @property onExploreClick lambda be invoke when explore button was clicked
*/
data class NotSupported(val onExploreClick: () -> Unit) : WalletTxHistoryState
/**
* Error state
*
* @property onReloadClick lambda be invoke when reload button was clicked
*/
data class Error(val onReloadClick: () -> Unit) : WalletTxHistoryState
/**
* Locked state
*
* @property onExploreClick lambda be invoke when explore button was clicked
*/
data class Locked(val onExploreClick: () -> Unit) :
ContentItemsState(
items = flowOf(
PagingData.from(
listOf(
TxHistoryItemState.Title(onExploreClick = onExploreClick),
TxHistoryItemState.Transaction(state = TransactionState.Loading),
),
),
),
),
WalletLockedContentState
/** Transactions history item state */
sealed interface TxHistoryItemState {
/**
* Title item
*
* @property onExploreClick lambda be invoke when explore button was clicked
*/
data class Title(val onExploreClick: () -> Unit) : TxHistoryItemState
/**
* Group title item
*
* @property title title
*/
data class GroupTitle(val title: String) : TxHistoryItemState
/**
* Transaction item
*
* @property state transaction state
*/
data class Transaction(val state: TransactionState) : TxHistoryItemState
}
}

View file

@ -8,6 +8,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletLoadedTokensListConverter.LoadedTokensListModel
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListErrorToWalletStateConverter
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.utils.converter.Converter
/**
@ -19,17 +20,19 @@ import com.tangem.utils.converter.Converter
*/
internal class WalletLoadedTokensListConverter(
private val currentStateProvider: Provider<WalletStateHolder>,
clickCallbacks: WalletClickCallbacks,
) : Converter<LoadedTokensListModel, WalletStateHolder> {
private val tokenListStateConverter = TokenListToWalletStateConverter(
currentState = currentStateProvider(),
currentStateProvider = currentStateProvider,
isWalletContentHidden = false, // TODO: [REDACTED_JIRA]
fiatCurrencyCode = "USD", // TODO: [REDACTED_JIRA]
fiatCurrencySymbol = "$", // TODO: [REDACTED_JIRA]
clickCallbacks = clickCallbacks,
)
private val tokenListErrorStateConverter = TokenListErrorToWalletStateConverter(
currentState = currentStateProvider(),
currentStateProvider = currentStateProvider,
)
override fun convert(value: LoadedTokensListModel): WalletStateHolder {

View file

@ -0,0 +1,130 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import androidx.paging.PagingData
import androidx.paging.map
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.transactions.TransactionState
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.txhistory.error.TxHistoryListError
import com.tangem.domain.txhistory.model.TxHistoryItem
import com.tangem.feature.wallet.presentation.wallet.state.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState.TxHistoryItemState
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/**
* Converter from loaded tx history to [WalletTxHistoryState]
*
* @property currentStateProvider current state provider
* @property currentCardTypeResolverProvider current card type resolver provider
*
[REDACTED_AUTHOR]
*/
internal class WalletLoadedTxHistoryConverter(
private val currentStateProvider: Provider<WalletStateHolder>,
private val currentCardTypeResolverProvider: Provider<CardTypesResolver>,
) : Converter<Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>, WalletStateHolder> {
override fun convert(value: Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>): WalletStateHolder {
return value.fold(ifLeft = { convertError() }, ifRight = ::convert)
}
private fun convertError(): WalletStateHolder {
val state = currentStateProvider()
return WalletStateHolder.SingleCurrencyContent(
onBackClick = state.onBackClick,
topBarConfig = state.topBarConfig,
walletsListConfig = state.walletsListConfig,
pullToRefreshConfig = state.pullToRefreshConfig,
notifications = state.notifications,
bottomSheet = state.bottomSheet,
buttons = persistentListOf(
WalletManageButton.Buy(onClick = {}),
WalletManageButton.Send(onClick = {}),
WalletManageButton.Receive(onClick = {}),
WalletManageButton.Exchange(onClick = {}),
WalletManageButton.CopyAddress(onClick = {}),
)
.map(WalletManageButton::config)
.toImmutableList(),
marketPriceBlockState = MarketPriceBlockState.Loading(
currencyName = currentCardTypeResolverProvider().getBlockchain().currency,
),
// TODO: [REDACTED_JIRA]
txHistoryState = WalletTxHistoryState.Error(onReloadClick = {}),
)
}
private fun convert(items: Flow<PagingData<TxHistoryItem>>): WalletStateHolder {
val state = currentStateProvider()
return WalletStateHolder.SingleCurrencyContent(
onBackClick = state.onBackClick,
topBarConfig = state.topBarConfig,
walletsListConfig = state.walletsListConfig,
pullToRefreshConfig = state.pullToRefreshConfig,
notifications = state.notifications,
bottomSheet = state.bottomSheet,
buttons = persistentListOf(
WalletManageButton.Buy(onClick = {}),
WalletManageButton.Send(onClick = {}),
WalletManageButton.Receive(onClick = {}),
WalletManageButton.Exchange(onClick = {}),
WalletManageButton.CopyAddress(onClick = {}),
)
.map(WalletManageButton::config)
.toImmutableList(),
marketPriceBlockState = MarketPriceBlockState.Loading(
currencyName = currentCardTypeResolverProvider().getBlockchain().currency,
),
txHistoryState = createContentTxHistory(items),
)
}
private fun createContentTxHistory(items: Flow<PagingData<TxHistoryItem>>): WalletTxHistoryState {
return WalletTxHistoryState.Content(
items = items.map { pagingData ->
pagingData.map { item ->
TxHistoryItemState.Transaction(
state = when (val direction = item.direction) {
is TxHistoryItem.TransactionDirection.Incoming -> {
when (item.status) {
TxHistoryItem.TxStatus.Confirmed -> TransactionState.Receive(
address = direction.from,
amount = item.amount.toPlainString(),
timestamp = item.timestamp.toString(),
)
TxHistoryItem.TxStatus.Unconfirmed -> TransactionState.Receiving(
address = direction.from,
amount = item.amount.toPlainString(),
timestamp = item.timestamp.toString(),
)
}
}
is TxHistoryItem.TransactionDirection.Outgoing -> {
when (item.status) {
TxHistoryItem.TxStatus.Confirmed -> TransactionState.Send(
address = direction.to,
amount = item.amount.toPlainString(),
timestamp = item.timestamp.toString(),
)
TxHistoryItem.TxStatus.Unconfirmed -> TransactionState.Sending(
address = direction.to,
amount = item.amount.toPlainString(),
timestamp = item.timestamp.toString(),
)
}
}
},
)
}
},
)
}
}

View file

@ -0,0 +1,103 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import androidx.paging.PagingData
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.transactions.TransactionState
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.txhistory.error.TxHistoryStateError
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.wallet.state.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.flowOf
/**
* Converter from loading tx history to [WalletTxHistoryState]
*
* @property currentStateProvider current state provider
* @property currentCardTypeResolverProvider current card type resolver provider
*
[REDACTED_AUTHOR]
*/
internal class WalletLoadingTxHistoryConverter(
private val currentStateProvider: Provider<WalletStateHolder>,
private val currentCardTypeResolverProvider: Provider<CardTypesResolver>,
) : Converter<Either<TxHistoryStateError, Int>, WalletStateHolder> {
override fun convert(value: Either<TxHistoryStateError, Int>): WalletStateHolder {
return value.fold(ifLeft = ::convertError, ifRight = ::convert)
}
private fun convert(value: Int): WalletStateHolder {
val state = currentStateProvider()
return WalletStateHolder.SingleCurrencyContent(
onBackClick = state.onBackClick,
topBarConfig = state.topBarConfig,
walletsListConfig = state.walletsListConfig,
pullToRefreshConfig = state.pullToRefreshConfig,
notifications = state.notifications,
bottomSheet = state.bottomSheet,
buttons = persistentListOf(
WalletManageButton.Buy(onClick = {}),
WalletManageButton.Send(onClick = {}),
WalletManageButton.Receive(onClick = {}),
WalletManageButton.Exchange(onClick = {}),
WalletManageButton.CopyAddress(onClick = {}),
)
.map(WalletManageButton::config)
.toImmutableList(),
marketPriceBlockState = MarketPriceBlockState.Loading(
currencyName = currentCardTypeResolverProvider().getBlockchain().currency,
),
txHistoryState = createLoadingTxHistory(itemCount = value),
)
}
private fun createLoadingTxHistory(itemCount: Int): WalletTxHistoryState {
return WalletTxHistoryState.Content(
items = flowOf(
value = PagingData.from(
data = buildList(
capacity = itemCount,
builderAction = {
add(
element = WalletTxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Loading,
),
)
},
),
),
),
)
}
private fun convertError(error: TxHistoryStateError): WalletStateHolder {
val state = currentStateProvider()
return WalletStateHolder.SingleCurrencyContent(
onBackClick = state.onBackClick,
topBarConfig = state.topBarConfig,
walletsListConfig = state.walletsListConfig,
pullToRefreshConfig = state.pullToRefreshConfig,
notifications = state.notifications,
bottomSheet = state.bottomSheet,
buttons = WalletPreviewData.singleWalletScreenState.buttons,
marketPriceBlockState = MarketPriceBlockState.Loading(
currencyName = currentCardTypeResolverProvider().getBlockchain().currency,
),
// TODO: [REDACTED_JIRA]
txHistoryState = when (error) {
is TxHistoryStateError.EmptyTxHistories -> WalletTxHistoryState.Empty(onBuyClick = {})
is TxHistoryStateError.DataError -> WalletTxHistoryState.Error(onReloadClick = {})
is TxHistoryStateError.TxHistoryNotImplemented -> WalletTxHistoryState.NotSupported(onExploreClick = {})
},
)
}
}

View file

@ -1,17 +1,20 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import androidx.paging.PagingData
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.*
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.flow
/**
* Converter from loaded list of [UserWallet] to skeleton state of screen [WalletStateHolder]
@ -40,10 +43,12 @@ internal class WalletSkeletonStateConverter(
topBarConfig = createTopBarConfig(),
walletsListConfig = createWalletsListConfig(wallets),
pullToRefreshConfig = createPullToRefreshConfig(),
contentItems = persistentListOf(),
tokensListState = WalletTokensListState.Content(
items = persistentListOf(),
onOrganizeTokensClick = clickCallbacks::onOrganizeTokensClick,
),
notifications = persistentListOf(),
bottomSheet = null,
onOrganizeTokensClick = clickCallbacks::onOrganizeTokensClick,
)
}
@ -56,13 +61,15 @@ internal class WalletSkeletonStateConverter(
topBarConfig = createTopBarConfig(),
walletsListConfig = createWalletsListConfig(wallets),
pullToRefreshConfig = createPullToRefreshConfig(),
contentItems = persistentListOf(),
notifications = persistentListOf(),
bottomSheet = null,
buttons = WalletPreviewData.singleWalletScreenState.buttons, // TODO: create buttons
marketPriceBlockState = MarketPriceBlockState.Loading(
currencyName = cardTypeResolver.getBlockchain().currency,
),
txHistoryState = WalletTxHistoryState.Content(
items = flow { PagingData.empty<WalletTxHistoryState.TxHistoryItemState>() },
),
)
}
@ -78,12 +85,7 @@ internal class WalletSkeletonStateConverter(
selectedWalletIndex = 0,
wallets = wallets.map { wallet ->
WalletCardState.Loading(
// TODO remove after adding release logic for GetTokenListUseCase
id = if (wallet.scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
UserWalletId("123")
} else {
UserWalletId("321")
},
id = wallet.walletId,
title = wallet.name,
additionalInfo = "", // TODO add additional info resolver
imageResId = WalletImageResolver.resolve(cardTypesResolver = wallet.scanResponse.cardTypesResolver),

View file

@ -1,9 +1,14 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import androidx.paging.PagingData
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.txhistory.error.TxHistoryListError
import com.tangem.domain.txhistory.error.TxHistoryStateError
import com.tangem.domain.txhistory.model.TxHistoryItem
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.WalletBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.WalletNotification
@ -11,6 +16,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletLoadedTokensListConverter.LoadedTokensListModel
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.Flow
/**
* Main factory for creating [WalletStateHolder]
@ -20,11 +26,32 @@ import kotlinx.collections.immutable.ImmutableList
*/
internal class WalletStateFactory(
private val currentStateProvider: Provider<WalletStateHolder>,
currentCardTypeResolverProvider: Provider<CardTypesResolver>,
private val clickCallbacks: WalletClickCallbacks,
) {
private val skeletonConverter = WalletSkeletonStateConverter(clickCallbacks = clickCallbacks)
private val loadedTokensListConverter = WalletLoadedTokensListConverter(currentStateProvider = currentStateProvider)
private val skeletonConverter by lazy { WalletSkeletonStateConverter(clickCallbacks = clickCallbacks) }
private val loadedTokensListConverter by lazy {
WalletLoadedTokensListConverter(
currentStateProvider = currentStateProvider,
clickCallbacks = clickCallbacks,
)
}
private val loadingTransactionsStateConverter by lazy {
WalletLoadingTxHistoryConverter(
currentStateProvider = currentStateProvider,
currentCardTypeResolverProvider = currentCardTypeResolverProvider,
)
}
private val loadedTxHistoryConverter by lazy {
WalletLoadedTxHistoryConverter(
currentStateProvider = currentStateProvider,
currentCardTypeResolverProvider = currentCardTypeResolverProvider,
)
}
fun getInitialState(): WalletStateHolder = WalletStateHolder.Loading(onBackClick = clickCallbacks::onBackClick)
@ -66,4 +93,14 @@ internal class WalletStateFactory(
)
}
}
fun getLoadingTxHistoryState(itemsCountEither: Either<TxHistoryStateError, Int>): WalletStateHolder {
return loadingTransactionsStateConverter.convert(value = itemsCountEither)
}
fun getLoadedTxHistoryState(
txHistoryEither: Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>,
): WalletStateHolder {
return loadedTxHistoryConverter.convert(txHistoryEither)
}
}

View file

@ -4,10 +4,7 @@ import androidx.activity.compose.BackHandler
import androidx.compose.animation.*
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.lazy.*
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.PullRefreshState
@ -17,29 +14,26 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemsIndexed
import com.tangem.core.ui.components.buttons.HorizontalActionChips
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.buttons.actions.RoundedActionButton
import com.tangem.core.ui.components.marketprice.MarketPriceBlock
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.transactions.Transaction
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.common.component.NetworkGroupItem
import com.tangem.feature.wallet.presentation.common.component.TokenItem
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletBottomSheet
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletTopBar
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.TransactionsBlockGroupTitle
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.TransactionsBlockTitle
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.MultiCurrencyContentItem
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.OrganizeTokensButton
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.SingleCurrencyContentItem
import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletContentItemDecoration
import com.tangem.feature.wallet.presentation.wallet.ui.utils.ScrollOffsetCollector
import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator
@ -74,6 +68,16 @@ internal fun WalletScreen(state: WalletStateHolder) {
.padding(paddingValues = scaffoldPaddings)
.pullRefresh(pullRefreshState),
) {
val txHistoryItems = if (state is WalletStateHolder.SingleCurrencyContent) {
if (state.txHistoryState is WalletTxHistoryState.ContentItemsState) {
state.txHistoryState.items.collectAsLazyPagingItems()
} else {
null
}
} else {
null
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(vertical = TangemTheme.dimens.spacing8),
@ -90,8 +94,7 @@ internal fun WalletScreen(state: WalletStateHolder) {
item {
HorizontalActionChips(
buttons = state.buttons,
modifier = changeableItemModifier
.padding(top = TangemTheme.dimens.spacing14),
modifier = changeableItemModifier.padding(top = TangemTheme.dimens.spacing14),
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16),
)
}
@ -120,33 +123,12 @@ internal fun WalletScreen(state: WalletStateHolder) {
}
}
itemsIndexed(
items = state.contentItems,
key = { index, item ->
when (item) {
is WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle -> item.networkName
is WalletContentItemState.MultiCurrencyItem.Token -> index
is WalletContentItemState.SingleCurrencyItem.Title -> index
is WalletContentItemState.SingleCurrencyItem.GroupTitle -> item.title
is WalletContentItemState.SingleCurrencyItem.Transaction -> index
is WalletContentItemState.Loading -> index
}
},
itemContent = { index, item ->
ContentItem(
item = item,
modifier = changeableItemModifier.walletContentItemDecoration(
currentIndex = index,
lastIndex = state.contentItems.lastIndex,
),
)
},
)
contentItems(state = state, txHistoryItems = txHistoryItems, modifier = changeableItemModifier)
if (state is WalletStateHolder.MultiCurrencyContent) {
item {
OrganizeTokensButton(
onClick = state.onOrganizeTokensClick,
onClick = state.tokensListState.onOrganizeTokensClick,
modifier = changeableItemModifier
.padding(top = TangemTheme.dimens.spacing14)
.padding(horizontal = TangemTheme.dimens.spacing16),
@ -173,6 +155,74 @@ internal fun WalletScreen(state: WalletStateHolder) {
}
}
private fun LazyListScope.contentItems(
state: WalletStateHolder,
txHistoryItems: LazyPagingItems<WalletTxHistoryState.TxHistoryItemState>?,
modifier: Modifier = Modifier,
) {
when (state) {
is WalletStateHolder.MultiCurrencyContent -> {
tokensListItems(state = state.tokensListState, modifier = modifier)
}
is WalletStateHolder.SingleCurrencyContent -> {
txHistoryItems(
state = state.txHistoryState,
txHistoryItems = txHistoryItems,
modifier = modifier,
)
}
is WalletStateHolder.Loading,
is WalletStateHolder.UnlockWalletContent,
-> Unit
}
}
private fun LazyListScope.tokensListItems(state: WalletTokensListState, modifier: Modifier = Modifier) {
itemsIndexed(
items = state.items,
key = { index, _ -> index },
itemContent = { index, item ->
MultiCurrencyContentItem(
state = item,
modifier = modifier.walletContentItemDecoration(
currentIndex = index,
lastIndex = state.items.lastIndex,
),
)
},
)
}
private fun LazyListScope.txHistoryItems(
state: WalletTxHistoryState,
txHistoryItems: LazyPagingItems<WalletTxHistoryState.TxHistoryItemState>?,
modifier: Modifier = Modifier,
) {
when (state) {
is WalletTxHistoryState.ContentItemsState -> {
checkNotNull(txHistoryItems)
itemsIndexed(
items = txHistoryItems,
key = { index, _ -> index },
itemContent = { index, item ->
if (item == null) return@itemsIndexed
SingleCurrencyContentItem(
state = item,
modifier = modifier.walletContentItemDecoration(
currentIndex = index,
lastIndex = txHistoryItems.itemCount,
),
)
},
)
}
is WalletTxHistoryState.Empty -> TODO("[REDACTED_JIRA]")
is WalletTxHistoryState.Error -> TODO("[REDACTED_JIRA]")
is WalletTxHistoryState.NotSupported -> TODO("[REDACTED_JIRA]")
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun PullToRefreshIndicator(isRefreshing: Boolean, state: PullRefreshState, modifier: Modifier = Modifier) {
@ -183,42 +233,6 @@ private fun PullToRefreshIndicator(isRefreshing: Boolean, state: PullRefreshStat
)
}
@Composable
private fun ContentItem(item: WalletContentItemState, modifier: Modifier = Modifier) {
when (item) {
is WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle -> {
NetworkGroupItem(networkName = item.networkName, modifier = modifier)
}
is WalletContentItemState.MultiCurrencyItem.Token -> {
TokenItem(state = item.state, modifier = modifier)
}
is WalletContentItemState.SingleCurrencyItem.Title -> {
TransactionsBlockTitle(config = item, modifier = modifier)
}
is WalletContentItemState.SingleCurrencyItem.GroupTitle -> {
TransactionsBlockGroupTitle(config = item, modifier = modifier)
}
is WalletContentItemState.SingleCurrencyItem.Transaction -> {
Transaction(state = item.state, modifier = modifier)
}
WalletContentItemState.Loading -> {
TokenItem(state = TokenItemState.Loading, modifier = modifier)
}
}
}
@Composable
private fun OrganizeTokensButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
RoundedActionButton(
config = ActionButtonConfig(
text = stringResource(id = R.string.organize_tokens_title),
iconResId = R.drawable.ic_filter_24,
onClick = onClick,
),
modifier = modifier,
)
}
// region Preview
@Preview
@Composable

View file

@ -0,0 +1,27 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.feature.wallet.presentation.common.component.NetworkGroupItem
import com.tangem.feature.wallet.presentation.common.component.TokenItem
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
/**
* Multi-currency content item
*
* @param state item state
* @param modifier modifier
*
[REDACTED_AUTHOR]
*/
@Composable
internal fun MultiCurrencyContentItem(state: WalletTokensListState.TokensListItemState, modifier: Modifier = Modifier) {
when (state) {
is WalletTokensListState.TokensListItemState.NetworkGroupTitle -> {
NetworkGroupItem(networkName = state.networkName, modifier = modifier)
}
is WalletTokensListState.TokensListItemState.Token -> {
TokenItem(state = state.state, modifier = modifier)
}
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.buttons.actions.RoundedActionButton
import com.tangem.feature.wallet.impl.R
/**
* Organize tokens button
*
* @param onClick callback, if null button is disabled
* @param modifier modifier
*
[REDACTED_AUTHOR]
*/
@Composable
internal fun OrganizeTokensButton(onClick: (() -> Unit)?, modifier: Modifier = Modifier) {
RoundedActionButton(
config = ActionButtonConfig(
text = stringResource(id = R.string.organize_tokens_title),
iconResId = R.drawable.ic_filter_24,
onClick = onClick ?: {},
enabled = onClick != null,
),
modifier = modifier,
)
}

View file

@ -0,0 +1,29 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.ui.components.transactions.Transaction
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
/**
* Single currency content item
*
* @param state state
* @param modifier modifier
*
[REDACTED_AUTHOR]
*/
@Composable
internal fun SingleCurrencyContentItem(state: WalletTxHistoryState.TxHistoryItemState, modifier: Modifier = Modifier) {
when (state) {
is WalletTxHistoryState.TxHistoryItemState.GroupTitle -> {
TxHistoryGroupTitle(config = state, modifier = modifier)
}
is WalletTxHistoryState.TxHistoryItemState.Title -> {
TxHistoryTitle(config = state, modifier = modifier)
}
is WalletTxHistoryState.TxHistoryItemState.Transaction -> {
Transaction(state = state.state, modifier = modifier)
}
}
}

View file

@ -9,7 +9,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState.TxHistoryItemState
/**
* Transactions block group title
@ -18,10 +18,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemStat
* @param modifier modifier
*/
@Composable
internal fun TransactionsBlockGroupTitle(
config: WalletContentItemState.SingleCurrencyItem.GroupTitle,
modifier: Modifier = Modifier,
) {
internal fun TxHistoryGroupTitle(config: TxHistoryItemState.GroupTitle, modifier: Modifier = Modifier) {
Text(
text = config.title,
modifier = modifier
@ -41,7 +38,7 @@ internal fun TransactionsBlockGroupTitle(
@Composable
private fun Preview_TransactionsBlockGroupTitle_Light() {
TangemTheme(isDark = false) {
TransactionsBlockGroupTitle(config = WalletContentItemState.SingleCurrencyItem.GroupTitle(title = "Today"))
TxHistoryGroupTitle(config = TxHistoryItemState.GroupTitle(title = "Today"))
}
}
@ -49,6 +46,6 @@ private fun Preview_TransactionsBlockGroupTitle_Light() {
@Composable
private fun Preview_TransactionsBlockGroupTitle_Dark() {
TangemTheme(isDark = true) {
TransactionsBlockGroupTitle(config = WalletContentItemState.SingleCurrencyItem.GroupTitle(title = "Today"))
TxHistoryGroupTitle(config = TxHistoryItemState.GroupTitle(title = "Today"))
}
}

View file

@ -12,7 +12,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState.TxHistoryItemState
/**
* Transactions block title
@ -21,10 +21,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemStat
* @param modifier modifier
*/
@Composable
internal fun TransactionsBlockTitle(
config: WalletContentItemState.SingleCurrencyItem.Title,
modifier: Modifier = Modifier,
) {
internal fun TxHistoryTitle(config: TxHistoryItemState.Title, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.background(TangemTheme.colors.background.primary)
@ -62,9 +59,7 @@ internal fun TransactionsBlockTitle(
@Composable
private fun Preview_TransactionsBlockTitle_Light() {
TangemTheme(isDark = false) {
TransactionsBlockTitle(
config = WalletContentItemState.SingleCurrencyItem.Title(onExploreClick = {}),
)
TxHistoryTitle(config = TxHistoryItemState.Title(onExploreClick = {}))
}
}
@ -72,8 +67,6 @@ private fun Preview_TransactionsBlockTitle_Light() {
@Composable
private fun Preview_TransactionsBlockTitle_Dark() {
TangemTheme(isDark = true) {
TransactionsBlockTitle(
config = WalletContentItemState.SingleCurrencyItem.Title(onExploreClick = {}),
)
TxHistoryTitle(config = TxHistoryItemState.Title(onExploreClick = {}))
}
}

View file

@ -1,15 +1,15 @@
package com.tangem.feature.wallet.presentation.wallet.utils
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState.MultiCurrencyItem
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
internal object LoadingItemsProvider {
fun getLoadingMultiCurrencyTokens(): PersistentList<MultiCurrencyItem> {
return List(size = 5) { TokenItemState.Loading }
.map { MultiCurrencyItem.Token(it) }
.toPersistentList()
fun getLoadingMultiCurrencyTokens(): ImmutableList<WalletTokensListState.TokensListItemState.Token> {
return buildList(capacity = 5) {
add(WalletTokensListState.TokensListItemState.Token(state = TokenItemState.Loading))
}.toImmutableList()
}
}

View file

@ -1,15 +1,27 @@
package com.tangem.feature.wallet.presentation.wallet.utils
import com.tangem.common.Provider
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
internal class TokenListErrorToWalletStateConverter(
private val currentState: WalletStateHolder,
private val currentStateProvider: Provider<WalletStateHolder>,
) : Converter<TokenListError, WalletStateHolder> {
// TODO: [REDACTED_JIRA]
override fun convert(value: TokenListError): WalletStateHolder {
return currentState
val state = currentStateProvider()
return WalletStateHolder.MultiCurrencyContent(
onBackClick = state.onBackClick,
topBarConfig = state.topBarConfig,
walletsListConfig = state.walletsListConfig,
pullToRefreshConfig = state.pullToRefreshConfig,
notifications = state.notifications,
bottomSheet = state.bottomSheet,
tokensListState = WalletTokensListState.Content(items = persistentListOf(), onOrganizeTokensClick = null),
)
}
}

View file

@ -3,10 +3,11 @@ package com.tangem.feature.wallet.presentation.wallet.utils
import com.tangem.domain.tokens.model.NetworkGroup
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.tokens.model.TokenStatus
import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState.MultiCurrencyItem
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState.TokensListItemState
import com.tangem.feature.wallet.presentation.wallet.utils.LoadingItemsProvider.getLoadingMultiCurrencyTokens
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate
import kotlinx.collections.immutable.persistentListOf
@ -15,36 +16,44 @@ internal class TokenListToContentItemsConverter(
isWalletContentHidden: Boolean,
fiatCurrencyCode: String,
fiatCurrencySymbol: String,
) : Converter<TokenList, ImmutableList<MultiCurrencyItem>> {
private val clickCallbacks: WalletClickCallbacks,
) : Converter<TokenList, WalletTokensListState> {
private val tokenStatusConverter = TokenStatusToTokenItemConverter(
isWalletContentHidden,
fiatCurrencyCode,
fiatCurrencySymbol,
isWalletContentHidden = isWalletContentHidden,
fiatCurrencyCode = fiatCurrencyCode,
fiatCurrencySymbol = fiatCurrencySymbol,
)
override fun convert(value: TokenList): ImmutableList<MultiCurrencyItem> {
return when (value) {
is TokenList.GroupedByNetwork -> value.mapToMultiCurrencyItems()
is TokenList.Ungrouped -> value.mapToMultiCurrencyItems()
is TokenList.NotInitialized -> getLoadingMultiCurrencyTokens()
}
override fun convert(value: TokenList): WalletTokensListState {
return WalletTokensListState.Content(
items = when (value) {
is TokenList.GroupedByNetwork -> value.mapToMultiCurrencyItems()
is TokenList.Ungrouped -> value.mapToMultiCurrencyItems()
is TokenList.NotInitialized -> getLoadingMultiCurrencyTokens()
},
onOrganizeTokensClick = if (value.totalFiatBalance is TokenList.FiatBalance.Loaded) {
clickCallbacks::onOrganizeTokensClick
} else {
null
},
)
}
private fun TokenList.GroupedByNetwork.mapToMultiCurrencyItems(): PersistentList<MultiCurrencyItem> {
private fun TokenList.GroupedByNetwork.mapToMultiCurrencyItems(): PersistentList<TokensListItemState> {
return groups.fold(initial = persistentListOf()) { acc, group ->
acc.mutate { it.addGroup(group) }
}
}
private fun TokenList.Ungrouped.mapToMultiCurrencyItems(): PersistentList<MultiCurrencyItem> {
private fun TokenList.Ungrouped.mapToMultiCurrencyItems(): PersistentList<TokensListItemState> {
return tokens.fold(initial = persistentListOf()) { acc, token ->
acc.mutate { it.addToken(token) }
}
}
private fun MutableList<MultiCurrencyItem>.addGroup(group: NetworkGroup): List<MultiCurrencyItem> {
this.add(MultiCurrencyItem.NetworkGroupTitle(group.network.name))
private fun MutableList<TokensListItemState>.addGroup(group: NetworkGroup): List<TokensListItemState> {
this.add(TokensListItemState.NetworkGroupTitle(group.network.name))
group.tokens.forEach { token ->
this.addToken(token)
@ -53,10 +62,10 @@ internal class TokenListToContentItemsConverter(
return this
}
private fun MutableList<MultiCurrencyItem>.addToken(token: TokenStatus): List<MultiCurrencyItem> {
private fun MutableList<TokensListItemState>.addToken(token: TokenStatus): List<TokensListItemState> {
val tokenItemState = tokenStatusConverter.convert(token)
this.add(MultiCurrencyItem.Token(tokenItemState))
this.add(TokensListItemState.Token(tokenItemState))
return this
}

View file

@ -1,48 +1,56 @@
package com.tangem.feature.wallet.presentation.wallet.utils
import com.tangem.core.ui.components.transactions.TransactionState
import com.tangem.common.Provider
import com.tangem.domain.tokens.model.TokenList
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder.MultiCurrencyContent
import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter.TokensListModel
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toPersistentList
internal class TokenListToWalletStateConverter(
private val currentState: WalletStateHolder,
private val currentStateProvider: Provider<WalletStateHolder>,
private val isWalletContentHidden: Boolean,
private val fiatCurrencyCode: String,
private val fiatCurrencySymbol: String,
clickCallbacks: WalletClickCallbacks,
) : Converter<TokensListModel, WalletStateHolder> {
private val tokenListToContentConverter = TokenListToContentItemsConverter(
isWalletContentHidden = isWalletContentHidden,
fiatCurrencyCode = fiatCurrencyCode,
fiatCurrencySymbol = fiatCurrencySymbol,
clickCallbacks = clickCallbacks,
)
override fun convert(value: TokensListModel): WalletStateHolder {
val state = if (currentState is MultiCurrencyContent) {
currentState.updateWithTokenList(tokenList = value.tokenList)
} else {
currentState
}
return state.copySealed(
walletsListConfig = state.updateSelectedWallet(value.tokenList.totalFiatBalance),
pullToRefreshConfig = if (value.isRefreshing) {
state.pullToRefreshConfig.copy(isRefreshing = state.getRefreshingStatus())
} else {
state.pullToRefreshConfig
},
)
val state = currentStateProvider()
return state
.updateWithTokenList(tokenList = value.tokenList)
.copySealed(
walletsListConfig = state.updateSelectedWallet(value.tokenList.totalFiatBalance),
pullToRefreshConfig = if (value.isRefreshing) {
state.pullToRefreshConfig.copy(isRefreshing = state.getRefreshingStatus())
} else {
state.pullToRefreshConfig
},
)
}
private fun MultiCurrencyContent.updateWithTokenList(tokenList: TokenList): MultiCurrencyContent {
return this.copy(contentItems = tokenListToContentConverter.convert(value = tokenList))
private fun WalletStateHolder.updateWithTokenList(tokenList: TokenList): MultiCurrencyContent {
return MultiCurrencyContent(
onBackClick = onBackClick,
topBarConfig = topBarConfig,
walletsListConfig = walletsListConfig,
pullToRefreshConfig = pullToRefreshConfig,
notifications = notifications,
bottomSheet = bottomSheet,
tokensListState = tokenListToContentConverter.convert(value = tokenList),
)
}
private fun WalletStateHolder.updateSelectedWallet(fiatBalance: TokenList.FiatBalance): WalletsListConfig {
@ -63,13 +71,13 @@ internal class TokenListToWalletStateConverter(
}
private fun WalletStateHolder.getRefreshingStatus(): Boolean {
return contentItems.any { state ->
val isMultiCurrencyItem = state as? WalletContentItemState.MultiCurrencyItem.Token
val isSingleCurrencyItem = state as? WalletContentItemState.SingleCurrencyItem.Transaction
isMultiCurrencyItem?.state is TokenItemState.Loading ||
isSingleCurrencyItem?.state is TransactionState.Loading ||
state is WalletContentItemState.Loading
return if (this is MultiCurrencyContent) {
tokensListState.items.any { tokensListItemState ->
tokensListItemState is WalletTokensListState.TokensListItemState.Token &&
tokensListItemState.state is TokenItemState.Loading
}
} else {
false
}
}

View file

@ -6,9 +6,9 @@ import com.tangem.domain.tokens.model.NetworkGroup
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.tokens.model.TokenStatus
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletNotification
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
@ -32,7 +32,7 @@ internal class WalletNotificationsListFactory(
private val clickCallbacks: WalletClickCallbacks,
) {
fun create(cardTypesResolver: CardTypesResolver, tokenList: TokenList): Flow<ImmutableList<WalletNotification>> {
fun create(cardTypesResolver: CardTypesResolver, tokenList: TokenList?): Flow<ImmutableList<WalletNotification>> {
// TODO: [REDACTED_JIRA] order
return flow {
emit(
@ -63,7 +63,7 @@ internal class WalletNotificationsListFactory(
add(element = WalletNotification.BackupCard(onClick = clickCallbacks::onBackupCardClick))
}
if (tokenList.hasMissedDerivations()) {
if (tokenList != null && tokenList.hasMissedDerivations()) {
add(element = WalletNotification.ScanCard(onClick = clickCallbacks::onScanCardClick))
}
@ -112,12 +112,12 @@ internal class WalletNotificationsListFactory(
}
private fun hasUnreachableNetworks(): Boolean {
val isUnreachableState = { item: WalletContentItemState.MultiCurrencyItem ->
(item as? WalletContentItemState.MultiCurrencyItem.Token)?.state is TokenItemState.Unreachable
val isUnreachableState = { item: WalletTokensListState.TokensListItemState ->
(item as? WalletTokensListState.TokensListItemState.Token)?.state is TokenItemState.Unreachable
}
return currentStateProvider().let { state ->
state is WalletStateHolder.MultiCurrencyContent && state.contentItems.any(isUnreachableState)
state is WalletStateHolder.MultiCurrencyContent && state.tokensListState.items.any(isUnreachableState)
}
}

View file

@ -4,6 +4,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.*
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.common.Provider
import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
@ -14,8 +15,10 @@ import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.settings.IsUserAlreadyRateAppUseCase
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.userwallets.UserWalletBuilder
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
@ -46,6 +49,8 @@ internal class WalletViewModel @Inject constructor(
private val isUserAlreadyRateAppUseCase: IsUserAlreadyRateAppUseCase,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val scanCardProcessor: ScanCardProcessor,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val dispatchers: CoroutineDispatcherProvider,
) : ViewModel(), DefaultLifecycleObserver, WalletClickCallbacks {
@ -62,6 +67,9 @@ internal class WalletViewModel @Inject constructor(
private val stateFactory = WalletStateFactory(
currentStateProvider = Provider { uiState },
currentCardTypeResolverProvider = Provider {
getCardTypeResolver(index = uiState.walletsListConfig.selectedWalletIndex)
},
clickCallbacks = this,
)
@ -69,10 +77,10 @@ internal class WalletViewModel @Inject constructor(
var uiState: WalletStateHolder by mutableStateOf(stateFactory.getInitialState())
private set
private var cardTypeResolverMap: Map<UserWalletId, CardTypesResolver> by Delegates.notNull()
private var wallets: List<UserWallet> by Delegates.notNull()
private val getTokensJobHolder = JobHolder()
private val getNotificationJobHolder = JobHolder()
private val tokensJobHolder = JobHolder()
private val notificationsJobHolder = JobHolder()
override fun onCreate(owner: LifecycleOwner) {
getWalletsUseCase()
@ -80,15 +88,7 @@ internal class WalletViewModel @Inject constructor(
.distinctUntilChanged()
.onEach { wallets ->
if (wallets.isEmpty()) return@onEach
cardTypeResolverMap = wallets.associate { wallet ->
// TODO remove after adding release logic for GetTokenListUseCase
if (wallet.scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
UserWalletId("123")
} else {
UserWalletId("321")
} to wallet.scanResponse.cardTypesResolver
}
this.wallets = wallets
uiState = stateFactory.getSkeletonState(wallets = wallets)
@ -99,8 +99,15 @@ internal class WalletViewModel @Inject constructor(
}
private fun updateContentItems(index: Int, isRefreshing: Boolean = false) {
// TODO: use GetTransactionsUseCase
val cardTypeResolver = getCardTypeResolver(index)
if (cardTypeResolver.isMultiwalletAllowed()) {
updateByTokensList(index, isRefreshing)
} else {
updateByTxHistory(index)
}
}
private fun updateByTokensList(index: Int, isRefreshing: Boolean) {
getTokenListUseCase(userWalletId = uiState.walletsListConfig.wallets[index].id)
.distinctUntilChanged()
.onEach { tokenListEither ->
@ -113,26 +120,50 @@ internal class WalletViewModel @Inject constructor(
}
.flowOn(dispatchers.io)
.launchIn(viewModelScope)
.saveIn(jobHolder = getTokensJobHolder)
.saveIn(tokensJobHolder)
}
private fun updateNotifications(index: Int, tokenList: TokenList) {
private fun updateByTxHistory(index: Int) {
viewModelScope.launch(dispatchers.io) {
val wallet = getWallet(index)
val blockchain = wallet.scanResponse.cardTypesResolver.getBlockchain()
uiState = stateFactory.getLoadingTxHistoryState(
itemsCountEither = txHistoryItemsCountUseCase(
networkId = blockchain.id,
derivationPath = requireNotNull(blockchain.derivationPath(style = DerivationStyle.LEGACY)).rawPath,
),
)
updateTxHistory(networkId = blockchain.id)
updateNotifications(index)
}
}
private fun updateTxHistory(networkId: String) {
uiState = stateFactory.getLoadedTxHistoryState(txHistoryEither = txHistoryItemsUseCase(networkId))
}
private fun updateNotifications(index: Int, tokenList: TokenList? = null) {
notificationsListFactory.create(
cardTypesResolver = requireNotNull(
value = cardTypeResolverMap[uiState.walletsListConfig.wallets[index].id],
lazyMessage = {
"CardTypeResolverMap doesn't contain this id = ${uiState.walletsListConfig.wallets[index].id}"
},
),
cardTypesResolver = getCardTypeResolver(index = index),
tokenList = tokenList,
)
.distinctUntilChanged()
.onEach { uiState = stateFactory.getStateByNotifications(notifications = it) }
.flowOn(dispatchers.io)
.launchIn(viewModelScope)
.saveIn(jobHolder = getNotificationJobHolder)
.saveIn(jobHolder = notificationsJobHolder)
}
private fun getWallet(index: Int): UserWallet {
return requireNotNull(
value = wallets.getOrNull(index),
lazyMessage = { "WalletsList doesn't contain element with index = $index" },
)
}
private fun getCardTypeResolver(index: Int): CardTypesResolver = getWallet(index).scanResponse.cardTypesResolver
override fun onBackClick() = router.popBackStack()
override fun onScanCardClick() {