diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/atoms/radiobutton/TangemRadioButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/atoms/radiobutton/TangemRadioButton.kt index 20d61ebe87..777062e8bd 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/atoms/radiobutton/TangemRadioButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/atoms/radiobutton/TangemRadioButton.kt @@ -26,11 +26,18 @@ import com.tangem.core.ui.res.TangemThemePreview * @param isSelected Whether the radio button is selected * @param onClick Called when the user clicks the button * @param modifier Modifier to be applied to the button + * @param isEnabled Whether the button click is enabled */ @Composable -fun TangemRadioButton(isSelected: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { +fun TangemRadioButton( + isSelected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, + isEnabled: Boolean = true, +) { Box( modifier = modifier.clickable( + enabled = isEnabled, interactionSource = remember { MutableInteractionSource() }, indication = rememberRipple(bounded = false, radius = TangemTheme.dimens.size16), onClick = onClick, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt index 7d70ebd667..79fff44a09 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt @@ -30,7 +30,9 @@ internal class StakingStateRouter( fun onNextClick() { when (stateController.uiState.value.currentStep) { StakingStep.InitialInfo -> showAmount() - StakingStep.Amount -> showConfirm() + StakingStep.Validators, + StakingStep.Amount, + -> showConfirm() StakingStep.Confirm -> showSuccess() StakingStep.Success -> onBackClick() } @@ -51,6 +53,10 @@ internal class StakingStateRouter( stateController.update { it.copy(currentStep = StakingStep.Amount) } } + fun showValidators() { + stateController.update { it.copy(currentStep = StakingStep.Validators) } + } + fun showConfirm() { stateController.update { it.copy(currentStep = StakingStep.Confirm) } } 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 bd01183407..1f6e81e3b3 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 @@ -6,7 +6,6 @@ import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.core.ui.event.StateEvent import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.appcurrency.model.AppCurrency -import com.tangem.domain.staking.model.Yield import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents import kotlinx.collections.immutable.ImmutableList import java.math.BigDecimal @@ -85,16 +84,12 @@ internal sealed class StakingStates { val appCurrency: AppCurrency, val isFeeApproximate: Boolean, ) - - data class ValidatorState( - val validatorState: InnerValidatorState, - val availableValidators: List, - ) } enum class StakingStep { InitialInfo, Amount, + Validators, Confirm, Success, } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerValidatorState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/ValidatorState.kt similarity index 53% rename from features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerValidatorState.kt rename to features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/ValidatorState.kt index 8a3c91fa45..d99ed81d8e 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerValidatorState.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/ValidatorState.kt @@ -4,13 +4,14 @@ import androidx.compose.runtime.Immutable import com.tangem.domain.staking.model.Yield @Immutable -internal sealed class InnerValidatorState { +internal sealed class ValidatorState { data class Content( val chosenValidator: Yield.Validator, - ) : InnerValidatorState() + val availableValidators: List, + ) : ValidatorState() - data object Loading : InnerValidatorState() + data object Loading : ValidatorState() - data object Error : InnerValidatorState() + data object Error : ValidatorState() } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmStakingStatePreviewData.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmStakingStatePreviewData.kt index 13d3cc4a1c..3e81a056fc 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmStakingStatePreviewData.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmStakingStatePreviewData.kt @@ -7,9 +7,9 @@ import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.staking.model.Yield import com.tangem.features.staking.impl.presentation.state.InnerFeeState -import com.tangem.features.staking.impl.presentation.state.InnerValidatorState import com.tangem.features.staking.impl.presentation.state.StakingNotification import com.tangem.features.staking.impl.presentation.state.StakingStates +import com.tangem.features.staking.impl.presentation.state.ValidatorState import kotlinx.collections.immutable.persistentListOf import java.math.BigDecimal @@ -73,10 +73,8 @@ internal object ConfirmStakingStatePreviewData { isFeeApproximate = false, isFeeConvertibleToFiat = true, ), - validatorState = StakingStates.ValidatorState( - validatorState = InnerValidatorState.Content( - chosenValidator = validatorList[0], - ), + validatorState = ValidatorState.Content( + chosenValidator = validatorList[0], availableValidators = validatorList, ), footerText = "You stake \$715.11 and will be receiving ~\$35 monthly", diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt index 7c01094036..f59a64f975 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt @@ -1,5 +1,6 @@ package com.tangem.features.staking.impl.presentation.state.stub +import com.tangem.domain.staking.model.Yield import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents object StakingClickIntentsStub : StakingClickIntents { @@ -19,4 +20,8 @@ object StakingClickIntentsStub : StakingClickIntents { override fun onCurrencyChangeClick(isFiat: Boolean) {} override fun onAmountNext() {} + + override fun openValidators() {} + + override fun onValidatorSelect(validator: Yield.Validator) {} } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingValidatorStateStub.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingValidatorStateStub.kt deleted file mode 100644 index 3c1c646537..0000000000 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingValidatorStateStub.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.tangem.features.staking.impl.presentation.state.stub - -import com.tangem.domain.staking.model.Yield -import com.tangem.features.staking.impl.presentation.state.StakingStates - -internal object StakingValidatorStateStub { - private val validator = Yield.Validator( - address = "address", - status = "status", - name = "Binance", - image = null, - website = null, - apr = "0.0354".toBigDecimal(), - commission = null, - stakedBalance = null, - votingPower = null, - preferred = false, - ) - - val state = StakingStates.ValidatorState.Data( - isPrimaryButtonEnabled = false, - validators = listOf( - validator, - validator.copy( - address = "TRONLink", - name = "TRONLink", - apr = "0.0506".toBigDecimal(), - ), - validator.copy( - address = "1inch", - name = "1inch", - apr = "0.0306".toBigDecimal(), - ), - ), - selectedValidator = validator, - ) -} \ 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 c06765c6ed..7a0d619a46 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 @@ -14,8 +14,10 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWallet import com.tangem.features.staking.impl.R import com.tangem.features.staking.impl.presentation.state.StakingStates -import com.tangem.features.staking.impl.presentation.state.StakingUiState import com.tangem.features.staking.impl.presentation.state.StakingStep +import com.tangem.features.staking.impl.presentation.state.StakingUiState +import com.tangem.features.staking.impl.presentation.state.ValidatorState +import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmStakingStatePreviewData import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents import com.tangem.utils.Provider import com.tangem.utils.transformer.Transformer @@ -47,6 +49,7 @@ internal class SetInitialDataStateTransformer( currentStep = StakingStep.InitialInfo, initialInfoState = createInitialInfoState(), amountState = createInitialAmountState(), + confirmStakingState = createInitialConfirmationState(), ) } @@ -75,6 +78,15 @@ internal class SetInitialDataStateTransformer( return amountStateConverter.convert("") } + private fun createInitialConfirmationState(): StakingStates.ConfirmStakingState { + return ConfirmStakingStatePreviewData.confirmStakingState.copy( + validatorState = ValidatorState.Content( + chosenValidator = yield.validators.first(), + availableValidators = yield.validators, + ), + ) + } + private fun getAprRange(): TextReference { val aprValues = yield.validators.mapNotNull { it.apr } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt new file mode 100644 index 0000000000..b72f227693 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt @@ -0,0 +1,24 @@ +package com.tangem.features.staking.impl.presentation.state.transformers.validator + +import com.tangem.domain.staking.model.Yield +import com.tangem.features.staking.impl.presentation.state.StakingStates +import com.tangem.features.staking.impl.presentation.state.StakingUiState +import com.tangem.features.staking.impl.presentation.state.ValidatorState +import com.tangem.utils.transformer.Transformer + +internal class ValidatorSelectChangeTransformer( + private val selectedValidator: Yield.Validator, +) : Transformer { + override fun transform(prevState: StakingUiState): StakingUiState { + val confirmState = prevState.confirmStakingState as? StakingStates.ConfirmStakingState.Data ?: return prevState + val validatorState = confirmState.validatorState as? ValidatorState.Content ?: return prevState + + return prevState.copy( + confirmStakingState = confirmState.copy( + validatorState = validatorState.copy( + chosenValidator = selectedValidator, + ), + ), + ) + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmContent.kt index 9c78086d8f..be8589fa2f 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmContent.kt @@ -18,11 +18,18 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmStakingStatePreviewData +import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub import com.tangem.features.staking.impl.presentation.ui.block.NotificationsBlock import com.tangem.features.staking.impl.presentation.ui.block.StakingFeeBlock +import com.tangem.features.staking.impl.presentation.ui.block.ValidatorBlock +import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents @Composable -internal fun StakingConfirmContent(amountState: AmountState, state: StakingStates.ConfirmStakingState) { +internal fun StakingConfirmContent( + amountState: AmountState, + state: StakingStates.ConfirmStakingState, + clickIntents: StakingClickIntents, +) { if (state !is StakingStates.ConfirmStakingState.Data) return Column( @@ -39,6 +46,7 @@ internal fun StakingConfirmContent(amountState: AmountState, state: StakingState isEditingDisabled = true, onClick = {}, ) + ValidatorBlock(validatorState = state.validatorState, onClick = clickIntents::openValidators) StakingFeeBlock(feeState = state.feeState) NotificationsBlock(notifications = state.notifications) SpacerHMax() @@ -66,6 +74,7 @@ private fun Preview_StakingConfirmContent() { StakingConfirmContent( amountState = AmountStatePreviewData.amountState, state = ConfirmStakingStatePreviewData.confirmStakingState, + clickIntents = StakingClickIntentsStub, ) } } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt index 21105e3419..9ae31fc482 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt @@ -1,6 +1,8 @@ package com.tangem.features.staking.impl.presentation.ui -import androidx.compose.animation.* +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandHorizontally +import androidx.compose.animation.shrinkHorizontally import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -9,7 +11,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -24,8 +26,8 @@ import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults import com.tangem.core.ui.res.TangemTheme import com.tangem.features.staking.impl.presentation.state.StakingStates -import com.tangem.features.staking.impl.presentation.state.StakingUiState import com.tangem.features.staking.impl.presentation.state.StakingStep +import com.tangem.features.staking.impl.presentation.state.StakingUiState @Composable internal fun StakingNavigationButtons(uiState: StakingUiState, modifier: Modifier = Modifier) { @@ -105,7 +107,8 @@ private fun getButtonData(currentState: StakingUiState): Pair Unit> { StakingStep.Amount, StakingStep.Confirm, StakingStep.Success, - -> R.string.common_next to { currentState.clickIntents.onNextClick() } + -> R.string.common_next to currentState.clickIntents::onNextClick + StakingStep.Validators -> R.string.common_continue to currentState.clickIntents::onNextClick } } @@ -113,6 +116,7 @@ private fun isButtonEnabled(uiState: StakingUiState): Boolean { return when (uiState.currentStep) { StakingStep.InitialInfo -> uiState.initialInfoState.isPrimaryButtonEnabled StakingStep.Amount -> uiState.amountState.isPrimaryButtonEnabled + StakingStep.Validators -> uiState.confirmStakingState.isPrimaryButtonEnabled StakingStep.Confirm -> uiState.confirmStakingState.isPrimaryButtonEnabled StakingStep.Success -> true } 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 a8f36b6e5e..4a41fba77f 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 @@ -16,6 +16,7 @@ import com.tangem.common.ui.amountScreen.AmountScreenContent import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon import com.tangem.core.ui.res.TangemTheme import com.tangem.features.staking.impl.R +import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.features.staking.impl.presentation.state.StakingStep import com.tangem.features.staking.impl.presentation.state.StakingUiState import kotlinx.coroutines.delay @@ -50,13 +51,16 @@ internal fun StakingScreen(uiState: StakingUiState) { @Composable private fun SendAppBar(uiState: StakingUiState) { val titleRes = when (uiState.currentStep) { - StakingStep.InitialInfo -> stringResource(id = R.string.common_stake) StakingStep.Amount -> stringResource(id = R.string.send_amount_label) - StakingStep.Confirm -> stringResource(id = R.string.common_stake) + StakingStep.InitialInfo, + StakingStep.Validators, + StakingStep.Confirm, + -> stringResource(id = R.string.common_stake) StakingStep.Success -> "" } val backIcon = when (uiState.currentStep) { StakingStep.Amount, + StakingStep.Validators, StakingStep.Confirm, StakingStep.Success, -> { @@ -130,7 +134,16 @@ private fun StakingScreenContent(uiState: StakingUiState, modifier: Modifier = M StakingStep.Confirm -> StakingConfirmContent( amountState = uiState.amountState, state = uiState.confirmStakingState, + clickIntents = uiState.clickIntents, ) + StakingStep.Validators -> { + val confirmState = uiState.confirmStakingState + if (confirmState !is StakingStates.ConfirmStakingState.Data) return@AnimatedContent + StakingValidatorListContent( + state = confirmState.validatorState, + clickIntents = uiState.clickIntents, + ) + } else -> TODO() } } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt index 88186729cf..1d6e05103d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt @@ -26,9 +26,9 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.features.staking.impl.R -import com.tangem.features.staking.impl.presentation.state.StakingStates +import com.tangem.features.staking.impl.presentation.state.ValidatorState +import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmStakingStatePreviewData import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub -import com.tangem.features.staking.impl.presentation.state.stub.StakingValidatorStateStub import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents import java.math.BigDecimal @@ -37,11 +37,10 @@ import java.math.BigDecimal */ @Composable internal fun StakingValidatorListContent( - state: StakingStates.ValidatorState, + state: ValidatorState, clickIntents: StakingClickIntents, modifier: Modifier = Modifier, ) { - if (state !is StakingStates.ValidatorState.Data) return val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() } LazyColumn( @@ -65,41 +64,44 @@ internal fun StakingValidatorListContent( ), ) } - items( - count = state.validators.size, - key = { state.validators[it] }, - contentType = { state.validators[it]::class.java }, - ) { index -> - val item = state.validators[index] + if (state is ValidatorState.Content) { + val validators = state.availableValidators + items( + count = validators.size, + key = { validators[it].address }, + contentType = { validators[it]::class.java }, + ) { index -> + val item = validators[index] - InputRowImageSelector( - subtitle = stringReference(item.name), - caption = combinedReference( - resourceReference(R.string.staking_details_apr), - annotatedReference( - buildAnnotatedString { - append(" ") - withStyle(style = SpanStyle(color = TangemTheme.colors.text.accent)) { - append( - BigDecimalFormatter.formatPercent(item.apr ?: BigDecimal.ZERO, true), - ) - } - }, + InputRowImageSelector( + subtitle = stringReference(item.name), + caption = combinedReference( + resourceReference(R.string.staking_details_apr), + annotatedReference( + buildAnnotatedString { + append(" ") + withStyle(style = SpanStyle(color = TangemTheme.colors.text.accent)) { + append( + BigDecimalFormatter.formatPercent(item.apr ?: BigDecimal.ZERO, true), + ) + } + }, + ), ), - ), - imageUrl = item.image.orEmpty(), - isSelected = item == state.selectedValidator, - onSelect = { clickIntents.onValidatorSelect(item) }, - modifier = Modifier - .clip( - if (index == state.validators.lastIndex) { - CornersToRound.BOTTOM_2 - } else { - CornersToRound.ZERO - }.getShape(), - ) - .background(TangemTheme.colors.background.action), - ) + imageUrl = item.image.orEmpty(), + isSelected = item == state.chosenValidator, + onSelect = { clickIntents.onValidatorSelect(item) }, + modifier = Modifier + .clip( + if (index == validators.lastIndex) { + CornersToRound.BOTTOM_2 + } else { + CornersToRound.ZERO + }.getShape(), + ) + .background(TangemTheme.colors.background.action), + ) + } } } } @@ -110,7 +112,7 @@ internal fun StakingValidatorListContent( @Composable private fun StakingValidatorListContent_Preview( @PreviewParameter(StakingValidatorListContentPreviewProvider::class) - data: StakingStates.ValidatorState.Data, + data: ValidatorState, ) { TangemThemePreview { StakingValidatorListContent( @@ -120,8 +122,8 @@ private fun StakingValidatorListContent_Preview( } } -private class StakingValidatorListContentPreviewProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf(StakingValidatorStateStub.state) +private class StakingValidatorListContentPreviewProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf(ConfirmStakingStatePreviewData.confirmStakingState.validatorState) } // endregion \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt new file mode 100644 index 0000000000..4cee3bcba5 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt @@ -0,0 +1,69 @@ +package com.tangem.features.staking.impl.presentation.ui.block + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.ripple.rememberRipple +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import com.tangem.core.ui.components.inputrow.InputRowImageChevron +import com.tangem.core.ui.extensions.annotatedReference +import com.tangem.core.ui.extensions.combinedReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.BigDecimalFormatter +import com.tangem.features.staking.impl.R +import com.tangem.features.staking.impl.presentation.state.ValidatorState +import java.math.BigDecimal + +@Composable +internal fun ValidatorBlock(validatorState: ValidatorState, onClick: () -> Unit) { + Column( + modifier = Modifier + .fillMaxWidth() + .clip(TangemTheme.shapes.roundedCornersXMedium) + .background(TangemTheme.colors.background.action) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple(), + onClick = onClick, + ) + .padding(TangemTheme.dimens.spacing12), + ) { + Text( + text = stringResource(R.string.staking_validator), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.tertiary, + modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing6), + ) + if (validatorState is ValidatorState.Content) { + InputRowImageChevron( + subtitle = stringReference(validatorState.chosenValidator.name), + caption = combinedReference( + resourceReference(R.string.staking_details_apr), + annotatedReference( + buildAnnotatedString { + append(" ") + withStyle(SpanStyle(color = TangemTheme.colors.text.accent)) { + val apr = validatorState.chosenValidator.apr ?: BigDecimal.ZERO + append(BigDecimalFormatter.formatPercent(apr, true)) + } + }, + ), + ), + imageUrl = validatorState.chosenValidator.image.orEmpty(), + ) + } + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt index 27cd56dced..235659fa3e 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt @@ -1,6 +1,7 @@ package com.tangem.features.staking.impl.presentation.viewmodel import com.tangem.common.ui.amountScreen.AmountScreenClickIntents +import com.tangem.domain.staking.model.Yield internal interface StakingClickIntents : AmountScreenClickIntents { @@ -11,4 +12,8 @@ internal interface StakingClickIntents : AmountScreenClickIntents { fun onPrevClick() override fun onAmountNext() = onNextClick() + + fun openValidators() + + fun onValidatorSelect(validator: Yield.Validator) } \ No newline at end of file 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 15d7803cc7..ee086db4f2 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 @@ -15,22 +15,20 @@ import com.tangem.domain.staking.model.Yield import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.features.staking.impl.navigation.InnerStakingRouter import com.tangem.features.staking.impl.presentation.state.StakingStateController import com.tangem.features.staking.impl.presentation.state.StakingStateRouter -import com.tangem.features.staking.impl.presentation.state.StakingStep import com.tangem.features.staking.impl.presentation.state.StakingUiState import com.tangem.features.staking.impl.presentation.state.transformers.HideBalanceStateTransformer -import com.tangem.features.staking.impl.presentation.state.transformers.SetConfirmStateDataStateTransformer import com.tangem.features.staking.impl.presentation.state.transformers.SetInitialDataStateTransformer import com.tangem.features.staking.impl.presentation.state.transformers.amount.AmountChangeStateTransformer import com.tangem.features.staking.impl.presentation.state.transformers.amount.AmountCurrencyChangeStateTransformer import com.tangem.features.staking.impl.presentation.state.transformers.amount.AmountMaxValueStateTransformer import com.tangem.features.staking.impl.presentation.state.transformers.amount.AmountPasteDismissStateTransformer +import com.tangem.features.staking.impl.presentation.state.transformers.validator.ValidatorSelectChangeTransformer import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.hilt.android.lifecycle.HiltViewModel @@ -48,7 +46,6 @@ internal class StakingViewModel @Inject constructor( private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getUserWalletUseCase: GetUserWalletUseCase, - private val isFeeApproximateUseCase: IsFeeApproximateUseCase, savedStateHandle: SavedStateHandle, ) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents { @@ -58,18 +55,17 @@ internal class StakingViewModel @Inject constructor( var stakingStateRouter: StakingStateRouter by Delegates.notNull() private set - private val cryptoCurrencyId: CryptoCurrency.ID = savedStateHandle.get( - AppRoute.Staking.CRYPTO_CURRENCY_ID_KEY, - ) - ?.let { it.unbundle(CryptoCurrency.ID.serializer()) } - ?: error("This screen can't be opened without `CryptoCurrency.ID`") + private val cryptoCurrencyId: CryptoCurrency.ID = + savedStateHandle.get(AppRoute.Staking.CRYPTO_CURRENCY_ID_KEY) + ?.unbundle(CryptoCurrency.ID.serializer()) + ?: error("This screen can't be opened without `CryptoCurrency.ID`") private val userWalletId: UserWalletId = savedStateHandle.get(AppRoute.Staking.USER_WALLET_ID_KEY) - ?.let { it.unbundle(UserWalletId.serializer()) } + ?.unbundle(UserWalletId.serializer()) ?: error("This screen can't be opened without `UserWalletId`") private val yield: Yield = savedStateHandle.get(AppRoute.Staking.YIELD_KEY) - ?.let { it.unbundle(Yield.serializer()) } + ?.unbundle(Yield.serializer()) ?: error("This screen can't be opened without `Yield`") private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull() @@ -90,27 +86,6 @@ internal class StakingViewModel @Inject constructor( override fun onNextClick() { stakingStateRouter.onNextClick() - when (value.currentStep) { - StakingStep.Confirm -> { - stateController.update( - SetConfirmStateDataStateTransformer( - yield = yield, - appCurrencyProvider = Provider { appCurrency }, - cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, - isFeeApproximateUseCase = isFeeApproximateUseCase, - ), - ) - } - StakingStep.InitialInfo -> { - // TODO staking - } - StakingStep.Amount -> { - // TODO staking - } - StakingStep.Success -> { - // TODO staking - } - } } override fun onPrevClick() { @@ -133,6 +108,12 @@ internal class StakingViewModel @Inject constructor( stateController.update(AmountCurrencyChangeStateTransformer(cryptoCurrencyStatus, isFiat)) } + override fun openValidators() = stakingStateRouter.showValidators() + + override fun onValidatorSelect(validator: Yield.Validator) { + stateController.update(ValidatorSelectChangeTransformer(validator)) + } + fun setRouter(router: InnerStakingRouter, stateRouter: StakingStateRouter) { innerRouter = router this.stakingStateRouter = stateRouter