Updated on 2026-08-14
This commit is contained in:
commit
e2c7c9bd56
23 changed files with 694 additions and 86 deletions
|
|
@ -0,0 +1,85 @@
|
|||
package com.tangem.core.ui.components.atoms.radiobutton
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
/**
|
||||
* [Radio button](https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=101-119&t=FH84ljLBk1vmGAei-4)
|
||||
*
|
||||
* @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,
|
||||
isEnabled: Boolean = true,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.clickable(
|
||||
enabled = isEnabled,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(bounded = false, radius = TangemTheme.dimens.size16),
|
||||
onClick = onClick,
|
||||
),
|
||||
) {
|
||||
val color = TangemTheme.colors.stroke.secondary
|
||||
val radius = with(LocalDensity.current) { TangemTheme.dimens.size9.toPx() }
|
||||
val width = with(LocalDensity.current) { TangemTheme.dimens.size2.toPx() }
|
||||
Canvas(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size24)
|
||||
.padding(TangemTheme.dimens.spacing2),
|
||||
) {
|
||||
drawCircle(
|
||||
color = color,
|
||||
radius = radius,
|
||||
style = Stroke(width),
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = isSelected,
|
||||
label = "Radio button animation",
|
||||
modifier = modifier
|
||||
.size(TangemTheme.dimens.size24),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_check_circle_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.control.checked,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemRadioButton_Preview() {
|
||||
var isSelected by remember { mutableStateOf(false) }
|
||||
TangemThemePreview {
|
||||
TangemRadioButton(isSelected, onClick = { isSelected = !isSelected })
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -5,7 +5,6 @@ import androidx.compose.foundation.background
|
|||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
|
|
@ -14,18 +13,15 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerWMax
|
||||
import com.tangem.core.ui.components.currency.tokenicon.LoadingIcon
|
||||
import com.tangem.core.ui.components.inputrow.inner.DividerContainer
|
||||
import com.tangem.core.ui.components.inputrow.inner.InputRowAsyncImage
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -63,7 +59,7 @@ fun InputRowBestRate(
|
|||
modifier = Modifier
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
InnerIcon(imageUrl = imageUrl)
|
||||
InputRowAsyncImage(imageUrl = imageUrl, modifier = Modifier.size(TangemTheme.dimens.spacing40))
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(start = TangemTheme.dimens.spacing12),
|
||||
|
|
@ -131,29 +127,6 @@ private fun InnerTitle(title: TextReference, titleExtra: TextReference, showTag:
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InnerIcon(imageUrl: String) {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size40),
|
||||
model = ImageRequest.Builder(context = LocalContext.current)
|
||||
.data(imageUrl)
|
||||
.crossfade(enable = true)
|
||||
.allowHardware(enable = false)
|
||||
.build(),
|
||||
loading = { LoadingIcon() },
|
||||
error = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.background.tertiary,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
//region preview
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
package com.tangem.core.ui.components.inputrow
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.tangem.core.ui.components.inputrow.inner.InputRowAsyncImage
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun InputRowImageBase(
|
||||
subtitle: TextReference,
|
||||
caption: TextReference,
|
||||
imageUrl: String,
|
||||
modifier: Modifier = Modifier,
|
||||
subtitleColor: Color = TangemTheme.colors.text.primary1,
|
||||
captionColor: Color = TangemTheme.colors.text.tertiary,
|
||||
extraContent: @Composable RowScope.() -> Unit = {},
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier,
|
||||
) {
|
||||
InputRowAsyncImage(
|
||||
imageUrl = imageUrl,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.spacing36)
|
||||
.padding(vertical = TangemTheme.dimens.size1),
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
Text(
|
||||
text = subtitle.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = subtitleColor,
|
||||
)
|
||||
Text(
|
||||
text = caption.resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = captionColor,
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing2),
|
||||
)
|
||||
}
|
||||
extraContent()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tangem.core.ui.components.inputrow
|
||||
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* Input row component with selector
|
||||
* [Input Row Image](https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=2100-842&t=hoBXmDX8NeLrp4p6-4)
|
||||
*
|
||||
* @param subtitle subtitle text
|
||||
* @param caption caption text
|
||||
* @param imageUrl icon to load
|
||||
* @param modifier modifier
|
||||
* @param subtitleColor subtitle text color
|
||||
* @param captionColor caption text color
|
||||
*/
|
||||
@Composable
|
||||
fun InputRowImageChevron(
|
||||
subtitle: TextReference,
|
||||
caption: TextReference,
|
||||
imageUrl: String,
|
||||
modifier: Modifier = Modifier,
|
||||
subtitleColor: Color = TangemTheme.colors.text.primary1,
|
||||
captionColor: Color = TangemTheme.colors.text.tertiary,
|
||||
) {
|
||||
InputRowImageBase(
|
||||
subtitle = subtitle,
|
||||
caption = caption,
|
||||
imageUrl = imageUrl,
|
||||
modifier = modifier,
|
||||
subtitleColor = subtitleColor,
|
||||
captionColor = captionColor,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_chevron_right_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
package com.tangem.core.ui.components.inputrow
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
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 com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.atoms.radiobutton.TangemRadioButton
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
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.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Input row component with selector
|
||||
* [Input Row Image](https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=2772-905&t=FH84ljLBk1vmGAei-4)
|
||||
*
|
||||
* @param subtitle subtitle text
|
||||
* @param caption caption text
|
||||
* @param imageUrl icon to load
|
||||
* @param onSelect callback when selected
|
||||
* @param modifier modifier
|
||||
* @param subtitleColor subtitle text color
|
||||
* @param captionColor caption text color
|
||||
* @param isSelected true if selected
|
||||
*/
|
||||
@Composable
|
||||
fun InputRowImageSelector(
|
||||
subtitle: TextReference,
|
||||
caption: TextReference,
|
||||
imageUrl: String,
|
||||
onSelect: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
subtitleColor: Color = TangemTheme.colors.text.primary1,
|
||||
captionColor: Color = TangemTheme.colors.text.tertiary,
|
||||
isSelected: Boolean = false,
|
||||
) {
|
||||
InputRowImageBase(
|
||||
subtitle = subtitle,
|
||||
caption = caption,
|
||||
imageUrl = imageUrl,
|
||||
subtitleColor = subtitleColor,
|
||||
captionColor = captionColor,
|
||||
modifier = modifier
|
||||
.clickable(
|
||||
onClick = onSelect,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(),
|
||||
)
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
TangemRadioButton(isSelected = isSelected, isEnabled = false, onClick = onSelect)
|
||||
}
|
||||
}
|
||||
|
||||
//region preview
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun InputRowImageSelectorPreview(
|
||||
@PreviewParameter(InputRowImageSelectorPreviewDataProvider::class) data: InputRowImageSelectorPreviewData,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
InputRowImageSelector(
|
||||
modifier = Modifier.background(TangemTheme.colors.background.action),
|
||||
subtitle = data.subtitle,
|
||||
caption = combinedReference(
|
||||
resourceReference(R.string.staking_details_apr),
|
||||
annotatedReference(
|
||||
buildAnnotatedString {
|
||||
append(" ")
|
||||
withStyle(style = SpanStyle(color = TangemTheme.colors.text.accent)) {
|
||||
append(
|
||||
BigDecimalFormatter.formatPercent(BigDecimal.ZERO, true),
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
imageUrl = "",
|
||||
isSelected = false,
|
||||
onSelect = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private data class InputRowImageSelectorPreviewData(
|
||||
val subtitle: TextReference,
|
||||
val caption: TextReference,
|
||||
val showDivider: Boolean,
|
||||
val actionIconRes: Int?,
|
||||
val isSelected: Boolean,
|
||||
)
|
||||
|
||||
private class InputRowImageSelectorPreviewDataProvider :
|
||||
PreviewParameterProvider<InputRowImageSelectorPreviewData> {
|
||||
override val values: Sequence<InputRowImageSelectorPreviewData>
|
||||
get() = sequenceOf(
|
||||
InputRowImageSelectorPreviewData(
|
||||
subtitle = TextReference.Str("subtitle"),
|
||||
caption = TextReference.Str("caption"),
|
||||
actionIconRes = null,
|
||||
showDivider = false,
|
||||
isSelected = false,
|
||||
),
|
||||
InputRowImageSelectorPreviewData(
|
||||
subtitle = TextReference.Str("subtitle"),
|
||||
caption = TextReference.Str("caption"),
|
||||
actionIconRes = R.drawable.ic_chevron_right_24,
|
||||
showDivider = true,
|
||||
isSelected = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
//endregion
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.core.ui.components.inputrow.inner
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.components.currency.tokenicon.LoadingIcon
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* Loads image by url for icon in the input row
|
||||
*
|
||||
* @param imageUrl url of the image
|
||||
* @param modifier modifier
|
||||
*/
|
||||
@Composable
|
||||
internal fun InputRowAsyncImage(imageUrl: String, modifier: Modifier = Modifier) {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = modifier,
|
||||
model = ImageRequest.Builder(context = LocalContext.current)
|
||||
.data(imageUrl)
|
||||
.crossfade(enable = true)
|
||||
.allowHardware(enable = false)
|
||||
.build(),
|
||||
loading = { LoadingIcon() },
|
||||
error = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.background.tertiary,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -48,6 +48,13 @@ sealed interface TextReference {
|
|||
*/
|
||||
data class Str(val value: String) : TextReference
|
||||
|
||||
/**
|
||||
* Annotated text
|
||||
*
|
||||
* @property value annotated string
|
||||
*/
|
||||
data class Annotated(val value: AnnotatedString) : TextReference
|
||||
|
||||
/**
|
||||
* Combined reference. It concatenates all [refs].
|
||||
*
|
||||
|
|
@ -83,6 +90,16 @@ fun stringReference(value: String): TextReference {
|
|||
return TextReference.Str(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [TextReference] using an annotated string value.
|
||||
*
|
||||
* @param value The annotated string value.
|
||||
* @return A [TextReference] representing the provided annotated string value.
|
||||
*/
|
||||
fun annotatedReference(value: AnnotatedString): TextReference {
|
||||
return TextReference.Annotated(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [TextReference] using a plural string resource ID with count and optional format arguments.
|
||||
*
|
||||
|
|
@ -133,6 +150,7 @@ fun TextReference.resolveReference(): String {
|
|||
}
|
||||
is TextReference.PluralRes -> pluralStringResource(id, count, *formatArgs.toTypedArray())
|
||||
is TextReference.Str -> value
|
||||
is TextReference.Annotated -> value.text
|
||||
is TextReference.Combined -> {
|
||||
buildString {
|
||||
refs.forEach {
|
||||
|
|
@ -155,6 +173,7 @@ fun TextReference.resolveReference(resources: Resources): String {
|
|||
}
|
||||
is TextReference.PluralRes -> resources.getQuantityString(id, count, *formatArgs.toTypedArray())
|
||||
is TextReference.Str -> value
|
||||
is TextReference.Annotated -> value.text
|
||||
is TextReference.Combined -> {
|
||||
buildString {
|
||||
refs.forEach {
|
||||
|
|
@ -180,9 +199,10 @@ fun TextReference.resolveAnnotatedReference(): AnnotatedString {
|
|||
pluralStringResource(id, count, *formatArgs.toTypedArray()),
|
||||
)
|
||||
is TextReference.Str -> formatAnnotated(value)
|
||||
is TextReference.Annotated -> value
|
||||
is TextReference.Combined -> buildAnnotatedString {
|
||||
refs.forEach {
|
||||
append(formatAnnotated(it.resolveReference()))
|
||||
append(it.resolveAnnotatedReference())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -195,6 +215,7 @@ operator fun TextReference.plus(ref: TextReference): TextReference {
|
|||
is TextReference.PluralRes,
|
||||
is TextReference.Res,
|
||||
is TextReference.Str,
|
||||
is TextReference.Annotated,
|
||||
-> TextReference.Combined(refs = wrappedList(this, ref))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ data class TangemDimens internal constructor(
|
|||
val size5: Dp = 5.dp,
|
||||
val size7: Dp = 7.dp,
|
||||
val size8: Dp = 8.dp,
|
||||
val size9: Dp = 9.dp,
|
||||
val size10: Dp = 10.dp,
|
||||
val size11: Dp = 11.dp,
|
||||
val size12: Dp = 12.dp,
|
||||
|
|
|
|||
5
core/ui/src/main/res/drawable/ic_check_circle_24.xml
Normal file
5
core/ui/src/main/res/drawable/ic_check_circle_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="#1E1E1E" android:pathData="M12,2C6.5,2 2,6.5 2,12C2,17.5 6.5,22 12,22C17.5,22 22,17.5 22,12C22,6.5 17.5,2 12,2ZM10,17L5,12L6.41,10.59L10,14.17L17.59,6.58L19,8L10,17Z"/>
|
||||
|
||||
</vector>
|
||||
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Yield.Validator>,
|
||||
)
|
||||
}
|
||||
|
||||
enum class StakingStep {
|
||||
InitialInfo,
|
||||
Amount,
|
||||
Validators,
|
||||
Confirm,
|
||||
Success,
|
||||
}
|
||||
|
|
@ -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<Yield.Validator>,
|
||||
) : ValidatorState()
|
||||
|
||||
data object Loading : InnerValidatorState()
|
||||
data object Loading : ValidatorState()
|
||||
|
||||
data object Error : InnerValidatorState()
|
||||
data object Error : ValidatorState()
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
}
|
||||
|
|
@ -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 }
|
||||
|
||||
|
|
|
|||
|
|
@ -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<StakingUiState> {
|
||||
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,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Int, () -> 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
package com.tangem.features.staking.impl.presentation.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
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 androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageSelector
|
||||
import com.tangem.core.ui.components.rows.CornersToRound
|
||||
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.res.TangemThemePreview
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.features.staking.impl.R
|
||||
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.viewmodel.StakingClickIntents
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Staking screen with validators
|
||||
*/
|
||||
@Composable
|
||||
internal fun StakingValidatorListContent(
|
||||
state: ValidatorState,
|
||||
clickIntents: StakingClickIntents,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(bottom = bottomBarHeight),
|
||||
modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
item(key = "HEADER") {
|
||||
Text(
|
||||
text = stringResource(R.string.staking_validator),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(CornersToRound.TOP_2.getShape())
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing12,
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
bottom = TangemTheme.dimens.spacing8,
|
||||
),
|
||||
)
|
||||
}
|
||||
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),
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun StakingValidatorListContent_Preview(
|
||||
@PreviewParameter(StakingValidatorListContentPreviewProvider::class)
|
||||
data: ValidatorState,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
StakingValidatorListContent(
|
||||
state = data,
|
||||
clickIntents = StakingClickIntentsStub,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class StakingValidatorListContentPreviewProvider : PreviewParameterProvider<ValidatorState> {
|
||||
override val values: Sequence<ValidatorState>
|
||||
get() = sequenceOf(ConfirmStakingStatePreviewData.confirmStakingState.validatorState)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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<Bundle>(
|
||||
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<Bundle>(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<Bundle>(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<Bundle>(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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue