Updated on 2026-08-14
This commit is contained in:
commit
6920ad3b6d
356 changed files with 7941 additions and 1194 deletions
|
|
@ -10,9 +10,11 @@ import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.nft.FetchNFTCollectionsUseCase
|
||||
import com.tangem.domain.settings.*
|
||||
import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
|
|
@ -41,6 +43,7 @@ import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
|
|||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.*
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -76,6 +79,8 @@ internal class WalletModel @Inject constructor(
|
|||
private val walletFeatureToggles: WalletFeatureToggles,
|
||||
private val biometryFeatureToggles: BiometryFeatureToggles,
|
||||
private val analyticsEventsHandler: AnalyticsEventHandler,
|
||||
private val fetchNFTCollectionsUseCase: FetchNFTCollectionsUseCase,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
val screenLifecycleProvider: ScreenLifecycleProvider,
|
||||
val innerWalletRouter: InnerWalletRouter,
|
||||
) : Model() {
|
||||
|
|
@ -86,6 +91,7 @@ internal class WalletModel @Inject constructor(
|
|||
private val walletsUpdateJobHolder = JobHolder()
|
||||
private val refreshWalletJobHolder = JobHolder()
|
||||
private val expressStatusJobHolder = JobHolder()
|
||||
private val walletsNFTsUpdateJobHolder = JobHolder()
|
||||
private var needToRefreshWallet = false
|
||||
|
||||
private var expressTxStatusTaskScheduler = SingleTaskScheduler<Unit>()
|
||||
|
|
@ -103,6 +109,7 @@ internal class WalletModel @Inject constructor(
|
|||
subscribeToScreenBackgroundState()
|
||||
subscribeOnPushNotificationsPermission()
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
subscribeOnNFTUpdates()
|
||||
|
||||
clickIntents.initialize(innerWalletRouter, modelScope)
|
||||
}
|
||||
|
|
@ -160,7 +167,10 @@ internal class WalletModel @Inject constructor(
|
|||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.map {
|
||||
walletsUpdateActionResolver.resolve(wallets = it, currentState = stateHolder.value)
|
||||
walletsUpdateActionResolver.resolve(
|
||||
wallets = it,
|
||||
currentState = stateHolder.value,
|
||||
)
|
||||
}
|
||||
.onEach(::updateWallets)
|
||||
.flowOn(dispatchers.main)
|
||||
|
|
@ -256,6 +266,29 @@ internal class WalletModel @Inject constructor(
|
|||
}.saveIn(expressStatusJobHolder)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun subscribeOnNFTUpdates() {
|
||||
getWalletsUseCase()
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { wallets ->
|
||||
wallets
|
||||
.map { wallet ->
|
||||
walletsRepository.nftEnabledStatus(wallet.walletId)
|
||||
.distinctUntilChanged()
|
||||
.onEach { nftEnabled ->
|
||||
if (nftEnabled) {
|
||||
fetchNFTCollectionsUseCase.invoke(wallet.walletId)
|
||||
}
|
||||
}
|
||||
}
|
||||
.merge()
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(modelScope)
|
||||
.saveIn(walletsNFTsUpdateJobHolder)
|
||||
}
|
||||
|
||||
private fun needToRefreshTimer() {
|
||||
modelScope.launch {
|
||||
delay(REFRESH_WALLET_BACKGROUND_TIMER_MILLIS)
|
||||
|
|
|
|||
|
|
@ -231,7 +231,10 @@ internal class WalletsUpdateActionResolver @Inject constructor(
|
|||
* @property prevWalletId previous selected wallet id
|
||||
* @property selectedWallet selected wallet
|
||||
*/
|
||||
data class ReinitializeWallet(val prevWalletId: UserWalletId, val selectedWallet: UserWallet) : Action() {
|
||||
data class ReinitializeWallet(
|
||||
val prevWalletId: UserWalletId,
|
||||
val selectedWallet: UserWallet,
|
||||
) : Action() {
|
||||
|
||||
override fun toString(): String {
|
||||
return "ReinitializeWallet(prevWalletId = $prevWalletId, selectedWallet = ${selectedWallet.walletId})"
|
||||
|
|
|
|||
|
|
@ -2,29 +2,19 @@ package com.tangem.feature.wallet.child.wallet.model.intents
|
|||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.mapToAddressModels
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.visa.GetVisaCurrencyUseCase
|
||||
import com.tangem.domain.visa.GetVisaTxDetailsUseCase
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.BalancesAndLimitsBottomSheetConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.VisaTxDetailsBottomSheetConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface VisaWalletIntents {
|
||||
|
||||
fun onDepositClick()
|
||||
|
||||
fun onBalancesAndLimitsClick()
|
||||
|
||||
fun onVisaTransactionClick(id: String)
|
||||
|
|
@ -36,7 +26,6 @@ internal interface VisaWalletIntents {
|
|||
internal class VisaWalletIntentsImplementor @Inject constructor(
|
||||
private val stateController: WalletStateController,
|
||||
private val eventSender: WalletEventSender,
|
||||
private val getCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase,
|
||||
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
|
||||
private val getVisaTxDetailsUseCase: GetVisaTxDetailsUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
|
|
@ -46,38 +35,6 @@ internal class VisaWalletIntentsImplementor @Inject constructor(
|
|||
BalancesAndLimitsBottomSheetConverter(eventSender)
|
||||
}
|
||||
|
||||
override fun onDepositClick() {
|
||||
val userWalletId = stateController.getSelectedWalletId()
|
||||
|
||||
modelScope.launch(dispatchers.main) {
|
||||
val currencyStatus = getPrimaryCurrencyStatus(userWalletId) ?: return@launch
|
||||
|
||||
createReceiveBottomSheetContent(currencyStatus)?.let { content ->
|
||||
stateController.showBottomSheet(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createReceiveBottomSheetContent(currencyStatus: CryptoCurrencyStatus): TangemBottomSheetConfigContent? {
|
||||
val currency = currencyStatus.currency
|
||||
val addresses = currencyStatus.value.networkAddress?.availableAddresses
|
||||
|
||||
if (addresses == null) {
|
||||
Timber.e("Addresses should not be null")
|
||||
return null
|
||||
}
|
||||
|
||||
return TokenReceiveBottomSheetConfig(
|
||||
name = currency.name,
|
||||
symbol = currency.symbol,
|
||||
network = currency.network.name,
|
||||
addresses = addresses.mapToAddressModels(currency).toImmutableList(),
|
||||
showMemoDisclaimer = currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
|
||||
onCopyClick = { /* no-op */ },
|
||||
onShareClick = { /* no-op */ },
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBalancesAndLimitsClick() {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
val userWalletId = stateController.getSelectedWalletId()
|
||||
|
|
@ -95,14 +52,6 @@ internal class VisaWalletIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getPrimaryCurrencyStatus(userWalletId: UserWalletId): CryptoCurrencyStatus? {
|
||||
return getCurrencyStatusUseCase(userWalletId)
|
||||
.getOrElse {
|
||||
Timber.e("Failed to get primary currency $it")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onVisaTransactionClick(id: String) {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
val userWalletId = stateController.getSelectedWalletId()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.appcurrency.extenstions.unwrap
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.nft.FetchNFTCollectionsUseCase
|
||||
import com.tangem.domain.onramp.FetchHotCryptoUseCase
|
||||
import com.tangem.domain.settings.NeverToShowWalletsScrollPreview
|
||||
import com.tangem.domain.tokens.FetchCardTokenListUseCase
|
||||
|
|
@ -14,6 +15,7 @@ import com.tangem.domain.tokens.FetchTokenListUseCase.RefreshMode
|
|||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.SelectWalletUseCase
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.IsWalletNFTEnabledSyncUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
|
||||
import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
|
|
@ -50,6 +52,8 @@ internal class WalletClickIntents @Inject constructor(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val onrampFeatureToggles: OnrampFeatureToggles,
|
||||
private val fetchHotCryptoUseCase: FetchHotCryptoUseCase,
|
||||
private val fetchNFTCollectionsUseCase: FetchNFTCollectionsUseCase,
|
||||
private val isWalletNFTEnabledSyncUseCase: IsWalletNFTEnabledSyncUseCase,
|
||||
) : BaseWalletClickIntents(),
|
||||
WalletCardClickIntents by walletCardClickIntentsImplementor,
|
||||
WalletWarningsClickIntents by warningsClickIntentsImplementer,
|
||||
|
|
@ -140,6 +144,10 @@ internal class WalletClickIntents @Inject constructor(
|
|||
if (onrampFeatureToggles.isHotTokensEnabled) {
|
||||
async { fetchHotCryptoUseCase() }.let(::add)
|
||||
}
|
||||
|
||||
if (isWalletNFTEnabledSyncUseCase.invoke(userWallet.walletId)) {
|
||||
async { fetchNFTCollectionsUseCase(userWalletId = userWallet.walletId) }.let(::add)
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
|
||||
|
|
|
|||
|
|
@ -120,6 +120,12 @@ internal object WalletScreenPreviewData {
|
|||
),
|
||||
bottomSheetConfig = null,
|
||||
tokensListState = textContentTokensState,
|
||||
nftState = WalletNFTItemUM.Content(
|
||||
previews = persistentListOf(WalletNFTItemUM.Content.CollectionPreview.Image("img1")),
|
||||
collectionsCount = 1,
|
||||
assetsCount = 3,
|
||||
isFlickering = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ sealed class WalletScreenAnalyticsEvent {
|
|||
sealed class Basic(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
error: Throwable? = null,
|
||||
) : AnalyticsEvent(category = "Basic", event = event, params = params, error = error) {
|
||||
) : AnalyticsEvent(category = "Basic", event = event, params = params) {
|
||||
|
||||
class WalletToppedUp(userWalletId: UserWalletId, walletType: AnalyticsParam.WalletType) :
|
||||
Basic(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.features.nft.NFTFeatureToggles
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
|
||||
class IsWalletNFTEnabledSyncUseCase(
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val nftFeatureToggles: NFTFeatureToggles,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId): Boolean = if (nftFeatureToggles.isNFTEnabled) {
|
||||
walletsRepository
|
||||
.nftEnabledStatuses()
|
||||
.firstOrNull()
|
||||
?.let { it[userWalletId] }
|
||||
?: false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
|
||||
import javax.inject.Inject
|
||||
|
|
@ -16,7 +15,7 @@ import javax.inject.Inject
|
|||
internal class ScanCardToUnlockWalletClickHandler @Inject constructor(
|
||||
private val scanCardProcessor: ScanCardProcessor,
|
||||
private val saveWalletUseCase: SaveWalletUseCase,
|
||||
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
|
||||
private val userWalletBuilderFactory: UserWalletBuilder.Factory,
|
||||
) {
|
||||
|
||||
private var scanFailsCounter = 0
|
||||
|
|
@ -34,7 +33,7 @@ internal class ScanCardToUnlockWalletClickHandler @Inject constructor(
|
|||
scanFailsCounter = 0
|
||||
|
||||
// If card's public key is null then user wallet will be null
|
||||
val scannedWallet = UserWalletBuilder(result.data, generateWalletNameUseCase).build()
|
||||
val scannedWallet = userWalletBuilderFactory.create(scanResponse = result.data).build()
|
||||
|
||||
ensure(walletId == scannedWallet?.walletId) {
|
||||
ScanCardToUnlockWalletError.WrongCardIsScanned
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ internal enum class Wallet2CobrandImage(
|
|||
BitcoinGold(
|
||||
cards2ResId = R.drawable.ill_bitcoingold_card2_120_106,
|
||||
cards3ResId = R.drawable.ill_bitcoingold_card3_120_106,
|
||||
batchIds = setOf("AF71"),
|
||||
batchIds = setOf("AF71", "AF990016", "AF990009"),
|
||||
),
|
||||
|
||||
BitcoinPizzaDay(
|
||||
|
|
@ -169,6 +169,12 @@ internal enum class Wallet2CobrandImage(
|
|||
batchIds = setOf("AF95"),
|
||||
),
|
||||
|
||||
Keiro(
|
||||
cards2ResId = R.drawable.ill_keiro_card2_120_106,
|
||||
cards3ResId = R.drawable.ill_keiro_card3_120_106,
|
||||
batchIds = setOf("BB000017"),
|
||||
),
|
||||
|
||||
KishuInu(
|
||||
cards2ResId = R.drawable.ill_kishu_inu_card2_120_106,
|
||||
cards3ResId = R.drawable.ill_kishu_inu_card3_120_106,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.deeplink.DeepLinksRegistry
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.nft.GetNFTCollectionsUseCase
|
||||
import com.tangem.domain.promo.GetStoryContentUseCase
|
||||
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
|
|
@ -21,6 +23,7 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActi
|
|||
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletTokenListSubscriber
|
||||
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
|
||||
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
|
||||
import com.tangem.features.nft.NFTFeatureToggles
|
||||
import com.tangem.features.swap.SwapFeatureToggles
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
|
|
@ -34,6 +37,7 @@ internal class MultiWalletContentLoader(
|
|||
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
|
||||
private val walletWithFundsChecker: WalletWithFundsChecker,
|
||||
private val tokenListStore: MultiWalletTokenListStore,
|
||||
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
|
||||
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
|
||||
|
|
@ -42,6 +46,8 @@ internal class MultiWalletContentLoader(
|
|||
private val getStoryContentUseCase: GetStoryContentUseCase,
|
||||
private val swapFeatureToggles: SwapFeatureToggles,
|
||||
private val deepLinksRegistry: DeepLinksRegistry,
|
||||
private val nftFeatureToggles: NFTFeatureToggles,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
) : WalletContentLoader(id = userWallet.walletId) {
|
||||
|
||||
override fun create(): List<WalletSubscriber> {
|
||||
|
|
@ -58,6 +64,15 @@ internal class MultiWalletContentLoader(
|
|||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
deepLinksRegistry = deepLinksRegistry,
|
||||
).let(::add)
|
||||
if (nftFeatureToggles.isNFTEnabled) {
|
||||
WalletNFTListSubscriber(
|
||||
userWallet = userWallet,
|
||||
getNFTCollectionsUseCase = getNFTCollectionsUseCase,
|
||||
stateHolder = stateHolder,
|
||||
walletsRepository = walletsRepository,
|
||||
clickIntents = clickIntents,
|
||||
).let(::add)
|
||||
}
|
||||
MultiWalletWarningsSubscriber(
|
||||
userWallet = userWallet,
|
||||
stateHolder = stateHolder,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
|
|||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.deeplink.DeepLinksRegistry
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.nft.GetNFTCollectionsUseCase
|
||||
import com.tangem.domain.promo.GetStoryContentUseCase
|
||||
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
|
|
@ -16,6 +18,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin
|
|||
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.features.nft.NFTFeatureToggles
|
||||
import com.tangem.features.swap.SwapFeatureToggles
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -36,6 +39,9 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
|
|||
private val getStoryContentUseCase: GetStoryContentUseCase,
|
||||
private val swapFeatureToggles: SwapFeatureToggles,
|
||||
private val deepLinksRegistry: DeepLinksRegistry,
|
||||
private val nftFeatureToggles: NFTFeatureToggles,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
|
||||
) {
|
||||
|
||||
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): WalletContentLoader {
|
||||
|
|
@ -56,6 +62,9 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
|
|||
shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase,
|
||||
swapFeatureToggles = swapFeatureToggles,
|
||||
deepLinksRegistry = deepLinksRegistry,
|
||||
nftFeatureToggles = nftFeatureToggles,
|
||||
walletsRepository = walletsRepository,
|
||||
getNFTCollectionsUseCase = getNFTCollectionsUseCase,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state
|
|||
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.model.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.NOT_INITIALIZED_WALLET_INDEX
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.model
|
||||
|
||||
internal data class DepositButtonState(
|
||||
val isEnabled: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
|
|
@ -22,6 +22,7 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
sealed class MultiCurrency : WalletState {
|
||||
|
||||
abstract val tokensListState: WalletTokensListState
|
||||
abstract val nftState: WalletNFTItemUM
|
||||
|
||||
data class Content(
|
||||
override val pullToRefreshConfig: PullToRefreshConfig,
|
||||
|
|
@ -30,6 +31,7 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
override val warnings: ImmutableList<WalletNotification>,
|
||||
override val bottomSheetConfig: TangemBottomSheetConfig?,
|
||||
override val tokensListState: WalletTokensListState,
|
||||
override val nftState: WalletNFTItemUM,
|
||||
) : MultiCurrency()
|
||||
|
||||
data class Locked(
|
||||
|
|
@ -46,6 +48,7 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
) {
|
||||
|
||||
override val tokensListState = WalletTokensListState.ContentState.Locked
|
||||
override val nftState: WalletNFTItemUM = WalletNFTItemUM.Hidden
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +99,6 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
override val bottomSheetConfig: TangemBottomSheetConfig?,
|
||||
override val balancesAndLimitBlockState: BalancesAndLimitsBlockState,
|
||||
override val txHistoryState: TxHistoryState,
|
||||
val depositButtonState: DepositButtonState,
|
||||
) : Visa()
|
||||
|
||||
data class Locked(
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ internal class InitializeWalletsTransformer(
|
|||
if (userWallet.isLocked) {
|
||||
createLockedState(userWallet)
|
||||
} else {
|
||||
walletLoadingStateFactory.create(userWallet)
|
||||
walletLoadingStateFactory.create(
|
||||
userWallet = userWallet,
|
||||
)
|
||||
}
|
||||
}
|
||||
.toImmutableList(),
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
|||
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletLoadingStateFactory
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
|
|
@ -38,7 +38,11 @@ internal class ReinitializeWalletTransformer(
|
|||
return prevState.copy(
|
||||
wallets = prevState.wallets
|
||||
.filterNot { it.walletCardState.id == prevWalletId }
|
||||
.plus(element = walletLoadingStateFactory.create(newUserWallet))
|
||||
.plus(
|
||||
element = walletLoadingStateFactory.create(
|
||||
userWallet = newUserWallet,
|
||||
),
|
||||
)
|
||||
.toImmutableList(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNFTItemUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
|
||||
internal class RemoveNFTCollectionsTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
) : WalletStateTransformer(userWalletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState = when (prevState) {
|
||||
is WalletState.MultiCurrency.Content -> prevState.copy(
|
||||
nftState = WalletNFTItemUM.Hidden,
|
||||
)
|
||||
is WalletState.SingleCurrency.Content,
|
||||
is WalletState.Visa.Content,
|
||||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> prevState
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.nft.models.NFTCollections
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNFTItemUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class SetNFTCollectionsTransformer(
|
||||
userWalletId: UserWalletId,
|
||||
private val nftCollections: List<NFTCollections>,
|
||||
) : WalletStateTransformer(userWalletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState = when (prevState) {
|
||||
is WalletState.MultiCurrency.Content -> prevState.copy(
|
||||
nftState = when {
|
||||
allCollectionsFailed() -> WalletNFTItemUM.Failed
|
||||
anyCollectionFailed() && allLoadedCollectionsEmpty() -> WalletNFTItemUM.Failed
|
||||
allCollectionsLoaded() && allCollectionsEmpty() -> WalletNFTItemUM.Empty
|
||||
!allCollectionsLoaded() && allCollectionsEmpty() -> WalletNFTItemUM.Loading
|
||||
else -> createContentNFTItemUM()
|
||||
},
|
||||
)
|
||||
is WalletState.SingleCurrency.Content,
|
||||
is WalletState.Visa.Content,
|
||||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> prevState
|
||||
}
|
||||
|
||||
private fun createContentNFTItemUM(): WalletNFTItemUM.Content {
|
||||
val collectionsContent = nftCollections
|
||||
.map { it.content }
|
||||
.filterIsInstance<NFTCollections.Content.Collections>()
|
||||
|
||||
val isFlickering = collectionsContent
|
||||
.map { it.source }
|
||||
.any { it == StatusSource.CACHE }
|
||||
|
||||
val collections = collectionsContent
|
||||
.mapNotNull { it.collections }
|
||||
.flatten()
|
||||
|
||||
return WalletNFTItemUM.Content(
|
||||
previews = if (collections.size > NFT_COLLECTIONS_MAX_PREVIEWS_COUNT) {
|
||||
collections
|
||||
.take(NFT_COLLECTIONS_MAX_PREVIEWS_COUNT - 1)
|
||||
.map { WalletNFTItemUM.Content.CollectionPreview.Image(it.logoUrl.orEmpty()) }
|
||||
.plus(WalletNFTItemUM.Content.CollectionPreview.More)
|
||||
.toPersistentList()
|
||||
} else {
|
||||
collections
|
||||
.take(NFT_COLLECTIONS_MAX_PREVIEWS_COUNT)
|
||||
.map { WalletNFTItemUM.Content.CollectionPreview.Image(it.logoUrl.orEmpty()) }
|
||||
.toPersistentList()
|
||||
},
|
||||
collectionsCount = collections.size,
|
||||
assetsCount = collections
|
||||
.sumOf { it.count },
|
||||
isFlickering = isFlickering,
|
||||
)
|
||||
}
|
||||
|
||||
private fun allCollectionsFailed() = nftCollections.all {
|
||||
it.content is NFTCollections.Content.Error
|
||||
}
|
||||
|
||||
private fun anyCollectionFailed() = nftCollections.any {
|
||||
it.content is NFTCollections.Content.Error
|
||||
}
|
||||
|
||||
private fun allLoadedCollectionsEmpty() = nftCollections
|
||||
.map { it.content }
|
||||
.filterIsInstance<NFTCollections.Content.Collections>()
|
||||
.all { it.collections.isNullOrEmpty() }
|
||||
|
||||
private fun allCollectionsLoaded() = nftCollections.all {
|
||||
val content = it.content
|
||||
content is NFTCollections.Content.Collections &&
|
||||
content.source != StatusSource.CACHE
|
||||
}
|
||||
|
||||
private fun allCollectionsEmpty() = nftCollections.all {
|
||||
val content = it.content
|
||||
content is NFTCollections.Content.Collections &&
|
||||
content.collections.isNullOrEmpty()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NFT_COLLECTIONS_MAX_PREVIEWS_COUNT = 4
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
|||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimitsBlockState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.DepositButtonState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.mutate
|
||||
|
|
@ -29,8 +28,8 @@ internal class SetRefreshStateTransformer(
|
|||
}
|
||||
is WalletState.Visa.Content -> {
|
||||
prevState.copy(
|
||||
buttons = prevState.buttons.toUpdatedState(),
|
||||
pullToRefreshConfig = prevState.pullToRefreshConfig.toUpdatedState(isRefreshing),
|
||||
depositButtonState = prevState.depositButtonState.toUpdatedState(isRefreshing),
|
||||
balancesAndLimitBlockState = prevState.balancesAndLimitBlockState.toUpdatedState(isRefreshing),
|
||||
)
|
||||
}
|
||||
|
|
@ -75,10 +74,6 @@ 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)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.core.ui.format.bigdecimal.crypto
|
|||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.common.util.getCardsCount
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.visa.exception.RefreshTokenExpiredException
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
|
@ -15,11 +16,14 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditiona
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletManageButton
|
||||
import com.tangem.utils.extensions.isZero
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.Days
|
||||
|
||||
internal class SetBalancesAndLimitsTransformer(
|
||||
internal class SetVisaInfoTransformer(
|
||||
private val userWallet: UserWallet,
|
||||
private val maybeVisaCurrency: Either<Throwable, VisaCurrency>,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
|
|
@ -35,15 +39,15 @@ internal class SetBalancesAndLimitsTransformer(
|
|||
}
|
||||
|
||||
return prevState.copy(
|
||||
buttons = createVisaButtonsDimmed(),
|
||||
walletCardState = getErrorWalletCardState(prevState.walletCardState),
|
||||
depositButtonState = prevState.depositButtonState.copy(isEnabled = false),
|
||||
balancesAndLimitBlockState = BalancesAndLimitsBlockState.Error,
|
||||
)
|
||||
}
|
||||
|
||||
return prevState.copy(
|
||||
buttons = createVisaButtons(visaCurrency = visaCurrency),
|
||||
walletCardState = getContentWalletCardState(prevState.walletCardState, visaCurrency),
|
||||
depositButtonState = prevState.depositButtonState.copy(isEnabled = true),
|
||||
balancesAndLimitBlockState = getContentBlockState(visaCurrency),
|
||||
)
|
||||
}
|
||||
|
|
@ -115,4 +119,43 @@ internal class SetBalancesAndLimitsTransformer(
|
|||
onUnlockVisaAccessNotificationClick = clickIntents::onUnlockVisaAccessClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createVisaButtonsDimmed(): PersistentList<WalletManageButton> {
|
||||
return persistentListOf(
|
||||
WalletManageButton.Receive(enabled = true, dimContent = true, onClick = {}, onLongClick = null),
|
||||
WalletManageButton.Buy(enabled = true, dimContent = true, onClick = {}),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createVisaButtons(visaCurrency: VisaCurrency): PersistentList<WalletManageButton> {
|
||||
// [Second Visa Iteration] Make VisaCurrency contain CryptoCurrencyStatus
|
||||
val cryptoCurrencyStatus = CryptoCurrencyStatus(
|
||||
currency = visaCurrency.cryptoCurrency,
|
||||
value = CryptoCurrencyStatus.Loaded(
|
||||
amount = visaCurrency.balances.available,
|
||||
fiatAmount = visaCurrency.balances.available.multiply(visaCurrency.fiatRate),
|
||||
fiatRate = visaCurrency.fiatRate,
|
||||
priceChange = visaCurrency.priceChange,
|
||||
yieldBalance = null,
|
||||
hasCurrentNetworkTransactions = false,
|
||||
pendingTransactions = emptySet(),
|
||||
networkAddress = visaCurrency.paymentAccountAddress,
|
||||
sources = CryptoCurrencyStatus.Sources(),
|
||||
),
|
||||
)
|
||||
|
||||
return return persistentListOf(
|
||||
WalletManageButton.Receive(
|
||||
enabled = true,
|
||||
dimContent = false,
|
||||
onClick = { clickIntents.onReceiveClick(cryptoCurrencyStatus = cryptoCurrencyStatus) },
|
||||
onLongClick = { clickIntents.onCopyAddressLongClick(cryptoCurrencyStatus = cryptoCurrencyStatus) },
|
||||
),
|
||||
WalletManageButton.Buy(
|
||||
enabled = true,
|
||||
dimContent = false,
|
||||
onClick = { clickIntents.onMultiWalletBuyClick(userWalletId = userWallet.walletId) },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,9 @@ internal class UnlockWalletTransformer(
|
|||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
-> walletLoadingStateFactory.create(userWallet = unlockedWallet)
|
||||
-> walletLoadingStateFactory.create(
|
||||
userWallet = unlockedWallet,
|
||||
)
|
||||
is WalletState.MultiCurrency.Content,
|
||||
is WalletState.SingleCurrency.Content,
|
||||
is WalletState.Visa.Content,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.utils
|
||||
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -41,6 +41,7 @@ internal class WalletLoadingStateFactory(
|
|||
warnings = persistentListOf(),
|
||||
bottomSheetConfig = null,
|
||||
tokensListState = WalletTokensListState.ContentState.Loading,
|
||||
nftState = WalletNFTItemUM.Hidden,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +68,7 @@ internal class WalletLoadingStateFactory(
|
|||
return WalletState.Visa.Content(
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
walletCardState = userWallet.toLoadingWalletCardState(),
|
||||
buttons = createMultiWalletActions(userWallet),
|
||||
buttons = createVisaDimmedButtons(),
|
||||
warnings = persistentListOf(),
|
||||
bottomSheetConfig = null,
|
||||
balancesAndLimitBlockState = BalancesAndLimitsBlockState.Loading,
|
||||
|
|
@ -76,12 +77,14 @@ internal class WalletLoadingStateFactory(
|
|||
value = TxHistoryState.getDefaultLoadingTransactions(clickIntents::onExploreClick),
|
||||
),
|
||||
),
|
||||
depositButtonState = DepositButtonState(isEnabled = false, clickIntents::onDepositClick),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPullToRefreshConfig(): PullToRefreshConfig {
|
||||
return PullToRefreshConfig(onRefresh = { clickIntents.onRefreshSwipe(it.value) }, isRefreshing = false)
|
||||
return PullToRefreshConfig(
|
||||
onRefresh = { clickIntents.onRefreshSwipe(it.value) },
|
||||
isRefreshing = false,
|
||||
)
|
||||
}
|
||||
|
||||
private fun UserWallet.toLoadingWalletCardState(): WalletCardState {
|
||||
|
|
@ -117,6 +120,13 @@ internal class WalletLoadingStateFactory(
|
|||
)
|
||||
}
|
||||
|
||||
private fun createVisaDimmedButtons(): PersistentList<WalletManageButton> {
|
||||
return persistentListOf(
|
||||
WalletManageButton.Receive(enabled = true, dimContent = true, onClick = {}, onLongClick = null),
|
||||
WalletManageButton.Buy(enabled = true, dimContent = true, onClick = {}),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createDimmedButtons(): PersistentList<WalletManageButton> {
|
||||
return persistentListOf(
|
||||
WalletManageButton.Receive(enabled = true, dimContent = true, onClick = {}, onLongClick = null),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.tangem.domain.visa.model.VisaTxHistoryItem
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetBalancesAndLimitsTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetVisaInfoTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryCountTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsErrorTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTxHistoryItemsTransformer
|
||||
|
|
@ -62,7 +62,7 @@ internal class VisaWalletSubscriber(
|
|||
|
||||
private fun setLoadedCurrencyState(maybeCurrency: Either<Throwable, VisaCurrency>) {
|
||||
stateController.update(
|
||||
SetBalancesAndLimitsTransformer(
|
||||
SetVisaInfoTransformer(
|
||||
userWallet = userWallet,
|
||||
maybeVisaCurrency = maybeCurrency,
|
||||
clickIntents = clickIntents,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.domain.nft.GetNFTCollectionsUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.RemoveNFTCollectionsTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetNFTCollectionsTransformer
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
internal class WalletNFTListSubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
private val stateHolder: WalletStateController,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
|
||||
clickIntents: WalletClickIntents,
|
||||
) : WalletSubscriber() {
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<*> = walletsRepository
|
||||
.nftEnabledStatus(userWallet.walletId)
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest { nftEnabled ->
|
||||
// if NFT is enabled for this wallet, then start observing changes from store and apply transformer if need
|
||||
if (nftEnabled) {
|
||||
getNFTCollectionsUseCase
|
||||
.launch(userWallet.walletId)
|
||||
.shareIn(
|
||||
scope = coroutineScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
replay = 1,
|
||||
)
|
||||
.onEach {
|
||||
stateHolder.update(
|
||||
SetNFTCollectionsTransformer(userWallet.walletId, it),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// otherwise, hide NFT from wallet
|
||||
stateHolder.update(
|
||||
RemoveNFTCollectionsTransformer(userWallet.walletId),
|
||||
)
|
||||
emptyFlow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -80,12 +80,12 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.TokenActionsB
|
|||
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.common.actions
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.nftCollections
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.organizeTokensButton
|
||||
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.VisaTxDetailsBottomSheet
|
||||
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 com.tangem.features.markets.entry.BottomSheetState
|
||||
import com.tangem.features.markets.entry.MarketsEntryComponent
|
||||
|
|
@ -230,11 +230,6 @@ private fun WalletContent(
|
|||
}
|
||||
|
||||
(selectedWallet as? WalletState.Visa.Content)?.let {
|
||||
depositButton(
|
||||
modifier = itemModifier.fillMaxWidth(),
|
||||
state = it.depositButtonState,
|
||||
)
|
||||
|
||||
balancesAndLimitsBlock(
|
||||
modifier = itemModifier,
|
||||
state = it.balancesAndLimitBlockState,
|
||||
|
|
@ -248,6 +243,8 @@ private fun WalletContent(
|
|||
modifier = movableItemModifier,
|
||||
)
|
||||
|
||||
nftCollections(state = selectedWallet, itemModifier = itemModifier)
|
||||
|
||||
organizeTokens(state = selectedWallet, itemModifier = itemModifier)
|
||||
}
|
||||
|
||||
|
|
@ -706,6 +703,16 @@ internal fun LazyListScope.organizeTokens(state: WalletState, itemModifier: Modi
|
|||
}
|
||||
}
|
||||
|
||||
internal fun LazyListScope.nftCollections(state: WalletState, itemModifier: Modifier) {
|
||||
(state as? WalletState.MultiCurrency)?.let {
|
||||
nftCollections(
|
||||
modifier = itemModifier,
|
||||
state = it.nftState,
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
|
||||
if (bottomSheetConfig != null) {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,20 @@ private fun WalletNFTItemFailed(modifier: Modifier = Modifier) {
|
|||
RowContentContainer(
|
||||
modifier = modifier,
|
||||
icon = {
|
||||
CollectionsPreviewsPlaceholder()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size36)
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius8))
|
||||
.background(TangemTheme.colors.field.primary),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
painter = painterResource(R.drawable.ic_error_sync_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
|
|
@ -158,7 +171,12 @@ private fun WalletNFTItemLoading(modifier: Modifier = Modifier) {
|
|||
RowContentContainer(
|
||||
modifier = modifier,
|
||||
icon = {
|
||||
CollectionsPreviewsPlaceholder()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size36)
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius8))
|
||||
.background(TangemTheme.colors.field.primary),
|
||||
)
|
||||
},
|
||||
text = {
|
||||
TextShimmer(
|
||||
|
|
@ -178,16 +196,6 @@ private fun WalletNFTItemLoading(modifier: Modifier = Modifier) {
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CollectionsPreviewsPlaceholder(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(TangemTheme.dimens.size36)
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius8))
|
||||
.background(TangemTheme.colors.field.primary),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("MagicNumber")
|
||||
private fun BoxScope.CollectionsPreviews(previews: ImmutableList<CollectionPreview>, modifier: Modifier = Modifier) {
|
||||
|
|
@ -207,7 +215,7 @@ private fun BoxScope.CollectionsPreviews(previews: ImmutableList<CollectionPrevi
|
|||
is CollectionPreview.Image -> {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = modifier,
|
||||
model = s,
|
||||
model = s.url,
|
||||
loading = {
|
||||
RectangleShimmer(radius = 0.dp)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNFTItemUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletNFTItem
|
||||
|
||||
private const val NFT_COLLECTIONS_CONTENT_TYPE = "NFTCollections"
|
||||
|
||||
internal fun LazyListScope.nftCollections(state: WalletNFTItemUM, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
item(key = NFT_COLLECTIONS_CONTENT_TYPE, contentType = NFT_COLLECTIONS_CONTENT_TYPE) {
|
||||
WalletNFTItem(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.visa
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.PrimaryButtonIconStart
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.DepositButtonState
|
||||
|
||||
private const val DEPOSIT_BUTTON_CONTENT_TYPE = "DepositButton"
|
||||
|
||||
internal fun LazyListScope.depositButton(state: DepositButtonState, modifier: Modifier = Modifier) {
|
||||
item(key = DEPOSIT_BUTTON_CONTENT_TYPE, contentType = DEPOSIT_BUTTON_CONTENT_TYPE) {
|
||||
PrimaryButtonIconStart(
|
||||
modifier = modifier,
|
||||
text = "Deposit",
|
||||
iconResId = R.drawable.ic_arrow_down_24,
|
||||
onClick = state.onClick,
|
||||
enabled = state.isEnabled,
|
||||
)
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Loading…
Add table
Add a link
Reference in a new issue