Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-04 09:40:55 +02:00
parent 3fe7585ba8
commit d0bc6087fe
34 changed files with 569 additions and 461 deletions

View file

@ -25,13 +25,17 @@ import dev.chrisbanes.haze.HazeTint
* elements and floating button at the bottom of the screen.
*/
@Composable
fun BottomFade(modifier: Modifier = Modifier, backgroundColor: Color = TangemTheme.colors.background.secondary) {
fun BottomFade(
modifier: Modifier = Modifier,
backgroundColor: Color = TangemTheme.colors.background.secondary,
height: Dp = 100.dp,
) {
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
Box(
modifier = modifier
.fillMaxWidth()
.height(TangemTheme.dimens.size100 + bottomBarHeight)
.height(height + bottomBarHeight)
.background(
brush = Brush.verticalGradient(
colors = listOf(

View file

@ -6,12 +6,14 @@ import androidx.compose.material3.CardColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import com.tangem.core.ui.res.TangemTheme
@Composable
fun BlockCard(
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = TangemTheme.shapes.roundedCornersXMedium,
colors: CardColors = TangemBlockCardColors,
onClick: () -> Unit = {},
content: @Composable ColumnScope.() -> Unit = {},
@ -19,7 +21,7 @@ fun BlockCard(
Card(
modifier = modifier,
onClick = onClick,
shape = TangemTheme.shapes.roundedCornersXMedium,
shape = shape,
colors = colors,
enabled = enabled,
content = content,

View file

@ -127,13 +127,13 @@ private fun DescriptionItemV2(
onClick = onReadMoreClick,
),
text = text,
style = TangemTheme.typography2.bodyRegular15,
style = TangemTheme.typography2.bodyMedium16,
)
} else {
Text(
modifier = modifier,
text = description.resolveReference(),
style = TangemTheme.typography2.bodyRegular15,
style = TangemTheme.typography2.bodyMedium16,
color = TangemTheme.colors2.text.neutral.tertiary,
)
}
@ -179,17 +179,17 @@ private fun DescriptionPlaceholderV2(modifier: Modifier = Modifier) {
) {
TextShimmer(
modifier = Modifier.fillMaxWidth(),
style = TangemTheme.typography2.bodyRegular15,
style = TangemTheme.typography2.bodyMedium16,
radius = TangemTheme.dimens2.x25,
)
TextShimmer(
modifier = Modifier.fillMaxWidth(),
style = TangemTheme.typography2.bodyRegular15,
style = TangemTheme.typography2.bodyMedium16,
radius = TangemTheme.dimens2.x25,
)
TextShimmer(
modifier = Modifier.fillMaxWidth(fraction = 0.8f),
style = TangemTheme.typography2.bodyRegular15,
style = TangemTheme.typography2.bodyMedium16,
radius = TangemTheme.dimens2.x25,
)
}

View file

@ -14,20 +14,20 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.*
import com.tangem.core.ui.components.haze.hazeEffectTangem
import com.tangem.core.ui.extensions.conditionalCompose
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.rememberHazeState
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
@ -63,6 +63,7 @@ private val SMALL_DOT_SIZE = DpSize(4.dp, 4.dp)
fun TangemPagerIndicator(
pagerState: PagerState,
modifier: Modifier = Modifier,
hazeState: HazeState = rememberHazeState(),
colors: PagerIndicatorColors = TangemPagerIndicatorColors,
) {
val totalPages = pagerState.pageCount
@ -84,10 +85,12 @@ fun TangemPagerIndicator(
.width(getSize(totalPages))
.conditionalCompose(colors.overlay != null) {
colors.overlay?.let { overlay ->
background(
color = overlay,
shape = CircleShape,
)
this
.clip(CircleShape)
.hazeEffectTangem(hazeState) {
this.blurRadius = 16.dp
backgroundColor = overlay
}
} ?: this
}
.padding(TangemTheme.dimens2.x3),

View file

@ -1,8 +1,10 @@
package com.tangem.core.ui.ds.tabs
import android.content.res.Configuration
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.snap
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -86,7 +88,7 @@ fun TangemSegmentedPicker(
val density = LocalDensity.current
val itemsWidths = remember { mutableStateListOf(*Array(items.size) { 0.dp }) }
val selectedIndex = remember { mutableStateOf(items.indexOfFirstOrNull { it == initialSelectedItem } ?: 0) }
val selectedIndex = remember { mutableIntStateOf(items.indexOfFirstOrNull { it == initialSelectedItem } ?: 0) }
val segmentHeight = remember { mutableStateOf(0.dp) }
val shape = RoundedCornerShape(TangemTheme.dimens2.x25)
@ -105,7 +107,7 @@ fun TangemSegmentedPicker(
) {
SegmentSelection(
itemsWidths = itemsWidths,
selectedIndex = selectedIndex.value,
selectedIndex = selectedIndex.intValue,
segmentHeight = segmentHeight.value,
)
Row(verticalAlignment = Alignment.CenterVertically) {
@ -151,18 +153,30 @@ fun TangemSegmentedPicker(
@Composable
private fun SegmentSelection(itemsWidths: SnapshotStateList<Dp>, selectedIndex: Int, segmentHeight: Dp) {
var hasInitiallyMeasured by remember { mutableStateOf(false) }
val animationSpec: AnimationSpec<Dp> = if (hasInitiallyMeasured) {
tween(durationMillis = 300)
} else {
snap()
}
val indicatorOffset by animateDpAsState(
targetValue = itemsWidths.take(selectedIndex).fold(0.dp, Dp::plus),
animationSpec = tween(durationMillis = 300),
animationSpec = animationSpec,
label = "indicatorOffset",
)
val indicatorWidth by animateDpAsState(
targetValue = itemsWidths[selectedIndex],
animationSpec = tween(durationMillis = 300),
animationSpec = animationSpec,
label = "indicatorWidth",
)
LaunchedEffect(itemsWidths[selectedIndex] > 0.dp) {
if (itemsWidths[selectedIndex] > 0.dp) hasInitiallyMeasured = true
}
Box(
modifier = Modifier
.offset {