Updated on 2026-08-14

This commit is contained in:
Tangem 2023-08-02 21:00:21 +08:00
parent 23aac9041c
commit 49904463e0
10 changed files with 108 additions and 41 deletions

View file

@ -0,0 +1,43 @@
package com.tangem.feature.wallet.presentation.wallet.domain
import com.tangem.domain.common.CardTypesResolver
import com.tangem.utils.toFormattedCurrencyString
import java.math.BigDecimal
/**
* Wallet additional info factory
*
[REDACTED_AUTHOR]
*/
// TODO: Finalize strings [REDACTED_JIRA]
internal object WalletAdditionalInfoFactory {
/**
* Get additional info
*
* @param cardTypesResolver card types resolver
* @param isLocked check if wallet is locked
* @param currencyAmount amount of currency
*/
fun resolve(cardTypesResolver: CardTypesResolver, isLocked: Boolean, currencyAmount: BigDecimal? = null): String {
return if (cardTypesResolver.isMultiwalletAllowed()) {
val backupInfo = "${cardTypesResolver.getBackupCardsCount()} cards"
when {
cardTypesResolver.isWallet2() && !isLocked -> "$backupInfo • Seed phrase"
cardTypesResolver.isTangemWallet() && !isLocked -> backupInfo
isLocked -> "$backupInfo • Locked"
else -> ""
}
} else {
if (isLocked) {
"Locked"
} else {
val blockchain = cardTypesResolver.getBlockchain()
currencyAmount?.toFormattedCurrencyString(
decimals = blockchain.decimals(),
currency = blockchain.currency,
).orEmpty()
}
}
}
}

View file

