diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/image/TangemIconUM.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/image/TangemIconUM.kt index a1f0c98b5b..f6ec4b82e1 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/image/TangemIconUM.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/image/TangemIconUM.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Immutable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest @@ -74,7 +75,7 @@ fun TangemIcon(tangemIconUM: TangemIconUM, modifier: Modifier = Modifier) { tint = tangemIconUM.tintReference(), ) is TangemIconUM.Image -> Image( - imageVector = ImageVector.vectorResource(tangemIconUM.imageRes), + painter = painterResource(tangemIconUM.imageRes), contentDescription = null, modifier = modifier, ) diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessage.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessage.kt index 86d955f2d9..01edf7ce54 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessage.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessage.kt @@ -66,7 +66,7 @@ fun TangemMessage( Alignment.Top }, ) - .size(TangemTheme.dimens2.x7), + .size(messageUM.iconSize), ) } }, diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageEffect.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageEffect.kt index 03b00e793a..8b11ea19ec 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageEffect.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageEffect.kt @@ -6,10 +6,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithContent @@ -25,6 +22,7 @@ import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.haze.hazeForegroundEffectTangem import com.tangem.core.ui.extensions.conditionalCompose import com.tangem.core.ui.res.LocalIsInDarkTheme +import com.tangem.core.ui.res.LocalMessageEffectAnimation import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign import com.tangem.core.ui.utils.toPx @@ -33,6 +31,10 @@ import dev.chrisbanes.haze.HazeTint import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf +data class MessageEffectAnimation( + val offsetState: State, +) + /** * Different visual effects for [Tangem message component]. */ @@ -222,7 +224,6 @@ enum class TangemMessageEffect(val isAnimatable: Boolean) { } } - // todo redesign replace with proper color when design is ready @Suppress("MagicNumber") fun fallbackColor(isInDarkTheme: Boolean): Color { return when (this) { @@ -242,12 +243,16 @@ internal fun Modifier.messageEffectBackground( contentColor: Color, ): Modifier { val isInDarkTheme = LocalIsInDarkTheme.current - val borderGradientColors = remember { messageEffect.getBorderGradient(isInDarkTheme) } - val gradientColors = remember { messageEffect.getColorGradient(isInDarkTheme) } - val gradientTint = remember { messageEffect.getGradientTint(isInDarkTheme) } + val borderGradientColors = remember(messageEffect, isInDarkTheme) { messageEffect.getBorderGradient(isInDarkTheme) } + val gradientColors = remember(messageEffect, isInDarkTheme) { messageEffect.getColorGradient(isInDarkTheme) } + val gradientTint = remember(messageEffect, isInDarkTheme) { messageEffect.getGradientTint(isInDarkTheme) } - val angle by rememberAnimationAngle(messageEffect.isAnimatable) - val brush = remember { Brush.sweepGradient(messageEffect.getColorGradient(isInDarkTheme)) } + val angle by if (messageEffect.isAnimatable) { + LocalMessageEffectAnimation.current.offsetState + } else { + remember { mutableFloatStateOf(0f) } + } + val brush = remember(gradientColors) { Brush.sweepGradient(gradientColors) } val padding = 1.dp.toPx() return this @@ -278,12 +283,14 @@ internal fun Modifier.messageEffectBackground( } .conditionalCompose(gradientColors.isNotEmpty()) { drawWithContent { - rotate(angle) { - drawCircle( - brush = brush, - radius = size.width, - blendMode = BlendMode.SrcIn, - ) + if (messageEffect.isAnimatable) { + rotate(angle) { + drawCircle( + brush = brush, + radius = size.width, + blendMode = BlendMode.SrcIn, + ) + } } drawRect( color = contentColor, @@ -296,9 +303,9 @@ internal fun Modifier.messageEffectBackground( } @Composable -private fun rememberAnimationAngle(isAnimatable: Boolean) = if (isAnimatable) { +internal fun rememberMessageEffectAnimationAngle(): MessageEffectAnimation { val infiniteTransition = rememberInfiniteTransition() - infiniteTransition.animateFloat( + val offsetState = infiniteTransition.animateFloat( initialValue = 0f, targetValue = 360f, animationSpec = infiniteRepeatable( @@ -306,8 +313,10 @@ private fun rememberAnimationAngle(isAnimatable: Boolean) = if (isAnimatable) { repeatMode = RepeatMode.Restart, ), ) -} else { - remember { mutableFloatStateOf(0f) } + + return remember(offsetState) { + MessageEffectAnimation(offsetState) + } } // region Preview diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageUM.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageUM.kt index 3015a07e46..acaabc9b54 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageUM.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageUM.kt @@ -1,6 +1,8 @@ package com.tangem.core.ui.ds.message import androidx.annotation.DrawableRes +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import com.tangem.core.ui.ds.button.* import com.tangem.core.ui.ds.image.TangemIconUM import com.tangem.core.ui.extensions.TextReference @@ -10,12 +12,16 @@ import kotlinx.collections.immutable.persistentListOf /** * Data model representing the properties of a Tangem message. * + * @param id Unique identifier for the message. * @param title TextReference for the message title. * @param subtitle TextReference for the message subtitle. * @param messageEffect TangemMessageEffect defining the visual effect of the message. + * @param iconUM Optional TangemIconUM representing the icon to be displayed in the message. + * @param iconSize Dp value defining the size of the icon (default is 28.dp). * @param isCentered Boolean indicating whether the icon is centered. * @param buttonsUM ImmutableList of TangemMessageButtonUM representing the buttons in the message. - * @param onCloseClick Lambda to be invoked when the close button is clicked (optional + * @param onClick Lambda to be invoked when the message is clicked (optional). + * @param onCloseClick Lambda to be invoked when the close button is clicked (optional). */ data class TangemMessageUM( val id: String, @@ -23,6 +29,7 @@ data class TangemMessageUM( val subtitle: TextReference, val messageEffect: TangemMessageEffect = TangemMessageEffect.None, val iconUM: TangemIconUM? = null, + val iconSize: Dp = 28.dp, val isCentered: Boolean = false, val buttonsUM: ImmutableList = persistentListOf(), val onClick: (() -> Unit)? = null, diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemTheme.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemTheme.kt index 46b8751e71..cb9dc458ca 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemTheme.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemTheme.kt @@ -23,6 +23,8 @@ import com.tangem.core.ui.components.powersaving.rememberPowerSavingState import com.tangem.core.ui.components.snackbar.TangemTopSnackbarHostState import com.tangem.core.ui.components.text.BladeAnimation import com.tangem.core.ui.components.text.rememberBladeAnimation +import com.tangem.core.ui.ds.message.MessageEffectAnimation +import com.tangem.core.ui.ds.message.rememberMessageEffectAnimationAngle import com.tangem.core.ui.haptic.DefaultHapticManager import com.tangem.core.ui.haptic.HapticManager import com.tangem.core.ui.haptic.VibratorHapticManager @@ -128,6 +130,7 @@ fun TangemTheme( LocalBladeAnimation provides rememberBladeAnimation(), LocalSystemBarsIconsController provides systemBarsIconsController, LocalPowerSavingState provides rememberPowerSavingState(), + LocalMessageEffectAnimation provides rememberMessageEffectAnimationAngle(), ) { CompositionLocalProvider( LocalTangemShimmer provides TangemShimmer, @@ -433,6 +436,10 @@ val LocalPowerSavingState = compositionLocalOf { error("No PowerSavingState provided") } +val LocalMessageEffectAnimation = compositionLocalOf { + error("No MessageEffectAnimation provided") +} + /** * Determines whether the dark theme should be used based on the given [AppThemeMode]. * diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/message/TangemMessageStory.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/message/TangemMessageStory.kt index f43e8ec903..8ee2be7006 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/message/TangemMessageStory.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/storybook/page/message/TangemMessageStory.kt @@ -1,4 +1,5 @@ @file:Suppress("MagicNumber", "LongMethod") + package com.tangem.feature.tester.presentation.storybook.page.message import androidx.compose.foundation.background @@ -16,7 +17,10 @@ import androidx.compose.ui.unit.dp import com.tangem.core.ui.R import com.tangem.core.ui.ds.button.TangemButtonType import com.tangem.core.ui.ds.image.TangemIconUM -import com.tangem.core.ui.ds.message.* +import com.tangem.core.ui.ds.message.TangemMessage +import com.tangem.core.ui.ds.message.TangemMessageButtonUM +import com.tangem.core.ui.ds.message.TangemMessageEffect +import com.tangem.core.ui.ds.message.TangemMessageUM import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.tester.presentation.storybook.entity.TangemMessageStory diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt index 9d24a0c3da..3a61317174 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt @@ -1,6 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.model import androidx.annotation.DrawableRes +import androidx.compose.ui.unit.dp import com.tangem.core.ui.ds.button.TangemButtonType import com.tangem.core.ui.ds.image.TangemIconUM import com.tangem.core.ui.ds.message.TangemMessageButtonUM @@ -196,7 +197,6 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t onClick = onConfirmClick, ), ), - ), type = WalletNotificationType.Critical, ) @@ -379,8 +379,14 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t title = resourceReference(R.string.notification_one_plus_one_title), subtitle = resourceReference(R.string.notification_one_plus_one_text), messageEffect = TangemMessageEffect.Magic, - onCloseClick = onCloseClick, + iconUM = TangemIconUM.Image(R.drawable.img_one_plus_one_promo), + iconSize = 54.dp, buttonsUM = persistentListOf( + TangemMessageButtonUM( + text = resourceReference(R.string.common_later), + type = TangemButtonType.PrimaryInverse, + onClick = onCloseClick, + ), TangemMessageButtonUM( text = resourceReference(R.string.notification_one_plus_one_button), type = TangemButtonType.Primary, @@ -452,7 +458,8 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t id = "PushNotificationsNotification", title = resourceReference(R.string.user_push_notification_banner_title), subtitle = resourceReference(R.string.user_push_notification_banner_subtitle), - onCloseClick = onCloseClick, + iconUM = TangemIconUM.Image(R.drawable.img_push_reminder), + iconSize = 54.dp, messageEffect = TangemMessageEffect.Magic, buttonsUM = persistentListOf( TangemMessageButtonUM(