Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-17 14:38:33 +04:00
commit dfd7076c2e
31 changed files with 345 additions and 648 deletions

View file

@ -37,11 +37,15 @@ dependencies {
implementation(projects.domain.appCurrency)
implementation(projects.domain.appCurrency.models)
implementation(projects.domain.walletConnect)
implementation(projects.domain.balanceHiding)
implementation(projects.domain.balanceHiding.models)
implementation(projects.domain.legacy)
/* SDK */
// TODO: For TangemError model, should be removed after card domain scanning refactoring
implementation(deps.tangem.card.core)
// For image resolving
implementation(deps.tangem.blockchain)
/* AndroidX */
implementation(deps.androidx.fragment.ktx)
@ -55,6 +59,7 @@ dependencies {
implementation(deps.compose.foundation)
implementation(deps.compose.material3)
implementation(deps.compose.shimmer)
implementation(deps.compose.coil)
/* DI */
implementation(deps.hilt.android)

View file

@ -19,23 +19,26 @@ internal class PreviewUserWalletListComponent : UserWalletListComponent {
userWallets = persistentListOf(
UserWalletListUM.UserWalletUM(
id = UserWalletId("user_wallet_1".encodeToByteArray()),
name = "My Wallet",
name = stringReference("My Wallet"),
information = getInformation(3, "4 496,75 $"),
imageResId = R.drawable.ill_card_wallet_2_211_343,
imageUrl = "",
isEnabled = true,
onClick = {},
),
UserWalletListUM.UserWalletUM(
id = UserWalletId("user_wallet_2".encodeToByteArray()),
name = "Old wallet",
name = stringReference("Old wallet"),
information = getInformation(3, "4 496,75 $"),
imageResId = R.drawable.ill_card_note_eth_211_343,
imageUrl = "",
isEnabled = true,
onClick = {},
),
UserWalletListUM.UserWalletUM(
id = UserWalletId("user_wallet_3".encodeToByteArray()),
name = "Multi Card",
name = stringReference("Multi Card"),
information = getInformation(3, "4 496,75 $"),
imageResId = R.drawable.ill_card_note_bnb_211_343,
imageUrl = "",
isEnabled = false,
onClick = {},
),
),

View file

@ -1,10 +1,11 @@
package com.tangem.features.details.entity
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.collections.immutable.ImmutableList
@Immutable
internal data class UserWalletListUM(
val userWallets: ImmutableList<UserWalletUM>,
val isWalletSavingInProgress: Boolean,
@ -12,12 +13,13 @@ internal data class UserWalletListUM(
val onAddNewWalletClick: () -> Unit,
) {
@Immutable
data class UserWalletUM(
val id: UserWalletId,
val name: String,
val name: TextReference,
val information: TextReference,
@DrawableRes
val imageResId: Int,
val imageUrl: String,
val isEnabled: Boolean,
val onClick: () -> Unit,
)
}

View file

@ -10,15 +10,21 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import coil.compose.SubcomposeAsyncImage
import coil.request.ImageRequest
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.block.BlockCard
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.details.entity.UserWalletListUM
import com.tangem.features.details.impl.R
import com.tangem.features.details.ui.coil.RotationTransformation
@Composable
internal fun UserWalletListBlock(state: UserWalletListUM, modifier: Modifier = Modifier) {
@ -46,6 +52,7 @@ private fun UserWalletItem(model: UserWalletListUM.UserWalletUM, modifier: Modif
BlockCard(
modifier = modifier,
onClick = model.onClick,
enabled = model.isEnabled,
) {
Row(
modifier = Modifier
@ -55,39 +62,81 @@ private fun UserWalletItem(model: UserWalletListUM.UserWalletUM, modifier: Modif
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
Image(
modifier = Modifier
.width(TangemTheme.dimens.size24)
.height(TangemTheme.dimens.size36),
painter = painterResource(id = model.imageResId),
contentScale = ContentScale.FillBounds,
contentDescription = null,
Image(imageUrl = model.imageUrl)
NameAndInfo(
name = model.name,
information = model.information,
)
Column(
modifier = Modifier.heightIn(min = TangemTheme.dimens.size40),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.SpaceEvenly,
) {
Text(
text = model.name,
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = model.information.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
}
}
@Composable
private fun NameAndInfo(name: TextReference, information: TextReference, modifier: Modifier = Modifier) {
Column(
modifier = modifier.heightIn(min = TangemTheme.dimens.size40),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.SpaceEvenly,
) {
Text(
text = name.resolveReference(),
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
AnimatedContent(
targetState = information.resolveReference(),
label = "User wallet information",
) { information ->
Text(
text = information,
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
}
@Composable
private fun Image(imageUrl: String, modifier: Modifier = Modifier) {
val imageModifier = modifier
.width(TangemTheme.dimens.size24)
.height(TangemTheme.dimens.size36)
.clip(TangemTheme.shapes.roundedCornersSmall)
SubcomposeAsyncImage(
modifier = imageModifier,
model = ImageRequest.Builder(LocalContext.current)
.transformations(RotationTransformation(angle = 90f))
.size(
width = with(LocalDensity.current) { TangemTheme.dimens.size36.roundToPx() },
height = with(LocalDensity.current) { TangemTheme.dimens.size24.roundToPx() },
)
.data(imageUrl)
.crossfade(enable = true)
.allowHardware(enable = false)
.build(),
loading = {
RectangleShimmer(
modifier = imageModifier,
radius = TangemTheme.dimens.size2,
)
},
error = {
Image(
modifier = imageModifier,
painter = painterResource(id = R.drawable.img_card_wallet_2_gray_22_36),
contentDescription = null,
)
},
contentDescription = null,
)
}
@Composable
private fun AddWalletButton(
text: TextReference,
@ -110,6 +159,7 @@ private fun AddWalletButton(
AnimatedContent(
modifier = Modifier.size(TangemTheme.dimens.size24),
targetState = isInProgress,
label = "Add wallet progress",
) { isInProgress ->
if (isInProgress) {
CircularProgressIndicator(

View file

@ -0,0 +1,22 @@
package com.tangem.features.details.ui.coil
import android.graphics.Bitmap
import android.graphics.Matrix
import coil.size.Size
import coil.transform.Transformation
internal class RotationTransformation(private val angle: Float) : Transformation {
override val cacheKey: String = "rotate:$angle"
override suspend fun transform(input: Bitmap, size: Size): Bitmap {
val matrix = Matrix().apply {
val centerX = input.width / 2f
val centerY = input.height / 2f
postRotate(angle, centerX, centerY)
}
return Bitmap.createBitmap(input, 0, 0, input.width, input.height, matrix, true)
}
}

View file

@ -1,9 +1,6 @@
package com.tangem.features.details.utils
import androidx.annotation.DrawableRes
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.scan.CardDTO
@ -12,6 +9,7 @@ import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.details.entity.UserWalletListUM.UserWalletUM
import com.tangem.features.details.impl.R
import com.tangem.utils.Strings.STARS
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
@ -19,11 +17,15 @@ internal fun List<UserWallet>.toUiModels(
onClick: (UserWalletId) -> Unit,
appCurrency: AppCurrency? = null,
balances: Map<UserWalletId, TotalFiatBalance> = emptyMap(),
isLoading: Boolean = true,
isBalancesHidden: Boolean = false,
): ImmutableList<UserWalletUM> = this.map { model ->
val balance = balances[model.walletId]
model.mapToUiModel(
balance = balance,
appCurrency = appCurrency,
isLoading = isLoading,
isBalanceHidden = isBalancesHidden,
onClick = { onClick(model.walletId) },
)
}.toImmutableList()
@ -31,22 +33,52 @@ internal fun List<UserWallet>.toUiModels(
private fun UserWallet.mapToUiModel(
balance: TotalFiatBalance?,
appCurrency: AppCurrency?,
isLoading: Boolean,
isBalanceHidden: Boolean,
onClick: () -> Unit,
): UserWalletUM = UserWalletUM(
id = walletId,
name = name,
information = getInfo(appCurrency, balance),
imageResId = resolveImage(),
name = stringReference(name),
information = getInfo(
appCurrency = appCurrency,
balance = balance,
isBalanceHidden = isBalanceHidden,
isLoading = isLoading,
),
imageUrl = artworkUrl,
isEnabled = !isLocked,
onClick = onClick,
)
private fun UserWallet.getInfo(appCurrency: AppCurrency?, balance: TotalFiatBalance?): TextReference {
private fun UserWallet.getInfo(
appCurrency: AppCurrency?,
balance: TotalFiatBalance?,
isBalanceHidden: Boolean,
isLoading: Boolean,
): TextReference {
val dividerRef = stringReference(value = "")
val cardCount = getCardCount()
val cardCountRef = TextReference.PluralRes(
id = R.plurals.card_label_card_count,
count = cardCount,
formatArgs = wrappedList(cardCount),
)
return when {
isLocked -> combinedReference(cardCountRef, dividerRef, resourceReference(R.string.common_locked))
isLoading -> cardCountRef
isBalanceHidden -> combinedReference(cardCountRef, dividerRef, stringReference(STARS))
else -> getBalanceInfo(balance, appCurrency, cardCountRef, dividerRef)
}
}
private fun getBalanceInfo(
balance: TotalFiatBalance?,
appCurrency: AppCurrency?,
cardCountRef: TextReference,
dividerRef: TextReference,
): TextReference {
val amount = when (balance) {
is TotalFiatBalance.Loaded -> balance.amount.takeIf { balance.isAllAmountsSummarized }
is TotalFiatBalance.Failed,
@ -56,16 +88,15 @@ private fun UserWallet.getInfo(appCurrency: AppCurrency?, balance: TotalFiatBala
}
return if (amount != null && appCurrency != null) {
val divider = stringReference(value = "")
val formattedAmount = BigDecimalFormatter.formatFiatAmount(
fiatAmount = amount,
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
)
val amountRef = stringReference(formattedAmount)
TextReference.Combined(wrappedList(cardCountRef, divider, amountRef))
combinedReference(cardCountRef, dividerRef, amountRef)
} else {
cardCountRef
combinedReference(cardCountRef, dividerRef, stringReference(BigDecimalFormatter.EMPTY_BALANCE_SIGN))
}
}
@ -75,10 +106,4 @@ private fun UserWallet.getCardCount() = when (val status = scanResponse.card.bac
is CardDTO.BackupStatus.NoBackup,
null,
-> 1
}
@DrawableRes
private fun UserWallet.resolveImage(): Int {
// TODO: Implement image resolving [REDACTED_JIRA]
return R.drawable.ill_card_wallet_2_211_343
}

View file

@ -10,6 +10,8 @@ import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.error.SelectedAppCurrencyError
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.BalanceHidingSettings
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.lce.lce
import com.tangem.domain.core.utils.getOrElse
@ -24,10 +26,7 @@ import com.tangem.features.details.entity.UserWalletListUM.UserWalletUM
import com.tangem.features.details.impl.R
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.flow.*
import javax.inject.Inject
@ComponentScoped
@ -35,6 +34,7 @@ internal class UserWalletsFetcher @Inject constructor(
getWalletsUseCase: GetWalletsUseCase,
private val getWalletTotalBalanceUseCase: GetWalletTotalBalanceUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
private val router: Router,
private val messageSender: UiMessageSender,
) {
@ -44,10 +44,16 @@ internal class UserWalletsFetcher @Inject constructor(
emit(wallets.toUiModels(onClick = ::navigateToWalletSettings))
combine(
getSelectedAppCurrencyUseCase(),
getWalletTotalBalanceUseCase(wallets.map(UserWallet::walletId)),
) { maybeAppCurrency, maybeBalances ->
val models = createUiModels(wallets, maybeAppCurrency, maybeBalances).getOrElse(
getSelectedAppCurrencyUseCase().distinctUntilChanged(),
getBalanceHidingSettingsUseCase().distinctUntilChanged(),
getWalletTotalBalanceUseCase(wallets.map(UserWallet::walletId)).distinctUntilChanged(),
) { maybeAppCurrency, balanceHidingSettings, maybeBalances ->
val models = createUiModels(
wallets = wallets,
maybeAppCurrency = maybeAppCurrency,
maybeBalances = maybeBalances,
balanceHidingSettings = balanceHidingSettings,
).getOrElse(
ifLoading = { return@combine },
ifError = {
val message = resourceReference(R.string.common_unknown_error)
@ -65,10 +71,11 @@ internal class UserWalletsFetcher @Inject constructor(
wallets: List<UserWallet>,
maybeAppCurrency: Either<SelectedAppCurrencyError, AppCurrency>,
maybeBalances: Lce<TokenListError, Map<UserWalletId, TotalFiatBalance>>,
balanceHidingSettings: BalanceHidingSettings,
): Lce<Error, ImmutableList<UserWalletUM>> = lce {
val balances = withError(
transform = { Error.UnableToGetBalances },
block = { maybeBalances.bind() },
block = { maybeBalances.bindOrNull().orEmpty() },
)
val appCurrency = withError(
transform = { Error.UnableToGetAppCurrency },
@ -79,6 +86,8 @@ internal class UserWalletsFetcher @Inject constructor(
appCurrency = appCurrency,
balances = balances,
onClick = ::navigateToWalletSettings,
isBalancesHidden = balanceHidingSettings.isBalanceHidden,
isLoading = maybeBalances.isLoading(),
)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View file

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="36dp"
android:viewportWidth="22"
android:viewportHeight="36">
<path
android:fillColor="#C9C9CA"
android:pathData="M22,2L22,34A2,2 0,0 1,20 36L2,36A2,2 0,0 1,0 34L0,2A2,2 0,0 1,2 0L20,0A2,2 0,0 1,22 2z" />
<path
android:fillColor="#A1A1A1"
android:pathData="M10.92,22.14H10.96C11.52,22.14 11.85,21.83 11.85,21.35C11.85,20.84 11.48,20.55 10.95,20.55H10.91C10.36,20.55 10.03,20.89 10.03,21.32C10.03,21.79 10.36,22.14 10.92,22.14ZM9.29,19.89V20.58C9,20.63 8.83,20.85 8.83,21.3C8.83,21.82 9.09,22.11 9.62,22.11H10.05C9.77,21.95 9.51,21.59 9.51,21.16C9.51,20.42 10.06,19.86 10.9,19.86H10.94C11.76,19.86 12.38,20.42 12.38,21.17C12.38,21.65 12.16,21.95 11.87,22.11H12.32V22.79H9.61C8.75,22.78 8.32,22.21 8.32,21.3C8.32,20.39 8.73,19.97 9.29,19.89ZM11.17,7.82V9.23H9.41C9.06,9.23 8.88,9.23 8.75,9.16C8.63,9.1 8.54,9 8.48,8.89C8.41,8.75 8.41,8.58 8.41,8.23V7.82H11.17ZM13.69,8.23V6C13.69,5.65 13.69,5.48 13.62,5.34C13.56,5.22 13.47,5.13 13.35,5.07C13.21,5 13.04,5 12.69,5H12.31V9.23H12.69H12.69C13.04,9.23 13.21,9.23 13.35,9.16C13.47,9.1 13.56,9 13.62,8.89C13.69,8.75 13.69,8.58 13.69,8.23ZM11.17,5V6.41H8.41V6C8.41,5.65 8.41,5.48 8.48,5.34C8.54,5.22 8.63,5.13 8.75,5.07C8.88,5 9.06,5 9.41,5L11.17,5ZM10.21,11.96H11.81V11.57H12.32V11.96H12.96L12.96,12.64H12.32V13.28H11.81V12.64H10.27C10.01,12.64 9.89,12.76 9.89,12.98C9.89,13.11 9.91,13.21 9.95,13.31H9.41C9.37,13.2 9.34,13.05 9.34,12.85C9.34,12.27 9.65,11.96 10.21,11.96ZM12.32,17.44V16.76H9.39V17.44H11.11C11.58,17.44 11.81,17.74 11.81,18.12C11.81,18.53 11.61,18.71 11.17,18.71H9.39L9.39,19.38H11.23C12.04,19.38 12.38,18.97 12.38,18.38C12.38,17.9 12.14,17.58 11.85,17.44H12.32ZM11.88,24.74C11.88,25.16 11.66,25.42 11.16,25.45V23.99C11.61,24.06 11.88,24.33 11.88,24.74ZM10.87,23.29H10.82C9.9,23.29 9.33,23.91 9.33,24.77C9.33,25.52 9.67,26.02 10.29,26.11V25.46C10,25.41 9.84,25.19 9.84,24.79C9.84,24.28 10.15,24 10.7,23.98V26.12H10.9C11.95,26.12 12.38,25.47 12.38,24.74C12.38,23.91 11.77,23.29 10.87,23.29ZM12.32,26.64V27.32H11.87C12.14,27.46 12.38,27.78 12.38,28.21C12.38,28.59 12.22,28.89 11.85,29.04C12.22,29.26 12.38,29.66 12.38,30.03C12.38,30.56 12.05,31 11.24,31H9.39V30.32H11.2C11.63,30.32 11.81,30.14 11.81,29.8C11.81,29.47 11.59,29.16 11.14,29.16H9.39V28.48H11.2C11.63,28.48 11.81,28.29 11.81,27.96C11.81,27.63 11.59,27.32 11.14,27.32H9.39V26.64H12.32ZM10.7,15.52H10.41C10.04,15.52 9.82,15.22 9.82,14.8C9.82,14.47 9.98,14.33 10.23,14.33C10.59,14.33 10.7,14.66 10.7,15.18V15.52ZM11.13,15.16C11.13,14.32 10.88,13.66 10.2,13.66C9.59,13.66 9.33,14.1 9.33,14.64C9.33,15.09 9.5,15.34 9.75,15.53H9.39V16.2H11.31C12.11,16.2 12.38,15.68 12.38,15.03C12.38,14.38 12.09,13.83 11.41,13.78V14.43C11.7,14.47 11.87,14.64 11.87,14.99C11.87,15.39 11.67,15.52 11.28,15.52H11.13V15.16Z" />
</vector>

View file

@ -1,20 +0,0 @@
package com.tangem.feature.wallet.di
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.feature.wallet.featuretoggle.WalletFeatureToggles
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object FeatureTogglesModule {
@Provides
@Singleton
fun provideWalletFeatureToggles(featureTogglesManager: FeatureTogglesManager): WalletFeatureToggles {
return WalletFeatureToggles(featureTogglesManager)
}
}

View file

@ -1,11 +0,0 @@
package com.tangem.feature.wallet.featuretoggle
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
internal class WalletFeatureToggles(
private val featureTogglesManager: FeatureTogglesManager,
) {
val isTokenListLceFlowEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled("TOKEN_LIST_LCE_ENABLED")
}

View file

@ -13,9 +13,7 @@ import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.ToggleTokenListGroupingUseCase
import com.tangem.domain.tokens.ToggleTokenListSortingUseCase
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.featuretoggle.WalletFeatureToggles
import com.tangem.feature.wallet.presentation.organizetokens.analytics.PortfolioOrganizeTokensAnalyticsEvent
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState
@ -42,7 +40,6 @@ internal class OrganizeTokensViewModel @Inject constructor(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
private val analyticsEventsHandler: AnalyticsEventHandler,
private val walletFeatureToggles: WalletFeatureToggles,
private val dispatchers: CoroutineDispatcherProvider,
savedStateHandle: SavedStateHandle,
) : ViewModel(), DefaultLifecycleObserver, OrganizeTokensIntents {
@ -173,34 +170,21 @@ internal class OrganizeTokensViewModel @Inject constructor(
}
private suspend fun getTokenList(): TokenList? {
return if (walletFeatureToggles.isTokenListLceFlowEnabled) {
val tokenList = getTokenListUseCase.launchLce(userWalletId)
.transform { maybeTokenList ->
val tokenList = maybeTokenList.getOrElse(
ifLoading = { return@transform },
ifError = { error ->
stateHolder.updateStateWithError(error)
val tokenList = getTokenListUseCase.launch(userWalletId)
.transform { maybeTokenList ->
val tokenList = maybeTokenList.getOrElse(
ifLoading = { return@transform },
ifError = { error ->
stateHolder.updateStateWithError(error)
return@transform
},
)
return@transform
},
)
emit(tokenList)
}
tokenList.firstOrNull()
} else {
val maybeTokenList = getTokenListUseCase.launch(userWalletId)
.first { maybeTokenList ->
maybeTokenList.getOrNull()?.totalFiatBalance !is TotalFiatBalance.Loading
}
maybeTokenList.getOrElse { error ->
stateHolder.updateStateWithError(error)
null
emit(tokenList)
}
}
return tokenList.firstOrNull()
}
private fun bootstrapDragAndDropUpdates() {

View file

@ -1,8 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.domain
import arrow.core.Either
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.promo.PromoBanner
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
@ -23,7 +23,6 @@ import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flow
import javax.inject.Inject
import kotlin.collections.count
@ -47,11 +46,11 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
val promoFlow = flow { emit(promoRepository.getOkxPromoBanner()) }
return combine(
flow = getTokenListUseCase.launch(userWallet.walletId).conflate(),
flow2 = isReadyToShowRateAppUseCase().conflate(),
flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(),
flow4 = shouldShowSwapPromoWalletUseCase().conflate(),
flow5 = promoFlow.conflate(),
flow = getTokenListUseCase.launch(userWallet.walletId),
flow2 = isReadyToShowRateAppUseCase(),
flow3 = isNeedToBackupUseCase(userWallet.walletId),
flow4 = shouldShowSwapPromoWalletUseCase(),
flow5 = promoFlow,
) { maybeTokenList, isReadyToShowRating, isNeedToBackup, shouldShowPromo, promoBanner ->
readyForRateAppNotification = true
@ -113,7 +112,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
private fun MutableList<WalletNotification>.addInformationalNotifications(
cardTypesResolver: CardTypesResolver,
maybeTokenList: Either<TokenListError, TokenList>,
maybeTokenList: Lce<TokenListError, TokenList>,
clickIntents: WalletClickIntents,
) {
addIf(
@ -125,7 +124,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
}
private fun MutableList<WalletNotification>.addMissingAddressesNotification(
maybeTokenList: Either<TokenListError, TokenList>,
maybeTokenList: Lce<TokenListError, TokenList>,
clickIntents: WalletClickIntents,
) {
val currencies = maybeTokenList.getMissingAddressCurrencies()
@ -141,26 +140,23 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
)
}
private fun Either<TokenListError, TokenList>.getMissingAddressCurrencies(): List<CryptoCurrency> {
return fold(
ifLeft = { emptyList() },
ifRight = { tokenList ->
val currencies = when (tokenList) {
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
is TokenList.Ungrouped -> tokenList.currencies
is TokenList.Empty -> emptyList()
}
private fun Lce<TokenListError, TokenList>.getMissingAddressCurrencies(): List<CryptoCurrency> {
val tokenList = getOrNull(isPartialContentAccepted = false) ?: return emptyList()
currencies
.filter { it.value is CryptoCurrencyStatus.MissedDerivation }
.map(CryptoCurrencyStatus::currency)
},
)
val currencies = when (tokenList) {
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
is TokenList.Ungrouped -> tokenList.currencies
is TokenList.Empty -> emptyList()
}
return currencies
.filter { it.value is CryptoCurrencyStatus.MissedDerivation }
.map(CryptoCurrencyStatus::currency)
}
private fun MutableList<WalletNotification>.addWarningNotifications(
cardTypesResolver: CardTypesResolver,
tokenList: Either<TokenListError, TokenList>,
tokenList: Lce<TokenListError, TokenList>,
isNeedToBackup: Boolean,
clickIntents: WalletClickIntents,
) {
@ -182,19 +178,16 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
)
}
private fun Either<TokenListError, TokenList>.hasUnreachableNetworks(): Boolean {
return fold(
ifLeft = { false },
ifRight = { tokenList ->
val currencies = when (tokenList) {
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
is TokenList.Ungrouped -> tokenList.currencies
is TokenList.Empty -> emptyList()
}
private fun Lce<TokenListError, TokenList>.hasUnreachableNetworks(): Boolean {
val tokenList = getOrNull(isPartialContentAccepted = false) ?: return false
currencies.any { it.value is CryptoCurrencyStatus.Unreachable }
},
)
val currencies = when (tokenList) {
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
is TokenList.Ungrouped -> tokenList.currencies
is TokenList.Empty -> emptyList()
}
return currencies.any { it.value is CryptoCurrencyStatus.Unreachable }
}
private fun MutableList<WalletNotification>.addRateTheAppNotification(

View file

@ -5,7 +5,6 @@ import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.featuretoggle.WalletFeatureToggles
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarningsFactory
@ -28,7 +27,6 @@ internal class MultiWalletContentLoader(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val walletFeatureToggles: WalletFeatureToggles,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
) : WalletContentLoader(id = userWallet.walletId) {
@ -42,7 +40,6 @@ internal class MultiWalletContentLoader(
walletWithFundsChecker = walletWithFundsChecker,
getTokenListUseCase = getTokenListUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
walletFeatureToggles = walletFeatureToggles,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
),

View file

@ -5,7 +5,6 @@ import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.featuretoggle.WalletFeatureToggles
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarningsFactory
@ -26,7 +25,6 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletFeatureToggles: WalletFeatureToggles,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
) {
@ -42,7 +40,6 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
walletFeatureToggles = walletFeatureToggles,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
)
}

View file

@ -3,7 +3,6 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.core.utils.toLce
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
@ -12,19 +11,16 @@ import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.featuretoggle.WalletFeatureToggles
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import kotlinx.coroutines.flow.map
@Suppress("LongParameterList")
internal class MultiWalletTokenListSubscriber(
private val userWallet: UserWallet,
private val getTokenListUseCase: GetTokenListUseCase,
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val walletFeatureToggles: WalletFeatureToggles,
stateHolder: WalletStateController,
clickIntents: WalletClickIntents,
tokenListAnalyticsSender: TokenListAnalyticsSender,
@ -42,11 +38,7 @@ internal class MultiWalletTokenListSubscriber(
) {
override fun tokenListFlow(): LceFlow<TokenListError, TokenList> {
return if (walletFeatureToggles.isTokenListLceFlowEnabled) {
getTokenListUseCase.launchLce(userWallet.walletId)
} else {
getTokenListUseCase.launch(userWallet.walletId).map { it.toLce() }
}
return getTokenListUseCase.launch(userWallet.walletId)
}
override suspend fun onTokenListReceived(maybeTokenList: Lce<TokenListError, TokenList>) {