Updated on 2026-08-14
This commit is contained in:
commit
5de74d024d
46 changed files with 155 additions and 354 deletions
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
@ -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)
|
||||
},
|
||||
) {}
|
||||
)
|
||||
}
|
||||
|
|
@ -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),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue