Updated on 2026-08-14
This commit is contained in:
commit
6ad667d49d
77 changed files with 880 additions and 343 deletions
|
|
@ -38,7 +38,7 @@ internal class WalletFragment : ComposeFragment() {
|
|||
setSystemBarsColor(systemBarsColor)
|
||||
}
|
||||
|
||||
_walletRouter.Initialize(fragmentManager = requireActivity().supportFragmentManager)
|
||||
_walletRouter.Initialize(onFinish = requireActivity()::finish)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -190,7 +190,13 @@ internal object WalletPreviewData {
|
|||
)
|
||||
}
|
||||
|
||||
val loadingTokenItemState by lazy { TokenItemState.Loading(id = "Loading#1") }
|
||||
val loadingTokenItemState by lazy {
|
||||
TokenItemState.Loading(
|
||||
id = "Loading#1",
|
||||
iconState = customTokenIconState.copy(isGrayscale = true),
|
||||
titleState = TokenItemState.TitleState.Content(text = "Polygon"),
|
||||
)
|
||||
}
|
||||
|
||||
private const val networksSize = 10
|
||||
private const val tokensSize = 3
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemTypography
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import org.burnoutcrew.reorderable.ReorderableLazyListState
|
||||
|
|
@ -73,6 +72,6 @@ private fun NonFiatContentText(@StringRes text: Int) {
|
|||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTypography.body2,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import com.tangem.common.Strings
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemTypography
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState.CryptoAmountState as TokenCryptoAmountState
|
||||
|
||||
|
|
@ -49,7 +48,7 @@ private fun CryptoAmountText(amount: String, modifier: Modifier = Modifier) {
|
|||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTypography.body2,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import com.tangem.common.Strings
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemTypography
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState.FiatAmountState as TokenFiatAmountState
|
||||
|
||||
@Composable
|
||||
|
|
@ -40,7 +39,7 @@ private fun FiatAmountText(text: String, modifier: Modifier = Modifier) {
|
|||
color = TangemTheme.colors.text.primary1,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTypography.body2,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import com.tangem.core.ui.components.RectangleShimmer
|
|||
import com.tangem.core.ui.components.SpacerW4
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemTypography
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState.PriceChangeState as TokenPriceChangeState
|
||||
|
|
@ -87,7 +86,7 @@ private fun PriceChangeText(type: PriceChangeType?, text: String?) {
|
|||
},
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = TangemTypography.body2,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemTypography
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState.TitleState as TokenTitleState
|
||||
|
||||
|
|
@ -63,7 +62,7 @@ private fun CurrencyNameText(name: String, modifier: Modifier = Modifier) {
|
|||
color = TangemTheme.colors.text.primary1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = TangemTypography.subtitle2,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ internal sealed class TokenItemState {
|
|||
abstract val priceChangeState: PriceChangeState?
|
||||
|
||||
/** Loading token state */
|
||||
data class Loading(override val id: String) : TokenItemState() {
|
||||
override val iconState: IconState = IconState.Loading
|
||||
override val titleState: TitleState = TitleState.Loading
|
||||
data class Loading(
|
||||
override val id: String,
|
||||
override val iconState: IconState,
|
||||
override val titleState: TitleState.Content,
|
||||
) : TokenItemState() {
|
||||
override val fiatAmountState: FiatAmountState = FiatAmountState.Loading
|
||||
override val cryptoAmountState: CryptoAmountState = CryptoAmountState.Loading
|
||||
override val priceChangeState: PriceChangeState = PriceChangeState.Loading
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import androidx.compose.ui.graphics.Brush
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -86,6 +88,7 @@ private fun TokenList(
|
|||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
Box(modifier = modifier) {
|
||||
val onDragEnd: (Int, Int) -> Unit = remember {
|
||||
{ _, _ ->
|
||||
|
|
@ -119,7 +122,10 @@ private fun TokenList(
|
|||
) { index, item ->
|
||||
|
||||
val onDragStart = remember(item) {
|
||||
{ dndConfig.onItemDragStart(item) }
|
||||
{
|
||||
dndConfig.onItemDragStart(item)
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
}
|
||||
}
|
||||
|
||||
DraggableItem(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavHostController
|
||||
|
|
@ -21,6 +20,7 @@ import com.tangem.core.navigation.NavigationAction
|
|||
import com.tangem.core.navigation.ReduxNavController
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.onboarding.navigation.OnboardingRouter
|
||||
import com.tangem.feature.wallet.presentation.WalletFragment
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensScreen
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensViewModel
|
||||
|
|
@ -33,13 +33,13 @@ import kotlin.properties.Delegates
|
|||
internal class DefaultWalletRouter(private val reduxNavController: ReduxNavController) : InnerWalletRouter {
|
||||
|
||||
private var navController: NavHostController by Delegates.notNull()
|
||||
private var fragmentManager: FragmentManager by Delegates.notNull()
|
||||
private var onFinish: () -> Unit = {}
|
||||
|
||||
override fun getEntryFragment(): Fragment = WalletFragment.create()
|
||||
|
||||
@Composable
|
||||
override fun Initialize(fragmentManager: FragmentManager) {
|
||||
this.fragmentManager = fragmentManager
|
||||
override fun Initialize(onFinish: () -> Unit) {
|
||||
this.onFinish = onFinish
|
||||
|
||||
NavHost(
|
||||
navController = rememberNavController().apply { navController = this },
|
||||
|
|
@ -78,11 +78,11 @@ internal class DefaultWalletRouter(private val reduxNavController: ReduxNavContr
|
|||
* next element is wallet screen entry.
|
||||
* If backstack contains only NavGraph entry and wallet screen entry then we close the wallet fragment.
|
||||
*/
|
||||
if (navController.backQueue.size == BACKSTACK_ENTRY_COUNT_TO_CLOSE_WALLET_SCREEN) {
|
||||
if (screen != null) {
|
||||
if (navController.currentBackStack.value.size == BACKSTACK_ENTRY_COUNT_TO_CLOSE_WALLET_SCREEN) {
|
||||
if (screen == AppScreen.Home) {
|
||||
reduxNavController.navigate(action = NavigationAction.PopBackTo(screen))
|
||||
} else {
|
||||
fragmentManager.popBackStack()
|
||||
onFinish.invoke()
|
||||
}
|
||||
} else {
|
||||
navController.popBackStack()
|
||||
|
|
@ -100,18 +100,26 @@ internal class DefaultWalletRouter(private val reduxNavController: ReduxNavContr
|
|||
}
|
||||
|
||||
override fun openOnboardingScreen() {
|
||||
reduxNavController.navigate(action = NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
|
||||
reduxNavController.navigate(
|
||||
action = NavigationAction.NavigateTo(
|
||||
screen = AppScreen.OnboardingWallet,
|
||||
bundle = bundleOf(OnboardingRouter.CAN_SKIP_BACKUP to false),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun openTxHistoryWebsite(url: String) {
|
||||
reduxNavController.navigate(action = NavigationAction.OpenUrl(url))
|
||||
}
|
||||
|
||||
override fun openTokenDetails(currency: CryptoCurrency) {
|
||||
override fun openTokenDetails(userWalletId: UserWalletId, currency: CryptoCurrency) {
|
||||
reduxNavController.navigate(
|
||||
action = NavigationAction.NavigateTo(
|
||||
screen = AppScreen.WalletDetails,
|
||||
bundle = bundleOf(TokenDetailsRouter.CRYPTO_CURRENCY_KEY to currency),
|
||||
bundle = bundleOf(
|
||||
TokenDetailsRouter.USER_WALLET_ID_KEY to userWalletId.stringValue,
|
||||
TokenDetailsRouter.CRYPTO_CURRENCY_KEY to currency,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.feature.wallet.presentation.router
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -22,11 +21,11 @@ internal interface InnerWalletRouter : WalletRouter {
|
|||
/**
|
||||
* Initialize router
|
||||
*
|
||||
* @param fragmentManager fragment manager
|
||||
* @param onFinish finish activity callback
|
||||
*/
|
||||
@Suppress("TopLevelComposableFunctions")
|
||||
@Composable
|
||||
fun Initialize(fragmentManager: FragmentManager)
|
||||
fun Initialize(onFinish: () -> Unit)
|
||||
|
||||
/** Pop back stack */
|
||||
fun popBackStack(screen: AppScreen? = null)
|
||||
|
|
@ -44,7 +43,7 @@ internal interface InnerWalletRouter : WalletRouter {
|
|||
fun openTxHistoryWebsite(url: String)
|
||||
|
||||
/** Open token details screen */
|
||||
fun openTokenDetails(currency: CryptoCurrency)
|
||||
fun openTokenDetails(userWalletId: UserWalletId, currency: CryptoCurrency)
|
||||
|
||||
/** Open stories screen */
|
||||
fun openStoriesScreen()
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ internal sealed interface WalletCardState {
|
|||
/** Title */
|
||||
val title: String
|
||||
|
||||
val additionalInfo: TextReference?
|
||||
|
||||
/** Wallet image resource id */
|
||||
@get:DrawableRes
|
||||
val imageResId: Int?
|
||||
|
|
@ -41,10 +43,10 @@ internal sealed interface WalletCardState {
|
|||
data class Content(
|
||||
override val id: UserWalletId,
|
||||
override val title: String,
|
||||
override val additionalInfo: TextReference,
|
||||
override val imageResId: Int?,
|
||||
override val onRenameClick: (UserWalletId, String) -> Unit,
|
||||
override val onDeleteClick: (UserWalletId) -> Unit,
|
||||
val additionalInfo: TextReference,
|
||||
val cardCount: Int?,
|
||||
val balance: String,
|
||||
) : WalletCardState
|
||||
|
|
@ -54,18 +56,18 @@ internal sealed interface WalletCardState {
|
|||
*
|
||||
* @property id wallet id
|
||||
* @property title wallet name
|
||||
* @property additionalInfo wallet additional info
|
||||
* @property imageResId wallet image resource id
|
||||
* @property onRenameClick lambda be invoked when Rename button is clicked
|
||||
* @property onDeleteClick lambda be invoked when Delete button is clicked
|
||||
* @property additionalInfo wallet additional info
|
||||
*/
|
||||
data class LockedContent(
|
||||
override val id: UserWalletId,
|
||||
override val title: String,
|
||||
override val additionalInfo: TextReference,
|
||||
override val imageResId: Int?,
|
||||
override val onRenameClick: (UserWalletId, String) -> Unit,
|
||||
override val onDeleteClick: (UserWalletId) -> Unit,
|
||||
val additionalInfo: TextReference,
|
||||
) : WalletCardState
|
||||
|
||||
/**
|
||||
|
|
@ -83,7 +85,9 @@ internal sealed interface WalletCardState {
|
|||
override val imageResId: Int?,
|
||||
override val onRenameClick: (UserWalletId, String) -> Unit,
|
||||
override val onDeleteClick: (UserWalletId) -> Unit,
|
||||
) : WalletCardState
|
||||
) : WalletCardState {
|
||||
override val additionalInfo: TextReference = EMPTY_BALANCE_TEXT
|
||||
}
|
||||
|
||||
/**
|
||||
* Wallet card loading state
|
||||
|
|
@ -97,6 +101,7 @@ internal sealed interface WalletCardState {
|
|||
data class Loading(
|
||||
override val id: UserWalletId,
|
||||
override val title: String,
|
||||
override val additionalInfo: TextReference? = null,
|
||||
override val imageResId: Int?,
|
||||
override val onRenameClick: (UserWalletId, String) -> Unit,
|
||||
override val onDeleteClick: (UserWalletId) -> Unit,
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ internal class WalletSkeletonStateConverter(
|
|||
return WalletCardState.Loading(
|
||||
id = walletId,
|
||||
title = name,
|
||||
additionalInfo = if (isMultiCurrency) WalletAdditionalInfoFactory.resolve(wallet = this) else null,
|
||||
imageResId = createImageResId(),
|
||||
onRenameClick = clickIntents::onRenameClick,
|
||||
onDeleteClick = clickIntents::onDeleteClick,
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ internal fun WalletCard(state: WalletCardState, isBalanceHidden: Boolean, modifi
|
|||
)
|
||||
|
||||
AdditionalInfo(
|
||||
text = resolveAdditionalTextByState(state),
|
||||
text = state.additionalInfo,
|
||||
modifier = Modifier.constrainAs(additionalTextRef) {
|
||||
start.linkTo(parent.start)
|
||||
top.linkTo(balanceRef.bottom)
|
||||
|
|
@ -345,15 +345,6 @@ private fun AdditionalInfo(text: TextReference?, modifier: Modifier = Modifier)
|
|||
}
|
||||
}
|
||||
|
||||
private fun resolveAdditionalTextByState(state: WalletCardState): TextReference? {
|
||||
return when (state) {
|
||||
is WalletCardState.Content -> state.additionalInfo
|
||||
is WalletCardState.LockedContent -> state.additionalInfo
|
||||
is WalletCardState.Error -> WalletCardState.EMPTY_BALANCE_TEXT
|
||||
is WalletCardState.Loading -> null
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AdditionalInfoText(text: TextReference) {
|
||||
Text(
|
||||
|
|
@ -361,7 +352,7 @@ private fun AdditionalInfoText(text: TextReference) {
|
|||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTheme.typography.caption,
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ private fun LazyListScope.nonContentItem(modifier: Modifier = Modifier) {
|
|||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing48),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.caption,
|
||||
style = TangemTheme.typography.caption2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,24 +16,31 @@ internal class CryptoCurrencyStatusToTokenItemConverter(
|
|||
private val clickIntents: WalletClickIntents,
|
||||
) : Converter<CryptoCurrencyStatus, TokenItemState> {
|
||||
|
||||
private val iconStateConverter = CryptoCurrencyToIconStateConverter()
|
||||
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
|
||||
|
||||
override fun convert(value: CryptoCurrencyStatus): TokenItemState {
|
||||
return when (value.value) {
|
||||
is CryptoCurrencyStatus.Loading -> TokenItemState.Loading(id = value.currency.id.value)
|
||||
is CryptoCurrencyStatus.Loading -> value.mapToLoadingState()
|
||||
is CryptoCurrencyStatus.Loaded,
|
||||
is CryptoCurrencyStatus.Custom,
|
||||
is CryptoCurrencyStatus.NoQuote,
|
||||
is CryptoCurrencyStatus.NoAccount,
|
||||
-> value.mapToTokenItemState()
|
||||
is CryptoCurrencyStatus.MissedDerivation -> value.mapToNoAddressTokenItemState()
|
||||
// TODO: Add other token item states, currently not designed
|
||||
is CryptoCurrencyStatus.Unreachable,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
-> value.mapToUnreachableTokenItemState()
|
||||
}
|
||||
}
|
||||
|
||||
private fun CryptoCurrencyStatus.mapToLoadingState(): TokenItemState.Loading {
|
||||
return TokenItemState.Loading(
|
||||
id = currency.id.value,
|
||||
iconState = iconStateConverter.convert(value = this),
|
||||
titleState = TokenItemState.TitleState.Content(text = currency.name),
|
||||
)
|
||||
}
|
||||
|
||||
private fun CryptoCurrencyStatus.mapToTokenItemState(): TokenItemState.Content {
|
||||
return TokenItemState.Content(
|
||||
id = currency.id.value,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ internal class FiatBalanceToWalletCardConverter(
|
|||
}
|
||||
|
||||
private fun WalletCardState.toLoadingWalletCardState(): WalletCardState {
|
||||
return WalletCardState.Loading(id, title, imageResId, onRenameClick, onDeleteClick)
|
||||
return WalletCardState.Loading(id, title, additionalInfo, imageResId, onRenameClick, onDeleteClick)
|
||||
}
|
||||
|
||||
private fun WalletCardState.toErrorWalletCardState(): WalletCardState {
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.utils
|
||||
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal object LoadingItemsProvider {
|
||||
|
||||
fun getLoadingMultiCurrencyTokens(): ImmutableList<WalletTokensListState.TokensListItemState.Token> {
|
||||
val items = mutableListOf<WalletTokensListState.TokensListItemState.Token>()
|
||||
repeat(times = 5) {
|
||||
items.add(
|
||||
WalletTokensListState.TokensListItemState.Token(
|
||||
state = TokenItemState.Loading(id = "Loading#$it"),
|
||||
),
|
||||
)
|
||||
}
|
||||
return items.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
|||
|
||||
import androidx.lifecycle.*
|
||||
import androidx.paging.cachedIn
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.blockchains.cardano.CardanoUtils
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
|
|
@ -39,6 +40,7 @@ import com.tangem.domain.redux.LegacyAction
|
|||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.settings.*
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
|
|
@ -48,6 +50,7 @@ import com.tangem.domain.tokens.models.analytics.TokenReceiveAnalyticsEvent
|
|||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.walletconnect.WalletConnectActions
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -156,6 +159,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
private var singleWalletCryptoCurrencyStatus: CryptoCurrencyStatus? = null
|
||||
|
||||
private val tokensJobHolder = JobHolder()
|
||||
private val updateWcJobHolder = JobHolder()
|
||||
private val marketPriceJobHolder = JobHolder()
|
||||
private val buttonsJobHolder = JobHolder()
|
||||
private val notificationsJobHolder = JobHolder()
|
||||
|
|
@ -453,6 +457,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
* If jobs aren't stopped and wallet is changed then it will update state for the prev wallet.
|
||||
*/
|
||||
tokensJobHolder.update(job = null)
|
||||
updateWcJobHolder.update(job = null)
|
||||
marketPriceJobHolder.update(job = null)
|
||||
buttonsJobHolder.update(job = null)
|
||||
notificationsJobHolder.update(job = null)
|
||||
|
|
@ -719,7 +724,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
|
||||
override fun onTokenItemClick(currency: CryptoCurrency) {
|
||||
analyticsEventsHandler.send(PortfolioEvent.TokenTapped)
|
||||
router.openTokenDetails(currency = currency)
|
||||
router.openTokenDetails(getSelectedWallet().walletId, currency)
|
||||
}
|
||||
|
||||
override fun onTokenItemLongClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
|
|
@ -849,6 +854,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
* If jobs aren't stopped and wallet is changed then it will update state for the prev wallet.
|
||||
*/
|
||||
tokensJobHolder.update(job = null)
|
||||
updateWcJobHolder.update(job = null)
|
||||
marketPriceJobHolder.update(job = null)
|
||||
buttonsJobHolder.update(job = null)
|
||||
notificationsJobHolder.update(job = null)
|
||||
|
|
@ -860,17 +866,22 @@ internal class WalletViewModel @Inject constructor(
|
|||
wallet.isLocked -> {
|
||||
uiState = stateFactory.getLockedState()
|
||||
}
|
||||
wallet.isMultiCurrency -> getMultiCurrencyContent(index)
|
||||
wallet.isMultiCurrency -> getMultiCurrencyContent(wallet, index)
|
||||
!wallet.isMultiCurrency -> getSingleCurrencyContent(index)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMultiCurrencyContent(walletIndex: Int) {
|
||||
private fun getMultiCurrencyContent(wallet: UserWallet, walletIndex: Int) {
|
||||
val state = requireNotNull(uiState as? WalletMultiCurrencyState) {
|
||||
"Impossible to get a token list updates if state isn't WalletMultiCurrencyState"
|
||||
}
|
||||
|
||||
getTokenListUseCase(userWalletId = state.walletsListConfig.wallets[walletIndex].id)
|
||||
val tokenListFlow = getTokenListUseCase(userWalletId = state.walletsListConfig.wallets[walletIndex].id)
|
||||
.shareIn(viewModelScope, SharingStarted.WhileSubscribed())
|
||||
|
||||
initAndSetupWc(tokenListFlow, wallet)
|
||||
|
||||
tokenListFlow
|
||||
.distinctUntilChanged()
|
||||
.onEach { maybeTokenList ->
|
||||
uiState = stateFactory.getStateByTokensList(maybeTokenList)
|
||||
|
|
@ -903,6 +914,44 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun initAndSetupWc(tokenListFlow: SharedFlow<Either<TokenListError, TokenList>>, wallet: UserWallet) {
|
||||
initWalletConnectForWallet(wallet)
|
||||
tokenListFlow
|
||||
.filter(::filterLoadedTokenList)
|
||||
.take(1)
|
||||
.onEach {
|
||||
it.onRight {
|
||||
setupWalletConnectOnWallet(wallet)
|
||||
}
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(updateWcJobHolder)
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.isAllCurrenciesLoaded(): Boolean {
|
||||
return !this.any { it.value is CryptoCurrencyStatus.Loading }
|
||||
}
|
||||
|
||||
private fun filterLoadedTokenList(either: Either<TokenListError, TokenList>): Boolean {
|
||||
return either.fold(
|
||||
ifRight = { list ->
|
||||
when (list) {
|
||||
is TokenList.Ungrouped -> {
|
||||
list.currencies.isAllCurrenciesLoaded()
|
||||
}
|
||||
is TokenList.GroupedByNetwork -> {
|
||||
list.groups.flatMap { group -> group.currencies }.isAllCurrenciesLoaded()
|
||||
}
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
},
|
||||
ifLeft = { false },
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.hasNonZeroWallets(): Boolean {
|
||||
return any {
|
||||
val amount = it.value.amount ?: return@any false
|
||||
|
|
@ -912,7 +961,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
|
||||
private fun getSingleCurrencyContent(index: Int) {
|
||||
val wallet = getWallet(index)
|
||||
getPrimaryCurrencyStatusUpdatesUseCase(userWalletId = wallet.walletId)
|
||||
getPrimaryCurrencyStatusUpdatesUseCase(wallet.walletId)
|
||||
.distinctUntilChanged()
|
||||
.onEach { maybeCryptoCurrencyStatus ->
|
||||
uiState = stateFactory.getSingleCurrencyLoadedBalanceState(maybeCryptoCurrencyStatus)
|
||||
|
|
@ -925,8 +974,8 @@ internal class WalletViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
updateNotifications(index)
|
||||
updateButtons(userWalletId = wallet.walletId, currencyStatus = status)
|
||||
updateTxHistory(status.currency)
|
||||
updateButtons(wallet.walletId, status)
|
||||
updateTxHistory(wallet.walletId, status.currency, refresh = false)
|
||||
}
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
|
|
@ -934,9 +983,12 @@ internal class WalletViewModel @Inject constructor(
|
|||
.saveIn(marketPriceJobHolder)
|
||||
}
|
||||
|
||||
private fun updateTxHistory(currency: CryptoCurrency) {
|
||||
private fun updateTxHistory(userWalletId: UserWalletId, currency: CryptoCurrency, refresh: Boolean) {
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
val txHistoryItemsCountEither = txHistoryItemsCountUseCase(currency.network)
|
||||
val txHistoryItemsCountEither = txHistoryItemsCountUseCase(
|
||||
userWalletId = userWalletId,
|
||||
network = currency.network,
|
||||
)
|
||||
|
||||
uiState = stateFactory.getLoadingTxHistoryState(
|
||||
itemsCountEither = txHistoryItemsCountEither,
|
||||
|
|
@ -944,7 +996,11 @@ internal class WalletViewModel @Inject constructor(
|
|||
|
||||
txHistoryItemsCountEither.onRight {
|
||||
uiState = stateFactory.getLoadedTxHistoryState(
|
||||
txHistoryEither = txHistoryItemsUseCase(currency = currency).map {
|
||||
txHistoryEither = txHistoryItemsUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currency = currency,
|
||||
refresh = refresh,
|
||||
).map {
|
||||
it.cachedIn(viewModelScope)
|
||||
},
|
||||
)
|
||||
|
|
@ -1006,6 +1062,10 @@ internal class WalletViewModel @Inject constructor(
|
|||
|
||||
uiState = stateFactory.getRefreshedState()
|
||||
uiState = result.fold(stateFactory::getStateByCurrencyStatusError) { uiState }
|
||||
|
||||
singleWalletCryptoCurrencyStatus?.let {
|
||||
updateTxHistory(wallet.walletId, it.currency, refresh = true)
|
||||
}
|
||||
}.saveIn(refreshContentJobHolder)
|
||||
}
|
||||
|
||||
|
|
@ -1021,6 +1081,18 @@ internal class WalletViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun initWalletConnectForWallet(userWallet: UserWallet) {
|
||||
reduxStateHolder.dispatch(
|
||||
WalletConnectActions.New.Initialize(userWallet = userWallet),
|
||||
)
|
||||
}
|
||||
|
||||
private fun setupWalletConnectOnWallet(userWallet: UserWallet) {
|
||||
reduxStateHolder.dispatch(
|
||||
WalletConnectActions.New.SetupUserChains(userWallet = userWallet),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getWallet(index: Int): UserWallet {
|
||||
return requireNotNull(
|
||||
value = wallets.getOrNull(index),
|
||||
|
|
@ -1028,5 +1100,12 @@ internal class WalletViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun getSelectedWallet(): UserWallet {
|
||||
val state = uiState as? WalletState.ContentState
|
||||
?: error("Unable to get selected user wallet")
|
||||
|
||||
return getWallet(state.walletsListConfig.selectedWalletIndex)
|
||||
}
|
||||
|
||||
private fun getCardTypeResolver(index: Int): CardTypesResolver = getWallet(index).scanResponse.cardTypesResolver
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue