Updated on 2026-08-14
This commit is contained in:
commit
dfd7076c2e
31 changed files with 345 additions and 648 deletions
|
|
@ -6,6 +6,7 @@ import com.squareup.moshi.JsonDataException
|
|||
import com.squareup.moshi.Types
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ inline fun <reified T> AppPreferencesStore.getObject(key: Preferences.Key<String
|
|||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -38,7 +39,7 @@ inline fun <reified T> AppPreferencesStore.getObject(key: Preferences.Key<String
|
|||
} catch (e: JsonDataException) {
|
||||
default
|
||||
}
|
||||
}
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -100,7 +101,7 @@ suspend inline fun <reified T> AppPreferencesStore.storeObjectList(key: Preferen
|
|||
/** Get flow of list of data [T] by string [key]. If data is not found, it returns `null` */
|
||||
inline fun <reified T> AppPreferencesStore.getObjectList(key: Preferences.Key<String>): Flow<List<T>?> {
|
||||
val adapter = moshi.adapter<List<T>>(Types.newParameterizedType(List::class.java, T::class.java))
|
||||
return data.map { it[key]?.let(adapter::fromJson) }
|
||||
return data.map { it[key]?.let(adapter::fromJson) }.distinctUntilChanged()
|
||||
}
|
||||
|
||||
/** Get list of data [T] by string [key], or empty if data is not found */
|
||||
|
|
|
|||
|
|
@ -19,10 +19,6 @@
|
|||
"name": "WC_SOLANA_TX_SIGN_ENABLED",
|
||||
"version": "undefined"
|
||||
},
|
||||
{
|
||||
"name": "TOKEN_LIST_LCE_ENABLED",
|
||||
"version": "5.12.0"
|
||||
},
|
||||
{
|
||||
"name": "CARDANO_TOKENS_SUPPORT_ENABLED",
|
||||
"version": "5.12.0"
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@ val TangemBlockCardColors: CardColors
|
|||
get() = CardColors(
|
||||
containerColor = TangemTheme.colors.background.primary,
|
||||
contentColor = TangemTheme.colors.text.primary1,
|
||||
disabledContainerColor = TangemTheme.colors.button.disabled,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
disabledContainerColor = TangemTheme.colors.background.primary,
|
||||
disabledContentColor = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
|
@ -261,7 +261,7 @@ internal class DefaultCurrenciesRepository(
|
|||
|
||||
launch(dispatchers.io) {
|
||||
combine(
|
||||
getMultiCurrencyWalletCurrencies(userWallet).distinctUntilChanged(),
|
||||
getMultiCurrencyWalletCurrencies(userWallet),
|
||||
isMultiCurrencyWalletCurrenciesFetching.map { it.getOrElse(userWallet.walletId) { false } },
|
||||
) { currencies, isFetching ->
|
||||
send(currencies, isStillLoading = isFetching)
|
||||
|
|
@ -442,21 +442,23 @@ internal class DefaultCurrenciesRepository(
|
|||
}
|
||||
|
||||
private suspend fun fetchTokensIfCacheExpired(userWallet: UserWallet, refresh: Boolean) {
|
||||
try {
|
||||
isMultiCurrencyWalletCurrenciesFetching.update {
|
||||
it + (userWallet.walletId to true)
|
||||
}
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getTokensCacheKey(userWallet.walletId),
|
||||
skipCache = refresh,
|
||||
block = {
|
||||
isMultiCurrencyWalletCurrenciesFetching.update {
|
||||
it + (userWallet.walletId to true)
|
||||
}
|
||||
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getTokensCacheKey(userWallet.walletId),
|
||||
skipCache = refresh,
|
||||
block = { fetchTokens(userWallet) },
|
||||
)
|
||||
} finally {
|
||||
isMultiCurrencyWalletCurrenciesFetching.update {
|
||||
it - userWallet.walletId
|
||||
}
|
||||
}
|
||||
try {
|
||||
fetchTokens(userWallet)
|
||||
} finally {
|
||||
isMultiCurrencyWalletCurrenciesFetching.update {
|
||||
it - userWallet.walletId
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchTokens(userWallet: UserWallet) {
|
||||
|
|
|
|||
|
|
@ -183,24 +183,22 @@ internal class DefaultNetworksRepository(
|
|||
networks: Set<Network>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
try {
|
||||
isNetworkStatusesFetching.update {
|
||||
it + (userWalletId to true)
|
||||
}
|
||||
val currencies = getCurrencies(userWalletId, networks)
|
||||
val networksDeferred = networks.mapNotNull { network ->
|
||||
fetchNetworkStatusIfCacheExpired(userWalletId, network, currencies, refresh)
|
||||
}
|
||||
|
||||
val currencies = getCurrencies(userWalletId, networks)
|
||||
coroutineScope {
|
||||
networks
|
||||
.map { network ->
|
||||
async {
|
||||
fetchNetworkStatusIfCacheExpired(userWalletId, network, currencies, refresh)
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
} finally {
|
||||
isNetworkStatusesFetching.update {
|
||||
it - userWalletId
|
||||
if (networksDeferred.isNotEmpty()) {
|
||||
try {
|
||||
isNetworkStatusesFetching.update {
|
||||
it + (userWalletId to true)
|
||||
}
|
||||
|
||||
networksDeferred.awaitAll()
|
||||
} finally {
|
||||
isNetworkStatusesFetching.update {
|
||||
it - userWalletId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -226,12 +224,19 @@ internal class DefaultNetworksRepository(
|
|||
network: Network,
|
||||
currencies: Sequence<CryptoCurrency>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getNetworksStatusesCacheKey(userWalletId, network),
|
||||
skipCache = refresh,
|
||||
block = { fetchNetworkStatus(userWalletId, network, currencies) },
|
||||
)
|
||||
): Deferred<Unit>? = coroutineScope {
|
||||
val key = getNetworksStatusesCacheKey(userWalletId, network)
|
||||
if (refresh || cacheRegistry.isExpired(key)) {
|
||||
async {
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = key,
|
||||
skipCache = refresh,
|
||||
block = { fetchNetworkStatus(userWalletId, network, currencies) },
|
||||
)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchNetworkStatus(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.domain.balancehiding.error
|
|||
|
||||
sealed class HideBalancesError {
|
||||
|
||||
object HidingDisabled : HideBalancesError()
|
||||
data object HidingDisabled : HideBalancesError()
|
||||
|
||||
data class DataError(val cause: Throwable) : HideBalancesError()
|
||||
}
|
||||
|
|
@ -107,4 +107,43 @@ sealed class Lce<out E : Any, out C : Any> {
|
|||
ifContent = { null },
|
||||
ifError = ::identity,
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns `true` if this [Lce] is a [Lce.Loading] state and the given predicate is `true`.
|
||||
*
|
||||
* @param predicate The predicate to apply to the partial content.
|
||||
* By default, the predicate is `true` for any partial content.
|
||||
* @return `true` if this [Lce] is a [Lce.Loading] state and the given predicate is `true`, `false` otherwise.
|
||||
*/
|
||||
fun isLoading(predicate: (maybeContent: C?) -> Boolean = { true }): Boolean = fold(
|
||||
ifLoading = { predicate(it) },
|
||||
ifContent = { false },
|
||||
ifError = { false },
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns `true` if this [Lce] is a [Lce.Error] state and the given predicate is `true`.
|
||||
*
|
||||
* @param predicate The predicate to apply to the error.
|
||||
* By default, the predicate is `true` for any error.
|
||||
* @return `true` if this [Lce] is a [Lce.Error] state and the given predicate is `true`, `false` otherwise.
|
||||
*/
|
||||
fun isError(predicate: (error: E) -> Boolean = { true }): Boolean = fold(
|
||||
ifLoading = { false },
|
||||
ifContent = { false },
|
||||
ifError = { predicate(it) },
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns `true` if this [Lce] is a [Lce.Content] state and the given predicate is `true`.
|
||||
*
|
||||
* @param predicate The predicate to apply to the content.
|
||||
* By default, the predicate is `true` for any content.
|
||||
* @return `true` if this [Lce] is a [Lce.Content] state and the given predicate is `true`, `false` otherwise.
|
||||
*/
|
||||
fun isContent(predicate: (content: C) -> Boolean = { true }): Boolean = fold(
|
||||
ifLoading = { false },
|
||||
ifContent = { predicate(it) },
|
||||
ifError = { false },
|
||||
)
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ class LceRaise<E : Any> @PublishedApi internal constructor(
|
|||
* */
|
||||
@RaiseDSL
|
||||
@OptIn(ExperimentalTypeInference::class)
|
||||
inline fun <OtherError : Any, C : Any> withError(
|
||||
inline fun <OtherError : Any, C> withError(
|
||||
transform: (OtherError) -> E,
|
||||
@BuilderInference block: LceRaise<OtherError>.() -> C,
|
||||
): C = recover(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.left
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.core.utils.EitherFlow
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
import com.tangem.domain.core.utils.toLce
|
||||
|
|
@ -12,7 +10,6 @@ import com.tangem.domain.tokens.error.mapper.mapToTokenListError
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesLceOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.operations.TokenListOperations
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
|
|
@ -31,29 +28,7 @@ class GetTokenListUseCase(
|
|||
) {
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun launch(userWalletId: UserWalletId): EitherFlow<TokenListError, TokenList> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
userWalletId = userWalletId,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
|
||||
return operations.getCurrenciesStatusesFlow().transformLatest { maybeTokens ->
|
||||
maybeTokens.fold(
|
||||
ifLeft = { error ->
|
||||
emit(error.mapToTokenListError().left())
|
||||
},
|
||||
ifRight = { tokens ->
|
||||
emitAll(createTokenList(userWalletId, tokens))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun launchLce(userWalletId: UserWalletId): LceFlow<TokenListError, TokenList> {
|
||||
fun launch(userWalletId: UserWalletId): LceFlow<TokenListError, TokenList> {
|
||||
val operations = CurrenciesStatusesLceOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
|
|
@ -78,21 +53,6 @@ class GetTokenListUseCase(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createTokenList(
|
||||
userWalletId: UserWalletId,
|
||||
tokens: List<CryptoCurrencyStatus>,
|
||||
): EitherFlow<TokenListError, TokenList> {
|
||||
val operations = TokenListOperations(
|
||||
userWalletId = userWalletId,
|
||||
tokens = tokens,
|
||||
currenciesRepository = currenciesRepository,
|
||||
)
|
||||
|
||||
return operations.getTokenListFlow().map { maybeTokenList ->
|
||||
maybeTokenList.mapLeft(TokenListOperations.Error::mapToTokenListError)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTokenListLce(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: List<CryptoCurrencyStatus>,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.atomic.update
|
||||
import arrow.core.raise.ensureNotNull
|
||||
import arrow.core.toNonEmptyListOrNull
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
|
|
@ -16,9 +17,10 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.transform
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
|
||||
class GetWalletTotalBalanceUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
|
|
@ -28,9 +30,9 @@ class GetWalletTotalBalanceUseCase(
|
|||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWallestIds: Collection<UserWalletId>,
|
||||
userTallestIds: Collection<UserWalletId>,
|
||||
): LceFlow<TokenListError, Map<UserWalletId, TotalFiatBalance>> {
|
||||
val flows = userWallestIds.distinct()
|
||||
val flows = userTallestIds.distinct()
|
||||
.map { userWalletId ->
|
||||
invoke(userWalletId).map { maybeBalance ->
|
||||
userWalletId to maybeBalance
|
||||
|
|
@ -39,17 +41,23 @@ class GetWalletTotalBalanceUseCase(
|
|||
|
||||
return combine(flows) { balances ->
|
||||
lce {
|
||||
balances.associate { (userWalletId, maybeBalance) ->
|
||||
userWalletId to maybeBalance.bind()
|
||||
balances.fold(mutableMapOf()) { acc, (userWalletId, maybeBalance) ->
|
||||
val balance = maybeBalance.bindOrNull() ?: TotalFiatBalance.Loading
|
||||
|
||||
isLoading.update { it || balance is TotalFiatBalance.Loading }
|
||||
|
||||
acc[userWalletId] = balance
|
||||
acc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
suspend operator fun invoke(userWalletId: UserWalletId): LceFlow<TokenListError, TotalFiatBalance> {
|
||||
val currenciesStatuses = getStatuses(userWalletId)
|
||||
|
||||
return currenciesStatuses.transform { maybeStatuses ->
|
||||
return currenciesStatuses.transformLatest { maybeStatuses ->
|
||||
val balance = createBalance(maybeStatuses)
|
||||
|
||||
emit(balance)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ internal class CurrenciesStatusesLceOperations(
|
|||
return transformToCurrenciesStatuses(
|
||||
userWalletId = userWalletId,
|
||||
flow = if (isSingleCurrencyWalletsAllowed) {
|
||||
getWalletCurrenies(userWalletId)
|
||||
getWalletCurrencies(userWalletId)
|
||||
} else {
|
||||
getMultiCurrencyWalletCurrencies(userWalletId)
|
||||
},
|
||||
|
|
@ -105,7 +105,7 @@ internal class CurrenciesStatusesLceOperations(
|
|||
return statuses
|
||||
}
|
||||
|
||||
private fun getWalletCurrenies(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrency>> {
|
||||
private fun getWalletCurrencies(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrency>> {
|
||||
return currenciesRepository.getWalletCurrenciesUpdates(userWalletId)
|
||||
.map { maybeCurrencies ->
|
||||
maybeCurrencies.mapError { TokenListError.DataError(it) }
|
||||
|
|
|
|||
|
|
@ -24,52 +24,6 @@ internal class CurrenciesStatusesOperations(
|
|||
private val userWalletId: UserWalletId,
|
||||
) {
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun getCurrenciesStatusesFlow(): EitherFlow<Error, List<CryptoCurrencyStatus>> {
|
||||
return getMultiCurrencyWalletCurrencies().transformLatest { maybeCurrencies ->
|
||||
val nonEmptyCurrencies = maybeCurrencies.fold(
|
||||
ifLeft = { error ->
|
||||
emit(error.left())
|
||||
return@transformLatest
|
||||
},
|
||||
ifRight = List<CryptoCurrency>::toNonEmptyListOrNull,
|
||||
)
|
||||
|
||||
if (nonEmptyCurrencies == null) {
|
||||
val emptyCurrenciesStatuses = emptyList<CryptoCurrencyStatus>()
|
||||
|
||||
emit(emptyCurrenciesStatuses.right())
|
||||
return@transformLatest
|
||||
}
|
||||
|
||||
val maybeLoadingCurrenciesStatuses = createCurrenciesStatuses(
|
||||
currencies = nonEmptyCurrencies,
|
||||
maybeNetworkStatuses = null,
|
||||
maybeQuotes = null,
|
||||
maybeYieldBalances = null,
|
||||
)
|
||||
|
||||
emit(maybeLoadingCurrenciesStatuses)
|
||||
|
||||
val (networks, currenciesIds) = getIds(nonEmptyCurrencies)
|
||||
|
||||
val currenciesFlow = combine(
|
||||
getQuotes(currenciesIds),
|
||||
getNetworksStatuses(networks),
|
||||
getYieldBalances(),
|
||||
) { maybeQuotes, maybeNetworksStatuses, maybeYieldBalances ->
|
||||
createCurrenciesStatuses(
|
||||
currencies = nonEmptyCurrencies,
|
||||
maybeQuotes = maybeQuotes,
|
||||
maybeNetworkStatuses = maybeNetworksStatuses,
|
||||
maybeYieldBalances = maybeYieldBalances,
|
||||
)
|
||||
}
|
||||
|
||||
emitAll(currenciesFlow)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getCurrenciesStatusesSync(): Either<Error, List<CryptoCurrencyStatus>> {
|
||||
return either {
|
||||
catch(
|
||||
|
|
@ -360,13 +314,6 @@ internal class CurrenciesStatusesOperations(
|
|||
return currencyStatusOperations.createTokenStatus()
|
||||
}
|
||||
|
||||
private fun getMultiCurrencyWalletCurrencies(): Flow<Either<Error, List<CryptoCurrency>>> {
|
||||
return currenciesRepository.getMultiCurrencyWalletCurrenciesUpdates(userWalletId)
|
||||
.map<List<CryptoCurrency>, Either<Error, List<CryptoCurrency>>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyCurrencies.left()) }
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getMultiCurrencyWalletCurrency(currencyId: CryptoCurrency.ID): CryptoCurrency {
|
||||
return Either.catch {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(
|
||||
|
|
|
|||
|
|
@ -1,322 +0,0 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.core.error.DataError
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.mock.MockNetworks
|
||||
import com.tangem.domain.tokens.mock.MockQuotes
|
||||
import com.tangem.domain.tokens.mock.MockTokenLists
|
||||
import com.tangem.domain.tokens.mock.MockTokens
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.tokens.repository.MockCurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.MockNetworksRepository
|
||||
import com.tangem.domain.tokens.repository.MockQuotesRepository
|
||||
import com.tangem.domain.tokens.repository.MockStakingRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
|
||||
internal class GetTokenListUseCaseTest {
|
||||
|
||||
private val userWalletId = UserWalletId(value = null)
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun `when list ungrouped and unsorted then correct token list should be returned`() = runTest {
|
||||
// Given
|
||||
val expectedResult = listOf(
|
||||
MockTokenLists.loadingUngroupedTokenList.right(),
|
||||
MockTokenLists.failedUngroupedTokenList.right(),
|
||||
)
|
||||
|
||||
val useCase = getUseCase(
|
||||
isGrouped = flowOf(false.right()),
|
||||
isSortedByBalance = flowOf(false.right()),
|
||||
)
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId)
|
||||
.take(count = 2)
|
||||
.toList()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when tokens getting failed then error should be received`() = runTest {
|
||||
// Given
|
||||
val expectedResult = TokenListError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
||||
|
||||
val useCase = getUseCase(tokens = flowOf(DataError.NetworkError.NoInternetConnection.left()))
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId).first()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when quotes getting failed then token list without quotes should be received`() = runTest {
|
||||
// Given
|
||||
val expectedResult = listOf(
|
||||
MockTokenLists.loadingUngroupedTokenList.right(),
|
||||
MockTokenLists.noQuotesUngroupedTokenList.right(),
|
||||
)
|
||||
|
||||
val useCase = getUseCase(
|
||||
quotes = flowOf(DataError.NetworkError.NoInternetConnection.left()),
|
||||
statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()),
|
||||
)
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId)
|
||||
.take(count = 2)
|
||||
.toList()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when grouping type getting failed then error should be received`() = runTest {
|
||||
// Given
|
||||
val expectedResult = TokenListError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
||||
|
||||
val useCase = getUseCase(isGrouped = flowOf(DataError.NetworkError.NoInternetConnection.left()))
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId).first()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when sorting type getting failed then error should be received`() = runTest {
|
||||
// Given
|
||||
val expectedResult = TokenListError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
||||
|
||||
val useCase = getUseCase(isSortedByBalance = flowOf(DataError.NetworkError.NoInternetConnection.left()))
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId).first()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun `when tokens getting failed on second emit then error should be received`() = runTest {
|
||||
// Given
|
||||
val error = DataError.NetworkError.NoInternetConnection.left()
|
||||
val expectedResult = listOf(
|
||||
MockTokenLists.loadingUngroupedTokenList.right(),
|
||||
MockTokenLists.failedUngroupedTokenList.right(),
|
||||
TokenListError.DataError(DataError.NetworkError.NoInternetConnection).left(),
|
||||
)
|
||||
|
||||
val useCase = getUseCase(
|
||||
tokens = flowOf(
|
||||
MockTokens.tokens.right(),
|
||||
error,
|
||||
).map { delay(timeMillis = 1_000); it },
|
||||
)
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId)
|
||||
.take(count = 3)
|
||||
.toList()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun `when list grouped then correct token list should be received`() = runTest {
|
||||
val expectedResult = listOf(
|
||||
MockTokenLists.loadingGroupedTokenList.right(),
|
||||
MockTokenLists.failedGroupedTokenList.right(),
|
||||
)
|
||||
|
||||
val useCase = getUseCase(isGrouped = flowOf(true.right()))
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId)
|
||||
.take(count = 2)
|
||||
.toList()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when list is sorted and ungrouped then correct token list should be received`() = runTest {
|
||||
val expectedResult = listOf(
|
||||
MockTokenLists.loadingUngroupedTokenList.copy(sortedBy = TokenList.SortType.BALANCE).right(),
|
||||
MockTokenLists.sortedUngroupedTokenList.right(),
|
||||
)
|
||||
|
||||
val useCase = getUseCase(
|
||||
statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()),
|
||||
isGrouped = flowOf(false.right()),
|
||||
isSortedByBalance = flowOf(true.right()),
|
||||
)
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId)
|
||||
.take(count = 2)
|
||||
.toList()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when list is sorted and grouped then correct token list should be received`() = runTest {
|
||||
val expectedResult = listOf(
|
||||
MockTokenLists.loadingGroupedTokenList.copy(sortedBy = TokenList.SortType.BALANCE).right(),
|
||||
MockTokenLists.sortedGroupedTokenList.right(),
|
||||
)
|
||||
|
||||
val useCase = getUseCase(
|
||||
statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()),
|
||||
isGrouped = flowOf(true.right()),
|
||||
isSortedByBalance = flowOf(true.right()),
|
||||
)
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId)
|
||||
.take(count = 2)
|
||||
.toList()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when tokens is empty then not initialized token list should be received`() = runTest {
|
||||
val expectedResult = MockTokenLists.emptyTokenList.right()
|
||||
|
||||
val useCase = getUseCase(tokens = flowOf(emptyList<CryptoCurrency>().right()))
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId).first()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when tokens flow is empty then error should be received`() = runTest {
|
||||
val expectedResult = TokenListError.EmptyTokens.left()
|
||||
|
||||
val useCase = getUseCase(tokens = flowOf())
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId).first()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when networks statuses flow is empty then error should be received`() = runTest {
|
||||
val expectedResult = listOf(
|
||||
MockTokenLists.loadingUngroupedTokenList.right(),
|
||||
TokenListError.EmptyTokens.left(),
|
||||
)
|
||||
|
||||
val useCase = getUseCase(statuses = flowOf())
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId)
|
||||
.take(count = 2)
|
||||
.toList()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when networks statuses is empty then loading token list should be received`() = runTest {
|
||||
val expectedResult = MockTokenLists.loadingUngroupedTokenList.right()
|
||||
|
||||
val useCase = getUseCase(statuses = flowOf(emptySet<NetworkStatus>().right()))
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId).first()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when quotes flow is empty then list without quotes should be received`() = runTest {
|
||||
val expectedResult = listOf(
|
||||
MockTokenLists.loadingUngroupedTokenList.right(),
|
||||
MockTokenLists.noQuotesUngroupedTokenList.right(),
|
||||
)
|
||||
|
||||
val useCase = getUseCase(
|
||||
statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()),
|
||||
quotes = flowOf(emptySet<Quote>().right()),
|
||||
)
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId)
|
||||
.take(count = 2)
|
||||
.toList()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when quotes is empty and statuses verified then loading token list should be received`() = runTest {
|
||||
val expectedResult = MockTokenLists.loadingUngroupedTokenList.right()
|
||||
|
||||
val useCase = getUseCase(
|
||||
statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()),
|
||||
quotes = flowOf(emptySet<Quote>().right()),
|
||||
)
|
||||
|
||||
// When
|
||||
val result = useCase.launch(userWalletId).first()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
private fun getUseCase(
|
||||
tokens: Flow<Either<DataError, List<CryptoCurrency>>> = flowOf(MockTokens.tokens.right()),
|
||||
quotes: Flow<Either<DataError, Set<Quote>>> = flowOf(MockQuotes.quotes.right()),
|
||||
statuses: Flow<Either<DataError, Set<NetworkStatus>>> = flowOf(MockNetworks.errorNetworksStatuses.right()),
|
||||
isGrouped: Flow<Either<DataError, Boolean>> = flowOf(MockTokenLists.isGrouped.right()),
|
||||
isSortedByBalance: Flow<Either<DataError, Boolean>> = flowOf(MockTokenLists.isSortedByBalance.right()),
|
||||
) = GetTokenListUseCase(
|
||||
currenciesRepository = MockCurrenciesRepository(
|
||||
sortTokensResult = Unit.right(),
|
||||
removeCurrencyResult = Unit.right(),
|
||||
token = MockTokens.token1.right(),
|
||||
tokens = tokens,
|
||||
isGrouped = isGrouped,
|
||||
isSortedByBalance = isSortedByBalance,
|
||||
),
|
||||
quotesRepository = MockQuotesRepository(quotes),
|
||||
networksRepository = MockNetworksRepository(statuses),
|
||||
stakingRepository = MockStakingRepository(),
|
||||
)
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 = {},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 |
|
|
@ -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>
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue