From 73bf0b7617ec32b993583b3c6b68bb7f33d20072 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 27 Feb 2026 13:22:44 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../core/ui/ds/button/GhostTangemButton.kt | 6 +- .../core/ui/ds/button/TangemButtonInternal.kt | 151 ++++++------ features/tester/STORYBOOK.md | 218 ++++++++++++++++++ .../storybook/entity/StoryBookPage.kt | 2 + .../storybook/page/buttons/Build.kt | 6 + .../storybook/page/buttons/ButtonsStory.kt | 200 ++++++++++++++++ .../storybook/ui/StoryBookListScreen.kt | 4 +- .../storybook/ui/StoryBookScreen.kt | 3 + 8 files changed, 522 insertions(+), 68 deletions(-) create mode 100644 features/tester/STORYBOOK.md create mode 100644 features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/buttons/Build.kt create mode 100644 features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/buttons/ButtonsStory.kt diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/button/GhostTangemButton.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/button/GhostTangemButton.kt index 0fece5aae0..1bd3696db3 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/button/GhostTangemButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/button/GhostTangemButton.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider @@ -36,6 +37,7 @@ fun GhostTangemButton(buttonUM: TangemButtonUM, modifier: Modifier = Modifier) { enabled = buttonUM.isEnabled, size = buttonUM.size, state = buttonUM.state, + shape = buttonUM.shape, ) } @@ -63,6 +65,7 @@ fun GhostTangemButton( size: TangemButtonSize = TangemButtonSize.X15, state: TangemButtonState = TangemButtonState.Default, iconPosition: TangemButtonIconPosition = TangemButtonIconPosition.Start, + shape: TangemButtonShape = TangemButtonShape.Default, ) { val contentColor = when (state) { TangemButtonState.Disabled -> TangemTheme.colors2.text.status.disabled @@ -70,7 +73,8 @@ fun GhostTangemButton( } TangemButtonInternal( onClick = onClick, - modifier = modifier, + modifier = modifier + .clip(shape = shape.toShape(size)), text = text, contentColor = contentColor, enabled = enabled, diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/button/TangemButtonInternal.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/button/TangemButtonInternal.kt index 4d6f5dc9d9..53166d0416 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/button/TangemButtonInternal.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/button/TangemButtonInternal.kt @@ -7,10 +7,10 @@ import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.TextAutoSize -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.Icon -import androidx.compose.material3.Text +import androidx.compose.material.ripple.RippleAlpha +import androidx.compose.material3.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -60,72 +60,91 @@ internal fun TangemButtonInternal( size: TangemButtonSize = TangemButtonSize.X15, state: TangemButtonState = TangemButtonState.Default, ) { - Row( - modifier = modifier - .testTag(BaseButtonTestTags.BUTTON) - .height(size.toHeightDp()) - .conditionalCompose(text == null) { - width(size.toHeightDp()) + ProvideButtonRippleConfiguration { + Row( + modifier = modifier + .testTag(BaseButtonTestTags.BUTTON) + .clickableSingle(enabled = enabled, onClick = onClick, role = Role.Button) + .height(size.toHeightDp()) + .conditionalCompose(text == null) { + width(size.toHeightDp()) + } + .conditionalCompose(text != null) { + padding(horizontal = size.toPaddingDp()) + } + .animateContentSize(), + horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + ) { + AnimatedVisibility( + visible = iconRes != null && iconPosition == TangemButtonIconPosition.Start, + modifier = Modifier.size(size = size.toContentSize()), + ) { + val wrappedIconRes = remember(this) { requireNotNull(iconRes) } + TangemButtonIcon(iconRes = wrappedIconRes, state = state, iconColor = contentColor, size = size) } - .clickableSingle(enabled = enabled, onClick = onClick, role = Role.Button) - .conditionalCompose(text != null) { - padding(horizontal = size.toPaddingDp()) + + AnimatedVisibility(text != null && state != TangemButtonState.Loading) { + val wrappedText = remember(this) { requireNotNull(text) } + val textStyle = size.toTextStyle() + Text( + text = wrappedText.resolveReference(), + style = textStyle, + color = contentColor, + textAlign = TextAlign.Center, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + autoSize = TextAutoSize.StepBased( + minFontSize = 12.sp, + maxFontSize = textStyle.fontSize, + ), + modifier = Modifier.testTag(BaseButtonTestTags.TEXT), + ) } - .animateContentSize(), - horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterHorizontally), - verticalAlignment = Alignment.CenterVertically, + + AnimatedVisibility(descriptionText != null && state != TangemButtonState.Loading) { + val wrappedText = remember(this) { requireNotNull(descriptionText) } + val textStyle = TangemTheme.typography2.captionSemibold12 + Text( + text = wrappedText.resolveReference(), + style = textStyle, + color = TangemTheme.colors2.text.status.disabled, + textAlign = TextAlign.Center, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + autoSize = TextAutoSize.StepBased( + minFontSize = 12.sp, + maxFontSize = textStyle.fontSize, + ), + modifier = Modifier.testTag(BaseButtonTestTags.TEXT), + ) + } + + AnimatedVisibility( + visible = iconRes != null && iconPosition == TangemButtonIconPosition.End, + modifier = Modifier.size(size = size.toContentSize()), + ) { + val wrappedIconRes = remember(this) { requireNotNull(iconRes) } + TangemButtonIcon(iconRes = wrappedIconRes, state = state, iconColor = contentColor, size = size) + } + } + } +} + +@Composable +private inline fun ProvideButtonRippleConfiguration(crossinline content: @Composable () -> Unit) { + CompositionLocalProvider( + LocalRippleConfiguration provides RippleConfiguration( + color = TangemTheme.colors2.overlay.overlaySecondary, + RippleAlpha( + pressedAlpha = 0.4f, + focusedAlpha = 0.4f, + draggedAlpha = 0.4f, + hoveredAlpha = 0.4f, + ), + ), ) { - AnimatedVisibility( - visible = iconRes != null && iconPosition == TangemButtonIconPosition.Start, - modifier = Modifier.size(size = size.toContentSize()), - ) { - val wrappedIconRes = remember(this) { requireNotNull(iconRes) } - TangemButtonIcon(iconRes = wrappedIconRes, state = state, iconColor = contentColor, size = size) - } - - AnimatedVisibility(text != null && state != TangemButtonState.Loading) { - val wrappedText = remember(this) { requireNotNull(text) } - val textStyle = size.toTextStyle() - Text( - text = wrappedText.resolveReference(), - style = textStyle, - color = contentColor, - textAlign = TextAlign.Center, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - autoSize = TextAutoSize.StepBased( - minFontSize = 12.sp, - maxFontSize = textStyle.fontSize, - ), - modifier = Modifier.testTag(BaseButtonTestTags.TEXT), - ) - } - - AnimatedVisibility(descriptionText != null && state != TangemButtonState.Loading) { - val wrappedText = remember(this) { requireNotNull(descriptionText) } - val textStyle = TangemTheme.typography2.captionSemibold12 - Text( - text = wrappedText.resolveReference(), - style = textStyle, - color = TangemTheme.colors2.text.status.disabled, - textAlign = TextAlign.Center, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - autoSize = TextAutoSize.StepBased( - minFontSize = 12.sp, - maxFontSize = textStyle.fontSize, - ), - modifier = Modifier.testTag(BaseButtonTestTags.TEXT), - ) - } - - AnimatedVisibility( - visible = iconRes != null && iconPosition == TangemButtonIconPosition.End, - modifier = Modifier.size(size = size.toContentSize()), - ) { - val wrappedIconRes = remember(this) { requireNotNull(iconRes) } - TangemButtonIcon(iconRes = wrappedIconRes, state = state, iconColor = contentColor, size = size) - } + content() } } diff --git a/features/tester/STORYBOOK.md b/features/tester/STORYBOOK.md new file mode 100644 index 0000000000..f9142cdd1b --- /dev/null +++ b/features/tester/STORYBOOK.md @@ -0,0 +1,218 @@ +# Storybook — Adding New Design System Pages + +The storybook lives in `features/tester` and lets developers browse and validate +design system components at runtime on a device or emulator. + +--- + +## Architecture overview + +``` +storybook/ +├── entity/ +│ ├── StoryBookPage.kt ← sealed interface + all page state classes +│ ├── StoryBookUM.kt ← top-level UI model (current page, navigation) +│ └── StoryPageFactory.kt ← factory interface used by the list screen +├── page/ +│ └── / +│ ├── Build.kt ← creates the StoryPageFactory for this page +│ └── Story.kt ← the Composable that renders the showcase +├── ui/ +│ ├── StoryBookListScreen.kt ← list of all stories (add your entry here) +│ └── StoryBookScreen.kt ← routes currentPage → correct Composable +└── viewmodel/ + ├── StoryBookViewModel.kt + └── StateUpdater.kt ← helper for stateful pages +``` + +--- + +## Step-by-step: adding a new page + +### 1. Declare the page type in `StoryBookPage.kt` + +For a **stateless** showcase (no user interaction that mutates page state): +```kotlin +internal data object FooStory : StoryBookPage +``` + +For a **stateful** page (e.g. toggle between variants like NorthernLightsStory): +```kotlin +internal data class FooStory( + val selectedVariant: Variant, + val onVariantChange: (Variant) -> Unit, +) : StoryBookPage { + enum class Variant { A, B } +} +``` + +--- + +### 2. Create `page/foo/Build.kt` + +**Stateless:** +```kotlin +internal val fooStoryFactory: StoryPageFactory = StoryPageFactory { FooStory } +``` + +**Stateful** (use `storyPageFactory` + `StateUpdater`): +```kotlin +internal fun StateUpdater.build(): FooStory { + return FooStory( + selectedVariant = FooStory.Variant.A, + onVariantChange = { newVariant -> + updateStory { it.copy(selectedVariant = newVariant) } + }, + ) +} + +internal val fooStoryFactory + get() = storyPageFactory(StateUpdater::build) +``` + +--- + +### 3. Create `page/foo/FooStory.kt` + +Write a `@Composable internal fun FooStory(...)` that renders the showcase. +See [Design guidelines](#design-guidelines) below for layout advice. + +**Stateless example skeleton:** +```kotlin +@Composable +internal fun FooStory(modifier: Modifier = Modifier) { + LazyColumn(modifier = modifier.fillMaxSize()) { + item("section_a") { /* ... */ } + } +} +``` + +**Stateful example skeleton:** +```kotlin +@Composable +internal fun FooStory(state: FooStory, modifier: Modifier = Modifier) { + // use state.selectedVariant, state.onVariantChange +} +``` + +--- + +### 4. Register in `StoryBookScreen.kt` + +Add a branch to the `when` block. + +> **Naming note:** the entity type and the Composable function will share the +> same simple name (e.g. `FooStory`). Kotlin resolves them correctly — the +> entity import is used in the pattern position, the function import is used +> as a call. This is the same pattern used for `NorthernLightsStory` and +> `ButtonsStory`. + +```kotlin +import com.tangem.feature.tester.presentation.storybook.entity.FooStory +import com.tangem.feature.tester.presentation.storybook.page.foo.FooStory + +when (storyState) { + StoryList -> StoryBookListScreen(state = state) + is NorthernLightsStory -> NorthernLightsStory(state = storyState) + ButtonsStory -> ButtonsStory() + FooStory -> FooStory() // stateless + is FooStory -> FooStory(storyState) // stateful (note `is`) +} +``` + +--- + +### 5. Register in `StoryBookListScreen.kt` + +Add one entry to `buildStories()`. **Every title must start with an emoji** that +represents the component category — this makes the list easier to scan at a glance. + +```kotlin +private fun buildStories() = listOf( + StoryItem(title = "🃏 Foo Component", factory = fooStoryFactory), + // existing entries... +) +``` + +Pick an emoji that reflects the component's visual nature or purpose, e.g.: +- Buttons → 🔘 +- Background effects → 🌌 +- Typography → 🔤 +- Icons → 🎨 +- Cards → 🃏 +- Inputs / Text fields → ✏️ +- Navigation → 🧭 +- Loaders / Progress → ⏳ + +--- + +## Design guidelines + +### Layout + +Use a `LazyColumn` as the root for component showcases so the page scrolls +when content is taller than the screen. + +```kotlin +LazyColumn( + contentPadding = PaddingValues(vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = modifier.fillMaxSize().background(TangemTheme.colors2.surface.level1), +) { /* items */ } +``` + +### Showing all variants + +Show every meaningful axis of variation in one place: + +| Axis | How to display | +|---|---| +| **States** (Default, Disabled, Pressed, Loading) | One row per state | +| **Shapes** (Default, Rounded) | One labeled group (`ShapeGroup`) per shape, iterate `TangemButtonShape.entries` | +| **Content** (text+icon vs icon-only) | Two columns per row | +| **Sizes** | Separate `LazyColumn` item per size group if needed | + +> **Prefer vertical stacking over horizontal.** A row should contain at most +> 2–3 components; more than that overflows on narrow screens. Use +> `Modifier.weight(1f)` on columns instead of fixed widths. + +### Section structure (component grids) + +Follow the pattern used in `ButtonsStory`: +- **Section title** — `TangemTheme.typography.subtitle1` +- **Group sub-header** (shape/size/variant name) — `TangemTheme.typography.body2` +- **Column headers** (Text + Icon, Icon only, etc.) — `TangemTheme.typography.caption2` +- **State label** (Default, Disabled…) — `TangemTheme.typography.caption2`, fixed width ~80 dp + +``` +Primary ← subtitle1 + Default ← body2 (shape/group sub-header) + Text + Icon Icon only ← caption2 column headers + Default [■ Continue] [■] ← state row + Disabled [■ Continue] [■] + Pressed [■ Continue] [■] + Loading [ ⟳ ] [⟳] + Rounded ← body2 + ... +``` + +### Colors + +- Page background: `TangemTheme.colors2.surface.level1` +- Sections that need a contrasting background (e.g. PrimaryInverse): + `TangemTheme.colors2.surface.level2` +- Section divider: `HorizontalDivider(color = TangemTheme.colors2.border.neutral.secondary)` + +### Realistic text + +Use representative text strings, not placeholders like "Btn". Pick labels that +match how the component would appear in the product (e.g. `"Continue"`, +`"Send payment"`, `"Confirm"`). + +### DS component imports + +All design system components (`PrimaryTangemButton`, `TangemButtonSize`, etc.) +live in `com.tangem.core.ui.ds.*` and are `public`, so they are directly +importable from the `features/tester` module. + +Use `com.tangem.core.ui.R` for drawable resources (e.g. `R.drawable.ic_tangem_24`). \ No newline at end of file diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/entity/StoryBookPage.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/entity/StoryBookPage.kt index 1c730da1d5..5967dd9e21 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/entity/StoryBookPage.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/entity/StoryBookPage.kt @@ -4,6 +4,8 @@ internal sealed interface StoryBookPage internal data object StoryList : StoryBookPage +internal data object ButtonsStory : StoryBookPage + internal data class NorthernLightsStory( val variant: Variant, val onVariantChange: (Variant) -> Unit, diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/buttons/Build.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/buttons/Build.kt new file mode 100644 index 0000000000..4ea6b7efbb --- /dev/null +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/buttons/Build.kt @@ -0,0 +1,6 @@ +package com.tangem.feature.tester.presentation.storybook.page.buttons + +import com.tangem.feature.tester.presentation.storybook.entity.ButtonsStory +import com.tangem.feature.tester.presentation.storybook.entity.StoryPageFactory + +internal val buttonsStoryFactory: StoryPageFactory = StoryPageFactory { ButtonsStory } \ No newline at end of file diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/buttons/ButtonsStory.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/buttons/ButtonsStory.kt new file mode 100644 index 0000000000..d57ebfdd8a --- /dev/null +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/buttons/ButtonsStory.kt @@ -0,0 +1,200 @@ +package com.tangem.feature.tester.presentation.storybook.page.buttons + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.R +import com.tangem.core.ui.ds.button.* +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.res.TangemTheme + +private const val STATE_LABEL_WIDTH = 80 + +@Suppress("LongMethod") +@Composable +internal fun ButtonsStory(modifier: Modifier = Modifier) { + LazyColumn( + contentPadding = PaddingValues(vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = modifier + .fillMaxSize() + .background(TangemTheme.colors2.surface.level1), + ) { + item("primary") { + ButtonSection(title = "Primary") { state, text, shape -> + PrimaryTangemButton( + onClick = {}, + text = if (text) stringReference("Continue") else null, + iconRes = R.drawable.ic_tangem_24, + size = TangemButtonSize.X10, + state = state, + shape = shape, + ) + } + } + item("secondary") { + ButtonSection(title = "Secondary") { state, text, shape -> + SecondaryTangemButton( + onClick = {}, + text = if (text) stringReference("Continue") else null, + iconRes = R.drawable.ic_tangem_24, + size = TangemButtonSize.X10, + state = state, + shape = shape, + ) + } + } + item("primary_inverse") { + ButtonSection( + title = "PrimaryInverse", + background = TangemTheme.colors2.surface.level2, + ) { state, text, shape -> + PrimaryInverseTangemButton( + onClick = {}, + text = if (text) stringReference("Continue") else null, + iconRes = R.drawable.ic_tangem_24, + size = TangemButtonSize.X10, + state = state, + shape = shape, + ) + } + } + item("outline") { + ButtonSection(title = "Outline") { state, text, shape -> + OutlineTangemButton( + onClick = {}, + text = if (text) stringReference("Continue") else null, + iconRes = R.drawable.ic_tangem_24, + size = TangemButtonSize.X10, + state = state, + shape = shape, + ) + } + } + item("accent") { + ButtonSection(title = "Accent") { state, text, shape -> + AccentTangemButton( + onClick = {}, + text = if (text) stringReference("Continue") else null, + iconRes = R.drawable.ic_tangem_24, + size = TangemButtonSize.X10, + state = state, + shape = shape, + ) + } + } + item("ghost") { + ButtonSection(title = "Ghost") { state, text, shape -> + GhostTangemButton( + onClick = {}, + text = if (text) stringReference("Continue") else null, + iconRes = R.drawable.ic_tangem_24, + size = TangemButtonSize.X10, + state = state, + shape = shape, + ) + } + } + } +} + +@Composable +private fun ButtonSection( + title: String, + background: Color = TangemTheme.colors2.surface.level1, + shapes: List = TangemButtonShape.entries, + button: @Composable (state: TangemButtonState, text: Boolean, shape: TangemButtonShape) -> Unit, +) { + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier + .fillMaxWidth() + .background(background) + .padding(horizontal = 16.dp, vertical = 12.dp), + ) { + Text( + text = title, + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + ) + shapes.forEach { shape -> + ShapeGroup(shape = shape, button = button) + } + } + HorizontalDivider( + color = TangemTheme.colors2.border.neutral.secondary, + modifier = Modifier.padding(horizontal = 16.dp), + ) +} + +@Composable +private fun ShapeGroup( + shape: TangemButtonShape, + button: @Composable (state: TangemButtonState, text: Boolean, shape: TangemButtonShape) -> Unit, +) { + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + Text( + text = shape.name, + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.secondary, + ) + ColumnHeaderRow() + TangemButtonState.entries.forEach { state -> + StateRow(state = state, shape = shape, button = button) + } + } +} + +@Composable +private fun ColumnHeaderRow() { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Spacer(Modifier.width(STATE_LABEL_WIDTH.dp)) + Text( + text = "Text + Icon", + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + modifier = Modifier.weight(1f), + ) + Text( + text = "Icon only", + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + modifier = Modifier.weight(1f), + ) + } +} + +@Composable +private fun StateRow( + state: TangemButtonState, + shape: TangemButtonShape, + button: @Composable (state: TangemButtonState, text: Boolean, shape: TangemButtonShape) -> Unit, +) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = state.name, + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + modifier = Modifier.width(STATE_LABEL_WIDTH.dp), + ) + Box(modifier = Modifier.weight(1f)) { + button(state, true, shape) + } + Box(modifier = Modifier.weight(1f)) { + button(state, false, shape) + } + } +} \ No newline at end of file diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/ui/StoryBookListScreen.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/ui/StoryBookListScreen.kt index ac74e45a74..4dc59eac12 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/ui/StoryBookListScreen.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/ui/StoryBookListScreen.kt @@ -16,11 +16,13 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.tester.presentation.storybook.entity.StoryBookUM import com.tangem.feature.tester.presentation.storybook.entity.StoryPageFactory import com.tangem.feature.tester.presentation.storybook.page.background.northernLightsStoryFactory +import com.tangem.feature.tester.presentation.storybook.page.buttons.buttonsStoryFactory private data class StoryItem(val title: String, val factory: StoryPageFactory) private fun buildStories() = listOf( - StoryItem(title = "Northern Lights Background", factory = northernLightsStoryFactory), + StoryItem(title = "🔘 Buttons", factory = buttonsStoryFactory), + StoryItem(title = "🌌 Northern Lights Background", factory = northernLightsStoryFactory), ) @Composable diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/ui/StoryBookScreen.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/ui/StoryBookScreen.kt index 73e643e0ac..1806965ad7 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/ui/StoryBookScreen.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/ui/StoryBookScreen.kt @@ -4,10 +4,12 @@ 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.NorthernLightsStory 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.page.background.NorthernLightsStory +import com.tangem.feature.tester.presentation.storybook.page.buttons.ButtonsStory @Composable internal fun StoryBookScreen(state: StoryBookUM, modifier: Modifier = Modifier) { @@ -20,6 +22,7 @@ internal fun StoryBookScreen(state: StoryBookUM, modifier: Modifier = Modifier) when (storyState) { StoryList -> StoryBookListScreen(state = state) is NorthernLightsStory -> NorthernLightsStory(state = storyState) + ButtonsStory -> ButtonsStory() } } } \ No newline at end of file