Updated on 2026-08-14
This commit is contained in:
parent
25c5142135
commit
a96fb4b2f4
5 changed files with 255 additions and 30 deletions
|
|
@ -97,6 +97,7 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
|
||||
TokenDetailsScreen(
|
||||
tokenDetailsUM = tokenDetailsUM,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -3,9 +3,12 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui
|
|||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
|
|
@ -15,14 +18,22 @@ import com.tangem.common.ui.notifications.notifications
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.account.AccountIconUM
|
||||
import com.tangem.core.ui.components.BottomFade
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
|
||||
|
|
@ -44,17 +55,22 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDeta
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsBalanceBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsBalanceBlockHeight
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import dev.chrisbanes.haze.HazeProgressive
|
||||
import dev.chrisbanes.haze.HazeTint
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
internal fun TokenDetailsScreen(tokenDetailsUM: TokenDetailsUM, modifier: Modifier = Modifier) {
|
||||
val topAppBarUM = tokenDetailsUM.topAppBarUM
|
||||
private val TopBarHeight: Dp = 64.dp
|
||||
private val MarketBlockHorizontalPadding: Dp = 14.dp
|
||||
|
||||
@Composable
|
||||
internal fun TokenDetailsScreen(
|
||||
tokenDetailsUM: TokenDetailsUM,
|
||||
tokenMarketBlockComponent: TokenMarketBlockComponent?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val statusBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getTop(this).toDp() }
|
||||
val topBarHeight = 64.dp
|
||||
val partialCollapsedHeight = topBarHeight + statusBarHeight
|
||||
val partialCollapsedHeight = TopBarHeight + statusBarHeight
|
||||
val expandedHeight = TokenDetailsBalanceBlockHeight + partialCollapsedHeight
|
||||
|
||||
val behavior = rememberTangemExitUntilCollapsedScrollBehavior(
|
||||
|
|
@ -63,6 +79,7 @@ internal fun TokenDetailsScreen(tokenDetailsUM: TokenDetailsUM, modifier: Modifi
|
|||
)
|
||||
|
||||
val rootBackground by LocalRootBackgroundColor.current
|
||||
var marketBlockHeight by remember { mutableStateOf(0.dp) }
|
||||
val notificationModifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens2.x4)
|
||||
|
|
@ -80,16 +97,18 @@ internal fun TokenDetailsScreen(tokenDetailsUM: TokenDetailsUM, modifier: Modifi
|
|||
collapsingPart = {
|
||||
TokenDetailsBalanceBlock(
|
||||
balanceBlockUM = tokenDetailsUM.balanceBlockUM,
|
||||
behavior = behavior,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.statusBarsPadding()
|
||||
.padding(top = topBarHeight),
|
||||
.padding(top = TopBarHeight),
|
||||
)
|
||||
},
|
||||
body = {
|
||||
TokenDetailsBody(
|
||||
tokenDetailsUM = tokenDetailsUM,
|
||||
rootBackground = rootBackground,
|
||||
bottomContentPadding = marketBlockHeight,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.nestedScroll(behavior.nestedScrollConnection),
|
||||
|
|
@ -99,33 +118,90 @@ internal fun TokenDetailsScreen(tokenDetailsUM: TokenDetailsUM, modifier: Modifi
|
|||
)
|
||||
}
|
||||
|
||||
val hazeIntensity by animateFloatAsState(
|
||||
targetValue = (behavior.state.collapsedFraction * 2f).coerceIn(0f, 1f),
|
||||
label = "TopBarHazeIntensity",
|
||||
TokenDetailsTopBarOverlay(
|
||||
topAppBarUM = tokenDetailsUM.topAppBarUM,
|
||||
collapsedFraction = behavior.state.collapsedFraction,
|
||||
rootBackground = rootBackground,
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier.hazeEffectTangem {
|
||||
fallbackTint = HazeTint(rootBackground.copy(alpha = hazeIntensity / 2f))
|
||||
progressive = HazeProgressive.verticalGradient(
|
||||
startIntensity = hazeIntensity,
|
||||
endIntensity = 0f,
|
||||
preferPerformance = true,
|
||||
)
|
||||
},
|
||||
) {
|
||||
TokenDetailsTopBar(topAppBarUM = topAppBarUM)
|
||||
|
||||
if (tokenMarketBlockComponent != null) {
|
||||
TokenDetailsMarketBlockOverlay(
|
||||
component = tokenMarketBlockComponent,
|
||||
rootBackground = rootBackground,
|
||||
onHeightChange = { marketBlockHeight = it },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenDetailsTopBarOverlay(
|
||||
topAppBarUM: TokenDetailsTopAppBarUM,
|
||||
collapsedFraction: Float,
|
||||
rootBackground: Color,
|
||||
) {
|
||||
val hazeIntensity by animateFloatAsState(
|
||||
targetValue = (collapsedFraction * 2f).coerceIn(0f, 1f),
|
||||
label = "TopBarHazeIntensity",
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier.hazeEffectTangem {
|
||||
fallbackTint = HazeTint(rootBackground.copy(alpha = hazeIntensity / 2f))
|
||||
progressive = HazeProgressive.verticalGradient(
|
||||
startIntensity = hazeIntensity,
|
||||
endIntensity = 0f,
|
||||
preferPerformance = true,
|
||||
)
|
||||
},
|
||||
) {
|
||||
TokenDetailsTopBar(topAppBarUM = topAppBarUM)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.TokenDetailsMarketBlockOverlay(
|
||||
component: TokenMarketBlockComponent,
|
||||
rootBackground: Color,
|
||||
onHeightChange: (Dp) -> Unit,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
|
||||
BottomFade(
|
||||
gradientBrush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
rootBackground.copy(alpha = 0f),
|
||||
rootBackground,
|
||||
),
|
||||
),
|
||||
modifier = Modifier.align(Alignment.BottomCenter),
|
||||
)
|
||||
|
||||
component.Content(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.onSizeChanged { size ->
|
||||
onHeightChange(with(density) { size.height.toDp() })
|
||||
}
|
||||
.navigationBarsPadding()
|
||||
.padding(
|
||||
horizontal = MarketBlockHorizontalPadding,
|
||||
vertical = TangemTheme.dimens2.x1_5,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenDetailsBody(
|
||||
tokenDetailsUM: TokenDetailsUM,
|
||||
rootBackground: Color,
|
||||
bottomContentPadding: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
itemModifier: Modifier = Modifier,
|
||||
) {
|
||||
LazyColumn(modifier = modifier) {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = PaddingValues(bottom = bottomContentPadding),
|
||||
) {
|
||||
notifications(
|
||||
notifications = tokenDetailsUM.notifications,
|
||||
contentColor = rootBackground,
|
||||
|
|
@ -150,6 +226,7 @@ private fun TokenDetailsBody(
|
|||
private fun TokenDetailsScreen_Preview() {
|
||||
TangemThemePreviewRedesign {
|
||||
TokenDetailsScreen(
|
||||
tokenMarketBlockComponent = null,
|
||||
tokenDetailsUM = TokenDetailsUM(
|
||||
topAppBarUM = TokenDetailsTopAppBarUM(
|
||||
titleState = TitleState.WithAccount(
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ 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.alpha
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -31,6 +33,9 @@ import com.tangem.core.ui.ds.button.TangemButtonType
|
|||
import com.tangem.core.ui.ds.button.TangemButtonUM
|
||||
import com.tangem.core.ui.ds.button.action.ActionButtons
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.rememberTangemExitUntilCollapsedScrollBehavior
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.snapToExitUntilCollapsed
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -45,13 +50,26 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
private val CurrencyIconSize: Dp = 70.dp
|
||||
private val NetworkBadgeSize: Dp = 24.dp
|
||||
internal val TokenDetailsBalanceBlockHeight: Dp = 404.dp
|
||||
private const val MIN_SCALE = 0.75f
|
||||
private const val MAX_SCALE = 1f
|
||||
|
||||
@Composable
|
||||
internal fun TokenDetailsBalanceBlock(balanceBlockUM: TokenDetailsBalanceBlockUM, modifier: Modifier = Modifier) {
|
||||
internal fun TokenDetailsBalanceBlock(
|
||||
balanceBlockUM: TokenDetailsBalanceBlockUM,
|
||||
behavior: TangemCollapsingAppBarBehavior,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val rootBackground by LocalRootBackgroundColor.current
|
||||
val collapsedFraction = behavior.state.collapsedFraction
|
||||
val alpha = 1f - collapsedFraction
|
||||
val scale = alpha.coerceIn(MIN_SCALE, MAX_SCALE)
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
.alpha(alpha)
|
||||
.scale(scale)
|
||||
.snapToExitUntilCollapsed(behavior)
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens2.x10),
|
||||
) {
|
||||
|
|
@ -165,6 +183,7 @@ private fun TokenDetailsBalanceBlock_Preview(
|
|||
TangemThemePreviewRedesign {
|
||||
TokenDetailsBalanceBlock(
|
||||
balanceBlockUM = params,
|
||||
behavior = rememberTangemExitUntilCollapsedScrollBehavior(),
|
||||
modifier = Modifier.background(TangemTheme.colors2.surface.level2),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue