Updated on 2026-08-14
This commit is contained in:
parent
584d99e95e
commit
a57d077863
9 changed files with 313 additions and 81 deletions
|
|
@ -20,7 +20,7 @@ internal object WalletPreviewData {
|
|||
val walletTopBarConfig = WalletTopBarConfig(onScanCardClick = {}, onMoreClick = {})
|
||||
|
||||
val walletCardContentState = WalletCardState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
id = UserWalletId(UUID.randomUUID().toString()),
|
||||
title = "Wallet 1",
|
||||
balance = "8923,05 $",
|
||||
additionalInfo = "3 cards • Seed enabled",
|
||||
|
|
@ -29,7 +29,7 @@ internal object WalletPreviewData {
|
|||
)
|
||||
|
||||
val walletCardLoadingState = WalletCardState.Loading(
|
||||
id = UUID.randomUUID().toString(),
|
||||
id = UserWalletId(UUID.randomUUID().toString()),
|
||||
title = "Wallet 1",
|
||||
additionalInfo = "3 cards • Seed enabled",
|
||||
imageResId = R.drawable.ill_businessman_3d,
|
||||
|
|
@ -37,7 +37,7 @@ internal object WalletPreviewData {
|
|||
)
|
||||
|
||||
val walletCardHiddenContentState = WalletCardState.HiddenContent(
|
||||
id = UUID.randomUUID().toString(),
|
||||
id = UserWalletId(UUID.randomUUID().toString()),
|
||||
title = "Wallet 1",
|
||||
additionalInfo = "3 cards • Seed enabled",
|
||||
imageResId = R.drawable.ill_businessman_3d,
|
||||
|
|
@ -45,7 +45,7 @@ internal object WalletPreviewData {
|
|||
)
|
||||
|
||||
val walletCardErrorState = WalletCardState.Error(
|
||||
id = UUID.randomUUID().toString(),
|
||||
id = UserWalletId(UUID.randomUUID().toString()),
|
||||
title = "Wallet 1",
|
||||
additionalInfo = "3 cards • Seed enabled",
|
||||
imageResId = R.drawable.ill_businessman_3d,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.activity.compose.BackHandler
|
|||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
|
|
@ -40,8 +41,9 @@ internal class DefaultWalletRouter(private val navigationStateHolder: Navigation
|
|||
startDestination = WalletScreens.WALLET.name,
|
||||
) {
|
||||
composable(WalletScreens.WALLET.name) {
|
||||
val viewModel = hiltViewModel<WalletViewModel>()
|
||||
.apply { router = this@DefaultWalletRouter }
|
||||
val viewModel = hiltViewModel<WalletViewModel>().apply { router = this@DefaultWalletRouter }
|
||||
LocalLifecycleOwner.current.lifecycle.addObserver(observer = viewModel)
|
||||
|
||||
WalletScreen(state = viewModel.uiState)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ package com.tangem.feature.wallet.presentation.wallet.state
|
|||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/** Wallet card state */
|
||||
@Immutable
|
||||
internal sealed interface WalletCardState {
|
||||
|
||||
/** Id */
|
||||
val id: String
|
||||
val id: UserWalletId
|
||||
|
||||
/** Title */
|
||||
val title: String
|
||||
|
|
@ -34,7 +35,7 @@ internal sealed interface WalletCardState {
|
|||
* @property balance wallet balance
|
||||
*/
|
||||
data class Content(
|
||||
override val id: String,
|
||||
override val id: UserWalletId,
|
||||
override val title: String,
|
||||
override val additionalInfo: String,
|
||||
override val imageResId: Int?,
|
||||
|
|
@ -52,7 +53,7 @@ internal sealed interface WalletCardState {
|
|||
* @property onClick lambda be invoked when wallet card is clicked
|
||||
*/
|
||||
data class Loading(
|
||||
override val id: String,
|
||||
override val id: UserWalletId,
|
||||
override val title: String,
|
||||
override val additionalInfo: String,
|
||||
override val imageResId: Int?,
|
||||
|
|
@ -69,7 +70,7 @@ internal sealed interface WalletCardState {
|
|||
* @property onClick lambda be invoked when wallet card is clicked
|
||||
*/
|
||||
data class HiddenContent(
|
||||
override val id: String,
|
||||
override val id: UserWalletId,
|
||||
override val title: String,
|
||||
override val additionalInfo: String,
|
||||
override val imageResId: Int?,
|
||||
|
|
@ -86,7 +87,7 @@ internal sealed interface WalletCardState {
|
|||
* @property onClick lambda be invoked when wallet card is clicked
|
||||
*/
|
||||
data class Error(
|
||||
override val id: String,
|
||||
override val id: UserWalletId,
|
||||
override val title: String,
|
||||
override val additionalInfo: String,
|
||||
override val imageResId: Int?,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package com.tangem.feature.wallet.presentation.wallet.state
|
|||
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Wallet screen state holder
|
||||
|
|
@ -26,6 +28,44 @@ internal sealed class WalletStateHolder(
|
|||
open val bottomSheet: WalletBottomSheetConfig? = null,
|
||||
) {
|
||||
|
||||
fun copySealed(
|
||||
onBackClick: () -> Unit = this.onBackClick,
|
||||
topBarConfig: WalletTopBarConfig = this.topBarConfig,
|
||||
walletsListConfig: WalletsListConfig = this.walletsListConfig,
|
||||
pullToRefreshConfig: WalletPullToRefreshConfig = this.pullToRefreshConfig,
|
||||
contentItems: ImmutableList<WalletContentItemState> = this.contentItems,
|
||||
notifications: ImmutableList<WalletNotification> = this.notifications,
|
||||
bottomSheet: WalletBottomSheetConfig? = this.bottomSheet,
|
||||
): WalletStateHolder {
|
||||
return when (this) {
|
||||
is MultiCurrencyContent -> this.copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
contentItems = contentItems as ImmutableList<WalletContentItemState.MultiCurrencyItem>,
|
||||
notifications = notifications,
|
||||
bottomSheet = bottomSheet,
|
||||
)
|
||||
is SingleCurrencyContent -> this.copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
contentItems = contentItems as ImmutableList<WalletContentItemState.SingleCurrencyItem>,
|
||||
notifications = notifications,
|
||||
bottomSheet = bottomSheet,
|
||||
)
|
||||
is UnlockWalletContent -> this.copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
)
|
||||
is Loading -> copy(onBackClick = onBackClick)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multi currency wallet content state
|
||||
*
|
||||
|
|
@ -44,7 +84,7 @@ internal sealed class WalletStateHolder(
|
|||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val contentItems: ImmutableList<WalletContentItemState.MultiCurrencyItem>,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
override val bottomSheet: WalletBottomSheetConfig,
|
||||
override val bottomSheet: WalletBottomSheetConfig? = null,
|
||||
val onOrganizeTokensClick: () -> Unit,
|
||||
) : WalletStateHolder(
|
||||
onBackClick = onBackClick,
|
||||
|
|
@ -75,7 +115,7 @@ internal sealed class WalletStateHolder(
|
|||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val contentItems: ImmutableList<WalletContentItemState.SingleCurrencyItem>,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
override val bottomSheet: WalletBottomSheetConfig,
|
||||
override val bottomSheet: WalletBottomSheetConfig? = null,
|
||||
val buttons: ImmutableList<ActionButtonConfig>,
|
||||
val marketPriceBlockState: MarketPriceBlockState,
|
||||
) : WalletStateHolder(
|
||||
|
|
@ -87,4 +127,67 @@ internal sealed class WalletStateHolder(
|
|||
notifications = notifications,
|
||||
bottomSheet = bottomSheet,
|
||||
)
|
||||
|
||||
/**
|
||||
* Unlock wallet content state
|
||||
*
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
* @property topBarConfig top bar config
|
||||
* @property walletsListConfig wallets list config
|
||||
* @property onUnlockWalletsNotificationClick lambda be invoked when unlock wallets notification is clicked
|
||||
* @property onBottomSheetDismissRequest lambda be invoked when bottom sheet is dismissed
|
||||
* @property onUnlockClick lambda be invoked when unlock button is clicked
|
||||
* @property onScanClick lambda be invoked when scan card button is clicked
|
||||
*/
|
||||
data class UnlockWalletContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
val onUnlockWalletsNotificationClick: () -> Unit,
|
||||
val onBottomSheetDismissRequest: () -> Unit,
|
||||
val onUnlockClick: () -> Unit,
|
||||
val onScanClick: () -> Unit,
|
||||
) : WalletStateHolder(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
contentItems = persistentListOf(WalletContentItemState.Loading),
|
||||
notifications = persistentListOf(WalletNotification.UnlockWallets(onUnlockWalletsNotificationClick)),
|
||||
bottomSheet = WalletBottomSheetConfig(
|
||||
isShow = false,
|
||||
onDismissRequest = onBottomSheetDismissRequest,
|
||||
content = WalletBottomSheetConfig.BottomSheetContentConfig.UnlockWallets(
|
||||
onUnlockClick = onUnlockClick,
|
||||
onScanClick = onScanClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Loading state
|
||||
*
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
*/
|
||||
data class Loading(override val onBackClick: () -> Unit) : WalletStateHolder(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = WalletTopBarConfig(onScanCardClick = {}, onMoreClick = {}),
|
||||
walletsListConfig = WalletsListConfig(
|
||||
selectedWalletIndex = 0,
|
||||
wallets = persistentListOf(
|
||||
WalletCardState.Loading(
|
||||
id = UserWalletId(stringValue = ""),
|
||||
title = "",
|
||||
additionalInfo = "",
|
||||
imageResId = null,
|
||||
),
|
||||
),
|
||||
onWalletChange = {},
|
||||
),
|
||||
pullToRefreshConfig = WalletPullToRefreshConfig(isRefreshing = false, onRefresh = {}),
|
||||
contentItems = persistentListOf(WalletContentItemState.Loading),
|
||||
notifications = persistentListOf(),
|
||||
bottomSheet = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.builder
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.*
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class WalletStateFactory(
|
||||
private val routerProvider: Provider<InnerWalletRouter>,
|
||||
private val onScanCardClick: () -> Unit,
|
||||
private val onWalletChange: (Int) -> Unit,
|
||||
private val onRefreshSwipe: () -> Unit,
|
||||
) {
|
||||
|
||||
fun getInitialState(): WalletStateHolder = WalletStateHolder.Loading(onBackClick = ::onBackClick)
|
||||
|
||||
fun getContentState(wallets: List<UserWallet>): WalletStateHolder {
|
||||
val cardTypeResolver = requireNotNull(wallets.firstOrNull()).scanResponse.cardTypesResolver
|
||||
|
||||
return if (cardTypeResolver.isMultiwalletAllowed()) {
|
||||
createMultiCurrencyState(wallets)
|
||||
} else {
|
||||
createSingleCurrencyState(wallets)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createMultiCurrencyState(wallets: List<UserWallet>): WalletStateHolder.MultiCurrencyContent {
|
||||
return WalletStateHolder.MultiCurrencyContent(
|
||||
onBackClick = ::onBackClick,
|
||||
topBarConfig = createTopBarConfig(),
|
||||
walletsListConfig = createWalletsListConfig(wallets),
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
contentItems = persistentListOf(),
|
||||
notifications = persistentListOf(), // TODO: create notifications
|
||||
bottomSheet = WalletBottomSheetConfig(
|
||||
// TODO: check notifications
|
||||
isShow = false,
|
||||
onDismissRequest = {},
|
||||
content = WalletBottomSheetConfig.BottomSheetContentConfig.LikeTangemApp(
|
||||
onRateTheAppClick = {},
|
||||
onShareClick = {},
|
||||
),
|
||||
),
|
||||
onOrganizeTokensClick = routerProvider()::openOrganizeTokensScreen,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSingleCurrencyState(wallets: List<UserWallet>): WalletStateHolder.SingleCurrencyContent {
|
||||
return WalletStateHolder.SingleCurrencyContent(
|
||||
onBackClick = ::onBackClick,
|
||||
topBarConfig = createTopBarConfig(),
|
||||
walletsListConfig = createWalletsListConfig(wallets),
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
contentItems = persistentListOf(),
|
||||
notifications = persistentListOf(), // TODO: create notifications
|
||||
bottomSheet = WalletBottomSheetConfig(
|
||||
// TODO: check notifications
|
||||
isShow = false,
|
||||
onDismissRequest = {},
|
||||
content = WalletBottomSheetConfig.BottomSheetContentConfig.LikeTangemApp(
|
||||
onRateTheAppClick = {},
|
||||
onShareClick = {},
|
||||
),
|
||||
),
|
||||
buttons = WalletPreviewData.singleWalletScreenState.buttons, // TODO: create buttons
|
||||
// TODO: create market price block
|
||||
marketPriceBlockState = WalletPreviewData.singleWalletScreenState.marketPriceBlockState,
|
||||
)
|
||||
}
|
||||
|
||||
private fun onBackClick() = routerProvider().popBackStack()
|
||||
|
||||
private fun createTopBarConfig(): WalletTopBarConfig {
|
||||
return WalletTopBarConfig(
|
||||
onScanCardClick = onScanCardClick,
|
||||
onMoreClick = routerProvider()::openDetailsScreen,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createWalletsListConfig(wallets: List<UserWallet>): WalletsListConfig {
|
||||
return WalletsListConfig(
|
||||
selectedWalletIndex = 0,
|
||||
wallets = wallets.map { wallet ->
|
||||
WalletCardState.Loading(
|
||||
id = if (wallet.scanResponse.cardTypesResolver.isMultiwalletAllowed()) { // TODO
|
||||
UserWalletId("123")
|
||||
} else {
|
||||
UserWalletId("321")
|
||||
},
|
||||
// TODO: wallet.walletId,
|
||||
title = wallet.name,
|
||||
additionalInfo = "", // TODO
|
||||
imageResId = WalletImageResolver.resolve(cardTypesResolver = wallet.scanResponse.cardTypesResolver),
|
||||
)
|
||||
}.toImmutableList(),
|
||||
onWalletChange = onWalletChange,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPullToRefreshConfig(): WalletPullToRefreshConfig {
|
||||
return WalletPullToRefreshConfig(isRefreshing = false, onRefresh = onRefreshSwipe)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,10 +19,8 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.utils.ScrollOffsetCollector
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
|
||||
/**
|
||||
* Wallets list component
|
||||
|
|
@ -32,7 +30,7 @@ import kotlinx.coroutines.InternalCoroutinesApi
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalFoundationApi::class, InternalCoroutinesApi::class)
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
internal fun WalletsList(config: WalletsListConfig, lazyListState: LazyListState, modifier: Modifier = Modifier) {
|
||||
val horizontalCardPadding = TangemTheme.dimens.spacing16
|
||||
|
|
@ -45,7 +43,7 @@ internal fun WalletsList(config: WalletsListConfig, lazyListState: LazyListState
|
|||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
flingBehavior = rememberSnapFlingBehavior(lazyListState = lazyListState),
|
||||
) {
|
||||
items(items = config.wallets, key = WalletCardState::id) { state ->
|
||||
items(items = config.wallets, key = { it.id.stringValue }) { state ->
|
||||
WalletCard(state = state, modifier = Modifier.width(itemWidth))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,21 +12,27 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
*/
|
||||
internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastIndex: Int): Modifier = composed {
|
||||
val modifierWithHorizontalPadding = this.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
when (currentIndex) {
|
||||
0 -> {
|
||||
val isSingleItem = currentIndex == 0 && lastIndex == 0
|
||||
when {
|
||||
isSingleItem -> {
|
||||
modifierWithHorizontalPadding
|
||||
.padding(top = TangemTheme.dimens.spacing14)
|
||||
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
|
||||
}
|
||||
currentIndex == 0 -> {
|
||||
modifierWithHorizontalPadding
|
||||
.padding(top = TangemTheme.dimens.spacing14)
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
shape = RoundedCornerShape(
|
||||
topStart = TangemTheme.dimens.radius16,
|
||||
topEnd = TangemTheme.dimens.radius16,
|
||||
),
|
||||
)
|
||||
}
|
||||
lastIndex -> {
|
||||
currentIndex == lastIndex -> {
|
||||
modifierWithHorizontalPadding
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
shape = RoundedCornerShape(
|
||||
bottomStart = TangemTheme.dimens.radius16,
|
||||
bottomEnd = TangemTheme.dimens.radius16,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ internal class TokenListToWalletStateConverter(
|
|||
return when (currentState) {
|
||||
is MultiCurrencyContent -> currentState.updateWithTokenList(value)
|
||||
is SingleCurrencyContent -> currentState.updateWithTokenList(value)
|
||||
is WalletStateHolder.Loading,
|
||||
is WalletStateHolder.UnlockWalletContent,
|
||||
-> currentState
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,33 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.*
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.core.ui.components.transactions.TransactionState
|
||||
import com.tangem.domain.card.GetAccessCodeSavingStatusUseCase
|
||||
import com.tangem.domain.card.GetBiometricsStatusUseCase
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.SetAccessCodeRequestPolicyUseCase
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
|
||||
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.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletTopBarConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.LoadingItemsProvider.getLoadingMultiCurrencyTokens
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.builder.WalletStateFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListErrorToWalletStateConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
|
@ -48,50 +46,66 @@ internal class WalletViewModel @Inject constructor(
|
|||
private val setAccessCodeRequestPolicyUseCase: SetAccessCodeRequestPolicyUseCase,
|
||||
private val getAccessCodeSavingStatusUseCase: GetAccessCodeSavingStatusUseCase,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
private val getWalletsUseCase: GetWalletsUseCase,
|
||||
private val scanCardProcessor: ScanCardProcessor,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : ViewModel() {
|
||||
) : ViewModel(), DefaultLifecycleObserver {
|
||||
|
||||
/** Feature router */
|
||||
var router: InnerWalletRouter by Delegates.notNull()
|
||||
|
||||
private val stateFactory = WalletStateFactory(
|
||||
routerProvider = Provider { router },
|
||||
onScanCardClick = ::onScanCardClick,
|
||||
onWalletChange = ::changeWallet,
|
||||
onRefreshSwipe = ::refreshContent,
|
||||
)
|
||||
|
||||
/** Screen state */
|
||||
var uiState by mutableStateOf(getInitialState())
|
||||
var uiState by mutableStateOf(stateFactory.getInitialState())
|
||||
private set
|
||||
|
||||
private var getTokenListJob: Job? = null
|
||||
set(value) {
|
||||
field?.cancel()
|
||||
field = value
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
getWalletsUseCase()
|
||||
.distinctUntilChanged()
|
||||
.flowWithLifecycle(owner.lifecycle)
|
||||
.onEach { wallets ->
|
||||
if (wallets.isEmpty()) return@onEach
|
||||
|
||||
uiState = stateFactory.getContentState(wallets = wallets)
|
||||
updateContentItems()
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun updateContentItems() {
|
||||
getTokenListUseCase(
|
||||
userWalletId = uiState.walletsListConfig.wallets.get(
|
||||
index = uiState.walletsListConfig.selectedWalletIndex,
|
||||
).id,
|
||||
)
|
||||
.distinctUntilChanged()
|
||||
.mapLatest(::updateStateWithTokenListOrError)
|
||||
.onEach {
|
||||
uiState = it.copySealed(
|
||||
pullToRefreshConfig = uiState.pullToRefreshConfig.copy(isRefreshing = getRefreshingStatus()),
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun getRefreshingStatus(): Boolean {
|
||||
return uiState.contentItems.any { state ->
|
||||
val isMultiCurrencyItem = state as? WalletContentItemState.MultiCurrencyItem.Token
|
||||
val isSingleCurrencyItem = state as? WalletContentItemState.SingleCurrencyItem.Transaction
|
||||
|
||||
isMultiCurrencyItem?.state is TokenItemState.Loading ||
|
||||
isSingleCurrencyItem?.state is TransactionState.Loading ||
|
||||
state is WalletContentItemState.Loading
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_TASK_KEY] Use production data instead of WalletPreviewData
|
||||
private fun getInitialState(): WalletStateHolder {
|
||||
val state = WalletPreviewData.multicurrencyWalletScreenState.copy(
|
||||
onBackClick = ::onBackClick,
|
||||
topBarConfig = createTopBarConfig(),
|
||||
walletsListConfig = WalletPreviewData.multicurrencyWalletScreenState.walletsListConfig.copy(
|
||||
onWalletChange = ::selectWallet,
|
||||
),
|
||||
contentItems = getLoadingMultiCurrencyTokens(),
|
||||
)
|
||||
|
||||
val selectedWalletIndex = state.walletsListConfig.selectedWalletIndex
|
||||
val selectedWalletId = WalletPreviewData.wallets.keys.elementAt(selectedWalletIndex)
|
||||
launchGetTokenListJob(selectedWalletId)
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
private fun onBackClick() {
|
||||
router.popBackStack()
|
||||
}
|
||||
|
||||
private fun createTopBarConfig(): WalletTopBarConfig {
|
||||
return WalletTopBarConfig(
|
||||
onScanCardClick = ::onScanCardClick,
|
||||
onMoreClick = { router.openDetailsScreen() },
|
||||
)
|
||||
}
|
||||
|
||||
private fun onScanCardClick() {
|
||||
|
|
@ -124,12 +138,9 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_TASK_KEY] Use production data instead of WalletPreviewData
|
||||
private fun selectWallet(index: Int) {
|
||||
private fun changeWallet(index: Int) {
|
||||
if (uiState.walletsListConfig.selectedWalletIndex == index) return
|
||||
|
||||
Log.i("WalletViewModel", "selectWallet: $index")
|
||||
|
||||
uiState = when (val state = uiState) {
|
||||
is WalletStateHolder.MultiCurrencyContent -> state.copy(
|
||||
walletsListConfig = uiState.walletsListConfig.copy(selectedWalletIndex = index),
|
||||
|
|
@ -137,19 +148,18 @@ internal class WalletViewModel @Inject constructor(
|
|||
is WalletStateHolder.SingleCurrencyContent -> state.copy(
|
||||
walletsListConfig = uiState.walletsListConfig.copy(selectedWalletIndex = index),
|
||||
)
|
||||
is WalletStateHolder.UnlockWalletContent -> state.copy(
|
||||
walletsListConfig = uiState.walletsListConfig.copy(selectedWalletIndex = index),
|
||||
)
|
||||
is WalletStateHolder.Loading -> state
|
||||
}
|
||||
|
||||
val selectedWalletId = WalletPreviewData.wallets.keys.elementAt(index)
|
||||
launchGetTokenListJob(selectedWalletId)
|
||||
updateContentItems()
|
||||
}
|
||||
|
||||
private fun launchGetTokenListJob(userWalletId: UserWalletId) {
|
||||
getTokenListJob = getTokenListUseCase(userWalletId)
|
||||
.distinctUntilChanged()
|
||||
.mapLatest(::updateStateWithTokenListOrError)
|
||||
.onEach { uiState = it }
|
||||
.flowOn(Dispatchers.Default)
|
||||
.launchIn(viewModelScope)
|
||||
private fun refreshContent() {
|
||||
uiState = uiState.copySealed(pullToRefreshConfig = uiState.pullToRefreshConfig.copy(isRefreshing = true))
|
||||
updateContentItems()
|
||||
}
|
||||
|
||||
private fun updateStateWithTokenListOrError(tokenList: Either<TokenListError, TokenList>): WalletStateHolder {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue