From febb2bda4cb9ab5a1cdca360d92081d2d2e7ed9c Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 13 Jul 2026 16:11:04 +0200 Subject: [PATCH] Updated on 2026-08-14 --- .../components/feed/DefaultFeedComponent.kt | 6 +- .../api/PromoBannersBlockComponent.kt | 9 +- .../impl/DefaultPromoBannersBlockComponent.kt | 11 +- .../impl/model/PromoBannersBlockModel.kt | 173 +++++++++++++----- .../DefaultPromoBannersRepository.kt | 4 + .../impl/repository/PromoBannersRepository.kt | 2 + .../wallet/child/wallet/WalletComponent.kt | 10 +- .../presentation/wallet/ui/WalletScreen.kt | 12 +- .../presentation/wallet/ui/WalletScreen2.kt | 14 +- .../ui/components/common/WalletContent.kt | 12 +- 10 files changed, 186 insertions(+), 67 deletions(-) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/feed/DefaultFeedComponent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/feed/DefaultFeedComponent.kt index 1000954081..d8d9841e4f 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/feed/DefaultFeedComponent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/components/feed/DefaultFeedComponent.kt @@ -87,7 +87,11 @@ internal class DefaultFeedComponent( modifier = modifier, state = state, promoBannersBlockComponent = ComposableContentComponent { promoModifier -> - promoBannersBlockComponent.ContentWithPadding(modifier = promoModifier, horizontalItemPadding = 16.dp) + promoBannersBlockComponent.ContentWithPadding( + modifier = promoModifier, + horizontalItemPadding = 16.dp, + walletId = null, + ) }, contentPadding = contentPadding, ) diff --git a/features/promo-banners/api/src/main/kotlin/com/tangem/features/promobanners/api/PromoBannersBlockComponent.kt b/features/promo-banners/api/src/main/kotlin/com/tangem/features/promobanners/api/PromoBannersBlockComponent.kt index d2eb78c1ae..92d6cfec1d 100644 --- a/features/promo-banners/api/src/main/kotlin/com/tangem/features/promobanners/api/PromoBannersBlockComponent.kt +++ b/features/promo-banners/api/src/main/kotlin/com/tangem/features/promobanners/api/PromoBannersBlockComponent.kt @@ -1,14 +1,21 @@ package com.tangem.features.promobanners.api import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import com.tangem.core.decompose.factory.ComponentFactory +@Immutable interface PromoBannersBlockComponent { + /** + * @param walletId when non-null, renders the banners of that specific wallet (used by the wallet + * pager so each page shows its own banners synchronously while swiping); when null, renders the + * currently selected wallet's banners. + */ @Composable - fun ContentWithPadding(horizontalItemPadding: Dp, modifier: Modifier) + fun ContentWithPadding(horizontalItemPadding: Dp, walletId: String?, modifier: Modifier) fun setVisibleOnScreen(isVisible: Boolean) diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/DefaultPromoBannersBlockComponent.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/DefaultPromoBannersBlockComponent.kt index fc2b86a4e4..662d8042da 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/DefaultPromoBannersBlockComponent.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/DefaultPromoBannersBlockComponent.kt @@ -26,8 +26,15 @@ internal class DefaultPromoBannersBlockComponent @AssistedInject constructor( } @Composable - override fun ContentWithPadding(horizontalItemPadding: Dp, modifier: Modifier) { - val state by model.uiState.collectAsStateWithLifecycle() + override fun ContentWithPadding(horizontalItemPadding: Dp, walletId: String?, modifier: Modifier) { + val state = if (walletId != null) { + val statesByWallet by model.bannerStates.collectAsStateWithLifecycle() + statesByWallet[walletId] + } else { + val selectedState by model.uiState.collectAsStateWithLifecycle() + selectedState + } ?: return + PromoBannersBlock( state = state, modifier = modifier, diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt index 108b6fe3e5..9e251f128c 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt @@ -1,11 +1,11 @@ package com.tangem.features.promobanners.impl.model import androidx.core.net.toUri -import com.tangem.core.navigation.deeplink.DeeplinkLauncher import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.core.navigation.deeplink.DeeplinkLauncher import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.features.promobanners.api.PromoBannersBlockComponent import com.tangem.features.promobanners.impl.analytics.PromoBannerAnalyticsEvent @@ -13,11 +13,13 @@ import com.tangem.features.promobanners.impl.converters.PromoBannerDisplayToNoti import com.tangem.features.promobanners.impl.repository.PromoBannersRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.runSuspendCatching -import kotlinx.collections.immutable.persistentListOf import com.tangem.utils.logging.TangemLogger +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Semaphore +import kotlinx.coroutines.sync.withPermit import java.util.Locale import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject @@ -39,20 +41,58 @@ internal class PromoBannersBlockModel @Inject constructor( private val placeholderName: String = params.placeholder.value private val shownBannerIds: MutableSet = ConcurrentHashMap.newKeySet() - private var isVisibleOnScreen: Boolean = params.isInitiallyVisibleOnScreen private var wasCarouselScrolled = false private val savedDisplayIdByWalletId: MutableMap = mutableMapOf() + private val prefetchedWalletIds: MutableSet = ConcurrentHashMap.newKeySet() + private val prefetchSemaphore = Semaphore(permits = PREFETCH_PARALLELISM) - val uiState: StateFlow - field = MutableStateFlow(getInitialState()) + /** Raw banners per wallet, filled from cache/prefetch/network. Source of truth for the UI. */ + private val rawBannersByWalletId = MutableStateFlow>>(emptyMap()) + + private val selectedWalletId = MutableStateFlow(null) + + private val screenVisible = MutableStateFlow(params.isInitiallyVisibleOnScreen) + + private val baseBannerStates: StateFlow> = + rawBannersByWalletId + .map { rawByWallet -> + rawByWallet.mapValues { (walletId, banners) -> buildState(walletId, banners, isVisible = false) } + } + .stateIn(modelScope, SharingStarted.Eagerly, emptyMap()) + + /** + * Per-wallet UI states, so a pager page can render its own wallet's banners synchronously from + * cache as it slides in — instead of the whole block waiting for the wallet selection to settle. + * Only cheaply toggles [PromoBannersBlockUM.isVisibleOnScreen] on selection/visibility change. + */ + val bannerStates: StateFlow> = + combine(baseBannerStates, selectedWalletId, screenVisible) { base, selected, visible -> + base.mapValues { (walletId, state) -> + // Only the active wallet is "visible on screen" for analytics purposes; pre-composed + // off-screen pager pages must not emit "banner shown" events. + val shouldBeVisible = visible && walletId == selected + if (state.isVisibleOnScreen == shouldBeVisible) { + state + } else { + state.copy( + isVisibleOnScreen = shouldBeVisible, + ) + } + } + }.stateIn(modelScope, SharingStarted.Eagerly, emptyMap()) + + val uiState: StateFlow = + combine(bannerStates, selectedWalletId) { states, selected -> + states[selected] ?: getInitialState() + }.stateIn(modelScope, SharingStarted.Eagerly, getInitialState()) init { subscribeOnSelectedWallet() + prefetchAllWallets() } fun setVisibleOnScreen(visible: Boolean) { - isVisibleOnScreen = visible - uiState.update { it.copy(isVisibleOnScreen = visible) } + screenVisible.value = visible } private fun subscribeOnSelectedWallet() { @@ -61,50 +101,97 @@ internal class PromoBannersBlockModel @Inject constructor( .filterNotNull() .map { it.walletId.stringValue } .distinctUntilChanged() - .onEach { + .collectLatest { walletId -> wasCarouselScrolled = false + selectedWalletId.value = walletId + loadWallet(walletId) } - .collectLatest { walletId -> loadBanners(walletId) } } } - private suspend fun loadBanners(walletId: String) { - val languageISOCode = Locale.getDefault().language + /** + * Warms the banners for every wallet in the background so switching to another wallet renders its + * banners instantly from cache instead of after a network gap. Each wallet is fetched at most once + * ([prefetchedWalletIds]); [PromoBannersRepository.getBanners] is a no-op once the wallet is cached. + */ + private fun prefetchAllWallets() { + modelScope.launch { + val languageISOCode = Locale.getDefault().language + userWalletsListRepository.userWallets + .filterNotNull() + .collect { wallets -> + wallets.forEach { wallet -> + val walletId = wallet.walletId.stringValue + if (prefetchedWalletIds.add(walletId)) { + modelScope.launch { + prefetchSemaphore.withPermit { + runSuspendCatching { + repository.getBanners(walletId, params.placeholder, languageISOCode) + }.onSuccess { putBanners(walletId, it) } + .onFailure { prefetchedWalletIds.remove(walletId) } + } + } + } + } + } + } + } + private suspend fun loadWallet(walletId: String) { + val cached = runSuspendCatching { repository.getCachedBanners(walletId, params.placeholder) }.getOrNull() + if (cached != null) { + putBanners(walletId, cached) + return + } + + putBanners(walletId, banners = emptyList()) runSuspendCatching { - repository.getBanners(walletId, params.placeholder, languageISOCode) + repository.getBanners(walletId, params.placeholder, Locale.getDefault().language) }.onSuccess { banners -> - val bannerUMs = banners.map { banner -> - converter.convert( - banner = banner, - onDeeplinkClick = { deeplink -> onButtonClick(banner.id, deeplink) }, - onDismiss = { displayId -> onBannerDismiss(walletId, displayId) }, - ) - }.toImmutableList() - - val savedDisplayId = savedDisplayIdByWalletId[walletId] - val initialPage = if (savedDisplayId != null) { - bannerUMs.indexOfFirst { it.displayId == savedDisplayId }.coerceAtLeast(0) - } else { - 0 - } - - uiState.value = PromoBannersBlockUM( - userWalletId = walletId, - initialPage = initialPage, - banners = bannerUMs, - isVisibleOnScreen = isVisibleOnScreen, - placeholder = params.placeholder, - onBannerShown = { displayId -> onBannerShown(walletId, displayId) }, - onCarouselScrolled = ::onCarouselScrolled, - onPageChanged = { displayId -> savedDisplayIdByWalletId[walletId] = displayId }, - ) + putBanners(walletId, banners) }.onFailure { error -> TangemLogger.w("Failed to load promo banners", error) } } + private fun putBanners(walletId: String, banners: List) { + rawBannersByWalletId.update { it + (walletId to banners) } + } + + private fun buildState( + walletId: String, + banners: List, + isVisible: Boolean, + ): PromoBannersBlockUM { + val bannerUMs = banners.map { banner -> + converter.convert( + banner = banner, + onDeeplinkClick = { deeplink -> onButtonClick(banner.id, deeplink) }, + onDismiss = { displayId -> onBannerDismiss(walletId, displayId) }, + ) + }.toImmutableList() + + val savedDisplayId = savedDisplayIdByWalletId[walletId] + val initialPage = if (savedDisplayId != null) { + bannerUMs.indexOfFirst { it.displayId == savedDisplayId }.coerceAtLeast(0) + } else { + 0 + } + + return PromoBannersBlockUM( + userWalletId = walletId, + initialPage = initialPage, + banners = bannerUMs, + isVisibleOnScreen = isVisible, + placeholder = params.placeholder, + onBannerShown = { displayId -> onBannerShown(walletId, displayId) }, + onCarouselScrolled = ::onCarouselScrolled, + onPageChanged = { displayId -> savedDisplayIdByWalletId[walletId] = displayId }, + ) + } + private fun onBannerShown(walletId: String, displayId: Int) { + if (walletId != selectedWalletId.value) return if (shownBannerIds.add(walletId to displayId)) { analyticsEventHandler.send(PromoBannerAnalyticsEvent.Shown(displayId, placeholderName)) } @@ -137,7 +224,7 @@ internal class PromoBannersBlockModel @Inject constructor( userWalletId = "", initialPage = 0, banners = persistentListOf(), - isVisibleOnScreen = isVisibleOnScreen, + isVisibleOnScreen = screenVisible.value, placeholder = params.placeholder, onBannerShown = {}, onCarouselScrolled = {}, @@ -146,12 +233,9 @@ internal class PromoBannersBlockModel @Inject constructor( private fun onBannerDismiss(walletId: String, displayId: Int) { analyticsEventHandler.send(PromoBannerAnalyticsEvent.Dismissed(displayId, placeholderName)) - uiState.update { state -> - state.copy( - banners = state.banners - .filterNot { it.displayId == displayId } - .toImmutableList(), - ) + rawBannersByWalletId.update { byWallet -> + val banners = byWallet[walletId] ?: return@update byWallet + byWallet + (walletId to banners.filterNot { it.id == displayId }) } modelScope.launch { runSuspendCatching { @@ -169,5 +253,6 @@ internal class PromoBannersBlockModel @Inject constructor( const val DEEPLINK_SCHEME_TANGEM = "tangem" const val DEEPLINK_HOST_SURVEY = "survey" const val QUERY_DISPLAY_ID = "display_id" + const val PREFETCH_PARALLELISM = 3 } } \ No newline at end of file diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt index 0ab8bf3ee9..0f5fc3d743 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt @@ -52,6 +52,10 @@ internal class DefaultPromoBannersRepository( return banners } + override suspend fun getCachedBanners(walletId: String, placeholder: Placeholder): List? { + return cache.getSyncOrNull()?.get(BannersCacheKey(walletId, placeholder)) + } + override suspend fun dismissBanner(walletId: String, displayId: Int) { cache.update(default = emptyMap()) { current -> current.mapValues { (key, banners) -> diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/PromoBannersRepository.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/PromoBannersRepository.kt index 0fd96683b7..b00cae5a85 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/PromoBannersRepository.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/PromoBannersRepository.kt @@ -11,5 +11,7 @@ internal interface PromoBannersRepository { languageISOCode: String, ): List + suspend fun getCachedBanners(walletId: String, placeholder: Placeholder): List? + suspend fun dismissBanner(walletId: String, displayId: Int) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt index f1a93abe4b..730448af16 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt @@ -25,7 +25,6 @@ import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.domain.tokens.model.details.TokenAction import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent -import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent import com.tangem.feature.wallet.child.tokenActions.DefaultTokenActionsComponent import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent import com.tangem.feature.wallet.child.wallet.model.WalletModel @@ -36,6 +35,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen2 import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.KycRejectedComponent import com.tangem.feature.walletsettings.component.RenameWalletComponent import com.tangem.features.biometry.AskBiometryComponent +import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent import com.tangem.features.feed.entry.components.FeedEntryComponent import com.tangem.features.promobanners.api.PromoBannersBlockComponent @@ -295,14 +295,10 @@ internal class WalletComponent @AssistedInject constructor( var headerSize by remember { mutableStateOf(0.dp) } val dialog by dialog.subscribeAsState() val uiState by model.uiState.collectAsStateWithLifecycle() - val promoBannersBlockComponentContentComponent = ComposableContentComponent { promoModifier -> - promoBannersBlockComponent.ContentWithPadding(modifier = promoModifier, horizontalItemPadding = 12.dp) - } - if (designFeatureToggles.isRedesignEnabled) { WalletScreen2( state = uiState, - promoBannersBlockComponent = promoBannersBlockComponentContentComponent, + promoBannersBlockComponent = promoBannersBlockComponent, tangemPayComponent = tangemPayMainBlockComponent, virtualAccountComponent = virtualAccountMainBlockComponent, bottomSheetContent = { onExpandSheet -> @@ -319,7 +315,7 @@ internal class WalletComponent @AssistedInject constructor( } else { WalletScreen( state = uiState, - promoBannersBlockComponent = promoBannersBlockComponentContentComponent, + promoBannersBlockComponent = promoBannersBlockComponent, tangemPayComponent = tangemPayMainBlockComponent, virtualAccountComponent = virtualAccountMainBlockComponent, bottomSheetContent = { onExpandSheet -> diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index 3b467d4542..92b74ed718 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -59,7 +59,6 @@ import com.tangem.core.ui.components.sheetscaffold.* import com.tangem.core.ui.components.snackbar.CopiedTextSnackbar import com.tangem.core.ui.components.snackbar.TangemSnackbar import com.tangem.core.ui.components.transactions.state.TxHistoryState -import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.event.StateEvent import com.tangem.core.ui.extensions.softLayerShadow import com.tangem.core.ui.extensions.stringResourceSafe @@ -83,6 +82,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency 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.utils.changeWalletAnimator +import com.tangem.features.promobanners.api.PromoBannersBlockComponent import com.tangem.features.tangempay.component.TangemPayMainBlockComponent import com.tangem.features.tangempay.entity.TangemPayMainUM import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent @@ -98,7 +98,7 @@ internal fun WalletScreen( state: WalletScreenState, tangemPayComponent: TangemPayMainBlockComponent, virtualAccountComponent: VirtualAccountMainBlockComponent, - promoBannersBlockComponent: ComposableContentComponent? = null, + promoBannersBlockComponent: PromoBannersBlockComponent? = null, bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit, bottomSheetHeaderHeightProvider: () -> Dp, onBottomSheetStateChange: (BottomSheetState) -> Unit, @@ -142,7 +142,7 @@ private fun WalletContent( snackbarHostState: SnackbarHostState, isAutoScroll: State, onAutoScrollReset: () -> Unit, - promoBannersBlockComponent: ComposableContentComponent? = null, + promoBannersBlockComponent: PromoBannersBlockComponent? = null, bottomSheetHeaderHeightProvider: () -> Dp, onBottomSheetStateChange: (BottomSheetState) -> Unit, bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit, @@ -226,7 +226,11 @@ private fun WalletContent( promoBannersBlockComponent?.let { component -> item(key = "PromoBannersBlock") { - component.Content(modifier = itemModifier) + component.ContentWithPadding( + horizontalItemPadding = 12.dp, + modifier = itemModifier, + walletId = null, + ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt index 8c4b1cfede..7e40f611a4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt @@ -55,7 +55,6 @@ import com.tangem.core.ui.components.haze.hazeEffectTangem import com.tangem.core.ui.components.haze.hazeSourceTangem import com.tangem.core.ui.components.rememberIsKeyboardVisible import com.tangem.core.ui.components.sheetscaffold.* -import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingTopBar import com.tangem.core.ui.ds.topbar.collapsing.rememberTangemExitUntilCollapsedScrollBehavior @@ -74,12 +73,15 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.common.Wallet import com.tangem.feature.wallet.presentation.wallet.ui.components.common.WalletPagerIndicator import com.tangem.feature.wallet.presentation.wallet.ui.components.common.WalletTopBar import com.tangem.feature.wallet.presentation.wallet.ui.utils.lazyListStateMapSaver +import com.tangem.features.promobanners.api.PromoBannersBlockComponent import com.tangem.features.tangempay.component.TangemPayMainBlockComponent import com.tangem.features.tangempay.entity.TangemPayMainUM import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent import com.tangem.features.virtualaccount.main.entity.VirtualAccountMainUM import dev.chrisbanes.haze.HazeProgressive import dev.chrisbanes.haze.HazeTint +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.drop import kotlinx.coroutines.launch @@ -95,7 +97,7 @@ internal fun WalletScreen2( tangemPayComponent: TangemPayMainBlockComponent, virtualAccountComponent: VirtualAccountMainBlockComponent, modifier: Modifier = Modifier, - promoBannersBlockComponent: ComposableContentComponent? = null, + promoBannersBlockComponent: PromoBannersBlockComponent? = null, bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit, bottomSheetHeaderHeightProvider: () -> Dp, onBottomSheetStateChange: (BottomSheetState) -> Unit, @@ -147,7 +149,7 @@ internal fun WalletScreen2( bottomSheetHeaderHeightProvider = bottomSheetHeaderHeightProvider, onBottomSheetStateChange = onBottomSheetStateChange, modifier = modifier, - listStates = listStates, + listStates = remember(listStates) { listStates.toImmutableMap() }, ) WalletEventEffect( @@ -171,9 +173,9 @@ private fun WalletContent2( tangemPayComponent: TangemPayMainBlockComponent, virtualAccountComponent: VirtualAccountMainBlockComponent, behavior: TangemCollapsingAppBarBehavior, - listStates: Map, + listStates: ImmutableMap, modifier: Modifier = Modifier, - promoBannersBlockComponent: ComposableContentComponent? = null, + promoBannersBlockComponent: PromoBannersBlockComponent? = null, bottomSheetHeaderHeightProvider: () -> Dp, onBottomSheetStateChange: (BottomSheetState) -> Unit, bottomSheetContent: @Composable (onExpandSheet: () -> Unit) -> Unit, @@ -282,6 +284,7 @@ private fun WalletContent2( val currentWallet = state.wallets2.getOrElse(currentWalletIndex) { state.wallets2[state.selectedWalletIndex] } + val currentWalletId = currentWallet.walletsBalanceUM.id.stringValue LaunchedEffect(walletsPagerState.currentPage, currentWallet.walletsBalanceUM) { if (walletsPagerState.currentPage == currentWalletIndex) { @@ -350,6 +353,7 @@ private fun WalletContent2( contentPadding = contentPadding, tangemPayComponent = tangemPayComponent, promoBannersBlockComponent = promoBannersBlockComponent, + walletId = currentWalletId, virtualAccountComponent = virtualAccountComponent, modifier = Modifier .fillMaxSize() diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletContent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletContent.kt index 844acea245..4489e87a40 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletContent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletContent.kt @@ -10,12 +10,12 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag +import androidx.compose.ui.unit.dp import androidx.paging.compose.LazyPagingItems import com.tangem.common.ui.notifications.notifications import com.tangem.common.ui.notifications.notificationsCarousel import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.components.transactions.txHistoryItems -import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.test.MainScreenTestTags import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState @@ -26,6 +26,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.nftCollection import com.tangem.feature.wallet.presentation.wallet.ui.components.organizeTokens2 import com.tangem.feature.wallet.presentation.wallet.ui.components.tangemPay import com.tangem.feature.wallet.presentation.wallet.ui.components.virtualAccount +import com.tangem.features.promobanners.api.PromoBannersBlockComponent import com.tangem.features.tangempay.component.TangemPayMainBlockComponent import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent import kotlinx.collections.immutable.toPersistentList @@ -40,7 +41,8 @@ internal fun WalletListContent( virtualAccountComponent: VirtualAccountMainBlockComponent, contentPadding: PaddingValues, modifier: Modifier = Modifier, - promoBannersBlockComponent: ComposableContentComponent? = null, + promoBannersBlockComponent: PromoBannersBlockComponent? = null, + walletId: String? = null, ) { val containerColor = TangemTheme.colors2.surface.level1 @@ -67,7 +69,11 @@ internal fun WalletListContent( promoBannersBlockComponent?.let { component -> item(key = "PromoBannersBlock") { - component.Content(modifier = Modifier.padding(top = TangemTheme.dimens2.x3)) + component.ContentWithPadding( + horizontalItemPadding = 12.dp, + modifier = Modifier.padding(top = TangemTheme.dimens2.x3), + walletId = walletId, + ) } }