Updated on 2026-08-14
This commit is contained in:
parent
17add53bc0
commit
304e6d0c5c
6 changed files with 41 additions and 27 deletions
|
|
@ -5,8 +5,11 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
|
|||
|
||||
interface PromoBannersBlockComponent : ComposableContentComponent {
|
||||
|
||||
fun setVisibleOnScreen(isVisible: Boolean)
|
||||
|
||||
data class Params(
|
||||
val placeholder: Placeholder,
|
||||
val isInitiallyVisibleOnScreen: Boolean = true,
|
||||
)
|
||||
|
||||
enum class Placeholder {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ internal class DefaultPromoBannersBlockComponent @AssistedInject constructor(
|
|||
|
||||
private val model: PromoBannersBlockModel = getOrCreateModel(params)
|
||||
|
||||
override fun setVisibleOnScreen(isVisible: Boolean) {
|
||||
model.setVisibleOnScreen(isVisible)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ internal class PromoBannersBlockModel @Inject constructor(
|
|||
|
||||
private val placeholder: String = params.placeholder.name.lowercase()
|
||||
private val shownBannerIds: MutableSet<Int> = ConcurrentHashMap.newKeySet()
|
||||
private var isVisibleOnScreen: Boolean = params.isInitiallyVisibleOnScreen
|
||||
private var wasCarouselScrolled = false
|
||||
private val savedDisplayIdByWalletId: MutableMap<String, Int> = mutableMapOf()
|
||||
|
||||
|
|
@ -46,6 +47,11 @@ internal class PromoBannersBlockModel @Inject constructor(
|
|||
subscribeOnSelectedWallet()
|
||||
}
|
||||
|
||||
fun setVisibleOnScreen(visible: Boolean) {
|
||||
isVisibleOnScreen = visible
|
||||
uiState.update { it.copy(isVisibleOnScreen = visible) }
|
||||
}
|
||||
|
||||
private fun subscribeOnSelectedWallet() {
|
||||
modelScope.launch {
|
||||
userWalletsListRepository.selectedUserWallet
|
||||
|
|
@ -53,7 +59,6 @@ internal class PromoBannersBlockModel @Inject constructor(
|
|||
.map { it.walletId.stringValue }
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
shownBannerIds.clear()
|
||||
wasCarouselScrolled = false
|
||||
}
|
||||
.collectLatest { walletId -> loadBanners(walletId) }
|
||||
|
|
@ -85,6 +90,7 @@ internal class PromoBannersBlockModel @Inject constructor(
|
|||
userWalletId = walletId,
|
||||
initialPage = initialPage,
|
||||
banners = bannerUMs,
|
||||
isVisibleOnScreen = isVisibleOnScreen,
|
||||
onBannerShown = ::onBannerShown,
|
||||
onCarouselScrolled = ::onCarouselScrolled,
|
||||
onPageChanged = { displayId -> savedDisplayIdByWalletId[walletId] = displayId },
|
||||
|
|
@ -116,6 +122,7 @@ internal class PromoBannersBlockModel @Inject constructor(
|
|||
userWalletId = "",
|
||||
initialPage = 0,
|
||||
banners = persistentListOf(),
|
||||
isVisibleOnScreen = isVisibleOnScreen,
|
||||
onBannerShown = {},
|
||||
onCarouselScrolled = {},
|
||||
onPageChanged = {},
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ internal data class PromoBannersBlockUM(
|
|||
val userWalletId: String,
|
||||
val initialPage: Int,
|
||||
val banners: ImmutableList<PromoBannerNotificationUM>,
|
||||
val isVisibleOnScreen: Boolean,
|
||||
val onBannerShown: (displayId: Int) -> Unit,
|
||||
val onCarouselScrolled: (displayId: Int) -> Unit,
|
||||
val onPageChanged: (displayId: Int) -> Unit,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier =
|
|||
|
||||
if (state.banners.size == 1) {
|
||||
val banner = state.banners.first()
|
||||
LaunchedEffect(banner.displayId) {
|
||||
state.onBannerShown(banner.displayId)
|
||||
LaunchedEffect(banner.displayId, state.isVisibleOnScreen) {
|
||||
if (state.isVisibleOnScreen) {
|
||||
state.onBannerShown(banner.displayId)
|
||||
}
|
||||
}
|
||||
SingleBanner(
|
||||
banner = banner,
|
||||
|
|
@ -38,11 +40,7 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier =
|
|||
} else {
|
||||
key(state.userWalletId) {
|
||||
BannersCarousel(
|
||||
banners = state.banners,
|
||||
initialPage = state.initialPage,
|
||||
onBannerShown = state.onBannerShown,
|
||||
onCarouselScroll = state.onCarouselScrolled,
|
||||
onPageChange = state.onPageChanged,
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -59,31 +57,25 @@ private fun SingleBanner(banner: PromoBannerNotificationUM, modifier: Modifier =
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun BannersCarousel(
|
||||
banners: List<PromoBannerNotificationUM>,
|
||||
initialPage: Int,
|
||||
onBannerShown: (Int) -> Unit,
|
||||
onCarouselScroll: (Int) -> Unit,
|
||||
onPageChange: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun BannersCarousel(state: PromoBannersBlockUM, modifier: Modifier = Modifier) {
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = initialPage,
|
||||
pageCount = { banners.size },
|
||||
initialPage = state.initialPage,
|
||||
pageCount = { state.banners.size },
|
||||
)
|
||||
|
||||
LaunchedEffect(pagerState, banners) {
|
||||
LaunchedEffect(pagerState, state.banners, state.isVisibleOnScreen) {
|
||||
if (!state.isVisibleOnScreen) return@LaunchedEffect
|
||||
var previousPage = pagerState.currentPage
|
||||
snapshotFlow { pagerState.currentPage }
|
||||
.collect { page ->
|
||||
banners.getOrNull(page)?.let { banner ->
|
||||
onPageChange(banner.displayId)
|
||||
onBannerShown(banner.displayId)
|
||||
if (page == 1) {
|
||||
// one-time event when user scrolls from first to second page,
|
||||
// indicating that he has interacted with the carousel
|
||||
onCarouselScroll(banner.displayId)
|
||||
state.banners.getOrNull(page)?.let { banner ->
|
||||
state.onPageChanged(banner.displayId)
|
||||
state.onBannerShown(banner.displayId)
|
||||
if (previousPage == 0 && page == 1) {
|
||||
state.onCarouselScrolled(banner.displayId)
|
||||
}
|
||||
}
|
||||
previousPage = page
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +84,7 @@ private fun BannersCarousel(
|
|||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
SmoothHeightPager(
|
||||
banners = banners,
|
||||
banners = state.banners,
|
||||
pagerState = pagerState,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue