Updated on 2026-08-14
This commit is contained in:
commit
302cb6080b
12 changed files with 65 additions and 17 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
9
core/ui/src/main/res/drawable/ic_staking_filled_18.xml
Normal file
9
core/ui/src/main/res/drawable/ic_staking_filled_18.xml
Normal 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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -282,6 +282,7 @@ private fun ActiveStakingBlock(
|
|||
imageUrl = balance.getImage(),
|
||||
iconRes = icon,
|
||||
iconTint = iconTint,
|
||||
onImageError = { ValidatorImagePlaceholder() },
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable(
|
||||
|
|
|
|||
|
|
@ -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() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
@ -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() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue