Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-05 14:55:31 +05:00
commit 3ae32901d4
30 changed files with 992 additions and 282 deletions

View file

@ -43,4 +43,14 @@ internal data class NorthernLightsStory(
internal data class TangemTokenRowStory(
val isBalanceHidden: Boolean,
val onBalanceHiddenToggle: () -> Unit,
) : StoryBookPage
internal data class TangemContextMenuStory(
val isExpanded: Boolean,
val onExpandedChange: (Boolean) -> Unit,
) : StoryBookPage
internal data class TangemHeaderRowStory(
val isBalanceHidden: Boolean,
val onBalanceHiddenToggle: () -> Unit,
) : StoryBookPage

View file

@ -0,0 +1,17 @@
package com.tangem.feature.tester.presentation.storybook.page.contextmenu
import com.tangem.feature.tester.presentation.storybook.entity.TangemContextMenuStory
import com.tangem.feature.tester.presentation.storybook.viewmodel.StateUpdater
import com.tangem.feature.tester.presentation.storybook.viewmodel.storyPageFactory
internal fun StateUpdater<TangemContextMenuStory>.build(): TangemContextMenuStory {
return TangemContextMenuStory(
isExpanded = false,
onExpandedChange = { expanded ->
updateStory { it.copy(isExpanded = expanded) }
},
)
}
internal val tangemContextMenuStoryFactory
get() = storyPageFactory(StateUpdater<TangemContextMenuStory>::build)

View file

@ -0,0 +1,80 @@
package com.tangem.feature.tester.presentation.storybook.page.contextmenu
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.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.haze.hazeEffectTangem
import com.tangem.core.ui.components.haze.hazeSourceTangem
import com.tangem.core.ui.ds.contextmenu.TangemContextMenu
import com.tangem.core.ui.ds.contextmenu.TangemContextMenuCheckboxItem
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.res.TangemTheme
import dev.chrisbanes.haze.rememberHazeState
import com.tangem.feature.tester.presentation.storybook.entity.TangemContextMenuStory as TangemContextMenuStoryState
@Composable
internal fun TangemContextMenuStory(state: TangemContextMenuStoryState, modifier: Modifier = Modifier) {
val hazeState = rememberHazeState()
LazyColumn(
contentPadding = PaddingValues(vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier
.statusBarsPadding()
.fillMaxSize()
.background(TangemTheme.colors2.surface.level1)
.hazeSourceTangem(state = hazeState, zIndex = -1f),
) {
item("context_menu") {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
) {
Text(
text = "TangemContextMenu",
style = TangemTheme.typography2.headingSemibold17,
color = TangemTheme.colors2.text.neutral.primary,
)
Box {
PrimaryButton(
text = "Show Context Menu",
onClick = { state.onExpandedChange(true) },
)
TangemContextMenu(
expanded = state.isExpanded,
onDismissRequest = { state.onExpandedChange(false) },
offset = DpOffset(0.dp, 4.dp),
modifier = Modifier.hazeEffectTangem(hazeState),
) {
TangemContextMenuCheckboxItem(
title = TextReference.Str("Sort by balance"),
isChecked = true,
onClick = {},
)
HorizontalDivider(
thickness = 0.5.dp,
color = TangemTheme.colors2.border.neutral.quaternary,
)
TangemContextMenuCheckboxItem(
title = TextReference.Str("Group tokens"),
isChecked = false,
onClick = {},
)
}
}
}
}
}
}

View file

@ -0,0 +1,17 @@
@file:Suppress("MagicNumber", "LongMethod")
package com.tangem.feature.tester.presentation.storybook.page.headerrow
import com.tangem.feature.tester.presentation.storybook.entity.TangemHeaderRowStory
import com.tangem.feature.tester.presentation.storybook.viewmodel.StateUpdater
import com.tangem.feature.tester.presentation.storybook.viewmodel.storyPageFactory
internal fun StateUpdater<TangemHeaderRowStory>.build(): TangemHeaderRowStory {
return TangemHeaderRowStory(
isBalanceHidden = false,
onBalanceHiddenToggle = { updateStory { it.copy(isBalanceHidden = !it.isBalanceHidden) } },
)
}
internal val tangemHeaderRowStoryFactory
get() = storyPageFactory(StateUpdater<TangemHeaderRowStory>::build)

View file

@ -0,0 +1,111 @@
@file:Suppress("MagicNumber", "LongMethod")
package com.tangem.feature.tester.presentation.storybook.page.headerrow
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
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.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.R
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.row.header.TangemHeaderRow
import com.tangem.core.ui.ds.row.header.TangemHeaderRowUM
import com.tangem.core.ui.ds.row.internal.TangemRowTailUM
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.tester.presentation.storybook.entity.TangemHeaderRowStory
@Composable
internal fun TangemHeaderRowStory(state: TangemHeaderRowStory, modifier: Modifier = Modifier) {
val rows = remember { buildSampleRows() }
LazyColumn(
contentPadding = PaddingValues(bottom = 16.dp),
modifier = modifier
.statusBarsPadding()
.fillMaxSize()
.background(TangemTheme.colors2.surface.level1),
) {
stickyHeader("balance_toggle") {
BalanceToggle(
isHidden = state.isBalanceHidden,
onToggle = state.onBalanceHiddenToggle,
modifier = Modifier
.fillMaxWidth()
.background(TangemTheme.colors2.surface.level1)
.padding(horizontal = 16.dp, vertical = 8.dp),
)
}
items(rows, key = { it.id }) { um ->
TangemHeaderRow(
headerRowUM = um,
isBalanceHidden = state.isBalanceHidden,
modifier = Modifier.background(TangemTheme.colors2.surface.level3),
)
HorizontalDivider(
color = TangemTheme.colors2.border.neutral.secondary,
modifier = Modifier.padding(start = 16.dp),
)
}
}
}
private fun buildSampleRows(): List<TangemHeaderRowUM> = listOf(
TangemHeaderRowUM(
id = "icon_subtitle_no_tail",
startIconUM = TangemIconUM.Currency(currencyIconState = CurrencyIconState.Locked),
tailUM = TangemRowTailUM.Empty,
title = stringReference("Account"),
subtitle = stringReference("\$ 42,900.17"),
),
TangemHeaderRowUM(
id = "icon_subtitle_collapse",
startIconUM = TangemIconUM.Currency(currencyIconState = CurrencyIconState.Locked),
tailUM = TangemRowTailUM.Icon(R.drawable.ic_arrow_collapse_24),
title = stringReference("Account"),
subtitle = stringReference("\$ 42,900.17"),
),
TangemHeaderRowUM(
id = "icon_subtitle_group_drop",
startIconUM = TangemIconUM.Currency(currencyIconState = CurrencyIconState.Locked),
tailUM = TangemRowTailUM.Icon(R.drawable.ic_group_drop_24),
title = stringReference("Account"),
subtitle = stringReference("\$ 42,900.17"),
),
TangemHeaderRowUM(
id = "title_only",
title = stringReference("Account"),
),
)
@Composable
private fun BalanceToggle(isHidden: Boolean, onToggle: () -> Unit, modifier: Modifier = Modifier) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = modifier,
) {
Text(
text = "isBalanceHidden",
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
)
Switch(checked = isHidden, onCheckedChange = { onToggle() })
}
}

View file

@ -1,4 +1,5 @@
@file:Suppress("MagicNumber", "LongMethod")
package com.tangem.feature.tester.presentation.storybook.page.tokenrow
import androidx.compose.foundation.background
@ -44,7 +45,7 @@ internal fun TangemTokenRowStory(state: TangemTokenRowStory, modifier: Modifier
TangemTokenRow(
tokenRowUM = um,
isBalanceHidden = state.isBalanceHidden,
reorderableTokenListState = null,
reorderableState = null,
modifier = Modifier.background(TangemTheme.colors2.surface.level1),
)
HorizontalDivider(

View file

@ -18,9 +18,11 @@ 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.badge.tangemBadgeStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.buttons.buttonsStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.opportunities.opportunitiesBGStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.message.tangemMessageStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.checkbox.tangemCheckboxStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.contextmenu.tangemContextMenuStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.headerrow.tangemHeaderRowStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.message.tangemMessageStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.opportunities.opportunitiesBGStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.tabs.tangemSegmentedPickerStoryFactory
import com.tangem.feature.tester.presentation.storybook.page.tokenrow.tangemTokenRowStoryFactory
@ -35,6 +37,8 @@ private fun buildStories() = listOf(
StoryItem(title = "🗂️ Segmented Picker", factory = tangemSegmentedPickerStoryFactory),
StoryItem(title = "☑️ Checkbox", factory = tangemCheckboxStoryFactory),
StoryItem(title = "🪙 Token Row", factory = tangemTokenRowStoryFactory),
StoryItem(title = "📑 Header Row", factory = tangemHeaderRowStoryFactory),
StoryItem(title = "📋 Context Menu", factory = tangemContextMenuStoryFactory),
)
@Composable

View file

@ -11,6 +11,8 @@ import com.tangem.feature.tester.presentation.storybook.entity.TangemBadgeStory
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.TangemContextMenuStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemMessageStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemSegmentedPickerStory
import com.tangem.feature.tester.presentation.storybook.entity.TangemTokenRowStory
@ -22,6 +24,8 @@ import com.tangem.feature.tester.presentation.storybook.page.checkbox.TangemChec
import com.tangem.feature.tester.presentation.storybook.page.message.TangemMessageStory
import com.tangem.feature.tester.presentation.storybook.page.tabs.TangemSegmentedPickerStory
import com.tangem.feature.tester.presentation.storybook.page.tokenrow.TangemTokenRowStory
import com.tangem.feature.tester.presentation.storybook.page.headerrow.TangemHeaderRowStory
import com.tangem.feature.tester.presentation.storybook.page.contextmenu.TangemContextMenuStory
@Composable
internal fun StoryBookScreen(state: StoryBookUM, modifier: Modifier = Modifier) {
@ -42,6 +46,8 @@ internal fun StoryBookScreen(state: StoryBookUM, modifier: Modifier = Modifier)
is TangemCheckboxStory -> TangemCheckboxStory(state = storyState)
TangemSegmentedPickerStory -> TangemSegmentedPickerStory()
is TangemTokenRowStory -> TangemTokenRowStory(state = storyState)
is TangemHeaderRowStory -> TangemHeaderRowStory(state = storyState)
is TangemContextMenuStory -> TangemContextMenuStory(state = storyState)
}
}
}