@ -2,33 +2,38 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.tokens.model.TokenList
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletLoadedTokensListConverter.LoadedTokensListModel
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListErrorToWalletStateConverter
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.converter.Converter
/**
* Converter from loaded [TokenListError] or [TokenList] to [WalletStateHolder]
*
* @property currentStateProvider current ui state provider
* @property currentStateProvider current ui state provider
* @param cardTypeResolverProvider card type resolver
* @param clickIntents screen click intents
*
[REDACTED_AUTHOR]
*/
internal class WalletLoadedTokensListConverter(
private val currentStateProvider: Provider<WalletStateHolder>,
clickCallbacks: WalletClickCallbacks,
cardTypeResolverProvider: Provider<CardTypesResolver>,
clickIntents: WalletClickIntents,
) : Converter<LoadedTokensListModel, WalletStateHolder> {
private val tokenListStateConverter = TokenListToWalletStateConverter(
currentStateProvider = currentStateProvider,
cardTypeResolverProvider = cardTypeResolverProvider,
isWalletContentHidden = false, // TODO: [REDACTED_JIRA]
fiatCurrencyCode = "USD", // TODO: [REDACTED_JIRA]
fiatCurrencySymbol = "$", // TODO: [REDACTED_JIRA]
clickCallbacks = clickCallbacks,
clickIntents = clickIntents,
)
private val tokenListErrorStateConverter = TokenListErrorToWalletStateConverter(

View file

@ -6,11 +6,12 @@ import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.*
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@ -19,12 +20,12 @@ import kotlinx.coroutines.flow.flow
/**
* Converter from loaded list of [UserWallet] to skeleton state of screen [WalletStateHolder]
*
* @property clickCallbacks screen click callbacks
* @property clickIntents screen click intents
*
[REDACTED_AUTHOR]
*/
internal class WalletSkeletonStateConverter(
private val clickCallbacks: WalletClickCallbacks,
private val clickIntents: WalletClickIntents,
) : Converter<List<UserWallet>, WalletStateHolder> {
override fun convert(value: List<UserWallet>): WalletStateHolder {
@ -39,13 +40,13 @@ internal class WalletSkeletonStateConverter(
private fun createMultiCurrencyState(wallets: List<UserWallet>): WalletStateHolder.MultiCurrencyContent {
return WalletStateHolder.MultiCurrencyContent(
onBackClick = clickCallbacks::onBackClick,
onBackClick = clickIntents::onBackClick,
topBarConfig = createTopBarConfig(),
walletsListConfig = createWalletsListConfig(wallets),
pullToRefreshConfig = createPullToRefreshConfig(),
tokensListState = WalletTokensListState.Content(
items = persistentListOf(),
onOrganizeTokensClick = clickCallbacks::onOrganizeTokensClick,
onOrganizeTokensClick = clickIntents::onOrganizeTokensClick,
),
notifications = persistentListOf(),
bottomSheet = null,
@ -57,7 +58,7 @@ internal class WalletSkeletonStateConverter(
cardTypeResolver: CardTypesResolver,
): WalletStateHolder.SingleCurrencyContent {
return WalletStateHolder.SingleCurrencyContent(
onBackClick = clickCallbacks::onBackClick,
onBackClick = clickIntents::onBackClick,
topBarConfig = createTopBarConfig(),
walletsListConfig = createWalletsListConfig(wallets),
pullToRefreshConfig = createPullToRefreshConfig(),
@ -75,8 +76,8 @@ internal class WalletSkeletonStateConverter(
private fun createTopBarConfig(): WalletTopBarConfig {
return WalletTopBarConfig(
onScanCardClick = clickCallbacks::onScanCardClick,
onMoreClick = clickCallbacks::onDetailsClick,
onScanCardClick = clickIntents::onScanCardClick,
onMoreClick = clickIntents::onDetailsClick,
)
}
@ -84,18 +85,22 @@ internal class WalletSkeletonStateConverter(
return WalletsListConfig(
selectedWalletIndex = 0,
wallets = wallets.map { wallet ->
val cardTypeResolver = wallet.scanResponse.cardTypesResolver
WalletCardState.Loading(
id = wallet.walletId,
title = wallet.name,
additionalInfo = "", // TODO add additional info resolver
imageResId = WalletImageResolver.resolve(cardTypesResolver = wallet.scanResponse.cardTypesResolver),
additionalInfo = WalletAdditionalInfoFactory.resolve(
cardTypesResolver = cardTypeResolver,
isLocked = wallet.isLocked,
),
imageResId = WalletImageResolver.resolve(cardTypesResolver = cardTypeResolver),
)
}.toImmutableList(),
onWalletChange = clickCallbacks::onWalletChange,
onWalletChange = clickIntents::onWalletChange,
)
}
private fun createPullToRefreshConfig(): WalletPullToRefreshConfig {
return WalletPullToRefreshConfig(isRefreshing = false, onRefresh = clickCallbacks::onRefreshSwipe)
return WalletPullToRefreshConfig(isRefreshing = false, onRefresh = clickIntents::onRefreshSwipe)
}
}

View file

@ -14,28 +14,30 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletBottomSheetConf
import com.tangem.feature.wallet.presentation.wallet.state.WalletNotification
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletLoadedTokensListConverter.LoadedTokensListModel
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.Flow
/**
* Main factory for creating [WalletStateHolder]
*
* @property currentStateProvider current ui state provider
* @property clickCallbacks screen click callbacks
* @property currentStateProvider current ui state provider
* @param currentCardTypeResolverProvider current card type resolver
* @property clickIntents screen click intents
*/
internal class WalletStateFactory(
private val currentStateProvider: Provider<WalletStateHolder>,
currentCardTypeResolverProvider: Provider<CardTypesResolver>,
private val clickCallbacks: WalletClickCallbacks,
private val clickIntents: WalletClickIntents,
) {
private val skeletonConverter by lazy { WalletSkeletonStateConverter(clickCallbacks = clickCallbacks) }
private val skeletonConverter by lazy { WalletSkeletonStateConverter(clickIntents = clickIntents) }
private val loadedTokensListConverter by lazy {
WalletLoadedTokensListConverter(
currentStateProvider = currentStateProvider,
clickCallbacks = clickCallbacks,
cardTypeResolverProvider = currentCardTypeResolverProvider,
clickIntents = clickIntents,
)
}
@ -53,7 +55,7 @@ internal class WalletStateFactory(
)
}
fun getInitialState(): WalletStateHolder = WalletStateHolder.Loading(onBackClick = clickCallbacks::onBackClick)
fun getInitialState(): WalletStateHolder = WalletStateHolder.Loading(onBackClick = clickIntents::onBackClick)
fun getSkeletonState(wallets: List<UserWallet>): WalletStateHolder = skeletonConverter.convert(wallets)

View file

@ -1,19 +1,27 @@
package com.tangem.feature.wallet.presentation.wallet.utils
import com.tangem.common.Provider
import com.tangem.core.ui.utils.BigDecimalFormatter.formatFiatAmount
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.tokens.model.TokenList
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState
import com.tangem.utils.converter.Converter
internal class FiatBalanceToWalletCardConverter(
private val currentState: WalletCardState,
private val cardTypeResolverProvider: Provider<CardTypesResolver>,
private val isLockedState: Boolean,
private val isWalletContentHidden: Boolean,
private val fiatCurrencyCode: String,
private val fiatCurrencySymbol: String,
) : Converter<TokenList.FiatBalance, WalletCardState> {
override fun convert(value: TokenList.FiatBalance): WalletCardState {
// TODO: [REDACTED_JIRA]
val additionalInfo = WalletAdditionalInfoFactory.resolve(
cardTypesResolver = cardTypeResolverProvider(),
isLocked = isLockedState,
)
return when (value) {
is TokenList.FiatBalance.Loading -> with(currentState) {
WalletCardState.Loading(id, title, additionalInfo, imageResId, onClick)

View file

@ -6,7 +6,7 @@ import com.tangem.domain.tokens.model.TokenList
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState.TokensListItemState
import com.tangem.feature.wallet.presentation.wallet.utils.LoadingItemsProvider.getLoadingMultiCurrencyTokens
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate
@ -16,7 +16,7 @@ internal class TokenListToContentItemsConverter(
isWalletContentHidden: Boolean,
fiatCurrencyCode: String,
fiatCurrencySymbol: String,
private val clickCallbacks: WalletClickCallbacks,
private val clickIntents: WalletClickIntents,
) : Converter<TokenList, WalletTokensListState> {
private val tokenStatusConverter = CryptoCurrencyStatusToTokenItemConverter(
@ -33,7 +33,7 @@ internal class TokenListToContentItemsConverter(
is TokenList.NotInitialized -> getLoadingMultiCurrencyTokens()
},
onOrganizeTokensClick = if (value.totalFiatBalance is TokenList.FiatBalance.Loaded) {
clickCallbacks::onOrganizeTokensClick
clickIntents::onOrganizeTokensClick
} else {
null
},

View file

@ -1,6 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.utils
import com.tangem.common.Provider
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.tokens.model.TokenList
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
@ -8,23 +9,24 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder.Mul
import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter.TokensListModel
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickCallbacks
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toPersistentList
internal class TokenListToWalletStateConverter(
private val currentStateProvider: Provider<WalletStateHolder>,
private val cardTypeResolverProvider: Provider<CardTypesResolver>,
private val isWalletContentHidden: Boolean,
private val fiatCurrencyCode: String,
private val fiatCurrencySymbol: String,
clickCallbacks: WalletClickCallbacks,
clickIntents: WalletClickIntents,
) : Converter<TokensListModel, WalletStateHolder> {
private val tokenListToContentConverter = TokenListToContentItemsConverter(
isWalletContentHidden = isWalletContentHidden,
fiatCurrencyCode = fiatCurrencyCode,
fiatCurrencySymbol = fiatCurrencySymbol,
clickCallbacks = clickCallbacks,
clickIntents = clickIntents,
)
override fun convert(value: TokensListModel): WalletStateHolder {
@ -58,6 +60,8 @@ internal class TokenListToWalletStateConverter(
val selectedWalletCard = walletsListConfig.wallets[selectedWalletIndex]
val converter = FiatBalanceToWalletCardConverter(
currentState = selectedWalletCard,
isLockedState = this is WalletStateHolder.UnlockWalletContent,
cardTypeResolverProvider = cardTypeResolverProvider,
isWalletContentHidden = isWalletContentHidden,
fiatCurrencyCode = fiatCurrencyCode,
fiatCurrencySymbol = fiatCurrencySymbol,

View file

@ -1,6 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.viewmodels
internal interface WalletClickCallbacks {
internal interface WalletClickIntents {
fun onBackClick()

View file

@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.flow
* @property wasCardScannedCallback callback that check if card was scanned
* @property isUserAlreadyRateAppCallback callback that check if card is user already rate app
* @property isDemoCardCallback callback that check if card is demo
* @property clickCallbacks screen click callbacks
* @property clickIntents screen click intents
*
[REDACTED_AUTHOR]
*/
@ -29,7 +29,7 @@ internal class WalletNotificationsListFactory(
private val wasCardScannedCallback: suspend (String) -> Boolean,
private val isUserAlreadyRateAppCallback: suspend () -> Boolean,
private val isDemoCardCallback: (String) -> Boolean,
private val clickCallbacks: WalletClickCallbacks,
private val clickIntents: WalletClickIntents,
) {
fun create(cardTypesResolver: CardTypesResolver, tokenList: TokenList?): Flow<ImmutableList<WalletNotification>> {
@ -60,15 +60,15 @@ internal class WalletNotificationsListFactory(
}
if (!cardTypesResolver.isBackupForbidden() && !cardTypesResolver.hasBackup()) {
add(element = WalletNotification.BackupCard(onClick = clickCallbacks::onBackupCardClick))
add(element = WalletNotification.BackupCard(onClick = clickIntents::onBackupCardClick))
}
if (tokenList != null && tokenList.hasMissedDerivations()) {
add(element = WalletNotification.ScanCard(onClick = clickCallbacks::onScanCardClick))
add(element = WalletNotification.ScanCard(onClick = clickIntents::onScanCardClick))
}
if (isUserAlreadyRateAppCallback()) {
add(element = WalletNotification.LikeTangemApp(onClick = clickCallbacks::onLikeTangemAppClick))
add(element = WalletNotification.LikeTangemApp(onClick = clickIntents::onLikeTangemAppClick))
}
}.toImmutableList(),
)
@ -94,13 +94,13 @@ internal class WalletNotificationsListFactory(
if (cardTypesResolver.isBackupForbidden() && cardTypesResolver.hasWalletSignedHashes()) {
add(
element = WalletNotification.CriticalWarningAlreadySignedHashes(
onClick = clickCallbacks::onCriticalWarningAlreadySignedHashesClick,
onClick = clickIntents::onCriticalWarningAlreadySignedHashesClick,
),
)
} else if (cardTypesResolver.hasWalletSignedHashes()) {
add(
element = WalletNotification.WarningAlreadySignedHashes(
onClick = clickCallbacks::onCloseWarningAlreadySignedHashesClick,
onClick = clickIntents::onCloseWarningAlreadySignedHashesClick,
),
)
}

View file

@ -52,7 +52,7 @@ internal class WalletViewModel @Inject constructor(
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val dispatchers: CoroutineDispatcherProvider,
) : ViewModel(), DefaultLifecycleObserver, WalletClickCallbacks {
) : ViewModel(), DefaultLifecycleObserver, WalletClickIntents {
/** Feature router */
var router: InnerWalletRouter by Delegates.notNull()
@ -62,7 +62,7 @@ internal class WalletViewModel @Inject constructor(
wasCardScannedCallback = getCardWasScannedUseCase::invoke,
isUserAlreadyRateAppCallback = isUserAlreadyRateAppUseCase::invoke,
isDemoCardCallback = isDemoCardUseCase::invoke,
clickCallbacks = this,
clickIntents = this,
)
private val stateFactory = WalletStateFactory(
@ -70,7 +70,7 @@ internal class WalletViewModel @Inject constructor(
currentCardTypeResolverProvider = Provider {
getCardTypeResolver(index = uiState.walletsListConfig.selectedWalletIndex)
},
clickCallbacks = this,
clickIntents = this,
)
/** Screen state */