From 9c524c81131e1f17b1e6e5c0fa8602b621dd4d34 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 11 Aug 2023 17:30:05 +0800 Subject: [PATCH] Updated on 2026-08-14 --- .../wallet/domain/WalletImageResolver.kt | 2 +- .../presentation/wallet/state/WalletState.kt | 14 +++++ ...letSingleCurrencyLoadedBalanceConverter.kt | 11 +++- .../state/factory/WalletStateFactory.kt | 1 + .../wallet/viewmodels/WalletStateCache.kt | 22 ++++++++ .../wallet/viewmodels/WalletStateHolder.kt | 40 ++++++++++++++ .../viewmodels/WalletStateHolderDelegate.kt | 20 +++++++ .../wallet/viewmodels/WalletViewModel.kt | 54 ++++++++++++++++--- 8 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateCache.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateHolder.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateHolderDelegate.kt diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/WalletImageResolver.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/WalletImageResolver.kt index 2dd09d7535..c54155dd33 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/WalletImageResolver.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/WalletImageResolver.kt @@ -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 diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletState.kt index 570accc073..9cc1f3fa27 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletState.kt @@ -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) + } + } } /** diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt index 6087b1f2fa..143c38fdb4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt @@ -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, + private val cardTypeResolverProvider: Provider, private val fiatCurrencyCode: String, private val fiatCurrencySymbol: String, ) : Converter, 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( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt index c1ab20757d..80436dcaa8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt @@ -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] ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateCache.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateCache.kt new file mode 100644 index 0000000000..c5d4e10424 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateCache.kt @@ -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() + + /** 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 + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateHolder.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateHolder.kt new file mode 100644 index 0000000000..59c1f39f13 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateHolder.kt @@ -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) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateHolderDelegate.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateHolderDelegate.kt new file mode 100644 index 0000000000..25c3d12698 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletStateHolderDelegate.kt @@ -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 { + + 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 { + return WalletStateHolderDelegate(uiStateHolder = WalletStateHolder(initialState = initialState)) +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index eb8e6247e1..06ca0ab8c5 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -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 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() + .any { it.state is TokenItemState.Loading } + } + is WalletSingleCurrencyState -> { + txHistoryState is TxHistoryState.Loading || marketPriceBlockState is MarketPriceBlockState.Loading + } + is WalletState.Initial -> false + } } override fun onRefreshSwipe() {