Updated on 2026-08-14
This commit is contained in:
parent
300179445d
commit
9c524c8113
8 changed files with 153 additions and 11 deletions
|
|
@ -42,7 +42,7 @@ internal object WalletImageResolver {
|
|||
return when (cardTypesResolver.getBlockchain()) {
|
||||
Blockchain.Bitcoin -> R.drawable.ill_note_btc_120_106
|
||||
Blockchain.Ethereum -> R.drawable.ill_note_ethereum_120_106
|
||||
Blockchain.Binance -> R.drawable.ill_note_binance_120_106
|
||||
Blockchain.BSC -> R.drawable.ill_note_binance_120_106
|
||||
Blockchain.Dogecoin -> R.drawable.ill_note_doge_120_106
|
||||
Blockchain.Cardano -> R.drawable.ill_note_cardano_120_106
|
||||
Blockchain.XRP -> R.drawable.ill_note_xrp_120_106
|
||||
|
|
|
|||
|
|
@ -30,6 +30,20 @@ internal sealed class WalletState {
|
|||
|
||||
/** Bottom sheet config */
|
||||
abstract val bottomSheetConfig: WalletBottomSheetConfig?
|
||||
|
||||
/**
|
||||
* Util function that allow to make a copy
|
||||
*
|
||||
* @param walletsListConfig wallets list config
|
||||
*/
|
||||
fun copySealed(walletsListConfig: WalletsListConfig = this.walletsListConfig): ContentState {
|
||||
return when (this) {
|
||||
is WalletMultiCurrencyState.Content -> copy(walletsListConfig = walletsListConfig)
|
||||
is WalletMultiCurrencyState.Locked -> copy(walletsListConfig = walletsListConfig)
|
||||
is WalletSingleCurrencyState.Content -> copy(walletsListConfig = walletsListConfig)
|
||||
is WalletSingleCurrencyState.Locked -> copy(walletsListConfig = walletsListConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ import com.tangem.common.Provider
|
|||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeConfig
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.error.CurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
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.WalletCardState
|
||||
|
|
@ -17,6 +19,7 @@ import java.math.BigDecimal
|
|||
|
||||
internal class WalletSingleCurrencyLoadedBalanceConverter(
|
||||
private val currentStateProvider: Provider<WalletState>,
|
||||
private val cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val fiatCurrencyCode: String,
|
||||
private val fiatCurrencySymbol: String,
|
||||
) : Converter<Either<CurrencyError, CryptoCurrencyStatus>, WalletSingleCurrencyState.Content> {
|
||||
|
|
@ -33,7 +36,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
val state = requireNotNull(currentStateProvider() as? WalletSingleCurrencyState.Content)
|
||||
val currencyName = state.marketPriceBlockState.currencyName
|
||||
return state.copy(
|
||||
walletsListConfig = getUpdatedSelectedWallet(status.value, state),
|
||||
walletsListConfig = getUpdatedSelectedWallet(status = status.value, state = state),
|
||||
marketPriceBlockState = getMarketPriceState(status = status.value, currencyName = currencyName),
|
||||
)
|
||||
}
|
||||
|
|
@ -78,7 +81,11 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
WalletCardState.Content(
|
||||
id = selectedWallet.id,
|
||||
title = selectedWallet.title,
|
||||
additionalInfo = selectedWallet.additionalInfo,
|
||||
additionalInfo = WalletAdditionalInfoFactory.resolve(
|
||||
cardTypesResolver = cardTypeResolverProvider(),
|
||||
isLocked = false,
|
||||
currencyAmount = status.amount,
|
||||
),
|
||||
imageResId = selectedWallet.imageResId,
|
||||
onClick = selectedWallet.onClick,
|
||||
balance = BigDecimalFormatter.formatFiatAmount(
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ internal class WalletStateFactory(
|
|||
private val singleCurrencyLoadedBalanceConverter by lazy {
|
||||
WalletSingleCurrencyLoadedBalanceConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
cardTypeResolverProvider = currentCardTypeResolverProvider,
|
||||
fiatCurrencyCode = "USD", // TODO: [REDACTED_JIRA]
|
||||
fiatCurrencySymbol = "$", // TODO: [REDACTED_JIRA]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
||||
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
|
||||
/**
|
||||
* Wallet state cache. It allows to switch the wallets without additional loading like a PagerView.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object WalletStateCache {
|
||||
|
||||
private val states = mutableMapOf<UserWalletId, WalletState>()
|
||||
|
||||
/** Get state by [userWalletId] */
|
||||
fun getState(userWalletId: UserWalletId): WalletState? = states[userWalletId]
|
||||
|
||||
/** Add or update [state] by [userWalletId] */
|
||||
fun update(userWalletId: UserWalletId, state: WalletState) {
|
||||
states[userWalletId] = state
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
|
||||
/**
|
||||
* Wallet state holder
|
||||
*
|
||||
* @param initialState initial ui state
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class WalletStateHolder(initialState: WalletState) {
|
||||
|
||||
/** Screen state */
|
||||
var uiState: WalletState by mutableStateOf(initialState)
|
||||
private set
|
||||
|
||||
/** Set screen [state] */
|
||||
fun setState(state: WalletState) {
|
||||
when (state) {
|
||||
is WalletState.ContentState -> {
|
||||
cache(state = state)
|
||||
|
||||
uiState = state
|
||||
}
|
||||
is WalletState.Initial -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
/** Cache [state] [WalletState.ContentState] to [WalletStateCache] */
|
||||
private fun cache(state: WalletState.ContentState) {
|
||||
val selectedWalletIndex = state.walletsListConfig.selectedWalletIndex
|
||||
val selectedWalletId = state.walletsListConfig.wallets[selectedWalletIndex].id
|
||||
|
||||
WalletStateCache.update(userWalletId = selectedWalletId, state = state)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
||||
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
internal class WalletStateHolderDelegate(
|
||||
private val uiStateHolder: WalletStateHolder,
|
||||
) : ReadWriteProperty<Any?, WalletState> {
|
||||
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): WalletState = uiStateHolder.uiState
|
||||
|
||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: WalletState) {
|
||||
uiStateHolder.setState(value)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun uiStateHolder(initialState: WalletState): ReadWriteProperty<Any?, WalletState> {
|
||||
return WalletStateHolderDelegate(uiStateHolder = WalletStateHolder(initialState = initialState))
|
||||
}
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.*
|
||||
import androidx.paging.cachedIn
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
|
|
@ -10,6 +7,8 @@ import com.tangem.blockchain.common.DerivationStyle
|
|||
import com.tangem.common.Provider
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.domain.card.*
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
|
|
@ -26,12 +25,15 @@ import com.tangem.domain.userwallets.UserWalletBuilder
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletLockedState
|
||||
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.WalletBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletStateFactory
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -48,7 +50,7 @@ import kotlin.properties.Delegates
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Suppress("LongParameterList", "TooManyFunctions")
|
||||
@Suppress("LargeClass", "LongParameterList", "TooManyFunctions")
|
||||
@HiltViewModel
|
||||
internal class WalletViewModel @Inject constructor(
|
||||
private val getWalletsUseCase: GetWalletsUseCase,
|
||||
|
|
@ -96,8 +98,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
)
|
||||
|
||||
/** Screen state */
|
||||
var uiState: WalletState by mutableStateOf(stateFactory.getInitialState())
|
||||
private set
|
||||
var uiState: WalletState by uiStateHolder(initialState = stateFactory.getInitialState())
|
||||
|
||||
private var wallets: List<UserWallet> by Delegates.notNull()
|
||||
|
||||
|
|
@ -131,6 +132,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
uiState = stateFactory.getSkeletonState(wallets = sourceList, selectedWalletIndex = selectedWalletIndex)
|
||||
|
||||
updateContentItems(index = selectedWalletIndex)
|
||||
}
|
||||
|
||||
|
|
@ -316,13 +318,49 @@ 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)
|
||||
notificationsJobHolder.update(job = null)
|
||||
|
||||
uiState = stateFactory.getSkeletonState(wallets = wallets, selectedWalletIndex = index)
|
||||
val cacheState = WalletStateCache.getState(userWalletId = state.walletsListConfig.wallets[index].id)
|
||||
if (cacheState != null) {
|
||||
uiState = if (cacheState is WalletState.ContentState) {
|
||||
cacheState.copySealed(walletsListConfig = state.walletsListConfig.copy(selectedWalletIndex = index))
|
||||
} else {
|
||||
cacheState
|
||||
}
|
||||
|
||||
updateContentItems(index = index)
|
||||
if (cacheState.isLoadingState()) updateContentItems(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 -> {
|
||||
tokensListState is WalletTokensListState.Loading ||
|
||||
tokensListState.items
|
||||
.filterIsInstance<WalletTokensListState.TokensListItemState.Token>()
|
||||
.any { it.state is TokenItemState.Loading }
|
||||
}
|
||||
is WalletSingleCurrencyState -> {
|
||||
txHistoryState is TxHistoryState.Loading || marketPriceBlockState is MarketPriceBlockState.Loading
|
||||
}
|
||||
is WalletState.Initial -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRefreshSwipe() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue