Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-24 15:50:00 +05:00
parent fbfcad9325
commit 3acfadfb08
16 changed files with 242 additions and 9 deletions

View file

@ -42,6 +42,7 @@ internal class StakingStateController @Inject constructor() {
confirmStakingState = StakingStates.ConfirmStakingState.Empty(),
isBalanceHidden = false,
event = consumedEvent(),
bottomSheetConfig = null,
)
}
}

View file

@ -3,9 +3,11 @@ package com.tangem.features.staking.impl.presentation.state
import androidx.compose.runtime.Immutable
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.features.staking.impl.presentation.state.transformers.InfoType
import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents
import kotlinx.collections.immutable.ImmutableList
import java.math.BigDecimal
@ -22,6 +24,7 @@ internal data class StakingUiState(
val amountState: AmountState,
val confirmStakingState: StakingStates.ConfirmStakingState,
val isBalanceHidden: Boolean,
val bottomSheetConfig: TangemBottomSheetConfig?,
val event: StateEvent<StakingEvent>,
) {
@ -52,6 +55,7 @@ internal sealed class StakingStates {
val rewardClaiming: String,
val warmupPeriod: String,
val rewardSchedule: String,
val onInfoClick: (InfoType) -> Unit,
) : InitialInfoState()
data class Empty(

View file

@ -0,0 +1,9 @@
package com.tangem.features.staking.impl.presentation.state.bottomsheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.extensions.TextReference
data class StakingInfoBottomSheetConfig(
val title: TextReference,
val text: TextReference,
) : TangemBottomSheetConfigContent

View file

@ -1,6 +1,7 @@
package com.tangem.features.staking.impl.presentation.state.stub
import com.tangem.domain.staking.model.Yield
import com.tangem.features.staking.impl.presentation.state.transformers.InfoType
import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents
object StakingClickIntentsStub : StakingClickIntents {
@ -11,6 +12,8 @@ object StakingClickIntentsStub : StakingClickIntents {
override fun onPrevClick() {}
override fun onInfoClick(infoType: InfoType) {}
override fun onAmountValueChange(value: String) {}
override fun onAmountPasteTriggerDismiss() {}

View file

@ -0,0 +1,10 @@
package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class DismissBottomSheetStateTransformer : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(bottomSheetConfig = null)
}
}

View file

@ -70,7 +70,7 @@ internal class SetInitialDataStateTransformer(
rewardClaiming = yield.metadata.rewardClaiming,
warmupPeriod = yield.metadata.warmupPeriod.days.toString(),
rewardSchedule = yield.metadata.rewardSchedule,
onInfoClick = clickIntents::onInfoClick,
)
}

View file

@ -0,0 +1,53 @@
package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingInfoBottomSheetConfig
import com.tangem.utils.transformer.Transformer
internal class ShowInfoBottomSheetStateTransformer(
private val infoType: InfoType,
private val onDismiss: () -> Unit,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(
bottomSheetConfig = TangemBottomSheetConfig(
onDismissRequest = onDismiss,
isShow = true,
content = when (infoType) {
InfoType.APY -> StakingInfoBottomSheetConfig(
title = resourceReference(R.string.staking_details_apy),
text = resourceReference(R.string.staking_details_apy_info),
)
InfoType.UNBOUNDING_PERIOD -> StakingInfoBottomSheetConfig(
title = resourceReference(R.string.staking_details_unbonding_period),
text = resourceReference(R.string.staking_details_unbonding_period_info),
)
InfoType.REWARD_CLAIMING -> StakingInfoBottomSheetConfig(
title = resourceReference(R.string.staking_details_reward_claiming),
text = resourceReference(R.string.staking_details_reward_claiming_info),
)
InfoType.WARMUP_PERIOD -> StakingInfoBottomSheetConfig(
title = resourceReference(R.string.staking_details_warmup_period),
text = resourceReference(R.string.staking_details_warmup_period_info),
)
InfoType.REWARD_SCHEDULE -> StakingInfoBottomSheetConfig(
title = resourceReference(R.string.staking_details_reward_schedule),
text = resourceReference(R.string.staking_details_reward_schedule_info),
)
},
),
)
}
}
enum class InfoType {
APY,
UNBOUNDING_PERIOD,
REWARD_CLAIMING,
WARMUP_PERIOD,
REWARD_SCHEDULE,
}

View file

@ -25,6 +25,7 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.StakingStates
import com.tangem.features.staking.impl.presentation.state.transformers.InfoType
@Composable
internal fun StakingInitialInfoContent(state: StakingStates.InitialInfoState) {
@ -121,11 +122,13 @@ internal fun StakingDetailsRows(state: StakingStates.InitialInfoState.Data) {
startText = stringResource(id = R.string.staking_details_apy),
endText = state.aprRange.resolveReference(),
cornersToRound = CornersToRound.ZERO,
iconClick = { state.onInfoClick(InfoType.APY) },
)
InitialInfoContentRow(
startText = stringResource(id = R.string.staking_details_unbonding_period),
endText = state.unbondingPeriod,
cornersToRound = CornersToRound.ZERO,
iconClick = { state.onInfoClick(InfoType.UNBOUNDING_PERIOD) },
)
InitialInfoContentRow(
startText = stringResource(id = R.string.staking_details_minimum_requirement),
@ -136,21 +139,29 @@ internal fun StakingDetailsRows(state: StakingStates.InitialInfoState.Data) {
startText = stringResource(id = R.string.staking_details_reward_claiming),
endText = state.rewardClaiming,
cornersToRound = CornersToRound.ZERO,
iconClick = { state.onInfoClick(InfoType.REWARD_CLAIMING) },
)
InitialInfoContentRow(
startText = stringResource(id = R.string.staking_details_warmup_period),
endText = state.warmupPeriod,
cornersToRound = CornersToRound.ZERO,
iconClick = { state.onInfoClick(InfoType.WARMUP_PERIOD) },
)
InitialInfoContentRow(
startText = stringResource(id = R.string.staking_details_reward_schedule),
endText = state.rewardSchedule,
cornersToRound = CornersToRound.BOTTOM_2,
iconClick = { state.onInfoClick(InfoType.REWARD_SCHEDULE) },
)
}
@Composable
private fun InitialInfoContentRow(startText: String, endText: String, cornersToRound: CornersToRound) {
private fun InitialInfoContentRow(
startText: String,
endText: String,
cornersToRound: CornersToRound,
iconClick: (() -> Unit)? = null,
) {
RoundableCornersRow(
startText = startText,
startTextColor = TangemTheme.colors.text.primary1,
@ -159,7 +170,8 @@ private fun InitialInfoContentRow(startText: String, endText: String, cornersToR
endTextColor = TangemTheme.colors.text.tertiary,
endTextStyle = TangemTheme.typography.body2,
cornersToRound = cornersToRound,
iconResId = null, // TODO staking add bottom sheets when text will be available
iconResId = R.drawable.ic_information_24,
iconClick = iconClick,
)
}
@ -189,6 +201,7 @@ private class StakingInitialInfoContentPreviewProvider : PreviewParameterProvide
rewardClaiming = "Auto",
warmupPeriod = "Days",
rewardSchedule = "Block",
onInfoClick = {},
),
)
}

View file

@ -14,11 +14,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.tangem.common.ui.amountScreen.AmountScreenContent
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
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 com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingInfoBottomSheetConfig
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingInfoBottomSheet
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@ -45,6 +48,15 @@ internal fun StakingScreen(uiState: StakingUiState) {
StakingNavigationButtons(
uiState = uiState,
)
StakingBottomSheet(bottomSheetConfig = uiState.bottomSheetConfig)
}
}
@Composable
fun StakingBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
if (bottomSheetConfig == null) return
when (bottomSheetConfig.content) {
is StakingInfoBottomSheetConfig -> StakingInfoBottomSheet(bottomSheetConfig)
}
}

View file

@ -0,0 +1,38 @@
package com.tangem.features.staking.impl.presentation.ui.bottomsheet
import androidx.compose.foundation.layout.Column
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.ui.Modifier
import com.tangem.core.ui.components.appbar.AppBar
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingInfoBottomSheetConfig
@Composable
fun StakingInfoBottomSheet(config: TangemBottomSheetConfig) {
val scrollState = rememberScrollState()
TangemBottomSheet(
config = config,
) { content: StakingInfoBottomSheetConfig ->
Column(
modifier = Modifier.verticalScroll(scrollState),
) {
AppBar(text = content.title)
Text(
text = content.text.resolveReference(),
color = TangemTheme.colors.text.secondary,
style = TangemTheme.typography.body2,
modifier = Modifier.padding(
horizontal = TangemTheme.dimens.spacing28,
vertical = TangemTheme.dimens.spacing16,
),
)
}
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.features.staking.impl.presentation.viewmodel
import com.tangem.common.ui.amountScreen.AmountScreenClickIntents
import com.tangem.domain.staking.model.Yield
import com.tangem.features.staking.impl.presentation.state.transformers.InfoType
internal interface StakingClickIntents : AmountScreenClickIntents {
@ -11,6 +12,8 @@ internal interface StakingClickIntents : AmountScreenClickIntents {
fun onPrevClick()
fun onInfoClick(infoType: InfoType)
override fun onAmountNext() = onNextClick()
fun openValidators()

View file

@ -22,8 +22,7 @@ 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.StakingUiState
import com.tangem.features.staking.impl.presentation.state.transformers.HideBalanceStateTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.SetInitialDataStateTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.*
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
@ -92,6 +91,14 @@ internal class StakingViewModel @Inject constructor(
stakingStateRouter.onBackClick()
}
override fun onInfoClick(infoType: InfoType) {
stateController.update(
ShowInfoBottomSheetStateTransformer(infoType) {
stateController.update(DismissBottomSheetStateTransformer())
},
)
}
override fun onAmountValueChange(value: String) {
stateController.update(AmountChangeStateTransformer(cryptoCurrencyStatus, value))
}