diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 7f058ec409..64ae04d208 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 7f058ec409b4eaaf8688ecd4bf944ef8d58d3564 +Subproject commit 64ae04d2086e5a605dd4da3cba4af32a60d46c79 diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/Dp.kt b/app/src/main/java/com/tangem/tap/common/compose/extensions/Dp.kt new file mode 100644 index 0000000000..3ba4555c3f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/compose/extensions/Dp.kt @@ -0,0 +1,14 @@ +package com.tangem.tap.common.compose.extensions + +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp + +/** +[REDACTED_AUTHOR] + */ +@Composable +fun Dp.toPx(): Float { + val currentDp = this + return with(LocalDensity.current) { currentDp.toPx() } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt index 8c2184ae50..9cf8354a70 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt @@ -93,32 +93,39 @@ fun View.invisible(invisible: Boolean = true, invokeBeforeStateChanged: (() -> U } fun Context.dpToPixels(dp: Int): Int = - TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), this.resources.displayMetrics - ).toInt() + TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), this.resources.displayMetrics + ).toInt() fun Context.pixelsToDp(pixels: Int): Int { return (pixels.toFloat() / - (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)) + (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)) .toInt() } +fun Context.dpToPixels(dp: Float): Float = + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, this.resources.displayMetrics) + + +fun Context.pixelsToDp(pixels: Float): Float = + (pixels / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)) + tailrec fun Context?.getActivity(): Activity? = this as? Activity - ?: (this as? ContextWrapper)?.baseContext?.getActivity() + ?: (this as? ContextWrapper)?.baseContext?.getActivity() fun MaterialCardView.setMargins( - marginLeftDp: Int = 16, - marginTopDp: Int = 8, - marginRightDp: Int = 16, - marginBottomDp: Int = 8 + marginLeftDp: Int = 16, + marginTopDp: Int = 8, + marginRightDp: Int = 16, + marginBottomDp: Int = 8 ) { val params = this.layoutParams (params as ViewGroup.MarginLayoutParams).setMargins( - context.dpToPixels(marginLeftDp), - context.dpToPixels(marginTopDp), - context.dpToPixels(marginRightDp), - context.dpToPixels(marginBottomDp) + context.dpToPixels(marginLeftDp), + context.dpToPixels(marginTopDp), + context.dpToPixels(marginRightDp), + context.dpToPixels(marginBottomDp) ) this.layoutParams = params } @@ -128,11 +135,11 @@ fun Activity.setSystemBarTextColor(setTextDark: Boolean) { val flags = this.window.decorView.systemUiVisibility // Update the SystemUiVisibility dependening on whether we want a Light or Dark theme. this.window.decorView.systemUiVisibility = - if (setTextDark) { - flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() - } else { - flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - } + if (setTextDark) { + flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() + } else { + flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + } } } @@ -150,7 +157,7 @@ fun Context.copyToClipboard(value: Any, label: String = "") { fun Context.getFromClipboard(default: CharSequence? = null): CharSequence? { val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager - ?: return default + ?: return default val clipData = clipboard.primaryClip ?: return default if (clipData.itemCount == 0) return default @@ -172,10 +179,10 @@ fun Fragment.shareText(text: String) { } fun Context.safeStartActivity( - intent: Intent, - options: Bundle? = null, - fallback: ((ActivityNotFoundException) -> Unit)? = null, - finally: VoidCallback? = null + intent: Intent, + options: Bundle? = null, + fallback: ((ActivityNotFoundException) -> Unit)? = null, + finally: VoidCallback? = null ) { try { this.startActivity(intent, options) diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/FirstStoriesContent.kt b/app/src/main/java/com/tangem/tap/features/home/compose/FirstStoriesContent.kt deleted file mode 100644 index 30e72ec626..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/compose/FirstStoriesContent.kt +++ /dev/null @@ -1,153 +0,0 @@ -package com.tangem.tap.features.home.compose - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.animation.core.Animatable -import androidx.compose.animation.core.LinearEasing -import androidx.compose.animation.core.tween -import androidx.compose.animation.scaleIn -import androidx.compose.animation.slideInVertically -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.mutableStateOf -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.Color -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.wallet.R - -@OptIn(ExperimentalAnimationApi::class) -@Composable -fun FirstStoriesContent( - paused: Boolean, duration: Int = 8_000, - hideContent: (Boolean) -> Unit -) { - val screenState = remember { mutableStateOf(StartingScreenState.INIT) } - val progress = remember { Animatable(0f) } - - LaunchedEffect(paused) { - if (paused) { - progress.stop() - } else { - progress.animateTo( - targetValue = 2f, - animationSpec = tween( - durationMillis = duration, - easing = LinearEasing - ) - ) - } - } - - 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) hideContent(true) - if (screenState.value == StartingScreenState.BUY) hideContent(false) - - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = - Modifier - .fillMaxSize(), - ) { - - val text = when (screenState.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 - } - - val style = TextStyle( - fontSize = 60.sp, - fontWeight = FontWeight.SemiBold, - color = Color.White, - textAlign = TextAlign.Center, - ) - - if (screenState.value != StartingScreenState.MEET_TANGEM) { - TextAutoSize( - modifier = Modifier - .padding(start = 20.dp, end = 20.dp, bottom = 100.dp) - .alpha(if (screenState.value == StartingScreenState.SHOW_CARD) 0f else 1f), - text = text?.let { stringResource(text) } ?: "", - textStyle = style, - fontSizeRange = FontSizeRange(20.sp, 60.sp) - ) - } - - AnimatedVisibility( - visible = screenState.value == StartingScreenState.MEET_TANGEM, - enter = slideInVertically() { it / 2 } - ) { - TextAutoSize( - modifier = Modifier - .fillMaxWidth() - .padding(start = 40.dp, end = 40.dp), - text = text?.let { stringResource(text) } ?: "", - textStyle = style, - fontSizeRange = FontSizeRange(20.sp, 60.sp) - ) - } - - AnimatedVisibility( - visible = screenState.value == StartingScreenState.SHOW_CARD || - screenState.value == StartingScreenState.MEET_TANGEM, - enter = scaleIn(initialScale = 3f) - ) { - Image( - painter = painterResource( - id = R.drawable.meet_tangem - ), - contentDescription = null, - contentScale = ContentScale.FillWidth, - modifier = Modifier.fillMaxWidth() - ) - } - } -} - -enum class StartingScreenState { - INIT, BUY, STORE, SEND, PAY, EXCHANGE, BORROW, LEND, SHOW_CARD, MEET_TANGEM -} - - -@Preview -@Composable -fun Stories1Preview() { - FirstStoriesContent(false, 7_000) {} -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/Stories.kt b/app/src/main/java/com/tangem/tap/features/home/compose/Stories.kt index 4bfac1e8a0..2179b5be44 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/Stories.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/Stories.kt @@ -22,10 +22,12 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource 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 com.tangem.tap.common.compose.SpacerS24 import androidx.compose.ui.unit.sp +import com.tangem.tap.common.compose.SpacerS24 +import com.tangem.tap.features.home.compose.content.* +import com.tangem.tap.features.home.compose.views.HomeButtons +import com.tangem.tap.features.home.compose.views.StoriesProgressBar import com.tangem.tap.features.home.redux.HomeState import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.wallet.R @@ -39,8 +41,6 @@ fun StoriesScreen( onSearchTokensClick: () -> Unit, ) { val steps = 6 - val stepDuration = 8_000 - val currentStep = remember { mutableStateOf(1) } val isDarkBackground = currentStep.value !in 3..5 @@ -55,7 +55,7 @@ fun StoriesScreen( val isPressed = remember { mutableStateOf(false) } val needsToBePaused = remember(homeState) { mutableStateOf(homeState.value.btnScanState.progressState == ProgressState.Loading) } - val pause = isPressed.value || needsToBePaused.value + val isPaused = isPressed.value || needsToBePaused.value val hideContent = remember { mutableStateOf(true) } @@ -122,9 +122,8 @@ fun StoriesScreen( StoriesProgressBar( steps = steps, currentStep = currentStep.value, -// paused = isPressed.value, - stepDuration = stepDuration, - paused = pause, + stepDuration = currentStep.duration(), + paused = isPaused, onStepFinished = goToNextScreen, ) Image( @@ -139,12 +138,12 @@ fun StoriesScreen( colorFilter = if (isDarkBackground) null else ColorFilter.tint(Color.Black) ) when (currentStep.value) { - 1 -> FirstStoriesContent(pause, stepDuration) { hideContent.value = it } - 2 -> StoriesRevolutionaryWallet() - 3 -> StoriesUltraSecureBackup() - 4 -> StoriesThousandsOfCurrencies() - 5 -> StoriesWeb3() - 6 -> StoriesWalletForEveryone() + 1 -> FirstStoriesContent(isPaused, currentStep.duration()) { hideContent.value = it } + 2 -> StoriesRevolutionaryWallet(currentStep.duration()) + 3 -> StoriesUltraSecureBackup(isPaused, currentStep.duration()) + 4 -> StoriesCurrencies(isPaused, currentStep.duration()) + 5 -> StoriesWeb3(isPaused, currentStep.duration()) + 6 -> StoriesWalletForEveryone(currentStep.duration()) } } Column( @@ -157,8 +156,7 @@ fun StoriesScreen( modifier = Modifier .fillMaxWidth() .padding(start = 16.dp, end = 16.dp, bottom = 16.dp) - .height(48.dp) - , + .height(48.dp), colors = ButtonDefaults.textButtonColors( backgroundColor = Color.White, contentColor = Color(0xFF080C10) @@ -188,9 +186,7 @@ fun StoriesScreen( } } - -@Preview -@Composable -fun InstagramScreenPreview() { - StoriesScreen(onScanButtonClick = {}, onShopButtonClick = {}, onSearchTokensClick = {}) +private fun MutableState.duration(): Int = when (this.value) { + 1 -> 8000 + else -> 6000 } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesGeneralContent.kt b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesGeneralContent.kt deleted file mode 100644 index 410a8118aa..0000000000 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesGeneralContent.kt +++ /dev/null @@ -1,162 +0,0 @@ -package com.tangem.tap.features.home.compose - -import android.content.Context -import android.graphics.Typeface -import android.util.TypedValue -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.* -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -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.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.compose.ui.viewinterop.AndroidView -import com.tangem.tangem_sdk_new.extensions.dpToPx -import com.tangem.tap.common.compose.SpacerS16 -import com.tangem.tap.common.compose.SpacerS24 -import com.tangem.tap.common.compose.extensions.toAndroidGraphicsColor -import com.tangem.wallet.R - -@Composable -fun StoriesGeneralContent( - titleText: String, - subtitleText: String, - imageSource: Int?, - isDarkBackground: Boolean, - subtitleTextId: Int? = null, - imageComposable: (() -> Unit)? = null, -) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = - Modifier - .fillMaxWidth() - .fillMaxHeight(), - ) { - - Text( - text = titleText, - fontSize = 32.sp, - fontWeight = FontWeight.SemiBold, - modifier = Modifier - .padding(start = 40.dp, end = 40.dp), - color = if (isDarkBackground) Color.White else Color(0xFF090E13), - textAlign = TextAlign.Center - ) - - SpacerS16() - - SubtitleText(subtitleText, subtitleTextId) - - SpacerS24() - - if (imageSource != null) { - Image( - painter = painterResource(id = imageSource), - contentDescription = null, - contentScale = if (isDarkBackground) ContentScale.Inside else ContentScale.FillWidth, - modifier = Modifier.fillMaxWidth() - ) - } - imageComposable?.invoke() - } -} - -@Composable -fun SubtitleText(subtitleText: String, subtitleTextId: Int?) { - val color = Color(0xFFA6AAAD) - - if (subtitleTextId == null) { - Text( - text = subtitleText, - fontSize = 20.sp, - fontWeight = FontWeight.Normal, - modifier = Modifier.padding(start = 40.dp, end = 40.dp), - color = color, - textAlign = TextAlign.Center - ) - } else { - HtmlText(subtitleTextId) { context -> - val padding = context.dpToPx(40f).toInt() - TextView(context).apply { - layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - setPadding(padding, 0, padding, 0) - textAlignment = View.TEXT_ALIGNMENT_CENTER - typeface = Typeface.DEFAULT - setTextSize(TypedValue.COMPLEX_UNIT_SP, 20f) - setTextColor(color.toAndroidGraphicsColor()) - } - } - } -} - -@Composable -fun StoriesRevolutionaryWallet() { - StoriesGeneralContent( - titleText = stringResource(id = R.string.story_awe_title), - subtitleText = stringResource(id = R.string.story_awe_description), - imageSource = R.drawable.revolutionary_wallet, - isDarkBackground = true - ) -} - -@Composable -fun StoriesUltraSecureBackup() { - StoriesGeneralContent( - titleText = stringResource(id = R.string.story_backup_title), - subtitleText = stringResource(id = R.string.story_backup_description), - imageSource = R.drawable.floating_cards, - subtitleTextId = R.string.story_backup_description, - isDarkBackground = false - ) -} - -@Composable -fun StoriesThousandsOfCurrencies() { - StoriesGeneralContent( - titleText = stringResource(id = R.string.story_currencies_title), - subtitleText = stringResource(id = R.string.story_currencies_description), - imageSource = R.drawable.thousands_of_currencies, - isDarkBackground = false - ) -} - -@Composable -fun StoriesWeb3() { - StoriesGeneralContent( - titleText = stringResource(id = R.string.story_web3_title), - subtitleText = stringResource(id = R.string.story_web3_description), - imageSource = R.drawable.web_3, - isDarkBackground = false - ) -} - -@Composable -fun StoriesWalletForEveryone() { - StoriesGeneralContent( - titleText = stringResource(id = R.string.story_finish_title), - subtitleText = stringResource(id = R.string.story_finish_description), - imageSource = R.drawable.wallet_for_everyone, - isDarkBackground = true - ) -} - -@Composable -fun HtmlText( - stringResId: Int, - modifier: Modifier = Modifier, - factory: (Context) -> TextView -) { - AndroidView(factory, modifier) { it.text = it.context.getText(stringResId) } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt new file mode 100644 index 0000000000..d7f5443f6e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/Content.kt @@ -0,0 +1,251 @@ +package com.tangem.tap.features.home.compose.content + +import android.content.Context +import android.graphics.Typeface +import android.util.TypedValue +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.annotation.DrawableRes +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +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.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.viewinterop.AndroidView +import com.tangem.tangem_sdk_new.extensions.dpToPx +import com.tangem.tap.common.compose.SpacerH +import com.tangem.tap.common.compose.SpacerH16 +import com.tangem.tap.common.compose.extensions.toAndroidGraphicsColor +import com.tangem.tap.features.home.compose.uiTools.StoriesBottomImageAnimation +import com.tangem.tap.features.home.compose.uiTools.StoriesTextAnimation +import com.tangem.wallet.R + +@Composable +fun StoriesRevolutionaryWallet(stepDuration: Int) { + SplitContent( + topContent = { + TopContent( + titleText = stringResource(id = R.string.story_awe_title), + subtitleText = stringResource(id = R.string.story_awe_description), + isDarkBackground = true, + ) + }, + bottomContent = { + StoriesBottomImageAnimation( + totalDuration = stepDuration, + firstStepDuration = 300, + ) { modifier -> + StoriesImage( + modifier = modifier, + drawableResId = R.drawable.revolutionary_wallet, + isDarkBackground = true, + ) + } + } + ) +} + +@Composable +fun StoriesUltraSecureBackup(isPaused: Boolean, stepDuration: Int) { + SplitContent( + topContent = { + TopContent( + titleText = stringResource(id = R.string.story_backup_title), + subtitleText = stringResource(id = R.string.story_backup_description), + isDarkBackground = false, + ) + }, + bottomContent = { + FloatingCardsContent(isPaused, stepDuration) + } + ) +} + +@Composable +fun StoriesCurrencies(isPaused: Boolean, stepDuration: Int) { + SplitContent( + topContent = { + TopContent( + titleText = stringResource(id = R.string.story_currencies_title), + subtitleText = stringResource(id = R.string.story_currencies_description), + isDarkBackground = false, + ) + }, + bottomContent = { + StoriesCurrenciesContent(paused = isPaused, duration = stepDuration) + } + ) +} + +@Composable +fun StoriesWeb3(isPaused: Boolean, stepDuration: Int) { + SplitContent( + topContent = { + TopContent( + titleText = stringResource(id = R.string.story_web3_title), + subtitleText = stringResource(id = R.string.story_web3_description), + isDarkBackground = false, + ) + }, + bottomContent = { + StoriesWeb3Content(paused = isPaused, duration = stepDuration) + } + ) +} + +@Composable +fun StoriesWalletForEveryone(stepDuration: Int) { + SplitContent( + topContent = { + TopContent( + titleText = stringResource(id = R.string.story_finish_title), + subtitleText = stringResource(id = R.string.story_finish_description), + isDarkBackground = true, + ) + }, + bottomContent = { + StoriesBottomImageAnimation( + totalDuration = stepDuration, + firstStepDuration = 500, + ) { modifier -> + StoriesImage( + modifier = modifier, + drawableResId = R.drawable.wallet_for_everyone, + isDarkBackground = true, + ) + } + } + ) +} + +@Composable +private fun SplitContent( + topContent: @Composable () -> Unit, + bottomContent: @Composable () -> Unit, +) { + Column( + modifier = Modifier + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top + ) { + topContent() + bottomContent() + } +} + +@Composable +private fun TopContent( + titleText: String, + subtitleText: String, + isDarkBackground: Boolean, + subtitleTextId: Int? = null, +) { + SpacerH(32.dp) + StoriesTitleText( + text = titleText, + isDarkBackground = isDarkBackground, + ) + SpacerH16() + StoriesSubtitleText( + subtitleText = subtitleText, + subtitleTextId = subtitleTextId, + ) + SpacerH(32.dp) +} + +@Composable +private fun StoriesTitleText( + text: String, + isDarkBackground: Boolean, +) { + StoriesTextAnimation( + slideInDuration = 500, + slideInDelay = 150, + ) { modifier -> + Text( + modifier = modifier + .padding(start = 40.dp, end = 40.dp), + text = text, + fontSize = 32.sp, + fontWeight = FontWeight.SemiBold, + color = if (isDarkBackground) Color.White else Color(0xFF090E13), + textAlign = TextAlign.Center + ) + } +} + +@Composable +private fun StoriesSubtitleText( + subtitleText: String, + subtitleTextId: Int?, +) { + val color = Color(0xFFA6AAAD) + + StoriesTextAnimation( + slideInDuration = 500, + slideInDelay = 400, + ) { modifier -> + val internalModifier = modifier + .padding(start = 40.dp, end = 40.dp) + + if (subtitleTextId == null) { + Text( + text = subtitleText, + fontSize = 20.sp, + fontWeight = FontWeight.Normal, + modifier = internalModifier, + color = color, + textAlign = TextAlign.Center + ) + } else { + HtmlText( + modifier = internalModifier, + stringResId = subtitleTextId, + ) { context -> + val padding = context.dpToPx(40f).toInt() + TextView(context).apply { + layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + setPadding(padding, 0, padding, 0) + textAlignment = View.TEXT_ALIGNMENT_CENTER + typeface = Typeface.DEFAULT + setTextSize(TypedValue.COMPLEX_UNIT_SP, 20f) + setTextColor(color.toAndroidGraphicsColor()) + } + } + } + } +} + +@Composable +private fun HtmlText( + stringResId: Int, + modifier: Modifier = Modifier, + factory: (Context) -> TextView +) { + AndroidView(factory, modifier) { it.text = it.context.getText(stringResId) } +} + +@Composable +fun StoriesImage( + modifier: Modifier = Modifier, + @DrawableRes drawableResId: Int, + isDarkBackground: Boolean, +) { + Image( + painter = painterResource(id = drawableResId), + contentDescription = null, + contentScale = if (isDarkBackground) ContentScale.Inside else ContentScale.FillWidth, + modifier = modifier.fillMaxWidth() + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt new file mode 100644 index 0000000000..480a2a23e2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/CurrenciesWeb3Content.kt @@ -0,0 +1,161 @@ +package com.tangem.tap.features.home.compose.content + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import com.tangem.tangem_sdk_new.extensions.dpToPx +import com.tangem.tangem_sdk_new.extensions.pxToDp +import com.tangem.tap.common.compose.SpacerH +import com.tangem.tap.common.compose.extensions.toPx +import com.tangem.tap.common.extensions.isEven +import com.tangem.tap.features.home.compose.uiTools.HorizontalSlidingImage +import com.tangem.wallet.R + +@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, + ) + } + + val screenWidth = LocalConfiguration.current.screenWidthDp.dp + val decreaseRate = remember { 1f / currencyDrawableList.size } + val designItemHeight = remember { 82.dp } + + LightenBox { + Column(modifier = Modifier.graphicsLayer(clip = false)) { + currencyDrawableList.forEachIndexed { index, drawableResId -> + val painter = painterResource(id = drawableResId) + val scaledItemSize = scaleToDesignSize(painter.dpSize(), designItemHeight = designItemHeight) + 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) + + HorizontalSlidingImage( + paused = paused, + duration = duration, + painter = painter, + itemSize = scaledItemSize, + startOffset = animateFrom.toPx(), + targetOffset = animateTo.toPx(), + contentDescription = "Currency row", + ) + SpacerH(12.dp) + } + } + } +} + +@Composable +fun StoriesWeb3Content( + paused: Boolean, + duration: Int, +) { + val dappsItemList = remember { + listOf( + R.drawable.dapps0, + R.drawable.dapps1, + R.drawable.dapps2, + R.drawable.dapps3, + R.drawable.dapps4, + R.drawable.dapps5, + ) + } + val screenWidth = LocalConfiguration.current.screenWidthDp.dp + val decreaseRate = remember { 1f / dappsItemList.size } + val designItemHeight = 50.dp + + LightenBox { + Column(modifier = Modifier.graphicsLayer(clip = false)) { + dappsItemList.forEachIndexed { index, drawableResId -> + val painter = painterResource(id = drawableResId) + val scaledItemSize = scaleToDesignSize(painter.dpSize(), designItemHeight = designItemHeight) + val itemOversizedScreenWidthBy = scaledItemSize.width - screenWidth + val moveItemToStartOfScreen = itemOversizedScreenWidthBy / 2 + + val chessOffset = if (index.isEven()) 0.dp else scaledItemSize.width / 3 + val animateFrom = chessOffset - moveItemToStartOfScreen + val animateTo = 90.dp - (90.dp * index * decreaseRate) + + HorizontalSlidingImage( + paused = paused, + duration = duration, + painter = painter, + itemSize = scaledItemSize, + startOffset = animateFrom.toPx(), + targetOffset = animateTo.toPx(), + contentDescription = "Web3 row", + ) + SpacerH(14.dp) + } + } + + } +} + +@Composable +private fun LightenBox(content: @Composable () -> Unit) { + Box() { + content() + Box( + modifier = Modifier + .fillMaxSize() + .padding(top = 170.dp) + .background( + brush = Brush.verticalGradient( + colors = listOf( + Color.White.copy(alpha = 0.3f), + Color.White + ) + ) + ) + ) {} + } +} + +@Composable +private fun Painter.dpSize(): DpSize = DpSize( + intrinsicSize.width.pxToDp().dp, + intrinsicSize.height.pxToDp().dp, +) + +@Composable +private fun Float.dpToPx(): Float = LocalContext.current.dpToPx(this) + +@Composable +private fun Float.pxToDp(): Float = LocalContext.current.pxToDp(this) + +private fun scaleToDesignSize(itemSize: DpSize, designItemHeight: Dp): DpSize { + val scaleRate = itemSize.height / designItemHeight + return itemSize / scaleRate +} + +private fun DpSize.halfWidth(): Dp = this.width / 2 + +private fun DpSize.halfHeight(): Dp = this.height / 2 \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt new file mode 100644 index 0000000000..af7e3d586a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/FirstStoriesContent.kt @@ -0,0 +1,161 @@ +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.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.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.unit.dp +import androidx.compose.ui.unit.sp +import com.tangem.tap.features.home.compose.uiTools.StoriesBottomImageAnimation +import com.tangem.tap.features.home.compose.uiTools.StoriesTextAnimation +import com.tangem.tap.features.home.compose.views.FontSizeRange +import com.tangem.tap.features.home.compose.views.TextAutoSize +import com.tangem.wallet.R + +@Composable +fun FirstStoriesContent( + isPaused: Boolean, duration: Int = 8_000, + hideContent: (Boolean) -> Unit +) { + val screenState = remember { mutableStateOf(StartingScreenState.INIT) } + val progress = remember { Animatable(0f) } + + LaunchedEffect(isPaused) { + if (isPaused) { + progress.stop() + } else { + progress.animateTo( + targetValue = 2f, + animationSpec = tween( + durationMillis = duration, + easing = LinearEasing + ) + ) + } + } + + 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) hideContent(true) + if (screenState.value == StartingScreenState.BUY) hideContent(false) + + val style = TextStyle( + fontSize = 60.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(20.sp, 60.sp) + ) + } + + } + } + Box( + modifier = Modifier + .fillMaxWidth() + .weight(1.25f) + ) { + StoriesBottomImageAnimation( + totalDuration = duration, + firstStepDuration = 500, + ) { modifier -> + Image( + modifier = modifier.fillMaxWidth(), + painter = painterResource(id = R.drawable.meet_tangem), + contentDescription = "Tangem Wallet card", + contentScale = ContentScale.FillWidth, + ) + } + } + } + } + } +} + +enum class StartingScreenState { + INIT, BUY, STORE, SEND, PAY, EXCHANGE, BORROW, LEND, SHOW_CARD, MEET_TANGEM +} + +@StringRes +private fun MutableState.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.isSplashingTextDisplaying(): Boolean { + return this.value != StartingScreenState.MEET_TANGEM && + this.value != StartingScreenState.SHOW_CARD +} + +private fun MutableState.isTangemCardDisplaying(): Boolean { + return this.value == StartingScreenState.SHOW_CARD || + this.value == StartingScreenState.MEET_TANGEM +} + +private fun MutableState.isMeetTangemDisplaying(): Boolean { + return this.value == StartingScreenState.MEET_TANGEM +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt b/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt new file mode 100644 index 0000000000..221f3329ca --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/compose/content/FloatingCardsContent.kt @@ -0,0 +1,103 @@ +package com.tangem.tap.features.home.compose.content + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.graphicsLayer +import com.tangem.tap.features.home.compose.uiTools.AnimatedValue +import com.tangem.tap.features.home.compose.uiTools.asImageBitmap +import com.tangem.tap.features.home.compose.uiTools.toAnimatable +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +@Composable +fun FloatingCardsContent( + isPaused: Boolean, + stepDuration: Int, +) { + + val imageBitmap = asImageBitmap(R.drawable.card_placeholder_wallet) + val cards = listOf( + FloatingCard.first(), + FloatingCard.second(), + FloatingCard.third(), + ) + Box() { + cards.forEach { floatingCard -> + FloatingCard.Item( + isPaused = isPaused, + imageBitmap = imageBitmap, + cardValues = floatingCard, + stepDuration = stepDuration, + ) + } + } +} + +private data class CardValues( + val translateX: AnimatedValue = AnimatedValue(0f, 0f), + val translateY: AnimatedValue = AnimatedValue(0f, 0f), + val rotationX: AnimatedValue = AnimatedValue(0f, 0f), + val rotationY: AnimatedValue = AnimatedValue(0f, 0f), + val rotationZ: AnimatedValue = AnimatedValue(0f, 0f), + val scale: AnimatedValue = AnimatedValue(1f, 1f), +) + +private class FloatingCard { + companion object { + + @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, + ), + ) + } + + fun first(): CardValues = CardValues( + translateX = -400f to -350f, + translateY = 30f to 32f, + rotationX = 10f to 12f, + rotationY = 15f to 15f, + rotationZ = 40f to 27f, + scale = 0.6f to 0.6f, + ) + + fun second(): CardValues = CardValues( + translateX = 350f to 300f, + translateY = 0f to 50f, + rotationX = 30f to 48f, + rotationY = 0f to 5f, + rotationZ = -34f to -42f, + scale = 0.47f to 0.35f, + ) + + fun third(): 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.7f, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/AnimatedValue.kt b/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/AnimatedValue.kt new file mode 100644 index 0000000000..d8afd02e6f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/AnimatedValue.kt @@ -0,0 +1,47 @@ +package com.tangem.tap.features.home.compose.uiTools + +import androidx.compose.animation.core.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember + +typealias AnimatedValue = Pair + +@Composable +fun AnimatedValue.toAnimatable( + isPaused: Boolean, + duration: Int, + easing: Easing = LinearEasing, +): Animatable { + return animatable( + values = this, + isPaused = isPaused, + duration = duration, + easing = easing, + ) +} + +@Composable +fun animatable( + values: AnimatedValue, + isPaused: Boolean, + duration: Int, + easing: Easing = LinearEasing, +): Animatable { + val animatable = remember { Animatable(values.first) } + + LaunchedEffect(isPaused) { + if (isPaused) { + animatable.stop() + } else { + animatable.animateTo( + targetValue = values.second, + animationSpec = tween( + durationMillis = duration, + easing = easing + ) + ) + } + } + return animatable +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/StoriesAnimtion.kt b/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/StoriesAnimtion.kt new file mode 100644 index 0000000000..a5d596c425 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/StoriesAnimtion.kt @@ -0,0 +1,174 @@ +package com.tangem.tap.features.home.compose.uiTools + +import androidx.annotation.DrawableRes +import androidx.appcompat.content.res.AppCompatResources +import androidx.compose.animation.core.* +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.absoluteOffset +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +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.draw.scale +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.core.graphics.drawable.toBitmap + +@Composable +fun HorizontalSlidingImage( + painter: Painter, + paused: Boolean, + duration: Int, + itemSize: DpSize, + startOffset: Float, + targetOffset: Float, + contentDescription: String, +) { + val offsetX = remember { Animatable(startOffset * -1f) } + + Image( + modifier = Modifier + .offset { IntOffset(offsetX.value.toInt(), 0) } + .requiredWidth(itemSize.width) + .requiredHeight(itemSize.height), + alignment = Alignment.TopStart, + contentScale = ContentScale.FillBounds, + painter = painter, + contentDescription = contentDescription, + ) + + LaunchedEffect(paused) { + if (paused) { + offsetX.stop() + } else { + offsetX.animateTo( + targetValue = (startOffset + targetOffset) * -1f, + animationSpec = tween( + durationMillis = duration, + easing = LinearEasing, + ), + ) + } + } +} + +@Composable +fun StoriesTextAnimation( + slideInDuration: Int = 500, + slideInDelay: Int = 200, + slideDistance: Dp = 60.dp, + label: String = "", + content: @Composable (Modifier) -> Unit +) { + val isLaunched = remember { mutableStateOf(false) } + val transition = updateTransition(targetState = isLaunched.value, label = label) + + val offsetY = transition.animateDp( + transitionSpec = { + tween( + durationMillis = slideInDuration, + delayMillis = slideInDelay, + easing = FastOutSlowInEasing + ) + }, + label = "Slide in" + ) { value -> if (value) 0.dp else slideDistance } + + val alpha = transition.animateFloat( + transitionSpec = { + tween( + durationMillis = slideInDuration * 2, + delayMillis = slideInDelay, + easing = FastOutSlowInEasing + ) + }, + label = "Visibility" + ) { value -> if (value) 1f else 0f } + + content( + Modifier + .absoluteOffset(y = offsetY.value) + .alpha(alpha.value) + ) + + LaunchedEffect(Unit) { isLaunched.value = true } +} + +@Composable +fun StoriesBottomImageAnimation( + initialScale: Float = 2f, + firstStepDuration: Int, + totalDuration: Int, + content: @Composable (Modifier) -> Unit +) { + val scaleSwitchBarrier = remember { 1.15f } + val secondStepDuration = remember { totalDuration - firstStepDuration } + + val isFirstStepLaunched = remember { mutableStateOf(false) } + val isSecondStepLaunched = remember { mutableStateOf(false) } + + val firstTransition = updateTransition(targetState = isFirstStepLaunched.value, label = "Bottom image animation") + val secondTransition = updateTransition(targetState = isSecondStepLaunched.value, label = "Bottom image animation") + + val fadeIn = firstTransition.animateFloat( + transitionSpec = { + tween( + durationMillis = 400, + ) + }, + label = "Fade in animation" + ) { value -> if (value) 1f else 0f } + + val firstScaleStep = firstTransition.animateFloat( + transitionSpec = { + tween( + durationMillis = firstStepDuration, + easing = FastOutLinearInEasing, + ) + }, + label = "Scale" + ) { value -> if (value) scaleSwitchBarrier else initialScale } + + + val secondScaleStep = secondTransition.animateFloat( + transitionSpec = { + tween( + durationMillis = secondStepDuration, + easing = LinearEasing, + ) + }, + label = "Scale" + ) { value -> if (value) 1f else scaleSwitchBarrier } + + if (firstScaleStep.value == scaleSwitchBarrier) isSecondStepLaunched.value = true + + val modifier = if (!isSecondStepLaunched.value) { + Modifier.scale(firstScaleStep.value) + } else { + Modifier.scale(secondScaleStep.value) + }.alpha(fadeIn.value) + + content(modifier) + + LaunchedEffect(Unit) { isFirstStepLaunched.value = true } +} + +@Composable +fun asImageBitmap(@DrawableRes drawableId: Int): ImageBitmap { + val drawable = AppCompatResources.getDrawable(LocalContext.current, drawableId) + ?: throw NullPointerException() + return drawable.toBitmap().asImageBitmap() +} diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/StoriesPreviews.kt b/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/StoriesPreviews.kt new file mode 100644 index 0000000000..a09559cbf4 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/home/compose/uiTools/StoriesPreviews.kt @@ -0,0 +1,51 @@ +package com.tangem.tap.features.home.compose.uiTools + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.tap.features.home.compose.StoriesScreen +import com.tangem.tap.features.home.compose.content.* + +/** +[REDACTED_AUTHOR] + */ +@Preview +@Composable +fun StoriesScreenPreview() { + StoriesScreen(onScanButtonClick = {}, onShopButtonClick = {}, onSearchTokensClick = {}) +} + +@Preview +@Composable +fun Stories1Preview() { + FirstStoriesContent(false, 8000) {} +} + +@Preview +@Composable +private fun RevolutionaryWalletPreview() { + StoriesRevolutionaryWallet(6000) +} + +@Preview +@Composable +private fun UltraSecureBackupPreview() { + StoriesUltraSecureBackup(false, 6000) +} + +@Preview +@Composable +private fun CurrenciesPreview() { + StoriesCurrencies(false, 6000) +} + +@Preview +@Composable +private fun Web3Preview() { + StoriesWeb3(false, 6000) +} + +@Preview +@Composable +private fun WalletForEveryonePreview() { + StoriesWalletForEveryone(6000) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/AutoSizeText.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/AutoSizeText.kt similarity index 93% rename from app/src/main/java/com/tangem/tap/features/home/compose/AutoSizeText.kt rename to app/src/main/java/com/tangem/tap/features/home/compose/views/AutoSizeText.kt index 2bb6c5b8d5..f930160da5 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/AutoSizeText.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/AutoSizeText.kt @@ -1,6 +1,5 @@ -package com.tangem.tap.features.home.compose +package com.tangem.tap.features.home.compose.views -import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.material.LocalTextStyle import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -12,7 +11,6 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.sp -@OptIn(ExperimentalAnimationApi::class) @Composable fun TextAutoSize( modifier: Modifier = Modifier, diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/HomeButtons.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/home/compose/HomeButtons.kt rename to app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt index 04fb1f2647..d49013db87 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/HomeButtons.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose +package com.tangem.tap.features.home.compose.views import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesProgressBar.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt similarity index 97% rename from app/src/main/java/com/tangem/tap/features/home/compose/StoriesProgressBar.kt rename to app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt index d121949529..096b87cb0b 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesProgressBar.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.home.compose +package com.tangem.tap.features.home.compose.views import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.LinearEasing diff --git a/app/src/main/res/drawable/currency0.png b/app/src/main/res/drawable/currency0.png new file mode 100644 index 0000000000..0d293ec8bb Binary files /dev/null and b/app/src/main/res/drawable/currency0.png differ diff --git a/app/src/main/res/drawable/currency1.png b/app/src/main/res/drawable/currency1.png new file mode 100644 index 0000000000..37144efffe Binary files /dev/null and b/app/src/main/res/drawable/currency1.png differ diff --git a/app/src/main/res/drawable/currency2.png b/app/src/main/res/drawable/currency2.png new file mode 100644 index 0000000000..bd75790221 Binary files /dev/null and b/app/src/main/res/drawable/currency2.png differ diff --git a/app/src/main/res/drawable/currency3.png b/app/src/main/res/drawable/currency3.png new file mode 100644 index 0000000000..c517578807 Binary files /dev/null and b/app/src/main/res/drawable/currency3.png differ diff --git a/app/src/main/res/drawable/currency4.png b/app/src/main/res/drawable/currency4.png new file mode 100644 index 0000000000..9a39d5651d Binary files /dev/null and b/app/src/main/res/drawable/currency4.png differ diff --git a/app/src/main/res/drawable/dapps0.png b/app/src/main/res/drawable/dapps0.png new file mode 100644 index 0000000000..846c417a6d Binary files /dev/null and b/app/src/main/res/drawable/dapps0.png differ diff --git a/app/src/main/res/drawable/dapps1.png b/app/src/main/res/drawable/dapps1.png new file mode 100644 index 0000000000..b18d362ac7 Binary files /dev/null and b/app/src/main/res/drawable/dapps1.png differ diff --git a/app/src/main/res/drawable/dapps2.png b/app/src/main/res/drawable/dapps2.png new file mode 100644 index 0000000000..549a45e403 Binary files /dev/null and b/app/src/main/res/drawable/dapps2.png differ diff --git a/app/src/main/res/drawable/dapps3.png b/app/src/main/res/drawable/dapps3.png new file mode 100644 index 0000000000..ebe35565cf Binary files /dev/null and b/app/src/main/res/drawable/dapps3.png differ diff --git a/app/src/main/res/drawable/dapps4.png b/app/src/main/res/drawable/dapps4.png new file mode 100644 index 0000000000..046e96eefa Binary files /dev/null and b/app/src/main/res/drawable/dapps4.png differ diff --git a/app/src/main/res/drawable/dapps5.png b/app/src/main/res/drawable/dapps5.png new file mode 100644 index 0000000000..dc5d2271e1 Binary files /dev/null and b/app/src/main/res/drawable/dapps5.png differ