Updated on 2026-08-14
This commit is contained in:
parent
65ead13295
commit
6227d835b0
17 changed files with 250 additions and 93 deletions
|
|
@ -16,7 +16,7 @@ class StakeKitErrorResponse(
|
|||
@Json(name = "code")
|
||||
val code: String? = null,
|
||||
@Json(name = "countryCode")
|
||||
val countryCode: String,
|
||||
val countryCode: String?,
|
||||
@Json(name = "regionCode")
|
||||
val regionCode: String? = null,
|
||||
@Json(name = "tags")
|
||||
|
|
|
|||
|
|
@ -16,16 +16,39 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
private const val ROUNDED_LIST_WITH_DIVIDERS_HEADER_KEY = "ROUNDED_LIST_WITH_DIVIDERS_HEADER_KEY"
|
||||
private const val ROUNDED_LIST_WITH_DIVIDERS_FOOTER_KEY = "ROUNDED_LIST_WITH_DIVIDERS_FOOTER_KEY"
|
||||
|
||||
@Composable
|
||||
fun RoundedListWithDividers(rows: List<RoundedListWithDividersItemData>, modifier: Modifier = Modifier) {
|
||||
fun RoundedListWithDividers(
|
||||
rows: ImmutableList<RoundedListWithDividersItemData>,
|
||||
modifier: Modifier = Modifier,
|
||||
headerContent: (@Composable () -> Unit)? = null,
|
||||
footerContent: (@Composable () -> Unit)? = null,
|
||||
) {
|
||||
LazyColumn(modifier = modifier) {
|
||||
this.roundedListItems(rows)
|
||||
this.roundedListWithDividersItems(
|
||||
rows = rows,
|
||||
headerContent = headerContent,
|
||||
footerContent = footerContent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun LazyListScope.roundedListItems(rows: List<RoundedListWithDividersItemData>) {
|
||||
fun LazyListScope.roundedListWithDividersItems(
|
||||
rows: ImmutableList<RoundedListWithDividersItemData>,
|
||||
headerContent: (@Composable () -> Unit)? = null,
|
||||
footerContent: (@Composable () -> Unit)? = null,
|
||||
) {
|
||||
if (headerContent != null) {
|
||||
item(key = ROUNDED_LIST_WITH_DIVIDERS_HEADER_KEY) {
|
||||
headerContent()
|
||||
}
|
||||
}
|
||||
|
||||
itemsIndexed(
|
||||
items = rows,
|
||||
key = { _, item -> item.id },
|
||||
|
|
@ -40,6 +63,12 @@ fun LazyListScope.roundedListItems(rows: List<RoundedListWithDividersItemData>)
|
|||
RoundedListDivider()
|
||||
}
|
||||
}
|
||||
|
||||
if (footerContent != null) {
|
||||
item(key = ROUNDED_LIST_WITH_DIVIDERS_FOOTER_KEY) {
|
||||
footerContent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
|||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -135,7 +136,7 @@ internal class DefaultStakingRepository(
|
|||
val yield = getYield(cryptoCurrencyId, symbol)
|
||||
|
||||
StakingEntryInfo(
|
||||
interestRate = yield.apy,
|
||||
interestRate = requireNotNull(yield.validators.maxByOrNull { it.apr.orZero() }?.apr),
|
||||
periodInDays = yield.metadata.cooldownPeriod.days,
|
||||
tokenSymbol = yield.token.symbol,
|
||||
)
|
||||
|
|
@ -568,23 +569,24 @@ internal class DefaultStakingRepository(
|
|||
const val AVALANCHE_INTEGRATION_ID = "avalanche-avax-native-staking"
|
||||
const val TRON_INTEGRATION_ID = "tron-trx-native-staking"
|
||||
const val CRONOS_INTEGRATION_ID = "cronos-cro-native-staking"
|
||||
const val BINANCE_INTEGRATION_ID = "binance-bnb-native-staking"
|
||||
const val BINANCE_INTEGRATION_ID = "bsc-bnb-native-staking"
|
||||
const val KAVA_INTEGRATION_ID = "kava-kava-native-staking"
|
||||
const val NEAR_INTEGRATION_ID = "near-near-native-staking"
|
||||
const val TEZOS_INTEGRATION_ID = "tezos-xtz-native-staking"
|
||||
|
||||
// uncomment items as implementation is ready
|
||||
val integrationIdMap = mapOf(
|
||||
Blockchain.Solana.toCoinId() to SOLANA_INTEGRATION_ID,
|
||||
Blockchain.Cosmos.toCoinId() to COSMOS_INTEGRATION_ID,
|
||||
Blockchain.Polkadot.toCoinId() to POLKADOT_INTEGRATION_ID,
|
||||
Blockchain.Polygon.toCoinId() to ETHEREUM_INTEGRATION_ID,
|
||||
Blockchain.Avalanche.toCoinId() to AVALANCHE_INTEGRATION_ID,
|
||||
Blockchain.Tron.toCoinId() to TRON_INTEGRATION_ID,
|
||||
Blockchain.Cronos.toCoinId() to CRONOS_INTEGRATION_ID,
|
||||
Blockchain.Binance.toCoinId() to BINANCE_INTEGRATION_ID,
|
||||
Blockchain.Kava.toCoinId() to KAVA_INTEGRATION_ID,
|
||||
Blockchain.Near.toCoinId() to NEAR_INTEGRATION_ID,
|
||||
Blockchain.Tezos.toCoinId() to TEZOS_INTEGRATION_ID,
|
||||
// Blockchain.Polkadot.toCoinId() to POLKADOT_INTEGRATION_ID,
|
||||
// Blockchain.Polygon.toCoinId() to ETHEREUM_INTEGRATION_ID,
|
||||
// Blockchain.Avalanche.toCoinId() to AVALANCHE_INTEGRATION_ID,
|
||||
// Blockchain.Tron.toCoinId() to TRON_INTEGRATION_ID,
|
||||
// Blockchain.Cronos.toCoinId() to CRONOS_INTEGRATION_ID,
|
||||
// Blockchain.Binance.toCoinId() to BINANCE_INTEGRATION_ID,
|
||||
// Blockchain.Kava.toCoinId() to KAVA_INTEGRATION_ID,
|
||||
// Blockchain.Near.toCoinId() to NEAR_INTEGRATION_ID,
|
||||
// Blockchain.Tezos.toCoinId() to TEZOS_INTEGRATION_ID,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.features.staking.impl.presentation.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Immutable
|
||||
sealed class FeeState {
|
||||
|
||||
data class Content(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.staking.impl.presentation.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceType
|
||||
import com.tangem.domain.staking.model.stakekit.PendingAction
|
||||
|
|
@ -12,12 +13,14 @@ sealed class InnerYieldBalanceState {
|
|||
val rewardsCrypto: String,
|
||||
val rewardsFiat: String,
|
||||
val isRewardsToClaim: Boolean,
|
||||
val balance: List<BalanceGroupedState>,
|
||||
val balance: ImmutableList<BalanceGroupedState>,
|
||||
) : InnerYieldBalanceState()
|
||||
|
||||
data object Empty : InnerYieldBalanceState()
|
||||
}
|
||||
|
||||
// TODO staking get rid of unstable types
|
||||
@Immutable
|
||||
data class BalanceGroupedState(
|
||||
val items: ImmutableList<BalanceState>,
|
||||
val footer: TextReference?,
|
||||
|
|
@ -26,6 +29,7 @@ data class BalanceGroupedState(
|
|||
val isClickable: Boolean,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class BalanceState(
|
||||
val validator: Yield.Validator,
|
||||
val cryptoValue: String,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.staking.impl.presentation.state
|
|||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.features.staking.impl.R
|
||||
|
||||
|
|
@ -23,7 +24,15 @@ internal sealed class StakingNotification(val config: NotificationConfig) {
|
|||
onCloseClick = onCloseClick,
|
||||
),
|
||||
) {
|
||||
// TODO staking
|
||||
data class StakedPositionNotFoundError(val message: String) : Error(
|
||||
title = stringReference(message),
|
||||
subtitle = stringReference(message),
|
||||
)
|
||||
|
||||
data class Common(val subtitle: TextReference) : Error(
|
||||
title = resourceReference(R.string.common_error),
|
||||
subtitle = subtitle,
|
||||
)
|
||||
}
|
||||
|
||||
sealed class Warning(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,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.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.SetButtonsStateTransformer
|
||||
|
|
@ -42,6 +43,7 @@ internal class StakingStateController @Inject constructor() {
|
|||
|
||||
private fun getInitialState(): StakingUiState {
|
||||
return StakingUiState(
|
||||
title = TextReference.EMPTY,
|
||||
clickIntents = StakingClickIntentsStub,
|
||||
cryptoCurrencyName = "",
|
||||
currentStep = StakingStep.InitialInfo,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
*/
|
||||
@Immutable
|
||||
internal data class StakingUiState(
|
||||
val title: TextReference,
|
||||
val clickIntents: StakingClickIntents,
|
||||
val cryptoCurrencyName: String,
|
||||
val currentStep: StakingStep,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ internal class YieldBalancesConverter(
|
|||
)
|
||||
}
|
||||
}
|
||||
.toPersistentList()
|
||||
|
||||
private fun List<BalanceItem>.mapBalances(): List<BalanceState> {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ internal object InitialStakingStatePreview {
|
|||
rewardsFiat = "100 $",
|
||||
rewardsCrypto = "100 SOL",
|
||||
isRewardsToClaim = false,
|
||||
balance = listOf(
|
||||
balance = persistentListOf(
|
||||
BalanceGroupedState(
|
||||
title = stringReference("Staked"),
|
||||
footer = null,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class AddStakingErrorTransformer(
|
||||
private val error: StakingError,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val confirmationState =
|
||||
prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState
|
||||
|
||||
return prevState.copy(
|
||||
confirmationState = confirmationState.copy(
|
||||
notifications = (confirmationState.notifications + convertToNotification(error)).toPersistentList(),
|
||||
feeState = FeeState.Error,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertToNotification(error: StakingError): StakingNotification {
|
||||
return when (error) {
|
||||
is StakingError.StakedPositionNotFoundError -> StakingNotification.Error.StakedPositionNotFoundError(
|
||||
message = error.toString(),
|
||||
)
|
||||
// TODO staking
|
||||
else -> StakingNotification.Error.Common(
|
||||
subtitle = stringReference(error.toString()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,10 +5,7 @@ import com.tangem.common.ui.amountScreen.converters.AmountStateConverter
|
|||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.list.RoundedListWithDividersItemData
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
|
|
@ -28,7 +25,7 @@ import com.tangem.utils.Provider
|
|||
import com.tangem.utils.extensions.orZero
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class SetInitialDataStateTransformer(
|
||||
|
|
@ -62,6 +59,10 @@ internal class SetInitialDataStateTransformer(
|
|||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
return prevState.copy(
|
||||
title = TextReference.Res(
|
||||
R.string.staking_initial_info_title,
|
||||
wrappedList(cryptoCurrencyStatusProvider().currency.name),
|
||||
),
|
||||
clickIntents = clickIntents,
|
||||
currentStep = StakingStep.InitialInfo,
|
||||
initialInfoState = createInitialInfoState(),
|
||||
|
|
@ -87,70 +88,118 @@ internal class SetInitialDataStateTransformer(
|
|||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance
|
||||
|
||||
return persistentListOf(
|
||||
RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_available,
|
||||
startText = TextReference.Res(R.string.staking_details_available),
|
||||
endText = TextReference.Str(
|
||||
value = BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoAmount = cryptoCurrencyStatus.value.amount,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency.symbol,
|
||||
decimals = cryptoCurrencyStatus.currency.decimals,
|
||||
),
|
||||
return listOfNotNull(
|
||||
createAvailableItem(cryptoCurrencyStatus),
|
||||
createApyItem(),
|
||||
createOnStakeItem(cryptoCurrencyStatus, yieldBalance),
|
||||
createUnbondingPeriodItem(),
|
||||
createMinimumRequirementItem(cryptoCurrencyStatus),
|
||||
createRewardClaimingItem(),
|
||||
createWarmupPeriodItem(),
|
||||
createRewardScheduleItem(),
|
||||
).toPersistentList()
|
||||
}
|
||||
|
||||
private fun createAvailableItem(cryptoCurrencyStatus: CryptoCurrencyStatus): RoundedListWithDividersItemData {
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_available,
|
||||
startText = TextReference.Res(R.string.staking_details_available),
|
||||
endText = TextReference.Str(
|
||||
value = BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoAmount = cryptoCurrencyStatus.value.amount,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency.symbol,
|
||||
decimals = cryptoCurrencyStatus.currency.decimals,
|
||||
),
|
||||
),
|
||||
RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_apy,
|
||||
startText = TextReference.Res(R.string.staking_details_apy),
|
||||
endText = getAprRange(),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.APY) },
|
||||
),
|
||||
RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_on_stake,
|
||||
startText = TextReference.Res(R.string.staking_details_on_stake),
|
||||
endText = TextReference.Str(
|
||||
value = BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoAmount = (yieldBalance as? YieldBalance.Data)?.getTotalStakingBalance().orZero(),
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency.symbol,
|
||||
decimals = cryptoCurrencyStatus.currency.decimals,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createApyItem(): RoundedListWithDividersItemData {
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_apy,
|
||||
startText = TextReference.Res(R.string.staking_details_apy),
|
||||
endText = getAprRange(),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.APY) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun createOnStakeItem(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
yieldBalance: YieldBalance?,
|
||||
): RoundedListWithDividersItemData {
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_on_stake,
|
||||
startText = TextReference.Res(R.string.staking_details_on_stake),
|
||||
endText = TextReference.Str(
|
||||
value = BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoAmount = (yieldBalance as? YieldBalance.Data)?.getTotalStakingBalance().orZero(),
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency.symbol,
|
||||
decimals = cryptoCurrencyStatus.currency.decimals,
|
||||
),
|
||||
),
|
||||
RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_unbonding_period,
|
||||
startText = TextReference.Res(R.string.staking_details_unbonding_period),
|
||||
endText = TextReference.Str(yield.metadata.cooldownPeriod.days.toString()),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.UNBOUNDING_PERIOD) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun createUnbondingPeriodItem(): RoundedListWithDividersItemData {
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_unbonding_period,
|
||||
startText = TextReference.Res(R.string.staking_details_unbonding_period),
|
||||
endText = pluralReference(
|
||||
id = R.plurals.common_days,
|
||||
count = yield.metadata.cooldownPeriod.days,
|
||||
formatArgs = wrappedList(yield.metadata.cooldownPeriod.days),
|
||||
),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.UNBONDING_PERIOD) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun createMinimumRequirementItem(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
): RoundedListWithDividersItemData? {
|
||||
val minimumCryptoAmount = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum
|
||||
return minimumCryptoAmount?.let {
|
||||
RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_minimum_requirement,
|
||||
startText = TextReference.Res(R.string.staking_details_minimum_requirement),
|
||||
endText = TextReference.Str(
|
||||
value = BigDecimalFormatter.formatCryptoAmount(
|
||||
cryptoAmount = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum,
|
||||
cryptoAmount = it,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency.symbol,
|
||||
decimals = cryptoCurrencyStatus.currency.decimals,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRewardClaimingItem(): RoundedListWithDividersItemData {
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_reward_claiming,
|
||||
startText = TextReference.Res(R.string.staking_details_reward_claiming),
|
||||
endText = TextReference.Str(yield.metadata.rewardClaiming),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.REWARD_CLAIMING) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun createWarmupPeriodItem(): RoundedListWithDividersItemData {
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_warmup_period,
|
||||
startText = TextReference.Res(R.string.staking_details_warmup_period),
|
||||
endText = pluralReference(
|
||||
id = R.plurals.common_days,
|
||||
count = yield.metadata.warmupPeriod.days,
|
||||
formatArgs = wrappedList(yield.metadata.warmupPeriod.days),
|
||||
),
|
||||
RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_reward_claiming,
|
||||
startText = TextReference.Res(R.string.staking_details_reward_claiming),
|
||||
endText = TextReference.Str(yield.metadata.rewardClaiming),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.REWARD_CLAIMING) },
|
||||
),
|
||||
RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_warmup_period,
|
||||
startText = TextReference.Res(R.string.staking_details_warmup_period),
|
||||
endText = TextReference.Str(yield.metadata.warmupPeriod.days.toString()),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.WARMUP_PERIOD) },
|
||||
),
|
||||
RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_reward_schedule,
|
||||
startText = TextReference.Res(R.string.staking_details_reward_schedule),
|
||||
endText = TextReference.Str(yield.metadata.rewardSchedule),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.REWARD_SCHEDULE) },
|
||||
),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.WARMUP_PERIOD) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun createRewardScheduleItem(): RoundedListWithDividersItemData {
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_reward_schedule,
|
||||
startText = TextReference.Res(R.string.staking_details_reward_schedule),
|
||||
endText = TextReference.Str(yield.metadata.rewardSchedule),
|
||||
iconClick = { clickIntents.onInfoClick(InfoType.REWARD_SCHEDULE) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ internal class ShowInfoBottomSheetStateTransformer(
|
|||
title = resourceReference(R.string.staking_details_apy),
|
||||
text = resourceReference(R.string.staking_details_apy_info),
|
||||
)
|
||||
InfoType.UNBOUNDING_PERIOD -> StakingInfoBottomSheetConfig(
|
||||
InfoType.UNBONDING_PERIOD -> StakingInfoBottomSheetConfig(
|
||||
title = resourceReference(R.string.staking_details_unbonding_period),
|
||||
text = resourceReference(R.string.staking_details_unbonding_period_info),
|
||||
)
|
||||
|
|
@ -46,7 +46,7 @@ internal class ShowInfoBottomSheetStateTransformer(
|
|||
|
||||
enum class InfoType {
|
||||
APY,
|
||||
UNBOUNDING_PERIOD,
|
||||
UNBONDING_PERIOD,
|
||||
REWARD_CLAIMING,
|
||||
WARMUP_PERIOD,
|
||||
REWARD_SCHEDULE,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import com.tangem.core.ui.components.SpacerH12
|
|||
import com.tangem.core.ui.components.containers.FooterContainer
|
||||
import com.tangem.core.ui.components.inputrow.InputRowDefault
|
||||
import com.tangem.core.ui.components.inputrow.InputRowImageInfo
|
||||
import com.tangem.core.ui.components.list.roundedListItems
|
||||
import com.tangem.core.ui.components.list.roundedListWithDividersItems
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
|
@ -40,9 +40,12 @@ import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickInten
|
|||
import com.tangem.utils.StringsSigns.DOT
|
||||
import com.tangem.utils.StringsSigns.PLUS
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
// TODO staking metrics block is temporary disabled
|
||||
// private const val METRICS_BLOCK_KEY = "MetricsBlock"
|
||||
|
||||
private const val STAKING_REWARD_BLOCK_KEY = "StakingRewardBlock"
|
||||
private const val METRICS_BLOCK_KEY = "MetricsBlock"
|
||||
private const val ACTIVE_STAKING_BLOCK_KEY = "ActiveStakingBlock"
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
|
|
@ -52,21 +55,25 @@ internal fun StakingInitialInfoContent(state: StakingStates.InitialInfoState, cl
|
|||
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors.background.tertiary)
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.fillMaxSize(),
|
||||
contentPadding = PaddingValues(TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
if (state.yieldBalance == InnerYieldBalanceState.Empty) {
|
||||
item(key = METRICS_BLOCK_KEY) {
|
||||
Column(modifier = Modifier.animateItemPlacement()) {
|
||||
MetricsBlock(state)
|
||||
SpacerH12()
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO staking metrics block is temporary disabled
|
||||
// https://www.figma.com/design/Vs6SkVsFnUPsSCNwlnVf5U?node-id=12484-35755#876661319
|
||||
// if (state.yieldBalance == InnerYieldBalanceState.Empty) {
|
||||
// item(key = METRICS_BLOCK_KEY) {
|
||||
// Column(modifier = Modifier.animateItemPlacement()) {
|
||||
// MetricsBlock(state)
|
||||
// SpacerH12()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
this.roundedListItems(state.infoItems)
|
||||
item { SpacerH12() }
|
||||
this.roundedListWithDividersItems(
|
||||
rows = state.infoItems,
|
||||
footerContent = { SpacerH12() },
|
||||
)
|
||||
|
||||
if (state.yieldBalance is InnerYieldBalanceState.Data) {
|
||||
item(key = STAKING_REWARD_BLOCK_KEY) {
|
||||
|
|
@ -93,6 +100,7 @@ internal fun StakingInitialInfoContent(state: StakingStates.InitialInfoState, cl
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@Composable
|
||||
private fun MetricsBlock(state: StakingStates.InitialInfoState.Data) {
|
||||
Column(
|
||||
|
|
@ -193,7 +201,7 @@ private fun StakingRewardBlock(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ActiveStakingBlock(groups: List<BalanceGroupedState>, onClick: (BalanceState) -> Unit) {
|
||||
private fun ActiveStakingBlock(groups: ImmutableList<BalanceGroupedState>, onClick: (BalanceState) -> Unit) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import com.tangem.common.ui.amountScreen.AmountScreenContent
|
|||
import com.tangem.common.ui.navigationButtons.NavigationButtonsBlock
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
|
||||
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.R
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
|
|
@ -74,7 +75,7 @@ private fun SendAppBar(uiState: StakingUiState) {
|
|||
StakingStep.RewardsValidators,
|
||||
StakingStep.Validators,
|
||||
StakingStep.Confirmation,
|
||||
-> stringResource(id = R.string.common_stake)
|
||||
-> uiState.title.resolveReference()
|
||||
}
|
||||
val backIcon = when (uiState.currentStep) {
|
||||
StakingStep.Amount,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,23 @@
|
|||
package com.tangem.features.staking.impl.presentation.ui.block
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
internal fun NotificationsBlock(notifications: List<StakingNotification>) {
|
||||
notifications.forEach {
|
||||
Notification(config = it.config, iconTint = TangemTheme.colors.icon.accent)
|
||||
internal fun NotificationsBlock(notifications: ImmutableList<StakingNotification>) {
|
||||
notifications.forEach { notification ->
|
||||
key(notification) {
|
||||
Notification(
|
||||
config = notification.config,
|
||||
iconTint = when (notification) {
|
||||
is StakingNotification.Error -> TangemTheme.colors.icon.warning
|
||||
is StakingNotification.Warning -> TangemTheme.colors.icon.accent
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -180,7 +180,10 @@ internal class StakingViewModel @Inject constructor(
|
|||
passthrough = pendingAction?.passthrough,
|
||||
type = pendingAction?.type,
|
||||
),
|
||||
).getOrElse { error("Can't get fee info") }
|
||||
).getOrElse {
|
||||
stateController.update(AddStakingErrorTransformer(it))
|
||||
return@launch
|
||||
}
|
||||
|
||||
stateController.update(
|
||||
SetConfirmationStateAssentTransformer(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue