Updated on 2026-08-14
This commit is contained in:
parent
3acfadfb08
commit
164030dc9c
5 changed files with 442 additions and 19 deletions
|
|
@ -0,0 +1,193 @@
|
|||
package com.tangem.core.ui.components.block.information
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.SecondarySmallButton
|
||||
import com.tangem.core.ui.components.buttons.SmallButtonConfig
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.components.text.TooltipText
|
||||
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.TangemThemePreview
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Immutable
|
||||
class InformationBlockContentScope(val scope: BoxScope) : BoxScope by scope
|
||||
|
||||
@Composable
|
||||
fun InformationBlock(
|
||||
title: @Composable BoxScope.() -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
action: (@Composable BoxScope.() -> Unit)? = null,
|
||||
content: (@Composable InformationBlockContentScope.() -> Unit)? = null,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(color = TangemTheme.colors.background.action),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.size40)
|
||||
.padding(
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
bottom = TangemTheme.dimens.spacing6,
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(weight = 1f)
|
||||
.heightIn(min = TangemTheme.dimens.size20),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
content = title,
|
||||
)
|
||||
if (action != null) {
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.spacing8))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(weight = 1f)
|
||||
.heightIn(min = TangemTheme.dimens.size24),
|
||||
contentAlignment = Alignment.CenterEnd,
|
||||
content = action,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (content != null) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
val scope = InformationBlockContentScope(scope = this)
|
||||
content(scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Previews
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 328)
|
||||
@Preview(showBackground = true, widthDp = 328, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_Grid() {
|
||||
TangemThemePreview {
|
||||
InformationBlock(
|
||||
title = {
|
||||
TooltipText(
|
||||
text = stringReference("Grid title"),
|
||||
onInfoClick = { },
|
||||
)
|
||||
},
|
||||
content = {
|
||||
GridItems(
|
||||
items = persistentListOf(
|
||||
stringReference("Fist item"),
|
||||
stringReference("Second item"),
|
||||
),
|
||||
itemContent = {
|
||||
PreviewItem(text = it)
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 328)
|
||||
@Preview(showBackground = true, widthDp = 328, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_List() {
|
||||
TangemThemePreview {
|
||||
InformationBlock(
|
||||
title = {
|
||||
Text(
|
||||
text = "List",
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
},
|
||||
action = {
|
||||
SecondarySmallButton(
|
||||
config = SmallButtonConfig(
|
||||
text = stringReference("Add token"),
|
||||
icon = TangemButtonIconPosition.Start(R.drawable.ic_plus_24),
|
||||
onClick = {},
|
||||
),
|
||||
)
|
||||
},
|
||||
content = {
|
||||
ListItems(
|
||||
items = persistentListOf(
|
||||
stringReference("Fist item"),
|
||||
stringReference("Second item"),
|
||||
),
|
||||
itemContent = {
|
||||
PreviewItem(it)
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 328)
|
||||
@Preview(showBackground = true, widthDp = 328, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_Plain() {
|
||||
TangemThemePreview {
|
||||
InformationBlock(
|
||||
title = {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
|
||||
) {
|
||||
TooltipText(
|
||||
text = stringReference("Title"),
|
||||
onInfoClick = { /* [REDACTED_TODO_COMMENT]*/ },
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "Subtitle",
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
},
|
||||
action = {
|
||||
PreviewItem(text = stringReference("Action"))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreviewItem(text: TextReference) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.padding(all = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
Text(
|
||||
text = text.resolveReference(),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package com.tangem.core.ui.components.block.information
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Composable
|
||||
fun <T : Any> InformationBlockContentScope.ListItems(
|
||||
items: ImmutableList<T>,
|
||||
itemContent: @Composable BoxScope.(T) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.padding(vertical = TangemTheme.dimens.spacing8)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8, Alignment.Top),
|
||||
) {
|
||||
items.fastForEach { item ->
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
itemContent(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun <T : Any> InformationBlockContentScope.GridItems(
|
||||
items: ImmutableList<T>,
|
||||
itemContent: @Composable BoxScope.(T) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val rowItems by remember(items) {
|
||||
derivedStateOf {
|
||||
items.asSequence()
|
||||
.windowed(size = 2, step = 2, partialWindows = true)
|
||||
.map { it.toImmutableList() }
|
||||
.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Top,
|
||||
) {
|
||||
rowItems.fastForEach { row ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(vertical = TangemTheme.dimens.spacing8)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.Top,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12, Alignment.Start),
|
||||
) {
|
||||
row.fastForEach { item ->
|
||||
Box(
|
||||
modifier = Modifier.weight(1f),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
itemContent(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,17 +6,21 @@ import androidx.compose.foundation.background
|
|||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
/**
|
||||
* Small button config
|
||||
|
|
@ -28,6 +32,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
data class SmallButtonConfig(
|
||||
val text: TextReference,
|
||||
val onClick: () -> Unit,
|
||||
val icon: TangemButtonIconPosition = TangemButtonIconPosition.None,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
@ -61,13 +66,12 @@ private fun SmallButton(config: SmallButtonConfig, isPrimary: Boolean, modifier:
|
|||
label = "Update background color",
|
||||
)
|
||||
|
||||
val textColor by animateColorAsState(
|
||||
targetValue = if (isPrimary) TangemTheme.colors.text.primary2 else TangemTheme.colors.text.primary1,
|
||||
label = "Update text color",
|
||||
)
|
||||
Box(
|
||||
Row(
|
||||
modifier = modifier
|
||||
.defaultMinSize(minWidth = TangemTheme.dimens.size46, minHeight = TangemTheme.dimens.size24)
|
||||
.defaultMinSize(
|
||||
minWidth = TangemTheme.dimens.size46,
|
||||
minHeight = TangemTheme.dimens.size24,
|
||||
)
|
||||
.clip(shape)
|
||||
.background(
|
||||
color = backgroundColor,
|
||||
|
|
@ -75,22 +79,68 @@ private fun SmallButton(config: SmallButtonConfig, isPrimary: Boolean, modifier:
|
|||
)
|
||||
.clickable(enabled = true, onClick = config.onClick)
|
||||
.padding(
|
||||
vertical = TangemTheme.dimens.spacing2,
|
||||
paddingValues = when (config.icon) {
|
||||
is TangemButtonIconPosition.None -> PaddingValues(
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
)
|
||||
is TangemButtonIconPosition.End -> PaddingValues(
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing8,
|
||||
)
|
||||
is TangemButtonIconPosition.Start -> PaddingValues(
|
||||
start = TangemTheme.dimens.spacing8,
|
||||
end = TangemTheme.dimens.spacing12,
|
||||
)
|
||||
},
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = TangemTheme.dimens.spacing10,
|
||||
),
|
||||
text = config.text.resolveReference(),
|
||||
color = textColor,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.button,
|
||||
ContentContainer(
|
||||
iconPosition = config.icon,
|
||||
text = {
|
||||
val textColor by animateColorAsState(
|
||||
targetValue = if (isPrimary) TangemTheme.colors.text.primary2 else TangemTheme.colors.text.primary1,
|
||||
label = "Update text color",
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing4),
|
||||
text = config.text.resolveReference(),
|
||||
color = textColor,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.button,
|
||||
)
|
||||
},
|
||||
icon = { iconResId ->
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size16),
|
||||
painter = painterResource(id = iconResId),
|
||||
tint = TangemTheme.colors.icon.secondary,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.ContentContainer(
|
||||
iconPosition: TangemButtonIconPosition,
|
||||
text: @Composable RowScope.() -> Unit,
|
||||
icon: @Composable RowScope.(Int) -> Unit,
|
||||
) {
|
||||
if (iconPosition is TangemButtonIconPosition.Start) {
|
||||
icon(iconPosition.iconResId)
|
||||
Spacer(modifier = Modifier.requiredWidth(TangemTheme.dimens.spacing4))
|
||||
}
|
||||
text()
|
||||
if (iconPosition is TangemButtonIconPosition.End) {
|
||||
Spacer(modifier = Modifier.requiredWidth(TangemTheme.dimens.spacing4))
|
||||
icon(iconPosition.iconResId)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
|
|
@ -112,5 +162,17 @@ private fun ButtonsSample() {
|
|||
)
|
||||
PrimarySmallButton(config = config)
|
||||
SecondarySmallButton(config = config.copy(text = TextReference.Str(value = "Add")))
|
||||
SecondarySmallButton(
|
||||
config = config.copy(
|
||||
text = TextReference.Str(value = "Rating"),
|
||||
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_chevron_24),
|
||||
),
|
||||
)
|
||||
SecondarySmallButton(
|
||||
config = config.copy(
|
||||
text = TextReference.Str(value = "Add token"),
|
||||
icon = TangemButtonIconPosition.Start(iconResId = R.drawable.ic_plus_24),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import androidx.compose.runtime.State
|
|||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
class TangemButtonColors(
|
||||
data class TangemButtonColors(
|
||||
private val backgroundColor: Color,
|
||||
private val contentColor: Color,
|
||||
private val disabledBackgroundColor: Color,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
package com.tangem.core.ui.components.text
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
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.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
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.TangemThemePreview
|
||||
|
||||
@Composable
|
||||
fun TooltipText(
|
||||
text: TextReference,
|
||||
onInfoClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
useSmallerText: Boolean = false,
|
||||
) {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.clickable(
|
||||
interactionSource = interactionSource,
|
||||
indication = null,
|
||||
onClick = onInfoClick,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceAround,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
text = text.resolveReference(),
|
||||
style = if (useSmallerText) {
|
||||
TangemTheme.typography.caption2
|
||||
} else {
|
||||
TangemTheme.typography.subtitle2
|
||||
},
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier.requiredSize(TangemTheme.dimens.size24),
|
||||
interactionSource = interactionSource,
|
||||
onClick = onInfoClick,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size16),
|
||||
painter = painterResource(id = R.drawable.ic_information_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_TooltipText() {
|
||||
TangemThemePreview {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(width = 90.dp)
|
||||
.background(color = TangemTheme.colors.background.primary),
|
||||
) {
|
||||
TooltipText(
|
||||
text = stringReference("Text"),
|
||||
onInfoClick = { /* [REDACTED_TODO_COMMENT]*/ },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion Preview
|
||||
Loading…
Add table
Add a link
Reference in a new issue