Updated on 2026-08-14

This commit is contained in:
Tangem 2024-01-10 15:56:05 +03:00
commit 8bba8e1afa
825 changed files with 9837 additions and 22210 deletions

View file

@ -4,7 +4,7 @@ import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
/**
* Default implementation of CustomToken feature toggles
* Default implementation of Wallet feature toggles
*
* @property featureTogglesManager manager for getting information about the availability of feature toggles
*
@ -14,9 +14,6 @@ internal class DefaultWalletFeatureToggles(
private val featureTogglesManager: FeatureTogglesManager,
) : WalletFeatureToggles {
override val isRedesignedScreenEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(name = "REDESIGNED_WALLET_SCREEN_ENABLED")
override val isWalletsScrollingPreviewEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(name = "WALLETS_SCROLLING_PREVIEW_ENABLED")
}

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.organizetokens
import com.tangem.common.Provider
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.event.triggeredEvent
import com.tangem.domain.appcurrency.model.AppCurrency
@ -16,6 +15,7 @@ import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.err
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.CryptoCurrencyToDraggableItemConverter
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.NetworkGroupToDraggableItemsConverter
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.TokenListToListStateConverter
import com.tangem.utils.Provider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update

View file

@ -2,7 +2,6 @@ package com.tangem.feature.wallet.presentation.organizetokens
import androidx.lifecycle.*
import arrow.core.getOrElse
import com.tangem.common.Provider
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
@ -22,6 +21,7 @@ import com.tangem.feature.wallet.presentation.organizetokens.utils.common.disabl
import com.tangem.feature.wallet.presentation.organizetokens.utils.dnd.DragAndDropAdapter
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
import com.tangem.feature.wallet.presentation.router.WalletRoute
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.*

View file

@ -1,10 +1,10 @@
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter
import com.tangem.common.Provider
import com.tangem.domain.tokens.model.TokenList
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items.TokenListToListStateConverter
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
internal class TokenListToStateConverter(

View file

@ -1,9 +1,9 @@
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.error
import com.tangem.common.Provider
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.InProgressStateConverter
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
internal class TokenListErrorConverter(

View file

@ -1,9 +1,9 @@
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.error
import com.tangem.common.Provider
import com.tangem.domain.tokens.error.TokenListSortingError
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensState
import com.tangem.feature.wallet.presentation.organizetokens.utils.converter.InProgressStateConverter
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
internal class TokenListSortingErrorConverter(

View file

@ -1,14 +1,14 @@
package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.items
import com.tangem.common.Provider
import com.tangem.core.ui.components.currency.tokenicon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.core.ui.components.currency.tokenicon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getGroupHeaderId
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getTokenItemId
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
internal class CryptoCurrencyToDraggableItemConverter(

View file

@ -1,12 +1,12 @@
package com.tangem.feature.wallet.presentation.organizetokens.utils.dnd
import com.tangem.common.Provider
import com.tangem.feature.wallet.presentation.organizetokens.DragAndDropIntents
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.divideMovingItem
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.uniteItems
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.updateItems
import com.tangem.utils.Provider
import kotlinx.collections.immutable.mutate
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow

View file

@ -62,5 +62,33 @@ sealed class WalletScreenAnalyticsEvent {
object NoticeScanYourCardTapped : MainScreen(event = "Notice - Scan Your Card Tapped")
object NoticeWalletLocked : MainScreen(event = "Notice - Wallet Locked")
object WalletUnlockTapped : MainScreen(event = "Button - Wallet Unlock Tapped")
object NetworksUnreachable : MainScreen(event = "Notice - Networks Unreachable")
object MissingAddresses : MainScreen(event = "Notice - Missing Addresses")
object CardSignedTransactions : MainScreen(event = "Notice - Card Signed Transactions")
object HowDoYouLikeTangem : MainScreen(event = "Notice - How Do You Like Tangem")
object ProductSampleCard : MainScreen(event = "Notice - Product Sample Card")
object TestnetCard : MainScreen(event = "Notice - Testnet Card")
object DemoCard : MainScreen(event = "Notice - Demo Card")
object DevelopmentCard : MainScreen(event = "Notice - Development Card")
object WalletUnlock : MainScreen(event = "Notice - Wallet Unlock")
object BackupYourWallet : MainScreen(event = "Notice - Backup Your Wallet")
object UnlockAllWithFaceID : MainScreen(event = "Button - Unlock All With Face ID")
object UnlockWithCardScan : MainScreen(event = "Button - Unlock With Card Scan")
object EditWalletTapped : MainScreen(event = "Button - Edit Wallet Tapped")
object DeleteWalletTapped : MainScreen(event = "Button - Delete Wallet Tapped")
}
}

View file

@ -11,7 +11,8 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkGroup
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.Basic
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
import dagger.hilt.android.scopes.ViewModelScoped
import java.math.BigDecimal
import javax.inject.Inject
@ -23,58 +24,45 @@ internal class TokenListAnalyticsSender @Inject constructor(
) {
suspend fun send(userWallet: UserWallet, maybeTokenList: Either<TokenListError, TokenList>) {
val tokenList = (maybeTokenList as? Either.Right)?.value ?: return
val tokenList = maybeTokenList.getOrElse { return }
sendBalanceLoadedEventIfNeeded(tokenList)
sendToppedUpEventIfNeeded(tokenList, userWallet)
if (tokenList.totalFiatBalance is TokenList.FiatBalance.Loading) return
val currenciesStatuses = getCurrenciesStatuses(tokenList)
sendBalanceLoadedEventIfNeeded(tokenList.totalFiatBalance, currenciesStatuses)
sendToppedUpEventIfNeeded(userWallet, tokenList.totalFiatBalance, currenciesStatuses)
sendUnreachableNetworksEventIfNeeded(currenciesStatuses)
sendMissedAddressesEventIfNeeded(currenciesStatuses)
}
private fun sendBalanceLoadedEventIfNeeded(tokenList: TokenList) {
createCardBalanceState(tokenList)?.let { balanceState ->
analyticsEventHandler.send(event = WalletScreenAnalyticsEvent.Basic.BalanceLoaded(balanceState))
private fun getCurrenciesStatuses(tokenList: TokenList): List<CryptoCurrencyStatus> = when (tokenList) {
is TokenList.Empty -> emptyList()
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
is TokenList.Ungrouped -> tokenList.currencies
}
private fun sendBalanceLoadedEventIfNeeded(
fiatBalance: TokenList.FiatBalance,
currenciesStatuses: List<CryptoCurrencyStatus>,
) {
createCardBalanceState(fiatBalance, currenciesStatuses)?.let { balanceState ->
analyticsEventHandler.send(Basic.BalanceLoaded(balanceState))
}
}
private suspend fun sendToppedUpEventIfNeeded(tokenList: TokenList, userWallet: UserWallet) {
val balanceState = tokenList.toWalletBalanceState() ?: return
val isWalletToppedUp = checkIsWalletToppedUpUseCase(userWallet.walletId, balanceState)
.getOrElse { return }
if (isWalletToppedUp) {
val walletType = if (userWallet.isMultiCurrency) {
AnalyticsParam.WalletType.MultiCurrency
} else {
// For single currency wallets with token list, e.g. Noodle
val currency = when (tokenList) {
is TokenList.Empty -> return
is TokenList.GroupedByNetwork -> tokenList.groups.first().currencies.first()
is TokenList.Ungrouped -> tokenList.currencies.first()
}
AnalyticsParam.WalletType.SingleCurrency(currency.currency.name)
}
analyticsEventHandler.send(WalletScreenAnalyticsEvent.Basic.WalletToppedUp(userWallet.walletId, walletType))
}
}
private fun createCardBalanceState(tokenList: TokenList): AnalyticsParam.CardBalanceState? {
return when (val fiatBalance = tokenList.totalFiatBalance) {
is TokenList.FiatBalance.Failed -> fiatBalance.toCardBalanceState(tokenList)
is TokenList.FiatBalance.Loaded -> fiatBalance.toCardBalanceState()
private fun createCardBalanceState(
fiatBalance: TokenList.FiatBalance,
currenciesStatuses: List<CryptoCurrencyStatus>,
): AnalyticsParam.CardBalanceState? {
return when (fiatBalance) {
is TokenList.FiatBalance.Failed -> getCardBalanceState(currenciesStatuses)
is TokenList.FiatBalance.Loaded -> getCardBalanceState(fiatBalance)
is TokenList.FiatBalance.Loading -> null
}
}
@Suppress("UnusedReceiverParameter")
private fun TokenList.FiatBalance.Failed.toCardBalanceState(tokenList: TokenList): AnalyticsParam.CardBalanceState {
val currenciesStatuses = when (tokenList) {
is TokenList.Empty -> emptyList()
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
is TokenList.Ungrouped -> tokenList.currencies
}
private fun getCardBalanceState(currenciesStatuses: List<CryptoCurrencyStatus>): AnalyticsParam.CardBalanceState {
return when {
currenciesStatuses.isEmpty() -> AnalyticsParam.CardBalanceState.Empty
currenciesStatuses.any { it.value is CryptoCurrencyStatus.NoQuote } -> {
@ -84,19 +72,43 @@ internal class TokenListAnalyticsSender @Inject constructor(
}
}
private fun TokenList.FiatBalance.Loaded.toCardBalanceState(): AnalyticsParam.CardBalanceState {
return if (amount > BigDecimal.ZERO) {
private fun getCardBalanceState(fiatBalance: TokenList.FiatBalance.Loaded): AnalyticsParam.CardBalanceState {
return if (fiatBalance.amount > BigDecimal.ZERO) {
AnalyticsParam.CardBalanceState.Full
} else {
AnalyticsParam.CardBalanceState.Empty
}
}
private fun TokenList.toWalletBalanceState(): WalletBalanceState? {
return when (val balance = totalFiatBalance) {
private suspend fun sendToppedUpEventIfNeeded(
userWallet: UserWallet,
fiatBalance: TokenList.FiatBalance,
currenciesStatuses: List<CryptoCurrencyStatus>,
) {
val balanceState = getWalletBalanceState(fiatBalance) ?: return
val isWalletToppedUp = checkIsWalletToppedUpUseCase(userWallet.walletId, balanceState)
.getOrElse { return }
if (isWalletToppedUp) {
val walletType = if (userWallet.isMultiCurrency) {
AnalyticsParam.WalletType.MultiCurrency
} else {
// For single currency wallets with token list, e.g. Noodle
val currency = currenciesStatuses.firstOrNull() ?: return
AnalyticsParam.WalletType.SingleCurrency(currency.currency.name)
}
analyticsEventHandler.send(Basic.WalletToppedUp(userWallet.walletId, walletType))
}
}
private fun getWalletBalanceState(fiatBalance: TokenList.FiatBalance): WalletBalanceState? {
return when (fiatBalance) {
is TokenList.FiatBalance.Failed -> WalletBalanceState.Error
is TokenList.FiatBalance.Loaded -> {
if (balance.amount > BigDecimal.ZERO) {
if (fiatBalance.amount > BigDecimal.ZERO) {
WalletBalanceState.ToppedUp
} else {
WalletBalanceState.Empty
@ -105,4 +117,22 @@ internal class TokenListAnalyticsSender @Inject constructor(
is TokenList.FiatBalance.Loading -> null
}
}
private fun sendUnreachableNetworksEventIfNeeded(currenciesStatuses: List<CryptoCurrencyStatus>) {
val hasUnreachableCurrencies = currenciesStatuses.any { it.value is CryptoCurrencyStatus.Unreachable }
if (hasUnreachableCurrencies) {
analyticsEventHandler.send(MainScreen.NetworksUnreachable)
}
}
private fun sendMissedAddressesEventIfNeeded(currenciesStatuses: List<CryptoCurrencyStatus>) {
val hasCurrenciesWithMissedDerivation = currenciesStatuses.any {
it.value is CryptoCurrencyStatus.MissedDerivation
}
if (hasCurrenciesWithMissedDerivation) {
analyticsEventHandler.send(MainScreen.MissingAddresses)
}
}
}

View file

@ -0,0 +1,39 @@
package com.tangem.feature.wallet.presentation.wallet.analytics.utils
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.collections.immutable.ImmutableList
import javax.inject.Inject
@ViewModelScoped
internal class WalletWarningsAnalyticsSender @Inject constructor(
private val analyticsEventHandler: AnalyticsEventHandler,
) {
fun send(warnings: ImmutableList<WalletNotification>) {
val analyticsEvents = warnings.mapNotNull { warning ->
when (warning) {
is WalletNotification.Critical.DevCard -> MainScreen.DevelopmentCard
is WalletNotification.Informational.DemoCard -> MainScreen.DemoCard
is WalletNotification.RateApp -> MainScreen.HowDoYouLikeTangem
is WalletNotification.Warning.NumberOfSignedHashesIncorrect -> MainScreen.CardSignedTransactions
is WalletNotification.Warning.TestNetCard -> MainScreen.TestnetCard
is WalletNotification.UnlockWallets -> MainScreen.WalletUnlock
is WalletNotification.Critical.FailedCardValidation -> MainScreen.ProductSampleCard
is WalletNotification.Warning.MissingBackup -> MainScreen.BackupYourWallet
is WalletNotification.Informational.MissingAddresses,
is WalletNotification.Informational.NoAccount,
is WalletNotification.Warning.LowSignatures,
is WalletNotification.Warning.NetworksUnreachable,
is WalletNotification.Warning.SomeNetworksUnreachable,
-> null
}
}
analyticsEvents.forEach { event ->
analyticsEventHandler.send(event)
}
}
}

View file

@ -52,10 +52,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
flow = getTokenListUseCase(userWallet.walletId).conflate(),
flow2 = isReadyToShowRateAppUseCase().conflate(),
flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(),
// flow4 = getMissedAddressCryptoCurrenciesUseCase(userWallet.walletId).conflate(),
) { maybeTokenList, isReadyToShowRating, isNeedToBackup ->
// maybeTokenList.onRight { Timber.e(it.toString()) }
// maybeMissedAddressCurrencies.onRight { Timber.e(it.toString()) }
readyForRateAppNotification = true
buildList {
addCriticalNotifications(cardTypesResolver)

View file

@ -1,12 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.loaders
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.MultiWalletContentLoaderFactory
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.SingleWalletContentLoaderFactory
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.SingleWalletWithTokenContentLoaderFactory
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.WalletContentLoader
import com.tangem.feature.wallet.presentation.wallet.loaders.implementors.*
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import dagger.hilt.android.scopes.ViewModelScoped
import javax.inject.Inject
@ -16,23 +12,24 @@ internal class WalletContentLoaderFactory @Inject constructor(
private val multiWalletContentLoaderFactory: MultiWalletContentLoaderFactory,
private val singleWalletWithTokenContentLoaderFactory: SingleWalletWithTokenContentLoaderFactory,
private val singleWalletContentLoaderFactory: SingleWalletContentLoaderFactory,
private val visaWalletContentLoaderFactory: VisaWalletContentLoaderFactory,
) {
fun create(
userWallet: UserWallet,
appCurrency: AppCurrency,
clickIntents: WalletClickIntentsV2,
isRefresh: Boolean = false,
): WalletContentLoader? {
return when {
userWallet.isMultiCurrency -> {
multiWalletContentLoaderFactory.create(userWallet, appCurrency, clickIntents)
}
userWallet.isMultiCurrency -> multiWalletContentLoaderFactory.create(userWallet, clickIntents)
userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken() -> {
singleWalletWithTokenContentLoaderFactory.create(userWallet, appCurrency, clickIntents)
singleWalletWithTokenContentLoaderFactory.create(userWallet, clickIntents)
}
userWallet.scanResponse.cardTypesResolver.isVisaWallet() -> {
visaWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh)
}
!userWallet.isMultiCurrency -> {
singleWalletContentLoaderFactory.create(userWallet, appCurrency, clickIntents, isRefresh)
singleWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh)
}
else -> null
}

View file

@ -23,4 +23,9 @@ internal class WalletLoaderStorage @Inject constructor() {
loaders.remove(id)
}
}
fun clear() {
loaders.values.forEach { it.forEach(Job::cancel) }
loaders.clear()
}
}

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.loaders
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@ -30,14 +29,12 @@ internal class WalletScreenContentLoader @Inject constructor(
* Load content by [UserWallet]
*
* @param userWallet user wallet
* @param appCurrency app currency
* @param clickIntents click intents
* @param isRefresh flag that determinate if content must load again
* @param coroutineScope coroutine scope
*/
fun load(
userWallet: UserWallet,
appCurrency: AppCurrency,
clickIntents: WalletClickIntentsV2,
isRefresh: Boolean = false,
coroutineScope: CoroutineScope,
@ -46,11 +43,11 @@ internal class WalletScreenContentLoader @Inject constructor(
val id = userWallet.walletId
if (!storage.contains(id)) {
loadInternal(userWallet, appCurrency, clickIntents, coroutineScope, isRefresh)
loadInternal(userWallet, clickIntents, coroutineScope, isRefresh)
} else {
if (isRefresh) {
storage.remove(id)
loadInternal(userWallet, appCurrency, clickIntents, coroutineScope, true)
loadInternal(userWallet, clickIntents, coroutineScope, true)
} else {
Timber.d("$id content loading has already started")
}
@ -63,16 +60,19 @@ internal class WalletScreenContentLoader @Inject constructor(
storage.remove(id)
}
fun cancelAll() {
Timber.d("All content loading is canceled")
storage.clear()
}
private fun loadInternal(
userWallet: UserWallet,
appCurrency: AppCurrency,
clickIntents: WalletClickIntentsV2,
coroutineScope: CoroutineScope,
isRefresh: Boolean,
) {
val loader = factory.create(
userWallet = userWallet,
appCurrency = appCurrency,
clickIntents = clickIntents,
isRefresh = isRefresh,
)

View file

@ -1,45 +1,56 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.wallets.models.UserWallet
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
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.TokenListSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletConnectNetworksSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@Suppress("LongParameterList")
internal class MultiWalletContentLoader(
private val userWallet: UserWallet,
private val appCurrency: AppCurrency,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntentsV2,
private val stateHolder: WalletStateHolderV2,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getTokenListUseCase: GetTokenListUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val reduxStateHolder: ReduxStateHolder,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber<*>> {
override fun create(): List<WalletSubscriber> {
return listOf(
TokenListSubscriber(
userWallet = userWallet,
appCurrency = appCurrency,
stateHolder = stateHolder,
clickIntents = clickIntents,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getTokenListUseCase = getTokenListUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
),
MultiWalletWarningsSubscriber(
userWalletId = userWallet.walletId,
stateHolder = stateHolder,
clickIntents = clickIntents,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
),
WalletConnectNetworksSubscriber(
userWallet = userWallet,
getTokenListUseCase = getTokenListUseCase,
reduxStateHolder = reduxStateHolder,
),
)
}

View file

@ -1,39 +1,43 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.wallets.models.UserWallet
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
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import dagger.hilt.android.scopes.ViewModelScoped
import javax.inject.Inject
@Suppress("LongParameterList")
@ViewModelScoped
internal class MultiWalletContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateHolderV2,
private val getTokenListUseCase: GetTokenListUseCase,
private val stateHolder: WalletStateController,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val getTokenListUseCase: GetTokenListUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val reduxStateHolder: ReduxStateHolder,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
) {
fun create(
userWallet: UserWallet,
appCurrency: AppCurrency,
clickIntents: WalletClickIntentsV2,
): WalletContentLoader {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntentsV2): WalletContentLoader {
return MultiWalletContentLoader(
userWallet = userWallet,
appCurrency = appCurrency,
clickIntents = clickIntents,
stateHolder = stateHolder,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getTokenListUseCase = getTokenListUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
reduxStateHolder = reduxStateHolder,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
)
}
}

View file

@ -1,42 +1,44 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@Suppress("LongParameterList")
internal class SingleWalletContentLoader(
private val userWallet: UserWallet,
private val appCurrency: AppCurrency,
private val clickIntents: WalletClickIntentsV2,
private val isRefresh: Boolean,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber<*>> {
override fun create(): List<WalletSubscriber> {
return listOf(
PrimaryCurrencySubscriber(
userWallet = userWallet,
appCurrency = appCurrency,
stateHolder = stateHolder,
getPrimaryCurrencyStatusUpdatesUseCase = getPrimaryCurrencyStatusUpdatesUseCase,
setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
analyticsEventHandler = analyticsEventHandler,
),
SingleWalletButtonsSubscriber(
@ -51,6 +53,7 @@ internal class SingleWalletContentLoader(
stateHolder = stateHolder,
clickIntents = clickIntents,
getSingleWalletWarningsFactory = getSingleWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
),
TxHistorySubscriber(
userWallet = userWallet,

View file

@ -1,15 +1,16 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import dagger.hilt.android.scopes.ViewModelScoped
import javax.inject.Inject
@ -17,25 +18,21 @@ import javax.inject.Inject
@ViewModelScoped
@Suppress("LongParameterList")
internal class SingleWalletContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
) {
fun create(
userWallet: UserWallet,
appCurrency: AppCurrency,
clickIntents: WalletClickIntentsV2,
isRefresh: Boolean,
): WalletContentLoader {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntentsV2, isRefresh: Boolean): WalletContentLoader {
return SingleWalletContentLoader(
userWallet = userWallet,
appCurrency = appCurrency,
clickIntents = clickIntents,
isRefresh = isRefresh,
stateHolder = stateHolder,
@ -45,7 +42,9 @@ internal class SingleWalletContentLoaderFactory @Inject constructor(
setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase,
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
txHistoryItemsUseCase = txHistoryItemsUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
analyticsEventHandler = analyticsEventHandler,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
)
}
}

View file

@ -1,12 +1,13 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.tokens.GetCardTokensListUseCase
import com.tangem.domain.wallets.models.UserWallet
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
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.SingleWalletWithTokenListSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
@ -15,31 +16,33 @@ import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletCl
@Suppress("LongParameterList")
internal class SingleWalletWithTokenContentLoader(
private val userWallet: UserWallet,
private val appCurrency: AppCurrency,
private val clickIntents: WalletClickIntentsV2,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getCardTokensListUseCase: GetCardTokensListUseCase,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val getCardTokensListUseCase: GetCardTokensListUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber<*>> {
override fun create(): List<WalletSubscriber> {
return listOf(
SingleWalletWithTokenListSubscriber(
userWallet = userWallet,
appCurrency = appCurrency,
stateHolder = stateHolder,
clickIntents = clickIntents,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getCardTokensListUseCase = getCardTokensListUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
),
MultiWalletWarningsSubscriber(
userWalletId = userWallet.walletId,
stateHolder = stateHolder,
clickIntents = clickIntents,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
),
)
}

View file

@ -1,37 +1,39 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.tokens.GetCardTokensListUseCase
import com.tangem.domain.wallets.models.UserWallet
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
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import javax.inject.Inject
// TODO: Refactor
@Suppress("LongParameterList")
internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getCardTokensListUseCase: GetCardTokensListUseCase,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val getCardTokensListUseCase: GetCardTokensListUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
) {
fun create(
userWallet: UserWallet,
appCurrency: AppCurrency,
clickIntents: WalletClickIntentsV2,
): SingleWalletWithTokenContentLoader {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntentsV2): SingleWalletWithTokenContentLoader {
return SingleWalletWithTokenContentLoader(
userWallet = userWallet,
appCurrency = appCurrency,
clickIntents = clickIntents,
stateHolder = stateHolder,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getCardTokensListUseCase = getCardTokensListUseCase,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
getCardTokensListUseCase = getCardTokensListUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
)
}
}

View file

@ -0,0 +1,53 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.PrimaryCurrencySubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.TxHistorySubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.VisaWalletBalancesAndLimitsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@Suppress("LongParameterList")
internal class VisaWalletContentLoader(
private val userWallet: UserWallet,
private val clickIntents: WalletClickIntentsV2,
private val isRefresh: Boolean,
private val stateHolder: WalletStateController,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> {
return listOf(
PrimaryCurrencySubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
getPrimaryCurrencyStatusUpdatesUseCase = getPrimaryCurrencyStatusUpdatesUseCase,
setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase,
analyticsEventHandler = analyticsEventHandler,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
),
VisaWalletBalancesAndLimitsSubscriber(userWallet, stateHolder, clickIntents),
TxHistorySubscriber(
userWallet = userWallet,
isRefresh = isRefresh,
stateHolder = stateHolder,
clickIntents = clickIntents,
getPrimaryCurrencyStatusUpdatesUseCase = getPrimaryCurrencyStatusUpdatesUseCase,
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
txHistoryItemsUseCase = txHistoryItemsUseCase,
),
)
}
}

View file

@ -0,0 +1,41 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import dagger.hilt.android.scopes.ViewModelScoped
import javax.inject.Inject
@ViewModelScoped
@Suppress("LongParameterList")
internal class VisaWalletContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateController,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntentsV2, isRefresh: Boolean): WalletContentLoader {
return VisaWalletContentLoader(
userWallet = userWallet,
clickIntents = clickIntents,
isRefresh = isRefresh,
stateHolder = stateHolder,
getPrimaryCurrencyStatusUpdatesUseCase = getPrimaryCurrencyStatusUpdatesUseCase,
setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase,
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
txHistoryItemsUseCase = txHistoryItemsUseCase,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
analyticsEventHandler = analyticsEventHandler,
)
}
}

View file

@ -13,7 +13,7 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscribe
internal abstract class WalletContentLoader(val id: UserWalletId) {
/** Loader's subscribers */
val subscribers: List<WalletSubscriber<*>> get() = create()
val subscribers: List<WalletSubscriber> get() = create()
protected abstract fun create(): List<WalletSubscriber<*>>
protected abstract fun create(): List<WalletSubscriber>
}

View file

@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.feature.wallet.impl.R
@Immutable
@ -38,4 +39,23 @@ internal sealed class WalletAlertState {
override val message: TextReference = resourceReference(R.string.key_invalidated_warning_description)
override val onConfirmClick: (() -> Unit)? = null
}
object VisaBalancesInfo : WalletAlertState() {
override val title: TextReference? = null
override val message: TextReference = stringReference(
value = "Available balance is actual funds available, considering pending transactions, " +
"blocked amounts, and debit balance to prevent overdrafts.",
)
override val onConfirmClick: (() -> Unit)? = null
}
object VisaLimitsInfo : WalletAlertState() {
override val title: TextReference? = null
override val message: TextReference = stringReference(
value = "Limits are needed to control costs, improve security, manage risk. " +
"You can spend 1 000 USDT during the week for card payments in shops and " +
"100 USDT for other transactions, e. g. subscriptions or debts.",
)
override val onConfirmClick: (() -> Unit)? = null
}
}

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import com.tangem.common.Provider
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.common.util.cardTypesResolver
@ -11,6 +10,7 @@ import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.feature.wallet.presentation.wallet.state.TokenActionButtonConfig
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.isNullOrZero
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import com.tangem.common.Provider
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.wallets.models.UserWallet
@ -9,6 +8,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyS
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList

View file

@ -1,11 +1,11 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import com.tangem.common.Provider
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletDeleteStateConverter.DeleteWalletModel
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletsUpdateActionResolver
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

View file

@ -1,7 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.tokens.model.TokenList
@ -11,6 +10,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListErrorConverter
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
/**

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import com.tangem.common.Provider
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
@ -8,6 +7,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.WalletMana
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletPullToRefreshConfig
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTopBarConfig
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList

View file

@ -1,12 +1,12 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import com.tangem.common.Provider
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletPullToRefreshConfig
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate

View file

@ -1,8 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import com.tangem.common.Provider
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toImmutableList

View file

@ -1,7 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.marketprice.PriceChangeState
import com.tangem.core.ui.components.marketprice.PriceChangeType
@ -18,6 +17,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
import com.tangem.feature.wallet.presentation.wallet.utils.CurrencyStatusErrorConverter
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toPersistentList
import java.math.BigDecimal
@ -73,6 +73,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
is CryptoCurrencyStatus.Custom,
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.UnreachableWithoutAddresses,
is CryptoCurrencyStatus.NoQuote,
-> MarketPriceBlockState.Error(currencySymbol)
}
@ -116,6 +117,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Custom,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.UnreachableWithoutAddresses,
-> {
WalletCardState.Error(
id = selectedWallet.id,

View file

@ -1,7 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import androidx.annotation.DrawableRes
import com.tangem.common.Provider
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.common.util.cardTypesResolver
@ -15,6 +14,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.*
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletSkeletonStateConverter.SkeletonModel
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf

View file

@ -2,7 +2,6 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory
import androidx.paging.PagingData
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.event.consumedEvent
@ -26,6 +25,7 @@ import com.tangem.feature.wallet.presentation.wallet.utils.HiddenStateConverter
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListErrorConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletsUpdateActionResolver
import com.tangem.utils.Provider
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.Flow

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import com.tangem.common.Provider
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
@ -8,6 +7,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toImmutableList

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.state.factory
import com.tangem.common.Provider
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.common.util.cardTypesResolver
@ -12,6 +11,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyS
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.components.*
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf

View file

@ -2,7 +2,6 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory
import androidx.paging.PagingData
import arrow.core.Either
import com.tangem.common.Provider
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.txhistory.models.TxHistoryItem
@ -11,6 +10,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencySt
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.coroutines.flow.Flow

View file

@ -2,8 +2,6 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory
import androidx.paging.PagingData
import arrow.core.Either
import com.tangem.common.Converter
import com.tangem.common.Provider
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState.*
import com.tangem.domain.common.CardTypesResolver
@ -12,6 +10,8 @@ import com.tangem.domain.txhistory.models.TxHistoryStateError
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update

View file

@ -3,7 +3,6 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory
import android.text.format.DateUtils
import androidx.paging.*
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.Provider
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistoryItemState
@ -12,6 +11,7 @@ import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.isToday
import com.tangem.utils.extensions.isYesterday

View file

@ -1,187 +0,0 @@
package com.tangem.feature.wallet.presentation.wallet.state2
import androidx.paging.PagingData
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state.components.*
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.MutableStateFlow
import javax.annotation.concurrent.Immutable
const val NOT_INITIALIZED_WALLET_INDEX = -1
internal data class WalletScreenState(
val onBackClick: () -> Unit,
val topBarConfig: WalletTopBarConfig,
val selectedWalletIndex: Int,
val wallets: ImmutableList<WalletState>,
val onWalletChange: (Int) -> Unit,
val event: StateEvent<WalletEvent>,
val isHidingMode: Boolean,
)
internal sealed class WalletState {
abstract val pullToRefreshConfig: WalletPullToRefreshConfig
abstract val walletCardState: WalletCardState
abstract val warnings: ImmutableList<WalletNotification>
abstract val bottomSheetConfig: TangemBottomSheetConfig?
sealed class MultiCurrency : WalletState() {
abstract val tokensListState: WalletTokensListState
abstract val manageTokensButtonConfig: ManageTokensButtonConfig?
data class Content(
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val walletCardState: WalletCardState,
override val warnings: ImmutableList<WalletNotification>,
override val bottomSheetConfig: TangemBottomSheetConfig?,
override val tokensListState: WalletTokensListState,
override val manageTokensButtonConfig: ManageTokensButtonConfig?,
) : MultiCurrency()
data class Locked(
override val walletCardState: WalletCardState,
val onUnlockNotificationClick: () -> Unit,
val isBottomSheetShow: Boolean = false,
val onBottomSheetDismiss: () -> Unit = {},
val onUnlockClick: () -> Unit,
val onScanClick: () -> Unit,
) : MultiCurrency() {
override val pullToRefreshConfig: WalletPullToRefreshConfig
get() = WalletPullToRefreshConfig(isRefreshing = false, onRefresh = {})
override val warnings: ImmutableList<WalletNotification> = persistentListOf(
WalletNotification.UnlockWallets(onUnlockNotificationClick),
)
override val bottomSheetConfig = TangemBottomSheetConfig(
isShow = isBottomSheetShow,
onDismissRequest = onBottomSheetDismiss,
content = WalletBottomSheetConfig.UnlockWallets(
onUnlockClick = onUnlockClick,
onScanClick = onScanClick,
),
)
override val tokensListState = WalletTokensListState.ContentState.Locked
override val manageTokensButtonConfig = null
}
}
sealed class SingleCurrency : WalletState() {
abstract val buttons: PersistentList<WalletManageButton>
abstract val marketPriceBlockState: MarketPriceBlockState?
abstract val txHistoryState: TxHistoryState
data class Content(
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val walletCardState: WalletCardState,
override val warnings: ImmutableList<WalletNotification>,
override val bottomSheetConfig: TangemBottomSheetConfig?,
override val buttons: PersistentList<WalletManageButton>,
override val marketPriceBlockState: MarketPriceBlockState,
override val txHistoryState: TxHistoryState,
) : SingleCurrency()
data class Locked(
override val walletCardState: WalletCardState,
override val buttons: PersistentList<WalletManageButton>,
val onUnlockNotificationClick: () -> Unit,
val isBottomSheetShow: Boolean = false,
val onBottomSheetDismiss: () -> Unit = {},
val onUnlockClick: () -> Unit,
val onScanClick: () -> Unit,
val onExploreClick: () -> Unit,
) : SingleCurrency() {
override val pullToRefreshConfig: WalletPullToRefreshConfig
get() = WalletPullToRefreshConfig(isRefreshing = false, onRefresh = {})
override val warnings: ImmutableList<WalletNotification> = persistentListOf(
WalletNotification.UnlockWallets(onUnlockNotificationClick),
)
override val bottomSheetConfig = TangemBottomSheetConfig(
isShow = isBottomSheetShow,
onDismissRequest = onBottomSheetDismiss,
content = WalletBottomSheetConfig.UnlockWallets(
onUnlockClick = onUnlockClick,
onScanClick = onScanClick,
),
)
override val marketPriceBlockState: MarketPriceBlockState? = null
override val txHistoryState: TxHistoryState = TxHistoryState.Content(
contentItems = MutableStateFlow(
value = PagingData.from(
data = listOf(
TxHistoryState.TxHistoryItemState.Title(onExploreClick = onExploreClick),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Locked(txHash = "LOCKED_TX_HASH"),
),
),
),
),
)
}
}
}
internal sealed class WalletTokensListState {
object Empty : WalletTokensListState()
sealed class ContentState : WalletTokensListState() {
abstract val items: ImmutableList<TokensListItemState>
abstract val organizeTokensButtonConfig: OrganizeTokensButtonConfig?
object Loading : ContentState() {
override val items = persistentListOf<TokensListItemState>()
override val organizeTokensButtonConfig = null
}
data class Content(
override val items: ImmutableList<TokensListItemState>,
override val organizeTokensButtonConfig: OrganizeTokensButtonConfig?,
) : ContentState()
object Locked : ContentState() {
override val items = persistentListOf(
TokensListItemState.NetworkGroupTitle(id = 42, name = TextReference.Res(id = R.string.main_tokens)),
TokensListItemState.Token(state = TokenItemState.Locked(id = "Locked#1")),
)
override val organizeTokensButtonConfig = null
}
}
data class OrganizeTokensButtonConfig(val isEnabled: Boolean, val onClick: () -> Unit)
@Immutable
sealed class TokensListItemState {
abstract val id: Any
data class NetworkGroupTitle(override val id: Int, val name: TextReference) : TokensListItemState()
data class Token(val state: TokenItemState) : TokensListItemState() {
override val id: String = state.id
}
}
}
internal data class ManageTokensButtonConfig(val onClick: () -> Unit)

View file

@ -1,8 +1,14 @@
package com.tangem.feature.wallet.presentation.wallet.state2
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.event.consumedEvent
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTopBarConfig
import com.tangem.feature.wallet.presentation.wallet.state2.model.NOT_INITIALIZED_WALLET_INDEX
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.CloseBottomSheetTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.OpenBottomSheetTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.WalletScreenStateTransformer
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.MutableStateFlow
@ -17,7 +23,7 @@ import javax.inject.Singleton
[REDACTED_AUTHOR]
*/
@Singleton
internal class WalletStateHolderV2 @Inject constructor() {
internal class WalletStateController @Inject constructor() {
val uiState: StateFlow<WalletScreenState> get() = mutableUiState
val value: WalletScreenState get() = uiState.value
@ -32,6 +38,10 @@ internal class WalletStateHolderV2 @Inject constructor() {
mutableUiState.update(function = transformer::transform)
}
fun clear() {
mutableUiState.update { getInitialState() }
}
fun getSelectedWallet(): WalletState {
return with(value) { wallets[selectedWalletIndex] }
}
@ -40,6 +50,16 @@ internal class WalletStateHolderV2 @Inject constructor() {
return with(value) { wallets[selectedWalletIndex].walletCardState.id }
}
fun showBottomSheet(content: TangemBottomSheetConfigContent, userWalletId: UserWalletId = getSelectedWalletId()) {
update(
OpenBottomSheetTransformer(
userWalletId = userWalletId,
content = content,
onDismissBottomSheet = { update(CloseBottomSheetTransformer(userWalletId)) },
),
)
}
private fun getInitialState(): WalletScreenState {
return WalletScreenState(
onBackClick = {},

View file

@ -0,0 +1,19 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model
import androidx.compose.runtime.Immutable
@Immutable
internal sealed class BalancesAndLimitsBlockState {
object Loading : BalancesAndLimitsBlockState()
object Error : BalancesAndLimitsBlockState()
data class Content(
val availableBalance: String,
val currencySymbol: String,
val limitDays: Int,
val isEnabled: Boolean,
val onClick: () -> Unit,
) : BalancesAndLimitsBlockState()
}

View file

@ -0,0 +1,28 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
internal data class BalancesAndLimitsBottomSheetConfig(
val currency: String,
val balance: Balance,
val limit: Limit,
val onBalanceInfoClick: () -> Unit,
val onLimitInfoClick: () -> Unit,
) : TangemBottomSheetConfigContent {
data class Balance(
val totalBalance: String,
val availableBalance: String,
val blockedBalance: String,
val debit: String,
val pending: String,
val amlVerified: String,
)
data class Limit(
val availableBy: String,
val inStore: String,
val other: String,
val singleTransaction: String,
)
}

View file

@ -0,0 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model
internal data class DepositButtonState(
val isEnabled: Boolean,
val onClick: () -> Unit,
)

View file

@ -0,0 +1,3 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model
internal data class ManageTokensButtonConfig(val onClick: () -> Unit)

View file

@ -0,0 +1,16 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model
import com.tangem.core.ui.event.StateEvent
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTopBarConfig
import kotlinx.collections.immutable.ImmutableList
internal data class WalletScreenState(
val onBackClick: () -> Unit,
val topBarConfig: WalletTopBarConfig,
val selectedWalletIndex: Int,
val wallets: ImmutableList<WalletState>,
val onWalletChange: (Int) -> Unit,
val event: StateEvent<WalletEvent>,
val isHidingMode: Boolean,
)

View file

@ -0,0 +1,134 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletPullToRefreshConfig
import com.tangem.feature.wallet.presentation.wallet.state2.model.holder.LockedTxHistoryStateHolder
import com.tangem.feature.wallet.presentation.wallet.state2.model.holder.LockedWalletStateHolder
import com.tangem.feature.wallet.presentation.wallet.state2.model.holder.TxHistoryStateHolder
import com.tangem.feature.wallet.presentation.wallet.state2.model.holder.WalletStateHolder
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.PersistentList
internal const val NOT_INITIALIZED_WALLET_INDEX = -1
@Immutable
internal sealed interface WalletState : WalletStateHolder {
sealed class MultiCurrency : WalletState {
abstract val tokensListState: WalletTokensListState
abstract val manageTokensButtonConfig: ManageTokensButtonConfig?
data class Content(
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val walletCardState: WalletCardState,
override val warnings: ImmutableList<WalletNotification>,
override val bottomSheetConfig: TangemBottomSheetConfig?,
override val tokensListState: WalletTokensListState,
override val manageTokensButtonConfig: ManageTokensButtonConfig?,
) : MultiCurrency()
data class Locked(
override val walletCardState: WalletCardState,
val onUnlockNotificationClick: () -> Unit,
val isBottomSheetShow: Boolean = false,
val onBottomSheetDismiss: () -> Unit = {},
val onUnlockClick: () -> Unit,
val onScanClick: () -> Unit,
) : MultiCurrency(),
WalletStateHolder by LockedWalletStateHolder(
walletCardState,
onUnlockNotificationClick,
isBottomSheetShow,
onBottomSheetDismiss,
onUnlockClick,
onScanClick,
) {
override val tokensListState = WalletTokensListState.ContentState.Locked
override val manageTokensButtonConfig = null
}
}
sealed class SingleCurrency : WalletState, TxHistoryStateHolder {
abstract val buttons: PersistentList<WalletManageButton>
abstract val marketPriceBlockState: MarketPriceBlockState?
data class Content(
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val walletCardState: WalletCardState,
override val warnings: ImmutableList<WalletNotification>,
override val bottomSheetConfig: TangemBottomSheetConfig?,
override val buttons: PersistentList<WalletManageButton>,
override val marketPriceBlockState: MarketPriceBlockState,
override val txHistoryState: TxHistoryState,
) : SingleCurrency()
data class Locked(
override val walletCardState: WalletCardState,
override val buttons: PersistentList<WalletManageButton>,
val onUnlockNotificationClick: () -> Unit,
val isBottomSheetShow: Boolean = false,
val onBottomSheetDismiss: () -> Unit = {},
val onUnlockClick: () -> Unit,
val onScanClick: () -> Unit,
val onExploreClick: () -> Unit,
) : SingleCurrency(),
TxHistoryStateHolder by LockedTxHistoryStateHolder(onExploreClick),
WalletStateHolder by LockedWalletStateHolder(
walletCardState,
onUnlockNotificationClick,
isBottomSheetShow,
onBottomSheetDismiss,
onUnlockClick,
onScanClick,
) {
override val marketPriceBlockState: MarketPriceBlockState? = null
}
}
sealed class Visa : WalletState, TxHistoryStateHolder {
abstract val balancesAndLimitBlockState: BalancesAndLimitsBlockState?
data class Content(
override val pullToRefreshConfig: WalletPullToRefreshConfig,
override val walletCardState: WalletCardState,
override val warnings: ImmutableList<WalletNotification>,
override val bottomSheetConfig: TangemBottomSheetConfig?,
override val balancesAndLimitBlockState: BalancesAndLimitsBlockState,
override val txHistoryState: TxHistoryState,
val depositButtonState: DepositButtonState,
) : Visa()
data class Locked(
override val walletCardState: WalletCardState,
val onUnlockNotificationClick: () -> Unit,
val isBottomSheetShow: Boolean = false,
val onBottomSheetDismiss: () -> Unit = {},
val onUnlockClick: () -> Unit,
val onScanClick: () -> Unit,
val onExploreClick: () -> Unit,
) : Visa(),
TxHistoryStateHolder by LockedTxHistoryStateHolder(onExploreClick),
WalletStateHolder by LockedWalletStateHolder(
walletCardState,
onUnlockNotificationClick,
isBottomSheetShow,
onBottomSheetDismiss,
onUnlockClick,
onScanClick,
) {
override val balancesAndLimitBlockState: BalancesAndLimitsBlockState? = null
}
}
}

View file

@ -0,0 +1,52 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@Immutable
internal sealed class WalletTokensListState {
object Empty : WalletTokensListState()
sealed class ContentState : WalletTokensListState() {
abstract val items: ImmutableList<TokensListItemState>
abstract val organizeTokensButtonConfig: OrganizeTokensButtonConfig?
object Loading : ContentState() {
override val items = persistentListOf<TokensListItemState>()
override val organizeTokensButtonConfig = null
}
data class Content(
override val items: ImmutableList<TokensListItemState>,
override val organizeTokensButtonConfig: OrganizeTokensButtonConfig?,
) : ContentState()
object Locked : ContentState() {
override val items = persistentListOf(
TokensListItemState.NetworkGroupTitle(id = 42, name = TextReference.Res(id = R.string.main_tokens)),
TokensListItemState.Token(state = TokenItemState.Locked(id = "Locked#1")),
)
override val organizeTokensButtonConfig = null
}
}
data class OrganizeTokensButtonConfig(val isEnabled: Boolean, val onClick: () -> Unit)
@Immutable
sealed class TokensListItemState {
abstract val id: Any
data class NetworkGroupTitle(override val id: Int, val name: TextReference) : TokensListItemState()
data class Token(val state: TokenItemState) : TokensListItemState() {
override val id: String = state.id
}
}
}

View file

@ -0,0 +1,43 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model.holder
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletPullToRefreshConfig
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
internal interface WalletStateHolder {
val pullToRefreshConfig: WalletPullToRefreshConfig
val walletCardState: WalletCardState
val warnings: ImmutableList<WalletNotification>
val bottomSheetConfig: TangemBottomSheetConfig?
}
internal class LockedWalletStateHolder(
override val walletCardState: WalletCardState,
onUnlockNotificationClick: () -> Unit,
isBottomSheetShow: Boolean,
onBottomSheetDismiss: () -> Unit,
onUnlockClick: () -> Unit,
onScanClick: () -> Unit,
) : WalletStateHolder {
override val pullToRefreshConfig: WalletPullToRefreshConfig
get() = WalletPullToRefreshConfig(isRefreshing = false, onRefresh = {})
override val warnings: ImmutableList<WalletNotification> = persistentListOf(
WalletNotification.UnlockWallets(onUnlockNotificationClick),
)
override val bottomSheetConfig = TangemBottomSheetConfig(
isShow = isBottomSheetShow,
onDismissRequest = onBottomSheetDismiss,
content = WalletBottomSheetConfig.UnlockWallets(
onUnlockClick = onUnlockClick,
onScanClick = onScanClick,
),
)
}

View file

@ -0,0 +1,27 @@
package com.tangem.feature.wallet.presentation.wallet.state2.model.holder
import androidx.paging.PagingData
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import kotlinx.coroutines.flow.MutableStateFlow
internal interface TxHistoryStateHolder {
val txHistoryState: TxHistoryState
}
internal class LockedTxHistoryStateHolder(onExploreClick: () -> Unit) : TxHistoryStateHolder {
override val txHistoryState: TxHistoryState = TxHistoryState.Content(
contentItems = MutableStateFlow(
value = PagingData.from(
data = listOf(
TxHistoryState.TxHistoryItemState.Title(onExploreClick = onExploreClick),
TxHistoryState.TxHistoryItemState.Transaction(
state = TransactionState.Locked(txHash = "LOCKED_TX_HASH"),
),
),
),
),
)
}

View file

@ -1,7 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletLoadingStateFactory
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.collections.immutable.toImmutableList

View file

@ -1,7 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
internal class CloseBottomSheetTransformer(userWalletId: UserWalletId) : WalletStateTransformer(userWalletId) {
@ -15,6 +15,10 @@ internal class CloseBottomSheetTransformer(userWalletId: UserWalletId) : WalletS
prevState.copy(bottomSheetConfig = prevState.bottomSheetConfig?.copy(isShow = false))
}
is WalletState.SingleCurrency.Locked -> prevState.copy(isBottomSheetShow = false)
is WalletState.Visa.Content -> prevState.copy(
bottomSheetConfig = prevState.bottomSheetConfig?.copy(isShow = false),
)
is WalletState.Visa.Locked -> prevState.copy(isBottomSheetShow = false)
}
}
}

View file

@ -1,8 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import kotlinx.collections.immutable.toImmutableList
import timber.log.Timber

View file

@ -6,8 +6,8 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTopBarConfig
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletLoadingStateFactory
import com.tangem.feature.wallet.presentation.wallet.state2.utils.createStateByWalletType
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@ -72,6 +72,15 @@ internal class InitializeWalletsTransformer(
onExploreClick = clickIntents::onExploreClick,
)
},
visaWalletCreator = {
WalletState.Visa.Locked(
walletCardState = userWallet.toLockedWalletCardState(),
onUnlockNotificationClick = clickIntents::onOpenUnlockWalletsBottomSheetClick,
onUnlockClick = clickIntents::onUnlockWalletClick,
onScanClick = clickIntents::onScanToUnlockWalletClick,
onExploreClick = clickIntents::onExploreClick,
)
},
)
}

View file

@ -3,7 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
internal class OpenBottomSheetTransformer(
userWalletId: UserWalletId,
@ -37,6 +37,17 @@ internal class OpenBottomSheetTransformer(
is WalletState.SingleCurrency.Locked -> {
prevState.copy(isBottomSheetShow = true, onBottomSheetDismiss = onDismissBottomSheet)
}
is WalletState.Visa.Content -> prevState.copy(
bottomSheetConfig = TangemBottomSheetConfig(
isShow = true,
onDismissRequest = onDismissBottomSheet,
content = content,
),
)
is WalletState.Visa.Locked -> prevState.copy(
isBottomSheetShow = true,
onBottomSheetDismiss = onDismissBottomSheet,
)
}
}
}

View file

@ -1,7 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletLoadingStateFactory
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.collections.immutable.persistentListOf

View file

@ -1,7 +1,7 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import timber.log.Timber
internal class RenameWalletTransformer(
@ -17,8 +17,12 @@ internal class RenameWalletTransformer(
is WalletState.SingleCurrency.Content -> {
prevState.copy(walletCardState = prevState.walletCardState.copySealed(title = newName))
}
is WalletState.Visa.Content -> {
prevState.copy(walletCardState = prevState.walletCardState.copySealed(title = newName))
}
is WalletState.MultiCurrency.Locked,
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> {
Timber.e("Impossible to rename wallet in locked state")
prevState

View file

@ -1,10 +1,10 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.common.Provider
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.event.triggeredEvent
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.utils.Provider
internal class ScrollToWalletTransformer(
private val index: Int,

View file

@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.core.ui.event.triggeredEvent
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
internal class SendEventTransformer(
private val event: WalletEvent,

View file

@ -0,0 +1,32 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.model.BalancesAndLimitsBlockState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
internal class SetBalancesAndLimitsTransformer(
userWallet: UserWallet,
private val clickIntents: WalletClickIntentsV2,
) : WalletStateTransformer(userWallet.walletId) {
override fun transform(prevState: WalletState): WalletState {
return prevState.transformWhenInState<WalletState.Visa.Content> { state ->
state.copy(
balancesAndLimitBlockState = state.balancesAndLimitBlockState.toLoadedState(),
)
}
}
// TODO: Implement in [REDACTED_JIRA]
@Suppress("UnusedReceiverParameter")
private fun BalancesAndLimitsBlockState.toLoadedState(): BalancesAndLimitsBlockState {
return BalancesAndLimitsBlockState.Content(
availableBalance = "400.00",
currencySymbol = "USDT",
limitDays = 7,
isEnabled = true,
onClick = clickIntents::onBalancesAndLimitsClick,
)
}
}

View file

@ -4,7 +4,7 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
@ -21,14 +21,16 @@ internal class SetCryptoCurrencyActionsTransformer(
is WalletState.SingleCurrency.Content -> {
prevState.copy(buttons = tokenActionsState.toManageButtons())
}
is WalletState.SingleCurrency.Locked,
-> {
Timber.e("Impossible to load primary currency status for locked wallet")
is WalletState.SingleCurrency.Locked -> {
Timber.w("Impossible to load primary currency status for locked wallet")
prevState
}
is WalletState.MultiCurrency,
-> {
Timber.e("Impossible to load crypto currency actions for multi-currency wallet")
is WalletState.MultiCurrency -> {
Timber.w("Impossible to load crypto currency actions for multi-currency wallet")
prevState
}
is WalletState.Visa -> {
Timber.w("Impossible to load crypto currency actions for VISA wallet")
prevState
}
}

View file

@ -5,14 +5,15 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.SingleWalletCardStateConverter
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.SingleWalletMarketPriceConverter
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.VisaWalletCardStateConverter
import timber.log.Timber
internal class SetPrimaryCurrencyTransformer(
private val userWallet: UserWallet,
private val status: CryptoCurrencyStatus.Status,
private val status: CryptoCurrencyStatus,
private val appCurrency: AppCurrency,
) : WalletStateTransformer(userWallet.walletId) {
@ -20,28 +21,38 @@ internal class SetPrimaryCurrencyTransformer(
return when (prevState) {
is WalletState.SingleCurrency.Content -> {
prevState.copy(
walletCardState = prevState.walletCardState.toLoadedState(),
walletCardState = prevState.walletCardState.toLoadedSingleCurrencyState(),
marketPriceBlockState = prevState.marketPriceBlockState.toLoadedState(),
)
}
is WalletState.Visa.Content -> {
prevState.copy(
walletCardState = prevState.walletCardState.toLoadedVisaState(),
depositButtonState = prevState.depositButtonState.copy(isEnabled = true),
)
}
is WalletState.Visa.Locked,
is WalletState.SingleCurrency.Locked,
-> {
Timber.e("Impossible to load primary currency status for locked wallet")
Timber.w("Impossible to load primary currency status for locked wallet")
prevState
}
is WalletState.MultiCurrency,
-> {
Timber.e("Impossible to load primary currency status for multi-currency wallet")
is WalletState.MultiCurrency -> {
Timber.w("Impossible to load primary currency status for multi-currency wallet")
prevState
}
}
}
private fun WalletCardState.toLoadedState(): WalletCardState {
return SingleWalletCardStateConverter(status, userWallet, appCurrency).convert(value = this)
private fun WalletCardState.toLoadedSingleCurrencyState(): WalletCardState {
return SingleWalletCardStateConverter(status.value, userWallet, appCurrency).convert(value = this)
}
private fun WalletCardState.toLoadedVisaState(): WalletCardState {
return VisaWalletCardStateConverter(status, userWallet, appCurrency).convert(value = this)
}
private fun MarketPriceBlockState.toLoadedState(): MarketPriceBlockState {
return SingleWalletMarketPriceConverter(status, appCurrency).convert(value = this)
return SingleWalletMarketPriceConverter(status.value, appCurrency).convert(value = this)
}
}

View file

@ -3,8 +3,10 @@ package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletPullToRefreshConfig
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.model.BalancesAndLimitsBlockState
import com.tangem.feature.wallet.presentation.wallet.state2.model.DepositButtonState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate
@ -27,8 +29,16 @@ internal class SetRefreshStateTransformer(
buttons = prevState.buttons.toUpdatedState(),
)
}
is WalletState.Visa.Content -> {
prevState.copy(
pullToRefreshConfig = prevState.pullToRefreshConfig.toUpdatedState(isRefreshing),
depositButtonState = prevState.depositButtonState.toUpdatedState(isRefreshing),
balancesAndLimitBlockState = prevState.balancesAndLimitBlockState.toUpdatedState(isRefreshing),
)
}
is WalletState.MultiCurrency.Locked,
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> prevState
}
}
@ -64,4 +74,17 @@ internal class SetRefreshStateTransformer(
}
}
}
private fun DepositButtonState.toUpdatedState(isRefreshing: Boolean): DepositButtonState {
return copy(isEnabled = !isRefreshing)
}
private fun BalancesAndLimitsBlockState.toUpdatedState(isRefreshing: Boolean): BalancesAndLimitsBlockState {
return when (this) {
is BalancesAndLimitsBlockState.Content -> copy(isEnabled = !isRefreshing)
is BalancesAndLimitsBlockState.Error,
is BalancesAndLimitsBlockState.Loading,
-> this
}
}
}

View file

@ -2,8 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState
import timber.log.Timber
internal class SetTokenListErrorTransformer(
@ -18,14 +18,16 @@ internal class SetTokenListErrorTransformer(
is WalletState.MultiCurrency.Content -> {
prevState.copy(tokensListState = WalletTokensListState.Empty)
}
is WalletState.MultiCurrency.Locked,
-> {
Timber.e("Impossible to load tokens list for locked wallet")
is WalletState.MultiCurrency.Locked -> {
Timber.w("Impossible to load tokens list for locked wallet")
prevState
}
is WalletState.SingleCurrency,
-> {
Timber.e("Impossible to load tokens list for single-currency wallet")
is WalletState.SingleCurrency -> {
Timber.w("Impossible to load tokens list for single-currency wallet")
prevState
}
is WalletState.Visa -> {
Timber.w("Impossible to load tokens list for VISA wallet")
prevState
}
}

View file

@ -5,9 +5,9 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state2.ManageTokensButtonConfig
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.model.ManageTokensButtonConfig
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.MultiWalletCardStateConverter
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.TokenListStateConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
@ -29,14 +29,14 @@ internal class SetTokenListTransformer(
manageTokensButtonConfig = createManageTokensButtonConfig(),
)
}
is WalletState.MultiCurrency.Locked,
-> {
Timber.e("Impossible to load tokens list for locked wallet")
is WalletState.MultiCurrency.Locked -> {
Timber.w("Impossible to load tokens list for locked wallet")
prevState
}
is WalletState.Visa,
is WalletState.SingleCurrency,
-> {
Timber.e("Impossible to load tokens list for single-currency wallet")
Timber.w("Impossible to load tokens list for single-currency wallet")
prevState
}
}

View file

@ -5,7 +5,7 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.txhistory.models.TxHistoryStateError
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.TxHistoryItemStateConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.collections.immutable.toImmutableList
@ -29,40 +29,37 @@ internal class SetTxHistoryCountErrorTransformer(
override fun transform(prevState: WalletState): WalletState {
return when (prevState) {
is WalletState.SingleCurrency.Content -> prevState.toErrorState()
is WalletState.SingleCurrency.Content -> prevState.copy(txHistoryState = createErrorState())
is WalletState.Visa.Content -> prevState.copy(txHistoryState = createErrorState())
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> {
Timber.e("Impossible to load transactions history for locked wallet")
Timber.w("Impossible to load transactions history for locked wallet")
prevState
}
is WalletState.MultiCurrency,
-> {
Timber.e("Impossible to load transactions history for multi-currency wallet")
is WalletState.MultiCurrency -> {
Timber.w("Impossible to load transactions history for multi-currency wallet")
prevState
}
}
}
private fun WalletState.SingleCurrency.Content.toErrorState(): WalletState {
return copy(
txHistoryState = when (error) {
is TxHistoryStateError.EmptyTxHistories -> {
TxHistoryState.Empty(onExploreClick = clickIntents::onExploreClick)
}
is TxHistoryStateError.DataError -> {
TxHistoryState.Error(
onReloadClick = clickIntents::onReloadClick,
onExploreClick = clickIntents::onExploreClick,
)
}
is TxHistoryStateError.TxHistoryNotImplemented -> {
TxHistoryState.NotSupported(
pendingTransactions = txHistoryItemConverter.convertList(pendingTransactions)
.toImmutableList(),
onExploreClick = clickIntents::onExploreClick,
)
}
},
)
private fun createErrorState(): TxHistoryState = when (error) {
is TxHistoryStateError.EmptyTxHistories -> {
TxHistoryState.Empty(onExploreClick = clickIntents::onExploreClick)
}
is TxHistoryStateError.DataError -> {
TxHistoryState.Error(
onReloadClick = clickIntents::onReloadClick,
onExploreClick = clickIntents::onExploreClick,
)
}
is TxHistoryStateError.TxHistoryNotImplemented -> {
TxHistoryState.NotSupported(
pendingTransactions = txHistoryItemConverter.convertList(pendingTransactions)
.toImmutableList(),
onExploreClick = clickIntents::onExploreClick,
)
}
}
}

View file

@ -4,7 +4,7 @@ import androidx.paging.PagingData
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
@ -18,34 +18,40 @@ internal class SetTxHistoryCountTransformer(
override fun transform(prevState: WalletState): WalletState {
return when (prevState) {
is WalletState.SingleCurrency.Content -> prevState.toLoadingState()
is WalletState.SingleCurrency.Content -> prevState.copy(
txHistoryState = prevState.txHistoryState.toLoadingState(),
)
is WalletState.Visa.Content -> prevState.copy(
txHistoryState = prevState.txHistoryState.toLoadingState(),
)
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> {
Timber.e("Impossible to load transactions history for locked wallet")
Timber.w("Impossible to load transactions history for locked wallet")
prevState
}
is WalletState.MultiCurrency,
-> {
Timber.e("Impossible to load transactions history for multi-currency wallet")
is WalletState.MultiCurrency -> {
Timber.w("Impossible to load transactions history for multi-currency wallet")
prevState
}
}
}
private fun WalletState.SingleCurrency.Content.toLoadingState(): WalletState {
return if (txHistoryState is TxHistoryState.Content) {
(txHistoryState as? TxHistoryState.Content)?.contentItems?.update {
Timber.d("Load transactions history: $transactionsCount")
PagingData.from(data = createLoadingItems())
}
this
} else {
val txHistoryContent = TxHistoryState.Content(
contentItems = MutableStateFlow(
value = PagingData.from(data = createLoadingItems()),
),
private fun TxHistoryState.toLoadingState(): TxHistoryState {
return if (this is TxHistoryState.Content) {
Timber.d("Load transactions history: $transactionsCount")
copy(
contentItems = contentItems.apply {
update {
PagingData.from(data = createLoadingItems())
}
},
)
} else {
TxHistoryState.Content(
contentItems = MutableStateFlow(PagingData.from(createLoadingItems())),
)
copy(txHistoryState = txHistoryContent)
}
}

View file

@ -3,7 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.txhistory.models.TxHistoryListError
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import timber.log.Timber
@ -15,27 +15,27 @@ internal class SetTxHistoryItemsErrorTransformer(
override fun transform(prevState: WalletState): WalletState {
return when (prevState) {
is WalletState.SingleCurrency.Content -> {
prevState.copy(
txHistoryState = when (error) {
is TxHistoryListError.DataError -> {
TxHistoryState.Error(
onReloadClick = clickIntents::onReloadClick,
onExploreClick = clickIntents::onExploreClick,
)
}
},
)
}
is WalletState.SingleCurrency.Content -> prevState.copy(txHistoryState = createErrorState())
is WalletState.Visa.Content -> prevState.copy(txHistoryState = createErrorState())
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> {
Timber.e("Impossible to load transactions history for locked wallet")
Timber.w("Impossible to load transactions history for locked wallet")
prevState
}
is WalletState.MultiCurrency -> {
Timber.e("Impossible to load transactions history for multi-currency wallet")
Timber.w("Impossible to load transactions history for multi-currency wallet")
prevState
}
}
}
private fun createErrorState(): TxHistoryState.Error = when (error) {
is TxHistoryListError.DataError -> {
TxHistoryState.Error(
onReloadClick = clickIntents::onReloadClick,
onExploreClick = clickIntents::onExploreClick,
)
}
}
}

View file

@ -1,9 +1,10 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import androidx.paging.PagingData
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.TxHistoryItemFlowConverter
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.flow.Flow
@ -17,25 +18,32 @@ internal class SetTxHistoryItemsTransformer(
override fun transform(prevState: WalletState): WalletState {
return when (prevState) {
is WalletState.SingleCurrency.Content -> {
val converter = TxHistoryItemFlowConverter(
userWallet = userWallet,
currentState = prevState,
clickIntents = clickIntents,
)
prevState.copy(
txHistoryState = converter.convert(value = flow),
)
}
is WalletState.SingleCurrency.Content -> prevState.copy(
txHistoryState = prevState.txHistoryState.toContentState(),
)
is WalletState.Visa.Content -> prevState.copy(
txHistoryState = prevState.txHistoryState.toContentState(),
)
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> {
Timber.e("Impossible to load transactions history for locked wallet")
Timber.w("Impossible to load transactions history for locked wallet")
prevState
}
is WalletState.MultiCurrency -> {
Timber.e("Impossible to load transactions history for multi-currency wallet")
Timber.w("Impossible to load transactions history for multi-currency wallet")
prevState
}
}
}
private fun TxHistoryState.toContentState(): TxHistoryState {
val converter = TxHistoryItemFlowConverter(
userWallet = userWallet,
currentState = this,
clickIntents = clickIntents,
)
return converter.convert(flow)
}
}

View file

@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import kotlinx.collections.immutable.ImmutableList
import timber.log.Timber
@ -15,10 +15,12 @@ internal class SetWarningsTransformer(
return when (prevState) {
is WalletState.MultiCurrency.Content -> prevState.copy(warnings = warnings)
is WalletState.SingleCurrency.Content -> prevState.copy(warnings = warnings)
is WalletState.Visa.Content -> prevState.copy(warnings = warnings)
is WalletState.MultiCurrency.Locked,
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> {
Timber.e("Impossible to update notifications for locked wallet")
Timber.w("Impossible to update notifications for locked wallet")
prevState
}
}

View file

@ -3,8 +3,8 @@ package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTopBarConfig
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletLoadingStateFactory
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.collections.immutable.toImmutableList
@ -41,9 +41,11 @@ internal class UnlockWalletTransformer(
return when (prevState) {
is WalletState.MultiCurrency.Locked,
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> walletLoadingStateFactory.create(userWallet = unlockedWallet)
is WalletState.MultiCurrency.Content,
is WalletState.SingleCurrency.Content,
is WalletState.Visa.Content,
-> {
Timber.e("Impossible to unlock wallet with content state")
prevState

View file

@ -1,6 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
internal class UpdateBalanceHidingModeTransformer(
private val isHidingMode: Boolean,

View file

@ -5,7 +5,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfo
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import timber.log.Timber
internal class UpdateWalletCardsCountTransformer(
@ -20,8 +20,12 @@ internal class UpdateWalletCardsCountTransformer(
is WalletState.SingleCurrency.Content -> {
prevState.copy(walletCardState = prevState.walletCardState.toUpdatedState())
}
is WalletState.Visa.Content -> {
prevState.copy(walletCardState = prevState.walletCardState.toUpdatedState())
}
is WalletState.MultiCurrency.Locked,
is WalletState.SingleCurrency.Locked,
is WalletState.Visa.Locked,
-> {
Timber.e("Impossible to update wallet cards count for locked wallet")
prevState

View file

@ -1,6 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
internal interface WalletScreenStateTransformer {

View file

@ -1,9 +1,10 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
import kotlinx.collections.immutable.toImmutableList
import timber.log.Timber
internal abstract class WalletStateTransformer(
protected val userWalletId: UserWalletId,
@ -20,4 +21,13 @@ internal abstract class WalletStateTransformer(
.toImmutableList(),
)
}
protected inline fun <reified S : WalletState> WalletState.transformWhenInState(
transform: (state: S) -> WalletState,
): WalletState = if (this is S) {
transform(this)
} else {
Timber.w("Impossible to transform ${this::class.simpleName} because current is ${S::class.simpleName}")
this
}
}

View file

@ -21,6 +21,7 @@ internal class SingleWalletCardStateConverter(
is CryptoCurrencyStatus.Custom,
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.UnreachableWithoutAddresses,
-> value.toErrorState()
is CryptoCurrencyStatus.NoQuote,
is CryptoCurrencyStatus.Loaded,

View file

@ -25,6 +25,7 @@ internal class SingleWalletMarketPriceConverter(
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.NoQuote,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.UnreachableWithoutAddresses,
-> MarketPriceBlockState.Error(value.currencySymbol)
}
}

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter
import com.tangem.common.Provider
import com.tangem.core.ui.components.currency.tokenicon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.utils.BigDecimalFormatter
@ -8,6 +7,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import java.math.BigDecimal
@ -28,6 +28,7 @@ internal class TokenItemStateConverter(
-> value.mapToTokenItemState()
is CryptoCurrencyStatus.MissedDerivation -> value.mapToNoAddressTokenItemState()
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.UnreachableWithoutAddresses,
is CryptoCurrencyStatus.NoAmount,
-> value.mapToUnreachableTokenItemState()
}

View file

@ -1,6 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter
import com.tangem.common.Provider
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.util.cardTypesResolver
@ -8,14 +7,15 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkGroup
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState.TokensListItemState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState.TokensListItemState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate
import kotlinx.collections.immutable.persistentListOf
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState.OrganizeTokensButtonConfig as WalletOrganizeTokensButtonConfig
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState.OrganizeTokensButtonConfig as WalletOrganizeTokensButtonConfig
internal class TokenListStateConverter(
private val tokenList: TokenList,

View file

@ -9,7 +9,6 @@ import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import com.tangem.utils.converter.Converter
import kotlinx.coroutines.CoroutineScope
@ -21,7 +20,7 @@ private val scope = CoroutineScope(Dispatchers.IO)
internal class TxHistoryItemFlowConverter(
private val userWallet: UserWallet,
private val currentState: WalletState.SingleCurrency.Content,
private val currentState: TxHistoryState,
private val clickIntents: WalletClickIntentsV2,
) : Converter<Flow<PagingData<TxHistoryItem>>, TxHistoryState?> {
@ -35,7 +34,7 @@ internal class TxHistoryItemFlowConverter(
}
override fun convert(value: Flow<PagingData<TxHistoryItem>>): TxHistoryState {
val txHistoryContent = currentState.txHistoryState as? TxHistoryState.Content
val txHistoryContent = currentState as? TxHistoryState.Content
?: TxHistoryState.Content(contentItems = MutableStateFlow(PagingData.empty()))
// FIXME: TxHistoryRepository should send loading transactions

View file

@ -0,0 +1,90 @@
package com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletAdditionalInfo
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.utils.converter.Converter
internal class VisaWalletCardStateConverter(
private val status: CryptoCurrencyStatus,
private val selectedWallet: UserWallet,
private val appCurrency: AppCurrency,
) : Converter<WalletCardState, WalletCardState> {
override fun convert(value: WalletCardState): WalletCardState {
return when (status.value) {
is CryptoCurrencyStatus.Loading -> value.toLoadingState()
is CryptoCurrencyStatus.Custom,
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.UnreachableWithoutAddresses,
-> value.toErrorState()
is CryptoCurrencyStatus.NoQuote,
is CryptoCurrencyStatus.Loaded,
is CryptoCurrencyStatus.NoAccount,
is CryptoCurrencyStatus.NoAmount,
-> value.toContentState(status)
}
}
private fun WalletCardState.toLoadingState(): WalletCardState {
return WalletCardState.Loading(
id = id,
title = title,
imageResId = imageResId,
onRenameClick = onRenameClick,
onDeleteClick = onDeleteClick,
)
}
private fun WalletCardState.toErrorState(): WalletCardState {
return WalletCardState.Error(
id = id,
title = title,
imageResId = imageResId,
onRenameClick = onRenameClick,
onDeleteClick = onDeleteClick,
)
}
private fun WalletCardState.toContentState(status: CryptoCurrencyStatus): WalletCardState {
return WalletCardState.Content(
id = id,
title = title,
additionalInfo = createAdditionalInfo(status),
imageResId = imageResId,
onRenameClick = onRenameClick,
onDeleteClick = onDeleteClick,
balance = formatAmount(status),
cardCount = selectedWallet.getCardsCount(),
)
}
private fun createAdditionalInfo(status: CryptoCurrencyStatus): WalletAdditionalInfo {
val fiatAmount = BigDecimalFormatter.formatFiatAmount(
status.value.fiatAmount,
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
)
val infoContent = stringReference(
value = buildString {
append(fiatAmount)
append("")
append(status.currency.network.name)
},
)
return WalletAdditionalInfo(hideable = true, infoContent)
}
private fun formatAmount(status: CryptoCurrencyStatus): String {
val amount = status.value.amount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
return BigDecimalFormatter.formatCryptoAmount(amount, status.currency)
}
}

View file

@ -2,15 +2,22 @@ package com.tangem.feature.wallet.presentation.wallet.state2.utils
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
internal inline fun UserWallet.createStateByWalletType(
multiCurrencyCreator: () -> WalletState.MultiCurrency,
singleCurrencyCreator: () -> WalletState.SingleCurrency,
): WalletState {
return if (isWalletWithTokens()) multiCurrencyCreator() else singleCurrencyCreator()
visaWalletCreator: () -> WalletState.Visa,
): WalletState = when {
isVisaWallet() -> visaWalletCreator()
isWalletWithTokens() -> multiCurrencyCreator()
else -> singleCurrencyCreator()
}
private fun UserWallet.isWalletWithTokens(): Boolean {
return isMultiCurrency || scanResponse.cardTypesResolver.isSingleWalletWithToken()
}
private fun UserWallet.isVisaWallet(): Boolean {
return scanResponse.cardTypesResolver.isVisaWallet()
}

View file

@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state2.utils
import com.tangem.core.ui.event.consumedEvent
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SendEventTransformer
import javax.inject.Inject
@ -14,7 +14,7 @@ import javax.inject.Inject
[REDACTED_AUTHOR]
*/
internal class WalletEventSender @Inject constructor(
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
) {
fun send(event: WalletEvent) {

View file

@ -9,9 +9,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletPullToRefreshConfig
import com.tangem.feature.wallet.presentation.wallet.state2.ManageTokensButtonConfig
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.model.*
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
@ -28,6 +26,7 @@ internal class WalletLoadingStateFactory(private val clickIntents: WalletClickIn
return userWallet.createStateByWalletType(
multiCurrencyCreator = { createLoadingMultiCurrencyContent(userWallet) },
singleCurrencyCreator = { createLoadingSingleCurrencyContent(userWallet) },
visaWalletCreator = { createLoadingVisaWalletContent(userWallet) },
)
}
@ -59,6 +58,22 @@ internal class WalletLoadingStateFactory(private val clickIntents: WalletClickIn
)
}
private fun createLoadingVisaWalletContent(userWallet: UserWallet): WalletState.Visa.Content {
return WalletState.Visa.Content(
pullToRefreshConfig = createPullToRefreshConfig(),
walletCardState = userWallet.toLoadingWalletCardState(),
warnings = persistentListOf(),
bottomSheetConfig = null,
balancesAndLimitBlockState = BalancesAndLimitsBlockState.Loading,
txHistoryState = TxHistoryState.Content(
contentItems = MutableStateFlow(
value = TxHistoryState.getDefaultLoadingTransactions(clickIntents::onExploreClick),
),
),
depositButtonState = DepositButtonState(isEnabled = false, clickIntents::onDepositClick),
)
}
private fun createPullToRefreshConfig(): WalletPullToRefreshConfig {
return WalletPullToRefreshConfig(onRefresh = clickIntents::onRefreshSwipe, isRefreshing = false)
}

View file

@ -1,9 +1,10 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetWarningsTransformer
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.collections.immutable.ImmutableList
@ -12,26 +13,22 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlin.coroutines.CoroutineContext
internal class MultiWalletWarningsSubscriber(
private val userWalletId: UserWalletId,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntentsV2,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
) : WalletSubscriber<ImmutableList<WalletNotification>>(name = "multi_wallet_warnings") {
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
) : WalletSubscriber() {
override fun create(
coroutineScope: CoroutineScope,
uiDispatcher: CoroutineContext,
): Flow<ImmutableList<WalletNotification>> {
override fun create(coroutineScope: CoroutineScope): Flow<ImmutableList<WalletNotification>> {
return getMultiWalletWarningsFactory.create(clickIntents)
.conflate()
.distinctUntilChanged()
.onEach {
stateHolder.update(
SetWarningsTransformer(userWalletId = userWalletId, warnings = it),
)
.onEach { warnings ->
stateHolder.update(SetWarningsTransformer(userWalletId, warnings))
walletWarningsAnalyticsSender.send(warnings)
}
}
}

View file

@ -1,9 +1,11 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.common.extensions.isZero
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
@ -11,52 +13,58 @@ import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetPrimaryCurrencyTransformer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.*
import timber.log.Timber
import java.math.BigDecimal
import kotlin.coroutines.CoroutineContext
internal class PrimaryCurrencySubscriber(
private val userWallet: UserWallet,
private val appCurrency: AppCurrency,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
) : WalletSubscriber<Either<CurrencyStatusError, CryptoCurrencyStatus>>(name = "primary_currency") {
) : WalletSubscriber() {
override fun create(
coroutineScope: CoroutineScope,
uiDispatcher: CoroutineContext,
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
return getPrimaryCurrencyStatusUpdatesUseCase(userWallet.walletId)
.conflate()
.distinctUntilChanged()
.onEach(::updateContent)
.onEach(::sendAnalyticsEvent)
.onEach(::checkWalletWithFunds)
): Flow<Pair<Either<CurrencyStatusError, CryptoCurrencyStatus>, AppCurrency>> {
return combine(
flow = getPrimaryCurrencyStatusUpdatesUseCase(userWallet.walletId)
.conflate()
.distinctUntilChanged(),
flow2 = getSelectedAppCurrencyUseCase()
.conflate()
.distinctUntilChanged()
.map { maybeAppCurrency -> maybeAppCurrency.getOrElse { AppCurrency.Default } },
transform = { maybeCurrencyStatus, appCurrency -> maybeCurrencyStatus to appCurrency },
)
.onEach { maybeCurrencyStatusAndAppCurrency ->
val status = maybeCurrencyStatusAndAppCurrency.first.getOrElse {
Timber.e("Unable to get primary currency status: $it")
return@onEach
}
updateContent(status, maybeCurrencyStatusAndAppCurrency.second)
sendAnalyticsEvent(status)
checkWalletWithFunds(status)
}
}
private fun updateContent(maybeCurrencyStatus: Either<CurrencyStatusError, CryptoCurrencyStatus>) {
val status = (maybeCurrencyStatus as? Either.Right)?.value ?: return
private fun updateContent(status: CryptoCurrencyStatus, appCurrency: AppCurrency) {
stateHolder.update(
SetPrimaryCurrencyTransformer(
status = status.value,
status = status,
userWallet = userWallet,
appCurrency = appCurrency,
),
)
}
private fun sendAnalyticsEvent(maybeCurrencyStatus: Either<CurrencyStatusError, CryptoCurrencyStatus>) {
val status = (maybeCurrencyStatus as? Either.Right)?.value ?: return
private fun sendAnalyticsEvent(status: CryptoCurrencyStatus) {
val fiatAmount = status.value.fiatAmount
val cardBalanceState = when (status.value) {
is CryptoCurrencyStatus.Loaded,
@ -64,7 +72,9 @@ internal class PrimaryCurrencySubscriber(
is CryptoCurrencyStatus.NoAmount,
-> createCardBalanceState(fiatAmount)
is CryptoCurrencyStatus.NoQuote -> AnalyticsParam.CardBalanceState.NoRate
is CryptoCurrencyStatus.Unreachable -> AnalyticsParam.CardBalanceState.BlockchainError
is CryptoCurrencyStatus.Unreachable,
is CryptoCurrencyStatus.UnreachableWithoutAddresses,
-> AnalyticsParam.CardBalanceState.BlockchainError
is CryptoCurrencyStatus.MissedDerivation,
is CryptoCurrencyStatus.Loading,
is CryptoCurrencyStatus.Custom,
@ -84,9 +94,7 @@ internal class PrimaryCurrencySubscriber(
}
}
private suspend fun checkWalletWithFunds(maybeCurrencyStatus: Either<CurrencyStatusError, CryptoCurrencyStatus>) {
val status = (maybeCurrencyStatus as? Either.Right)?.value ?: return
private suspend fun checkWalletWithFunds(status: CryptoCurrencyStatus) {
if (status.value.amount?.isZero() == false) setWalletWithFundsFoundUseCase()
}
}

View file

@ -5,22 +5,21 @@ import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetCryptoCurrencyActionsTransformer
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlin.coroutines.CoroutineContext
internal class SingleWalletButtonsSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntentsV2,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
) : WalletSubscriber<TokenActionsState>(name = "single_wallet_buttons") {
) : WalletSubscriber() {
override fun create(coroutineScope: CoroutineScope, uiDispatcher: CoroutineContext): Flow<TokenActionsState> {
override fun create(coroutineScope: CoroutineScope): Flow<TokenActionsState> {
return channelFlow {
getPrimaryCurrencyStatusUpdatesUseCase.collectLatest(userWalletId = userWallet.walletId) { status ->
getCryptoCurrencyActionsUseCase(userWallet = userWallet, cryptoCurrencyStatus = status)

View file

@ -1,9 +1,10 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetSingleWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetWarningsTransformer
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.collections.immutable.ImmutableList
@ -12,29 +13,25 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlin.coroutines.CoroutineContext
/**
[REDACTED_AUTHOR]
*/
internal class SingleWalletNotificationsSubscriber(
private val userWalletId: UserWalletId,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val getSingleWalletWarningsFactory: GetSingleWalletWarningsFactory,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val clickIntents: WalletClickIntentsV2,
) : WalletSubscriber<ImmutableList<WalletNotification>>(name = "single_wallet_warnings") {
) : WalletSubscriber() {
override fun create(
coroutineScope: CoroutineScope,
uiDispatcher: CoroutineContext,
): Flow<ImmutableList<WalletNotification>> {
override fun create(coroutineScope: CoroutineScope): Flow<ImmutableList<WalletNotification>> {
return getSingleWalletWarningsFactory.create(clickIntents)
.conflate()
.distinctUntilChanged()
.onEach {
stateHolder.update(
SetWarningsTransformer(userWalletId = userWalletId, warnings = it),
)
.onEach { warnings ->
stateHolder.update(SetWarningsTransformer(userWalletId, warnings))
walletWarningsAnalyticsSender.send(warnings)
}
}
}

View file

@ -1,6 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.GetCardTokensListUseCase
import com.tangem.domain.tokens.error.TokenListError
@ -8,41 +10,43 @@ import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.wallets.models.UserWallet
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.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListTransformer
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.flow.*
@Suppress("LongParameterList")
internal class SingleWalletWithTokenListSubscriber(
private val userWallet: UserWallet,
private val appCurrency: AppCurrency,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntentsV2,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getCardTokensListUseCase: GetCardTokensListUseCase,
) : WalletSubscriber<Either<TokenListError, TokenList>>(name = "single_wallet_with_token_list") {
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
) : WalletSubscriber() {
override fun create(
coroutineScope: CoroutineScope,
uiDispatcher: CoroutineContext,
): Flow<Either<TokenListError, TokenList>> {
return getCardTokensListUseCase(userWalletId = userWallet.walletId)
.conflate()
.distinctUntilChanged()
.onEach(::updateContent)
.onEach { tokenListAnalyticsSender.send(userWallet, maybeTokenList = it) }
.onEach(walletWithFundsChecker::check)
override fun create(coroutineScope: CoroutineScope): Flow<Pair<Either<TokenListError, TokenList>, AppCurrency>> {
return combine(
flow = getCardTokensListUseCase(userWalletId = userWallet.walletId)
.conflate()
.distinctUntilChanged(),
flow2 = getSelectedAppCurrencyUseCase()
.conflate()
.distinctUntilChanged()
.map { maybeAppCurrency -> maybeAppCurrency.getOrElse { AppCurrency.Default } },
transform = { tokenList, appCurrency -> tokenList to appCurrency },
)
.onEach { (maybeTokenList, appCurrency) ->
updateContent(maybeTokenList, appCurrency)
tokenListAnalyticsSender.send(userWallet, maybeTokenList)
walletWithFundsChecker.check(maybeTokenList)
}
}
private fun updateContent(maybeTokenList: Either<TokenListError, TokenList>) {
private fun updateContent(maybeTokenList: Either<TokenListError, TokenList>, appCurrency: AppCurrency) {
stateHolder.update(
maybeTokenList.fold(
ifLeft = { SetTokenListErrorTransformer(userWalletId = userWallet.walletId, error = it) },

View file

@ -1,6 +1,8 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.error.TokenListError
@ -8,43 +10,45 @@ import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.wallets.models.UserWallet
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.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListTransformer
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.flow.*
typealias MaybeTokenListFlow = Flow<Either<TokenListError, TokenList>>
@Suppress("LongParameterList")
internal class TokenListSubscriber(
private val userWallet: UserWallet,
private val appCurrency: AppCurrency,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntentsV2,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getTokenListUseCase: GetTokenListUseCase,
) : WalletSubscriber<Either<TokenListError, TokenList>>(name = "token_list") {
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
) : WalletSubscriber() {
override fun create(
coroutineScope: CoroutineScope,
uiDispatcher: CoroutineContext,
): Flow<Either<TokenListError, TokenList>> {
return getTokenListUseCase(userWalletId = userWallet.walletId)
.conflate()
.distinctUntilChanged()
.onEach(::updateContent)
.onEach { tokenListAnalyticsSender.send(userWallet, maybeTokenList = it) }
.onEach(walletWithFundsChecker::check)
override fun create(coroutineScope: CoroutineScope): Flow<Pair<Either<TokenListError, TokenList>, AppCurrency>> {
return combine(
flow = getTokenListUseCase(userWalletId = userWallet.walletId)
.conflate()
.distinctUntilChanged(),
flow2 = getSelectedAppCurrencyUseCase()
.conflate()
.distinctUntilChanged()
.map { maybeAppCurrency -> maybeAppCurrency.getOrElse { AppCurrency.Default } },
transform = { tokenList, appCurrency -> tokenList to appCurrency },
)
.onEach { (maybeTokenList, appCurrency) ->
updateContent(maybeTokenList, appCurrency)
tokenListAnalyticsSender.send(userWallet, maybeTokenList)
walletWithFundsChecker.check(maybeTokenList)
}
}
private fun updateContent(maybeTokenList: Either<TokenListError, TokenList>) {
private fun updateContent(maybeTokenList: Either<TokenListError, TokenList>, appCurrency: AppCurrency) {
stateHolder.update(
maybeTokenList.fold(
ifLeft = { SetTokenListErrorTransformer(userWalletId = userWallet.walletId, error = it) },

View file

@ -12,7 +12,7 @@ import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountErrorTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountTransformer
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsErrorTransformer
@ -21,7 +21,6 @@ import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletCl
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlin.coroutines.CoroutineContext
typealias MaybeTxHistoryCount = Either<TxHistoryStateError, Int>
typealias MaybeTxHistoryItems = Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>
@ -30,17 +29,14 @@ typealias MaybeTxHistoryItems = Either<TxHistoryListError, Flow<PagingData<TxHis
internal class TxHistorySubscriber(
private val userWallet: UserWallet,
private val isRefresh: Boolean,
private val stateHolder: WalletStateHolderV2,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntentsV2,
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
) : WalletSubscriber<PagingData<TxHistoryItem>>(name = "tx_history") {
) : WalletSubscriber() {
override fun create(
coroutineScope: CoroutineScope,
uiDispatcher: CoroutineContext,
): Flow<PagingData<TxHistoryItem>> {
override fun create(coroutineScope: CoroutineScope): Flow<PagingData<TxHistoryItem>> {
return flow {
getPrimaryCurrencyStatusUpdatesUseCase.collectLatest(userWalletId = userWallet.walletId) { status ->
val maybeTxHistoryItemCount = txHistoryItemsCountUseCase(

View file

@ -0,0 +1,23 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetBalancesAndLimitsTransformer
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
internal class VisaWalletBalancesAndLimitsSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntentsV2,
) : WalletSubscriber() {
// TODO: Implement in [REDACTED_JIRA]
override fun create(coroutineScope: CoroutineScope): Flow<*> = suspend {
delay(timeMillis = 500)
stateHolder.update(SetBalancesAndLimitsTransformer(userWallet, clickIntents))
}.asFlow()
}

View file

@ -0,0 +1,80 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import arrow.core.Either
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkGroup
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.walletconnect.WalletConnectActions
import com.tangem.domain.wallets.models.UserWallet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
/**
* WalletConnect networks subscriber. Update WalletConnect networks for a specified [userWallet].
*
* @property userWallet user wallet
* @property getTokenListUseCase use case for subscribing on token list changes
* @property reduxStateHolder redux state holder
*
[REDACTED_AUTHOR]
*/
internal class WalletConnectNetworksSubscriber(
private val userWallet: UserWallet,
private val getTokenListUseCase: GetTokenListUseCase,
private val reduxStateHolder: ReduxStateHolder,
) : WalletSubscriber() {
private val mutex = Mutex()
override fun create(coroutineScope: CoroutineScope): Flow<Either<TokenListError, TokenList>> {
return getTokenListUseCase(userWalletId = userWallet.walletId)
.conflate()
.distinctUntilCurrenciesChanged()
.filterLoadedTokens()
.onEach {
mutex.withLock {
Timber.d("WalletConnect: ${userWallet.walletId} networks is updated")
reduxStateHolder.dispatch(
action = WalletConnectActions.New.SetupUserChains(userWallet = userWallet),
)
}
}
}
private fun MaybeTokenListFlow.distinctUntilCurrenciesChanged(): MaybeTokenListFlow {
return distinctUntilChanged { old, new ->
val oldCurrencies = old.fold(ifLeft = { null }, ifRight = { it.getCryptoCurrencies() })
val newCurrencies = new.fold(ifLeft = { null }, ifRight = { it.getCryptoCurrencies() })
oldCurrencies == newCurrencies
}
}
private fun MaybeTokenListFlow.filterLoadedTokens(): MaybeTokenListFlow {
return filter { either ->
either.fold(
ifLeft = { false },
ifRight = { it.getCryptoCurrencies().isAllCurrenciesLoaded() },
)
}
}
private fun TokenList.getCryptoCurrencies(): List<CryptoCurrencyStatus> {
return when (this) {
is TokenList.Ungrouped -> currencies
is TokenList.GroupedByNetwork -> groups.flatMap(NetworkGroup::currencies)
else -> emptyList()
}
}
private fun List<CryptoCurrencyStatus>.isAllCurrenciesLoaded(): Boolean {
return none { it.value is CryptoCurrencyStatus.Loading }
}
}

View file

@ -7,23 +7,20 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import timber.log.Timber
import kotlin.coroutines.CoroutineContext
/**
* Component for implementation of flow subscription
*
* @property name unique name of subscriber
* [T] - type of flow
*
[REDACTED_AUTHOR]
*/
internal abstract class WalletSubscriber<T>(val name: String) {
internal abstract class WalletSubscriber {
protected abstract fun create(coroutineScope: CoroutineScope, uiDispatcher: CoroutineContext): Flow<T>
protected abstract fun create(coroutineScope: CoroutineScope): Flow<*>
fun subscribe(coroutineScope: CoroutineScope, dispatchers: CoroutineDispatcherProvider): Job {
Timber.d("Subscribe on $name")
return create(coroutineScope, dispatchers.main)
Timber.d("Subscribe on ${this::class.simpleName}")
return create(coroutineScope)
.flowOn(dispatchers.main)
.launchIn(coroutineScope)
}

View file

@ -29,16 +29,16 @@ import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.ActionsBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
import com.tangem.feature.wallet.presentation.wallet.state2.NOT_INITIALIZED_WALLET_INDEX
import com.tangem.feature.wallet.presentation.wallet.state2.WalletScreenState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.model.*
import com.tangem.feature.wallet.presentation.wallet.ui.components.TokenActionsBottomSheet
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
import com.tangem.feature.wallet.presentation.wallet.ui.components.common.*
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.organizeTokensButton
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.controlButtons
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.marketPriceBlock
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.BalancesAndLimitsBottomSheet
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.balancesAndLimitsBlock
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.depositButton
import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator
import kotlinx.collections.immutable.toImmutableList
@ -141,6 +141,18 @@ private fun WalletContent(
}
}
(selectedWallet as? WalletState.Visa.Content)?.let {
depositButton(
modifier = itemModifier.fillMaxWidth(),
state = it.depositButtonState,
)
balancesAndLimitsBlock(
modifier = itemModifier,
state = it.balancesAndLimitBlockState,
)
}
contentItemsV2(
state = selectedWallet,
txHistoryItems = txHistoryItems,
@ -158,6 +170,7 @@ private fun WalletContent(
is TokenReceiveBottomSheetConfig -> TokenReceiveBottomSheet(config = bottomSheetConfig)
is ActionsBottomSheetConfig -> TokenActionsBottomSheet(config = bottomSheetConfig)
is ChooseAddressBottomSheetConfig -> ChooseAddressBottomSheet(config = bottomSheetConfig)
is BalancesAndLimitsBottomSheetConfig -> BalancesAndLimitsBottomSheet(config = bottomSheetConfig)
}
}

View file

@ -10,7 +10,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyS
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.tokensListItems
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.tokensListItemsV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState as WalletStateV2
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState as WalletStateV2
/**
* Wallet content
@ -46,5 +46,8 @@ internal fun LazyListScope.contentItemsV2(
is WalletStateV2.SingleCurrency -> {
txHistoryItems(state.txHistoryState, txHistoryItems, isBalanceHidden, modifier)
}
is WalletStateV2.Visa -> {
txHistoryItems(state.txHistoryState, txHistoryItems, isBalanceHidden, modifier)
}
}
}

View file

@ -19,8 +19,8 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
import kotlinx.collections.immutable.ImmutableList
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState as WalletTokensListStateV2
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState.TokensListItemState as TokensListItemStateV2
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState as WalletTokensListStateV2
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState.TokensListItemState as TokensListItemStateV2
private const val NON_CONTENT_TOKENS_LIST_KEY = "NON_CONTENT_TOKENS_LIST"

View file

@ -6,7 +6,7 @@ import com.tangem.core.ui.extensions.resolveReference
import com.tangem.feature.wallet.presentation.common.component.NetworkGroupItem
import com.tangem.feature.wallet.presentation.common.component.TokenItem
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state2.WalletTokensListState.TokensListItemState
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletTokensListState.TokensListItemState
/**
* Multi-currency content item

View file

@ -0,0 +1,197 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state2.model.BalancesAndLimitsBlockState
private const val BALANCES_AND_LIMITS_BLOCK_KEY = "BalancesAndLimitsBlock"
internal fun LazyListScope.balancesAndLimitsBlock(state: BalancesAndLimitsBlockState, modifier: Modifier = Modifier) {
item(key = BALANCES_AND_LIMITS_BLOCK_KEY, contentType = BALANCES_AND_LIMITS_BLOCK_KEY) {
BalancesAndLimitsBlock(state, modifier)
}
}
@Composable
private fun BalancesAndLimitsBlock(state: BalancesAndLimitsBlockState, modifier: Modifier = Modifier) {
val onClick: () -> Unit = remember(state) {
{ (state as? BalancesAndLimitsBlockState.Content)?.onClick?.invoke() }
}
val isEnabled: Boolean = remember(state) {
state is BalancesAndLimitsBlockState.Content && state.isEnabled
}
ContentContainer(
modifier = modifier.fillMaxWidth(),
enabled = isEnabled,
onClick = onClick,
title = {
Text(
text = "Balances & Limits",
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
},
content = {
Content(state = state)
},
endIcon = {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size24),
painter = painterResource(id = R.drawable.ic_chevron_right_24),
tint = TangemTheme.colors.icon.informative,
contentDescription = null,
)
},
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private inline fun ContentContainer(
enabled: Boolean,
noinline onClick: () -> Unit,
crossinline title: @Composable () -> Unit,
crossinline content: @Composable () -> Unit,
crossinline endIcon: @Composable () -> Unit,
modifier: Modifier = Modifier,
) {
Card(
modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(TangemTheme.dimens.radius16),
colors = CardDefaults.cardColors(
containerColor = TangemTheme.colors.background.primary,
contentColor = TangemTheme.colors.text.primary1,
disabledContainerColor = TangemTheme.colors.background.primary,
disabledContentColor = TangemTheme.colors.text.primary1,
),
onClick = onClick,
enabled = enabled,
) {
Row(
modifier = Modifier
.padding(all = TangemTheme.dimens.spacing12)
.fillMaxWidth()
.heightIn(min = TangemTheme.dimens.size48),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Column(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing6),
horizontalAlignment = Alignment.Start,
) {
title()
content()
}
endIcon()
}
}
}
@Composable
private fun Content(state: BalancesAndLimitsBlockState, modifier: Modifier = Modifier) {
AnimatedContent(
modifier = modifier,
targetState = state,
label = "Update the balances and limits block",
) { blockState ->
when (blockState) {
is BalancesAndLimitsBlockState.Content -> with(blockState) {
AvailableLimit(
availableBalance = availableBalance,
currencySymbol = currencySymbol,
limitDays = limitDays,
)
}
is BalancesAndLimitsBlockState.Error -> {
Text(
text = "",
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.primary1,
)
}
is BalancesAndLimitsBlockState.Loading -> {
RectangleShimmer(
modifier = Modifier
.width(TangemTheme.dimens.size200)
.height(TangemTheme.dimens.size20),
)
}
}
}
}
@Composable
private fun AvailableLimit(
availableBalance: String,
currencySymbol: String,
limitDays: Int,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
Text(
text = "$availableBalance $currencySymbol",
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
)
Text(
text = "available $limitDays-day limit",
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)
}
}
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Composable
private fun BalancesAndLimitsBlockPreview_Light(
@PreviewParameter(BalancesAndLimitsBlockParameterProvider::class) state: BalancesAndLimitsBlockState,
) {
TangemTheme {
BalancesAndLimitsBlock(state)
}
}
@Preview(showBackground = true, widthDp = 360)
@Composable
private fun BalancesAndLimitsBlockPreview_Dark(
@PreviewParameter(BalancesAndLimitsBlockParameterProvider::class) state: BalancesAndLimitsBlockState,
) {
TangemTheme(isDark = true) {
BalancesAndLimitsBlock(state)
}
}
private class BalancesAndLimitsBlockParameterProvider : CollectionPreviewParameterProvider<BalancesAndLimitsBlockState>(
collection = listOf(
BalancesAndLimitsBlockState.Loading,
BalancesAndLimitsBlockState.Error,
BalancesAndLimitsBlockState.Content(
availableBalance = "400.00",
currencySymbol = "USDT",
limitDays = 7,
isEnabled = true,
onClick = {},
),
),
)
// endregion Preview

Some files were not shown because too many files have changed in this diff Show more