Updated on 2026-08-14
This commit is contained in:
parent
4a29162e11
commit
1716318447
8 changed files with 74 additions and 22 deletions
|
|
@ -33,7 +33,7 @@ internal class TokenListAnalyticsSender @Inject constructor(
|
|||
private val mutex = Mutex()
|
||||
|
||||
suspend fun send(displayedUiState: WalletState?, userWallet: UserWallet, tokenList: TokenList) {
|
||||
if (screenLifecycleProvider.isBackground) return
|
||||
if (screenLifecycleProvider.isBackgroundState.value) return
|
||||
if (displayedUiState == null || displayedUiState.pullToRefreshConfig.isRefreshing) return
|
||||
if (tokenList.totalFiatBalance is TokenList.FiatBalance.Loading) return
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
|||
) {
|
||||
|
||||
fun send(displayedUiState: WalletState?, newWarnings: List<WalletNotification>) {
|
||||
if (screenLifecycleProvider.isBackground) return
|
||||
if (screenLifecycleProvider.isBackgroundState.value) return
|
||||
if (newWarnings.isEmpty()) return
|
||||
if (displayedUiState == null || displayedUiState.pullToRefreshConfig.isRefreshing) return
|
||||
|
||||
|
|
|
|||
|
|
@ -6,4 +6,10 @@ package com.tangem.feature.wallet.presentation.wallet.state.model
|
|||
* @property isRefreshing state is indicator visible
|
||||
* @property onRefresh lambda be invoked when pulled to refresh
|
||||
*/
|
||||
data class WalletPullToRefreshConfig(val isRefreshing: Boolean, val onRefresh: () -> Unit)
|
||||
data class WalletPullToRefreshConfig(val isRefreshing: Boolean, val onRefresh: (ShowRefreshState) -> Unit) {
|
||||
|
||||
@JvmInline
|
||||
value class ShowRefreshState(
|
||||
val value: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ internal class WalletLoadingStateFactory(private val clickIntents: WalletClickIn
|
|||
}
|
||||
|
||||
private fun createPullToRefreshConfig(): WalletPullToRefreshConfig {
|
||||
return WalletPullToRefreshConfig(onRefresh = clickIntents::onRefreshSwipe, isRefreshing = false)
|
||||
return WalletPullToRefreshConfig(onRefresh = { clickIntents.onRefreshSwipe(it.value) }, isRefreshing = false)
|
||||
}
|
||||
|
||||
private fun UserWallet.toLoadingWalletCardState(): WalletCardState {
|
||||
|
|
|
|||
|
|
@ -135,7 +135,9 @@ private fun WalletContent(
|
|||
.padding(horizontal = horizontalPadding)
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize().testTag(TestTags.WALLET_SCREEN),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.WALLET_SCREEN),
|
||||
contentPadding = PaddingValues(
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
bottom = TangemTheme.dimens.spacing92,
|
||||
|
|
@ -317,7 +319,9 @@ private fun BaseScaffoldManageTokenRedesign(
|
|||
content = { paddingValues ->
|
||||
val pullRefreshState = rememberPullRefreshState(
|
||||
refreshing = selectedWallet.pullToRefreshConfig.isRefreshing,
|
||||
onRefresh = selectedWallet.pullToRefreshConfig.onRefresh,
|
||||
onRefresh = {
|
||||
selectedWallet.pullToRefreshConfig.onRefresh(WalletPullToRefreshConfig.ShowRefreshState(true))
|
||||
},
|
||||
)
|
||||
|
||||
Column(
|
||||
|
|
@ -503,7 +507,9 @@ private fun BaseScaffold(
|
|||
content = {
|
||||
val pullRefreshState = rememberPullRefreshState(
|
||||
refreshing = selectedWallet.pullToRefreshConfig.isRefreshing,
|
||||
onRefresh = selectedWallet.pullToRefreshConfig.onRefresh,
|
||||
onRefresh = {
|
||||
selectedWallet.pullToRefreshConfig.onRefresh(WalletPullToRefreshConfig.ShowRefreshState(true))
|
||||
},
|
||||
)
|
||||
|
||||
Box(
|
||||
|
|
|
|||
|
|
@ -3,19 +3,21 @@ package com.tangem.feature.wallet.presentation.wallet.utils
|
|||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@ViewModelScoped
|
||||
internal class ScreenLifecycleProvider @Inject constructor() : DefaultLifecycleObserver {
|
||||
|
||||
var isBackground: Boolean = true
|
||||
private set
|
||||
private val _isBackgroundState = MutableStateFlow(false)
|
||||
val isBackgroundState: StateFlow<Boolean> = _isBackgroundState
|
||||
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
isBackground = false
|
||||
_isBackgroundState.value = false
|
||||
}
|
||||
|
||||
override fun onPause(owner: LifecycleOwner) {
|
||||
isBackground = true
|
||||
_isBackgroundState.value = true
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContent
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent.DemonstrateWalletsScrollPreview.Direction
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletPullToRefreshConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
|
||||
|
|
@ -31,7 +32,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -61,7 +62,9 @@ internal class WalletViewModel @Inject constructor(
|
|||
val uiState: StateFlow<WalletScreenState> = stateHolder.uiState
|
||||
|
||||
private lateinit var router: InnerWalletRouter
|
||||
private var walletsUpdateJobHolder: JobHolder = JobHolder()
|
||||
private val walletsUpdateJobHolder = JobHolder()
|
||||
private val refreshWalletJobHolder = JobHolder()
|
||||
private var needToRefreshWallet = false
|
||||
|
||||
init {
|
||||
analyticsEventsHandler.send(WalletScreenAnalyticsEvent.MainScreen.ScreenOpened)
|
||||
|
|
@ -71,6 +74,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
subscribeToUserWalletsUpdates()
|
||||
subscribeOnBalanceHiding()
|
||||
subscribeOnSelectedWalletFlow()
|
||||
subscribeToScreenBackgroundState()
|
||||
}
|
||||
|
||||
fun setWalletRouter(router: InnerWalletRouter) {
|
||||
|
|
@ -150,6 +154,36 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// We need to update the current wallet if the application was in the background for more than 10 seconds
|
||||
// and then returned to the foreground
|
||||
private fun subscribeToScreenBackgroundState() {
|
||||
screenLifecycleProvider.isBackgroundState
|
||||
.onEach { isBackground ->
|
||||
refreshWalletJobHolder.cancel()
|
||||
when {
|
||||
isBackground -> needToRefreshTimer()
|
||||
needToRefreshWallet && !isBackground -> triggerRefreshWallet()
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun needToRefreshTimer() {
|
||||
viewModelScope.launch {
|
||||
delay(REFRESH_WALLET_BACKGROUND_TIMER_MILLIS)
|
||||
needToRefreshWallet = true
|
||||
}.saveIn(refreshWalletJobHolder)
|
||||
}
|
||||
|
||||
private fun triggerRefreshWallet() {
|
||||
needToRefreshWallet = false
|
||||
val state = stateHolder.uiState.value
|
||||
val wallet = state.wallets.getOrNull(state.selectedWalletIndex) ?: return
|
||||
wallet.pullToRefreshConfig.onRefresh.invoke(
|
||||
WalletPullToRefreshConfig.ShowRefreshState(false),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun updateWallets(action: WalletsUpdateActionResolver.Action) {
|
||||
when (action) {
|
||||
is WalletsUpdateActionResolver.Action.InitializeWallets -> initializeWallets(action)
|
||||
|
|
@ -280,7 +314,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun closeScreen(screen: AppScreen) {
|
||||
if (!screenLifecycleProvider.isBackground) {
|
||||
if (!screenLifecycleProvider.isBackgroundState.value) {
|
||||
stateHolder.clear()
|
||||
router.popBackStack(screen = screen)
|
||||
}
|
||||
|
|
@ -296,4 +330,8 @@ internal class WalletViewModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val REFRESH_WALLET_BACKGROUND_TIMER_MILLIS = 10000L
|
||||
}
|
||||
}
|
||||
|
|
@ -77,17 +77,17 @@ internal class WalletClickIntents @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onRefreshSwipe() {
|
||||
fun onRefreshSwipe(showRefreshState: Boolean) {
|
||||
when (stateHolder.getSelectedWallet()) {
|
||||
is WalletState.MultiCurrency.Content -> {
|
||||
analyticsEventHandler.send(PortfolioEvent.Refreshed)
|
||||
refreshMultiCurrencyContent()
|
||||
refreshMultiCurrencyContent(showRefreshState)
|
||||
}
|
||||
is WalletState.SingleCurrency.Content,
|
||||
is WalletState.Visa.Content,
|
||||
-> {
|
||||
analyticsEventHandler.send(PortfolioEvent.Refreshed)
|
||||
refreshSingleCurrencyContent()
|
||||
refreshSingleCurrencyContent(showRefreshState)
|
||||
}
|
||||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
|
|
@ -97,14 +97,14 @@ internal class WalletClickIntents @Inject constructor(
|
|||
}
|
||||
|
||||
fun onReloadClick() {
|
||||
refreshSingleCurrencyContent()
|
||||
refreshSingleCurrencyContent(showRefreshState = true)
|
||||
}
|
||||
|
||||
private fun refreshMultiCurrencyContent() {
|
||||
private fun refreshMultiCurrencyContent(showRefreshState: Boolean) {
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
stateHolder.update(
|
||||
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = true),
|
||||
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = showRefreshState),
|
||||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
|
|
@ -126,11 +126,11 @@ internal class WalletClickIntents @Inject constructor(
|
|||
|
||||
// FIXME: refreshSingleCurrencyContent mustn't update the TxHistory and Buttons. It only must fetch primary
|
||||
// currency. Now it not works because GetPrimaryCurrency's subscriber uses .distinctUntilChanged()
|
||||
private fun refreshSingleCurrencyContent() {
|
||||
private fun refreshSingleCurrencyContent(showRefreshState: Boolean) {
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
stateHolder.update(
|
||||
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = true),
|
||||
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = showRefreshState),
|
||||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue