Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-15 13:13:09 +03:00
parent 7db3810064
commit b208c0dd7c
7 changed files with 258 additions and 55 deletions

View file

@ -30,6 +30,7 @@ dependencies {
/** Compose */
implementation(deps.compose.foundation)
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.lifecycle.compose)
/** Other */

View file

@ -1,7 +1,9 @@
package com.tangem.features.promobanners.impl.ui
import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
@ -13,14 +15,23 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
import com.tangem.core.ui.components.SpacerH8
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.components.pager.PagerIndicator
import com.tangem.core.ui.ds.message.TangemMessage
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.features.promobanners.api.PromoBannersBlockComponent.Placeholder
import com.tangem.features.promobanners.impl.model.PromoBannerNotificationUM
import com.tangem.features.promobanners.impl.model.PromoBannersBlockUM
import kotlinx.collections.immutable.persistentListOf
import kotlin.math.ceil
import kotlin.math.floor
@ -54,17 +65,46 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier =
}
@Composable
private fun bannerContainerColor(placeholder: Placeholder): Color = when (placeholder) {
Placeholder.MAIN -> TangemTheme.colors.background.primary
Placeholder.FEED -> TangemTheme.colors.background.action
private fun bannerContainerColor(placeholder: Placeholder): Color = if (LocalRedesignEnabled.current) {
when (placeholder) {
Placeholder.MAIN -> TangemTheme.colors2.surface.level1
Placeholder.FEED -> TangemTheme.colors2.surface.level3
}
} else {
when (placeholder) {
Placeholder.MAIN -> TangemTheme.colors.background.primary
Placeholder.FEED -> TangemTheme.colors.background.action
}
}
/**
* Renders a banner either with the redesigned [TangemMessage] component or the legacy [Notification],
* depending on [LocalRedesignEnabled]. Both accept the same [NotificationConfig], so the banner model
* and converters stay untouched.
*/
@Composable
private fun BannerNotification(config: NotificationConfig, containerColor: Color, modifier: Modifier = Modifier) {
if (LocalRedesignEnabled.current) {
TangemMessage(
config = config,
modifier = modifier.fillMaxWidth(),
contentColor = containerColor,
)
} else {
Notification(
config = config,
modifier = modifier.fillMaxWidth(),
containerColor = containerColor,
)
}
}
@Composable
private fun SingleBanner(banner: PromoBannerNotificationUM, containerColor: Color, modifier: Modifier = Modifier) {
Notification(
BannerNotification(
config = banner.config,
modifier = modifier.fillMaxWidth(),
containerColor = containerColor,
modifier = modifier,
)
}
@ -139,18 +179,16 @@ private fun SmoothHeightPager(
val fraction = scrollPosition - floor(scrollPosition)
val lowerHeight = subcompose(slotId = "measure_lower") {
Notification(
BannerNotification(
config = banners[lowerPage].config,
modifier = Modifier.fillMaxWidth(),
containerColor = containerColor,
)
}.first().measure(pageConstraints).height
val upperHeight = if (upperPage != lowerPage) {
subcompose(slotId = "measure_upper") {
Notification(
BannerNotification(
config = banners[upperPage].config,
modifier = Modifier.fillMaxWidth(),
containerColor = containerColor,
)
}.first().measure(pageConstraints).height
@ -167,9 +205,8 @@ private fun SmoothHeightPager(
pageSpacing = TangemTheme.dimens.spacing16,
) { page ->
val banner = banners.getOrNull(page) ?: return@HorizontalPager
Notification(
BannerNotification(
config = banner.config,
modifier = Modifier.fillMaxWidth(),
containerColor = containerColor,
)
}
@ -181,4 +218,51 @@ private fun SmoothHeightPager(
pagerPlaceable.place(0, 0)
}
}
}
}
// region Preview
private fun previewState(bannerCount: Int) = PromoBannersBlockUM(
userWalletId = "preview",
initialPage = 0,
banners = persistentListOf(
*Array(bannerCount) { index ->
PromoBannerNotificationUM(
displayId = index,
config = NotificationConfig(
title = stringReference("Earn up to 14% APY"),
subtitle = stringReference("Staking is the easiest way to earn rewards on your crypto."),
iconResId = com.tangem.core.ui.R.drawable.ic_alert_circle_24,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = stringReference("Start earning"),
onClick = {},
),
onCloseClick = {},
),
)
},
),
isVisibleOnScreen = false,
placeholder = Placeholder.MAIN,
onBannerShown = {},
onCarouselScrolled = {},
onPageChanged = {},
)
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun Preview_PromoBannersBlock_Legacy() {
TangemThemePreview {
PromoBannersBlock(state = previewState(bannerCount = 2), modifier = Modifier.padding(16.dp))
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun Preview_PromoBannersBlock_Redesign() {
TangemThemePreviewRedesign {
PromoBannersBlock(state = previewState(bannerCount = 2), modifier = Modifier.padding(16.dp))
}
}
// endregion