From 00c5775f03f4065faf18fbb26f8cd0efc613e35c Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 18 May 2026 15:52:37 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/tap/routing/RootContent.kt | 5 +- .../RoutingTransitionAnimationFactory.kt | 74 ++++++++++++++----- .../tangem/core/ui/components/haze/HazeExt.kt | 4 +- .../ui/ds/button/SecondaryTangemButton.kt | 6 +- .../tangem/core/ui/res/TangemThemeRedesign.kt | 7 +- .../token/block/impl/ui/TokenMarketBlock.kt | 1 + gradle/dependencies.toml | 2 +- 7 files changed, 70 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/routing/RootContent.kt b/app/src/main/java/com/tangem/tap/routing/RootContent.kt index a2701684bf..14f5871bbc 100644 --- a/app/src/main/java/com/tangem/tap/routing/RootContent.kt +++ b/app/src/main/java/com/tangem/tap/routing/RootContent.kt @@ -28,6 +28,7 @@ import com.arkivanov.decompose.value.Value import com.arkivanov.essenty.backhandler.BackHandler import com.tangem.common.routing.AppRoute import com.tangem.core.ui.UiDependencies +import com.tangem.core.ui.components.haze.ProvideHaze import com.tangem.core.ui.components.snackbar.TangemSnackbarHost import com.tangem.core.ui.components.snackbar.TangemTopSnackbarHost import com.tangem.core.ui.message.EventMessageEffect @@ -72,7 +73,9 @@ internal fun RootContent( when (val instance = child.instance) { is RoutingComponent.Child.Initial -> Unit is RoutingComponent.Child.ComposableComponent -> { - instance.component.Content(Modifier.fillMaxSize()) + ProvideHaze { + instance.component.Content(Modifier.fillMaxSize()) + } } is RoutingComponent.Child.LegacyIntent -> { // TODO: Remove and use it's own router: [REDACTED_JIRA] diff --git a/app/src/main/java/com/tangem/tap/routing/transitions/RoutingTransitionAnimationFactory.kt b/app/src/main/java/com/tangem/tap/routing/transitions/RoutingTransitionAnimationFactory.kt index f575967f52..53119a0ccd 100644 --- a/app/src/main/java/com/tangem/tap/routing/transitions/RoutingTransitionAnimationFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/transitions/RoutingTransitionAnimationFactory.kt @@ -4,10 +4,12 @@ import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.FiniteAnimationSpec import androidx.compose.animation.core.tween import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.layout import com.arkivanov.decompose.extensions.compose.stack.animation.* import com.tangem.common.routing.AppRoute +import kotlin.math.abs object RoutingTransitionAnimationFactory { @@ -18,13 +20,15 @@ object RoutingTransitionAnimationFactory { is AppRoute.Home, -> fade(tween(400)).plus(scale(tween(400))) is AppRoute.Wallet, - -> slideAndFade(directions = setOf(Direction.ENTER_BACK, Direction.EXIT_BACK)) - .plus( - scaleWithDirection( - directions = setOf(Direction.ENTER_FRONT, Direction.EXIT_FRONT), - animationSpec = tween(400), - ), - ) + -> slideAndFade( + slideDirections = setOf(Direction.ENTER_BACK, Direction.EXIT_BACK), + fadeDirections = emptySet(), + ).plus( + scaleWithDirection( + directions = setOf(Direction.ENTER_FRONT, Direction.EXIT_FRONT), + animationSpec = tween(400), + ), + ) else -> slideAndFade() } } @@ -52,28 +56,64 @@ object RoutingTransitionAnimationFactory { ) } + /** + * @param slideDirections directions in which the horizontal slide is applied. + * `null` (default) means slide in all directions. + * @param fadeDirections directions in which the alpha fade is applied. + * `null` (default) means fade in all directions. Pass `emptySet()` to disable the fade + * entirely — useful for screens that own a `hazeEffect` (e.g. WalletTopBar's progressive + * blur), where wrapping the screen in an animated `graphicsLayer { alpha = ... }` causes + * a visible blink over the blurred region. + */ @Suppress("MagicNumber") - private fun slideAndFade(directions: Set? = null): StackAnimator { + private fun slideAndFade( + slideDirections: Set? = null, + fadeDirections: Set? = null, + ): StackAnimator { val easing = CubicBezierEasing(a = 0.55f, b = 0.0f, c = 0.0f, d = 1f) - return stackAnimator( + val slide = stackAnimator( animationSpec = tween(durationMillis = 400, easing = easing), ) { factor, direction, content -> content( - if (directions == null || directions.contains(direction)) { + if (slideDirections == null || slideDirections.contains(direction)) { Modifier.offsetXFactor(factor) } else { Modifier }, ) - }.plus( - fade( - animationSpec = tween( - delayMillis = 50, - durationMillis = 300, - easing = easing, - ), + } + + val fade = directionalFade( + animationSpec = tween( + delayMillis = 50, + durationMillis = 300, + easing = easing, ), + directions = fadeDirections, + ) + + return slide.plus(fade) + } + + /** + * Like `decompose.fade(...)` but only applies the alpha `graphicsLayer` when `direction` + * is in [directions]. `null` directions = always fade (matches stock `fade()` behavior). + * `emptySet()` directions = never fade (modifier passes through untouched). + */ + private fun directionalFade( + animationSpec: FiniteAnimationSpec, + directions: Set?, + ): StackAnimator = stackAnimator(animationSpec) { factor, direction, content -> + content( + if (directions == null || directions.contains(direction)) { + Modifier.graphicsLayer { + alpha = 1f - abs(factor) + compositingStrategy = CompositingStrategy.Offscreen + } + } else { + Modifier + }, ) } diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/haze/HazeExt.kt b/core/ui/src/main/java/com/tangem/core/ui/components/haze/HazeExt.kt index 105ff25790..a3438a1798 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/haze/HazeExt.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/haze/HazeExt.kt @@ -14,7 +14,7 @@ import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi @OptIn(ExperimentalHazeMaterialsApi::class) @Composable -internal fun ProvideHaze(content: @Composable () -> Unit) { +fun ProvideHaze(content: @Composable () -> Unit) { val hazeState = rememberHazeState() CompositionLocalProvider( LocalHazeState provides hazeState, @@ -47,7 +47,7 @@ fun isHazeBlurEffectivelyEnabled(state: HazeState = LocalHazeState.current): Boo @Composable fun Modifier.hazeEffectTangem( state: HazeState = LocalHazeState.current, - style: HazeStyle = HazeStyle.Unspecified, + style: HazeStyle = CupertinoMaterials.ultraThin(), configure: HazeEffectScope.() -> Unit = {}, ): Modifier { val isGlobalBlurEnabled = isHazeBlurEffectivelyEnabled(state) diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/button/SecondaryTangemButton.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/button/SecondaryTangemButton.kt index 7ef68a6a28..7eeff08677 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/button/SecondaryTangemButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/button/SecondaryTangemButton.kt @@ -28,7 +28,7 @@ import com.tangem.core.ui.res.TangemThemePreviewRedesign * @param modifier Modifier to be applied to the button. */ @Composable -fun SecondaryTangemButton(buttonUM: TangemButtonUM, modifier: Modifier = Modifier) { +fun SecondaryTangemButton(buttonUM: TangemButtonUM, modifier: Modifier = Modifier, withHazeEffect: Boolean = true) { SecondaryTangemButton( onClick = buttonUM.onClick, modifier = modifier, @@ -40,6 +40,7 @@ fun SecondaryTangemButton(buttonUM: TangemButtonUM, modifier: Modifier = Modifie size = buttonUM.size, shape = buttonUM.shape, onLongClick = buttonUM.onLongClick, + withHazeEffect = withHazeEffect, ) } @@ -70,6 +71,7 @@ fun SecondaryTangemButton( size: TangemButtonSize = TangemButtonSize.X15, shape: TangemButtonShape = TangemButtonShape.Default, onLongClick: (() -> Unit)? = null, + withHazeEffect: Boolean = true, ) { val backgroundModifier = if (isEnabled) { Modifier.background(TangemTheme.colors2.button.backgroundSecondary) @@ -86,7 +88,7 @@ fun SecondaryTangemButton( onClick = onClick, modifier = modifier .clip(shape.toShape(size)) - .hazeEffectTangem() + .then(if (withHazeEffect) Modifier.hazeEffectTangem() else Modifier) .then(backgroundModifier), text = text, contentColor = contentColor, diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemThemeRedesign.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemThemeRedesign.kt index 9fcfadf1f8..f7840693f7 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemThemeRedesign.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemThemeRedesign.kt @@ -2,14 +2,11 @@ package com.tangem.core.ui.res -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.text.selection.LocalTextSelectionColors import androidx.compose.foundation.text.selection.TextSelectionColors import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.* -import androidx.compose.ui.Modifier import com.tangem.core.ui.components.haze.ProvideHaze -import com.tangem.core.ui.components.haze.hazeSourceTangem import com.tangem.core.ui.res.generated.TangemDimens3 import com.tangem.core.ui.res.generated.TangemTypography3 import com.tangem.core.ui.res.generated.darkColors3 @@ -55,9 +52,7 @@ fun TangemThemeRedesign(content: @Composable () -> Unit) { LocalTextSelectionColors provides TangemTextSelectionColors2, ) { ProvideHaze { - Box(Modifier.hazeSourceTangem(zIndex = 1f)) { - content() - } + content() } } } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlock.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlock.kt index 66ce42ea67..d2a8cc8ea6 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlock.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/token/block/impl/ui/TokenMarketBlock.kt @@ -101,6 +101,7 @@ internal fun TokenMarketBlock(tokenMarketBlockUM: TokenMarketBlockUM, modifier: tangemIconUM = TangemIconUM.Icon(iconRes = CoreR.drawable.ic_arrow_expand_24), shape = TangemButtonShape.Rounded, size = TangemButtonSize.X10, + withHazeEffect = false, modifier = Modifier .layoutId(TangemRowLayoutId.TAIL) .padding(start = TangemTheme.dimens2.x10), diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 5c04c70efa..38e75470f6 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -98,7 +98,7 @@ markdown = "0.7.2" markdownComposeView = "0.5.4" usedesk = "4.4.0" sumsub = "1.38.0" -haze = "1.7.1" +haze = "1.7.2" kotlinpoet = "1.18.1" customerio = "4.6.3" surveysparrow = "1.2.9"