Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-04 13:40:23 +05:00
parent 7dab5f79b2
commit cc3a64bb05
15 changed files with 144 additions and 21 deletions

View file

@ -2,6 +2,7 @@ package com.tangem.features.staking.impl.presentation.state
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.event.triggeredEvent
import com.tangem.core.ui.extensions.TextReference
@ -19,7 +20,9 @@ import javax.inject.Inject
import javax.inject.Singleton
@Singleton
internal class StakingStateController @Inject constructor() {
internal class StakingStateController @Inject constructor(
private val urlOpener: UrlOpener,
) {
val value: StakingUiState get() = uiState.value
@ -27,7 +30,7 @@ internal class StakingStateController @Inject constructor() {
val uiState: StateFlow<StakingUiState> get() = mutableUiState.asStateFlow()
private val buttonsTransformer = SetButtonsStateTransformer()
private val buttonsTransformer = SetButtonsStateTransformer(urlOpener)
private val titleTransformer = SetTitleTransformer
fun update(function: (StakingUiState) -> StakingUiState) {

View file

@ -2,6 +2,7 @@ package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.common.ui.navigationButtons.NavigationButton
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.R
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
@ -12,7 +13,9 @@ import com.tangem.utils.transformer.Transformer
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
internal class SetButtonsStateTransformer : Transformer<StakingUiState> {
internal class SetButtonsStateTransformer(
private val urlOpener: UrlOpener,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
val confirmState = prevState.confirmationState as? StakingStates.ConfirmationState.Data
@ -23,6 +26,7 @@ internal class SetButtonsStateTransformer : Transformer<StakingUiState> {
prevButton = getPrevButton(prevState),
extraButtons = getExtraButtons(prevState),
txUrl = (confirmState?.transactionDoneState as? TransactionDoneState.Content)?.txUrl,
onTextClick = urlOpener::openUrl,
)
} else {
NavigationButtonsState.Empty

View file

@ -28,6 +28,9 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.Density
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
import com.tangem.common.ui.navigationButtons.NavigationPrimaryButton
import com.tangem.core.ui.components.SpacerH12
import com.tangem.core.ui.components.containers.FooterContainer
import com.tangem.core.ui.components.inputrow.InputRowDefault
@ -56,14 +59,21 @@ import kotlinx.collections.immutable.ImmutableList
private const val BANNER_BLOCK_KEY = "BannerBlock"
private const val STAKING_REWARD_BLOCK_KEY = "StakingRewardBlock"
private const val ACTIVE_STAKING_BLOCK_KEY = "ActiveStakingBlock"
private const val STAKE_PRIMARY_BUTTON_KEY = "StakePrimaryButton"
@OptIn(ExperimentalFoundationApi::class)
@Composable
internal fun StakingInitialInfoContent(state: StakingStates.InitialInfoState, clickIntents: StakingClickIntents) {
internal fun StakingInitialInfoContent(
state: StakingStates.InitialInfoState,
buttonState: NavigationButtonsState,
clickIntents: StakingClickIntents,
) {
if (state !is StakingStates.InitialInfoState.Data) return
LazyColumn(
verticalArrangement = alignLastToBottom(),
modifier = Modifier
.fillMaxSize()
.background(TangemTheme.colors.background.secondary)
.padding(horizontal = TangemTheme.dimens.spacing16),
) {
@ -105,6 +115,10 @@ internal fun StakingInitialInfoContent(state: StakingStates.InitialInfoState, cl
}
}
}
item(STAKE_PRIMARY_BUTTON_KEY) {
StakeButtonBlock(buttonState)
}
}
}
@ -236,6 +250,21 @@ private fun ActiveStakingBlock(groups: ImmutableList<BalanceGroupedState>, onCli
}
}
@Composable
private fun StakeButtonBlock(buttonState: NavigationButtonsState) {
val state = buttonState as? NavigationButtonsState.Data
val primaryButton = state?.primaryButton
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
state?.onTextClick?.let { StakingTosText(it) }
NavigationPrimaryButton(primaryButton = primaryButton)
}
}
@Composable
private fun getCaption(balanceType: BalanceType, balance: BalanceState): TextReference {
return when (balanceType) {
@ -289,6 +318,24 @@ private val textGradientColors = listOf(
Color(0xff8fb4df),
)
@Composable
private fun alignLastToBottom() = remember {
object : Arrangement.Vertical {
override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) {
var currentOffset = 0
sizes.forEachIndexed { index, size ->
if (index == sizes.lastIndex) {
outPositions[index] = totalSize - size
} else {
outPositions[index] = currentOffset
currentOffset += size
}
}
}
}
}
// region preview
@Preview(showBackground = true, widthDp = 360)
@ -300,6 +347,7 @@ private fun StakingInitialInfoContent_Preview(
TangemThemePreview {
StakingInitialInfoContent(
state = feeState,
buttonState = NavigationButtonsState.Empty,
clickIntents = StakingClickIntentsStub,
)
}

View file

@ -16,6 +16,7 @@ import com.tangem.common.ui.amountScreen.AmountScreenContent
import com.tangem.common.ui.bottomsheet.permission.GiveTxPermissionBottomSheet
import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionBottomSheetConfig
import com.tangem.common.ui.navigationButtons.NavigationButtonsBlock
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.resolveReference
@ -55,7 +56,8 @@ internal fun StakingScreen(uiState: StakingUiState) {
modifier = Modifier.weight(1f),
)
NavigationButtonsBlock(
buttonState = uiState.buttonsState,
buttonState = uiState.buttonsState.takeUnless { uiState.currentStep == StakingStep.InitialInfo }
?: NavigationButtonsState.Empty,
footerText = confirmationState?.footerText.takeIf { uiState.currentStep == StakingStep.Confirmation },
modifier = Modifier.padding(
start = TangemTheme.dimens.spacing16,
@ -153,6 +155,7 @@ private fun StakingScreenContent(uiState: StakingUiState, modifier: Modifier = M
when (state) {
StakingStep.InitialInfo -> StakingInitialInfoContent(
state = uiState.initialInfoState,
buttonState = uiState.buttonsState,
clickIntents = uiState.clickIntents,
)
StakingStep.RewardsValidators -> {

View file

@ -0,0 +1,62 @@
package com.tangem.features.staking.impl.presentation.ui
import androidx.compose.foundation.text.ClickableText
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import com.tangem.core.ui.extensions.appendColored
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.staking.impl.R
private const val TERMS_OF_USE_KEY = "termsOfUse"
private const val PRIVACY_POLICY_KEY = "privacyPolicy"
private const val TERMS_OF_USE_URL = "https://docs.stakek.it/docs/terms-of-use"
private const val PRIVACY_POLICY_URL = "https://docs.stakek.it/docs/privacy-policy"
@Composable
internal fun StakingTosText(onTextClick: (String) -> Unit) {
val termsOfUse = stringResource(R.string.common_terms_of_use)
val privacyPolicy = stringResource(R.string.common_privacy_policy)
val tosText = stringResource(R.string.staking_legal, termsOfUse, privacyPolicy)
val clickableAnnotation = buildAnnotatedString {
append(tosText.substringBefore(termsOfUse))
pushStringAnnotation(TERMS_OF_USE_KEY, "")
appendColored(termsOfUse, TangemTheme.colors.text.accent)
pop()
append(tosText.substringAfter(termsOfUse).substringBefore(privacyPolicy))
pushStringAnnotation(PRIVACY_POLICY_KEY, "")
appendColored(privacyPolicy, TangemTheme.colors.text.accent)
pop()
}
ClickableText(
text = clickableAnnotation,
style = TangemTheme.typography.caption2.copy(
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
),
onClick = { offset ->
clickableAnnotation.getStringAnnotations(
tag = TERMS_OF_USE_KEY,
start = offset,
end = offset,
).firstOrNull()?.let {
onTextClick(TERMS_OF_USE_URL)
}
clickableAnnotation.getStringAnnotations(
tag = PRIVACY_POLICY_KEY,
start = offset,
end = offset,
).firstOrNull()?.let {
onTextClick(PRIVACY_POLICY_URL)
}
},
)
}