Updated on 2026-08-14
This commit is contained in:
parent
a9b5490cc4
commit
f58a422765
10 changed files with 888 additions and 6 deletions
|
|
@ -24,6 +24,20 @@ internal fun ProvideHaze(content: @Composable () -> Unit) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the haze blur effect would actually render for the given [state], taking both
|
||||
* the global [HazeState.blurEnabled] flag and the device's power-saving mode into account.
|
||||
*
|
||||
* Callers that pass a fully-transparent fallback to [hazeEffectTangem] should use this to decide
|
||||
* whether they need to render an opaque fallback layer themselves — otherwise the surface can
|
||||
* become invisible whenever blur is disabled (e.g. while power-saving mode is on).
|
||||
*/
|
||||
@Composable
|
||||
fun isHazeBlurEffectivelyEnabled(state: HazeState = LocalHazeState.current): Boolean {
|
||||
val isPowerSavingEnabled by LocalPowerSavingState.current.isPowerSavingModeEnabled.collectAsState()
|
||||
return state.blurEnabled && !isPowerSavingEnabled
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a haze effect to the [Modifier] with consideration of global haze settings and power saving mode.
|
||||
*
|
||||
|
|
@ -36,8 +50,7 @@ fun Modifier.hazeEffectTangem(
|
|||
style: HazeStyle = HazeStyle.Unspecified,
|
||||
configure: HazeEffectScope.() -> Unit = {},
|
||||
): Modifier {
|
||||
val powerSavingEnabled = LocalPowerSavingState.current.isPowerSavingModeEnabled.collectAsState()
|
||||
val isGlobalBlurEnabled = state.blurEnabled && !powerSavingEnabled.value
|
||||
val isGlobalBlurEnabled = isHazeBlurEffectivelyEnabled(state)
|
||||
val rootBackground by LocalRootBackgroundColor.current
|
||||
|
||||
return hazeEffect(state, style) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,405 @@
|
|||
package com.tangem.core.ui.ds2.badge
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.role
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.ds.image.TangemIcon
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds2.surface.TangemSurface
|
||||
import com.tangem.core.ui.extensions.ColorReference2
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
/**
|
||||
* Design-system v2 badge: a compact pill displaying a short label with optional leading / trailing
|
||||
* icons.
|
||||
*
|
||||
* [Figma](https://www.figma.com/design/AsnJ5CPHib4Qxw12gszjMS/%F0%9F%92%A0-DS-Components?node-id=2002-213)
|
||||
*
|
||||
* Behavior notes:
|
||||
* - Shape is always a fully-rounded pill (`borderRadius.full`).
|
||||
* - Icon tints are driven by [variant] + [status]; any tint set on a supplied [TangemIconUM.Icon]
|
||||
* is overridden. Other [TangemIconUM] subtypes (e.g. currency / image / url) pass through with
|
||||
* their own colors intact.
|
||||
* - The badge is non-interactive by default. Pass [onClick] to make it clickable.
|
||||
*
|
||||
* @param text Badge label.
|
||||
* @param modifier Modifier applied to the badge container.
|
||||
* @param variant Visual style. See [TangemBadge.Variant].
|
||||
* @param status Status color scheme (Neutral / Info / Error / Success / Warning).
|
||||
* @param size Token-driven size preset controlling height, padding, icon size and text style.
|
||||
* See [TangemBadge.Size].
|
||||
* @param iconStart Optional leading icon.
|
||||
* @param iconEnd Optional trailing icon.
|
||||
* @param contentDescription Accessibility label announced by TalkBack. When non-null it overrides
|
||||
* the label text for screen readers.
|
||||
* @param onClick Optional click handler. `null` makes the badge non-interactive.
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
fun TangemBadge(
|
||||
text: TextReference,
|
||||
modifier: Modifier = Modifier,
|
||||
variant: TangemBadge.Variant = TangemBadge.Variant.Tinted,
|
||||
status: TangemBadge.Status = TangemBadge.Status.Neutral,
|
||||
size: TangemBadge.Size = TangemBadge.Size.X9,
|
||||
iconStart: TangemIconUM? = null,
|
||||
iconEnd: TangemIconUM? = null,
|
||||
contentDescription: String? = null,
|
||||
onClick: (() -> Unit)? = null,
|
||||
) {
|
||||
val colorTokens = resolveColorTokens(variant = variant, status = status)
|
||||
val sizeTokens = size.tokens()
|
||||
|
||||
TangemSurface(
|
||||
modifier = modifier
|
||||
.semantics(mergeDescendants = true) {
|
||||
if (onClick != null) role = Role.Button
|
||||
contentDescription?.let { this.contentDescription = it }
|
||||
}
|
||||
.heightIn(min = sizeTokens.minHeight),
|
||||
onClick = onClick,
|
||||
color = colorTokens.backgroundColor,
|
||||
border = colorTokens.borderColor?.let { BorderStroke(TangemTheme.dimens3.borderWidth.sm, it) },
|
||||
shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.full),
|
||||
) {
|
||||
BadgeContent(
|
||||
iconStart = iconStart,
|
||||
iconEnd = iconEnd,
|
||||
text = text,
|
||||
colorTokens = colorTokens,
|
||||
sizeTokens = sizeTokens,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BadgeContent(
|
||||
iconStart: TangemIconUM?,
|
||||
iconEnd: TangemIconUM?,
|
||||
text: TextReference,
|
||||
colorTokens: BadgeColorTokens,
|
||||
sizeTokens: BadgeSizeTokens,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.heightIn(min = sizeTokens.minHeight)
|
||||
.padding(
|
||||
horizontal = sizeTokens.containerHorizontalPadding,
|
||||
vertical = sizeTokens.containerVerticalPadding,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
iconStart?.let { icon ->
|
||||
TangemIcon(
|
||||
modifier = Modifier.size(sizeTokens.iconSize),
|
||||
tangemIconUM = icon.applyTint(colorTokens.iconTint),
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = sizeTokens.labelPadding),
|
||||
text = text.resolveReference(),
|
||||
color = colorTokens.textColor,
|
||||
style = sizeTokens.textStyle,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
iconEnd?.let { icon ->
|
||||
TangemIcon(
|
||||
modifier = Modifier.size(sizeTokens.iconSize),
|
||||
tangemIconUM = icon.applyTint(colorTokens.iconTint),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces [tint] onto [TangemIconUM.Icon] so the badge's variant always drives icon color. Other
|
||||
* icon types (currency, image, url) pass through unchanged so they keep their own visuals.
|
||||
*/
|
||||
private fun TangemIconUM.applyTint(tint: Color): TangemIconUM = when (this) {
|
||||
is TangemIconUM.Icon -> copy(tint = ColorReference2 { tint })
|
||||
else -> this
|
||||
}
|
||||
|
||||
object TangemBadge {
|
||||
|
||||
/**
|
||||
* Visual style of the badge.
|
||||
*
|
||||
* - [Tinted] — soft tinted fill (subtle status color or opaque neutral), no border.
|
||||
* - [Outline] — tinted fill with a matching border.
|
||||
* - [Solid] — saturated status color fill with static-dark content.
|
||||
*/
|
||||
enum class Variant {
|
||||
Tinted,
|
||||
Outline,
|
||||
Solid,
|
||||
}
|
||||
|
||||
/** Status color scheme of the badge. */
|
||||
enum class Status {
|
||||
Neutral,
|
||||
Info,
|
||||
Error,
|
||||
Success,
|
||||
Warning,
|
||||
}
|
||||
|
||||
/**
|
||||
* Size preset. Names follow the design-system size scale: X9 is the largest (min height 36dp),
|
||||
* X4 is the smallest (min height 16dp).
|
||||
*/
|
||||
enum class Size {
|
||||
X9,
|
||||
X6,
|
||||
X4,
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolved colors for a (variant, status) pair. */
|
||||
private data class BadgeColorTokens(
|
||||
val backgroundColor: Color,
|
||||
val textColor: Color,
|
||||
val iconTint: Color,
|
||||
val borderColor: Color? = null,
|
||||
)
|
||||
|
||||
/** Resolved per-size dimensions used by [TangemBadge]. */
|
||||
private data class BadgeSizeTokens(
|
||||
val minHeight: Dp,
|
||||
val containerHorizontalPadding: Dp,
|
||||
val containerVerticalPadding: Dp,
|
||||
val labelPadding: Dp,
|
||||
val iconSize: Dp,
|
||||
val textStyle: TextStyle,
|
||||
)
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun TangemBadge.Size.tokens(): BadgeSizeTokens {
|
||||
val dimens = TangemTheme.dimens3
|
||||
val typography = TangemTheme.typography3
|
||||
return when (this) {
|
||||
TangemBadge.Size.X9 -> BadgeSizeTokens(
|
||||
minHeight = dimens.size.s450,
|
||||
containerHorizontalPadding = dimens.spacing.s100,
|
||||
containerVerticalPadding = dimens.spacing.s100,
|
||||
labelPadding = dimens.spacing.s050,
|
||||
iconSize = 20.dp,
|
||||
textStyle = typography.subheading.medium,
|
||||
)
|
||||
TangemBadge.Size.X6 -> BadgeSizeTokens(
|
||||
minHeight = dimens.size.s300,
|
||||
containerHorizontalPadding = dimens.spacing.s050,
|
||||
containerVerticalPadding = dimens.spacing.s050,
|
||||
labelPadding = dimens.spacing.s050,
|
||||
iconSize = 16.dp,
|
||||
textStyle = typography.caption.medium,
|
||||
)
|
||||
TangemBadge.Size.X4 -> BadgeSizeTokens(
|
||||
minHeight = dimens.size.s200,
|
||||
containerHorizontalPadding = dimens.spacing.s025,
|
||||
containerVerticalPadding = dimens.spacing.none,
|
||||
labelPadding = dimens.spacing.s025,
|
||||
iconSize = 12.dp,
|
||||
textStyle = typography.caption.medium,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun resolveColorTokens(variant: TangemBadge.Variant, status: TangemBadge.Status): BadgeColorTokens {
|
||||
val colors = TangemTheme.colors3
|
||||
return when (variant) {
|
||||
TangemBadge.Variant.Tinted -> when (status) {
|
||||
TangemBadge.Status.Neutral -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.opaque.primary,
|
||||
textColor = colors.text.secondary,
|
||||
iconTint = colors.icon.secondary,
|
||||
)
|
||||
TangemBadge.Status.Info -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.infoSubtle,
|
||||
textColor = colors.text.status.info,
|
||||
iconTint = colors.icon.status.info,
|
||||
)
|
||||
TangemBadge.Status.Error -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.errorSubtle,
|
||||
textColor = colors.text.status.error,
|
||||
iconTint = colors.icon.status.error,
|
||||
)
|
||||
TangemBadge.Status.Success -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.successSubtle,
|
||||
textColor = colors.text.status.success,
|
||||
iconTint = colors.icon.status.success,
|
||||
)
|
||||
TangemBadge.Status.Warning -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.warningSubtle,
|
||||
textColor = colors.text.status.warning,
|
||||
iconTint = colors.icon.status.warning,
|
||||
)
|
||||
}
|
||||
TangemBadge.Variant.Outline -> when (status) {
|
||||
TangemBadge.Status.Neutral -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.opaque.primary,
|
||||
textColor = colors.text.secondary,
|
||||
iconTint = colors.icon.secondary,
|
||||
borderColor = colors.border.primary,
|
||||
)
|
||||
TangemBadge.Status.Info -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.infoSubtle,
|
||||
textColor = colors.text.status.info,
|
||||
iconTint = colors.icon.status.info,
|
||||
borderColor = colors.border.status.infoSubtle,
|
||||
)
|
||||
TangemBadge.Status.Error -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.errorSubtle,
|
||||
textColor = colors.text.status.error,
|
||||
iconTint = colors.icon.status.error,
|
||||
borderColor = colors.border.status.errorSubtle,
|
||||
)
|
||||
TangemBadge.Status.Success -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.successSubtle,
|
||||
textColor = colors.text.status.success,
|
||||
iconTint = colors.icon.status.success,
|
||||
borderColor = colors.border.status.successSubtle,
|
||||
)
|
||||
TangemBadge.Status.Warning -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.warningSubtle,
|
||||
textColor = colors.text.status.warning,
|
||||
iconTint = colors.icon.status.warning,
|
||||
borderColor = colors.border.status.warningSubtle,
|
||||
)
|
||||
}
|
||||
TangemBadge.Variant.Solid -> when (status) {
|
||||
TangemBadge.Status.Neutral -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.opaque.primary,
|
||||
textColor = colors.text.primary,
|
||||
iconTint = colors.icon.primary,
|
||||
)
|
||||
TangemBadge.Status.Info -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.info,
|
||||
textColor = colors.text.staticDark.primary,
|
||||
iconTint = colors.icon.staticDark,
|
||||
)
|
||||
TangemBadge.Status.Error -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.error,
|
||||
textColor = colors.text.staticDark.primary,
|
||||
iconTint = colors.icon.staticDark,
|
||||
)
|
||||
TangemBadge.Status.Success -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.success,
|
||||
textColor = colors.text.staticDark.primary,
|
||||
iconTint = colors.icon.staticDark,
|
||||
)
|
||||
TangemBadge.Status.Warning -> BadgeColorTokens(
|
||||
backgroundColor = colors.bg.status.warning,
|
||||
textColor = colors.text.staticDark.primary,
|
||||
iconTint = colors.icon.staticDark,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Previews
|
||||
|
||||
@Preview(name = "Light", showBackground = true)
|
||||
@Preview(name = "Dark", uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES, showBackground = true)
|
||||
@Composable
|
||||
private fun TangemBadgePreview() {
|
||||
TangemThemePreviewRedesign {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors3.bg.primary)
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
TangemBadge.Variant.entries.forEach { variant ->
|
||||
PreviewVariantBlock(variant = variant)
|
||||
}
|
||||
PreviewSizesBlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewVariantBlock(variant: TangemBadge.Variant) {
|
||||
val icon = remember { TangemIconUM.Icon(iconRes = R.drawable.ic_information_24) }
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(
|
||||
text = variant.name,
|
||||
color = TangemTheme.colors3.text.secondary,
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
TangemBadge.Status.entries.forEach { status ->
|
||||
TangemBadge(
|
||||
text = stringReference(status.name),
|
||||
variant = variant,
|
||||
status = status,
|
||||
iconStart = icon,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewSizesBlock() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(
|
||||
modifier = Modifier.widthIn(min = 72.dp),
|
||||
text = "Sizes (Tinted / Info)",
|
||||
color = TangemTheme.colors3.text.secondary,
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
TangemBadge.Size.entries.forEach { size ->
|
||||
TangemBadge(
|
||||
text = stringReference(size.name),
|
||||
variant = TangemBadge.Variant.Tinted,
|
||||
status = TangemBadge.Status.Info,
|
||||
size = size,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
|
@ -25,9 +25,9 @@ import androidx.compose.ui.graphics.Shape
|
|||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.haze.hazeEffectTangem
|
||||
import com.tangem.core.ui.components.haze.isHazeBlurEffectivelyEnabled
|
||||
import com.tangem.core.ui.extensions.conditionalCompose
|
||||
import com.tangem.core.ui.extensions.softLayerShadow
|
||||
import com.tangem.core.ui.res.LocalHazeState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import dev.chrisbanes.haze.HazeStyle
|
||||
import dev.chrisbanes.haze.HazeTint
|
||||
|
|
@ -133,9 +133,15 @@ private fun Modifier.materialBorder(shape: Shape): Modifier = border(
|
|||
*
|
||||
* When the haze state is enabled, paints a haze-blurred backdrop. When disabled, layers two
|
||||
* solid colors so the result still reads as "tinted fill" instead of going transparent.
|
||||
*
|
||||
* Uses [isHazeBlurEffectivelyEnabled] (rather than [LocalHazeState]'s `blurEnabled` directly) so
|
||||
* the solid fallback is also applied when blur is suppressed for reasons other than the haze flag
|
||||
* — most notably when the device is in power-saving mode. Otherwise the haze modifier's
|
||||
* `fallbackTint = HazeTint(Color.Transparent)` would leave the surface fully transparent.
|
||||
*/
|
||||
@Composable
|
||||
private fun Modifier.materialFill(): Modifier {
|
||||
val isBlurEnabled = isHazeBlurEffectivelyEnabled()
|
||||
val hazed = hazeEffectTangem(
|
||||
style = HazeStyle(
|
||||
backgroundColor = TangemTheme.colors3.material.fill.blur,
|
||||
|
|
@ -145,7 +151,7 @@ private fun Modifier.materialFill(): Modifier {
|
|||
) {
|
||||
fallbackTint = HazeTint(Color.Transparent)
|
||||
}
|
||||
return hazed.conditionalCompose(!LocalHazeState.current.blurEnabled) {
|
||||
return hazed.conditionalCompose(!isBlurEnabled) {
|
||||
// Paint the opaque fill first, then layer the translucent tint on top so both are visible.
|
||||
background(TangemTheme.colors3.material.fill.solid)
|
||||
.background(TangemTheme.colors3.material.tint.solid)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.tester.presentation.storybook.entity
|
|||
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeColor
|
||||
import com.tangem.core.ui.ds.field.search.TangemFieldShape
|
||||
import com.tangem.core.ui.ds2.badge.TangemBadge
|
||||
import com.tangem.core.ui.ds2.button.TangemButton
|
||||
import com.tangem.core.ui.ds2.loader.TangemLoaderSize
|
||||
import com.tangem.core.ui.ds.message.TangemMessageEffect
|
||||
|
|
@ -106,6 +107,7 @@ internal data class TangemLoaderStory(
|
|||
internal data class TangemButtonStory(
|
||||
val variant: TangemButton.Variant,
|
||||
val size: TangemButton.Size,
|
||||
val background: Background,
|
||||
val isLoading: Boolean,
|
||||
val isEnabled: Boolean,
|
||||
val hasIconStart: Boolean,
|
||||
|
|
@ -115,6 +117,7 @@ internal data class TangemButtonStory(
|
|||
val textScale: Float,
|
||||
val onVariantChange: (TangemButton.Variant) -> Unit,
|
||||
val onSizeChange: (TangemButton.Size) -> Unit,
|
||||
val onBackgroundChange: (Background) -> Unit,
|
||||
val onLoadingToggle: () -> Unit,
|
||||
val onEnabledToggle: () -> Unit,
|
||||
val onIconStartToggle: () -> Unit,
|
||||
|
|
@ -122,4 +125,41 @@ internal data class TangemButtonStory(
|
|||
val onTextToggle: () -> Unit,
|
||||
val onBlurToggle: () -> Unit,
|
||||
val onTextScaleChange: (Float) -> Unit,
|
||||
) : DsStoryBookPage
|
||||
) : DsStoryBookPage {
|
||||
|
||||
/** Backdrop the button preview is rendered on top of. */
|
||||
enum class Background(val label: String) {
|
||||
Rainbow("rainbow"),
|
||||
BgPrimary("bg.primary"),
|
||||
BgSecondary("bg.secondary"),
|
||||
BgBrand("bg.brand"),
|
||||
BgInverse("bg.inverse"),
|
||||
}
|
||||
}
|
||||
|
||||
internal data class TangemBadgeV2Story(
|
||||
val variant: TangemBadge.Variant,
|
||||
val status: TangemBadge.Status,
|
||||
val size: TangemBadge.Size,
|
||||
val background: Background,
|
||||
val hasIconStart: Boolean,
|
||||
val hasIconEnd: Boolean,
|
||||
val textScale: Float,
|
||||
val onVariantChange: (TangemBadge.Variant) -> Unit,
|
||||
val onStatusChange: (TangemBadge.Status) -> Unit,
|
||||
val onSizeChange: (TangemBadge.Size) -> Unit,
|
||||
val onBackgroundChange: (Background) -> Unit,
|
||||
val onIconStartToggle: () -> Unit,
|
||||
val onIconEndToggle: () -> Unit,
|
||||
val onTextScaleChange: (Float) -> Unit,
|
||||
) : DsStoryBookPage {
|
||||
|
||||
/** Backdrop the badge preview is rendered on top of. */
|
||||
enum class Background(val label: String) {
|
||||
Rainbow("rainbow"),
|
||||
BgPrimary("bg.primary"),
|
||||
BgSecondary("bg.secondary"),
|
||||
BgBrand("bg.brand"),
|
||||
BgInverse("bg.inverse"),
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import com.tangem.core.ui.components.PrimaryButton
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.tester.presentation.storybook.entity.DsComponentsListStory
|
||||
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.loader.tangemLoaderStoryFactory
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ private data class DsStoryItem(val title: String, val factory: StoryPageFactory)
|
|||
private fun buildDsStories() = listOf(
|
||||
DsStoryItem(title = "⏳ TangemLoader", factory = tangemLoaderStoryFactory),
|
||||
DsStoryItem(title = "🔘 TangemButton", factory = tangemButtonStoryFactory),
|
||||
DsStoryItem(title = "🏷️ TangemBadge", factory = tangemBadgeV2StoryFactory),
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tangem.feature.tester.presentation.storybook.page.ds.badge
|
||||
|
||||
import com.tangem.core.ui.ds2.badge.TangemBadge
|
||||
import com.tangem.feature.tester.presentation.storybook.entity.TangemBadgeV2Story
|
||||
import com.tangem.feature.tester.presentation.storybook.viewmodel.StateUpdater
|
||||
import com.tangem.feature.tester.presentation.storybook.viewmodel.storyPageFactory
|
||||
|
||||
internal fun StateUpdater<TangemBadgeV2Story>.build(): TangemBadgeV2Story {
|
||||
return TangemBadgeV2Story(
|
||||
variant = TangemBadge.Variant.Tinted,
|
||||
status = TangemBadge.Status.Info,
|
||||
size = TangemBadge.Size.X9,
|
||||
background = TangemBadgeV2Story.Background.BgPrimary,
|
||||
hasIconStart = false,
|
||||
hasIconEnd = false,
|
||||
textScale = 1f,
|
||||
onVariantChange = { variant ->
|
||||
updateStory { it.copy(variant = variant) }
|
||||
},
|
||||
onStatusChange = { status ->
|
||||
updateStory { it.copy(status = status) }
|
||||
},
|
||||
onSizeChange = { size ->
|
||||
updateStory { it.copy(size = size) }
|
||||
},
|
||||
onBackgroundChange = { background ->
|
||||
updateStory { it.copy(background = background) }
|
||||
},
|
||||
onIconStartToggle = {
|
||||
updateStory { it.copy(hasIconStart = !it.hasIconStart) }
|
||||
},
|
||||
onIconEndToggle = {
|
||||
updateStory { it.copy(hasIconEnd = !it.hasIconEnd) }
|
||||
},
|
||||
onTextScaleChange = { scale ->
|
||||
updateStory { it.copy(textScale = scale) }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
internal val tangemBadgeV2StoryFactory
|
||||
get() = storyPageFactory(StateUpdater<TangemBadgeV2Story>::build)
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
@file:Suppress("MagicNumber")
|
||||
|
||||
package com.tangem.feature.tester.presentation.storybook.page.ds.badge
|
||||
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.RepeatMode
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
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.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.SliderDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
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.Density
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.haze.hazeSourceTangem
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds2.badge.TangemBadge
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.tester.presentation.storybook.entity.TangemBadgeV2Story
|
||||
import com.tangem.feature.tester.presentation.storybook.entity.TangemBadgeV2Story.Background
|
||||
|
||||
@Composable
|
||||
internal fun TangemBadgeV2Story(state: TangemBadgeV2Story, modifier: Modifier = Modifier) {
|
||||
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)
|
||||
StatusSelector(selected = state.status, onSelect = state.onStatusChange)
|
||||
SizeSelector(selected = state.size, onSelect = state.onSizeChange)
|
||||
BackgroundSelector(selected = state.background, onSelect = state.onBackgroundChange)
|
||||
TextScaleSlider(value = state.textScale, onChange = state.onTextScaleChange)
|
||||
Toggles(state = state)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BlurTestBackground(modifier: Modifier = Modifier) {
|
||||
val bands = remember {
|
||||
listOf(
|
||||
Color(0xFFFF1744), // red
|
||||
Color(0xFFFF9100), // orange
|
||||
Color(0xFFFFEA00), // yellow
|
||||
Color(0xFF00E676), // green
|
||||
Color(0xFF00B8D4), // cyan
|
||||
Color(0xFF2962FF), // blue
|
||||
Color(0xFFD500F9), // magenta
|
||||
)
|
||||
}
|
||||
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) { 320.dp.toPx() }
|
||||
val transition = rememberInfiniteTransition(label = "badge-blur-bg")
|
||||
val offset by transition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = tilePx,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(durationMillis = 4_000, easing = LinearEasing),
|
||||
repeatMode = RepeatMode.Restart,
|
||||
),
|
||||
label = "badge-blur-bg-offset",
|
||||
)
|
||||
Box(
|
||||
modifier = modifier.background(
|
||||
brush = Brush.linearGradient(
|
||||
colorStops = stops,
|
||||
start = Offset(offset, 0f),
|
||||
end = Offset(offset + tilePx, 0f),
|
||||
tileMode = TileMode.Repeated,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewBackground(background: Background, modifier: Modifier = Modifier) {
|
||||
when (background) {
|
||||
Background.Rainbow -> BlurTestBackground(modifier = modifier)
|
||||
Background.BgPrimary -> Box(modifier.background(TangemTheme.colors3.bg.primary))
|
||||
Background.BgSecondary -> Box(modifier.background(TangemTheme.colors3.bg.secondary))
|
||||
Background.BgBrand -> Box(modifier.background(TangemTheme.colors3.bg.brand))
|
||||
Background.BgInverse -> Box(modifier.background(TangemTheme.colors3.bg.inverse))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ComponentPreview(state: TangemBadgeV2Story) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.clip(RoundedCornerShape(16.dp)),
|
||||
) {
|
||||
PreviewBackground(
|
||||
background = state.background,
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.hazeSourceTangem(zIndex = 0f),
|
||||
)
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 32.dp),
|
||||
) {
|
||||
val baseDensity = LocalDensity.current
|
||||
val scaledDensity = remember(baseDensity, state.textScale) {
|
||||
Density(density = baseDensity.density, fontScale = state.textScale)
|
||||
}
|
||||
CompositionLocalProvider(LocalDensity provides scaledDensity) {
|
||||
TangemBadge(
|
||||
text = stringReference("Label"),
|
||||
variant = state.variant,
|
||||
status = state.status,
|
||||
size = state.size,
|
||||
iconStart = if (state.hasIconStart) {
|
||||
TangemIconUM.Icon(iconRes = R.drawable.ic_information_24)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
iconEnd = if (state.hasIconEnd) {
|
||||
TangemIconUM.Icon(iconRes = R.drawable.ic_information_24)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun VariantSelector(selected: TangemBadge.Variant, onSelect: (TangemBadge.Variant) -> Unit) {
|
||||
Section(label = "Variant") {
|
||||
ChipGrid(
|
||||
items = TangemBadge.Variant.entries,
|
||||
label = { it.name },
|
||||
isSelected = { it == selected },
|
||||
onSelect = onSelect,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StatusSelector(selected: TangemBadge.Status, onSelect: (TangemBadge.Status) -> Unit) {
|
||||
Section(label = "Status") {
|
||||
ChipGrid(
|
||||
items = TangemBadge.Status.entries,
|
||||
label = { it.name },
|
||||
isSelected = { it == selected },
|
||||
onSelect = onSelect,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SizeSelector(selected: TangemBadge.Size, onSelect: (TangemBadge.Size) -> Unit) {
|
||||
Section(label = "Size") {
|
||||
ChipGrid(
|
||||
items = TangemBadge.Size.entries,
|
||||
label = { it.name },
|
||||
isSelected = { it == selected },
|
||||
onSelect = onSelect,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BackgroundSelector(selected: Background, onSelect: (Background) -> Unit) {
|
||||
Section(label = "Background") {
|
||||
ChipGrid(
|
||||
items = Background.entries,
|
||||
label = { it.label },
|
||||
isSelected = { it == selected },
|
||||
onSelect = onSelect,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextScaleSlider(value: Float, onChange: (Float) -> Unit) {
|
||||
Section(label = "Text scale: ${"%.2f".format(value)}x") {
|
||||
Slider(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
value = value,
|
||||
onValueChange = onChange,
|
||||
valueRange = 0.5f..2f,
|
||||
steps = 14,
|
||||
colors = SliderDefaults.colors(
|
||||
thumbColor = TangemTheme.colors.text.accent,
|
||||
activeTrackColor = TangemTheme.colors.text.accent,
|
||||
activeTickColor = TangemTheme.colors2.surface.level3,
|
||||
inactiveTrackColor = TangemTheme.colors2.surface.level3,
|
||||
inactiveTickColor = TangemTheme.colors.text.accent,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Toggles(state: TangemBadgeV2Story) {
|
||||
Section(label = "Flags") {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
ToggleRow(label = "iconStart", checked = state.hasIconStart, onToggle = state.onIconStartToggle)
|
||||
ToggleRow(label = "iconEnd", checked = state.hasIconEnd, onToggle = state.onIconEndToggle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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.body2,
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ internal fun StateUpdater<TangemButtonStory>.build(): TangemButtonStory {
|
|||
return TangemButtonStory(
|
||||
variant = TangemButton.Variant.Primary,
|
||||
size = TangemButton.Size.X10,
|
||||
background = TangemButtonStory.Background.Rainbow,
|
||||
isLoading = false,
|
||||
isEnabled = true,
|
||||
hasIconStart = false,
|
||||
|
|
@ -22,6 +23,9 @@ internal fun StateUpdater<TangemButtonStory>.build(): TangemButtonStory {
|
|||
onSizeChange = { size ->
|
||||
updateStory { it.copy(size = size) }
|
||||
},
|
||||
onBackgroundChange = { background ->
|
||||
updateStory { it.copy(background = background) }
|
||||
},
|
||||
onLoadingToggle = {
|
||||
updateStory { it.copy(isLoading = !it.isLoading) }
|
||||
},
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.core.ui.res.LocalHazeState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.tester.presentation.storybook.entity.TangemButtonStory
|
||||
import com.tangem.feature.tester.presentation.storybook.entity.TangemButtonStory.Background
|
||||
|
||||
@Composable
|
||||
internal fun TangemButtonStory(state: TangemButtonStory, modifier: Modifier = Modifier) {
|
||||
|
|
@ -52,6 +53,7 @@ internal fun TangemButtonStory(state: TangemButtonStory, modifier: Modifier = Mo
|
|||
ComponentPreview(state = state)
|
||||
VariantSelector(selected = state.variant, onSelect = state.onVariantChange)
|
||||
SizeSelector(selected = state.size, onSelect = state.onSizeChange)
|
||||
BackgroundSelector(selected = state.background, onSelect = state.onBackgroundChange)
|
||||
TextScaleSlider(value = state.textScale, onChange = state.onTextScaleChange)
|
||||
Toggles(state = state)
|
||||
}
|
||||
|
|
@ -104,6 +106,17 @@ private fun BlurTestBackground(modifier: Modifier = Modifier) {
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewBackground(background: Background, modifier: Modifier = Modifier) {
|
||||
when (background) {
|
||||
Background.Rainbow -> BlurTestBackground(modifier = modifier)
|
||||
Background.BgPrimary -> Box(modifier.background(TangemTheme.colors3.bg.primary))
|
||||
Background.BgSecondary -> Box(modifier.background(TangemTheme.colors3.bg.secondary))
|
||||
Background.BgBrand -> Box(modifier.background(TangemTheme.colors3.bg.brand))
|
||||
Background.BgInverse -> Box(modifier.background(TangemTheme.colors3.bg.inverse))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ComponentPreview(state: TangemButtonStory) {
|
||||
Box(
|
||||
|
|
@ -113,7 +126,8 @@ private fun ComponentPreview(state: TangemButtonStory) {
|
|||
.padding(horizontal = 16.dp)
|
||||
.clip(RoundedCornerShape(16.dp)),
|
||||
) {
|
||||
BlurTestBackground(
|
||||
PreviewBackground(
|
||||
background = state.background,
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.hazeSourceTangem(zIndex = 0f),
|
||||
|
|
@ -176,6 +190,18 @@ private fun SizeSelector(selected: TangemButton.Size, onSelect: (TangemButton.Si
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BackgroundSelector(selected: Background, onSelect: (Background) -> Unit) {
|
||||
Section(label = "Background") {
|
||||
ChipGrid(
|
||||
items = Background.entries,
|
||||
label = { it.label },
|
||||
isSelected = { it == selected },
|
||||
onSelect = onSelect,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextScaleSlider(value: Float, onChange: (Float) -> Unit) {
|
||||
Section(label = "Text scale: ${"%.2f".format(value)}x") {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.feature.tester.presentation.storybook.entity.OpportunitiesBGSt
|
|||
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.StoryBookUM
|
||||
import com.tangem.feature.tester.presentation.storybook.entity.StoryList
|
||||
|
|
@ -32,6 +33,7 @@ import com.tangem.feature.tester.presentation.storybook.page.badge.TangemBadgeSt
|
|||
import com.tangem.feature.tester.presentation.storybook.page.buttons.ButtonsStory
|
||||
import com.tangem.feature.tester.presentation.storybook.page.deviceicon.DeviceIconStory
|
||||
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.loader.TangemLoaderStory
|
||||
import com.tangem.feature.tester.presentation.storybook.page.opportunities.OpportunitiesBGStory
|
||||
|
|
@ -82,6 +84,7 @@ internal fun StoryBookScreen(state: StoryBookUM, modifier: Modifier = Modifier)
|
|||
is DsComponentsListStory -> DsComponentsListStory(state = storyState)
|
||||
is TangemLoaderStory -> TangemLoaderStory(state = storyState)
|
||||
is TangemButtonStory -> TangemButtonStory(state = storyState)
|
||||
is TangemBadgeV2Story -> TangemBadgeV2Story(state = storyState)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue