From 4dc40538692ae0a482080290a42c2f1ae0977bf0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 8 Sep 2024 11:16:31 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../ui/components/rows/RoundableCornersRow.kt | 4 +- .../state/StakingStateController.kt | 2 +- .../impl/presentation/state/StakingUiState.kt | 2 + .../previewdata/InitialStakingStatePreview.kt | 2 + .../state/stub/StakingClickIntentsStub.kt | 5 +- .../SetInitialDataStateTransformer.kt | 9 +- .../SetInitialLoadingStateTransformer.kt | 20 ++ .../ui/StakingInitialInfoContent.kt | 220 +++++++++++------- .../viewmodel/StakingClickIntents.kt | 2 + .../viewmodel/StakingViewModel.kt | 88 ++++--- .../TokenDetailsSkeletonStateConverter.kt | 2 +- .../tokendetails/ui/TokenDetailsScreen.kt | 2 +- 12 files changed, 231 insertions(+), 127 deletions(-) create mode 100644 features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialLoadingStateTransformer.kt diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/rows/RoundableCornersRow.kt b/core/ui/src/main/java/com/tangem/core/ui/components/rows/RoundableCornersRow.kt index c2b1e97286..ac525e0fb1 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/rows/RoundableCornersRow.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/rows/RoundableCornersRow.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.tangem.core.ui.R import com.tangem.core.ui.res.TangemTheme @@ -95,8 +96,7 @@ enum class CornersToRound { @Suppress("TopLevelComposableFunctions") @Composable - fun getShape(): RoundedCornerShape { - val radius = TangemTheme.dimens.radius12 + fun getShape(radius: Dp = TangemTheme.dimens.radius12): RoundedCornerShape { return when (this) { ALL_4 -> RoundedCornerShape(radius) TOP_2 -> RoundedCornerShape(topStart = radius, topEnd = radius) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt index 8a47bfe35d..4c450c78a2 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt @@ -21,7 +21,7 @@ import javax.inject.Singleton @Singleton internal class StakingStateController @Inject constructor( - private val urlOpener: UrlOpener, + urlOpener: UrlOpener, ) { val value: StakingUiState get() = uiState.value diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt index ca9f2e192b..1a276f55e0 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt @@ -8,6 +8,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.list.RoundedListWithDividersItemData import com.tangem.core.ui.event.StateEvent import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig import com.tangem.domain.staking.model.stakekit.PendingAction import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType @@ -62,6 +63,7 @@ internal sealed class StakingStates { val aprRange: TextReference, val onInfoClick: (InfoType) -> Unit, val yieldBalance: InnerYieldBalanceState, + val pullToRefreshConfig: PullToRefreshConfig, ) : InitialInfoState() data class Empty( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt index 77d30e2fb2..6ad1e50645 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt @@ -3,6 +3,7 @@ package com.tangem.features.staking.impl.presentation.state.previewdata import com.tangem.core.ui.components.list.RoundedListWithDividersItemData import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig import com.tangem.domain.staking.model.stakekit.BalanceType import com.tangem.domain.staking.model.stakekit.RewardBlockType import com.tangem.domain.staking.model.stakekit.Yield @@ -57,6 +58,7 @@ internal object InitialStakingStatePreview { ), onInfoClick = {}, yieldBalance = InnerYieldBalanceState.Empty, + pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}), ) val stateWithYield = defaultState.copy( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt index 4697e7fe88..a13675c8bf 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt @@ -21,6 +21,8 @@ internal object StakingClickIntentsStub : StakingClickIntents { override fun onPrevClick() {} + override fun onRefreshSwipe(isRefreshing: Boolean) {} + override fun onInitialInfoBannerClick() {} override fun onInfoClick(infoType: InfoType) {} @@ -59,7 +61,8 @@ internal object StakingClickIntentsStub : StakingClickIntents { reduceAmountBy: BigDecimal, reduceAmountByDiff: BigDecimal, notification: Class, - ) {} + ) { + } override fun onAmountReduceToClick(reduceAmountTo: BigDecimal, notification: Class) {} diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt index 35b98d0107..13c748e962 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt @@ -6,6 +6,7 @@ import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter import com.tangem.core.ui.components.list.RoundedListWithDividersItemData import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.core.serialization.SerializedBigDecimal @@ -14,10 +15,6 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWallet import com.tangem.features.staking.impl.R import com.tangem.features.staking.impl.presentation.state.* -import com.tangem.features.staking.impl.presentation.state.StakingStates -import com.tangem.features.staking.impl.presentation.state.StakingUiState -import com.tangem.features.staking.impl.presentation.state.TransactionDoneState -import com.tangem.features.staking.impl.presentation.state.ValidatorState import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType import com.tangem.features.staking.impl.presentation.state.converters.RewardsValidatorStateConverter import com.tangem.features.staking.impl.presentation.state.converters.YieldBalancesConverter @@ -88,6 +85,10 @@ internal class SetInitialDataStateTransformer( infoItems = getInfoItems(), onInfoClick = clickIntents::onInfoClick, yieldBalance = yieldBalance, + pullToRefreshConfig = PullToRefreshConfig( + onRefresh = { clickIntents.onRefreshSwipe(it.value) }, + isRefreshing = false, + ), ) } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialLoadingStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialLoadingStateTransformer.kt new file mode 100644 index 0000000000..416ec78676 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialLoadingStateTransformer.kt @@ -0,0 +1,20 @@ +package com.tangem.features.staking.impl.presentation.state.transformers + +import com.tangem.features.staking.impl.presentation.state.StakingStates +import com.tangem.features.staking.impl.presentation.state.StakingUiState +import com.tangem.utils.transformer.Transformer + +internal class SetInitialLoadingStateTransformer( + private val isRefreshing: Boolean, +) : Transformer { + override fun transform(prevState: StakingUiState): StakingUiState { + val initialState = prevState.initialInfoState as? StakingStates.InitialInfoState.Data + return prevState.copy( + initialInfoState = initialState?.copy( + pullToRefreshConfig = prevState.initialInfoState.pullToRefreshConfig.copy( + isRefreshing = isRefreshing, + ), + ) ?: prevState.initialInfoState, + ) + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt index 96a17749b0..6ffdee416f 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt @@ -8,11 +8,16 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -35,7 +40,9 @@ import com.tangem.core.ui.components.SpacerH12 import com.tangem.core.ui.components.inputrow.InputRowDefault import com.tangem.core.ui.components.inputrow.InputRowImageInfo import com.tangem.core.ui.components.list.roundedListWithDividersItems +import com.tangem.core.ui.components.rows.CornersToRound import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -52,14 +59,13 @@ import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickInten import com.tangem.utils.StringsSigns.DOT import com.tangem.utils.StringsSigns.PLUS import com.tangem.utils.extensions.orZero -import kotlinx.collections.immutable.ImmutableList private const val BANNER_BLOCK_KEY = "BannerBlock" private const val STAKING_REWARD_BLOCK_KEY = "StakingRewardBlock" private const val ACTIVE_STAKING_BLOCK_KEY = "ActiveStakingBlock" private const val STAKE_PRIMARY_BUTTON_KEY = "StakePrimaryButton" -@OptIn(ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class) @Composable internal fun StakingInitialInfoContent( state: StakingStates.InitialInfoState, @@ -69,60 +75,116 @@ internal fun StakingInitialInfoContent( ) { if (state !is StakingStates.InitialInfoState.Data) return - LazyColumn( - verticalArrangement = alignLastToBottom(), - modifier = Modifier - .fillMaxSize() - .background(TangemTheme.colors.background.secondary) - .padding(horizontal = TangemTheme.dimens.spacing16), - ) { - if (state.showBanner) { - item(key = BANNER_BLOCK_KEY) { - Column( - modifier = Modifier.animateItemPlacement(), - ) { - BannerBlock(onClick = clickIntents::onInitialInfoBannerClick) - SpacerH12() + val pullRefreshState = rememberPullRefreshState( + refreshing = state.pullToRefreshConfig.isRefreshing, + onRefresh = { state.pullToRefreshConfig.onRefresh(PullToRefreshConfig.ShowRefreshState()) }, + ) + Box(modifier = Modifier.pullRefresh(pullRefreshState)) { + LazyColumn( + verticalArrangement = alignLastToBottom(), + modifier = Modifier + .fillMaxSize() + .background(TangemTheme.colors.background.secondary) + .padding(horizontal = TangemTheme.dimens.spacing16), + ) { + if (state.showBanner) { + item(key = BANNER_BLOCK_KEY) { + Column( + modifier = Modifier.animateItemPlacement(), + ) { + BannerBlock(onClick = clickIntents::onInitialInfoBannerClick) + SpacerH12() + } } } + + this.roundedListWithDividersItems( + rows = state.infoItems, + footerContent = { SpacerH12() }, + hideEndText = isBalanceHidden, + ) + + if (state.yieldBalance is InnerYieldBalanceState.Data) { + item(key = STAKING_REWARD_BLOCK_KEY) { + Column(modifier = Modifier.animateItemPlacement()) { + StakingRewardBlock( + rewardCrypto = state.yieldBalance.rewardsCrypto, + rewardFiat = state.yieldBalance.rewardsFiat, + rewardBlockType = state.yieldBalance.rewardBlockType, + onRewardsClick = clickIntents::openRewardsValidators, + isBalanceHidden = isBalanceHidden, + ) + SpacerH12() + } + } + } + + activeStakingBlock( + state = state, + clickIntents = clickIntents, + isBalanceHidden = isBalanceHidden, + ) + + item(STAKE_PRIMARY_BUTTON_KEY) { + SpacerH12() + StakeButtonBlock(buttonState) + } } - this.roundedListWithDividersItems( - rows = state.infoItems, - footerContent = { SpacerH12() }, - hideEndText = isBalanceHidden, + PullRefreshIndicator( + modifier = Modifier.align(Alignment.TopCenter), + refreshing = state.pullToRefreshConfig.isRefreshing, + state = pullRefreshState, ) + } +} - if (state.yieldBalance is InnerYieldBalanceState.Data) { - item(key = STAKING_REWARD_BLOCK_KEY) { - Column(modifier = Modifier.animateItemPlacement()) { - StakingRewardBlock( - rewardCrypto = state.yieldBalance.rewardsCrypto, - rewardFiat = state.yieldBalance.rewardsFiat, - rewardBlockType = state.yieldBalance.rewardBlockType, - onRewardsClick = clickIntents::openRewardsValidators, - isBalanceHidden = isBalanceHidden, - ) - SpacerH12() - } - } +@OptIn(ExperimentalFoundationApi::class) +private fun LazyListScope.activeStakingBlock( + state: StakingStates.InitialInfoState.Data, + clickIntents: StakingClickIntents, + isBalanceHidden: Boolean, +) { + if (state.yieldBalance is InnerYieldBalanceState.Data) { + item(ACTIVE_STAKING_BLOCK_KEY) { + Text( + text = stringResource(id = R.string.staking_your_stakes), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.tertiary, + modifier = Modifier + .fillMaxWidth() + .clip(CornersToRound.TOP_2.getShape()) + .background(TangemTheme.colors.background.action) + .padding( + top = TangemTheme.dimens.spacing12, + start = TangemTheme.dimens.spacing12, + end = TangemTheme.dimens.spacing12, + bottom = TangemTheme.dimens.spacing4, + ), + ) } - - if (state.yieldBalance is InnerYieldBalanceState.Data) { - item(key = ACTIVE_STAKING_BLOCK_KEY) { - Column(modifier = Modifier.animateItemPlacement()) { - ActiveStakingBlock( - balances = state.yieldBalance.balance, - onClick = clickIntents::onActiveStake, - isBalanceHidden = isBalanceHidden, - ) - SpacerH12() - } - } - } - - item(STAKE_PRIMARY_BUTTON_KEY) { - StakeButtonBlock(buttonState) + items( + items = state.yieldBalance.balance, + key = { + // Staked balance does not have unique identifier. + // Balance type and group id is used to identify item. + it.id + it.type + }, + ) { balance -> + ActiveStakingBlock( + balance = balance, + onClick = clickIntents::onActiveStake, + isBalanceHidden = isBalanceHidden, + modifier = Modifier + .animateItemPlacement() + .then( + if (state.yieldBalance.balance.last() == balance) { + Modifier.clip(CornersToRound.BOTTOM_2.getShape()) + } else { + Modifier + }, + ), + ) } } } @@ -205,49 +267,29 @@ private fun StakingRewardBlock( @Composable private fun ActiveStakingBlock( - balances: ImmutableList, + balance: BalanceState, onClick: (BalanceState) -> Unit, isBalanceHidden: Boolean, + modifier: Modifier = Modifier, ) { - Column( - modifier = Modifier - .fillMaxWidth() - .clip(TangemTheme.shapes.roundedCornersXMedium) - .background(TangemTheme.colors.background.action), - ) { - Text( - text = stringResource(id = R.string.staking_your_stakes), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.tertiary, - modifier = Modifier.padding( - top = TangemTheme.dimens.spacing12, - start = TangemTheme.dimens.spacing12, - end = TangemTheme.dimens.spacing12, - bottom = TangemTheme.dimens.spacing4, + val (icon, iconTint) = balance.type.getIcon() + InputRowImageInfo( + subtitle = balance.title, + caption = balance.subtitle ?: balance.getAprText(), + infoTitle = balance.fiatAmount.orMaskWithStars(isBalanceHidden), + infoSubtitle = balance.cryptoAmount.orMaskWithStars(isBalanceHidden), + imageUrl = balance.getImage(), + iconRes = icon, + iconTint = iconTint, + modifier = modifier + .background(TangemTheme.colors.background.action) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple(), + enabled = balance.isClickable, + onClick = { onClick(balance) }, ), - ) - balances.forEach { balance -> - key(balance.id) { - val (icon, iconTint) = balance.type.getIcon() - InputRowImageInfo( - subtitle = balance.title, - caption = balance.subtitle ?: balance.getAprText(), - isGrayscaleImage = !balance.isClickable, - infoTitle = balance.fiatAmount.orMaskWithStars(isBalanceHidden), - infoSubtitle = balance.cryptoAmount.orMaskWithStars(isBalanceHidden), - imageUrl = balance.getImage(), - iconRes = icon, - iconTint = iconTint, - modifier = Modifier.clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = rememberRipple(), - enabled = balance.isClickable, - onClick = { onClick(balance) }, - ), - ) - } - } - } + ) } @Composable diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt index 076d61b47d..b9743fb560 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt @@ -21,6 +21,8 @@ internal interface StakingClickIntents : AmountScreenClickIntents { fun onPrevClick() + fun onRefreshSwipe(isRefreshing: Boolean) + fun onInitialInfoBannerClick() fun onInfoClick(infoType: InfoType) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt index 6e833d5ebb..ce71e2b75b 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt @@ -76,7 +76,7 @@ internal class StakingViewModel @Inject constructor( private val stateController: StakingStateController, private val dispatchers: CoroutineDispatcherProvider, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, - private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase, + private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase, private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getUserWalletUseCase: GetUserWalletUseCase, @@ -149,6 +149,7 @@ internal class StakingViewModel @Inject constructor( private val transactionsInProgress: CopyOnWriteArrayList = CopyOnWriteArrayList() private var approvalJobHolder: JobHolder = JobHolder() + private var updateBalancesJobHolder: JobHolder = JobHolder() init { subscribeOnSelectedAppCurrency() @@ -156,6 +157,12 @@ internal class StakingViewModel @Inject constructor( subscribeOnCurrencyStatusUpdates() } + override fun onCleared() { + super.onCleared() + updateBalancesJobHolder.cancel() + approvalJobHolder.cancel() + } + override fun onBackClick() { stakingStateRouter.onBackClick() } @@ -173,7 +180,10 @@ internal class StakingViewModel @Inject constructor( } stakingStateRouter.onNextClick() when { - isInitState() -> stateController.update(SetConfirmationStateLoadingTransformer(yield, appCurrency)) + isInitState() -> { + stateController.update(SetConfirmationStateLoadingTransformer(yield, appCurrency)) + onRefreshSwipe(isRefreshing = false) + } isAssentState() -> getFee(pendingAction) } } @@ -364,6 +374,19 @@ internal class StakingViewModel @Inject constructor( stakingStateRouter.onPrevClick() } + override fun onRefreshSwipe(isRefreshing: Boolean) { + stateController.update(SetInitialLoadingStateTransformer(isRefreshing)) + viewModelScope.launch { + val balancesUpdate = async { updateStakeBalance() } + val networkUpdate = async { updateNetworkStatuses(0) } + + awaitAll(balancesUpdate, networkUpdate) + }.saveIn(updateBalancesJobHolder) + .invokeOnCompletion { + stateController.update(SetInitialLoadingStateTransformer(false)) + } + } + override fun onInitialInfoBannerClick() { innerRouter.openUrl(WHAT_IS_STAKING_ARTICLE_URL) } @@ -711,33 +734,42 @@ internal class StakingViewModel @Inject constructor( stateController.update(SetConfirmationStateResetAssentTransformer) }, ) - getCryptoCurrencyStatusSyncUseCase(userWalletId, cryptoCurrencyId).fold( - ifRight = { - feeCryptoCurrencyStatus = getFeePaidCryptoCurrencyStatusSyncUseCase(userWalletId, it).getOrNull() - val isAnyTokenStaked = isAnyTokenStakedUseCase(userWalletId).getOrNull() ?: false - cryptoCurrencyStatus = it + getCurrencyStatusUpdatesUseCase(userWalletId, cryptoCurrencyId, false) + .conflate() + .distinctUntilChanged() + .filter { value.currentStep == StakingStep.InitialInfo } + .onEach { maybeStatus -> + maybeStatus.fold( + ifRight = { status -> + feeCryptoCurrencyStatus = + getFeePaidCryptoCurrencyStatusSyncUseCase(userWalletId, status).getOrNull() + cryptoCurrencyStatus = status + val isAnyTokenStaked = isAnyTokenStakedUseCase(userWalletId).getOrNull() ?: false - setupApprovalNeeded() - checkIfSubtractAvailable() + setupApprovalNeeded() + checkIfSubtractAvailable() - stateController.update( - transformer = SetInitialDataStateTransformer( - clickIntents = this@StakingViewModel, - yield = yield, - isApprovalNeeded = stakingApproval is StakingApproval.Needed, - isAnyTokenStaked = isAnyTokenStaked, - cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, - userWalletProvider = Provider { userWallet }, - appCurrencyProvider = Provider { appCurrency }, - ), + stateController.update( + transformer = SetInitialDataStateTransformer( + clickIntents = this@StakingViewModel, + yield = yield, + isAnyTokenStaked = isAnyTokenStaked, + isApprovalNeeded = stakingApproval is StakingApproval.Needed, + cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, + userWalletProvider = Provider { userWallet }, + appCurrencyProvider = Provider { appCurrency }, + ), + ) + }, + ifLeft = { error -> + Timber.e(error.toString()) + stakingEventFactory.createGenericErrorAlert(error.toString()) + stateController.update(SetConfirmationStateResetAssentTransformer) + }, ) - }, - ifLeft = { - Timber.e(it.toString()) - stakingEventFactory.createGenericErrorAlert(it.toString()) - stateController.update(SetConfirmationStateResetAssentTransformer) - }, - ) + } + .flowOn(dispatchers.main) + .launchIn(viewModelScope) } } @@ -850,11 +882,11 @@ internal class StakingViewModel @Inject constructor( } } - private suspend fun updateNetworkStatuses() { + private suspend fun updateNetworkStatuses(delay: Long = BALANCE_UPDATE_DELAY) { updateDelayedNetworkStatusUseCase( userWalletId = userWalletId, network = cryptoCurrencyStatus.currency.network, - delayMillis = BALANCE_UPDATE_DELAY, + delayMillis = delay, refresh = true, ) } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt index a87e9b10a4..4aeac3dd4b 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt @@ -139,6 +139,6 @@ internal class TokenDetailsSkeletonStateConverter( private fun createPullToRefresh(): PullToRefreshConfig = PullToRefreshConfig( isRefreshing = false, - onRefresh = { clickIntents.onRefreshSwipe(it.value) } , + onRefresh = { clickIntents.onRefreshSwipe(it.value) }, ) } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index 9ad67ab5bf..0cda424f1a 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt @@ -81,7 +81,7 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon ) { scaffoldPaddings -> val pullRefreshState = rememberPullRefreshState( refreshing = state.pullToRefreshConfig.isRefreshing, - onRefresh = { state.pullToRefreshConfig.onRefresh(PullToRefreshConfig.ShowRefreshState()) } , + onRefresh = { state.pullToRefreshConfig.onRefresh(PullToRefreshConfig.ShowRefreshState()) }, ) val txHistoryItems = if (state.txHistoryState is TxHistoryState.Content) {