Updated on 2026-08-14
This commit is contained in:
parent
4aac8dc94c
commit
b392e4b176
16 changed files with 119 additions and 323 deletions
|
|
@ -13,59 +13,41 @@ android {
|
|||
dependencies {
|
||||
/** Api */
|
||||
implementation(projects.features.home.api)
|
||||
implementation(projects.features.hotWallet.api)
|
||||
|
||||
/** Core modules */
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.res)
|
||||
implementation(projects.core.analytics)
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.configToggles)
|
||||
|
||||
/** Common */
|
||||
implementation(projects.common.routing)
|
||||
|
||||
|
||||
/** Domain */
|
||||
implementation(projects.domain.common)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.feedback)
|
||||
implementation(projects.domain.feedback.models)
|
||||
implementation(projects.domain.referral)
|
||||
|
||||
/** Referral */
|
||||
implementation(projects.features.referral.domain)
|
||||
|
||||
/** AndroidX libraries */
|
||||
implementation(deps.androidx.activity.compose)
|
||||
implementation(deps.lifecycle.runtime.ktx)
|
||||
|
||||
/** Compose libraries */
|
||||
implementation(deps.compose.ui)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
implementation(deps.compose.foundation)
|
||||
implementation(deps.compose.material3)
|
||||
implementation(deps.compose.animation)
|
||||
implementation(deps.compose.coil)
|
||||
implementation(deps.decompose.ext.compose)
|
||||
|
||||
|
||||
/** Tangem libraries */
|
||||
implementation(tangemDeps.card.android)
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(tangemDeps.blockchain)
|
||||
|
||||
|
||||
/** Other libraries */
|
||||
implementation(deps.kotlin.immutable.collections)
|
||||
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>BooleanPropertyNaming:HomeButtons.kt$HomeButtonsState$val btnScanStateInProgress: Boolean</ID>
|
||||
<ID>BooleanPropertyNaming:HomeUM.kt$HomeUM$val scanInProgress: Boolean</ID>
|
||||
<ID>MultilineLambdaItParameter:StoriesProgressBar.kt${ when (index) { currentStep -> it.fillMaxWidth(progress.value) in 0 until currentStep -> it.fillMaxWidth(fraction = 1f) else -> it } }</ID>
|
||||
<ID>ReusedModifierInstance:HomeButtonsV2.kt$StoriesButton( modifier = modifier, text = stringResourceSafe(id = R.string.common_get_started), useDarkerColors = false, onClick = onGetStartedClick, )</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
@ -85,7 +85,7 @@ internal class HomeModel @Inject constructor(
|
|||
private fun createInitialState(): HomeUM {
|
||||
val initialStories = getRestrictedStories().toImmutableList()
|
||||
return HomeUM(
|
||||
scanInProgress = false,
|
||||
isScanInProgress = false,
|
||||
isStoriesContainerEnabled = homeFeatureToggles.isStoriesContainerEnabled,
|
||||
stories = initialStories,
|
||||
storiesConfig = HomeStoriesConfig(stories = initialStories),
|
||||
|
|
@ -204,7 +204,7 @@ internal class HomeModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun setLoading(isLoading: Boolean) {
|
||||
uiState.update { it.copy(scanInProgress = isLoading) }
|
||||
uiState.update { it.copy(isScanInProgress = isLoading) }
|
||||
}
|
||||
|
||||
private fun handleScanError(error: TangemError) {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ internal fun HomeStoriesScreen(state: HomeUM, modifier: Modifier = Modifier) {
|
|||
StoriesContainer(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
config = state.storiesConfig,
|
||||
isPauseStories = state.scanInProgress,
|
||||
isPauseStories = state.isScanInProgress,
|
||||
) { story, isPaused ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ private const val SCALE_SWITCH_BARRIER = 1.15f
|
|||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
fun HorizontalSlidingImage(
|
||||
internal fun HorizontalSlidingImage(
|
||||
painter: Painter,
|
||||
paused: Boolean,
|
||||
duration: Int,
|
||||
|
|
@ -52,7 +52,7 @@ fun HorizontalSlidingImage(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesTextAnimation(
|
||||
internal fun StoriesTextAnimation(
|
||||
slideInDuration: Int = 500,
|
||||
slideInDelay: Int = 200,
|
||||
slideDistance: Dp = 60.dp,
|
||||
|
|
@ -94,7 +94,7 @@ fun StoriesTextAnimation(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesBottomImageAnimation(
|
||||
internal fun StoriesBottomImageAnimation(
|
||||
firstStepDuration: Int,
|
||||
totalDuration: Int,
|
||||
initialScale: Float = 2.5f,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ internal fun StoriesScreenV2(state: HomeUM, onGetStartedClick: () -> Unit, modif
|
|||
storiesSize = state.stories.lastIndex,
|
||||
currentStoryIndex = currentStoryIndex,
|
||||
currentStory = currentStory,
|
||||
isScanInProgress = state.scanInProgress,
|
||||
isScanInProgress = state.isScanInProgress,
|
||||
onGoToPreviousStory = goToPreviousStory,
|
||||
onGoToNextStory = goToNextStory,
|
||||
onGetStartedClick = onGetStartedClick,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.features.home.impl.ui.compose.content
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
|
|
@ -22,33 +21,44 @@ import com.tangem.core.ui.R
|
|||
import com.tangem.core.ui.utils.dpSize
|
||||
import com.tangem.core.ui.utils.toPx
|
||||
|
||||
@Composable
|
||||
fun StoriesCurrenciesContent(paused: Boolean, duration: Int) {
|
||||
val currencyDrawableList = remember {
|
||||
listOf(
|
||||
R.drawable.currency0,
|
||||
R.drawable.currency1,
|
||||
R.drawable.currency2,
|
||||
R.drawable.currency3,
|
||||
R.drawable.currency4,
|
||||
)
|
||||
}
|
||||
private val currencyDrawables = listOf(
|
||||
R.drawable.currency0,
|
||||
R.drawable.currency1,
|
||||
R.drawable.currency2,
|
||||
R.drawable.currency3,
|
||||
R.drawable.currency4,
|
||||
)
|
||||
|
||||
private val web3DappDrawables = listOf(
|
||||
R.drawable.dapps1,
|
||||
R.drawable.dapps1,
|
||||
R.drawable.dapps2,
|
||||
R.drawable.dapps3,
|
||||
R.drawable.dapps4,
|
||||
R.drawable.dapps5,
|
||||
)
|
||||
|
||||
private val currencyDesignItemHeight = 82.dp
|
||||
private val web3DesignItemHeight = 75.dp
|
||||
private val currencyDecreaseRate = 1f / currencyDrawables.size
|
||||
private val web3DecreaseRate = 1f / web3DappDrawables.size
|
||||
private const val WEB3_CHESS_OFFSET_DIVIDER = 3
|
||||
|
||||
@Composable
|
||||
internal fun StoriesCurrenciesContent(paused: Boolean, duration: Int) {
|
||||
val screenWidth = LocalConfiguration.current.screenWidthDp.dp
|
||||
val decreaseRate = remember { 1f / currencyDrawableList.size }
|
||||
val designItemHeight = remember { 82.dp }
|
||||
|
||||
BoxWithGradient {
|
||||
Column(modifier = Modifier.graphicsLayer(clip = false)) {
|
||||
currencyDrawableList.forEachIndexed { index, drawableResId ->
|
||||
currencyDrawables.forEachIndexed { index, drawableResId ->
|
||||
val painter = painterResource(id = drawableResId)
|
||||
val scaledItemSize = scaleToDesignSize(painter.dpSize(), designItemHeight = designItemHeight)
|
||||
val scaledItemSize = scaleToDesignSize(painter.dpSize(), designItemHeight = currencyDesignItemHeight)
|
||||
val itemOversizedScreenWidthBy = scaledItemSize.width - screenWidth
|
||||
val moveItemToStartOfScreen = itemOversizedScreenWidthBy / 2
|
||||
|
||||
val chessOffset = if (index.isEven()) 0.dp else scaledItemSize.halfHeight()
|
||||
val animateFrom = chessOffset - moveItemToStartOfScreen
|
||||
val animateTo = 50.dp - 50.dp * index * decreaseRate
|
||||
val animateTo = 50.dp - 50.dp * index * currencyDecreaseRate
|
||||
|
||||
HorizontalSlidingImage(
|
||||
paused = paused,
|
||||
|
|
@ -65,34 +75,21 @@ fun StoriesCurrenciesContent(paused: Boolean, duration: Int) {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
fun StoriesWeb3Content(paused: Boolean, duration: Int) {
|
||||
val dappsItemList = remember {
|
||||
listOf(
|
||||
R.drawable.dapps1,
|
||||
R.drawable.dapps1,
|
||||
R.drawable.dapps2,
|
||||
R.drawable.dapps3,
|
||||
R.drawable.dapps4,
|
||||
R.drawable.dapps5,
|
||||
)
|
||||
}
|
||||
internal fun StoriesWeb3Content(paused: Boolean, duration: Int) {
|
||||
val screenWidth = LocalConfiguration.current.screenWidthDp.dp
|
||||
val decreaseRate = remember { 1f / dappsItemList.size }
|
||||
val designItemHeight = 75.dp
|
||||
|
||||
BoxWithGradient {
|
||||
Column(modifier = Modifier.graphicsLayer(clip = false)) {
|
||||
dappsItemList.forEachIndexed { index, drawableResId ->
|
||||
web3DappDrawables.forEachIndexed { index, drawableResId ->
|
||||
val painter = painterResource(id = drawableResId)
|
||||
val scaledItemSize = scaleToDesignSize(painter.dpSize(), designItemHeight = designItemHeight)
|
||||
val scaledItemSize = scaleToDesignSize(painter.dpSize(), designItemHeight = web3DesignItemHeight)
|
||||
val itemOversizedScreenWidthBy = scaledItemSize.width - screenWidth
|
||||
val moveItemToStartOfScreen = itemOversizedScreenWidthBy / 2
|
||||
|
||||
val chessOffset = if (index.isEven()) 0.dp else scaledItemSize.width / 3
|
||||
val chessOffset = if (index.isEven()) 0.dp else scaledItemSize.width / WEB3_CHESS_OFFSET_DIVIDER
|
||||
val animateFrom = chessOffset - moveItemToStartOfScreen
|
||||
val animateTo = 70.dp - 70.dp * index * decreaseRate
|
||||
val animateTo = 70.dp - 70.dp * index * web3DecreaseRate
|
||||
|
||||
HorizontalSlidingImage(
|
||||
paused = paused,
|
||||
|
|
@ -138,6 +135,6 @@ private val BottomGradient: Brush = Brush.verticalGradient(
|
|||
),
|
||||
)
|
||||
|
||||
fun DpSize.halfHeight(): Dp = this.height / 2
|
||||
private fun DpSize.halfHeight(): Dp = this.height / 2
|
||||
|
||||
fun Int.isEven() = this and 1 == 0
|
||||
private fun Int.isEven() = this and 1 == 0
|
||||
|
|
@ -13,7 +13,6 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
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.text.TextStyle
|
||||
|
|
@ -21,16 +20,21 @@ 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.sp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.home.impl.ui.compose.StoriesTextAnimation
|
||||
import com.tangem.core.ui.R
|
||||
|
||||
@Suppress("LongMethod", "ComplexMethod", "MagicNumber")
|
||||
private val firstStoryTitleStyle = TextStyle(
|
||||
fontSize = 46.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun FirstStoriesContent(isPaused: Boolean, duration: Int) {
|
||||
internal fun FirstStoriesContent(isPaused: Boolean, duration: Int) {
|
||||
val progress = remember { Animatable(0f) }
|
||||
|
||||
LaunchedEffect(isPaused) {
|
||||
|
|
@ -47,16 +51,8 @@ fun FirstStoriesContent(isPaused: Boolean, duration: Int) {
|
|||
}
|
||||
}
|
||||
|
||||
val style = TextStyle(
|
||||
fontSize = 46.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color.White,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
SpacerH(TangemTheme.dimens.spacing94)
|
||||
|
|
@ -67,15 +63,14 @@ fun FirstStoriesContent(isPaused: Boolean, duration: Int) {
|
|||
Text(
|
||||
modifier = modifier,
|
||||
text = stringResourceSafe(R.string.story_meet_title),
|
||||
style = style,
|
||||
style = firstStoryTitleStyle,
|
||||
color = TangemColorPalette.White,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
SpacerH(TangemTheme.dimens.spacing46)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
painter = painterResource(R.drawable.img_meet_tangem),
|
||||
contentScale = ContentScale.Inside,
|
||||
contentDescription = "Tangem Wallet card",
|
||||
|
|
@ -86,8 +81,5 @@ fun FirstStoriesContent(isPaused: Boolean, duration: Int) {
|
|||
@Preview
|
||||
@Composable
|
||||
private fun FirstStoriesPreview() {
|
||||
FirstStoriesContent(
|
||||
false,
|
||||
8000,
|
||||
)
|
||||
FirstStoriesContent(isPaused = false, duration = 8000)
|
||||
}
|
||||
|
|
@ -1,40 +1,56 @@
|
|||
package com.tangem.features.home.impl.ui.compose.content
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.utils.AnimatedValue
|
||||
import com.tangem.core.ui.utils.asImageBitmap
|
||||
import com.tangem.core.ui.utils.toAnimatable
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int) {
|
||||
val imageBitmap = asImageBitmap(R.drawable.img_card_placeholder_wallet_2)
|
||||
val cards = listOf(
|
||||
FloatingCard.first(),
|
||||
FloatingCard.second(),
|
||||
FloatingCard.third(),
|
||||
)
|
||||
|
||||
internal fun FloatingCardsContent(isPaused: Boolean, stepDuration: Int) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
cards.forEach { floatingCard ->
|
||||
FloatingCard.Item(
|
||||
floatingCards.forEach { cardValues ->
|
||||
FloatingCardItem(
|
||||
isPaused = isPaused,
|
||||
imageBitmap = imageBitmap,
|
||||
cardValues = floatingCard,
|
||||
imageRes = R.drawable.img_card_placeholder_wallet_2,
|
||||
cardValues = cardValues,
|
||||
stepDuration = stepDuration,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FloatingCardItem(
|
||||
isPaused: Boolean,
|
||||
stepDuration: Int,
|
||||
@DrawableRes imageRes: Int,
|
||||
cardValues: CardValues,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(imageRes),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.graphicsLayer(
|
||||
translationX = cardValues.translateX.toAnimatable(isPaused, stepDuration).value,
|
||||
translationY = cardValues.translateY.toAnimatable(isPaused, stepDuration).value,
|
||||
rotationX = cardValues.rotationX.toAnimatable(isPaused, stepDuration).value,
|
||||
rotationY = cardValues.rotationY.toAnimatable(isPaused, stepDuration).value,
|
||||
rotationZ = cardValues.rotationZ.toAnimatable(isPaused, stepDuration).value,
|
||||
scaleX = cardValues.scale.toAnimatable(isPaused, stepDuration).value,
|
||||
scaleY = cardValues.scale.toAnimatable(isPaused, stepDuration).value,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private data class CardValues(
|
||||
val translateX: AnimatedValue = AnimatedValue(0f, 0f),
|
||||
val translateY: AnimatedValue = AnimatedValue(0f, 0f),
|
||||
|
|
@ -44,54 +60,30 @@ private data class CardValues(
|
|||
val scale: AnimatedValue = AnimatedValue(1f, 1f),
|
||||
)
|
||||
|
||||
private object FloatingCard {
|
||||
|
||||
@Suppress("TopLevelComposableFunctions")
|
||||
@Composable
|
||||
fun Item(isPaused: Boolean, stepDuration: Int, imageBitmap: ImageBitmap, cardValues: CardValues) {
|
||||
Image(
|
||||
bitmap = imageBitmap,
|
||||
contentDescription = "Floating Tangem card",
|
||||
modifier = Modifier
|
||||
.graphicsLayer(
|
||||
translationX = cardValues.translateX.toAnimatable(isPaused, stepDuration).value,
|
||||
translationY = cardValues.translateY.toAnimatable(isPaused, stepDuration).value,
|
||||
rotationX = cardValues.rotationX.toAnimatable(isPaused, stepDuration).value,
|
||||
rotationY = cardValues.rotationY.toAnimatable(isPaused, stepDuration).value,
|
||||
rotationZ = cardValues.rotationZ.toAnimatable(isPaused, stepDuration).value,
|
||||
scaleX = cardValues.scale.toAnimatable(isPaused, stepDuration).value,
|
||||
scaleY = cardValues.scale.toAnimatable(isPaused, stepDuration).value,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun first(): CardValues = CardValues(
|
||||
@Suppress("MagicNumber")
|
||||
private val floatingCards = listOf(
|
||||
CardValues(
|
||||
translateX = -400f to -350f,
|
||||
translateY = 30f to 32f,
|
||||
rotationX = 10f to 15f,
|
||||
rotationY = 15f to 15f,
|
||||
rotationZ = 40f to 27f,
|
||||
scale = 0.6f to 0.6f,
|
||||
)
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun second(): CardValues = CardValues(
|
||||
),
|
||||
CardValues(
|
||||
translateX = 350f to 300f,
|
||||
translateY = -70f to 0f,
|
||||
rotationX = 30f to 48f,
|
||||
rotationY = 0f to 5f,
|
||||
rotationZ = -34f to -42f,
|
||||
scale = 0.47f to 0.35f,
|
||||
)
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun third(): CardValues = CardValues(
|
||||
),
|
||||
CardValues(
|
||||
translateX = 320f to 250f,
|
||||
translateY = 500f to 500f,
|
||||
rotationX = 0f to 3f,
|
||||
rotationY = 10f to 10f,
|
||||
rotationZ = -45f to -30f,
|
||||
scale = 0.6f to 0.75f,
|
||||
)
|
||||
}
|
||||
),
|
||||
)
|
||||
|
|
@ -26,7 +26,7 @@ import com.tangem.features.home.impl.ui.compose.StoriesTextAnimation
|
|||
import com.tangem.core.ui.R
|
||||
|
||||
@Composable
|
||||
fun StoriesRevolutionaryWallet() {
|
||||
internal fun StoriesRevolutionaryWallet() {
|
||||
SplitContent(
|
||||
topContent = {
|
||||
TopContent(
|
||||
|
|
@ -45,7 +45,7 @@ fun StoriesRevolutionaryWallet() {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) {
|
||||
internal fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) {
|
||||
SplitContent(
|
||||
topContent = {
|
||||
TopContent(
|
||||
|
|
@ -64,7 +64,7 @@ fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesCurrencies(isPaused: Boolean, stepDuration: Int) {
|
||||
internal fun StoriesCurrencies(isPaused: Boolean, stepDuration: Int) {
|
||||
SplitContent(
|
||||
topContent = {
|
||||
TopContent(
|
||||
|
|
@ -80,7 +80,7 @@ fun StoriesCurrencies(isPaused: Boolean, stepDuration: Int) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesWeb3(isPaused: Boolean, stepDuration: Int) {
|
||||
internal fun StoriesWeb3(isPaused: Boolean, stepDuration: Int) {
|
||||
SplitContent(
|
||||
topContent = {
|
||||
TopContent(
|
||||
|
|
@ -96,7 +96,7 @@ fun StoriesWeb3(isPaused: Boolean, stepDuration: Int) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesWalletForEveryone(stepDuration: Int) {
|
||||
internal fun StoriesWalletForEveryone(stepDuration: Int) {
|
||||
SplitContent(
|
||||
topContent = {
|
||||
TopContent(
|
||||
|
|
@ -127,8 +127,7 @@ fun StoriesWalletForEveryone(stepDuration: Int) {
|
|||
@Composable
|
||||
private fun SplitContent(topContent: @Composable () -> Unit, bottomContent: @Composable () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Top,
|
||||
) {
|
||||
|
|
@ -140,16 +139,11 @@ private fun SplitContent(topContent: @Composable () -> Unit, bottomContent: @Com
|
|||
@Composable
|
||||
private fun TopContent(titleText: String, subtitleText: String) {
|
||||
SpacerH(TangemTheme.dimens.spacing36)
|
||||
StoriesTitleText(
|
||||
text = titleText,
|
||||
)
|
||||
StoriesTitleText(text = titleText)
|
||||
SpacerH16()
|
||||
StoriesSubtitleText(
|
||||
subtitleText = subtitleText,
|
||||
)
|
||||
StoriesSubtitleText(subtitleText = subtitleText)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
private fun StoriesTitleText(text: String) {
|
||||
StoriesTextAnimation(
|
||||
|
|
@ -157,8 +151,7 @@ private fun StoriesTitleText(text: String) {
|
|||
slideInDelay = 150,
|
||||
) { modifier ->
|
||||
Text(
|
||||
modifier = modifier
|
||||
.padding(start = 40.dp, end = 40.dp),
|
||||
modifier = modifier.padding(horizontal = 40.dp),
|
||||
text = text,
|
||||
style = TangemTheme.typography.head,
|
||||
color = TangemColorPalette.White,
|
||||
|
|
@ -167,7 +160,6 @@ private fun StoriesTitleText(text: String) {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
private fun StoriesSubtitleText(subtitleText: String) {
|
||||
StoriesTextAnimation(
|
||||
|
|
@ -175,8 +167,7 @@ private fun StoriesSubtitleText(subtitleText: String) {
|
|||
slideInDelay = 400,
|
||||
) { modifier ->
|
||||
Text(
|
||||
modifier = modifier
|
||||
.padding(start = 40.dp, end = 40.dp),
|
||||
modifier = modifier.padding(horizontal = 40.dp),
|
||||
text = subtitleText,
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemColorPalette.Dark1,
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
package com.tangem.features.home.impl.ui.compose.views
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.SpacerW12
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.StoriesScreenTestTags
|
||||
import com.tangem.core.ui.R
|
||||
|
||||
@Composable
|
||||
internal fun HomeButtons(
|
||||
btnScanStateInProgress: Boolean,
|
||||
onScanButtonClick: () -> Unit,
|
||||
onShopButtonClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
modifier = modifier,
|
||||
) {
|
||||
ScanCardButton(
|
||||
modifier = Modifier
|
||||
.weight(weight = 1f)
|
||||
.testTag(StoriesScreenTestTags.SCAN_BUTTON),
|
||||
showProgress = btnScanStateInProgress,
|
||||
onClick = onScanButtonClick,
|
||||
)
|
||||
SpacerW12()
|
||||
OrderCardButton(
|
||||
modifier = Modifier
|
||||
.weight(weight = 1f)
|
||||
.testTag(StoriesScreenTestTags.ORDER_BUTTON),
|
||||
onClick = onShopButtonClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ScanCardButton(showProgress: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
StoriesButton(
|
||||
modifier = modifier,
|
||||
text = stringResourceSafe(id = R.string.home_button_scan),
|
||||
useDarkerColors = false,
|
||||
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24),
|
||||
onClick = onClick,
|
||||
showProgress = showProgress,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OrderCardButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
StoriesButton(
|
||||
modifier = modifier,
|
||||
text = stringResourceSafe(id = R.string.home_button_order),
|
||||
useDarkerColors = true,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun HomeButtonsPreview(@PreviewParameter(HomeButtonsParameterProvider::class) state: HomeButtonsState) {
|
||||
TangemThemePreview {
|
||||
Box(
|
||||
modifier = Modifier.background(Color.Black),
|
||||
) {
|
||||
HomeButtons(
|
||||
btnScanStateInProgress = state.btnScanStateInProgress,
|
||||
onScanButtonClick = {},
|
||||
onShopButtonClick = {},
|
||||
modifier = Modifier.padding(all = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HomeButtonsParameterProvider : CollectionPreviewParameterProvider<HomeButtonsState>(
|
||||
collection = listOf(
|
||||
HomeButtonsState(
|
||||
btnScanStateInProgress = false,
|
||||
),
|
||||
HomeButtonsState(
|
||||
btnScanStateInProgress = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
private data class HomeButtonsState(
|
||||
val btnScanStateInProgress: Boolean,
|
||||
)
|
||||
// endregion Preview
|
||||
|
|
@ -24,7 +24,7 @@ internal fun HomeButtonsV2(onGetStartedClick: () -> Unit, modifier: Modifier = M
|
|||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
StoriesButton(
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResourceSafe(id = R.string.common_get_started),
|
||||
useDarkerColors = false,
|
||||
onClick = onGetStartedClick,
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
package com.tangem.features.home.impl.ui.compose.views
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.R
|
||||
|
||||
@Composable
|
||||
internal fun SearchCurrenciesButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
StoriesButton(
|
||||
modifier = modifier,
|
||||
text = stringResourceSafe(id = R.string.common_search_tokens),
|
||||
icon = TangemButtonIconPosition.Start(R.drawable.ic_search_24),
|
||||
showProgress = false,
|
||||
useDarkerColors = true,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun SearchCurrenciesButtonPreview() {
|
||||
TangemThemePreview {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(color = Color.Black)
|
||||
.padding(all = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
SearchCurrenciesButton(modifier = Modifier.fillMaxWidth(), onClick = {})
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -23,7 +23,7 @@ import kotlinx.coroutines.delay
|
|||
private const val STORIES_ANIMATION_SPEED_ZERO_DURATION = 3000L
|
||||
|
||||
@Composable
|
||||
fun StoriesProgressBar(
|
||||
internal fun StoriesProgressBar(
|
||||
steps: Int,
|
||||
currentStep: Int,
|
||||
paused: Boolean = false,
|
||||
|
|
@ -82,11 +82,11 @@ fun StoriesProgressBar(
|
|||
.clip(RoundedCornerShape(TangemTheme.dimens.radius2))
|
||||
.background(TangemColorPalette.White)
|
||||
.fillMaxHeight()
|
||||
.let {
|
||||
.let { progressModifier ->
|
||||
when (index) {
|
||||
currentStep -> it.fillMaxWidth(progress.value)
|
||||
in 0 until currentStep -> it.fillMaxWidth(fraction = 1f)
|
||||
else -> it
|
||||
currentStep -> progressModifier.fillMaxWidth(progress.value)
|
||||
in 0 until currentStep -> progressModifier.fillMaxWidth(fraction = 1f)
|
||||
else -> progressModifier
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import com.tangem.core.ui.components.stories.model.StoriesContentConfig
|
|||
import com.tangem.core.ui.components.stories.model.StoryConfig
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class HomeUM(
|
||||
val scanInProgress: Boolean,
|
||||
internal data class HomeUM(
|
||||
val isScanInProgress: Boolean,
|
||||
val isStoriesContainerEnabled: Boolean,
|
||||
val stories: ImmutableList<Stories>,
|
||||
val storiesConfig: HomeStoriesConfig,
|
||||
|
|
@ -20,13 +20,13 @@ data class HomeUM(
|
|||
* Config for the redesigned Home stories ([StoriesContainer]). The Home intro loops forever and is
|
||||
* not closable, so [isCloseButtonVisible] is `false` and [onClose] keeps its no-op default.
|
||||
*/
|
||||
data class HomeStoriesConfig(
|
||||
internal data class HomeStoriesConfig(
|
||||
override val stories: ImmutableList<Stories>,
|
||||
override val isRestartable: Boolean = true,
|
||||
override val isCloseButtonVisible: Boolean = false,
|
||||
) : StoriesContentConfig<Stories>
|
||||
|
||||
enum class Stories(override val duration: Int = 6000) : StoryConfig {
|
||||
internal enum class Stories(override val duration: Int = 6000) : StoryConfig {
|
||||
TangemIntro,
|
||||
RevolutionaryWallet,
|
||||
UltraSecureBackup,
|
||||
|
|
@ -38,6 +38,6 @@ enum class Stories(override val duration: Int = 6000) : StoryConfig {
|
|||
/**
|
||||
* For FCA restriction stories
|
||||
*/
|
||||
fun getRestrictedStories(): List<Stories> {
|
||||
internal fun getRestrictedStories(): List<Stories> {
|
||||
return Stories.entries.filterNot { it == Stories.Currencies }
|
||||
}
|
||||
|
|
@ -157,13 +157,13 @@ internal class HomeModelTest {
|
|||
// Act + Assert — loading on
|
||||
progressSlot.captured.invoke(true)
|
||||
advanceUntilIdle()
|
||||
assertThat(model.uiState.value.scanInProgress).isTrue()
|
||||
assertThat(model.uiState.value.isScanInProgress).isTrue()
|
||||
assertThat(model.uiState.value.storiesConfig).isSameInstanceAs(initialConfig)
|
||||
|
||||
// Act + Assert — loading off
|
||||
progressSlot.captured.invoke(false)
|
||||
advanceUntilIdle()
|
||||
assertThat(model.uiState.value.scanInProgress).isFalse()
|
||||
assertThat(model.uiState.value.isScanInProgress).isFalse()
|
||||
assertThat(model.uiState.value.storiesConfig).isSameInstanceAs(initialConfig)
|
||||
|
||||
model.onDestroy()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue