Updated on 2026-08-14
This commit is contained in:
commit
45156f05b0
1184 changed files with 47887 additions and 11982 deletions
|
|
@ -19,7 +19,6 @@ import com.tangem.domain.models.account.Account
|
|||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.quote.PriceChange
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.isZero
|
||||
import java.math.BigDecimal
|
||||
|
||||
class AccountCryptoPortfolioItemStateConverter(
|
||||
|
|
@ -41,14 +40,11 @@ class AccountCryptoPortfolioItemStateConverter(
|
|||
private fun Account.CryptoPortfolio.mapToContentState(
|
||||
fiatBalance: TotalFiatBalance.Loaded,
|
||||
): TokenItemState.Content {
|
||||
val subtitle2State = when (fiatBalance.amount.isZero()) {
|
||||
true -> null
|
||||
false -> priceChangeLce?.fold(
|
||||
ifLoading = { priceChange -> priceChange?.toSubtitle2State() ?: Subtitle2State.Loading },
|
||||
ifError = { null },
|
||||
ifContent = { priceChange -> priceChange.toSubtitle2State() },
|
||||
)
|
||||
}
|
||||
val subtitle2State = priceChangeLce?.fold(
|
||||
ifLoading = { priceChange -> priceChange?.toSubtitle2State() ?: Subtitle2State.Loading },
|
||||
ifError = { null },
|
||||
ifContent = { priceChange -> priceChange.toSubtitle2State() },
|
||||
)
|
||||
return TokenItemState.Content(
|
||||
id = account.accountId.toItemId(),
|
||||
iconState = AccountIconItemStateConverter.convert(this),
|
||||
|
|
@ -120,7 +116,7 @@ class AccountCryptoPortfolioItemStateConverter(
|
|||
)
|
||||
}
|
||||
|
||||
private fun AccountId.toItemId() = this.userWalletId.stringValue + this.value
|
||||
private fun AccountId.toItemId() = this.value
|
||||
|
||||
private fun BigDecimal.getPriceChangeType(): PriceChangeType = PriceChangeConverter.fromBigDecimal(value = this)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.common.ui.R
|
|||
import com.tangem.core.ui.components.account.AccountCharIcon
|
||||
import com.tangem.core.ui.components.account.AccountIconSize
|
||||
import com.tangem.core.ui.components.account.AccountResIcon
|
||||
import com.tangem.core.ui.components.account.PaymentAccountIcon
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
|
|
@ -16,7 +17,7 @@ import com.tangem.domain.models.account.CryptoPortfolioIcon.Color
|
|||
* - a single character (derived from the [name]) using [AccountCharIcon], or
|
||||
* - a predefined vector resource (from [icon]) using [AccountResIcon].
|
||||
*
|
||||
* The background color is taken from [CryptoPortfolioIconUM.color],
|
||||
* The background color is taken from [AccountIconUM.CryptoPortfolio.color],
|
||||
* and the icon size, text style, and container shape are adapted based on the given [size].
|
||||
*
|
||||
* @param name A [TextReference] used to resolve and display the first letter
|
||||
|
|
@ -31,29 +32,43 @@ import com.tangem.domain.models.account.CryptoPortfolioIcon.Color
|
|||
@Composable
|
||||
fun AccountIcon(
|
||||
name: TextReference,
|
||||
icon: CryptoPortfolioIconUM,
|
||||
icon: AccountIconUM.CryptoPortfolio,
|
||||
size: AccountIconSize,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val letter = name.resolveReference().firstOrNull()
|
||||
val iconColor = icon.color.getUiColor()
|
||||
when {
|
||||
icon.value == CryptoPortfolioIcon.Icon.Letter && letter == null -> {
|
||||
AccountResIcon(
|
||||
resId = R.drawable.ic_tangem_24,
|
||||
color = icon.color.getUiColor(),
|
||||
color = iconColor,
|
||||
size = size,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
icon.value == CryptoPortfolioIcon.Icon.Letter -> AccountCharIcon(
|
||||
char = letter ?: 'N',
|
||||
color = icon.color.getUiColor(),
|
||||
color = iconColor,
|
||||
size = size,
|
||||
modifier = modifier,
|
||||
)
|
||||
else -> AccountResIcon(
|
||||
resId = icon.value.getResId(),
|
||||
color = icon.color.getUiColor(),
|
||||
color = iconColor,
|
||||
size = size,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AccountIcon(name: TextReference, icon: AccountIconUM, size: AccountIconSize, modifier: Modifier = Modifier) {
|
||||
when (icon) {
|
||||
is AccountIconUM.Payment -> PaymentAccountIcon(size = size, modifier = modifier)
|
||||
is AccountIconUM.CryptoPortfolio -> AccountIcon(
|
||||
name = name,
|
||||
icon = icon,
|
||||
size = size,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
|
@ -62,7 +77,7 @@ fun AccountIcon(
|
|||
|
||||
object AccountIconPreviewData {
|
||||
|
||||
fun randomAccountIcon(letter: Boolean = false) = CryptoPortfolioIconUM(
|
||||
fun randomAccountIcon(letter: Boolean = false) = AccountIconUM.CryptoPortfolio(
|
||||
value = if (letter) CryptoPortfolioIcon.Icon.Letter else CryptoPortfolioIcon.Icon.entries.random(),
|
||||
color = Color.entries.random(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,5 +20,6 @@ object AccountIconItemStateConverter : Converter<Account, CurrencyIconState.Cryp
|
|||
isGrayscale = false,
|
||||
)
|
||||
}
|
||||
is Account.Payment -> TODO("[REDACTED_JIRA]")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.common.ui.account
|
||||
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon.Color
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon.Icon
|
||||
|
||||
sealed class AccountIconUM {
|
||||
data class CryptoPortfolio(val value: Icon, val color: Color) : AccountIconUM()
|
||||
|
||||
data object Payment : AccountIconUM()
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
@Composable
|
||||
fun AccountLabel(
|
||||
name: TextReference,
|
||||
icon: CryptoPortfolioIconUM,
|
||||
icon: AccountIconUM,
|
||||
iconSize: AccountIconSize,
|
||||
modifier: Modifier = Modifier,
|
||||
nameStyle: TextStyle = TangemTheme.typography.subtitle2,
|
||||
|
|
|
|||
|
|
@ -22,21 +22,24 @@ class AccountPortfolioItemUMConverter(
|
|||
) : Converter<Account, UserWalletItemUM> {
|
||||
|
||||
override fun convert(value: Account): UserWalletItemUM {
|
||||
return with(value) {
|
||||
UserWalletItemUM(
|
||||
id = accountId.value,
|
||||
name = accountName.toUM().value,
|
||||
information = getInfo(account = this),
|
||||
balance = getBalanceInfo(),
|
||||
isEnabled = isEnabled,
|
||||
endIcon = endIcon,
|
||||
onClick = onClick,
|
||||
imageState = getImageState(account = this),
|
||||
)
|
||||
return when (value) {
|
||||
is Account.CryptoPortfolio -> with(value) {
|
||||
UserWalletItemUM(
|
||||
id = accountId.value,
|
||||
name = accountName.toUM().value,
|
||||
information = getInfo(account = this),
|
||||
balance = getBalanceInfo(),
|
||||
isEnabled = isEnabled,
|
||||
endIcon = endIcon,
|
||||
onClick = onClick,
|
||||
imageState = getImageState(account = this),
|
||||
)
|
||||
}
|
||||
is Account.Payment -> TODO("[REDACTED_JIRA]")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInfo(account: Account): UserWalletItemUM.Information.Loaded = when (account) {
|
||||
private fun getInfo(account: Account.CryptoPortfolio): UserWalletItemUM.Information.Loaded = when (account) {
|
||||
is Account.CryptoPortfolio -> {
|
||||
val text = pluralReference(
|
||||
R.plurals.common_tokens_count,
|
||||
|
|
@ -45,13 +48,15 @@ class AccountPortfolioItemUMConverter(
|
|||
)
|
||||
UserWalletItemUM.Information.Loaded(text)
|
||||
}
|
||||
is Account.Payment -> TODO("[REDACTED_JIRA]")
|
||||
}
|
||||
|
||||
private fun getImageState(account: Account) = when (account) {
|
||||
private fun getImageState(account: Account.CryptoPortfolio) = when (account) {
|
||||
is Account.CryptoPortfolio -> UserWalletItemUM.ImageState.Account(
|
||||
name = account.accountName.toUM().value,
|
||||
icon = account.icon.toUM(),
|
||||
icon = CryptoPortfolioIconConverter.convert(account.icon),
|
||||
)
|
||||
is Account.Payment -> TODO("[REDACTED_JIRA]")
|
||||
}
|
||||
|
||||
private fun getBalanceInfo(): UserWalletItemUM.Balance {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import com.tangem.core.ui.res.TangemThemePreview
|
|||
fun AccountRow(
|
||||
title: TextReference,
|
||||
subtitle: TextReference,
|
||||
icon: CryptoPortfolioIconUM,
|
||||
icon: AccountIconUM.CryptoPortfolio,
|
||||
modifier: Modifier = Modifier,
|
||||
isReverse: Boolean = false,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.common.ui.account
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -9,11 +11,16 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.account.AccountIconSize
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.SendScreenTestTags
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.utils.StringsSigns
|
||||
|
||||
/**
|
||||
* A composable function that displays an account label (icon + name) with an optional prefix.
|
||||
|
|
@ -61,4 +68,28 @@ fun AccountTitle(
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PreviewAccountTitle() {
|
||||
TangemThemePreview {
|
||||
Column {
|
||||
AccountTitle(
|
||||
accountTitleUM = AccountTitleUM.Account(
|
||||
prefixText = stringReference(StringsSigns.DOT),
|
||||
name = stringReference("Main Wallet"),
|
||||
icon = AccountIconUM.CryptoPortfolio(
|
||||
value = CryptoPortfolioIcon.Icon.Bookmark,
|
||||
color = CryptoPortfolioIcon.Color.Pattypan,
|
||||
),
|
||||
),
|
||||
modifier = Modifier.padding(4.dp),
|
||||
)
|
||||
AccountTitle(
|
||||
accountTitleUM = AccountTitleUM.Account.payment(prefixText = stringReference(StringsSigns.DOT)),
|
||||
modifier = Modifier.padding(4.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.common.ui.account
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
|
||||
/**
|
||||
* A sealed interface representing the title of an account, which can be either a simple text
|
||||
|
|
@ -19,6 +21,16 @@ sealed interface AccountTitleUM {
|
|||
data class Account(
|
||||
val prefixText: TextReference,
|
||||
val name: TextReference,
|
||||
val icon: CryptoPortfolioIconUM,
|
||||
) : AccountTitleUM
|
||||
val icon: AccountIconUM,
|
||||
) : AccountTitleUM {
|
||||
companion object {
|
||||
fun payment(prefixText: TextReference = TextReference.EMPTY): Account {
|
||||
return Account(
|
||||
prefixText = prefixText,
|
||||
name = resourceReference(R.string.tangempay_payment_account),
|
||||
icon = AccountIconUM.Payment,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.common.ui.account
|
||||
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
|
||||
object CryptoPortfolioIconConverter : TwoWayConverter<CryptoPortfolioIcon, AccountIconUM.CryptoPortfolio> {
|
||||
override fun convert(value: CryptoPortfolioIcon): AccountIconUM.CryptoPortfolio {
|
||||
return AccountIconUM.CryptoPortfolio(value = value.value, color = value.color)
|
||||
}
|
||||
|
||||
override fun convertBack(value: AccountIconUM.CryptoPortfolio): CryptoPortfolioIcon {
|
||||
return CryptoPortfolioIcon.ofCustomAccount(value = value.value, color = value.color)
|
||||
}
|
||||
}
|
||||
|
|
@ -47,7 +47,4 @@ fun CryptoPortfolioIcon.Icon.getResId(): Int {
|
|||
CryptoPortfolioIcon.Icon.Package -> R.drawable.ic_package_24
|
||||
CryptoPortfolioIcon.Icon.Gift -> R.drawable.ic_gift_24
|
||||
}
|
||||
}
|
||||
|
||||
fun CryptoPortfolioIcon.toUM() = CryptoPortfolioIconUM(domainModel = this)
|
||||
fun CryptoPortfolioIconUM.toDomain() = CryptoPortfolioIcon.ofCustomAccount(value = this.value, color = this.color)
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package com.tangem.common.ui.account
|
||||
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon.Color
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon.Icon
|
||||
|
||||
data class CryptoPortfolioIconUM(
|
||||
val value: Icon,
|
||||
val color: Color,
|
||||
) {
|
||||
constructor(domainModel: CryptoPortfolioIcon) : this(
|
||||
value = domainModel.value,
|
||||
color = domainModel.color,
|
||||
)
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ fun PortfolioSelectRow(
|
|||
|
||||
@Immutable
|
||||
data class PortfolioSelectUM(
|
||||
val icon: CryptoPortfolioIconUM?,
|
||||
val icon: AccountIconUM.CryptoPortfolio?,
|
||||
val name: TextReference,
|
||||
val isAccountMode: Boolean,
|
||||
val isMultiChoice: Boolean,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.common.ui.amountScreen.converters
|
||||
|
||||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.common.ui.account.CryptoPortfolioIconConverter
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.models.account.Account
|
||||
|
|
@ -15,7 +16,7 @@ class AmountAccountConverter(
|
|||
return if (value != null && isAccountsMode) {
|
||||
AccountTitleUM.Account(
|
||||
name = value.accountName.toUM().value,
|
||||
icon = value.icon.toUM(),
|
||||
icon = CryptoPortfolioIconConverter.convert(value.icon),
|
||||
prefixText = prefixText,
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.account.AccountNameUM
|
||||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.common.ui.account.CryptoPortfolioIconConverter
|
||||
import com.tangem.common.ui.amountScreen.models.AmountFieldModel
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
|
|
@ -88,7 +88,7 @@ object AmountStatePreviewData {
|
|||
val amountStateV2Accounts = amountState.copy(
|
||||
accountTitleUM = AccountTitleUM.Account(
|
||||
name = AccountNameUM.DefaultMain.value,
|
||||
icon = CryptoPortfolioIcon.ofDefaultCustomAccount().toUM(),
|
||||
icon = CryptoPortfolioIconConverter.convert(CryptoPortfolioIcon.ofDefaultCustomAccount()),
|
||||
prefixText = resourceReference(R.string.common_from),
|
||||
),
|
||||
availableBalanceCrypto = stringReference("2 130,81231238 USDT"),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.clickable
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -19,7 +20,6 @@ import androidx.compose.ui.unit.dp
|
|||
import com.tangem.common.ui.account.AccountTitle
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData
|
||||
import com.tangem.core.ui.components.ResizableText
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
|
|
@ -66,11 +66,14 @@ fun AmountBlock(amountState: AmountState, isClickDisabled: Boolean, isEditingDis
|
|||
state = amountState.tokenIconState,
|
||||
iconSize = 40.dp,
|
||||
)
|
||||
ResizableText(
|
||||
Text(
|
||||
text = firstAmount,
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
autoSize = TextAutoSize.StepBased(
|
||||
maxFontSize = TangemTheme.typography.h2.fontSize,
|
||||
),
|
||||
maxLines = 1,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.res.Configuration
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -18,7 +19,6 @@ import com.tangem.common.ui.account.AccountTitle
|
|||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData
|
||||
import com.tangem.core.ui.components.ResizableText
|
||||
import com.tangem.core.ui.components.SpacerWMax
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
|
|
@ -128,21 +128,23 @@ private fun AmountBlockV2(
|
|||
.padding(top = 8.dp)
|
||||
.weight(1f),
|
||||
) {
|
||||
ResizableText(
|
||||
Text(
|
||||
text = firstAmount,
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
maxLines = 1,
|
||||
autoSize = TextAutoSize.StepBased(maxFontSize = TangemTheme.typography.h2.fontSize),
|
||||
modifier = Modifier.testTag(BaseAmountBlockTestTags.PRIMARY_AMOUNT),
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
ResizableText(
|
||||
Text(
|
||||
text = secondAmount,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
autoSize = TextAutoSize.StepBased(maxFontSize = TangemTheme.typography.body2.fontSize),
|
||||
modifier = Modifier.testTag(BaseAmountBlockTestTags.SECONDARY_AMOUNT),
|
||||
)
|
||||
extraContent()
|
||||
|
|
|
|||
|
|
@ -1,15 +1,23 @@
|
|||
package com.tangem.common.ui.bottomsheet.chooseaddress
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.common.ui.bottomsheet.receive.AddressModel
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SimpleSettingsRow
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
fun ChooseAddressBottomSheet(config: TangemBottomSheetConfig) {
|
||||
|
|
@ -31,4 +39,40 @@ private fun ChooseAddressBottomSheetContent(content: ChooseAddressBottomSheetCon
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun ChooseAddressBottomSheet_Preview(
|
||||
@PreviewParameter(ChooseAddressBottomSheetPreviewProvider::class) params: ChooseAddressBottomSheetConfig,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
ChooseAddressBottomSheetContent(params)
|
||||
}
|
||||
}
|
||||
|
||||
private class ChooseAddressBottomSheetPreviewProvider : PreviewParameterProvider<ChooseAddressBottomSheetConfig> {
|
||||
override val values: Sequence<ChooseAddressBottomSheetConfig>
|
||||
get() = sequenceOf(
|
||||
ChooseAddressBottomSheetConfig(
|
||||
addressModels = persistentListOf(
|
||||
AddressModel(
|
||||
displayName = stringReference("Main address"),
|
||||
fullName = stringReference("Bitcoin"),
|
||||
value = "0x1234...abcd",
|
||||
type = AddressModel.Type.Default,
|
||||
),
|
||||
AddressModel(
|
||||
displayName = stringReference("Legacy address"),
|
||||
fullName = stringReference("Bitcoin"),
|
||||
value = "0x1234...abcd",
|
||||
type = AddressModel.Type.Default,
|
||||
),
|
||||
),
|
||||
onClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
package com.tangem.common.ui.bottomsheet.chooseaddress
|
||||
|
||||
import com.tangem.common.ui.bottomsheet.receive.AddressModel
|
||||
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -14,13 +13,12 @@ class ChooseAddressBottomSheetConfig(
|
|||
val onClick: (AddressModel) -> Unit,
|
||||
) : TangemBottomSheetConfigContent {
|
||||
constructor(
|
||||
asset: TokenReceiveBottomSheetConfig.Asset,
|
||||
network: Network,
|
||||
currency: CryptoCurrency,
|
||||
networkAddress: NetworkAddress,
|
||||
onClick: (AddressModel) -> Unit,
|
||||
) : this(
|
||||
addressModels = networkAddress.availableAddresses
|
||||
.mapToAddressModels(asset, network)
|
||||
.mapToAddressModels(cryptoCurrency = currency)
|
||||
.toImmutableList(),
|
||||
onClick = onClick,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.tangem.common.ui.bottomsheet.receive
|
||||
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.combinedReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
|
|
@ -20,20 +18,6 @@ fun Set<NetworkAddress.Address>.mapToAddressModels(cryptoCurrency: CryptoCurrenc
|
|||
cryptoCurrency.network,
|
||||
)
|
||||
|
||||
fun Set<NetworkAddress.Address>.mapToAddressModels(
|
||||
asset: TokenReceiveBottomSheetConfig.Asset,
|
||||
network: Network,
|
||||
): List<AddressModel> = when (asset) {
|
||||
is TokenReceiveBottomSheetConfig.Asset.Currency -> mapToAddressModels(
|
||||
stringReference("${asset.name} (${asset.symbol})"),
|
||||
network,
|
||||
)
|
||||
is TokenReceiveBottomSheetConfig.Asset.NFT -> mapToAddressModels(
|
||||
resourceReference(R.string.common_nft),
|
||||
network,
|
||||
)
|
||||
}
|
||||
|
||||
private fun Set<NetworkAddress.Address>.mapToAddressModels(name: TextReference, network: Network): List<AddressModel> =
|
||||
this
|
||||
.sortedBy { it.type.ordinal }
|
||||
|
|
|
|||
|
|
@ -1,330 +0,0 @@
|
|||
package com.tangem.common.ui.bottomsheet.receive
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.res.getStringSafe
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SecondaryButtonIconStart
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.components.rememberQrPainters
|
||||
import com.tangem.core.ui.components.snackbar.CopiedTextSnackbarHost
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun TokenReceiveBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet(config) { content: TokenReceiveBottomSheetConfig ->
|
||||
TokenReceiveBottomSheetContent(content = content)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenReceiveBottomSheetContent(content: TokenReceiveBottomSheetConfig) {
|
||||
var selectedAddress by remember { mutableStateOf(content.addresses.first()) }
|
||||
|
||||
val snackbarHostState = remember(::SnackbarHostState)
|
||||
|
||||
ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(top = 24.dp, bottom = 16.dp)
|
||||
.padding(horizontal = 24.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 24.dp),
|
||||
) {
|
||||
QrCodeContent(content = content, onAddressChange = { selectedAddress = it })
|
||||
|
||||
Info(
|
||||
showMemoDisclaimer = content.showMemoDisclaimer,
|
||||
notifications = content.notifications,
|
||||
)
|
||||
|
||||
Buttons(
|
||||
snackbarHostState = snackbarHostState,
|
||||
onShareClick = { content.onShareClick(selectedAddress.value) },
|
||||
onCopyClick = { content.onCopyClick(selectedAddress.value) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Info(
|
||||
showMemoDisclaimer: Boolean,
|
||||
notifications: ImmutableList<NotificationConfig>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
if (showMemoDisclaimer) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 18.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResourceSafe(R.string.receive_bottom_sheet_no_memo_required_message),
|
||||
style = TangemTheme.typography.caption1,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
|
||||
notifications.fastForEach { notificationConfig ->
|
||||
key(notificationConfig.hashCode()) {
|
||||
Notification(config = notificationConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContainerWithSnackbarHost(snackbarHostState: SnackbarHostState, content: @Composable () -> Unit) {
|
||||
Box {
|
||||
content()
|
||||
|
||||
CopiedTextSnackbarHost(
|
||||
hostState = snackbarHostState,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = 80.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun QrCodeContent(content: TokenReceiveBottomSheetConfig, onAddressChange: (AddressModel) -> Unit) {
|
||||
val qrCodes = rememberQrPainters(content.addresses.map(AddressModel::value))
|
||||
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = 0,
|
||||
initialPageOffsetFraction = 0f,
|
||||
pageCount = content.addresses::count,
|
||||
)
|
||||
|
||||
LaunchedEffect(key1 = pagerState.currentPage) {
|
||||
onAddressChange.invoke(content.addresses[pagerState.currentPage])
|
||||
}
|
||||
|
||||
HorizontalPager(state = pagerState) { currentPage ->
|
||||
QrCodePage(
|
||||
content = content,
|
||||
qrCodePainter = qrCodes[currentPage],
|
||||
currentIndex = currentPage,
|
||||
)
|
||||
}
|
||||
|
||||
if (pagerState.pageCount > 1) {
|
||||
val indicatorState = rememberLazyListState()
|
||||
val selectedColor = TangemTheme.colors.icon.primary1
|
||||
val unselectedColor = TangemTheme.colors.icon.informative
|
||||
|
||||
LazyRow(
|
||||
modifier = Modifier.height(20.dp),
|
||||
state = indicatorState,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
repeat(pagerState.pageCount) { iteration ->
|
||||
item(key = iteration) {
|
||||
val color by animateColorAsState(
|
||||
targetValue = if (pagerState.currentPage == iteration) selectedColor else unselectedColor,
|
||||
label = "",
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp, vertical = 6.dp)
|
||||
.background(color = color, shape = CircleShape)
|
||||
.size(7.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun QrCodePage(content: TokenReceiveBottomSheetConfig, qrCodePainter: Painter, currentIndex: Int) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(24.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(
|
||||
R.string.receive_bottom_sheet_warning_message_compact,
|
||||
content.addresses[currentIndex].fullName.resolveReference(),
|
||||
content.network,
|
||||
),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.h3,
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = qrCodePainter,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Fit,
|
||||
modifier = Modifier.size(248.dp),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = content.addresses[currentIndex].value,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Buttons(
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onShareClick: () -> Unit,
|
||||
onCopyClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val resources = context.resources
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
SecondaryButtonIconStart(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringResourceSafe(id = R.string.common_copy),
|
||||
iconResId = R.drawable.ic_copy_24,
|
||||
onClick = {
|
||||
onCopyClick()
|
||||
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
|
||||
coroutineScope.launch {
|
||||
snackbarHostState.showSnackbar(
|
||||
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
SecondaryButtonIconStart(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringResourceSafe(id = R.string.common_share),
|
||||
iconResId = R.drawable.ic_share_24,
|
||||
onClick = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
|
||||
onShareClick()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_TokenReceiveBottomSheet(
|
||||
@PreviewParameter(TokenReceiveBottomSheetConfigPreviewProvider::class) params: TokenReceiveBottomSheetConfig,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
val config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
content = params,
|
||||
onDismissRequest = {},
|
||||
)
|
||||
|
||||
TokenReceiveBottomSheet(config)
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenReceiveBottomSheetConfigPreviewProvider : PreviewParameterProvider<TokenReceiveBottomSheetConfig> {
|
||||
val address = AddressModel(
|
||||
displayName = stringReference("Address 1"),
|
||||
fullName = combinedReference(
|
||||
stringReference("Address 1"),
|
||||
stringReference(" Stellar"),
|
||||
),
|
||||
value = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
|
||||
type = AddressModel.Type.Default,
|
||||
)
|
||||
private val baseConfig = TokenReceiveBottomSheetConfig(
|
||||
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
|
||||
name = "Stellar",
|
||||
symbol = "XLM",
|
||||
),
|
||||
network = "Ethereum",
|
||||
notifications = persistentListOf(
|
||||
NotificationConfig(
|
||||
title = stringReference("Send only XLM on the Ethereum network"),
|
||||
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
),
|
||||
),
|
||||
addresses = persistentListOf(address),
|
||||
showMemoDisclaimer = false,
|
||||
onCopyClick = {},
|
||||
onShareClick = {},
|
||||
)
|
||||
|
||||
override val values: Sequence<TokenReceiveBottomSheetConfig>
|
||||
get() = sequenceOf(
|
||||
baseConfig,
|
||||
baseConfig.copy(
|
||||
addresses = persistentListOf(
|
||||
address,
|
||||
address.copy(displayName = stringReference("Address 2")),
|
||||
),
|
||||
),
|
||||
baseConfig.copy(
|
||||
showMemoDisclaimer = true,
|
||||
),
|
||||
baseConfig.copy(
|
||||
showMemoDisclaimer = true,
|
||||
addresses = persistentListOf(
|
||||
address,
|
||||
address.copy(displayName = stringReference("Address 2")),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
package com.tangem.common.ui.bottomsheet.receive
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
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.domain.models.network.Network
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
data class TokenReceiveBottomSheetConfig(
|
||||
val asset: Asset,
|
||||
val network: String,
|
||||
val addresses: ImmutableList<AddressModel>,
|
||||
val showMemoDisclaimer: Boolean,
|
||||
val notifications: ImmutableList<NotificationConfig>,
|
||||
val onCopyClick: (String) -> Unit,
|
||||
val onShareClick: (String) -> Unit,
|
||||
) : TangemBottomSheetConfigContent {
|
||||
|
||||
constructor(
|
||||
asset: Asset,
|
||||
network: Network,
|
||||
networkAddress: NetworkAddress,
|
||||
showMemoDisclaimer: Boolean,
|
||||
customNotifications: ImmutableList<NotificationConfig> = persistentListOf(),
|
||||
onCopyClick: (String) -> Unit,
|
||||
onShareClick: (String) -> Unit,
|
||||
) : this(
|
||||
asset = asset,
|
||||
network = network.name,
|
||||
addresses = networkAddress.availableAddresses
|
||||
.mapToAddressModels(asset, network)
|
||||
.toImmutableList(),
|
||||
showMemoDisclaimer = showMemoDisclaimer,
|
||||
notifications = persistentListOf(defaultAssetNotificationConfig(asset, network)).addAll(0, customNotifications),
|
||||
onCopyClick = onCopyClick,
|
||||
onShareClick = onShareClick,
|
||||
)
|
||||
|
||||
companion object {
|
||||
private fun defaultAssetNotificationConfig(asset: Asset, network: Network): NotificationConfig =
|
||||
NotificationConfig(
|
||||
title = resourceReference(
|
||||
R.string.receive_bottom_sheet_warning_title,
|
||||
wrappedList(asset.displaySymbol, network.name),
|
||||
),
|
||||
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
iconTint = NotificationConfig.IconTint.Accent,
|
||||
)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
sealed class Asset {
|
||||
abstract val displaySymbol: TextReference
|
||||
|
||||
data class Currency(val name: String, val symbol: String) : Asset() {
|
||||
override val displaySymbol = stringReference(symbol)
|
||||
}
|
||||
|
||||
data object NFT : Asset() {
|
||||
override val displaySymbol = resourceReference(R.string.common_nft)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.common.ui.expressStatus.state
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.tangem.common.ui.tokendetails.TokenDetailsDialogConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
|
||||
data class ExpressTransactionsBlockState(
|
||||
val transactions: PersistentList<ExpressTransactionStateUM>,
|
||||
val bottomSheetSlot: BottomSheetSlot?,
|
||||
val dialogSlot: DialogSlot?,
|
||||
)
|
||||
|
||||
data class BottomSheetSlot(
|
||||
val config: TangemBottomSheetConfig,
|
||||
val content: @Composable () -> Unit,
|
||||
)
|
||||
|
||||
data class DialogSlot(
|
||||
val config: TokenDetailsDialogConfig,
|
||||
val content: @Composable () -> Unit,
|
||||
)
|
||||
|
|
@ -24,6 +24,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.common.ui.navigationButtons.preview.NavigationButtonsPreview
|
||||
import com.tangem.core.ui.components.HoldToConfirmButton
|
||||
import com.tangem.core.ui.components.Keyboard
|
||||
import com.tangem.core.ui.components.SecondaryButtonIconStart
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButton
|
||||
|
|
@ -98,34 +99,48 @@ fun NavigationPrimaryButton(primaryButton: NavigationButton?, modifier: Modifier
|
|||
modifier = modifier.fillMaxWidth(),
|
||||
) { button ->
|
||||
if (button != null && button.textReference != TextReference.EMPTY) {
|
||||
val icon = if (button.iconRes != null && button.isIconVisible) {
|
||||
TangemButtonIconPosition.End(iconResId = button.iconRes)
|
||||
} else {
|
||||
TangemButtonIconPosition.None
|
||||
}
|
||||
val color = if (button.isDimmed) {
|
||||
TangemButtonsDefaults.secondaryButtonColors
|
||||
.copy(contentColor = TangemTheme.colors.text.tertiary)
|
||||
} else {
|
||||
TangemButtonsDefaults.primaryButtonColors
|
||||
}
|
||||
TangemButton(
|
||||
text = button.textReference.resolveReference(),
|
||||
enabled = button.isEnabled,
|
||||
onClick = {
|
||||
GlobalMultipleClickPreventer.processEvent {
|
||||
if (button.isHapticClick) {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
if (button.isHoldToConfirm) {
|
||||
HoldToConfirmButton(
|
||||
text = button.textReference.resolveReference(),
|
||||
enabled = button.isEnabled,
|
||||
isLoading = button.shouldShowProgress,
|
||||
onConfirm = {
|
||||
GlobalMultipleClickPreventer.processEvent {
|
||||
button.onClick()
|
||||
}
|
||||
button.onClick()
|
||||
}
|
||||
},
|
||||
showProgress = button.shouldShowProgress,
|
||||
colors = color,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
icon = icon,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
} else {
|
||||
val icon = if (button.iconRes != null && button.isIconVisible) {
|
||||
TangemButtonIconPosition.End(iconResId = button.iconRes)
|
||||
} else {
|
||||
TangemButtonIconPosition.None
|
||||
}
|
||||
val color = if (button.isDimmed) {
|
||||
TangemButtonsDefaults.secondaryButtonColors
|
||||
.copy(contentColor = TangemTheme.colors.text.tertiary)
|
||||
} else {
|
||||
TangemButtonsDefaults.primaryButtonColors
|
||||
}
|
||||
TangemButton(
|
||||
text = button.textReference.resolveReference(),
|
||||
enabled = button.isEnabled,
|
||||
onClick = {
|
||||
GlobalMultipleClickPreventer.processEvent {
|
||||
if (button.isHapticClick) {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
}
|
||||
button.onClick()
|
||||
}
|
||||
},
|
||||
showProgress = button.shouldShowProgress,
|
||||
colors = color,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
icon = icon,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Spacer(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,5 +34,6 @@ data class NavigationButton(
|
|||
val isEnabled: Boolean = true,
|
||||
val isDimmed: Boolean = false,
|
||||
val isHapticClick: Boolean = false,
|
||||
val isHoldToConfirm: Boolean = false,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
|
|
@ -1,22 +1,24 @@
|
|||
package com.tangem.common.ui.news
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.CardColors
|
||||
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
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerHMax
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.block.TangemBlockCardColors
|
||||
import com.tangem.core.ui.components.label.Label
|
||||
|
|
@ -39,23 +41,36 @@ fun ArticleCard(
|
|||
modifier: Modifier = Modifier,
|
||||
colors: CardColors = TangemBlockCardColors,
|
||||
) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
onClick = onArticleClick,
|
||||
colors = colors,
|
||||
) {
|
||||
if (articleConfigUM.isTrending) {
|
||||
TrendingArticle(articleConfigUM = articleConfigUM)
|
||||
} else {
|
||||
DefaultArticle(articleConfigUM = articleConfigUM)
|
||||
}
|
||||
if (articleConfigUM.isTrending) {
|
||||
TrendingArticle(
|
||||
articleConfigUM = articleConfigUM,
|
||||
modifier = modifier,
|
||||
onArticleClick = onArticleClick,
|
||||
colors = colors,
|
||||
)
|
||||
} else {
|
||||
DefaultArticle(
|
||||
articleConfigUM = articleConfigUM,
|
||||
modifier = modifier,
|
||||
onArticleClick = onArticleClick,
|
||||
colors = colors,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrendingArticle(articleConfigUM: ArticleConfigUM) {
|
||||
private fun TrendingArticle(
|
||||
articleConfigUM: ArticleConfigUM,
|
||||
onArticleClick: () -> Unit,
|
||||
colors: CardColors,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 24.dp, horizontal = 16.dp),
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(colors.containerColor)
|
||||
.clickable { onArticleClick() }
|
||||
.padding(vertical = 24.dp, horizontal = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
|
|
@ -80,8 +95,7 @@ private fun TrendingArticle(articleConfigUM: ArticleConfigUM) {
|
|||
TangemTheme.colors.text.primary1
|
||||
},
|
||||
style = TangemTheme.typography.h3,
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
SpacerH(8.dp)
|
||||
|
|
@ -101,8 +115,54 @@ private fun TrendingArticle(articleConfigUM: ArticleConfigUM) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun DefaultArticle(articleConfigUM: ArticleConfigUM) {
|
||||
Column(modifier = Modifier.padding(12.dp)) {
|
||||
fun ShowMoreArticlesCard(modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(vertical = 31.dp, horizontal = 12.dp),
|
||||
) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_show_more_news_48),
|
||||
contentDescription = stringResourceSafe(R.string.common_show_more),
|
||||
)
|
||||
|
||||
SpacerH(16.dp)
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.news_all_news),
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.news_stay_in_the_loop),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DefaultArticle(
|
||||
articleConfigUM: ArticleConfigUM,
|
||||
onArticleClick: () -> Unit,
|
||||
colors: CardColors,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(colors.containerColor)
|
||||
.clickable { onArticleClick() }
|
||||
.padding(12.dp),
|
||||
) {
|
||||
ArticleInfo(
|
||||
score = articleConfigUM.score,
|
||||
createdAt = articleConfigUM.createdAt.resolveReference(),
|
||||
|
|
@ -122,33 +182,46 @@ private fun DefaultArticle(articleConfigUM: ArticleConfigUM) {
|
|||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
SpacerH(16.dp)
|
||||
SpacerHMax(modifier = Modifier.padding(bottom = 16.dp))
|
||||
|
||||
Tags(tags = articleConfigUM.tags.toImmutableList())
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun Tags(tags: ImmutableList<LabelUM>, modifier: Modifier = Modifier) {
|
||||
val expandIndicator = remember {
|
||||
ContextualFlowRowOverflow.expandIndicator {
|
||||
val remainingItems = tags.size - shownItemCount
|
||||
Label(state = LabelUM(TextReference.Str("${StringsSigns.PLUS}$remainingItems")))
|
||||
}
|
||||
}
|
||||
ContextualFlowRow(
|
||||
itemCount = tags.size,
|
||||
FlowRow(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
maxItemsInEachRow = MAX_TAGS_COUNT_TO_SHOW + 1,
|
||||
maxLines = 1,
|
||||
overflow = expandIndicator,
|
||||
) { index ->
|
||||
Label(state = tags[index])
|
||||
itemVerticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
val displayedTags = if (tags.size > MAX_TAGS_COUNT_TO_SHOW) {
|
||||
tags.take(MAX_TAGS_COUNT_TO_SHOW)
|
||||
} else {
|
||||
tags
|
||||
}
|
||||
|
||||
displayedTags.forEach { tag ->
|
||||
Label(state = tag)
|
||||
}
|
||||
|
||||
if (tags.size > MAX_TAGS_COUNT_TO_SHOW) {
|
||||
val remainingItems = tags.size - MAX_TAGS_COUNT_TO_SHOW
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = TextReference.Str("${StringsSigns.PLUS}$remainingItems"),
|
||||
maxLines = 1,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val MAX_TAGS_COUNT_TO_SHOW = 3
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package com.tangem.common.ui.news
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -9,6 +12,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -49,6 +53,8 @@ internal fun ArticleInfo(score: Float, createdAt: String, modifier: Modifier = M
|
|||
Text(
|
||||
text = createdAt,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ fun TrendingLoadingArticle(modifier: Modifier = Modifier) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun DefaultLoadingArticle() {
|
||||
fun DefaultLoadingArticle(modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(12.dp)) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import com.tangem.utils.extensions.isZero
|
|||
import com.tangem.utils.extensions.orZero
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Suppress("LargeClass")
|
||||
@Suppress("LargeClass", "CanBeNonNullable")
|
||||
object NotificationsFactory {
|
||||
|
||||
fun MutableList<NotificationUM>.addFeeUnreachableNotification(
|
||||
|
|
@ -314,12 +314,14 @@ object NotificationsFactory {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
fun MutableList<NotificationUM>.addExceedsBalanceNotification(
|
||||
cryptoCurrencyWarning: CryptoCurrencyWarning?,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
shouldMergeFeeNetworkName: Boolean,
|
||||
onClick: (CryptoCurrency) -> Unit,
|
||||
onAnalyticsEvent: (CryptoCurrency) -> Unit,
|
||||
onResetAnalyticsEvent: (CryptoCurrency) -> Unit,
|
||||
) {
|
||||
when (cryptoCurrencyWarning) {
|
||||
is CryptoCurrencyWarning.BalanceNotEnoughForFee -> {
|
||||
|
|
@ -357,7 +359,7 @@ object NotificationsFactory {
|
|||
)
|
||||
onAnalyticsEvent(cryptoCurrencyWarning.currency)
|
||||
}
|
||||
else -> Unit
|
||||
else -> onResetAnalyticsEvent(cryptoCurrencyStatus.currency)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
package com.tangem.common.ui.tokendetails
|
||||
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
|
||||
/**
|
||||
* Wallet bottom sheet config
|
||||
*
|
||||
* @property isShow flag that determine if bottom sheet is shown
|
||||
* @property onDismissRequest lambda be invoked when bottom sheet is dismissed
|
||||
* @property content content config
|
||||
*/
|
||||
data class TokenDetailsDialogConfig(
|
||||
val isShow: Boolean,
|
||||
val onDismissRequest: () -> Unit,
|
||||
val content: DialogContentConfig,
|
||||
) {
|
||||
|
||||
sealed class DialogContentConfig {
|
||||
|
||||
abstract val title: TextReference?
|
||||
abstract val message: TextReference
|
||||
abstract val confirmButtonConfig: ButtonConfig
|
||||
abstract val cancelButtonConfig: ButtonConfig?
|
||||
|
||||
data class ButtonConfig(
|
||||
val text: TextReference,
|
||||
val onClick: () -> Unit,
|
||||
val hasWarning: Boolean = false,
|
||||
)
|
||||
|
||||
data class ConfirmHideConfig(
|
||||
val currencyTitle: String,
|
||||
val onConfirmClick: () -> Unit,
|
||||
val onCancelClick: () -> Unit,
|
||||
) : DialogContentConfig() {
|
||||
override val title: TextReference = TextReference.Res(
|
||||
id = R.string.token_details_hide_alert_title,
|
||||
formatArgs = wrappedList(currencyTitle),
|
||||
)
|
||||
|
||||
override val message: TextReference = TextReference.Res(R.string.token_details_hide_alert_message)
|
||||
|
||||
override val cancelButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = TextReference.Res(R.string.common_cancel),
|
||||
onClick = onCancelClick,
|
||||
)
|
||||
|
||||
override val confirmButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = TextReference.Res(R.string.token_details_hide_alert_hide),
|
||||
onClick = onConfirmClick,
|
||||
hasWarning = true,
|
||||
)
|
||||
}
|
||||
|
||||
data class HasLinkedTokensConfig(
|
||||
val currencyName: String,
|
||||
val currencySymbol: String,
|
||||
val networkName: String,
|
||||
val onConfirmClick: () -> Unit,
|
||||
) : DialogContentConfig() {
|
||||
override val title: TextReference = TextReference.Res(
|
||||
id = R.string.token_details_unable_hide_alert_title,
|
||||
formatArgs = wrappedList(currencySymbol),
|
||||
)
|
||||
|
||||
override val message: TextReference = TextReference.Res(
|
||||
id = R.string.token_details_unable_hide_alert_message,
|
||||
formatArgs = wrappedList(currencyName, currencySymbol, networkName),
|
||||
)
|
||||
|
||||
override val cancelButtonConfig: ButtonConfig?
|
||||
get() = null
|
||||
|
||||
override val confirmButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = TextReference.Res(R.string.common_ok),
|
||||
onClick = onConfirmClick,
|
||||
)
|
||||
}
|
||||
|
||||
data class DisabledButtonReasonDialogConfig(
|
||||
val text: TextReference,
|
||||
val onConfirmClick: () -> Unit,
|
||||
) : DialogContentConfig() {
|
||||
|
||||
override val title = null
|
||||
|
||||
override val message: TextReference = text
|
||||
|
||||
override val cancelButtonConfig = null
|
||||
|
||||
override val confirmButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = TextReference.Res(R.string.common_ok),
|
||||
onClick = onConfirmClick,
|
||||
)
|
||||
}
|
||||
|
||||
data class RemoveIncompleteTransactionConfirmDialogConfig(
|
||||
val onConfirmClick: () -> Unit,
|
||||
val onCancelClick: () -> Unit,
|
||||
) : DialogContentConfig() {
|
||||
override val title = null
|
||||
|
||||
override val message: TextReference = TextReference.Res(
|
||||
id = R.string.warning_kaspa_unfinished_token_transaction_discard_message,
|
||||
)
|
||||
|
||||
override val cancelButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = TextReference.Res(R.string.common_cancel),
|
||||
onClick = onCancelClick,
|
||||
)
|
||||
|
||||
override val confirmButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = TextReference.Res(R.string.common_yes),
|
||||
onClick = onConfirmClick,
|
||||
)
|
||||
}
|
||||
|
||||
data class ErrorDialogConfig(
|
||||
val text: TextReference,
|
||||
val onConfirmClick: () -> Unit,
|
||||
) : DialogContentConfig() {
|
||||
|
||||
override val title = null
|
||||
|
||||
override val message: TextReference = text
|
||||
|
||||
override val cancelButtonConfig = null
|
||||
|
||||
override val confirmButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = TextReference.Res(R.string.common_ok),
|
||||
onClick = onConfirmClick,
|
||||
)
|
||||
}
|
||||
|
||||
data class ConfirmExpressStatusHideDialogConfig(
|
||||
val onConfirmClick: () -> Unit,
|
||||
val onCancelClick: () -> Unit,
|
||||
) : DialogContentConfig() {
|
||||
override val title: TextReference = resourceReference(R.string.express_status_hide_dialog_title)
|
||||
override val message: TextReference = resourceReference(R.string.express_status_hide_dialog_text)
|
||||
override val confirmButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = resourceReference(R.string.common_hide),
|
||||
onClick = onConfirmClick,
|
||||
)
|
||||
|
||||
override val cancelButtonConfig: ButtonConfig = ButtonConfig(
|
||||
text = resourceReference(R.string.common_cancel),
|
||||
onClick = onCancelClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,8 @@ import com.tangem.domain.models.currency.yieldSupplyKey
|
|||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.staking.model.StakingOption
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.common.RewardInfo
|
||||
import com.tangem.domain.staking.model.common.RewardType
|
||||
import com.tangem.domain.staking.utils.getTotalWithRewardsStakingBalance
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
|
|
@ -45,7 +46,7 @@ class TokenItemStateConverter(
|
|||
private val appCurrency: AppCurrency,
|
||||
private val yieldModuleApyMap: Map<String, BigDecimal> = emptyMap(),
|
||||
private val stakingApyMap: Map<CryptoCurrency, StakingAvailability> = emptyMap(),
|
||||
private val yieldSupplyPromoBannerKey: String? = null,
|
||||
private val promoCryptoCurrencyStatus: CryptoCurrencyStatus? = null,
|
||||
private val iconStateProvider: (CryptoCurrencyStatus) -> CurrencyIconState = {
|
||||
CryptoCurrencyToIconStateConverter().convert(it)
|
||||
},
|
||||
|
|
@ -74,7 +75,7 @@ class TokenItemStateConverter(
|
|||
createPromoBannerState(
|
||||
status = status,
|
||||
yieldModuleApyMap = yieldModuleApyMap,
|
||||
yieldSupplyPromoBannerKey = yieldSupplyPromoBannerKey,
|
||||
promoCryptoCurrencyStatus = promoCryptoCurrencyStatus,
|
||||
onApyLabelClick = onApyLabelClick,
|
||||
onYieldPromoCloseClick = onYieldPromoCloseClick,
|
||||
onYieldPromoShown = onYieldPromoShown,
|
||||
|
|
@ -251,9 +252,9 @@ class TokenItemStateConverter(
|
|||
stakingApyMap = stakingApyMap,
|
||||
)
|
||||
val rewardTypeRes = when (stakingInfo.rewardType) {
|
||||
Yield.RewardType.APR -> R.string.staking_apr_earn_badge
|
||||
Yield.RewardType.UNKNOWN,
|
||||
Yield.RewardType.APY,
|
||||
RewardType.APR -> R.string.staking_apr_earn_badge
|
||||
RewardType.UNKNOWN,
|
||||
RewardType.APY,
|
||||
null,
|
||||
-> R.string.yield_module_earn_badge
|
||||
}
|
||||
|
|
@ -283,12 +284,14 @@ class TokenItemStateConverter(
|
|||
|
||||
val stakingBalance = currencyStatus.value.stakingBalance as? StakingBalance.Data
|
||||
val stakeKitBalance = stakingBalance as? StakingBalance.Data.StakeKit
|
||||
val p2pEthPoolBalance = stakingBalance as? StakingBalance.Data.P2PEthPool
|
||||
|
||||
val rateInfo = when (val stakingOptions = stakingAvailability.option) {
|
||||
is StakingOption.P2P -> {
|
||||
// P2P or no balance: use preferred validators
|
||||
// TODO add p2p logic
|
||||
null
|
||||
is StakingOption.P2PEthPool -> {
|
||||
RewardInfo(
|
||||
rate = stakingOptions.apy,
|
||||
type = RewardType.APY,
|
||||
)
|
||||
}
|
||||
is StakingOption.StakeKit -> if (stakeKitBalance != null) {
|
||||
val validatorsByAddress = stakingOptions.yield.validators.associateBy { it.address }
|
||||
|
|
@ -314,7 +317,7 @@ class TokenItemStateConverter(
|
|||
|
||||
return StakingLocalInfo(
|
||||
rate = rateInfo?.rate,
|
||||
isActive = stakeKitBalance != null, // todo add p2p check
|
||||
isActive = stakeKitBalance != null || p2pEthPoolBalance != null,
|
||||
rewardType = rateInfo?.type,
|
||||
)
|
||||
}
|
||||
|
|
@ -401,7 +404,7 @@ class TokenItemStateConverter(
|
|||
private fun createPromoBannerState(
|
||||
status: CryptoCurrencyStatus,
|
||||
yieldModuleApyMap: Map<String, BigDecimal>,
|
||||
yieldSupplyPromoBannerKey: String?,
|
||||
promoCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
onApyLabelClick: ((CryptoCurrencyStatus, ApySource, String) -> Unit)?,
|
||||
onYieldPromoCloseClick: (() -> Unit)?,
|
||||
onYieldPromoShown: ((cryptoCurrency: CryptoCurrency) -> Unit)?,
|
||||
|
|
@ -411,13 +414,15 @@ class TokenItemStateConverter(
|
|||
if (status.value !is CryptoCurrencyStatus.Loaded) {
|
||||
return TokenItemState.PromoBannerState.Empty
|
||||
}
|
||||
if (yieldSupplyPromoBannerKey == null || yieldSupplyPromoBannerKey != token.yieldSupplyKey() ||
|
||||
yieldModuleApyMap[token.yieldSupplyKey()] == null
|
||||
) {
|
||||
if (promoCryptoCurrencyStatus == null || status.currency.id != promoCryptoCurrencyStatus.currency.id) {
|
||||
return TokenItemState.PromoBannerState.Empty
|
||||
}
|
||||
val yieldSupplyApy =
|
||||
yieldModuleApyMap[token.yieldSupplyKey()] ?: return TokenItemState.PromoBannerState.Empty
|
||||
val yieldSupplyApy = yieldModuleApyMap.entries.firstOrNull { (key, _) ->
|
||||
key.equals(
|
||||
other = token.yieldSupplyKey(),
|
||||
ignoreCase = BlockchainUtils.isCaseInsensitiveContractAddress(token.network.rawId),
|
||||
)
|
||||
}?.value ?: return TokenItemState.PromoBannerState.Empty
|
||||
|
||||
return TokenItemState.PromoBannerState.Content(
|
||||
title = resourceReference(
|
||||
|
|
@ -469,7 +474,7 @@ class TokenItemStateConverter(
|
|||
private data class StakingLocalInfo(
|
||||
val rate: BigDecimal?,
|
||||
val isActive: Boolean,
|
||||
val rewardType: Yield.RewardType?,
|
||||
val rewardType: RewardType?,
|
||||
)
|
||||
|
||||
private data class EarnApyInfo(
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class UserWalletItemUMConverter(
|
|||
private val isClickableIfLocked: Boolean = false,
|
||||
private val endIcon: UserWalletItemUM.EndIcon = UserWalletItemUM.EndIcon.None,
|
||||
artwork: UserWalletItemUM.ImageState? = null,
|
||||
private val mode: InfoField = InfoField.Devices,
|
||||
) : Converter<UserWallet, UserWalletItemUM> {
|
||||
|
||||
private val artwork = artwork ?: UserWalletItemUM.ImageState.Loading
|
||||
|
|
@ -61,17 +62,29 @@ class UserWalletItemUMConverter(
|
|||
private fun getInfo(userWallet: UserWallet): UserWalletItemUM.Information.Loaded {
|
||||
val text = when (userWallet) {
|
||||
is UserWallet.Cold -> {
|
||||
val cardCount = userWallet.getCardsCount() ?: 1
|
||||
TextReference.PluralRes(
|
||||
id = R.plurals.card_label_card_count,
|
||||
count = cardCount,
|
||||
formatArgs = wrappedList(cardCount),
|
||||
)
|
||||
when (mode) {
|
||||
is InfoField.Devices -> {
|
||||
val cardCount = userWallet.getCardsCount() ?: 1
|
||||
TextReference.PluralRes(
|
||||
id = R.plurals.card_label_card_count,
|
||||
count = cardCount,
|
||||
formatArgs = wrappedList(cardCount),
|
||||
)
|
||||
}
|
||||
is InfoField.Tokens -> {
|
||||
TextReference.PluralRes(
|
||||
id = R.plurals.common_tokens_count,
|
||||
count = mode.tokensCount,
|
||||
formatArgs = wrappedList(mode.tokensCount),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is UserWallet.Hot -> {
|
||||
TextReference.Res(R.string.hw_mobile_wallet)
|
||||
}
|
||||
}
|
||||
|
||||
return UserWalletItemUM.Information.Loaded(text)
|
||||
}
|
||||
|
||||
|
|
@ -103,4 +116,9 @@ class UserWalletItemUMConverter(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface InfoField {
|
||||
data object Devices : InfoField
|
||||
data class Tokens(val tokensCount: Int) : InfoField
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.common.ui.userwallet.state
|
||||
|
||||
import com.tangem.common.ui.account.CryptoPortfolioIconUM
|
||||
import com.tangem.common.ui.account.AccountIconUM
|
||||
import com.tangem.core.ui.components.artwork.ArtworkUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import javax.annotation.concurrent.Immutable
|
||||
|
|
@ -64,7 +64,7 @@ data class UserWalletItemUM(
|
|||
|
||||
data class Account(
|
||||
val name: TextReference,
|
||||
val icon: CryptoPortfolioIconUM,
|
||||
val icon: AccountIconUM.CryptoPortfolio,
|
||||
) : ImageState()
|
||||
|
||||
data class Image(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue