Updated on 2026-08-14

This commit is contained in:
Tangem 2024-03-11 21:29:08 +08:00
parent 6bc1179aa3
commit c668c24d27
6 changed files with 65 additions and 49 deletions

View file

@ -10,6 +10,7 @@ internal class ScrollToWalletTransformer(
private val index: Int,
private val currentStateProvider: Provider<WalletScreenState>,
private val stateUpdater: (WalletScreenState) -> Unit,
private val onConsume: () -> Unit = {},
) : WalletScreenStateTransformer {
override fun transform(prevState: WalletScreenState): WalletScreenState {
@ -23,6 +24,8 @@ internal class ScrollToWalletTransformer(
event = consumedEvent(),
),
)
onConsume()
},
),
)

View file

@ -113,7 +113,7 @@ private fun WalletContent(
alertConfig: WalletAlertState?,
) {
var selectedWalletIndex by remember(state.selectedWalletIndex) { mutableIntStateOf(state.selectedWalletIndex) }
val selectedWallet = state.wallets[selectedWalletIndex]
val selectedWallet = state.wallets.getOrElse(selectedWalletIndex) { state.wallets[state.selectedWalletIndex] }
val scaffoldContent: @Composable () -> Unit = {
val movableItemModifier = Modifier.changeWalletAnimator(walletsListState)

View file

@ -20,5 +20,12 @@ internal suspend fun LazyListState.animateScrollByIndex(prevIndex: Int, newIndex
}
private fun calculateOffset(layoutInfo: LazyListLayoutInfo, prevIndex: Int, newIndex: Int): Float {
return layoutInfo.viewportSize.width.times(other = newIndex - prevIndex).toFloat()
val indexDifference = newIndex - prevIndex
val coefficient = if (indexDifference == 0) 1 else indexDifference
return layoutInfo.getItemSizeWithSpacing().times(other = coefficient).toFloat()
}
private fun LazyListLayoutInfo.getItemSizeWithSpacing(): Int {
return viewportSize.width - afterContentPadding - beforeContentPadding + mainAxisItemSpacing
}

View file

@ -5,6 +5,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.navigation.AppScreen
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.settings.CanUseBiometryUseCase
@ -199,6 +200,14 @@ internal class WalletViewModel @Inject constructor(
is WalletsUpdateActionResolver.Action.UpdateWalletName -> {
stateHolder.update(transformer = RenameWalletTransformer(action.selectedWalletId, action.name))
}
is WalletsUpdateActionResolver.Action.NoAccessibleWallets -> {
stateHolder.clear()
router.popBackStack(screen = AppScreen.Welcome)
}
is WalletsUpdateActionResolver.Action.NoWallets -> {
stateHolder.clear()
router.popBackStack(screen = AppScreen.Home)
}
is WalletsUpdateActionResolver.Action.Unknown -> Unit
}
}
@ -274,23 +283,22 @@ internal class WalletViewModel @Inject constructor(
coroutineScope = viewModelScope,
)
if (action.selectedWalletIndex != 0) {
/*
* If card is reset to factory settings, then Compose need some time to draw the WalletScreen.
* Otherwise, scroll isn't happened
*/
withContext(dispatchers.io) { delay(timeMillis = 700) }
/*
* If card is reset to factory settings, then Compose need some time to draw the WalletScreen.
* Otherwise, scroll isn't happened
*/
withContext(dispatchers.io) { delay(timeMillis = 1000) }
scrollToWallet(index = action.selectedWalletIndex)
withContext(dispatchers.io) { delay(timeMillis = 1000) }
}
stateHolder.update(
DeleteWalletTransformer(
selectedWalletIndex = action.selectedWalletIndex,
deletedWalletId = action.deletedWalletId,
),
scrollToWallet(
index = action.selectedWalletIndex,
onConsume = {
stateHolder.update(
DeleteWalletTransformer(
selectedWalletIndex = action.selectedWalletIndex,
deletedWalletId = action.deletedWalletId,
),
)
},
)
}
@ -311,12 +319,13 @@ internal class WalletViewModel @Inject constructor(
)
}
private fun scrollToWallet(index: Int) {
private fun scrollToWallet(index: Int, onConsume: () -> Unit = {}) {
stateHolder.update(
ScrollToWalletTransformer(
index = index,
currentStateProvider = Provider(action = stateHolder::value),
stateUpdater = { newState -> stateHolder.update { newState } },
onConsume = onConsume,
),
)
}

View file

@ -26,17 +26,21 @@ internal class WalletsUpdateActionResolver @Inject constructor(
private var canSaveWallets: Boolean = false
fun resolve(wallets: List<UserWallet>, currentState: WalletScreenState, canSaveWallets: Boolean): Action {
val selectedWallet = wallets.getSelectedWallet() ?: return Action.Unknown
val selectedWallet = wallets.getSelectedWallet()
val action = when {
isFirstInitialization(currentState) -> {
createInitializeWalletsAction(wallets, selectedWallet, canSaveWallets)
val action = if (selectedWallet == null) {
createNoSelectedWalletAction(wallets)
} else {
when {
isFirstInitialization(currentState) -> {
createInitializeWalletsAction(wallets, selectedWallet, canSaveWallets)
}
isReinitialization(canSaveWallets) -> {
this.canSaveWallets = canSaveWallets
Action.ReinitializeWallets(selectedWallet = selectedWallet)
}
else -> getUpdateContentAction(currentState, wallets, selectedWallet)
}
isReinitialization(canSaveWallets) -> {
this.canSaveWallets = canSaveWallets
Action.ReinitializeWallets(selectedWallet = selectedWallet)
}
else -> getUpdateContentAction(currentState, wallets, selectedWallet)
}
Timber.d("Resolved action: $action")
@ -47,11 +51,19 @@ internal class WalletsUpdateActionResolver @Inject constructor(
private fun List<UserWallet>.getSelectedWallet(): UserWallet? {
return when {
isEmpty() -> null
size == 1 -> first()
size == 1 -> if (first().isLocked) null else first()
else -> getSelectedWalletSyncUseCase().fold(ifLeft = { null }, ifRight = { it })
}
}
private fun createNoSelectedWalletAction(wallets: List<UserWallet>): Action {
return when {
wallets.isEmpty() -> Action.NoWallets
wallets.all(UserWallet::isLocked) -> Action.NoAccessibleWallets
else -> Action.Unknown
}
}
private fun isFirstInitialization(state: WalletScreenState): Boolean {
return state.selectedWalletIndex == NOT_INITIALIZED_WALLET_INDEX
}
@ -305,8 +317,10 @@ internal class WalletsUpdateActionResolver @Inject constructor(
}
}
object Unknown : Action() {
override fun toString(): String = "Unknown"
}
data object NoAccessibleWallets : Action()
data object NoWallets : Action()
data object Unknown : Action()
}
}

View file

@ -1,7 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.navigation.AppScreen
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
import com.tangem.domain.wallets.usecase.UpdateWalletUseCase
@ -9,9 +8,7 @@ import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnaly
import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAlertState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.launch
@ -76,21 +73,7 @@ internal class WalletCardClickIntentsImplementor @Inject constructor(
viewModelScope.launch(dispatchers.main) {
walletScreenContentLoader.cancel(userWalletId)
deleteWalletUseCase(userWalletId)
.onRight { popBackIfAllWalletsIsLocked() }
.onLeft { Timber.e(it.toString()) }
}
}
private fun popBackIfAllWalletsIsLocked() {
val wallets = stateHolder.value.wallets.map(WalletState::walletCardState)
val unlockedWallet = wallets.count { it !is WalletCardState.LockedContent }
if (unlockedWallet == 1) {
stateHolder.clear()
router.popBackStack(
screen = if (wallets.size > 1) AppScreen.Welcome else AppScreen.Home,
)
}
}
}