Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-18 12:41:59 +05:00
commit 302cb6080b
12 changed files with 65 additions and 17 deletions

View file

@ -39,6 +39,7 @@ import com.tangem.core.ui.res.TangemThemePreview
* @param captionColor caption text color
* @param isGrayscaleImage whether to display grayscale image
* @param iconEndRes icon to end of row
* @param onImageError composable to show if image loading failed
* @param extraContent extra content
*/
@Composable
@ -53,6 +54,7 @@ internal fun InputRowImageBase(
iconTint: Color = TangemTheme.colors.icon.informative,
isGrayscaleImage: Boolean = false,
iconEndRes: Int? = null,
onImageError: (@Composable () -> Unit)? = null,
extraContent: (@Composable RowScope.() -> Unit)? = null,
) {
Row(
@ -63,13 +65,13 @@ internal fun InputRowImageBase(
InputRowAsyncImage(
imageUrl = imageUrl,
isGrayscale = isGrayscaleImage,
onImageError = onImageError,
modifier = Modifier
.size(TangemTheme.dimens.spacing36)
.clip(TangemTheme.shapes.roundedCornersXLarge),
)
SpacerW12()
}
if (iconRes != null) {
} else if (iconRes != null) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier

View file

@ -35,6 +35,7 @@ import com.tangem.core.ui.res.TangemThemePreview
* @param captionColor caption text color
* @param isGrayscaleImage whether to display grayscale image
* @param iconEndRes icon to end of row
* @param onImageError composable to show if image loading failed
*/
@Suppress("LongParameterList")
@Composable
@ -52,6 +53,7 @@ fun InputRowImageInfo(
iconTint: Color = TangemTheme.colors.icon.informative,
isGrayscaleImage: Boolean = false,
@DrawableRes iconEndRes: Int? = null,
onImageError: (@Composable () -> Unit)? = null,
) {
Column(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing6),
@ -75,6 +77,7 @@ fun InputRowImageInfo(
captionColor = captionColor,
isGrayscaleImage = isGrayscaleImage,
iconEndRes = iconEndRes,
onImageError = onImageError,
) {
Column(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing2),

View file

@ -41,6 +41,7 @@ import java.math.BigDecimal
* @param captionColor caption text color
* @param isSelected true if selected
* @param selectorContent selector content
* @param onImageError composable to show if image loading failed
*/
@Composable
fun InputRowImageSelector(
@ -52,6 +53,7 @@ fun InputRowImageSelector(
subtitleColor: Color = TangemTheme.colors.text.primary1,
captionColor: Color = TangemTheme.colors.text.tertiary,
isSelected: Boolean = false,
onImageError: (@Composable () -> Unit)? = null,
selectorContent: @Composable ((isSelected: Boolean, isEnabled: Boolean, onSelect: () -> Unit) -> Unit),
) {
InputRowImageBase(
@ -60,6 +62,7 @@ fun InputRowImageSelector(
imageUrl = imageUrl,
subtitleColor = subtitleColor,
captionColor = captionColor,
onImageError = onImageError,
modifier = modifier
.clickable(
onClick = onSelect,

View file

@ -18,9 +18,15 @@ import com.tangem.core.ui.utils.getGreyScaleColorFilter
* @param imageUrl url of the image
* @param modifier modifier
* @param isGrayscale whether to apply grayscale filter
* @param onImageError composable to show if image loading failed
*/
@Composable
internal fun InputRowAsyncImage(imageUrl: String, modifier: Modifier = Modifier, isGrayscale: Boolean = false) {
internal fun InputRowAsyncImage(
imageUrl: String,
modifier: Modifier = Modifier,
isGrayscale: Boolean = false,
onImageError: (@Composable () -> Unit)? = null,
) {
val (alpha, colorFilter) = getGreyScaleColorFilter(isGrayscale = isGrayscale)
SubcomposeAsyncImage(
modifier = modifier,
@ -33,7 +39,7 @@ internal fun InputRowAsyncImage(imageUrl: String, modifier: Modifier = Modifier,
.build(),
loading = { LoadingIcon() },
error = {
Box(
onImageError?.invoke() ?: Box(
modifier = Modifier
.background(
color = TangemTheme.colors.background.tertiary,

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="18dp" android:viewportHeight="18" android:viewportWidth="18" android:width="18dp">
<path android:fillColor="#C9C9C9" android:fillType="evenOdd" android:pathData="M7.235,2.66C8.331,2.044 9.669,2.044 10.765,2.66L16.641,5.965C16.924,6.125 17.1,6.425 17.1,6.75C17.1,7.075 16.924,7.375 16.641,7.534L10.765,10.84C9.669,11.456 8.331,11.456 7.235,10.84L1.359,7.534C1.075,7.375 0.9,7.075 0.9,6.75C0.9,6.425 1.075,6.125 1.359,5.965L7.235,2.66ZM9.882,4.229C9.334,3.921 8.665,3.921 8.117,4.229L3.636,6.75L8.117,9.271C8.665,9.579 9.334,9.579 9.882,9.271L14.364,6.75L9.882,4.229Z"/>
<path android:fillColor="#C9C9C9" android:pathData="M8.117,4.229C8.665,3.921 9.334,3.921 9.882,4.229L14.364,6.75L9.882,9.271C9.334,9.579 8.665,9.579 8.117,9.271L3.636,6.75L8.117,4.229Z"/>
<path android:fillColor="#C9C9C9" android:fillType="evenOdd" android:pathData="M1.016,10.809C1.259,10.375 1.808,10.222 2.241,10.465L8.118,13.771C8.666,14.079 9.335,14.079 9.883,13.771L15.759,10.465C16.192,10.222 16.741,10.375 16.985,10.809C17.228,11.242 17.074,11.79 16.641,12.034L10.765,15.34C9.669,15.956 8.331,15.956 7.235,15.34L1.359,12.034C0.926,11.79 0.772,11.242 1.016,10.809Z"/>
</vector>

View file

@ -73,6 +73,7 @@ internal class AddStakingNotificationsTransformer(
isSubtractAvailable = isSubtractAvailable,
reduceAmountBy = reduceAmountBy,
)
val minimumRequirement = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum.orZero()
val sendingAmount = if (isEnterAction) {
checkAndCalculateSubtractedAmount(
isAmountSubtractAvailable = isSubtractAvailable,
@ -84,7 +85,7 @@ internal class AddStakingNotificationsTransformer(
} else {
// No amount is taken from account balance on exit or pending actions
BigDecimal.ZERO
}
}.max(minimumRequirement)
val notifications = buildList {
// errors
@ -106,7 +107,7 @@ internal class AddStakingNotificationsTransformer(
amountState = amountState,
feeState = feeState,
sendingAmount = sendingAmount,
isFeeCoverage = isFeeCoverage && isEnterAction,
isFeeCoverage = isFeeCoverage && isEnterAction && !sendingAmount.equals(minimumRequirement),
)
addInfoNotifications(prevState)
@ -223,11 +224,10 @@ internal class AddStakingNotificationsTransformer(
cryptoCurrencyStatus: CryptoCurrencyStatus,
onClick: (CryptoCurrency) -> Unit,
) {
val minimumRequirement = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum
val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
if (!isSubtractionAvailable) return
val showNotification = sendingAmount + feeAmount > balance - minimumRequirement.orZero()
val showNotification = sendingAmount + feeAmount > balance
if (showNotification) {
val notification = if (actionType == StakingActionCommonType.ENTER) {
NotificationUM.Error.TotalExceedsBalance

View file

@ -35,7 +35,7 @@ internal class SetConfirmationStateLoadingTransformer(
availableValidators = yield.validators,
),
notifications = persistentListOf(),
footerText = getFooter(prevState),
footerText = getFooter(prevState, chosenValidator),
transactionDoneState = TransactionDoneState.Empty,
pendingAction = possibleConfirmationState?.pendingAction,
pendingActions = possibleConfirmationState?.pendingActions,
@ -45,14 +45,12 @@ internal class SetConfirmationStateLoadingTransformer(
)
}
private fun getFooter(state: StakingUiState): TextReference {
private fun getFooter(state: StakingUiState, validator: Yield.Validator): TextReference {
val amountState = state.amountState as? AmountState.Data
val confirmationState = state.confirmationState as? StakingStates.ConfirmationState.Data
val validatorState = confirmationState?.validatorState as? ValidatorState.Content
val isEnterAction = state.actionType == StakingActionCommonType.ENTER
val apr = validatorState?.chosenValidator?.apr.orZero()
val apr = validator.apr.orZero()
val amountDecimal = amountState?.amountTextField?.fiatAmount?.value
val potentialReward = amountDecimal?.multiply(apr)

View file

@ -52,6 +52,7 @@ internal fun StakingClaimRewardsValidatorContent(
infoTitle = item.fiatAmount,
infoSubtitle = item.cryptoAmount,
imageUrl = item.validator?.image.orEmpty(),
onImageError = { ValidatorImagePlaceholder() },
modifier = modifier
.roundedShapeItemDecoration(index, state.rewards.lastIndex, false)
.background(TangemTheme.colors.background.action)

View file

@ -282,6 +282,7 @@ private fun ActiveStakingBlock(
imageUrl = balance.getImage(),
iconRes = icon,
iconTint = iconTint,
onImageError = { ValidatorImagePlaceholder() },
modifier = modifier
.background(TangemTheme.colors.background.action)
.clickable(

View file

@ -3,10 +3,7 @@ package com.tangem.features.staking.impl.presentation.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
@ -95,6 +92,7 @@ internal fun StakingValidatorListContent(
)
}
},
onImageError = { ValidatorImagePlaceholder() },
)
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.features.staking.impl.presentation.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.vectorResource
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.staking.impl.R
@Composable
internal fun ValidatorImagePlaceholder() {
Icon(
painter = rememberVectorPainter(ImageVector.vectorResource(R.drawable.ic_staking_filled_18)),
contentDescription = null,
tint = TangemTheme.colors.icon.inactive,
modifier = Modifier
.background(TangemTheme.colors.icon.primary1, CircleShape)
.padding(TangemTheme.dimens.size9),
)
}

View file

@ -16,6 +16,7 @@ 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 com.tangem.features.staking.impl.presentation.ui.ValidatorImagePlaceholder
import com.tangem.utils.extensions.orZero
@Composable
@ -45,6 +46,7 @@ internal fun ValidatorBlock(validatorState: ValidatorState, onClick: () -> Unit)
)
},
imageUrl = validatorState.chosenValidator.image.orEmpty(),
onImageError = { ValidatorImagePlaceholder() },
)
}
}