diff --git a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/tokenselector/TokenSelectorBottomSheet.kt b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/tokenselector/TokenSelectorBottomSheet.kt index 65ebf6b827..e88de25858 100644 --- a/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/tokenselector/TokenSelectorBottomSheet.kt +++ b/common/ui-markets/src/main/kotlin/com/tangem/common/ui/markets/tokenselector/TokenSelectorBottomSheet.kt @@ -3,6 +3,7 @@ package com.tangem.common.ui.markets.tokenselector import android.content.res.Configuration import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon import androidx.compose.runtime.* @@ -18,6 +19,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.tangem.core.ui.R +import com.tangem.core.ui.components.bottomsheets.LocalBottomSheetContentScrollable import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetType @@ -78,12 +80,24 @@ private fun TokenSelectorContent( } else { topBarHeight } + val listState = rememberLazyListState() + val scrollableSignal = LocalBottomSheetContentScrollable.current + if (scrollableSignal != null) { + LaunchedEffect(listState) { + snapshotFlow { listState.canScrollForward || listState.canScrollBackward } + .collect { canScroll -> scrollableSignal.value = canScroll } + } + DisposableEffect(scrollableSignal) { + onDispose { scrollableSignal.value = true } + } + } Box(modifier = modifier.fillMaxWidth()) { val bottomFadeReserve = if (embedded) 0.dp else TangemTheme.dimens2.x10 val bottomListPadding = bottomFadeReserve + scrollBottomInset val topFadeColor = TangemTheme.colors2.surface.level2.copy(alpha = .95f) LazyColumn( + state = listState, modifier = Modifier .hazeSourceTangem(state = hazeState, 1f) .topFade(height = topBarHeight, color = topFadeColor, solidStop = .6f), diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt index 91b8c9b0b8..a286a52db4 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt @@ -49,6 +49,15 @@ import com.tangem.core.ui.utils.WindowInsetsZero */ val LocalTangemBottomSheetContentBottomInset = compositionLocalOf { 0.dp } +/** + * Provided by [FooterOverlay] so scrollable content under [BasicBottomSheet] can report whether + * it currently scrolls. When set to `false`, [FooterOverlay] omits the bottom fade gradient and + * shrinks [LocalTangemBottomSheetContentBottomInset] accordingly — so content that fits without + * scrolling sits flush above the sticky footer instead of leaving an empty gap. + * Defaults to `null` outside [BasicBottomSheet]; null-check before writing. + */ +val LocalBottomSheetContentScrollable = compositionLocalOf?> { null } + /** * Type of [TangemBottomSheet] that defines its behavior and appearance. * - [Default]: Standard bottom sheet with a draggable header @@ -290,7 +299,8 @@ fun BoxScope.FooterOverlay( content: @Composable () -> Unit, ) { val density = LocalDensity.current - val gradientHeight = TangemTheme.dimens2.x10 + val isContentScrollable = remember { mutableStateOf(true) } + val gradientHeight = if (isContentScrollable.value) TangemTheme.dimens2.x10 else 0.dp val isFooterRendered = measuredFooterHeight == null || measuredFooterHeight > 0.dp val contentBottomOverlayHeight = if (isFooterRendered) { (measuredFooterHeight ?: 0.dp) + gradientHeight @@ -300,6 +310,7 @@ fun BoxScope.FooterOverlay( val fadeMax = TangemTheme.colors2.surface.level2 CompositionLocalProvider( LocalTangemBottomSheetContentBottomInset provides contentBottomOverlayHeight, + LocalBottomSheetContentScrollable provides isContentScrollable, ) { content() } @@ -309,10 +320,12 @@ fun BoxScope.FooterOverlay( .fillMaxWidth() .align(Alignment.BottomCenter), ) { - Fade( - backgroundColor = fadeMax, - height = gradientHeight, - ) + if (gradientHeight > 0.dp) { + Fade( + backgroundColor = fadeMax, + height = gradientHeight, + ) + } Spacer( modifier = Modifier .fillMaxWidth() diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/sheetscaffold/TangemBottomSheetScaffold.kt b/core/ui/src/main/java/com/tangem/core/ui/components/sheetscaffold/TangemBottomSheetScaffold.kt index 814bd40232..06e001abfc 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/sheetscaffold/TangemBottomSheetScaffold.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/sheetscaffold/TangemBottomSheetScaffold.kt @@ -269,7 +269,7 @@ internal fun Modifier.bottomSheetDraggableAnchor( if (!state.skipPartiallyExpanded) { PartiallyExpanded at (layoutHeight - peekHeightPx) } - if (sheetHeight != peekHeightPx) { + if (state.skipPartiallyExpanded || sheetHeight != peekHeightPx) { Expanded at maxOf(layoutHeight - sheetHeight, 0f) } if (!state.skipHiddenState) { diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/tabs/TangemSegmentedPicker.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/tabs/TangemSegmentedPicker.kt index 7483bad306..c889e863df 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/tabs/TangemSegmentedPicker.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/tabs/TangemSegmentedPicker.kt @@ -1,11 +1,7 @@ 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.animation.core.* import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -21,6 +17,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider @@ -109,6 +106,7 @@ fun TangemSegmentedPicker( itemsWidths = itemsWidths, selectedIndex = selectedIndex.intValue, segmentHeight = segmentHeight.value, + separatorWidth = SEPARATOR_WIDTH, ) Row(verticalAlignment = Alignment.CenterVertically) { items.fastForEachIndexed { index, item -> @@ -139,7 +137,7 @@ fun TangemSegmentedPicker( Box( Modifier .alpha(alpha) - .width(0.5.dp) + .width(SEPARATOR_WIDTH) .height(20.dp) .background( color = TangemTheme.colors2.border.neutral.tertiary.copy(alpha = 0.1f), @@ -151,8 +149,15 @@ fun TangemSegmentedPicker( } } +private val SEPARATOR_WIDTH = 0.5.dp + @Composable -private fun SegmentSelection(itemsWidths: SnapshotStateList, selectedIndex: Int, segmentHeight: Dp) { +private fun SegmentSelection( + itemsWidths: SnapshotStateList, + selectedIndex: Int, + segmentHeight: Dp, + separatorWidth: Dp, +) { var hasInitiallyMeasured by remember { mutableStateOf(false) } val animationSpec: AnimationSpec = if (hasInitiallyMeasured) { @@ -162,7 +167,7 @@ private fun SegmentSelection(itemsWidths: SnapshotStateList, selectedIndex: } val indicatorOffset by animateDpAsState( - targetValue = itemsWidths.take(selectedIndex).fold(0.dp, Dp::plus), + targetValue = itemsWidths.take(selectedIndex).fold(0.dp, Dp::plus) + separatorWidth * selectedIndex, animationSpec = animationSpec, label = "indicatorOffset", ) @@ -216,6 +221,7 @@ private fun RowScope.Segment( selectedIndex.value = index onClick() }, + contentAlignment = Alignment.Center, ) { Text( text = item.title.resolveReference(), @@ -226,6 +232,7 @@ private fun RowScope.Segment( TangemTheme.colors2.tabs.textSecondary }, maxLines = 1, + textAlign = TextAlign.Center, modifier = Modifier .align(Alignment.Center) .padding( diff --git a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/AddToPortfolioBottomSheetV2.kt b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/AddToPortfolioBottomSheetV2.kt index 866fc6456c..89f444dc04 100644 --- a/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/AddToPortfolioBottomSheetV2.kt +++ b/features/common-features/impl/src/main/java/com/tangem/features/commonfeatures/impl/addtoportfolio/AddToPortfolioBottomSheetV2.kt @@ -1,9 +1,6 @@ package com.tangem.features.commonfeatures.impl.addtoportfolio import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState @@ -63,18 +60,12 @@ internal fun AddToPortfolioBottomSheetV2( } }, footer = { - AnimatedContent( - targetState = contentStack.value.active.configuration, - transitionSpec = { fadeIn() togetherWith fadeOut() }, - label = "Footer Animation", - ) { route -> - AddToPortfolioBottomSheetFooter( - currentRoute = route, - userPortfolioState = userPortfolioState, - onBack = onBack, - onAddFromUserPortfolioClick = onAddFromUserPortfolioClick, - ) - } + AddToPortfolioBottomSheetFooter( + currentRoute = contentStack.value.active.configuration, + userPortfolioState = userPortfolioState, + onBack = onBack, + onAddFromUserPortfolioClick = onAddFromUserPortfolioClick, + ) }, ) } diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/BlockHeader.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/BlockHeader.kt index 5c9fc72db8..0fe962de35 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/BlockHeader.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/feed/components/BlockHeader.kt @@ -32,7 +32,7 @@ internal fun ColumnScope.Header( ) { val isRedesignEnabled = LocalRedesignEnabled.current if (isRedesignEnabled) { - SpacerH(16.dp) + SpacerH(12.dp) } AnimatedContent(isLoading) { animatedState -> Row( diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/MetricsCards.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/MetricsCards.kt index c61808563d..04ac27ab73 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/MetricsCards.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/MetricsCards.kt @@ -130,8 +130,8 @@ internal fun MarketPositionCard(item: InfoPointUMV2.MarketPosition) { .fillMaxWidth() .height(6.dp), progress = { item.rangeValue }, - dotColor = TangemTheme.colors2.fill.neutral.primaryInvertedConstant, - backgroundColor = TangemTheme.colors2.graphic.neutral.primaryInvertedConstant.copy(alpha = .1f), + dotColor = TangemTheme.colors3.icon.primary, + backgroundColor = TangemTheme.colors3.bg.opaque.secondary, ) } SpacerH(12.dp)