Updated on 2026-08-14
This commit is contained in:
parent
6b01eacf9d
commit
b192949d27
24 changed files with 387 additions and 79 deletions
|
|
@ -84,6 +84,7 @@
|
|||
<string name="common_copy">Копировать</string>
|
||||
<string name="common_copy_address">Скопировать адрес</string>
|
||||
<string name="common_create">Создать</string>
|
||||
<string name="common_custom">Свое</string>
|
||||
<string name="common_delete">Удалить</string>
|
||||
<string name="common_disabled">Отключено</string>
|
||||
<string name="common_done">Готово</string>
|
||||
|
|
@ -95,7 +96,6 @@
|
|||
<string name="common_explorer">Обозреватель</string>
|
||||
<string name="common_fee_label">Комиссия</string>
|
||||
<string name="common_fee_selector_footer">Сетевые комиссии – это плата пользователя за обработку и подтверждение транзакций. Размер комиссии зависит от нагрузки на сеть, объема транзакции и приоритета исполнения. %s</string>
|
||||
<string name="common_fee_selector_option_custom">Свое</string>
|
||||
<string name="common_fee_selector_option_fast">Быстро</string>
|
||||
<string name="common_fee_selector_option_market">По рынку</string>
|
||||
<string name="common_fee_selector_option_slow">Медленно</string>
|
||||
|
|
@ -302,6 +302,7 @@
|
|||
<item quantity="many">%1$d из %2$d кошельков</item>
|
||||
<item quantity="other">%1$d из %2$d кошельков</item>
|
||||
</plurals>
|
||||
<string name="manage_tokens_remove">Удалить</string>
|
||||
<string name="manage_tokens_search_placeholder">например Bitcoin</string>
|
||||
<string name="manage_tokens_toast_portfolio_updated">Ваш портфель был обновлен</string>
|
||||
<string name="manage_tokens_unavailable_description">Выбранный токен не доступен в кошельке на данный момент. Но не переживайте, вы можете выразить свой интерес проголосовав за его добавление.</string>
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@
|
|||
<string name="cardano_max_amount_has_token_title">Not enough ADA</string>
|
||||
<string name="common_accept">Accept</string>
|
||||
<string name="common_access_denied">Access denied</string>
|
||||
<string name="common_all">All</string>
|
||||
<string name="common_allow">Allow</string>
|
||||
<string name="common_apply">Apply</string>
|
||||
<string name="common_approval">Approval</string>
|
||||
|
|
@ -84,6 +85,7 @@
|
|||
<string name="common_copy">Copy</string>
|
||||
<string name="common_copy_address">Copy address</string>
|
||||
<string name="common_create">Create</string>
|
||||
<string name="common_custom">Custom</string>
|
||||
<string name="common_delete">Delete</string>
|
||||
<string name="common_disabled">Disabled</string>
|
||||
<string name="common_done">Done</string>
|
||||
|
|
@ -95,7 +97,6 @@
|
|||
<string name="common_explorer">Explorer</string>
|
||||
<string name="common_fee_label">Fee</string>
|
||||
<string name="common_fee_selector_footer">Network fees are charges users pay to process and confirm transactions. The fee amount can be affected by network congestion, transaction size, and execution priority. %s</string>
|
||||
<string name="common_fee_selector_option_custom">Custom</string>
|
||||
<string name="common_fee_selector_option_fast">Fast</string>
|
||||
<string name="common_fee_selector_option_market">Market</string>
|
||||
<string name="common_fee_selector_option_slow">Slow</string>
|
||||
|
|
@ -304,6 +305,7 @@
|
|||
<item quantity="one">%1$d of %2$d wallet</item>
|
||||
<item quantity="other">%1$d of %2$d wallets</item>
|
||||
</plurals>
|
||||
<string name="manage_tokens_remove">Remove</string>
|
||||
<string name="manage_tokens_search_placeholder">e.g. BTC I trust, hodl I must</string>
|
||||
<string name="manage_tokens_toast_portfolio_updated">Your portfolio has been updated</string>
|
||||
<string name="manage_tokens_unavailable_description">The selected token is currently unavailable for actions within the crypto wallet. But worry not, you can express your interest by upvoting it.</string>
|
||||
|
|
@ -562,9 +564,11 @@
|
|||
<string name="staking_details_on_stake">On stake</string>
|
||||
<string name="staking_details_reward_claiming">Reward claiming</string>
|
||||
<string name="staking_details_reward_schedule">Reward schedule</string>
|
||||
<string name="staking_details_rewards_to_claim">Rewards to claim: %s</string>
|
||||
<string name="staking_details_title">Staking %s</string>
|
||||
<string name="staking_details_unbonding_period">Unbonding Period</string>
|
||||
<string name="staking_details_warmup_period">Warmup period</string>
|
||||
<string name="staking_native">Native staking</string>
|
||||
<string name="staking_notification_earn_rewards_text" formatted="false">Staking allow you to earn %1s. Your staking rewards arrive every ~%2s days.</string>
|
||||
<string name="staking_notification_earn_rewards_title">Earn staking rewards</string>
|
||||
<string name="staking_rewards">Rewards</string>
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ import androidx.compose.foundation.LocalIndication
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
|
|
@ -21,8 +18,9 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
|
|
@ -42,7 +40,7 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
*/
|
||||
@Composable
|
||||
inline fun <reified T> SegmentedButtons(
|
||||
config: PersistentList<T>,
|
||||
config: ImmutableList<T>,
|
||||
crossinline onClick: (T) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = TangemTheme.colors.background.tertiary,
|
||||
|
|
@ -51,7 +49,7 @@ inline fun <reified T> SegmentedButtons(
|
|||
showIndication: Boolean = true,
|
||||
initialSelectedItem: T? = null,
|
||||
isEnabled: Boolean = true,
|
||||
crossinline buttonContent: @Composable (T) -> Unit,
|
||||
crossinline buttonContent: @Composable BoxScope.(T) -> Unit,
|
||||
) {
|
||||
if (config.isEmpty() || config.size == 1) return
|
||||
|
||||
|
|
@ -97,7 +95,7 @@ inline fun <reified T> SegmentedButtons(
|
|||
onClick(config[index])
|
||||
},
|
||||
) {
|
||||
buttonContent.invoke(config[index])
|
||||
buttonContent.invoke(this, config[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.utils.Strings
|
||||
|
||||
@Composable
|
||||
fun SelectorRowItem(
|
||||
|
|
@ -127,7 +128,7 @@ private fun RowScope.SelectorValueContent(
|
|||
)
|
||||
if (postDot != null) {
|
||||
Text(
|
||||
text = "•",
|
||||
text = Strings.DOT,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
|
|||
|
|
@ -102,9 +102,11 @@ data class TangemDimens internal constructor(
|
|||
val spacing2: Dp = 2.dp,
|
||||
val spacing3: Dp = 3.dp,
|
||||
val spacing4: Dp = 4.dp,
|
||||
val spacing5: Dp = 5.dp,
|
||||
val spacing6: Dp = 6.dp,
|
||||
val spacing8: Dp = 8.dp,
|
||||
val spacing10: Dp = 10.dp,
|
||||
val spacing11: Dp = 11.dp,
|
||||
val spacing12: Dp = 12.dp,
|
||||
val spacing14: Dp = 14.dp,
|
||||
val spacing15: Dp = 15.dp,
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ package com.tangem.utils
|
|||
object Strings {
|
||||
|
||||
const val STARS = "\u2217\u2217\u2217"
|
||||
const val DOT = "•"
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ internal fun SendSpeedSelector(
|
|||
onSelect = { clickIntents.onFeeSelectorClick(FeeType.Fast) },
|
||||
)
|
||||
SendSpeedSelectorItem(
|
||||
titleRes = R.string.common_fee_selector_option_custom,
|
||||
titleRes = R.string.common_custom,
|
||||
iconRes = R.drawable.ic_edit_24,
|
||||
feeType = FeeType.Custom,
|
||||
state = state,
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ internal fun FeeBlock(feeState: SendStates.FeeState, isClickDisabled: Boolean, o
|
|||
FeeType.Slow -> R.string.common_fee_selector_option_slow to R.drawable.ic_tortoise_24
|
||||
FeeType.Market -> R.string.common_fee_selector_option_market to R.drawable.ic_bird_24
|
||||
FeeType.Fast -> R.string.common_fee_selector_option_fast to R.drawable.ic_hare_24
|
||||
FeeType.Custom -> R.string.common_fee_selector_option_custom to R.drawable.ic_edit_24
|
||||
FeeType.Custom -> R.string.common_custom to R.drawable.ic_edit_24
|
||||
}
|
||||
} else {
|
||||
R.string.common_fee_selector_option_market to R.drawable.ic_bird_24
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
|
|||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
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.res.TangemTheme
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.*
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton
|
||||
|
|
@ -18,6 +20,7 @@ import com.tangem.features.tokendetails.impl.R
|
|||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@Suppress("LargeClass")
|
||||
internal object TokenDetailsPreviewData {
|
||||
|
||||
val tokenDetailsTopAppBarConfig = TokenDetailsTopAppBarConfig(
|
||||
|
|
@ -100,17 +103,47 @@ internal object TokenDetailsPreviewData {
|
|||
TokenDetailsActionButton.Swap(dimContent = false, onClick = {}),
|
||||
)
|
||||
|
||||
val balanceLoading = TokenDetailsBalanceBlockState.Loading(actionButtons = actionButtons)
|
||||
private val balanceSegmentedButtonConfig = persistentListOf(
|
||||
TokenBalanceSegmentedButtonConfig(
|
||||
title = resourceReference(R.string.common_all),
|
||||
type = BalanceType.ALL,
|
||||
),
|
||||
TokenBalanceSegmentedButtonConfig(
|
||||
title = resourceReference(R.string.staking_details_available),
|
||||
type = BalanceType.AVAILABLE,
|
||||
),
|
||||
)
|
||||
|
||||
val balanceLoading = TokenDetailsBalanceBlockState.Loading(
|
||||
actionButtons = actionButtons,
|
||||
balanceSegmentedButtonConfig = balanceSegmentedButtonConfig,
|
||||
selectedBalanceType = BalanceType.ALL,
|
||||
)
|
||||
val balanceContent = TokenDetailsBalanceBlockState.Content(
|
||||
actionButtons = actionButtons,
|
||||
fiatBalance = "91,50$",
|
||||
cryptoBalance = "966,96 XLM",
|
||||
isStakingEnabled = true,
|
||||
balanceSegmentedButtonConfig = balanceSegmentedButtonConfig,
|
||||
selectedBalanceType = BalanceType.ALL,
|
||||
onBalanceSelect = {},
|
||||
)
|
||||
val balanceError = TokenDetailsBalanceBlockState.Error(
|
||||
actionButtons = actionButtons,
|
||||
balanceSegmentedButtonConfig = balanceSegmentedButtonConfig,
|
||||
selectedBalanceType = BalanceType.ALL,
|
||||
)
|
||||
val balanceError = TokenDetailsBalanceBlockState.Error(actionButtons = actionButtons)
|
||||
|
||||
private val marketPriceLoading = MarketPriceBlockState.Loading(currencySymbol = "USDT")
|
||||
|
||||
private val stakingLoading = StakingBlockState.Loading(iconState = iconState)
|
||||
private val stakingLoading = StakingBlocksState(
|
||||
stakingAvailable = StakingAvailable.Loading(iconState),
|
||||
stakingBalance = StakingBalance.Content(
|
||||
cryptoAmount = stringReference("5 SOL"),
|
||||
fiatAmount = stringReference("456.34 $"),
|
||||
rewardAmount = resourceReference(R.string.staking_details_no_rewards_to_claim, wrappedList("0.43 $")),
|
||||
),
|
||||
)
|
||||
|
||||
private val pullToRefreshConfig = TokenDetailsPullToRefreshConfig(
|
||||
isRefreshing = false,
|
||||
|
|
@ -246,7 +279,7 @@ internal object TokenDetailsPreviewData {
|
|||
tokenInfoBlockState = tokenInfoBlockState,
|
||||
tokenBalanceBlockState = balanceLoading,
|
||||
marketPriceBlockState = marketPriceLoading,
|
||||
stakingBlockState = stakingLoading,
|
||||
stakingBlocksState = stakingLoading,
|
||||
notifications = persistentListOf(),
|
||||
txHistoryState = TxHistoryState.Content(
|
||||
contentItems = MutableStateFlow(
|
||||
|
|
@ -278,12 +311,19 @@ internal object TokenDetailsPreviewData {
|
|||
type = PriceChangeType.UP,
|
||||
),
|
||||
),
|
||||
stakingBlockState = StakingBlockState.Content(
|
||||
interestRate = "7.38",
|
||||
periodInDays = 4,
|
||||
tokenSymbol = "XLM",
|
||||
iconState = iconState,
|
||||
onStakeClicked = {},
|
||||
stakingBlocksState = StakingBlocksState(
|
||||
stakingAvailable = StakingAvailable.Content(
|
||||
interestRate = "7.38",
|
||||
periodInDays = 4,
|
||||
tokenSymbol = "XLM",
|
||||
iconState = iconState,
|
||||
onStakeClicked = {},
|
||||
),
|
||||
stakingBalance = StakingBalance.Content(
|
||||
cryptoAmount = stringReference("5 SOL"),
|
||||
fiatAmount = stringReference("456.34 $"),
|
||||
rewardAmount = resourceReference(R.string.staking_details_rewards_to_claim, wrappedList("0.43 $")),
|
||||
),
|
||||
),
|
||||
notifications = persistentListOf(),
|
||||
txHistoryState = TxHistoryState.NotSupported(
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class StakingBlocksState(
|
||||
val stakingAvailable: StakingAvailable,
|
||||
val stakingBalance: StakingBalance,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal sealed interface StakingBlockState {
|
||||
|
||||
internal sealed interface StakingAvailable {
|
||||
val iconState: IconState
|
||||
|
||||
data class Error(override val iconState: IconState) : StakingBlockState
|
||||
data class Error(override val iconState: IconState) : StakingAvailable
|
||||
|
||||
data class Loading(override val iconState: IconState) : StakingBlockState
|
||||
data class Loading(override val iconState: IconState) : StakingAvailable
|
||||
|
||||
data class Content(
|
||||
override val iconState: IconState,
|
||||
|
|
@ -17,5 +22,16 @@ internal sealed interface StakingBlockState {
|
|||
val periodInDays: Int,
|
||||
val tokenSymbol: String,
|
||||
val onStakeClicked: () -> Unit,
|
||||
) : StakingBlockState
|
||||
) : StakingAvailable
|
||||
}
|
||||
|
||||
@Immutable
|
||||
sealed class StakingBalance {
|
||||
data object Empty : StakingBalance()
|
||||
|
||||
data class Content(
|
||||
val cryptoAmount: TextReference,
|
||||
val fiatAmount: TextReference,
|
||||
val rewardAmount: TextReference,
|
||||
) : StakingBalance()
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
data class TokenBalanceSegmentedButtonConfig(
|
||||
val title: TextReference,
|
||||
val type: BalanceType,
|
||||
)
|
||||
|
||||
enum class BalanceType {
|
||||
ALL,
|
||||
AVAILABLE,
|
||||
}
|
||||
|
|
@ -6,19 +6,29 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
internal sealed class TokenDetailsBalanceBlockState {
|
||||
|
||||
abstract val actionButtons: ImmutableList<TokenDetailsActionButton>
|
||||
abstract val balanceSegmentedButtonConfig: ImmutableList<TokenBalanceSegmentedButtonConfig>
|
||||
abstract val selectedBalanceType: BalanceType
|
||||
|
||||
data class Loading(
|
||||
override val actionButtons: ImmutableList<TokenDetailsActionButton>,
|
||||
override val balanceSegmentedButtonConfig: ImmutableList<TokenBalanceSegmentedButtonConfig>,
|
||||
override val selectedBalanceType: BalanceType,
|
||||
) : TokenDetailsBalanceBlockState()
|
||||
|
||||
data class Content(
|
||||
override val actionButtons: ImmutableList<TokenDetailsActionButton>,
|
||||
override val balanceSegmentedButtonConfig: ImmutableList<TokenBalanceSegmentedButtonConfig>,
|
||||
override val selectedBalanceType: BalanceType,
|
||||
val fiatBalance: String,
|
||||
val cryptoBalance: String,
|
||||
val isStakingEnabled: Boolean,
|
||||
val onBalanceSelect: (TokenBalanceSegmentedButtonConfig) -> Unit,
|
||||
) : TokenDetailsBalanceBlockState()
|
||||
|
||||
data class Error(
|
||||
override val actionButtons: ImmutableList<TokenDetailsActionButton>,
|
||||
override val balanceSegmentedButtonConfig: ImmutableList<TokenBalanceSegmentedButtonConfig>,
|
||||
override val selectedBalanceType: BalanceType,
|
||||
) : TokenDetailsBalanceBlockState()
|
||||
|
||||
fun copyActionButtons(buttons: ImmutableList<TokenDetailsActionButton>): TokenDetailsBalanceBlockState {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ internal data class TokenDetailsState(
|
|||
val tokenInfoBlockState: TokenInfoBlockState,
|
||||
val tokenBalanceBlockState: TokenDetailsBalanceBlockState,
|
||||
val marketPriceBlockState: MarketPriceBlockState,
|
||||
val stakingBlockState: StakingBlockState,
|
||||
val stakingBlocksState: StakingBlocksState,
|
||||
val notifications: ImmutableList<TokenDetailsNotification>,
|
||||
val pendingTxs: PersistentList<TransactionState>,
|
||||
val swapTxs: PersistentList<SwapTransactionsState>,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.tangem.core.ui.utils.BigDecimalFormatter
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.BalanceType
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
|
||||
|
|
@ -23,6 +24,7 @@ import kotlinx.collections.immutable.toPersistentList
|
|||
internal class TokenDetailsLoadedBalanceConverter(
|
||||
private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val isStakingEnabled: Boolean,
|
||||
private val symbol: String,
|
||||
private val decimals: Int,
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
|
|
@ -39,7 +41,11 @@ internal class TokenDetailsLoadedBalanceConverter(
|
|||
private fun convertError(): TokenDetailsState {
|
||||
val state = currentStateProvider()
|
||||
return state.copy(
|
||||
tokenBalanceBlockState = TokenDetailsBalanceBlockState.Error(state.tokenBalanceBlockState.actionButtons),
|
||||
tokenBalanceBlockState = TokenDetailsBalanceBlockState.Error(
|
||||
actionButtons = state.tokenBalanceBlockState.actionButtons,
|
||||
balanceSegmentedButtonConfig = state.tokenBalanceBlockState.balanceSegmentedButtonConfig,
|
||||
selectedBalanceType = state.tokenBalanceBlockState.selectedBalanceType,
|
||||
),
|
||||
marketPriceBlockState = MarketPriceBlockState.Error(state.marketPriceBlockState.currencySymbol),
|
||||
notifications = persistentListOf(TokenDetailsNotification.NetworksUnreachable),
|
||||
)
|
||||
|
|
@ -74,12 +80,24 @@ internal class TokenDetailsLoadedBalanceConverter(
|
|||
actionButtons = currentState.actionButtons,
|
||||
fiatBalance = formatFiatAmount(status.value, appCurrencyProvider()),
|
||||
cryptoBalance = formatCryptoAmount(status),
|
||||
isStakingEnabled = isStakingEnabled,
|
||||
balanceSegmentedButtonConfig = currentState.balanceSegmentedButtonConfig,
|
||||
onBalanceSelect = clickIntents::onBalanceSelect,
|
||||
selectedBalanceType = currentState.selectedBalanceType,
|
||||
)
|
||||
is CryptoCurrencyStatus.Loading -> TokenDetailsBalanceBlockState.Loading(
|
||||
actionButtons = currentState.actionButtons,
|
||||
balanceSegmentedButtonConfig = currentState.balanceSegmentedButtonConfig,
|
||||
selectedBalanceType = BalanceType.ALL,
|
||||
)
|
||||
is CryptoCurrencyStatus.Loading -> TokenDetailsBalanceBlockState.Loading(currentState.actionButtons)
|
||||
is CryptoCurrencyStatus.MissedDerivation,
|
||||
is CryptoCurrencyStatus.Unreachable,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
-> TokenDetailsBalanceBlockState.Error(currentState.actionButtons)
|
||||
-> TokenDetailsBalanceBlockState.Error(
|
||||
actionButtons = currentState.actionButtons,
|
||||
balanceSegmentedButtonConfig = currentState.balanceSegmentedButtonConfig,
|
||||
selectedBalanceType = BalanceType.ALL,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,9 +48,16 @@ internal class TokenDetailsSkeletonStateConverter(
|
|||
)
|
||||
},
|
||||
),
|
||||
tokenBalanceBlockState = TokenDetailsBalanceBlockState.Loading(actionButtons = createButtons()),
|
||||
tokenBalanceBlockState = TokenDetailsBalanceBlockState.Loading(
|
||||
actionButtons = createButtons(),
|
||||
balanceSegmentedButtonConfig = createBalanceSegmentedButtonConfig(),
|
||||
selectedBalanceType = BalanceType.ALL,
|
||||
),
|
||||
marketPriceBlockState = MarketPriceBlockState.Loading(value.symbol),
|
||||
stakingBlockState = StakingBlockState.Loading(iconState = iconState),
|
||||
stakingBlocksState = StakingBlocksState(
|
||||
stakingAvailable = StakingAvailable.Loading(iconState),
|
||||
stakingBalance = StakingBalance.Empty,
|
||||
),
|
||||
notifications = persistentListOf(),
|
||||
pendingTxs = persistentListOf(),
|
||||
swapTxs = persistentListOf(),
|
||||
|
|
@ -99,6 +106,19 @@ internal class TokenDetailsSkeletonStateConverter(
|
|||
)
|
||||
}
|
||||
|
||||
private fun createBalanceSegmentedButtonConfig(): ImmutableList<TokenBalanceSegmentedButtonConfig> {
|
||||
return persistentListOf(
|
||||
TokenBalanceSegmentedButtonConfig(
|
||||
title = resourceReference(R.string.common_all),
|
||||
type = BalanceType.ALL,
|
||||
),
|
||||
TokenBalanceSegmentedButtonConfig(
|
||||
title = resourceReference(R.string.staking_details_available),
|
||||
type = BalanceType.AVAILABLE,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPullToRefresh(): TokenDetailsPullToRefreshConfig = TokenDetailsPullToRefreshConfig(
|
||||
isRefreshing = false,
|
||||
onRefresh = clickIntents::onRefreshSwipe,
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
|||
import com.tangem.domain.txhistory.models.TxHistoryItem
|
||||
import com.tangem.domain.txhistory.models.TxHistoryListError
|
||||
import com.tangem.domain.txhistory.models.TxHistoryStateError
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsAppBarMenuConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.*
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadedTxHistoryConverter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter
|
||||
|
|
@ -46,6 +44,7 @@ internal class TokenDetailsStateFactory(
|
|||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
private val featureToggles: TokenDetailsFeatureToggles,
|
||||
private val isStakingEnabled: Boolean,
|
||||
symbol: String,
|
||||
decimals: Int,
|
||||
) {
|
||||
|
|
@ -65,6 +64,7 @@ internal class TokenDetailsStateFactory(
|
|||
TokenDetailsLoadedBalanceConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
isStakingEnabled = isStakingEnabled,
|
||||
symbol = symbol,
|
||||
decimals = decimals,
|
||||
clickIntents = clickIntents,
|
||||
|
|
@ -218,7 +218,7 @@ internal class TokenDetailsStateFactory(
|
|||
|
||||
fun getStateWithStaking(stakingEither: Either<Throwable, StakingEntryInfo>): TokenDetailsState {
|
||||
return currentStateProvider().copy(
|
||||
stakingBlockState = stakingStateConverter.convert(stakingEither),
|
||||
stakingBlocksState = stakingStateConverter.convert(stakingEither),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -348,6 +348,17 @@ internal class TokenDetailsStateFactory(
|
|||
}
|
||||
}
|
||||
|
||||
fun getStateWithUpdatedBalanceSegmentedButtonConfig(
|
||||
buttonConfig: TokenBalanceSegmentedButtonConfig,
|
||||
): TokenDetailsState {
|
||||
return with(currentStateProvider()) {
|
||||
val updatedState = (tokenBalanceBlockState as? TokenDetailsBalanceBlockState.Content)
|
||||
?.copy(selectedBalanceType = buttonConfig.type)
|
||||
?: tokenBalanceBlockState
|
||||
copy(tokenBalanceBlockState = updatedState)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TokenDetailsAppBarMenuConfig.updateMenu(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
isBitcoin: Boolean,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
|
|||
import arrow.core.Either
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.staking.model.StakingEntryInfo
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingAvailable
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBalance
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlocksState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -12,25 +14,31 @@ import com.tangem.utils.converter.Converter
|
|||
internal class TokenStakingStateConverter(
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
private val currentStateProvider: Provider<TokenDetailsState>,
|
||||
) : Converter<Either<Throwable, StakingEntryInfo>, StakingBlockState> {
|
||||
) : Converter<Either<Throwable, StakingEntryInfo>, StakingBlocksState> {
|
||||
|
||||
override fun convert(value: Either<Throwable, StakingEntryInfo>): StakingBlockState {
|
||||
override fun convert(value: Either<Throwable, StakingEntryInfo>): StakingBlocksState {
|
||||
value.fold(
|
||||
ifLeft = {
|
||||
return StakingBlockState.Error(
|
||||
iconState = currentStateProvider().tokenInfoBlockState.iconState,
|
||||
return StakingBlocksState(
|
||||
stakingAvailable = StakingAvailable.Error(
|
||||
iconState = currentStateProvider().tokenInfoBlockState.iconState,
|
||||
),
|
||||
stakingBalance = StakingBalance.Empty,
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
return StakingBlockState.Content(
|
||||
interestRate = BigDecimalFormatter.formatPercent(
|
||||
percent = it.interestRate,
|
||||
useAbsoluteValue = true,
|
||||
return StakingBlocksState(
|
||||
stakingAvailable = StakingAvailable.Content(
|
||||
interestRate = BigDecimalFormatter.formatPercent(
|
||||
percent = it.interestRate,
|
||||
useAbsoluteValue = true,
|
||||
),
|
||||
periodInDays = it.periodInDays,
|
||||
tokenSymbol = it.tokenSymbol,
|
||||
iconState = currentStateProvider().tokenInfoBlockState.iconState,
|
||||
onStakeClicked = clickIntents::onStakeBannerClick,
|
||||
),
|
||||
periodInDays = it.periodInDays,
|
||||
tokenSymbol = it.tokenSymbol,
|
||||
iconState = currentStateProvider().tokenInfoBlockState.iconState,
|
||||
onStakeClicked = clickIntents::onStakeBannerClick,
|
||||
stakingBalance = StakingBalance.Empty,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -41,10 +41,10 @@ import com.tangem.core.ui.extensions.resolveReference
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingAvailable
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBalance
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.*
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsBalanceBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsDialogs
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsTopAppBar
|
||||
|
|
@ -52,6 +52,8 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.T
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheetConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.swapTransactionsItems
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.StakingBalanceBlock
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking.TokenStakingBlock
|
||||
|
||||
// TODO: Split to blocks [REDACTED_JIRA]
|
||||
@Suppress("LongMethod")
|
||||
|
|
@ -140,10 +142,27 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
|
|||
|
||||
if (state.isStakingBlockShown) {
|
||||
item(
|
||||
key = StakingBlockState::class.java,
|
||||
contentType = StakingBlockState::class.java,
|
||||
content = { TokenStakingBlock(modifier = itemModifier, state = state.stakingBlockState) },
|
||||
key = StakingAvailable::class.java,
|
||||
contentType = StakingAvailable::class.java,
|
||||
content = {
|
||||
TokenStakingBlock(
|
||||
modifier = itemModifier,
|
||||
state = state.stakingBlocksState.stakingAvailable,
|
||||
)
|
||||
},
|
||||
)
|
||||
if (state.stakingBlocksState.stakingBalance is StakingBalance.Content) {
|
||||
item(
|
||||
key = StakingBalance::class.java,
|
||||
contentType = StakingBalance::class.java,
|
||||
content = {
|
||||
StakingBalanceBlock(
|
||||
state = state.stakingBlocksState.stakingBalance,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
swapTransactionsItems(
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.buttons.HorizontalActionChips
|
||||
import com.tangem.core.ui.components.buttons.segmentedbutton.SegmentedButtons
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
|
|
@ -35,20 +37,23 @@ internal fun TokenDetailsBalanceBlock(
|
|||
color = TangemTheme.colors.background.primary,
|
||||
) {
|
||||
Column {
|
||||
Box(
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing12)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12)
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.spacing24),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.common_balance_title),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
maxLines = 1,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(top = TangemTheme.dimens.spacing12),
|
||||
)
|
||||
BalanceButtons(state)
|
||||
}
|
||||
FiatBalance(
|
||||
state = state,
|
||||
|
|
@ -130,6 +135,35 @@ private fun CryptoBalance(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BalanceButtons(state: TokenDetailsBalanceBlockState) {
|
||||
if (state !is TokenDetailsBalanceBlockState.Content) return
|
||||
|
||||
SegmentedButtons(
|
||||
config = state.balanceSegmentedButtonConfig,
|
||||
onClick = state.onBalanceSelect,
|
||||
showIndication = false,
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing11)
|
||||
.width(IntrinsicSize.Min),
|
||||
) { config ->
|
||||
Text(
|
||||
text = config.title.resolveReference(),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.caption1,
|
||||
maxLines = 1,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing5,
|
||||
end = TangemTheme.dimens.spacing5,
|
||||
top = TangemTheme.dimens.spacing3,
|
||||
bottom = TangemTheme.dimens.spacing3,
|
||||
)
|
||||
.align(Alignment.Center),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 328, heightDp = 152)
|
||||
@Preview(widthDp = 328, heightDp = 152, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
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 com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBalance
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.utils.Strings
|
||||
|
||||
@Composable
|
||||
fun StakingBalanceBlock(state: StakingBalance.Content, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.staking_native),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing2),
|
||||
)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8)) {
|
||||
Text(
|
||||
text = state.fiatAmount.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = Strings.DOT,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = state.cryptoAmount.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = state.rewardAmount.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_chevron_right_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun StakingBalanceBlock_Preview(
|
||||
@PreviewParameter(StakingBalanceBlockPreviewProvider::class) data: StakingBalance,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
StakingBalanceBlock(
|
||||
state = data as StakingBalance.Content,
|
||||
modifier = Modifier.padding(TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class StakingBalanceBlockPreviewProvider : PreviewParameterProvider<StakingBalance> {
|
||||
override val values: Sequence<StakingBalance>
|
||||
get() = sequenceOf(
|
||||
TokenDetailsPreviewData.tokenDetailsState_1.stakingBlocksState.stakingBalance,
|
||||
TokenDetailsPreviewData.tokenDetailsState_2.stakingBlocksState.stakingBalance,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components
|
||||
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.staking
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -14,14 +15,17 @@ 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.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.SpacerW8
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.utils.GRAY_SCALE_ALPHA
|
||||
import com.tangem.core.ui.utils.GrayscaleColorFilter
|
||||
import com.tangem.core.ui.utils.NORMAL_ALPHA
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.IconState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingAvailable
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.CurrencyIcon
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
|
||||
/**
|
||||
|
|
@ -31,7 +35,7 @@ import com.tangem.features.tokendetails.impl.R
|
|||
* @param modifier modifier
|
||||
*/
|
||||
@Composable
|
||||
internal fun TokenStakingBlock(state: StakingBlockState, modifier: Modifier = Modifier) {
|
||||
internal fun TokenStakingBlock(state: StakingAvailable, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(
|
||||
|
|
@ -49,7 +53,7 @@ internal fun TokenStakingBlock(state: StakingBlockState, modifier: Modifier = Mo
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun Content(state: StakingBlockState, modifier: Modifier = Modifier) {
|
||||
private fun Content(state: StakingAvailable, modifier: Modifier = Modifier) {
|
||||
AnimatedContent(
|
||||
modifier = modifier.heightIn(min = TangemTheme.dimens.size60),
|
||||
targetState = state,
|
||||
|
|
@ -57,24 +61,24 @@ private fun Content(state: StakingBlockState, modifier: Modifier = Modifier) {
|
|||
label = "Update the content",
|
||||
) { stakingBlockState ->
|
||||
when (stakingBlockState) {
|
||||
is StakingBlockState.Content -> {
|
||||
is StakingAvailable.Content -> {
|
||||
StakingContent(
|
||||
stakingBlockState = stakingBlockState,
|
||||
iconState = stakingBlockState.iconState,
|
||||
)
|
||||
}
|
||||
is StakingBlockState.Loading -> {
|
||||
is StakingAvailable.Loading -> {
|
||||
StakingLoading(
|
||||
iconState = stakingBlockState.iconState,
|
||||
)
|
||||
}
|
||||
is StakingBlockState.Error -> Row {} // TODO staking
|
||||
is StakingAvailable.Error -> Row {} // TODO staking
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StakingContent(stakingBlockState: StakingBlockState.Content, iconState: IconState) {
|
||||
private fun StakingContent(stakingBlockState: StakingAvailable.Content, iconState: IconState) {
|
||||
Column {
|
||||
Row {
|
||||
val (alpha, colorFilter) = remember(iconState.isGrayscale) {
|
||||
|
|
@ -177,24 +181,24 @@ private fun StakingLoading(iconState: IconState) {
|
|||
@Composable
|
||||
private fun Preview_TokenStakingBlock(
|
||||
@PreviewParameter(StakingBlockStateProvider::class)
|
||||
state: StakingBlockState,
|
||||
state: StakingAvailable,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TokenStakingBlock(state = state)
|
||||
}
|
||||
}
|
||||
|
||||
private class StakingBlockStateProvider : CollectionPreviewParameterProvider<StakingBlockState>(
|
||||
private class StakingBlockStateProvider : CollectionPreviewParameterProvider<StakingAvailable>(
|
||||
collection = listOf(
|
||||
StakingBlockState.Content(
|
||||
StakingAvailable.Content(
|
||||
iconState = iconState,
|
||||
interestRate = "10",
|
||||
periodInDays = 4,
|
||||
tokenSymbol = "SOL",
|
||||
onStakeClicked = {},
|
||||
),
|
||||
StakingBlockState.Loading(iconState = iconState),
|
||||
StakingBlockState.Error(iconState = iconState),
|
||||
StakingAvailable.Loading(iconState = iconState),
|
||||
StakingAvailable.Error(iconState = iconState),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -4,6 +4,7 @@ import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
interface TokenDetailsClickIntents {
|
||||
|
|
@ -59,4 +60,6 @@ interface TokenDetailsClickIntents {
|
|||
fun onAssociateClick()
|
||||
|
||||
fun onStakeBannerClick()
|
||||
|
||||
fun onBalanceSelect(config: TokenBalanceSegmentedButtonConfig)
|
||||
}
|
||||
|
|
@ -63,6 +63,7 @@ import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRout
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsCurrencyStatusAnalyticsSender
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsNotificationsAnalyticsSender
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheetConfig
|
||||
|
|
@ -125,12 +126,12 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
) : ViewModel(), DefaultLifecycleObserver, TokenDetailsClickIntents {
|
||||
|
||||
private val userWalletId: UserWalletId = savedStateHandle.get<Bundle>(AppRoute.CurrencyDetails.USER_WALLET_ID_KEY)
|
||||
?.let { it.unbundle(UserWalletId.serializer()) }
|
||||
?.unbundle(UserWalletId.serializer())
|
||||
?: error("This screen can't open without `UserWalletId`")
|
||||
|
||||
private val cryptoCurrency: CryptoCurrency =
|
||||
savedStateHandle.get<Bundle>(AppRoute.CurrencyDetails.CRYPTO_CURRENCY_KEY)
|
||||
?.let { it.unbundle(CryptoCurrency.serializer()) }
|
||||
?.unbundle(CryptoCurrency.serializer())
|
||||
?: error("This screen can't open without `CryptoCurrency`")
|
||||
|
||||
private val userWallet: UserWallet
|
||||
|
|
@ -154,6 +155,7 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
symbol = cryptoCurrency.symbol,
|
||||
decimals = cryptoCurrency.decimals,
|
||||
featureToggles = tokenDetailsFeatureToggles,
|
||||
isStakingEnabled = stakingFeatureToggles.isStakingEnabled,
|
||||
)
|
||||
|
||||
private val exchangeStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
|
|
@ -787,6 +789,10 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onBalanceSelect(config: TokenBalanceSegmentedButtonConfig) {
|
||||
uiState = stateFactory.getStateWithUpdatedBalanceSegmentedButtonConfig(config)
|
||||
}
|
||||
|
||||
private fun handleUnavailabilityReason(unavailabilityReason: ScenarioUnavailabilityReason): Boolean {
|
||||
if (unavailabilityReason == ScenarioUnavailabilityReason.None) return false
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.domain.visa.model.VisaCurrency
|
|||
import com.tangem.domain.visa.model.VisaTxHistoryItem
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.VisaWalletIntents
|
||||
import com.tangem.utils.Strings
|
||||
import com.tangem.utils.converter.Converter
|
||||
import org.joda.time.DateTimeZone
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ internal class VisaTxHistoryItemStateConverter(
|
|||
override fun convert(value: VisaTxHistoryItem): TransactionState {
|
||||
val localDate = value.date.withZone(DateTimeZone.getDefault())
|
||||
val time = DateTimeFormatters.formatDate(localDate, DateTimeFormatters.timeFormatter)
|
||||
val subtitle = "$time • ${value.status.capitalize()}"
|
||||
val subtitle = "$time ${Strings.DOT} ${value.status.capitalize()}"
|
||||
|
||||
return TransactionState.Content(
|
||||
txHash = value.id,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue