Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-27 12:17:53 +03:00
parent 2604f4c41b
commit e9afc268d3
6 changed files with 476 additions and 0 deletions

View file

@ -7,6 +7,7 @@ import com.tangem.core.ui.ds.message.TangemMessageEffect
import com.tangem.core.ui.ds.topbar.TangemTopBarType
import com.tangem.core.ui.ds2.badge.TangemBadge
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.ds2.fade.TangemFade
import com.tangem.core.ui.ds2.loader.TangemLoaderSize
import com.tangem.core.ui.ds2.shimmers.TextShimmerStyle
@ -176,6 +177,15 @@ internal data class TangemButtonStory(
}
}
internal data class TangemFadeStory(
val variant: TangemFade.Variant,
val position: TangemFade.Position,
val isBlur: Boolean,
val onVariantChange: (TangemFade.Variant) -> Unit,
val onPositionChange: (TangemFade.Position) -> Unit,
val onBlurToggle: () -> Unit,
) : DsStoryBookPage
internal data class TangemBadgeV2Story(
val variant: TangemBadge.Variant,
val status: TangemBadge.Status,

View file

@ -17,6 +17,7 @@ import com.tangem.feature.tester.presentation.storybook.entity.DsComponentsListS
import com.tangem.feature.tester.presentation.storybook.entity.StoryPageFactory
import com.tangem.feature.tester.presentation.storybook.page.ds.badge.tangemBadgeV2StoryFactory
import com.tangem.feature.tester.presentation.storybook.page.ds.button.tangemButtonStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.ds.fade.tangemFadeStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.ds.loader.tangemLoaderStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.ds.shimmer.tangemShimmerStoryFactory
@ -27,6 +28,7 @@ private fun buildDsStories() = listOf(
DsStoryItem(title = "🔘 TangemButton", factory = tangemButtonStoryFactory),
DsStoryItem(title = "🏷️ TangemBadge", factory = tangemBadgeV2StoryFactory),
DsStoryItem(title = "✨ TangemShimmer", factory = tangemShimmerStoryFactory),
DsStoryItem(title = "🌫️ TangemFade", factory = tangemFadeStoryFactory),
)
@Composable

View file

@ -0,0 +1,26 @@
package com.tangem.feature.tester.presentation.storybook.page.ds.fade
import com.tangem.core.ui.ds2.fade.TangemFade
import com.tangem.feature.tester.presentation.storybook.entity.TangemFadeStory
import com.tangem.feature.tester.presentation.storybook.viewmodel.StateUpdater
import com.tangem.feature.tester.presentation.storybook.viewmodel.storyPageFactory
internal fun StateUpdater<TangemFadeStory>.build(): TangemFadeStory {
return TangemFadeStory(
variant = TangemFade.Variant.Hard,
position = TangemFade.Position.Top,
isBlur = false,
onVariantChange = { variant ->
updateStory { it.copy(variant = variant) }
},
onPositionChange = { position ->
updateStory { it.copy(position = position) }
},
onBlurToggle = {
updateStory { it.copy(isBlur = !it.isBlur) }
},
)
}
internal val tangemFadeStoryFactory
get() = storyPageFactory(StateUpdater<TangemFadeStory>::build)

View file

@ -0,0 +1,245 @@
@file:Suppress("MagicNumber")
package com.tangem.feature.tester.presentation.storybook.page.ds.fade
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.haze.hazeSourceTangem
import com.tangem.core.ui.ds2.fade.TangemFade
import com.tangem.core.ui.res.LocalHazeState
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.tester.presentation.storybook.entity.TangemFadeStory
@Composable
internal fun TangemFadeStory(state: TangemFadeStory, modifier: Modifier = Modifier) {
val hazeState = LocalHazeState.current
DisposableEffect(state.isBlur) {
val wasBlurEnabled = hazeState.blurEnabled
hazeState.blurEnabled = state.isBlur
onDispose { hazeState.blurEnabled = wasBlurEnabled }
}
Column(
modifier = modifier
.fillMaxSize()
.background(TangemTheme.colors.background.primary)
.padding(vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
ComponentPreview(state = state)
VariantSelector(selected = state.variant, onSelect = state.onVariantChange)
PositionSelector(selected = state.position, onSelect = state.onPositionChange)
Toggles(state = state)
}
}
@Composable
private fun ComponentPreview(state: TangemFadeStory) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.height(240.dp)
.clip(RoundedCornerShape(16.dp)),
) {
Backdrop(
modifier = Modifier
.fillMaxSize()
.hazeSourceTangem(zIndex = 0f),
)
TangemFade(
position = state.position,
variant = state.variant,
blur = state.isBlur,
modifier = Modifier.align(
when (state.position) {
TangemFade.Position.Top -> Alignment.TopCenter
TangemFade.Position.Bottom -> Alignment.BottomCenter
},
),
)
}
}
@Composable
private fun Backdrop(modifier: Modifier = Modifier) {
val bands = remember {
listOf(
Color(0xFFFF1744),
Color(0xFFFF9100),
Color(0xFFFFEA00),
Color(0xFF00E676),
Color(0xFF00B8D4),
Color(0xFF2962FF),
Color(0xFFD500F9),
)
}
val stops = remember(bands) {
buildList {
bands.forEachIndexed { index, color ->
val start = index.toFloat() / bands.size
val end = (index + 1).toFloat() / bands.size
add(start to color)
add(end to color)
}
}.toTypedArray()
}
val tilePx = with(LocalDensity.current) { 160.dp.toPx() }
Box(
modifier = modifier.background(
brush = Brush.linearGradient(
colorStops = stops,
start = Offset(0f, 0f),
end = Offset(tilePx, tilePx),
tileMode = TileMode.Repeated,
),
),
)
}
@Composable
private fun VariantSelector(selected: TangemFade.Variant, onSelect: (TangemFade.Variant) -> Unit) {
Section(label = "Variant") {
ChipGrid(
items = TangemFade.Variant.entries,
label = { it.name },
isSelected = { it == selected },
onSelect = onSelect,
)
}
}
@Composable
private fun PositionSelector(selected: TangemFade.Position, onSelect: (TangemFade.Position) -> Unit) {
Section(label = "Position") {
ChipGrid(
items = TangemFade.Position.entries,
label = { it.name },
isSelected = { it == selected },
onSelect = onSelect,
)
}
}
@Composable
private fun Toggles(state: TangemFadeStory) {
Section(label = "Flags") {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
ToggleRow(label = "blur", checked = state.isBlur, onToggle = state.onBlurToggle)
}
}
}
@Composable
private fun Section(label: String, content: @Composable () -> Unit) {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text(
modifier = Modifier.padding(horizontal = 16.dp),
text = label,
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
)
content()
}
}
@Composable
private fun <T> ChipGrid(items: List<T>, label: (T) -> String, isSelected: (T) -> Boolean, onSelect: (T) -> Unit) {
val shape = RoundedCornerShape(50)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.clip(shape)
.background(TangemTheme.colors2.surface.level2)
.border(
width = 1.dp,
color = TangemTheme.colors2.border.neutral.secondary,
shape = shape,
)
.padding(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
items.forEach { item ->
Chip(
label = label(item),
selected = isSelected(item),
onClick = { onSelect(item) },
modifier = Modifier.weight(1f),
)
}
}
}
@Composable
private fun Chip(label: String, selected: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
val chipShape = RoundedCornerShape(50)
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.clip(chipShape)
.background(
if (selected) TangemTheme.colors2.surface.level3 else TangemTheme.colors2.surface.level2,
)
.clickable(onClick = onClick)
.padding(vertical = 8.dp, horizontal = 4.dp),
) {
Text(
text = label,
style = TangemTheme.typography.caption2,
color = if (selected) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.secondary,
)
}
}
@Composable
private fun ToggleRow(label: String, checked: Boolean, onToggle: () -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(12.dp))
.background(TangemTheme.colors2.surface.level2)
.clickable(onClick = onToggle)
.padding(horizontal = 12.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = label,
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
Text(
text = if (checked) "ON" else "OFF",
style = TangemTheme.typography.caption2,
color = if (checked) TangemTheme.colors.text.accent else TangemTheme.colors.text.secondary,
)
}
}

View file

@ -4,6 +4,31 @@ import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.feature.tester.presentation.storybook.entity.ButtonsStory
import com.tangem.feature.tester.presentation.storybook.entity.DeviceIconStory
import com.tangem.feature.tester.presentation.storybook.entity.DsComponentsListStory
import com.tangem.feature.tester.presentation.storybook.entity.NorthernLightsStory
import com.tangem.feature.tester.presentation.storybook.entity.OpportunitiesBGStory
import com.tangem.feature.tester.presentation.storybook.entity.PlaceholderStory
import com.tangem.feature.tester.presentation.storybook.entity.ProgressIndicatorStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemBadgeStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemBadgeV2Story
import com.tangem.feature.tester.presentation.storybook.entity.TangemButtonStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemFadeStory
import com.tangem.feature.tester.presentation.storybook.entity.StoryBookUM
import com.tangem.feature.tester.presentation.storybook.entity.StoryList
import com.tangem.feature.tester.presentation.storybook.entity.TangemCheckboxStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemHeaderRowStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemLoaderStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemContextMenuStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemMessageStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemPagerIndicatorStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemSearchFieldStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemSegmentedPickerStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemTabStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemTokenRowStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemTopBarStory
import com.tangem.feature.tester.presentation.storybook.entity.TypographyStory
import com.tangem.feature.tester.presentation.storybook.entity.*
import com.tangem.feature.tester.presentation.storybook.page.background.NorthernLightsStory
import com.tangem.feature.tester.presentation.storybook.page.badge.TangemBadgeStory
@ -14,6 +39,7 @@ import com.tangem.feature.tester.presentation.storybook.page.deviceicon.DeviceIc
import com.tangem.feature.tester.presentation.storybook.page.ds.DsComponentsListStory
import com.tangem.feature.tester.presentation.storybook.page.ds.badge.TangemBadgeV2Story
import com.tangem.feature.tester.presentation.storybook.page.ds.button.TangemButtonStory
import com.tangem.feature.tester.presentation.storybook.page.ds.fade.TangemFadeStory
import com.tangem.feature.tester.presentation.storybook.page.ds.loader.TangemLoaderStory
import com.tangem.feature.tester.presentation.storybook.page.ds.shimmer.TangemShimmerStory
import com.tangem.feature.tester.presentation.storybook.page.headerrow.TangemHeaderRowStory
@ -64,6 +90,7 @@ internal fun StoryBookScreen(state: StoryBookUM, modifier: Modifier = Modifier)
is TangemButtonStory -> TangemButtonStory(state = storyState)
is TangemBadgeV2Story -> TangemBadgeV2Story(state = storyState)
is TangemShimmerStory -> TangemShimmerStory(state = storyState)
is TangemFadeStory -> TangemFadeStory(state = storyState)
}
}
}