Updated on 2026-08-14

This commit is contained in:
Tangem 2023-10-16 11:10:21 +03:00
commit 5de74d024d
46 changed files with 155 additions and 354 deletions

View file

@ -8,6 +8,7 @@ import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat
@ -16,6 +17,7 @@ import androidx.lifecycle.lifecycleScope
import com.tangem.core.analytics.Analytics
import com.tangem.core.navigation.AppScreen
import com.tangem.core.navigation.NavigationAction
import com.tangem.core.ui.components.SystemBarsEffect
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.tokens.TokensAction
import com.tangem.tap.common.analytics.events.IntroductionProcess
@ -52,6 +54,12 @@ class HomeFragment : Fragment(), StoreSubscriber<HomeState> {
BackHandler {
requireActivity().finish()
}
SystemBarsEffect {
setSystemBarsColor(
color = Color.Transparent,
darkIcons = false,
)
}
ScreenContent()
}
}

View file

@ -12,18 +12,13 @@ import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.learn2earn.presentation.ui.Learn2earnStoriesScreen
import com.tangem.tap.features.home.compose.content.*
@ -43,7 +38,6 @@ fun StoriesScreen(
onShopButtonClick: () -> Unit,
onSearchTokensClick: () -> Unit,
) {
val systemUiController = rememberSystemUiController()
val state = homeState.value
var currentStory by remember { mutableStateOf(state.firstStory) }
@ -62,13 +56,6 @@ fun StoriesScreen(
}
}
LaunchedEffect(key1 = currentStory.isDarkBackground) {
systemUiController.setSystemBarsColor(
color = Color.Transparent,
darkIcons = !currentStory.isDarkBackground,
)
}
StoriesScreenContent(
modifier = Modifier.fillMaxSize(),
config = StoriesScreenContentConfig(
@ -90,13 +77,12 @@ fun StoriesScreen(
@Composable
private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: Modifier = Modifier) {
var isPressed by remember { mutableStateOf(value = false) }
var hideContent by remember { mutableStateOf(value = true) }
val isPaused = isPressed || config.isScanInProgress
val currentStoryDuration = config.currentStory.duration
Box(
modifier = modifier.background(Color(0xFF090E13)),
modifier = modifier.background(Color(0xFF010101)),
) {
Row(
modifier = Modifier.fillMaxSize(),
@ -138,14 +124,6 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
},
)
}
if (!config.currentStory.isDarkBackground) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.ic_overlay),
contentDescription = null,
contentScale = ContentScale.FillBounds,
)
}
Column(
modifier = Modifier
@ -166,30 +144,23 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
contentDescription = null,
contentScale = ContentScale.FillHeight,
modifier = Modifier
.padding(start = 16.dp, top = 10.dp)
.height(17.dp)
.alpha(if (hideContent) 0f else 1f)
.padding(
start = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing16,
)
.height(TangemTheme.dimens.size18)
.align(Alignment.Start),
colorFilter = if (config.currentStory.isDarkBackground) {
null
} else {
ColorFilter.tint(TangemColorPalette.Dark6)
},
)
when (config.currentStory) {
Stories.OneInchPromo -> Learn2earnStoriesScreen(config.onLearn2earnClick)
Stories.TangemIntro -> FirstStoriesContent(
isPaused = isPaused,
duration = currentStoryDuration,
isNewWalletAvailable = config.currentStory.isNewWalletAvailable,
) {
hideContent = it
}
Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet(currentStoryDuration)
)
Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet()
is Stories.UltraSecureBackup -> StoriesUltraSecureBackup(
isPaused = isPaused,
stepDuration = currentStoryDuration,
isNewWalletAvailable = config.currentStory.isNewWalletAvailable,
)
Stories.Currencies -> StoriesCurrencies(isPaused, currentStoryDuration)
Stories.Web3 -> StoriesWeb3(isPaused, currentStoryDuration)
@ -223,7 +194,6 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
) {
HomeButtons(
modifier = Modifier.fillMaxWidth(),
isDarkBackground = config.currentStory.isDarkBackground,
btnScanStateInProgress = config.isScanInProgress,
onScanButtonClick = config.onScanButtonClick,
onShopButtonClick = config.onShopButtonClick,

View file

@ -5,79 +5,56 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.SpacerH32
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.home.compose.StoriesBottomImageAnimation
import com.tangem.tap.features.home.compose.StoriesTextAnimation
import com.tangem.wallet.R
@Composable
fun StoriesRevolutionaryWallet(stepDuration: Int) {
fun StoriesRevolutionaryWallet() {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_awe_title),
subtitleText = stringResource(id = R.string.story_awe_description).annotated(),
isDarkBackground = true,
subtitleText = stringResource(id = R.string.story_awe_description),
)
},
bottomContent = {
StoriesBottomImageAnimation(
totalDuration = stepDuration,
firstStepDuration = 300,
) { modifier ->
StoriesImage(
modifier = modifier,
drawableResId = R.drawable.revolutionary_wallet,
isDarkBackground = true,
)
}
SpacerH32()
StoriesImage(
modifier = Modifier,
drawableResId = R.drawable.img_revolutionary_wallet,
)
},
)
}
@Composable
fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int, isNewWalletAvailable: MutableState<Boolean>) {
val subtitleText = buildAnnotatedString {
append(stringResource(id = R.string.story_backup_description_1))
append(" ")
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(stringResource(id = R.string.story_backup_description_2_bold))
}
append(" ")
append(stringResource(id = R.string.story_backup_description_3))
}
fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) {
SplitContent(
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_backup_title),
subtitleText = subtitleText,
isDarkBackground = false,
subtitleText = stringResource(id = R.string.story_backup_description),
)
},
bottomContent = {
SpacerH32()
FloatingCardsContent(
isPaused = isPaused,
stepDuration = stepDuration,
isNewWalletAvailable = isNewWalletAvailable,
)
},
)
@ -89,11 +66,11 @@ fun StoriesCurrencies(isPaused: Boolean, stepDuration: Int) {
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_currencies_title),
subtitleText = stringResource(id = R.string.story_currencies_description).annotated(),
isDarkBackground = false,
subtitleText = stringResource(id = R.string.story_currencies_description),
)
},
bottomContent = {
SpacerH32()
StoriesCurrenciesContent(paused = isPaused, duration = stepDuration)
},
)
@ -105,11 +82,11 @@ fun StoriesWeb3(isPaused: Boolean, stepDuration: Int) {
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_web3_title),
subtitleText = stringResource(id = R.string.story_web3_description).annotated(),
isDarkBackground = false,
subtitleText = stringResource(id = R.string.story_web3_description),
)
},
bottomContent = {
SpacerH(TangemTheme.dimens.spacing70)
StoriesWeb3Content(paused = isPaused, duration = stepDuration)
},
)
@ -121,20 +98,21 @@ fun StoriesWalletForEveryone(stepDuration: Int) {
topContent = {
TopContent(
titleText = stringResource(id = R.string.story_finish_title),
subtitleText = stringResource(id = R.string.story_finish_description).annotated(),
isDarkBackground = true,
subtitleText = stringResource(id = R.string.story_finish_description),
)
},
bottomContent = {
StoriesBottomImageAnimation(
totalDuration = stepDuration,
firstStepDuration = 500,
) { modifier ->
StoriesImage(
modifier = modifier,
drawableResId = R.drawable.wallet_for_everyone,
isDarkBackground = true,
)
SpacerH32()
BoxWithGradient {
StoriesBottomImageAnimation(
totalDuration = stepDuration,
firstStepDuration = 500,
) { modifier ->
StoriesImage(
modifier = modifier,
drawableResId = R.drawable.img_tangem_for_everyone,
)
}
}
},
)
@ -154,22 +132,20 @@ private fun SplitContent(topContent: @Composable () -> Unit, bottomContent: @Com
}
@Composable
private fun TopContent(titleText: String, subtitleText: AnnotatedString, isDarkBackground: Boolean) {
SpacerH32()
private fun TopContent(titleText: String, subtitleText: String) {
SpacerH(TangemTheme.dimens.spacing36)
StoriesTitleText(
text = titleText,
isDarkBackground = isDarkBackground,
)
SpacerH16()
StoriesSubtitleText(
subtitleText = subtitleText,
)
SpacerH32()
}
@Suppress("MagicNumber")
@Composable
private fun StoriesTitleText(text: String, isDarkBackground: Boolean) {
private fun StoriesTitleText(text: String) {
StoriesTextAnimation(
slideInDuration = 500,
slideInDelay = 150,
@ -178,10 +154,8 @@ private fun StoriesTitleText(text: String, isDarkBackground: Boolean) {
modifier = modifier
.padding(start = 40.dp, end = 40.dp),
text = text,
fontSize = 32.sp,
lineHeight = 38.sp,
fontWeight = FontWeight.SemiBold,
color = if (isDarkBackground) Color.White else Color(0xFF090E13),
style = TangemTheme.typography.head,
color = TangemColorPalette.White,
textAlign = TextAlign.Center,
)
}
@ -189,9 +163,7 @@ private fun StoriesTitleText(text: String, isDarkBackground: Boolean) {
@Suppress("MagicNumber")
@Composable
private fun StoriesSubtitleText(subtitleText: AnnotatedString) {
val color = Color(0xFFA6AAAD)
private fun StoriesSubtitleText(subtitleText: String) {
StoriesTextAnimation(
slideInDuration = 500,
slideInDelay = 400,
@ -199,35 +171,28 @@ private fun StoriesSubtitleText(subtitleText: AnnotatedString) {
Text(
modifier = modifier
.padding(start = 40.dp, end = 40.dp),
fontWeight = FontWeight.Normal,
text = subtitleText,
fontSize = 20.sp,
lineHeight = 26.sp,
color = color,
style = TangemTheme.typography.body1,
color = TangemColorPalette.Dark1,
textAlign = TextAlign.Center,
)
}
}
@Composable
private fun StoriesImage(@DrawableRes drawableResId: Int, isDarkBackground: Boolean, modifier: Modifier = Modifier) {
private fun StoriesImage(@DrawableRes drawableResId: Int, modifier: Modifier = Modifier) {
Image(
painter = painterResource(id = drawableResId),
contentDescription = null,
contentScale = if (isDarkBackground) ContentScale.Inside else ContentScale.FillWidth,
contentScale = ContentScale.FillWidth,
modifier = modifier.fillMaxWidth(),
)
}
private fun String.annotated(): AnnotatedString {
val source = this
return buildAnnotatedString { append(source) }
}
@Preview
@Composable
private fun RevolutionaryWalletPreview() {
StoriesRevolutionaryWallet(6000)
StoriesRevolutionaryWallet()
}
@Preview
@ -236,9 +201,6 @@ private fun UltraSecureBackupPreview() {
StoriesUltraSecureBackup(
false,
6000,
remember {
mutableStateOf(true)
},
)
}

View file

@ -40,7 +40,7 @@ fun StoriesCurrenciesContent(paused: Boolean, duration: Int) {
val decreaseRate = remember { 1f / currencyDrawableList.size }
val designItemHeight = remember { 82.dp }
LightenBox {
BoxWithGradient {
Column(modifier = Modifier.graphicsLayer(clip = false)) {
currencyDrawableList.forEachIndexed { index, drawableResId ->
val painter = painterResource(id = drawableResId)
@ -72,7 +72,7 @@ fun StoriesCurrenciesContent(paused: Boolean, duration: Int) {
fun StoriesWeb3Content(paused: Boolean, duration: Int) {
val dappsItemList = remember {
listOf(
R.drawable.dapps0,
R.drawable.dapps1,
R.drawable.dapps1,
R.drawable.dapps2,
R.drawable.dapps3,
@ -84,7 +84,7 @@ fun StoriesWeb3Content(paused: Boolean, duration: Int) {
val decreaseRate = remember { 1f / dappsItemList.size }
val designItemHeight = 75.dp
LightenBox {
BoxWithGradient {
Column(modifier = Modifier.graphicsLayer(clip = false)) {
dappsItemList.forEachIndexed { index, drawableResId ->
val painter = painterResource(id = drawableResId)
@ -111,7 +111,7 @@ fun StoriesWeb3Content(paused: Boolean, duration: Int) {
}
@Composable
private fun LightenBox(content: @Composable () -> Unit) {
internal fun BoxWithGradient(content: @Composable () -> Unit) {
val bottomInsetsPx = WindowInsets.navigationBars.getBottom(LocalDensity.current)
Box(modifier = Modifier.fillMaxSize()) {
@ -133,9 +133,9 @@ private fun scaleToDesignSize(itemSize: DpSize, designItemHeight: Dp): DpSize {
private val BottomGradient: Brush = Brush.verticalGradient(
colors = listOf(
TangemColorPalette.White.copy(alpha = 0f),
TangemColorPalette.White.copy(alpha = 0.75f),
TangemColorPalette.White.copy(alpha = 0.95f),
TangemColorPalette.White,
TangemColorPalette.Black.copy(alpha = 0f),
TangemColorPalette.Black.copy(alpha = 0.75f),
TangemColorPalette.Black.copy(alpha = 0.95f),
TangemColorPalette.Black,
),
)

View file

@ -1,46 +1,36 @@
package com.tangem.tap.features.home.compose.content
import androidx.annotation.StringRes
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.common.compose.FontSizeRange
import com.tangem.tap.common.compose.TextAutoSize
import com.tangem.tap.features.home.compose.StoriesBottomImageAnimation
import com.tangem.tap.features.home.compose.StoriesTextAnimation
import com.tangem.wallet.R
@Suppress("LongMethod", "ComplexMethod", "MagicNumber")
@Composable
fun FirstStoriesContent(
isPaused: Boolean,
duration: Int,
isNewWalletAvailable: MutableState<Boolean>,
onHideContent: (Boolean) -> Unit,
) {
val bottomInsetsPx = WindowInsets.navigationBars.getBottom(LocalDensity.current)
val screenState = remember { mutableStateOf(StartingScreenState.INIT) }
fun FirstStoriesContent(isPaused: Boolean, duration: Int) {
val progress = remember { Animatable(0f) }
LaunchedEffect(isPaused) {
@ -57,142 +47,51 @@ fun FirstStoriesContent(
}
}
when (progress.value) {
in 0f..0.2f -> screenState.value = StartingScreenState.INIT
in 0.2f..0.3f -> screenState.value = StartingScreenState.BUY
in 0.3f..0.4f -> screenState.value = StartingScreenState.STORE
in 0.4f..0.5f -> screenState.value = StartingScreenState.SEND
in 0.5f..0.6f -> screenState.value = StartingScreenState.PAY
in 0.6f..0.7f -> screenState.value = StartingScreenState.EXCHANGE
in 0.7f..0.8f -> screenState.value = StartingScreenState.BORROW
in 0.8f..1f -> screenState.value = StartingScreenState.LEND
in 1f..1.2f -> screenState.value = StartingScreenState.SHOW_CARD
in 1.2f..2f -> screenState.value = StartingScreenState.MEET_TANGEM
}
if (screenState.value == StartingScreenState.INIT) onHideContent(true)
if (screenState.value == StartingScreenState.BUY) onHideContent(false)
val style = TextStyle(
fontSize = 60.sp,
fontSize = 46.sp,
fontWeight = FontWeight.SemiBold,
color = Color.White,
textAlign = TextAlign.Center,
)
val textId = screenState.textId()
Box(modifier = Modifier.fillMaxSize()) {
if (screenState.isSplashingTextDisplaying()) {
TextAutoSize(
modifier = Modifier
.align(Alignment.Center)
.padding(start = 20.dp, end = 20.dp, bottom = 100.dp),
text = textId?.let { stringResource(textId) } ?: "",
textStyle = style,
fontSizeRange = FontSizeRange(20.sp, 60.sp),
)
} else {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier
.weight(0.7f),
) {
if (screenState.isMeetTangemDisplaying()) {
StoriesTextAnimation(
slideInDelay = 0,
) { modifier ->
TextAutoSize(
modifier = modifier
.padding(start = 20.dp, end = 20.dp, top = 50.dp)
.alpha(if (screenState.value == StartingScreenState.SHOW_CARD) 0f else 1f),
text = textId?.let { stringResource(textId) } ?: "",
textStyle = style,
fontSizeRange = FontSizeRange(30.sp, 50.sp),
)
}
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.weight(1.2f)
.wrapContentSize(),
) {
val painter = if (isNewWalletAvailable.value) {
painterResource(id = R.drawable.img_meet_tangem2)
} else {
painterResource(id = R.drawable.img_meet_tangem)
}
StoriesBottomImageAnimation(
totalDuration = duration,
firstStepDuration = 400,
) { modifier ->
Image(
modifier = modifier.fillMaxWidth(),
painter = painter,
contentDescription = "Tangem Wallet card",
)
}
}
Box {
Column(
modifier = Modifier
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
SpacerH(TangemTheme.dimens.spacing94)
StoriesTextAnimation(
slideInDuration = 500,
slideInDelay = 150,
) { modifier ->
Text(
modifier = modifier
.weight(1f),
text = stringResource(R.string.story_meet_title),
style = style,
color = TangemColorPalette.White,
textAlign = TextAlign.Center,
)
}
SpacerH(TangemTheme.dimens.spacing46)
}
Box(
Image(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.height(TangemTheme.dimens.size72 + bottomInsetsPx.dp)
.background(BottomGradient),
.fillMaxWidth(),
painter = painterResource(R.drawable.img_meet_tangem),
contentScale = ContentScale.FillWidth,
contentDescription = "Tangem Wallet card",
)
}
}
private val BottomGradient: Brush = Brush.verticalGradient(
colors = listOf(
TangemColorPalette.Black.copy(alpha = 0f),
TangemColorPalette.Black.copy(alpha = 0.75f),
TangemColorPalette.Black.copy(alpha = 0.95f),
TangemColorPalette.Black,
),
)
private enum class StartingScreenState {
INIT, BUY, STORE, SEND, PAY, EXCHANGE, BORROW, LEND, SHOW_CARD, MEET_TANGEM
}
@StringRes
private fun MutableState<StartingScreenState>.textId(): Int? = when (this.value) {
StartingScreenState.INIT -> null
StartingScreenState.BUY -> R.string.story_meet_buy
StartingScreenState.STORE -> R.string.story_meet_store
StartingScreenState.SEND -> R.string.story_meet_send
StartingScreenState.PAY -> R.string.story_meet_pay
StartingScreenState.EXCHANGE -> R.string.story_meet_exchange
StartingScreenState.BORROW -> R.string.story_meet_borrow
StartingScreenState.LEND -> R.string.story_meet_lend
StartingScreenState.SHOW_CARD -> R.string.story_meet_title
StartingScreenState.MEET_TANGEM -> R.string.story_meet_title
}
private fun MutableState<StartingScreenState>.isSplashingTextDisplaying(): Boolean {
return this.value != StartingScreenState.MEET_TANGEM &&
this.value != StartingScreenState.SHOW_CARD
}
private fun MutableState<StartingScreenState>.isMeetTangemDisplaying(): Boolean {
return this.value == StartingScreenState.MEET_TANGEM
}
@Preview
@Composable
private fun FirstStoriesPreview() {
FirstStoriesContent(
false,
8000,
remember {
mutableStateOf(false)
},
) {}
)
}

View file

@ -1,18 +1,11 @@
package com.tangem.tap.features.home.compose.content
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.tap.common.compose.extensions.AnimatedValue
import com.tangem.tap.common.compose.extensions.asImageBitmap
import com.tangem.tap.common.compose.extensions.toAnimatable
@ -22,13 +15,8 @@ import com.tangem.wallet.R
[REDACTED_AUTHOR]
*/
@Composable
fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int, isNewWalletAvailable: MutableState<Boolean>) {
val bottomInsetsPx = WindowInsets.navigationBars.getBottom(LocalDensity.current)
val imageBitmap = if (isNewWalletAvailable.value) {
asImageBitmap(R.drawable.img_card_placeholder_wallet_2)
} else {
asImageBitmap(R.drawable.card_placeholder_wallet)
}
fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int) {
val imageBitmap = asImageBitmap(R.drawable.img_card_placeholder_wallet_2)
val cards = listOf(
FloatingCard.first(),
FloatingCard.second(),
@ -44,14 +32,6 @@ fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int, isNewWalletAvaila
stepDuration = stepDuration,
)
}
Box(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.height(bottomInsetsPx.dp)
.background(BottomGradient),
)
}
}
@ -114,12 +94,4 @@ private object FloatingCard {
rotationZ = -45f to -30f,
scale = 0.6f to 0.75f,
)
}
private val BottomGradient: Brush = Brush.verticalGradient(
colors = listOf(
TangemColorPalette.White.copy(alpha = 0f),
TangemColorPalette.White.copy(alpha = 0.75f),
TangemColorPalette.White.copy(alpha = 0.95f),
),
)
}

View file

@ -24,7 +24,6 @@ import com.tangem.wallet.R
@Suppress("MagicNumber")
@Composable
internal fun HomeButtons(
isDarkBackground: Boolean,
btnScanStateInProgress: Boolean,
onScanButtonClick: () -> Unit,
onShopButtonClick: () -> Unit,
@ -36,31 +35,24 @@ internal fun HomeButtons(
) {
ScanCardButton(
modifier = Modifier.weight(weight = 1f),
isDarkBackground = isDarkBackground,
showProgress = btnScanStateInProgress,
onClick = onScanButtonClick,
)
SpacerW8()
OrderCardButton(
modifier = Modifier.weight(weight = 1f),
isDarkBackground = isDarkBackground,
onClick = onShopButtonClick,
)
}
}
@Composable
private fun ScanCardButton(
isDarkBackground: Boolean,
showProgress: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
private fun ScanCardButton(showProgress: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
TangemButton(
modifier = modifier,
text = stringResource(id = R.string.home_button_scan),
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24),
colors = if (isDarkBackground) DarkBgScanCardButtonColors else LightBgScanCardButtonColors,
colors = LightBgScanCardButtonColors,
showProgress = showProgress,
enabled = true,
onClick = onClick,
@ -68,12 +60,12 @@ private fun ScanCardButton(
}
@Composable
private fun OrderCardButton(isDarkBackground: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
private fun OrderCardButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
TangemButton(
modifier = modifier,
text = stringResource(id = R.string.home_button_order),
icon = TangemButtonIconPosition.None,
colors = if (isDarkBackground) DarkBgOrderCardButtonColors else LightBgOrderCardButtonColors,
colors = LightBgOrderCardButtonColors,
showProgress = false,
enabled = true,
onClick = onClick,
@ -87,13 +79,6 @@ private val LightBgScanCardButtonColors: ButtonColors = TangemButtonColors(
disabledContentColor = TangemColorPalette.Dark6,
)
private val DarkBgScanCardButtonColors: ButtonColors = TangemButtonColors(
backgroundColor = TangemColorPalette.Dark5,
contentColor = TangemColorPalette.White,
disabledBackgroundColor = TangemColorPalette.Dark5,
disabledContentColor = TangemColorPalette.White,
)
private val LightBgOrderCardButtonColors: ButtonColors = TangemButtonColors(
backgroundColor = TangemColorPalette.Dark6,
contentColor = TangemColorPalette.White,
@ -101,24 +86,16 @@ private val LightBgOrderCardButtonColors: ButtonColors = TangemButtonColors(
disabledContentColor = TangemColorPalette.White,
)
private val DarkBgOrderCardButtonColors: ButtonColors = TangemButtonColors(
backgroundColor = TangemColorPalette.Light1,
contentColor = TangemColorPalette.Dark6,
disabledBackgroundColor = TangemColorPalette.Light1,
disabledContentColor = TangemColorPalette.Dark6,
)
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Composable
private fun HomeButtonsPreview(@PreviewParameter(HomeButtonsParameterProvider::class) state: HomeButtonsState) {
TangemTheme {
Box(
modifier = Modifier.background(if (state.isDarkBackground) Color.Black else Color.White),
modifier = Modifier.background(Color.Black),
) {
HomeButtons(
modifier = Modifier.padding(all = TangemTheme.dimens.spacing16),
isDarkBackground = state.isDarkBackground,
btnScanStateInProgress = state.btnScanStateInProgress,
onScanButtonClick = {},
onShopButtonClick = {},
@ -130,26 +107,15 @@ private fun HomeButtonsPreview(@PreviewParameter(HomeButtonsParameterProvider::c
private class HomeButtonsParameterProvider : CollectionPreviewParameterProvider<HomeButtonsState>(
collection = listOf(
HomeButtonsState(
isDarkBackground = false,
btnScanStateInProgress = false,
),
HomeButtonsState(
isDarkBackground = true,
btnScanStateInProgress = false,
),
HomeButtonsState(
isDarkBackground = false,
btnScanStateInProgress = true,
),
HomeButtonsState(
isDarkBackground = true,
btnScanStateInProgress = true,
),
),
)
private data class HomeButtonsState(
val isDarkBackground: Boolean,
val btnScanStateInProgress: Boolean,
)
// endregion Preview

View file

@ -24,8 +24,8 @@ internal fun SearchCurrenciesButton(onClick: () -> Unit, modifier: Modifier = Mo
}
private val SearchCurrenciesButtonColors: ButtonColors = TangemButtonColors(
backgroundColor = TangemColorPalette.Light2,
contentColor = TangemColorPalette.Dark6,
disabledBackgroundColor = TangemColorPalette.Light2,
disabledContentColor = TangemColorPalette.Dark6,
backgroundColor = TangemColorPalette.Dark5,
contentColor = TangemColorPalette.White,
disabledBackgroundColor = TangemColorPalette.Dark5,
disabledContentColor = TangemColorPalette.White,
)

View file

@ -1,19 +1,26 @@
package com.tangem.tap.features.home.compose.views
import android.provider.Settings
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
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.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerW4
import com.tangem.core.ui.res.TangemTheme
import kotlinx.coroutines.delay
private const val STORIES_ANIMATION_SPEED_ZERO_DURATION = 3000L
@Composable
fun StoriesProgressBar(
@ -25,10 +32,20 @@ fun StoriesProgressBar(
) {
val progress = remember(currentStep) { Animatable(0f) }
val context = LocalContext.current
val animatorSpeed = Settings.Global.getFloat(
context.contentResolver,
Settings.Global.ANIMATOR_DURATION_SCALE,
0f,
)
LaunchedEffect(paused, currentStep) {
if (paused) {
progress.stop()
} else {
if (animatorSpeed == 0f) {
delay(STORIES_ANIMATION_SPEED_ZERO_DURATION)
}
progress.animateTo(
targetValue = 1f,
animationSpec = tween(
@ -44,18 +61,23 @@ fun StoriesProgressBar(
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
// .height()
.padding(start = 9.dp, end = 9.dp, top = 16.dp),
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing16,
),
) {
for (index in 0..steps) {
Row(
modifier = Modifier
.height(2.dp)
.height(TangemTheme.dimens.size2)
.weight(1f)
.clip(RoundedCornerShape(TangemTheme.dimens.radius2))
.background(Color.White.copy(alpha = 0.4f)),
) {
Box(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius2))
.background(Color.White)
.fillMaxHeight().let {
when (index) {

View file

@ -49,15 +49,14 @@ data class HomeState(
}
sealed class Stories(
val isDarkBackground: Boolean,
val duration: Int,
val isNewWalletAvailable: MutableState<Boolean> = mutableStateOf(HomeState.isNewWalletAvailableInit()),
) {
object OneInchPromo : Stories(true, duration = 8000)
object TangemIntro : Stories(true, duration = 8000)
object RevolutionaryWallet : Stories(true, duration = 6000)
object UltraSecureBackup : Stories(false, duration = 6000)
object Currencies : Stories(false, duration = 6000)
object Web3 : Stories(false, duration = 6000)
object WalletForEveryone : Stories(true, duration = 6000)
object OneInchPromo : Stories(duration = 8000)
object TangemIntro : Stories(duration = 6000)
object RevolutionaryWallet : Stories(duration = 6000)
object UltraSecureBackup : Stories(duration = 6000)
object Currencies : Stories(duration = 6000)
object Web3 : Stories(duration = 6000)
object WalletForEveryone : Stories(duration = 6000)
}