diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml
index 2f740dd9d7..a50e97f246 100644
--- a/core/res/src/main/res/values-de/strings.xml
+++ b/core/res/src/main/res/values-de/strings.xml
@@ -115,10 +115,6 @@
Zum Anbieter gehen
Zum Token
Importieren
-
- - in %d Tag
- - in %d Tagen
-
Später
Gesperrt
Hauptnetz
@@ -641,8 +637,6 @@
Entferne diese Wallet
Hiermit wird die Wallet aus der Anwendung entfernt. Die Wallet selbst kann wieder hinzugefügt werden.
Name
- Aktiv
- Um deine Vermögenswerte freizugeben, tippe auf den Block oben
Die Anzahl der zu stakenden Krypros muss mindesten %s betragen
Nicht gestakte beanspruche
Jährliche prozentuale Rendite
@@ -702,7 +696,6 @@
Lösen der Bindungen
Gelocktes unlocken
Unstaken
- Prüfe, was nicht eingesetzt wurde, um dein Vermögen zu beanspruchen
Staking beenden
Validator/ Prüfer
Validatoren
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index 87595dbdf6..dd3a253e57 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -115,10 +115,6 @@
Aller au fournisseur
Aller au jeton
Importez
-
- - dans %d jour
- - dans %d jours
-
Plus tard
Verrouillé
Réseau principal
@@ -637,8 +633,6 @@
Oublier le portefeuille
Cela supprimera le portefeuille de l\'application. Le portefeuille lui-même peut être ajouté à nouveau.
Nom
- Actif
- Afin d\'unstaker vos actifs, appuyez sur le bloc ci-dessus
Le montant à staker doit être au moins %s
Réclamation déstakée
Pourcentage de rendement annuel
@@ -697,7 +691,6 @@
Dissociation
Débloquer
Non-staké
- Vérifiez non-stakés pour réclamer vos actifs
Unstaking
Validateur
Validateurs
diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml
index 33f3202506..5e94e5d5f8 100644
--- a/core/res/src/main/res/values-ja/strings.xml
+++ b/core/res/src/main/res/values-ja/strings.xml
@@ -83,6 +83,7 @@
カメラへのアクセスを許可していません。プライバシー設定を調整してください。
キャンセル
アクションを選択
+ 請求
報酬を受け取る
閉じる
続ける
@@ -113,9 +114,6 @@
プロバイダーへ移動
トークンへ移動
インポート
-
- - %d日で
-
後で
ロックされています
メインネットワーク
@@ -628,8 +626,6 @@
ウォレット削除
これにより、ウォレットがアプリから削除されます。ウォレットは再度追加できます。
名前
- アクティブ
- 資産のステーキングを解除するには、上のブロックをタップしてください
ステーキング金額は %s 以上である必要があります
ステーキング解除分を請求する
年率
@@ -654,14 +650,17 @@
ステーキングから資金の引き出しを要求した後、トークンが利用可能になるまでの待機期間。
ウォームアップ期間
ステーキングへの参加を有効にするために割り当てられた時間。
+ ステーキング機能を使用すると、プロバイダーの%1$sと%2$sに同意したことになります
ロック中
移行
ネイティブステーキング
+ 獲得した報酬はあなたのアドレスに直接送られます。受け取り後、資金は使用可能になります。
ステーキングにより%1$sを獲得できます。ステーキング報酬は毎日受け取れます。
ステーキングにより%1$sを獲得できます。ステーキング報酬は毎時間受け取れます。
ステーキングにより%1$sを獲得できます。ステーキング報酬は毎月受け取れます。
ステーキングにより%1$sを獲得できます。ステーキング報酬は毎週受け取れます。
ステーキング報酬を獲得
+ 獲得した報酬をステーキングに再投資し、潜在的な収益を増やします。
ステーキング解除プロセスの開始後、報酬の獲得はすぐに停止します。ステーキング解除には%sかかります。
あなたの資金はステーキング解除されました。獲得した報酬とともに引き出すことができます。
準備中
@@ -684,13 +683,14 @@
報酬
ステーキングはロックされています
もっとステーキングする
+ %1$sをステーキングし、年間 ~ %2$sを受け取ります
%sをステーキングする
%sのステーキング解除
ステーキング解約中
ステーキング解除はロックされています
ステーキングされていない
- 資産を請求するために、unstakedを確認してください
ステーキング解除
+ ステーキング解除中の資産%s
バリデーター
バリデーター
投票する
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 4d2fc19ca5..9011127a90 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -117,12 +117,6 @@
К провайдеру
Перейти в токен
Импортировать
-
- - через %d день
- - через %d дня
- - через %d дней
- - через %d дней
-
Позже
Заблокирован
Основная сеть
@@ -645,8 +639,6 @@
Забыть кошелек
Это приведет к удалению кошелька из приложения. Сам кошелек можно добавить снова.
Имя
- Активно
- Для завершения стейкинга нажмите на блок выше
Сумма для стейкинга должна быть не менее %s
Забрать средства
Процентная ставка
@@ -701,7 +693,6 @@
Отзыв
Разблокировать
Вывод из стейкинга
- Проверьте процесс завершения стейкинга, чтобы вывести свои средства.
Завершение стейкинга
Завершение стейкинга %s
Валидатор
diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml
index ca0bc61e34..96f929750f 100644
--- a/core/res/src/main/res/values-uk-rUA/strings.xml
+++ b/core/res/src/main/res/values-uk-rUA/strings.xml
@@ -642,8 +642,6 @@
Забути гаманець
Це призведе до видалення гаманця з застосунку. Сам гаманець можна додати знову.
Ім\'я
- Активний
- Для завершення стейкінгу натисніть на блок вище
Сума для стейкінгу має бути не менше %s
Зняти кошти
Процентна ставка
@@ -696,7 +694,6 @@
Зняти зі стейкінгу %s
Розблокувати
Вивід зі стейкінгу
- Перевірити незастейкані, щоб отримати свої активи
Зняти зі стейкінгу
Валідатор
Проголосувати
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index b89491b528..6c64f890e2 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -116,11 +116,8 @@
Go to provider
Go to token
Import
-
- - in %d day
- - in %d days
-
Later
+ %1$s left
Locked
Main network
Network fee
@@ -414,6 +411,8 @@
The maximum number of coins or tokens that can ever exist for a particular cryptocurrency
Trading volume (24h)
The total amount of a cryptocurrency that has been traded within the last 24 hours, indicating the level of activity and liquidity in the market
+ Pull this up or tap the search bar to add tokens directly from the market
+ Add tokens
You have to set up a single access code to protect all your cards
Protect
You can set up an individual access code on each card later
@@ -638,8 +637,6 @@
Forget wallet
This will remove the wallet from the application. The wallet itself can be added again.
Name
- Active
- To unstake your assets, tap the block above
The amount to stake must be at least %s
Claim unstaked
Annual percentage rate
@@ -698,12 +695,13 @@
Stake locked
Stake more
You stake %1$s and will be receiving ~%2$s yearly
+ Tap to unlock
+ Tap to withdraw
Stake %s
Unstake %s
Unbonding
Unlock locked
Unstaked
- Check unstaked to claim your assets
Unstaking
Unstaking assets %s
Validator
@@ -711,6 +709,7 @@
Vote
Vote locked
Withdraw
+ Your stakes
Store your crypto assets secure while keeping private keys contained in your card
Revolutionary Hardware Wallet
Up to 3 physical cards to one wallet
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt
index fd4913770c..0991dcdf5a 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt
@@ -1,7 +1,9 @@
package com.tangem.core.ui.components.inputrow
import android.content.res.Configuration
+import androidx.annotation.DrawableRes
import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
@@ -42,11 +44,13 @@ import com.tangem.core.ui.res.TangemThemePreview
@Composable
internal fun InputRowImageBase(
subtitle: TextReference,
- imageUrl: String?,
modifier: Modifier = Modifier,
caption: TextReference? = null,
+ imageUrl: String? = null,
+ @DrawableRes iconRes: Int? = null,
subtitleColor: Color = TangemTheme.colors.text.primary1,
captionColor: Color = TangemTheme.colors.text.tertiary,
+ iconTint: Color = TangemTheme.colors.icon.informative,
isGrayscaleImage: Boolean = false,
iconEndRes: Int? = null,
extraContent: (@Composable RowScope.() -> Unit)? = null,
@@ -65,6 +69,23 @@ internal fun InputRowImageBase(
)
SpacerW12()
}
+ if (iconRes != null) {
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = Modifier
+ .size(TangemTheme.dimens.spacing36)
+ .clip(TangemTheme.shapes.roundedCornersXLarge)
+ .background(iconTint.copy(alpha = 0.08f)),
+ ) {
+ Icon(
+ painter = rememberVectorPainter(image = ImageVector.vectorResource(id = iconRes)),
+ tint = iconTint,
+ contentDescription = null,
+ modifier = Modifier.size(TangemTheme.dimens.size18),
+ )
+ }
+ SpacerW12()
+ }
Column {
Text(
text = subtitle.resolveReference(),
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt
index 16ea439603..19bb005a00 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt
@@ -1,6 +1,7 @@
package com.tangem.core.ui.components.inputrow
import android.content.res.Configuration
+import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
@@ -40,15 +41,17 @@ import com.tangem.core.ui.res.TangemThemePreview
fun InputRowImageInfo(
subtitle: TextReference,
infoTitle: TextReference,
- imageUrl: String?,
modifier: Modifier = Modifier,
title: TextReference? = null,
caption: TextReference? = null,
infoSubtitle: TextReference? = null,
+ imageUrl: String? = null,
+ @DrawableRes iconRes: Int? = null,
subtitleColor: Color = TangemTheme.colors.text.primary1,
captionColor: Color = TangemTheme.colors.text.tertiary,
+ iconTint: Color = TangemTheme.colors.icon.informative,
isGrayscaleImage: Boolean = false,
- iconEndRes: Int? = null,
+ @DrawableRes iconEndRes: Int? = null,
) {
Column(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing6),
@@ -66,6 +69,8 @@ fun InputRowImageInfo(
subtitle = subtitle,
caption = caption,
imageUrl = imageUrl,
+ iconRes = iconRes,
+ iconTint = iconTint,
subtitleColor = subtitleColor,
captionColor = captionColor,
isGrayscaleImage = isGrayscaleImage,
diff --git a/core/ui/src/main/res/drawable/ic_connection_18.xml b/core/ui/src/main/res/drawable/ic_connection_18.xml
new file mode 100644
index 0000000000..80d76d5158
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_connection_18.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/staking/src/main/java/com/tangem/data/staking/converters/YieldBalanceConverter.kt b/data/staking/src/main/java/com/tangem/data/staking/converters/YieldBalanceConverter.kt
index 24eae9474a..70577561ed 100644
--- a/data/staking/src/main/java/com/tangem/data/staking/converters/YieldBalanceConverter.kt
+++ b/data/staking/src/main/java/com/tangem/data/staking/converters/YieldBalanceConverter.kt
@@ -18,6 +18,7 @@ internal class YieldBalanceConverter : Converter
BalanceItem(
+ id = item.groupId,
type = BalanceType.valueOf(item.type.name),
amount = item.amount,
pricePerShare = item.pricePerShare,
diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalance.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalance.kt
index 60cfb91e45..c789da63b3 100644
--- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalance.kt
+++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/YieldBalance.kt
@@ -34,6 +34,7 @@ data class YieldBalanceItem(
)
data class BalanceItem(
+ val id: String,
val type: BalanceType,
val amount: BigDecimal,
val pricePerShare: BigDecimal,
@@ -76,16 +77,21 @@ data class PendingAction(
}
}
-enum class BalanceType {
- AVAILABLE,
- STAKED,
- PREPARING,
- UNSTAKING,
- UNLOCKING,
- UNSTAKED,
- LOCKED,
- REWARDS,
- UNKNOWN,
+/**
+ * IMPORTANT!!!
+ * Order is used to sort balances.
+ */
+@Suppress("MagicNumber")
+enum class BalanceType(val order: Int) {
+ AVAILABLE(1),
+ STAKED(2),
+ PREPARING(3),
+ LOCKED(4),
+ UNSTAKING(5),
+ UNLOCKING(6),
+ UNSTAKED(7),
+ REWARDS(8),
+ UNKNOWN(9),
;
companion object {
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerYieldBalanceState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerYieldBalanceState.kt
index 41fa1c3862..c989de7fb1 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerYieldBalanceState.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerYieldBalanceState.kt
@@ -9,37 +9,29 @@ import com.tangem.domain.staking.model.stakekit.Yield
import kotlinx.collections.immutable.ImmutableList
import java.math.BigDecimal
-sealed class InnerYieldBalanceState {
+internal sealed class InnerYieldBalanceState {
data class Data(
val rewardsCrypto: String,
val rewardsFiat: String,
val rewardBlockType: RewardBlockType,
- val balance: ImmutableList,
+ val balance: ImmutableList,
) : InnerYieldBalanceState()
data object Empty : InnerYieldBalanceState()
}
-// TODO staking get rid of unstable types
@Immutable
-data class BalanceGroupedState(
- val items: ImmutableList,
- val footer: TextReference?,
+internal data class BalanceState(
+ val id: String,
val title: TextReference,
val type: BalanceType,
+ val subtitle: TextReference?,
val isClickable: Boolean,
-)
-
-@Immutable
-data class BalanceState(
- val validator: Yield.Validator?,
- val title: TextReference,
val cryptoValue: String,
val cryptoDecimal: BigDecimal,
val cryptoAmount: TextReference,
val fiatAmount: TextReference,
val rawCurrencyId: String?,
- val unbondingPeriod: TextReference,
- val warmupPeriod: TextReference,
+ val validator: Yield.Validator?,
val pendingActions: ImmutableList,
)
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/BalanceItemConverter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/BalanceItemConverter.kt
new file mode 100644
index 0000000000..c6317bf05d
--- /dev/null
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/BalanceItemConverter.kt
@@ -0,0 +1,125 @@
+package com.tangem.features.staking.impl.presentation.state.converters
+
+import com.tangem.core.ui.extensions.*
+import com.tangem.core.ui.utils.BigDecimalFormatter
+import com.tangem.core.ui.utils.parseBigDecimal
+import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.domain.staking.model.stakekit.BalanceItem
+import com.tangem.domain.staking.model.stakekit.BalanceType
+import com.tangem.domain.staking.model.stakekit.BalanceType.Companion.isClickable
+import com.tangem.domain.staking.model.stakekit.Yield
+import com.tangem.domain.tokens.model.CryptoCurrencyStatus
+import com.tangem.features.staking.impl.R
+import com.tangem.features.staking.impl.presentation.state.BalanceState
+import com.tangem.utils.Provider
+import com.tangem.utils.converter.Converter
+import kotlinx.collections.immutable.toPersistentList
+import org.joda.time.DateTime
+import java.util.Calendar
+
+internal class BalanceItemConverter(
+ private val cryptoCurrencyStatusProvider: Provider,
+ private val appCurrencyProvider: Provider,
+ private val yield: Yield,
+) : Converter {
+ override fun convert(value: BalanceItem): BalanceState? {
+ val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
+ val appCurrency = appCurrencyProvider()
+ val cryptoCurrency = cryptoCurrencyStatus.currency
+
+ val validator = yield.validators.firstOrNull {
+ value.validatorAddress?.contains(it.address, ignoreCase = true) == true
+ }
+
+ val cryptoAmount = value.amount
+ val fiatAmount = cryptoCurrencyStatus.value.fiatRate?.times(cryptoAmount)
+
+ val title = value.type.getTitle(validator?.name)
+ return title?.let {
+ BalanceState(
+ id = value.id,
+ validator = validator,
+ title = title,
+ subtitle = getSubtitle(value),
+ type = value.type,
+ cryptoValue = cryptoAmount.parseBigDecimal(cryptoCurrency.decimals),
+ cryptoDecimal = cryptoAmount,
+ cryptoAmount = stringReference(
+ BigDecimalFormatter.formatCryptoAmount(
+ cryptoAmount = cryptoAmount,
+ cryptoCurrency = cryptoCurrency,
+ ),
+ ),
+ fiatAmount = stringReference(
+ BigDecimalFormatter.formatFiatAmount(
+ fiatAmount = fiatAmount,
+ fiatCurrencyCode = appCurrency.code,
+ fiatCurrencySymbol = appCurrency.symbol,
+ ),
+ ),
+ rawCurrencyId = value.rawCurrencyId,
+ pendingActions = value.pendingActions.toPersistentList(),
+ isClickable = value.type.isClickable(),
+ )
+ }
+ }
+
+ private fun BalanceType.getTitle(validatorName: String?) = when (this) {
+ BalanceType.STAKED -> validatorName?.let { stringReference(it) }
+ BalanceType.PREPARING -> resourceReference(R.string.staking_preparing)
+ BalanceType.UNSTAKED -> resourceReference(R.string.staking_unstaked)
+ BalanceType.UNSTAKING -> resourceReference(R.string.staking_unstaking)
+ BalanceType.LOCKED -> resourceReference(R.string.staking_locked)
+ BalanceType.AVAILABLE,
+ BalanceType.REWARDS,
+ BalanceType.UNLOCKING,
+ BalanceType.UNKNOWN,
+ -> null
+ }
+
+ private fun getSubtitle(balance: BalanceItem) = when (balance.type) {
+ BalanceType.UNSTAKING -> getUnbondingDate(balance.date)
+ BalanceType.UNSTAKED -> resourceReference(R.string.staking_tap_to_withdraw)
+ BalanceType.LOCKED -> resourceReference(R.string.staking_tap_to_unlock)
+ BalanceType.AVAILABLE,
+ BalanceType.STAKED,
+ BalanceType.PREPARING,
+ BalanceType.UNLOCKING,
+ BalanceType.REWARDS,
+ BalanceType.UNKNOWN,
+ -> null
+ }
+
+ private fun getUnbondingDate(date: DateTime?): TextReference {
+ val now = DateTime.now().millis
+ val nowCalendar = Calendar.getInstance()
+ nowCalendar.resetHours()
+
+ val endDate = Calendar.getInstance()
+ endDate.timeInMillis = date?.millis ?: now
+ endDate.resetHours()
+
+ val days = ((endDate.timeInMillis - nowCalendar.timeInMillis) / DAY_IN_MILLIS).toInt()
+ return if (days > 0) {
+ resourceReference(
+ R.string.common_left,
+ wrappedList(
+ pluralReference(R.plurals.common_days, days, wrappedList(days)),
+ ),
+ )
+ } else {
+ resourceReference(R.string.common_today)
+ }
+ }
+
+ private fun Calendar.resetHours() {
+ this[Calendar.HOUR_OF_DAY] = 0
+ this[Calendar.MINUTE] = 0
+ this[Calendar.SECOND] = 0
+ this[Calendar.MILLISECOND] = 0
+ }
+
+ private companion object {
+ const val DAY_IN_MILLIS = 24 * 60 * 60 * 1000
+ }
+}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/RewardsValidatorStateConverter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/RewardsValidatorStateConverter.kt
index 987866f39b..e3cc2f8e07 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/RewardsValidatorStateConverter.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/RewardsValidatorStateConverter.kt
@@ -1,19 +1,18 @@
package com.tangem.features.staking.impl.presentation.state.converters
-import com.tangem.core.ui.extensions.pluralReference
import com.tangem.core.ui.extensions.stringReference
-import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
-import com.tangem.domain.staking.model.stakekit.*
+import com.tangem.domain.staking.model.stakekit.BalanceItem
+import com.tangem.domain.staking.model.stakekit.BalanceType
+import com.tangem.domain.staking.model.stakekit.Yield
+import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
-import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.BalanceState
import com.tangem.features.staking.impl.presentation.state.StakingStates
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
-import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toPersistentList
import java.math.BigDecimal
@@ -49,23 +48,21 @@ internal class RewardsValidatorStateConverter(
val fiatValue = cryptoCurrencyStatus.value.fiatRate?.times(cryptoValue)
validator?.toBalanceState(
+ balance = balance,
cryptoCurrencyStatus = cryptoCurrencyStatus,
cryptoValue = cryptoValue,
fiatValue = fiatValue,
- pendingActions = balance.pendingActions.toPersistentList(),
)
}
private fun Yield.Validator.toBalanceState(
+ balance: BalanceItem,
cryptoCurrencyStatus: CryptoCurrencyStatus,
cryptoValue: BigDecimal,
fiatValue: BigDecimal?,
- pendingActions: ImmutableList,
): BalanceState {
val appCurrency = appCurrencyProvider()
val cryptoCurrency = cryptoCurrencyStatus.currency
- val unbondingPeriod = yield.metadata.cooldownPeriod.days
- val warmupPeriod = yield.metadata.warmupPeriod.days
val cryptoAmount = stringReference(
BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = cryptoValue,
@@ -81,24 +78,18 @@ internal class RewardsValidatorStateConverter(
)
return BalanceState(
+ id = balance.id,
validator = this,
title = stringReference(this.name),
+ subtitle = null,
cryptoValue = cryptoValue.parseBigDecimal(cryptoCurrency.decimals),
cryptoDecimal = cryptoValue,
cryptoAmount = cryptoAmount,
fiatAmount = fiatAmount,
rawCurrencyId = cryptoCurrency.id.rawCurrencyId,
- unbondingPeriod = pluralReference(
- id = R.plurals.common_days,
- count = unbondingPeriod,
- formatArgs = wrappedList(unbondingPeriod),
- ),
- warmupPeriod = pluralReference(
- id = R.plurals.common_days,
- count = unbondingPeriod,
- formatArgs = wrappedList(warmupPeriod),
- ),
- pendingActions = pendingActions,
+ pendingActions = balance.pendingActions.toPersistentList(),
+ isClickable = true,
+ type = balance.type,
)
}
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt
index 856bec78cc..d948580b77 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/converters/YieldBalancesConverter.kt
@@ -1,29 +1,26 @@
package com.tangem.features.staking.impl.presentation.state.converters
import com.tangem.common.extensions.isZero
-import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.utils.BigDecimalFormatter
-import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.staking.model.stakekit.*
-import com.tangem.domain.staking.model.stakekit.BalanceType.Companion.isClickable
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
-import com.tangem.features.staking.impl.R
-import com.tangem.features.staking.impl.presentation.state.BalanceGroupedState
-import com.tangem.features.staking.impl.presentation.state.BalanceState
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
import com.tangem.lib.crypto.BlockchainUtils.isSolana
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toPersistentList
-import org.joda.time.DateTime
-import java.util.Calendar
internal class YieldBalancesConverter(
private val cryptoCurrencyStatusProvider: Provider,
private val appCurrencyProvider: Provider,
private val yield: Yield,
) : Converter {
+
+ private val balanceItemConverter by lazy(LazyThreadSafetyMode.NONE) {
+ BalanceItemConverter(cryptoCurrencyStatusProvider, appCurrencyProvider, yield)
+ }
+
override fun convert(value: Unit): InnerYieldBalanceState {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val appCurrency = appCurrencyProvider()
@@ -34,7 +31,6 @@ internal class YieldBalancesConverter(
return if (yieldBalance is YieldBalance.Data) {
val cryptoRewardsValue = yieldBalance.getRewardStakingBalance()
val fiatRewardsValue = cryptoCurrencyStatus.value.fiatRate?.times(cryptoRewardsValue)
- val groupedBalances = getGroupedBalance(yieldBalance.balance)
InnerYieldBalanceState.Data(
rewardsCrypto = BigDecimalFormatter.formatCryptoAmount(
@@ -47,121 +43,18 @@ internal class YieldBalancesConverter(
fiatCurrencySymbol = appCurrency.symbol,
),
rewardBlockType = getRewardBlockType(),
- balance = groupedBalances,
+ balance = yieldBalance.balance.items.mapBalances(),
)
} else {
InnerYieldBalanceState.Empty
}
}
- private fun getGroupedBalance(balance: YieldBalanceItem) = balance.items
- .sortedBy { it.type }
- .groupBy { it.type.toGroup() }
- .mapNotNull { item ->
- val (title, footer) = getGroupTitle(item.key)
- val isClickable = item.key.isClickable()
- title?.let {
- BalanceGroupedState(
- items = item.value.mapBalances(item.key).toPersistentList(),
- footer = footer,
- title = it,
- type = item.key,
- isClickable = isClickable,
- )
- }
- }
- .filterNot { it.items.isEmpty() }
+ private fun List.mapBalances() = sortedBy { it.type.order }
+ .filterNot { it.amount.isZero() || it.type == BalanceType.REWARDS }
+ .mapNotNull(balanceItemConverter::convert)
.toPersistentList()
- private fun List.mapBalances(balanceType: BalanceType): List {
- val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
- val appCurrency = appCurrencyProvider()
- val cryptoCurrency = cryptoCurrencyStatus.currency
- var incrementingIndex = 1
- return this
- .filterNot { it.amount.isZero() }
- .mapNotNull { balance ->
- val validator = yield.validators.firstOrNull {
- balance.validatorAddress?.contains(it.address, ignoreCase = true) == true
- }
-
- val cryptoAmount = balance.amount
- val fiatAmount = cryptoCurrencyStatus.value.fiatRate?.times(cryptoAmount)
- val unbonding = getUnbondingDate(balance.date)
- val warmupPeriod = yield.metadata.warmupPeriod.days
- val title = when {
- validator != null -> stringReference(validator.name)
- balanceType == BalanceType.UNSTAKING -> {
- resourceReference(R.string.staking_unstaking_item_name, wrappedList(incrementingIndex++))
- }
- else -> null
- }
- title?.let {
- BalanceState(
- validator = validator,
- title = title,
- cryptoValue = cryptoAmount.parseBigDecimal(cryptoCurrency.decimals),
- cryptoDecimal = cryptoAmount,
- cryptoAmount = stringReference(
- BigDecimalFormatter.formatCryptoAmount(
- cryptoAmount = cryptoAmount,
- cryptoCurrency = cryptoCurrency,
- ),
- ),
- fiatAmount = stringReference(
- BigDecimalFormatter.formatFiatAmount(
- fiatAmount = fiatAmount,
- fiatCurrencyCode = appCurrency.code,
- fiatCurrencySymbol = appCurrency.symbol,
- ),
- ),
- rawCurrencyId = balance.rawCurrencyId,
- unbondingPeriod = unbonding,
- warmupPeriod = pluralReference(R.plurals.common_days, warmupPeriod, wrappedList(warmupPeriod)),
- pendingActions = balance.pendingActions.toPersistentList(),
- )
- }
- }
- }
-
- private fun BalanceType.toGroup() = when (this) {
- BalanceType.REWARDS,
- BalanceType.UNKNOWN,
- -> BalanceType.UNKNOWN
- else -> this
- }
-
- private fun getGroupTitle(type: BalanceType) = when (type) {
- BalanceType.STAKED -> resourceReference(R.string.staking_active) to
- resourceReference(R.string.staking_active_footer)
- BalanceType.UNSTAKED -> resourceReference(R.string.staking_unstaked) to
- resourceReference(R.string.staking_unstaked_footer)
- BalanceType.UNSTAKING -> resourceReference(R.string.staking_unstaking) to null
- BalanceType.LOCKED -> resourceReference(R.string.staking_locked) to null
- BalanceType.AVAILABLE -> null to null
- BalanceType.PREPARING -> resourceReference(R.string.staking_preparing) to null
- BalanceType.REWARDS -> null to null
- BalanceType.UNLOCKING -> null to null
- BalanceType.UNKNOWN -> null to null
- }
-
- private fun getUnbondingDate(date: DateTime?): TextReference {
- val now = DateTime.now().millis
- val nowCalendar = Calendar.getInstance()
- nowCalendar.resetHours()
-
- val endDate = Calendar.getInstance()
- endDate.timeInMillis = date?.millis ?: now
- endDate.resetHours()
-
- val days = ((endDate.timeInMillis - nowCalendar.timeInMillis) / DAY_IN_MILLIS).toInt()
- return if (days > 0) {
- pluralReference(R.plurals.common_in_days, days, wrappedList(days))
- } else {
- resourceReference(R.string.common_today)
- }
- }
-
private fun getRewardBlockType(): RewardBlockType {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data
@@ -178,15 +71,4 @@ internal class YieldBalancesConverter(
else -> RewardBlockType.NoRewards
}
}
-
- private fun Calendar.resetHours() {
- this[Calendar.HOUR_OF_DAY] = 0
- this[Calendar.MINUTE] = 0
- this[Calendar.SECOND] = 0
- this[Calendar.MILLISECOND] = 0
- }
-
- private companion object {
- const val DAY_IN_MILLIS = 24 * 60 * 60 * 1000
- }
}
\ No newline at end of file
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt
index a6ac4963e9..c23cb74fda 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/InitialStakingStatePreview.kt
@@ -6,9 +6,9 @@ import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.staking.model.stakekit.BalanceType
import com.tangem.domain.staking.model.stakekit.RewardBlockType
import com.tangem.domain.staking.model.stakekit.Yield
-import com.tangem.domain.staking.model.stakekit.Yield.Validator.ValidatorStatus
import com.tangem.features.staking.impl.R
-import com.tangem.features.staking.impl.presentation.state.*
+import com.tangem.features.staking.impl.presentation.state.BalanceState
+import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
import com.tangem.features.staking.impl.presentation.state.StakingStates
import kotlinx.collections.immutable.persistentListOf
@@ -63,36 +63,30 @@ internal object InitialStakingStatePreview {
rewardsCrypto = "100 SOL",
rewardBlockType = RewardBlockType.RewardUnavailable,
balance = persistentListOf(
- BalanceGroupedState(
- title = stringReference("Staked"),
- footer = null,
- type = BalanceType.STAKED,
- isClickable = true,
- items = persistentListOf(
- BalanceState(
- title = stringReference("Binance"),
- cryptoValue = "100",
- cryptoAmount = stringReference("100 SOL"),
- cryptoDecimal = "100".toBigDecimal(),
- fiatAmount = stringReference("100 $"),
- rawCurrencyId = null,
- validator = Yield.Validator(
- address = "address",
- status = ValidatorStatus.ACTIVE,
- name = "Binance",
- image = null,
- website = null,
- apr = "5".toBigDecimal(),
- commission = null,
- stakedBalance = null,
- votingPower = null,
- preferred = false,
- ),
- unbondingPeriod = stringReference("3 days"),
- pendingActions = persistentListOf(),
- warmupPeriod = stringReference("3 days"),
- ),
+ BalanceState(
+ id = "id",
+ title = stringReference("Binance"),
+ cryptoValue = "100",
+ cryptoAmount = stringReference("100 SOL"),
+ cryptoDecimal = "100".toBigDecimal(),
+ fiatAmount = stringReference("100 $"),
+ rawCurrencyId = null,
+ validator = Yield.Validator(
+ address = "address",
+ status = Yield.Validator.ValidatorStatus.ACTIVE,
+ name = "Binance",
+ image = null,
+ website = null,
+ apr = "5".toBigDecimal(),
+ commission = null,
+ stakedBalance = null,
+ votingPower = null,
+ preferred = false,
),
+ pendingActions = persistentListOf(),
+ isClickable = true,
+ type = BalanceType.STAKED,
+ subtitle = null,
),
),
),
diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt
index 5e2f5c710b..530716b3fe 100644
--- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt
+++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt
@@ -32,7 +32,6 @@ import androidx.compose.ui.unit.Density
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
import com.tangem.common.ui.navigationButtons.NavigationPrimaryButton
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.roundedListWithDividersItems
@@ -44,7 +43,6 @@ import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.staking.model.stakekit.BalanceType
import com.tangem.domain.staking.model.stakekit.RewardBlockType
import com.tangem.features.staking.impl.R
-import com.tangem.features.staking.impl.presentation.state.BalanceGroupedState
import com.tangem.features.staking.impl.presentation.state.BalanceState
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
import com.tangem.features.staking.impl.presentation.state.StakingStates
@@ -198,53 +196,43 @@ private fun StakingRewardBlock(
}
@Composable
-private fun ActiveStakingBlock(groups: ImmutableList, onClick: (BalanceState) -> Unit) {
+private fun ActiveStakingBlock(balances: ImmutableList, onClick: (BalanceState) -> Unit) {
Column(
- verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action),
) {
- groups.forEach { group ->
- key(group.title) {
- FooterContainer(
- footer = group.footer?.resolveReference(),
- modifier = Modifier,
- ) {
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .clip(TangemTheme.shapes.roundedCornersXMedium)
- .background(TangemTheme.colors.background.action),
- ) {
- Text(
- text = group.title.resolveReference(),
- style = TangemTheme.typography.subtitle2,
- color = TangemTheme.colors.text.tertiary,
- modifier = Modifier.padding(
- top = TangemTheme.dimens.spacing12,
- start = TangemTheme.dimens.spacing12,
- end = TangemTheme.dimens.spacing12,
- ),
- )
- group.items.forEachIndexed { index, balance ->
- key(balance.title.resolveReference() + index) {
- InputRowImageInfo(
- subtitle = balance.title,
- caption = getCaption(group.type, balance),
- isGrayscaleImage = !group.isClickable,
- infoTitle = balance.fiatAmount,
- infoSubtitle = balance.cryptoAmount,
- imageUrl = balance.validator?.image,
- iconEndRes = R.drawable.ic_chevron_right_24.takeIf { group.isClickable },
- modifier = Modifier.clickable(
- interactionSource = remember { MutableInteractionSource() },
- indication = rememberRipple(),
- enabled = group.isClickable,
- onClick = { onClick(balance) },
- ),
- )
- }
- }
- }
- }
+ Text(
+ text = stringResource(id = R.string.staking_your_stakes),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ modifier = Modifier.padding(
+ top = TangemTheme.dimens.spacing12,
+ start = TangemTheme.dimens.spacing12,
+ end = TangemTheme.dimens.spacing12,
+ bottom = TangemTheme.dimens.spacing4,
+ ),
+ )
+ balances.forEach { balance ->
+ key(balance.id) {
+ val (icon, iconTint) = balance.type.getIcon()
+ InputRowImageInfo(
+ subtitle = balance.title,
+ caption = balance.subtitle ?: balance.getAprText(),
+ isGrayscaleImage = !balance.isClickable,
+ infoTitle = balance.fiatAmount,
+ infoSubtitle = balance.cryptoAmount,
+ imageUrl = balance.getImage(),
+ iconRes = icon,
+ iconTint = iconTint,
+ modifier = Modifier.clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = rememberRipple(),
+ enabled = balance.isClickable,
+ onClick = { onClick(balance) },
+ ),
+ )
}
}
}
@@ -266,51 +254,35 @@ private fun StakeButtonBlock(buttonState: NavigationButtonsState) {
}
@Composable
-private fun getCaption(balanceType: BalanceType, balance: BalanceState): TextReference {
- return when (balanceType) {
- BalanceType.UNSTAKING -> {
- combinedReference(
- resourceReference(R.string.staking_unbonding),
- annotatedReference {
- appendSpace()
- appendColored(
- text = balance.unbondingPeriod.resolveReference(),
- color = TangemTheme.colors.text.accent,
- )
- },
- )
- }
- BalanceType.UNSTAKED -> {
- resourceReference(R.string.staking_ready_to_withdraw)
- }
- BalanceType.PREPARING -> {
- combinedReference(
- resourceReference(R.string.staking_details_warmup_period),
- annotatedReference {
- appendSpace()
- appendColored(
- text = balance.warmupPeriod.resolveReference(),
- color = TangemTheme.colors.text.accent,
- )
- },
- )
- }
- else -> {
- combinedReference(
- resourceReference(R.string.staking_details_apr),
- annotatedReference {
- appendSpace()
- appendColored(
- text = BigDecimalFormatter.formatPercent(
- percent = balance.validator?.apr.orZero(),
- useAbsoluteValue = true,
- ),
- color = TangemTheme.colors.text.accent,
- )
- },
- )
- }
- }
+private fun BalanceState.getAprText() = combinedReference(
+ resourceReference(R.string.staking_details_apr),
+ annotatedReference {
+ appendSpace()
+ appendColored(
+ text = BigDecimalFormatter.formatPercent(
+ percent = validator?.apr.orZero(),
+ useAbsoluteValue = true,
+ ),
+ color = TangemTheme.colors.text.accent,
+ )
+ },
+)
+
+@Composable
+private fun BalanceType.getIcon() = when (this) {
+ BalanceType.UNSTAKING -> R.drawable.ic_connection_18 to TangemTheme.colors.icon.accent
+ BalanceType.UNSTAKED -> R.drawable.ic_connection_18 to TangemTheme.colors.icon.informative
+ BalanceType.LOCKED -> R.drawable.ic_lock_24 to TangemTheme.colors.icon.informative
+ else -> null to TangemTheme.colors.icon.informative
+}
+
+@Composable
+private fun BalanceState.getImage() = when (type) {
+ BalanceType.UNSTAKING,
+ BalanceType.UNSTAKED,
+ BalanceType.LOCKED,
+ -> null
+ else -> validator?.image
}
private val textGradientColors = listOf(