diff --git a/common/ui/src/main/java/com/tangem/common/ui/navigationButtons/NavigationButtonsBlock.kt b/common/ui/src/main/java/com/tangem/common/ui/navigationButtons/NavigationButtonsBlock.kt index 58cc324958..3f12092079 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/navigationButtons/NavigationButtonsBlock.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/navigationButtons/NavigationButtonsBlock.kt @@ -2,11 +2,13 @@ package com.tangem.common.ui.navigationButtons import android.content.res.Configuration import androidx.compose.animation.* +import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon +import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -14,14 +16,18 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.tangem.common.ui.navigationButtons.preview.NavigationButtonsPreview +import com.tangem.core.ui.components.Keyboard import com.tangem.core.ui.components.buttons.common.TangemButton import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults +import com.tangem.core.ui.components.keyboardAsState import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.isNullOrEmpty import com.tangem.core.ui.extensions.rememberHapticFeedback import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.res.TangemTheme @@ -29,12 +35,17 @@ import com.tangem.core.ui.res.TangemThemePreview import kotlinx.collections.immutable.ImmutableList @Composable -fun NavigationButtonsBlock(buttonState: NavigationButtonsState, modifier: Modifier = Modifier) { +fun NavigationButtonsBlock( + buttonState: NavigationButtonsState, + modifier: Modifier = Modifier, + footerText: TextReference? = null, +) { val state = buttonState as? NavigationButtonsState.Data Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier.fillMaxWidth(), ) { + InfoText(footerText) ExtraButtons(state?.extraButtons, state?.txUrl) Row( modifier = Modifier.fillMaxWidth(), @@ -134,6 +145,39 @@ private fun ExtraButtons(extraButtons: ImmutableList?, txUrl: } } +@Composable +private fun InfoText(footerText: TextReference?, modifier: Modifier = Modifier) { + var isVisibleProxy by remember { mutableStateOf(!footerText.isNullOrEmpty()) } + val keyboard by keyboardAsState() + + // the text should appear when the keyboard is closed + LaunchedEffect(footerText, keyboard) { + if (footerText.isNullOrEmpty() && keyboard is Keyboard.Opened) { + return@LaunchedEffect + } + isVisibleProxy = !footerText.isNullOrEmpty() + } + + AnimatedVisibility( + visible = isVisibleProxy, + modifier = modifier, + enter = slideInVertically() + fadeIn(), + exit = fadeOut(tween(durationMillis = 300)), + label = "Animate footer text appearance", + ) { + val text = remember(this) { requireNotNull(footerText) } + Text( + text = text.resolveReference(), + color = TangemTheme.colors.text.tertiary, + style = TangemTheme.typography.caption2, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = TangemTheme.dimens.spacing12), + ) + } +} + @Composable private fun rememberNavigationButton(button: NavigationButton?): MutableState { return remember( diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 66d4cf1e8c..3c7f4884ca 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -696,6 +696,7 @@ Rewards Stake locked Stake more + You stake %1$s and will be receiving ~%2$s yearly Stake %s Unstake %s Unbonding diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt index 637d40f910..bdf349c499 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt @@ -89,7 +89,7 @@ internal sealed class StakingStates { val validatorState: ValidatorState, val pendingAction: PendingAction?, val notifications: ImmutableList, - val footerText: String, + val footerText: TextReference, val transactionDoneState: TransactionDoneState, val isApprovalNeeded: Boolean, val reduceAmountBy: BigDecimal?, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt index 443491c582..09143b30de 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt @@ -4,6 +4,7 @@ import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType.Coin import com.tangem.blockchain.common.transaction.Fee import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.staking.model.stakekit.Yield @@ -77,7 +78,7 @@ internal object ConfirmationStatePreviewData { chosenValidator = validatorList[0], availableValidators = validatorList, ), - footerText = "You stake \$715.11 and will be receiving ~\$35 monthly", + footerText = stringReference("You stake \$715.11 and will be receiving ~\$35 monthly"), notifications = persistentListOf( StakingNotification.Info.EarnRewards( subtitleText = resourceReference( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateCompletedTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateCompletedTransformer.kt index d2e2435917..32936b8d7e 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateCompletedTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateCompletedTransformer.kt @@ -1,6 +1,7 @@ package com.tangem.features.staking.impl.presentation.state.transformers import com.tangem.blockchain.common.transaction.Fee +import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.staking.impl.presentation.state.* @@ -37,6 +38,7 @@ internal class SetConfirmationStateCompletedTransformer( validatorState = validatorState.copySealed( isClickable = false, ), + footerText = TextReference.EMPTY, notifications = persistentListOf(), transactionDoneState = TransactionDoneState.Content( timestamp = System.currentTimeMillis(), diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInProgressTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInProgressTransformer.kt index e17aad84b4..24bdd43c84 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInProgressTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInProgressTransformer.kt @@ -1,5 +1,6 @@ package com.tangem.features.staking.impl.presentation.state.transformers +import com.tangem.core.ui.extensions.TextReference import com.tangem.features.staking.impl.presentation.state.InnerConfirmationStakingState import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.features.staking.impl.presentation.state.StakingUiState @@ -19,6 +20,7 @@ internal class SetConfirmationStateInProgressTransformer : Transformer { override fun transform(prevState: StakingUiState): StakingUiState { @@ -25,7 +35,7 @@ internal class SetConfirmationStateLoadingTransformer( availableValidators = yield.validators, ), notifications = persistentListOf(), - footerText = "", + footerText = getFooter(prevState), transactionDoneState = TransactionDoneState.Empty, pendingAction = possibleConfirmationState?.pendingAction, isApprovalNeeded = false, @@ -33,4 +43,35 @@ internal class SetConfirmationStateLoadingTransformer( ), ) } + + private fun getFooter(state: StakingUiState): TextReference { + val amountState = state.amountState as? AmountState.Data + val confirmationState = state.confirmationState as? StakingStates.ConfirmationState.Data + val validatorState = confirmationState?.validatorState as? ValidatorState.Content + + val isEnterAction = state.actionType == StakingActionCommonType.ENTER + + val apr = validatorState?.chosenValidator?.apr.orZero() + val amountDecimal = amountState?.amountTextField?.fiatAmount?.value + val potentialReward = amountDecimal?.multiply(apr) + + val amountValue = BigDecimalFormatter.formatFiatAmount( + fiatAmount = amountDecimal, + fiatCurrencyCode = appCurrency.code, + fiatCurrencySymbol = appCurrency.symbol, + ) + val potentialRewardValue = BigDecimalFormatter.formatFiatAmount( + fiatAmount = potentialReward, + fiatCurrencyCode = appCurrency.code, + fiatCurrencySymbol = appCurrency.symbol, + ) + return if (isEnterAction && amountDecimal != null && potentialReward != null) { + resourceReference( + id = R.string.staking_summary_description_text, + formatArgs = wrappedList(amountValue, potentialRewardValue), + ) + } else { + TextReference.EMPTY + } + } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt index ec70635b66..796723c946 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt @@ -211,7 +211,7 @@ internal class SetInitialDataStateTransformer( feeState = FeeState.Loading, validatorState = ValidatorState.Loading, notifications = persistentListOf(), - footerText = "", + footerText = TextReference.EMPTY, transactionDoneState = TransactionDoneState.Empty, pendingAction = null, isApprovalNeeded = isApprovalNeeded, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt index d7a9431621..128ff53e50 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt @@ -5,20 +5,16 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData import com.tangem.common.ui.amountScreen.ui.AmountBlock -import com.tangem.core.ui.components.SpacerHMax import com.tangem.core.ui.components.transactions.TransactionDoneTitle import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -71,22 +67,9 @@ internal fun StakingConfirmationContent( } StakingFeeBlock(feeState = state.feeState) NotificationsBlock(notifications = state.notifications) - SpacerHMax() - FooterText(text = state.footerText) } } -@Composable -private fun FooterText(text: String) { - Text( - modifier = Modifier.fillMaxWidth(), - text = text, - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.caption2, - textAlign = TextAlign.Center, - ) -} - @Preview(widthDp = 360, showBackground = true) @Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt index 568d824f9e..54f2aedeb1 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt @@ -36,6 +36,7 @@ import kotlinx.coroutines.flow.withIndex @Composable internal fun StakingScreen(uiState: StakingUiState) { val snackbarHostState = remember { SnackbarHostState() } + val confirmationState = uiState.confirmationState as? StakingStates.ConfirmationState.Data BackHandler(onBack = uiState.clickIntents::onPrevClick) Column( @@ -55,6 +56,7 @@ internal fun StakingScreen(uiState: StakingUiState) { ) NavigationButtonsBlock( buttonState = uiState.buttonsState, + footerText = confirmationState?.footerText.takeIf { uiState.currentStep == StakingStep.Confirmation }, modifier = Modifier.padding( start = TangemTheme.dimens.spacing16, end = TangemTheme.dimens.spacing16, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt index e2e06a8b8e..dd305ad949 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt @@ -172,7 +172,7 @@ internal class StakingViewModel @Inject constructor( } stakingStateRouter.onNextClick() when { - isInitState() -> stateController.update(SetConfirmationStateLoadingTransformer(yield)) + isInitState() -> stateController.update(SetConfirmationStateLoadingTransformer(yield, appCurrency)) isAssentState() -> getFee(pendingAction) } } @@ -183,7 +183,7 @@ internal class StakingViewModel @Inject constructor( override fun getFee(pendingAction: PendingAction?) { viewModelScope.launch { - stateController.update(SetConfirmationStateLoadingTransformer(yield)) + stateController.update(SetConfirmationStateLoadingTransformer(yield, appCurrency)) val cryptoCurrencyValue = cryptoCurrencyStatus.value val confirmationState = value.confirmationState as? StakingStates.ConfirmationState.Data ?: error("No confirmation state")