Updated on 2026-08-14
This commit is contained in:
parent
5a169e6211
commit
b5e2899332
12 changed files with 375 additions and 380 deletions
|
|
@ -7,6 +7,7 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
|
|||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
internal sealed class WalletSingleCurrencyState : WalletState.ContentState() {
|
||||
|
||||
/** Manage buttons */
|
||||
abstract val buttons: ImmutableList<WalletManageButton>
|
||||
abstract val buttons: PersistentList<WalletManageButton>
|
||||
|
||||
/** Transactions history state */
|
||||
abstract val txHistoryState: TxHistoryState
|
||||
|
|
@ -31,7 +32,7 @@ internal sealed class WalletSingleCurrencyState : WalletState.ContentState() {
|
|||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
override val bottomSheetConfig: WalletBottomSheetConfig?,
|
||||
override val buttons: ImmutableList<WalletManageButton>,
|
||||
override val buttons: PersistentList<WalletManageButton>,
|
||||
override val txHistoryState: TxHistoryState,
|
||||
val marketPriceBlockState: MarketPriceBlockState,
|
||||
) : WalletSingleCurrencyState()
|
||||
|
|
@ -41,7 +42,7 @@ internal sealed class WalletSingleCurrencyState : WalletState.ContentState() {
|
|||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val buttons: ImmutableList<WalletManageButton>,
|
||||
override val buttons: PersistentList<WalletManageButton>,
|
||||
override val onUnlockWalletsNotificationClick: () -> Unit,
|
||||
override val onUnlockClick: () -> Unit,
|
||||
override val onScanClick: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class WalletCryptoCurrencyActionsConverter(
|
||||
private val currentStateProvider: Provider<WalletState>,
|
||||
|
|
@ -26,7 +26,7 @@ internal class WalletCryptoCurrencyActionsConverter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun List<TokenActionsState.ActionState>.mapToManageButtons(): ImmutableList<WalletManageButton> {
|
||||
private fun List<TokenActionsState.ActionState>.mapToManageButtons(): PersistentList<WalletManageButton> {
|
||||
return this
|
||||
.mapNotNull { action ->
|
||||
when (action) {
|
||||
|
|
@ -45,6 +45,6 @@ internal class WalletCryptoCurrencyActionsConverter(
|
|||
is TokenActionsState.ActionState.Swap -> null
|
||||
}
|
||||
}
|
||||
.toImmutableList()
|
||||
.toPersistentList()
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ import com.tangem.domain.tokens.model.TokenList
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletLoadedTokensListConverter.LoadedTokensListModel
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListErrorConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
|
|
@ -27,11 +26,12 @@ import com.tangem.utils.converter.Converter
|
|||
*/
|
||||
internal class WalletLoadedTokensListConverter(
|
||||
private val currentStateProvider: Provider<WalletState>,
|
||||
private val tokenListErrorConverter: TokenListErrorConverter,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
currentWalletProvider: Provider<UserWallet>,
|
||||
clickIntents: WalletClickIntents,
|
||||
) : Converter<LoadedTokensListModel, WalletState> {
|
||||
) : Converter<Either<TokenListError, TokenList>, WalletState> {
|
||||
|
||||
private val tokenListStateConverter = TokenListToWalletStateConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
|
|
@ -42,26 +42,10 @@ internal class WalletLoadedTokensListConverter(
|
|||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
private val tokenListErrorStateConverter = TokenListErrorConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
)
|
||||
|
||||
override fun convert(value: LoadedTokensListModel): WalletState {
|
||||
return value.tokenListEither.fold(
|
||||
ifLeft = tokenListErrorStateConverter::convert,
|
||||
ifRight = {
|
||||
tokenListStateConverter.convert(
|
||||
value = TokenListToWalletStateConverter.TokensListModel(
|
||||
tokenList = it,
|
||||
isRefreshing = value.isRefreshing,
|
||||
),
|
||||
)
|
||||
},
|
||||
override fun convert(value: Either<TokenListError, TokenList>): WalletState {
|
||||
return value.fold(
|
||||
ifLeft = tokenListErrorConverter::convert,
|
||||
ifRight = tokenListStateConverter::convert,
|
||||
)
|
||||
}
|
||||
|
||||
data class LoadedTokensListModel(
|
||||
val tokenListEither: Either<TokenListError, TokenList>,
|
||||
val isRefreshing: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTopB
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ internal class WalletLockedConverter(
|
|||
)
|
||||
}
|
||||
|
||||
private fun createButtons(): ImmutableList<WalletManageButton> {
|
||||
private fun createButtons(): PersistentList<WalletManageButton> {
|
||||
return persistentListOf(
|
||||
WalletManageButton.Buy(enabled = false, onClick = {}),
|
||||
WalletManageButton.Send(enabled = false, onClick = {}),
|
||||
|
|
|
|||
|
|
@ -1,124 +1,112 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.factory
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState.TokensListItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletPullToRefreshConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.mutate
|
||||
|
||||
internal class WalletRefreshStateConverter(
|
||||
private val currentStateProvider: Provider<WalletState>,
|
||||
private val currentCardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) : Converter<Unit, WalletState> {
|
||||
private val intents: WalletClickIntents,
|
||||
) : Converter<Boolean, WalletState> {
|
||||
|
||||
override fun convert(value: Unit): WalletState {
|
||||
return when (val state = currentStateProvider()) {
|
||||
is WalletMultiCurrencyState.Content -> state.getRefreshState()
|
||||
is WalletSingleCurrencyState.Content -> state.getRefreshState()
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
override fun convert(value: Boolean): WalletState {
|
||||
val state = currentStateProvider()
|
||||
val contentState = state as? WalletState.ContentState ?: return state
|
||||
|
||||
private fun WalletMultiCurrencyState.Content.getRefreshState(): WalletMultiCurrencyState.Content {
|
||||
return copy(
|
||||
walletsListConfig = createWalletsListConfig(),
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
tokensListState = createTokenListState(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletSingleCurrencyState.Content.getRefreshState(): WalletSingleCurrencyState.Content {
|
||||
return copy(
|
||||
walletsListConfig = createWalletsListConfig(),
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
buttons = buttons.mapToDisabledButton(),
|
||||
txHistoryState = createTxHistoryState(),
|
||||
marketPriceBlockState = MarketPriceBlockState.Loading(currencyName = marketPriceBlockState.currencyName),
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletState.ContentState.createWalletsListConfig(): WalletsListConfig {
|
||||
val selectedWallet = walletsListConfig.wallets[walletsListConfig.selectedWalletIndex]
|
||||
val additionalInfo = if (currentCardTypeResolverProvider().isMultiwalletAllowed()) {
|
||||
selectedWallet.additionalInfo
|
||||
return if (value) {
|
||||
contentState.getRefreshingState()
|
||||
} else {
|
||||
null
|
||||
contentState.getRefreshedState()
|
||||
}
|
||||
}
|
||||
|
||||
return walletsListConfig.copy(
|
||||
wallets = walletsListConfig.wallets.toPersistentList().set(
|
||||
index = walletsListConfig.selectedWalletIndex,
|
||||
element = WalletCardState.Loading(
|
||||
id = selectedWallet.id,
|
||||
title = selectedWallet.title,
|
||||
additionalInfo = additionalInfo,
|
||||
imageResId = selectedWallet.imageResId,
|
||||
onRenameClick = selectedWallet.onRenameClick,
|
||||
onDeleteClick = selectedWallet.onDeleteClick,
|
||||
),
|
||||
),
|
||||
private fun WalletState.ContentState.getRefreshingState(): WalletState {
|
||||
return when (this) {
|
||||
is WalletMultiCurrencyState.Content -> getRefreshingState()
|
||||
is WalletSingleCurrencyState.Content -> getRefreshingState()
|
||||
is WalletMultiCurrencyState.Locked,
|
||||
is WalletSingleCurrencyState.Locked,
|
||||
-> this
|
||||
}
|
||||
}
|
||||
|
||||
private fun WalletState.ContentState.getRefreshedState(): WalletState {
|
||||
return when (this) {
|
||||
is WalletMultiCurrencyState.Content -> getRefreshedState()
|
||||
is WalletSingleCurrencyState.Content -> getRefreshedState()
|
||||
is WalletMultiCurrencyState.Locked,
|
||||
is WalletSingleCurrencyState.Locked,
|
||||
-> this
|
||||
}
|
||||
}
|
||||
|
||||
private fun WalletMultiCurrencyState.Content.getRefreshingState(): WalletMultiCurrencyState {
|
||||
return copy(
|
||||
pullToRefreshConfig = updatePullToRefreshConfig(isRefreshing = true),
|
||||
tokensListState = updateTokenListState(isRefreshing = true),
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletState.ContentState.createPullToRefreshConfig(): WalletPullToRefreshConfig {
|
||||
return pullToRefreshConfig.copy(isRefreshing = true)
|
||||
private fun WalletSingleCurrencyState.Content.getRefreshingState(): WalletSingleCurrencyState {
|
||||
return copy(
|
||||
pullToRefreshConfig = updatePullToRefreshConfig(isRefreshing = true),
|
||||
buttons = updateButtons(isRefreshing = true),
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletMultiCurrencyState.Content.createTokenListState(): WalletTokensListState {
|
||||
return when (tokensListState) {
|
||||
private fun WalletMultiCurrencyState.Content.getRefreshedState(): WalletMultiCurrencyState {
|
||||
return copy(
|
||||
pullToRefreshConfig = updatePullToRefreshConfig(isRefreshing = false),
|
||||
tokensListState = updateTokenListState(isRefreshing = false),
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletSingleCurrencyState.Content.getRefreshedState(): WalletSingleCurrencyState {
|
||||
return copy(
|
||||
pullToRefreshConfig = updatePullToRefreshConfig(isRefreshing = false),
|
||||
buttons = updateButtons(isRefreshing = false),
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletMultiCurrencyState.updateTokenListState(isRefreshing: Boolean): WalletTokensListState {
|
||||
return when (val state = tokensListState) {
|
||||
is WalletTokensListState.Content -> {
|
||||
WalletTokensListState.Loading(
|
||||
items = tokensListState.items
|
||||
.filterIsInstance<TokensListItemState.Token>()
|
||||
.mapToLoadingTokenState(),
|
||||
)
|
||||
val onOrganizeTokensClick = if (isRefreshing) null else intents::onOrganizeTokensClick
|
||||
|
||||
state.copy(onOrganizeTokensClick = onOrganizeTokensClick)
|
||||
}
|
||||
is WalletTokensListState.Empty -> WalletTokensListState.Loading()
|
||||
is WalletTokensListState.Loading,
|
||||
is WalletTokensListState.Locked,
|
||||
-> tokensListState
|
||||
is WalletTokensListState.Loading,
|
||||
is WalletTokensListState.Empty,
|
||||
-> state
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<TokensListItemState.Token>.mapToLoadingTokenState(): ImmutableList<TokensListItemState.Token> {
|
||||
return this
|
||||
.map { TokensListItemState.Token(state = TokenItemState.Loading(id = it.state.id)) }
|
||||
.toImmutableList()
|
||||
}
|
||||
private fun WalletSingleCurrencyState.updateButtons(isRefreshing: Boolean): PersistentList<WalletManageButton> {
|
||||
val isButtonsEnabled = !isRefreshing
|
||||
|
||||
private fun ImmutableList<WalletManageButton>.mapToDisabledButton(): ImmutableList<WalletManageButton> {
|
||||
return this
|
||||
.mapNotNull { button ->
|
||||
return buttons.mutate {
|
||||
it.mapNotNull { button ->
|
||||
when (button) {
|
||||
is WalletManageButton.Buy -> button.copy(enabled = false)
|
||||
is WalletManageButton.Send -> button.copy(enabled = false)
|
||||
is WalletManageButton.Buy -> button.copy(enabled = isButtonsEnabled)
|
||||
is WalletManageButton.Send -> button.copy(enabled = isButtonsEnabled)
|
||||
is WalletManageButton.Sell -> button.copy(enabled = isButtonsEnabled)
|
||||
is WalletManageButton.Receive -> button
|
||||
is WalletManageButton.Sell -> button.copy(enabled = false)
|
||||
is WalletManageButton.Swap -> null
|
||||
}
|
||||
}
|
||||
.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun WalletSingleCurrencyState.Content.createTxHistoryState(): TxHistoryState {
|
||||
if (txHistoryState is TxHistoryState.Content) {
|
||||
txHistoryState.contentItems.update {
|
||||
TxHistoryState.getDefaultLoadingTransactions(onExploreClick = clickIntents::onExploreClick)
|
||||
}
|
||||
}
|
||||
|
||||
return txHistoryState
|
||||
private fun WalletState.ContentState.updatePullToRefreshConfig(isRefreshing: Boolean): WalletPullToRefreshConfig {
|
||||
return pullToRefreshConfig.copy(isRefreshing = isRefreshing)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyS
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletSingleCurrencyLoadedBalanceConverter.SingleCurrencyLoadedBalanceModel
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.CurrencyStatusErrorConverter
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -25,32 +25,21 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
private val cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val currentWalletProvider: Provider<UserWallet>,
|
||||
) : Converter<SingleCurrencyLoadedBalanceModel, WalletSingleCurrencyState.Content> {
|
||||
private val currencyStatusErrorConverter: CurrencyStatusErrorConverter,
|
||||
) : Converter<Either<CurrencyStatusError, CryptoCurrencyStatus>, WalletSingleCurrencyState.Content> {
|
||||
|
||||
override fun convert(value: SingleCurrencyLoadedBalanceModel): WalletSingleCurrencyState.Content {
|
||||
return value.cryptoCurrencyEither.fold(
|
||||
ifLeft = { convertError() },
|
||||
ifRight = { convertContent(it, value.isRefreshing) },
|
||||
override fun convert(value: Either<CurrencyStatusError, CryptoCurrencyStatus>): WalletSingleCurrencyState.Content {
|
||||
return value.fold(
|
||||
ifLeft = currencyStatusErrorConverter::convert,
|
||||
ifRight = ::convertContent,
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertError(): WalletSingleCurrencyState.Content {
|
||||
return requireNotNull(currentStateProvider() as? WalletSingleCurrencyState.Content)
|
||||
}
|
||||
|
||||
private fun convertContent(
|
||||
status: CryptoCurrencyStatus,
|
||||
isRefreshing: Boolean,
|
||||
): WalletSingleCurrencyState.Content {
|
||||
private fun convertContent(status: CryptoCurrencyStatus): WalletSingleCurrencyState.Content {
|
||||
val state = requireNotNull(currentStateProvider() as? WalletSingleCurrencyState.Content)
|
||||
val currencyName = state.marketPriceBlockState.currencyName
|
||||
return state.copy(
|
||||
walletsListConfig = getUpdatedSelectedWallet(status = status.value, state = state),
|
||||
pullToRefreshConfig = if (isRefreshing) {
|
||||
state.pullToRefreshConfig.copy(isRefreshing = status.value is CryptoCurrencyStatus.Loading)
|
||||
} else {
|
||||
state.pullToRefreshConfig
|
||||
},
|
||||
marketPriceBlockState = getMarketPriceState(status = status.value, currencyName = currencyName),
|
||||
)
|
||||
}
|
||||
|
|
@ -168,9 +157,4 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
}
|
||||
|
||||
data class SingleCurrencyLoadedBalanceModel(
|
||||
val cryptoCurrencyEither: Either<CurrencyStatusError, CryptoCurrencyStatus>,
|
||||
val isRefreshing: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletSkeletonStateConverter.SkeletonModel
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -128,7 +128,7 @@ internal class WalletSkeletonStateConverter(
|
|||
return WalletPullToRefreshConfig(isRefreshing = false, onRefresh = clickIntents::onRefreshSwipe)
|
||||
}
|
||||
|
||||
private fun createButtons(): ImmutableList<WalletManageButton> {
|
||||
private fun createButtons(): PersistentList<WalletManageButton> {
|
||||
return persistentListOf(
|
||||
WalletManageButton.Buy(enabled = false, onClick = {}),
|
||||
WalletManageButton.Send(enabled = false, onClick = {}),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBott
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory.WalletLoadedTxHistoryConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory.WalletLoadingTxHistoryConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.CurrencyStatusErrorConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListErrorConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -45,9 +47,16 @@ internal class WalletStateFactory(
|
|||
private val tokenActionsProvider by lazy { TokenActionsProvider(currentStateProvider = currentStateProvider) }
|
||||
private val skeletonConverter by lazy { WalletSkeletonStateConverter(currentStateProvider, clickIntents) }
|
||||
|
||||
private val tokenListErrorConverter by lazy {
|
||||
TokenListErrorConverter(currentStateProvider)
|
||||
}
|
||||
private val currencyStatusErrorConverter by lazy {
|
||||
CurrencyStatusErrorConverter(currentStateProvider)
|
||||
}
|
||||
private val loadedTokensListConverter by lazy {
|
||||
WalletLoadedTokensListConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
tokenListErrorConverter = tokenListErrorConverter,
|
||||
cardTypeResolverProvider = currentCardTypeResolverProvider,
|
||||
currentWalletProvider = currentWalletProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
|
|
@ -76,6 +85,7 @@ internal class WalletStateFactory(
|
|||
cardTypeResolverProvider = currentCardTypeResolverProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
currentWalletProvider = currentWalletProvider,
|
||||
currencyStatusErrorConverter = currencyStatusErrorConverter,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -91,8 +101,7 @@ internal class WalletStateFactory(
|
|||
private val refreshStateConverter by lazy {
|
||||
WalletRefreshStateConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
currentCardTypeResolverProvider = currentCardTypeResolverProvider,
|
||||
clickIntents = clickIntents,
|
||||
intents = clickIntents,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -114,13 +123,12 @@ internal class WalletStateFactory(
|
|||
)
|
||||
}
|
||||
|
||||
fun getStateByTokensList(tokenListEither: Either<TokenListError, TokenList>, isRefreshing: Boolean): WalletState {
|
||||
return loadedTokensListConverter.convert(
|
||||
value = WalletLoadedTokensListConverter.LoadedTokensListModel(
|
||||
tokenListEither = tokenListEither,
|
||||
isRefreshing = isRefreshing,
|
||||
),
|
||||
)
|
||||
fun getStateByTokensList(maybeTokenList: Either<TokenListError, TokenList>): WalletState {
|
||||
return loadedTokensListConverter.convert(maybeTokenList)
|
||||
}
|
||||
|
||||
fun getStateByTokenListError(error: TokenListError): WalletState {
|
||||
return tokenListErrorConverter.convert(error)
|
||||
}
|
||||
|
||||
fun getStateByNotifications(notifications: ImmutableList<WalletNotification>): WalletState {
|
||||
|
|
@ -131,7 +139,9 @@ internal class WalletStateFactory(
|
|||
}
|
||||
}
|
||||
|
||||
fun getStateAfterContentRefreshing(): WalletState = refreshStateConverter.convert(Unit)
|
||||
fun getRefreshingState(): WalletState = refreshStateConverter.convert(value = true)
|
||||
|
||||
fun getRefreshedState(): WalletState = refreshStateConverter.convert(value = false)
|
||||
|
||||
fun getStateWithOpenWalletBottomSheet(content: WalletBottomSheetConfig.BottomSheetContentConfig): WalletState {
|
||||
return when (val state = currentStateProvider() as WalletState.ContentState) {
|
||||
|
|
@ -157,6 +167,7 @@ internal class WalletStateFactory(
|
|||
isBottomSheetShow = true,
|
||||
onBottomSheetDismiss = clickIntents::onDismissBottomSheet,
|
||||
)
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,6 +181,7 @@ internal class WalletStateFactory(
|
|||
bottomSheetConfig = state.bottomSheetConfig?.copy(isShow = false),
|
||||
)
|
||||
is WalletSingleCurrencyState.Locked -> state.copy(isBottomSheetShow = false)
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,18 +211,16 @@ internal class WalletStateFactory(
|
|||
fun getLockedState(): WalletState = lockedConverter.convert(Unit)
|
||||
|
||||
fun getSingleCurrencyLoadedBalanceState(
|
||||
cryptoCurrencyEither: Either<CurrencyStatusError, CryptoCurrencyStatus>,
|
||||
isRefreshing: Boolean,
|
||||
maybeCryptoCurrencyStatus: Either<CurrencyStatusError, CryptoCurrencyStatus>,
|
||||
): WalletState {
|
||||
return singleCurrencyLoadedBalanceConverter.convert(
|
||||
value = WalletSingleCurrencyLoadedBalanceConverter.SingleCurrencyLoadedBalanceModel(
|
||||
cryptoCurrencyEither = cryptoCurrencyEither,
|
||||
isRefreshing = isRefreshing,
|
||||
),
|
||||
)
|
||||
return singleCurrencyLoadedBalanceConverter.convert(maybeCryptoCurrencyStatus)
|
||||
}
|
||||
|
||||
fun getSingleCurrencyManageButtonsState(actions: List<TokenActionsState.ActionState>): WalletState {
|
||||
return cryptoCurrencyActionsConverter.convert(value = actions)
|
||||
}
|
||||
|
||||
fun getStateByCurrencyStatusError(error: CurrencyStatusError): WalletState {
|
||||
return currencyStatusErrorConverter.convert(error)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.material3.FabPosition
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.utils
|
||||
|
||||
import com.tangem.common.Converter
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
|
||||
// TODO: Implement this
|
||||
internal class CurrencyStatusErrorConverter(
|
||||
private val currentStateProvider: Provider<WalletState>,
|
||||
) : Converter<CurrencyStatusError, WalletSingleCurrencyState.Content> {
|
||||
|
||||
override fun convert(value: CurrencyStatusError): WalletSingleCurrencyState.Content {
|
||||
return requireNotNull(currentStateProvider() as? WalletSingleCurrencyState.Content)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import com.tangem.domain.wallets.models.UserWallet
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter.TokensListModel
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
|
@ -21,7 +20,7 @@ internal class TokenListToWalletStateConverter(
|
|||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val isWalletContentHidden: Boolean,
|
||||
clickIntents: WalletClickIntents,
|
||||
) : Converter<TokensListModel, WalletMultiCurrencyState.Content> {
|
||||
) : Converter<TokenList, WalletMultiCurrencyState.Content> {
|
||||
|
||||
private val tokenListToContentConverter = TokenListToContentItemsConverter(
|
||||
isWalletContentHidden = isWalletContentHidden,
|
||||
|
|
@ -29,16 +28,11 @@ internal class TokenListToWalletStateConverter(
|
|||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
override fun convert(value: TokensListModel): WalletMultiCurrencyState.Content {
|
||||
override fun convert(value: TokenList): WalletMultiCurrencyState.Content {
|
||||
val state = requireNotNull(currentStateProvider() as? WalletMultiCurrencyState.Content)
|
||||
return state.copy(
|
||||
walletsListConfig = state.updateSelectedWallet(fiatBalance = value.tokenList.totalFiatBalance),
|
||||
pullToRefreshConfig = if (value.isRefreshing) {
|
||||
state.pullToRefreshConfig.copy(isRefreshing = getRefreshingStatus(tokenList = value.tokenList))
|
||||
} else {
|
||||
state.pullToRefreshConfig
|
||||
},
|
||||
tokensListState = tokenListToContentConverter.convert(value = value.tokenList),
|
||||
walletsListConfig = state.updateSelectedWallet(fiatBalance = value.totalFiatBalance),
|
||||
tokensListState = tokenListToContentConverter.convert(value = value),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -58,10 +52,4 @@ internal class TokenListToWalletStateConverter(
|
|||
.set(index = selectedWalletIndex, element = converter.convert(fiatBalance)),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getRefreshingStatus(tokenList: TokenList): Boolean {
|
||||
return tokenList.totalFiatBalance is TokenList.FiatBalance.Loading
|
||||
}
|
||||
|
||||
data class TokensListModel(val tokenList: TokenList, val isRefreshing: Boolean)
|
||||
}
|
||||
|
|
@ -21,9 +21,7 @@ import com.tangem.domain.redux.ReduxStateHolder
|
|||
import com.tangem.domain.settings.CanUseBiometryUseCase
|
||||
import com.tangem.domain.settings.IsUserAlreadyRateAppUseCase
|
||||
import com.tangem.domain.settings.ShouldShowSaveWalletScreenUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
|
|
@ -73,7 +71,9 @@ internal class WalletViewModel @Inject constructor(
|
|||
private val setAccessCodeRequestPolicyUseCase: SetAccessCodeRequestPolicyUseCase,
|
||||
private val getAccessCodeSavingStatusUseCase: GetAccessCodeSavingStatusUseCase,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
private val getPrimaryCurrencyUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val fetchTokenListUseCase: FetchTokenListUseCase,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val getCardWasScannedUseCase: GetCardWasScannedUseCase,
|
||||
private val isUserAlreadyRateAppUseCase: IsUserAlreadyRateAppUseCase,
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
|
|
@ -127,6 +127,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
private val marketPriceJobHolder = JobHolder()
|
||||
private val buttonsJobHolder = JobHolder()
|
||||
private val notificationsJobHolder = JobHolder()
|
||||
private val refreshContentJobHolder = JobHolder()
|
||||
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
|
|
@ -151,6 +152,10 @@ internal class WalletViewModel @Inject constructor(
|
|||
wallets = sourceList
|
||||
|
||||
val currentState = uiState
|
||||
val previousSelectedWalletIndex = (currentState as? WalletState.ContentState)
|
||||
?.walletsListConfig
|
||||
?.selectedWalletIndex
|
||||
|
||||
val selectedWalletIndex = if (currentState is WalletLockedState) {
|
||||
currentState.getSelectedWalletIndex()
|
||||
} else {
|
||||
|
|
@ -161,141 +166,13 @@ internal class WalletViewModel @Inject constructor(
|
|||
sourceList.indexOfFirst { it.walletId == selectedWallet.walletId }
|
||||
}
|
||||
|
||||
uiState = stateFactory.getSkeletonState(wallets = sourceList, selectedWalletIndex = selectedWalletIndex)
|
||||
if (previousSelectedWalletIndex != selectedWalletIndex) {
|
||||
uiState = stateFactory.getSkeletonState(wallets = sourceList, selectedWalletIndex = selectedWalletIndex)
|
||||
|
||||
updateContentItems(index = selectedWalletIndex)
|
||||
}
|
||||
|
||||
private fun updateContentItems(index: Int, isRefreshing: Boolean = false) {
|
||||
val cardTypeResolver = getCardTypeResolver(index)
|
||||
when {
|
||||
getWallet(index).isLocked -> uiState = stateFactory.getLockedState()
|
||||
cardTypeResolver.isMultiwalletAllowed() -> updateMultiCurrencyContent(index, isRefreshing)
|
||||
!cardTypeResolver.isMultiwalletAllowed() -> updateSingleCurrencyContent(index, isRefreshing)
|
||||
getContentItemsUpdates(index = selectedWalletIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateMultiCurrencyContent(index: Int, isRefreshing: Boolean = false) {
|
||||
val state = requireNotNull(uiState as? WalletMultiCurrencyState) {
|
||||
"Impossible to update tokens list if state isn't WalletMultiCurrencyState"
|
||||
}
|
||||
|
||||
getTokenListUseCase(userWalletId = state.walletsListConfig.wallets[index].id)
|
||||
.distinctUntilChanged()
|
||||
.onEach { tokenListEither ->
|
||||
uiState = stateFactory.getStateByTokensList(
|
||||
tokenListEither = tokenListEither,
|
||||
isRefreshing = isRefreshing,
|
||||
)
|
||||
|
||||
updateNotifications(
|
||||
index = index,
|
||||
tokenList = tokenListEither.fold(ifLeft = { null }, ifRight = { it }),
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(tokensJobHolder)
|
||||
}
|
||||
|
||||
private fun updateSingleCurrencyContent(index: Int, isRefreshing: Boolean) {
|
||||
val wallet = getWallet(index)
|
||||
val blockchain = getCardTypeResolver(index).getBlockchain()
|
||||
updateTxHistory(
|
||||
blockchain = blockchain,
|
||||
derivationStyle = wallet.scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
updateMarketPrice(userWalletId = wallet.walletId, isRefreshing = isRefreshing)
|
||||
updateNotifications(index)
|
||||
}
|
||||
|
||||
private fun updateTxHistory(blockchain: Blockchain, derivationStyle: DerivationStyle?) {
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
val derivationPath = blockchain.derivationPath(style = derivationStyle)?.rawPath
|
||||
|
||||
val txHistoryItemsCountEither = txHistoryItemsCountUseCase(
|
||||
networkId = Network.ID(blockchain.id),
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
|
||||
uiState = stateFactory.getLoadingTxHistoryState(itemsCountEither = txHistoryItemsCountEither)
|
||||
|
||||
txHistoryItemsCountEither.onRight {
|
||||
uiState = stateFactory.getLoadedTxHistoryState(
|
||||
txHistoryEither = txHistoryItemsUseCase(
|
||||
networkId = Network.ID(blockchain.id),
|
||||
derivationPath = derivationPath,
|
||||
).map {
|
||||
it.cachedIn(viewModelScope)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It also update wallet balance
|
||||
private fun updateMarketPrice(userWalletId: UserWalletId, isRefreshing: Boolean) {
|
||||
getPrimaryCurrencyUseCase(userWalletId = userWalletId)
|
||||
.distinctUntilChanged()
|
||||
.onEach { either ->
|
||||
uiState = stateFactory.getSingleCurrencyLoadedBalanceState(
|
||||
cryptoCurrencyEither = either,
|
||||
isRefreshing = isRefreshing,
|
||||
)
|
||||
|
||||
either.onRight { status ->
|
||||
cryptoCurrencyStatus = status
|
||||
updateButtons(userWalletId = userWalletId, currency = status.currency)
|
||||
}
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(marketPriceJobHolder)
|
||||
}
|
||||
|
||||
private fun updateButtons(userWalletId: UserWalletId, currency: CryptoCurrency) {
|
||||
getCryptoCurrencyActionsUseCase(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
.distinctUntilChanged()
|
||||
.onEach { uiState = stateFactory.getSingleCurrencyManageButtonsState(actions = it.states) }
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(buttonsJobHolder)
|
||||
}
|
||||
|
||||
private fun updateNotifications(index: Int, tokenList: TokenList? = null) {
|
||||
notificationsListFactory.create(
|
||||
cardTypesResolver = getCardTypeResolver(index = index),
|
||||
tokenList = tokenList,
|
||||
)
|
||||
.distinctUntilChanged()
|
||||
.onEach { uiState = stateFactory.getStateByNotifications(notifications = it) }
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(notificationsJobHolder)
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
saveSelectedWallet()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun saveSelectedWallet() {
|
||||
val state = uiState
|
||||
if (state is WalletState.ContentState) {
|
||||
selectWalletUseCase(getWallet(index = state.walletsListConfig.selectedWalletIndex).walletId)
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
router.popBackStack(screen = if (shouldSaveUserWalletsUseCase()) AppScreen.Welcome else AppScreen.Home)
|
||||
|
|
@ -373,14 +250,9 @@ internal class WalletViewModel @Inject constructor(
|
|||
|
||||
if (state.walletsListConfig.selectedWalletIndex == index) return
|
||||
|
||||
/*
|
||||
* When wallet is changed it's necessary to stop the last jobs.
|
||||
* If jobs aren't stopped and wallet is changed then it will update state for the prev wallet.
|
||||
*/
|
||||
tokensJobHolder.update(job = null)
|
||||
marketPriceJobHolder.update(job = null)
|
||||
buttonsJobHolder.update(job = null)
|
||||
notificationsJobHolder.update(job = null)
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
selectWalletUseCase(getWallet(index = index).walletId)
|
||||
}
|
||||
|
||||
val cacheState = WalletStateCache.getState(userWalletId = state.walletsListConfig.wallets[index].id)
|
||||
if (cacheState != null) {
|
||||
|
|
@ -393,50 +265,28 @@ internal class WalletViewModel @Inject constructor(
|
|||
cacheState
|
||||
}
|
||||
|
||||
if (cacheState.isLoadingState()) updateContentItems(index)
|
||||
if (cacheState.isLoadingState()) {
|
||||
getContentItemsUpdates(index)
|
||||
}
|
||||
} else {
|
||||
uiState = stateFactory.getSkeletonState(wallets = wallets, selectedWalletIndex = index)
|
||||
updateContentItems(index = index)
|
||||
}
|
||||
}
|
||||
|
||||
private fun WalletState.isLoadingState(): Boolean {
|
||||
// Check the base components
|
||||
if (this is WalletState.ContentState) {
|
||||
walletsListConfig.wallets[walletsListConfig.selectedWalletIndex] is WalletCardState.Loading ||
|
||||
notifications.isEmpty()
|
||||
}
|
||||
|
||||
// Check the special components
|
||||
return when (this) {
|
||||
is WalletMultiCurrencyState -> {
|
||||
val hasLoadingTokens = tokensListState is WalletTokensListState.ContentState &&
|
||||
(tokensListState as WalletTokensListState.ContentState).items
|
||||
.filterIsInstance<WalletTokensListState.TokensListItemState.Token>()
|
||||
.any { it.state is TokenItemState.Loading }
|
||||
|
||||
tokensListState is WalletTokensListState.Loading || hasLoadingTokens
|
||||
}
|
||||
is WalletSingleCurrencyState -> {
|
||||
this is WalletSingleCurrencyState.Content && marketPriceBlockState is MarketPriceBlockState.Loading
|
||||
}
|
||||
is WalletState.Initial -> false
|
||||
getContentItemsUpdates(index = index)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRefreshSwipe() {
|
||||
if (uiState is WalletState.Initial || uiState is WalletLockedState) return
|
||||
val selectedWalletIndex = (uiState as? WalletState.ContentState)
|
||||
?.walletsListConfig
|
||||
?.selectedWalletIndex
|
||||
?: return
|
||||
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
uiState = stateFactory.getStateAfterContentRefreshing()
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
delay(timeMillis = 500)
|
||||
|
||||
updateContentItems(
|
||||
index = requireNotNull(uiState as? WalletState.ContentState).walletsListConfig.selectedWalletIndex,
|
||||
isRefreshing = true,
|
||||
)
|
||||
when (uiState) {
|
||||
is WalletMultiCurrencyState.Content -> refreshMultiCurrencyContent(selectedWalletIndex)
|
||||
is WalletSingleCurrencyState.Content -> refreshSingleCurrencyContent(selectedWalletIndex)
|
||||
is WalletState.Initial,
|
||||
is WalletMultiCurrencyState.Locked,
|
||||
is WalletSingleCurrencyState.Locked,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -486,11 +336,12 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onReloadClick() {
|
||||
uiState = stateFactory.getStateAfterContentRefreshing()
|
||||
updateSingleCurrencyContent(
|
||||
index = requireNotNull(uiState as? WalletState.ContentState).walletsListConfig.selectedWalletIndex,
|
||||
isRefreshing = true,
|
||||
)
|
||||
val selectedWalletIndex = (uiState as? WalletSingleCurrencyState)
|
||||
?.walletsListConfig
|
||||
?.selectedWalletIndex
|
||||
?: return
|
||||
|
||||
refreshSingleCurrencyContent(selectedWalletIndex)
|
||||
}
|
||||
|
||||
override fun onExploreClick() {
|
||||
|
|
@ -553,18 +404,6 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createSelectedAppCurrencyFlow(): StateFlow<AppCurrency> {
|
||||
return getSelectedAppCurrencyUseCase()
|
||||
.map { maybeAppCurrency ->
|
||||
maybeAppCurrency.getOrElse { AppCurrency.Default }
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = AppCurrency.Default,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDismissBottomSheet() {
|
||||
uiState = stateFactory.getStateWithClosedBottomSheet()
|
||||
}
|
||||
|
|
@ -578,4 +417,188 @@ internal class WalletViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getContentItemsUpdates(index: Int) {
|
||||
/*
|
||||
* When wallet is changed it's necessary to stop the last jobs.
|
||||
* If jobs aren't stopped and wallet is changed then it will update state for the prev wallet.
|
||||
*/
|
||||
tokensJobHolder.update(job = null)
|
||||
marketPriceJobHolder.update(job = null)
|
||||
buttonsJobHolder.update(job = null)
|
||||
notificationsJobHolder.update(job = null)
|
||||
refreshContentJobHolder.update(job = null)
|
||||
|
||||
val wallet = getWallet(index)
|
||||
|
||||
when {
|
||||
wallet.isLocked -> {
|
||||
uiState = stateFactory.getLockedState()
|
||||
}
|
||||
wallet.isMultiCurrency -> getMultiCurrencyContent(index)
|
||||
!wallet.isMultiCurrency -> getSingleCurrencyContent(index)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMultiCurrencyContent(walletIndex: Int) {
|
||||
val state = requireNotNull(uiState as? WalletMultiCurrencyState) {
|
||||
"Impossible to get a token list updates if state isn't WalletMultiCurrencyState"
|
||||
}
|
||||
|
||||
getTokenListUseCase(userWalletId = state.walletsListConfig.wallets[walletIndex].id)
|
||||
.distinctUntilChanged()
|
||||
.onEach { maybeTokenList ->
|
||||
uiState = stateFactory.getStateByTokensList(maybeTokenList)
|
||||
|
||||
updateNotifications(
|
||||
index = walletIndex,
|
||||
tokenList = maybeTokenList.fold(ifLeft = { null }, ifRight = { it }),
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(tokensJobHolder)
|
||||
}
|
||||
|
||||
private fun getSingleCurrencyContent(index: Int) {
|
||||
val wallet = getWallet(index)
|
||||
val blockchain = getCardTypeResolver(index).getBlockchain()
|
||||
updateTxHistory(
|
||||
blockchain = blockchain,
|
||||
derivationStyle = wallet.scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
updateMarketPrice(userWalletId = wallet.walletId)
|
||||
updateNotifications(index)
|
||||
}
|
||||
|
||||
private fun updateTxHistory(blockchain: Blockchain, derivationStyle: DerivationStyle?) {
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
val derivationPath = blockchain.derivationPath(style = derivationStyle)?.rawPath
|
||||
|
||||
val txHistoryItemsCountEither = txHistoryItemsCountUseCase(
|
||||
networkId = Network.ID(blockchain.id),
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
|
||||
uiState = stateFactory.getLoadingTxHistoryState(itemsCountEither = txHistoryItemsCountEither)
|
||||
|
||||
txHistoryItemsCountEither.onRight {
|
||||
uiState = stateFactory.getLoadedTxHistoryState(
|
||||
txHistoryEither = txHistoryItemsUseCase(
|
||||
networkId = Network.ID(blockchain.id),
|
||||
derivationPath = derivationPath,
|
||||
).map {
|
||||
it.cachedIn(viewModelScope)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It also update wallet balance
|
||||
private fun updateMarketPrice(userWalletId: UserWalletId) {
|
||||
getPrimaryCurrencyStatusUpdatesUseCase(userWalletId = userWalletId)
|
||||
.distinctUntilChanged()
|
||||
.onEach { maybeCryptoCurrencyStatus ->
|
||||
uiState = stateFactory.getSingleCurrencyLoadedBalanceState(maybeCryptoCurrencyStatus)
|
||||
|
||||
maybeCryptoCurrencyStatus.onRight { status ->
|
||||
cryptoCurrencyStatus = status
|
||||
updateButtons(userWalletId = userWalletId, currency = status.currency)
|
||||
}
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(marketPriceJobHolder)
|
||||
}
|
||||
|
||||
private fun updateButtons(userWalletId: UserWalletId, currency: CryptoCurrency) {
|
||||
getCryptoCurrencyActionsUseCase(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
.distinctUntilChanged()
|
||||
.onEach { uiState = stateFactory.getSingleCurrencyManageButtonsState(actions = it.states) }
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(buttonsJobHolder)
|
||||
}
|
||||
|
||||
private fun updateNotifications(index: Int, tokenList: TokenList? = null) {
|
||||
notificationsListFactory.create(
|
||||
cardTypesResolver = getCardTypeResolver(index = index),
|
||||
tokenList = tokenList,
|
||||
)
|
||||
.distinctUntilChanged()
|
||||
.onEach { uiState = stateFactory.getStateByNotifications(notifications = it) }
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(notificationsJobHolder)
|
||||
}
|
||||
|
||||
private fun refreshMultiCurrencyContent(walletIndex: Int) {
|
||||
uiState = stateFactory.getRefreshingState()
|
||||
val wallet = getWallet(walletIndex)
|
||||
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
val result = fetchTokenListUseCase(wallet.walletId, refresh = true)
|
||||
|
||||
uiState = stateFactory.getRefreshedState()
|
||||
uiState = result.fold(stateFactory::getStateByTokenListError) { uiState }
|
||||
}.saveIn(refreshContentJobHolder)
|
||||
}
|
||||
|
||||
private fun refreshSingleCurrencyContent(walletIndex: Int) {
|
||||
uiState = stateFactory.getRefreshingState()
|
||||
val wallet = getWallet(walletIndex)
|
||||
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
val result = fetchCurrencyStatusUseCase(wallet.walletId, refresh = true)
|
||||
|
||||
uiState = stateFactory.getRefreshedState()
|
||||
uiState = result.fold(stateFactory::getStateByCurrencyStatusError) { uiState }
|
||||
}.saveIn(refreshContentJobHolder)
|
||||
}
|
||||
|
||||
private fun createSelectedAppCurrencyFlow(): StateFlow<AppCurrency> {
|
||||
return getSelectedAppCurrencyUseCase()
|
||||
.map { maybeAppCurrency ->
|
||||
maybeAppCurrency.getOrElse { AppCurrency.Default }
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = AppCurrency.Default,
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletState.isLoadingState(): Boolean {
|
||||
// Check the base components
|
||||
if (this is WalletState.ContentState) {
|
||||
walletsListConfig.wallets[walletsListConfig.selectedWalletIndex] is WalletCardState.Loading ||
|
||||
notifications.isEmpty()
|
||||
}
|
||||
|
||||
// Check the special components
|
||||
return when (this) {
|
||||
is WalletMultiCurrencyState -> {
|
||||
val hasLoadingTokens = tokensListState is WalletTokensListState.ContentState &&
|
||||
(tokensListState as WalletTokensListState.ContentState).items
|
||||
.filterIsInstance<WalletTokensListState.TokensListItemState.Token>()
|
||||
.any { it.state is TokenItemState.Loading }
|
||||
|
||||
tokensListState is WalletTokensListState.Loading || hasLoadingTokens
|
||||
}
|
||||
is WalletSingleCurrencyState -> {
|
||||
this is WalletSingleCurrencyState.Content && marketPriceBlockState is MarketPriceBlockState.Loading
|
||||
}
|
||||
is WalletState.Initial -> false
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue