Updated on 2026-08-14
This commit is contained in:
parent
e354f12cf5
commit
febb2bda4c
10 changed files with 186 additions and 67 deletions
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<ShownBannerKey> = ConcurrentHashMap.newKeySet()
|
||||
private var isVisibleOnScreen: Boolean = params.isInitiallyVisibleOnScreen
|
||||
private var wasCarouselScrolled = false
|
||||
private val savedDisplayIdByWalletId: MutableMap<String, Int> = mutableMapOf()
|
||||
private val prefetchedWalletIds: MutableSet<String> = ConcurrentHashMap.newKeySet()
|
||||
private val prefetchSemaphore = Semaphore(permits = PREFETCH_PARALLELISM)
|
||||
|
||||
val uiState: StateFlow<PromoBannersBlockUM>
|
||||
field = MutableStateFlow(getInitialState())
|
||||
/** Raw banners per wallet, filled from cache/prefetch/network. Source of truth for the UI. */
|
||||
private val rawBannersByWalletId = MutableStateFlow<Map<String, List<PromoBannerDisplay>>>(emptyMap())
|
||||
|
||||
private val selectedWalletId = MutableStateFlow<String?>(null)
|
||||
|
||||
private val screenVisible = MutableStateFlow(params.isInitiallyVisibleOnScreen)
|
||||
|
||||
private val baseBannerStates: StateFlow<Map<String, PromoBannersBlockUM>> =
|
||||
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<Map<String, PromoBannersBlockUM>> =
|
||||
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<PromoBannersBlockUM> =
|
||||
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,19 +101,68 @@ 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) {
|
||||
/**
|
||||
* 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, Locale.getDefault().language)
|
||||
}.onSuccess { banners ->
|
||||
putBanners(walletId, banners)
|
||||
}.onFailure { error ->
|
||||
TangemLogger.w("Failed to load promo banners", error)
|
||||
}
|
||||
}
|
||||
|
||||
private fun putBanners(walletId: String, banners: List<PromoBannerDisplay>) {
|
||||
rawBannersByWalletId.update { it + (walletId to banners) }
|
||||
}
|
||||
|
||||
private fun buildState(
|
||||
walletId: String,
|
||||
banners: List<PromoBannerDisplay>,
|
||||
isVisible: Boolean,
|
||||
): PromoBannersBlockUM {
|
||||
val bannerUMs = banners.map { banner ->
|
||||
converter.convert(
|
||||
banner = banner,
|
||||
|
|
@ -89,22 +178,20 @@ internal class PromoBannersBlockModel @Inject constructor(
|
|||
0
|
||||
}
|
||||
|
||||
uiState.value = PromoBannersBlockUM(
|
||||
return PromoBannersBlockUM(
|
||||
userWalletId = walletId,
|
||||
initialPage = initialPage,
|
||||
banners = bannerUMs,
|
||||
isVisibleOnScreen = isVisibleOnScreen,
|
||||
isVisibleOnScreen = isVisible,
|
||||
placeholder = params.placeholder,
|
||||
onBannerShown = { displayId -> onBannerShown(walletId, displayId) },
|
||||
onCarouselScrolled = ::onCarouselScrolled,
|
||||
onPageChanged = { displayId -> savedDisplayIdByWalletId[walletId] = displayId },
|
||||
)
|
||||
}.onFailure { error ->
|
||||
TangemLogger.w("Failed to load promo banners", error)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,10 @@ internal class DefaultPromoBannersRepository(
|
|||
return banners
|
||||
}
|
||||
|
||||
override suspend fun getCachedBanners(walletId: String, placeholder: Placeholder): List<PromoBannerDisplay>? {
|
||||
return cache.getSyncOrNull()?.get(BannersCacheKey(walletId, placeholder))
|
||||
}
|
||||
|
||||
override suspend fun dismissBanner(walletId: String, displayId: Int) {
|
||||
cache.update(default = emptyMap()) { current ->
|
||||
current.mapValues { (key, banners) ->
|
||||
|
|
|
|||
|
|
@ -11,5 +11,7 @@ internal interface PromoBannersRepository {
|
|||
languageISOCode: String,
|
||||
): List<PromoBannerDisplay>
|
||||
|
||||
suspend fun getCachedBanners(walletId: String, placeholder: Placeholder): List<PromoBannerDisplay>?
|
||||
|
||||
suspend fun dismissBanner(walletId: String, displayId: Int)
|
||||
}
|
||||
|
|
@ -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 ->
|
||||
|
|
|
|||
|
|
@ -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<Boolean>,
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Int, LazyListState>,
|
||||
listStates: ImmutableMap<Int, LazyListState>,
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue