Updated on 2026-08-14
This commit is contained in:
parent
a6cff6210b
commit
4c3312186d
6 changed files with 413 additions and 144 deletions
|
|
@ -0,0 +1,337 @@
|
|||
package com.tangem.tap.features.wallet.ui.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.AbstractComposeView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.SelectorButton
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH4
|
||||
import com.tangem.core.ui.components.SpacerW16
|
||||
import com.tangem.core.ui.components.SpacerW4
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.extensions.formatWithSpaces
|
||||
import com.tangem.tap.features.wallet.models.TotalBalance
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.wallet.R
|
||||
import com.valentinilk.shimmer.shimmer
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
|
||||
internal class TotalBalanceCard @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : AbstractComposeView(context, attrs, defStyleAttr) {
|
||||
private var state by mutableStateOf<TotalBalanceCardState>(TotalBalanceCardState.Empty)
|
||||
|
||||
var status: TotalBalance? = null
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
field = value
|
||||
updateState(value, onChangeFiatCurrencyClick)
|
||||
}
|
||||
|
||||
var onChangeFiatCurrencyClick: () -> Unit = { /* no-op */ }
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
field = value
|
||||
updateState(status, value)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
TangemTheme {
|
||||
TotalBalanceCardContent(state = state)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAccessibilityClassName(): CharSequence {
|
||||
return javaClass.name
|
||||
}
|
||||
|
||||
private fun updateState(status: TotalBalance?, onChangeCurrencyClick: () -> Unit) {
|
||||
state = when (status?.state) {
|
||||
null -> TotalBalanceCardState.Empty
|
||||
ProgressState.Loading -> TotalBalanceCardState.Loading(
|
||||
fiatCurrency = status.fiatCurrency,
|
||||
onChangeFiatCurrencyClick = onChangeCurrencyClick,
|
||||
)
|
||||
ProgressState.Error -> TotalBalanceCardState.Failure(
|
||||
amount = status.fiatAmount,
|
||||
fiatCurrency = status.fiatCurrency,
|
||||
onChangeFiatCurrencyClick = onChangeCurrencyClick,
|
||||
)
|
||||
ProgressState.Refreshing,
|
||||
ProgressState.Done,
|
||||
-> TotalBalanceCardState.Success(
|
||||
amount = status.fiatAmount,
|
||||
fiatCurrency = status.fiatCurrency,
|
||||
onChangeFiatCurrencyClick = onChangeCurrencyClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TotalBalanceCardContent(
|
||||
state: TotalBalanceCardState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TotalBalanceCardScaffold(
|
||||
modifier = modifier,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.main_page_balance),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
},
|
||||
amount = {
|
||||
when (state) {
|
||||
is TotalBalanceCardState.Empty,
|
||||
is TotalBalanceCardState.Loading,
|
||||
-> LoadingAmount()
|
||||
is TotalBalanceCardState.Failure,
|
||||
is TotalBalanceCardState.Success,
|
||||
-> LoadedAmount(
|
||||
amount = buildAmountString(
|
||||
amount = state.amount,
|
||||
fiatCurrencySymbol = state.fiatCurrency.symbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
currencySelector = {
|
||||
if (state !is TotalBalanceCardState.Empty) {
|
||||
SelectorButton(
|
||||
text = state.fiatCurrency.code,
|
||||
onClick = state.onChangeFiatCurrencyClick,
|
||||
)
|
||||
}
|
||||
},
|
||||
failureText = {
|
||||
AnimatedVisibility(visible = state is TotalBalanceCardState.Failure) {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(id = R.string.main_processing_full_amount),
|
||||
style = TangemTheme.typography.caption,
|
||||
color = TangemTheme.colors.text.attention,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TotalBalanceCardScaffold(
|
||||
title: @Composable () -> Unit,
|
||||
amount: @Composable () -> Unit,
|
||||
currencySelector: @Composable () -> Unit,
|
||||
failureText: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
amountWeight: Float = 0.8f,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
shape = TangemTheme.shapes.roundedCornersMedium,
|
||||
color = TangemTheme.colors.background.plain,
|
||||
elevation = TangemTheme.dimens.elevation1,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
SpacerW16()
|
||||
Column(
|
||||
modifier = Modifier.weight(amountWeight),
|
||||
) {
|
||||
SpacerH12()
|
||||
title()
|
||||
SpacerH4()
|
||||
amount()
|
||||
}
|
||||
currencySelector()
|
||||
SpacerW4()
|
||||
}
|
||||
SpacerH4()
|
||||
Box(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
) {
|
||||
failureText()
|
||||
}
|
||||
SpacerH12()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadingAmount(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier.shimmer()) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(TangemTheme.dimens.size116)
|
||||
.height(TangemTheme.dimens.size32)
|
||||
.background(
|
||||
color = TangemTheme.colors.stroke.primary,
|
||||
shape = TangemTheme.shapes.roundedCornersSmall2,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadedAmount(
|
||||
amount: AnnotatedString,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
Text(
|
||||
text = amount,
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun buildAmountString(
|
||||
amount: BigDecimal,
|
||||
fiatCurrencySymbol: String,
|
||||
): AnnotatedString {
|
||||
val format = DecimalFormat.getInstance(Locale.getDefault()) as DecimalFormat
|
||||
val scaledAmount = amount
|
||||
.setScale(2, RoundingMode.HALF_UP)
|
||||
.formatWithSpaces()
|
||||
val integer = scaledAmount.substringBefore('.')
|
||||
val reminder = scaledAmount.substringAfter('.')
|
||||
|
||||
return buildAnnotatedString {
|
||||
append(integer)
|
||||
append(format.decimalFormatSymbols.decimalSeparator)
|
||||
append(
|
||||
AnnotatedString(
|
||||
text = "$reminder $fiatCurrencySymbol",
|
||||
spanStyle = TangemTheme.typography.h3.toSpanStyle(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private sealed interface TotalBalanceCardState {
|
||||
val amount: BigDecimal
|
||||
val onChangeFiatCurrencyClick: () -> Unit
|
||||
val fiatCurrency: FiatCurrency
|
||||
|
||||
object Empty : TotalBalanceCardState {
|
||||
override val amount: BigDecimal = BigDecimal.ZERO
|
||||
override val fiatCurrency: FiatCurrency = FiatCurrency.Default
|
||||
override val onChangeFiatCurrencyClick: () -> Unit = { /* no-op */ }
|
||||
}
|
||||
|
||||
data class Loading(
|
||||
override val fiatCurrency: FiatCurrency,
|
||||
override val onChangeFiatCurrencyClick: () -> Unit,
|
||||
) : TotalBalanceCardState {
|
||||
override val amount: BigDecimal = BigDecimal.ZERO
|
||||
}
|
||||
|
||||
data class Failure(
|
||||
override val amount: BigDecimal,
|
||||
override val fiatCurrency: FiatCurrency,
|
||||
override val onChangeFiatCurrencyClick: () -> Unit,
|
||||
) : TotalBalanceCardState
|
||||
|
||||
data class Success(
|
||||
override val amount: BigDecimal,
|
||||
override val fiatCurrency: FiatCurrency,
|
||||
override val onChangeFiatCurrencyClick: () -> Unit,
|
||||
) : TotalBalanceCardState
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
private fun TotalBalanceCardContentSample(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.padding(all = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
TotalBalanceCardContent(state = TotalBalanceCardState.Empty)
|
||||
Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8))
|
||||
TotalBalanceCardContent(
|
||||
state = TotalBalanceCardState.Loading(FiatCurrency("USD", "USD", "$")) {},
|
||||
)
|
||||
Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8))
|
||||
TotalBalanceCardContent(
|
||||
state = TotalBalanceCardState.Failure(
|
||||
amount = BigDecimal("9917.72"),
|
||||
onChangeFiatCurrencyClick = {},
|
||||
fiatCurrency = FiatCurrency("USD", "USD", "$"),
|
||||
),
|
||||
)
|
||||
Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8))
|
||||
TotalBalanceCardContent(
|
||||
state = TotalBalanceCardState.Success(
|
||||
amount = BigDecimal("9917.72"),
|
||||
onChangeFiatCurrencyClick = {},
|
||||
fiatCurrency = FiatCurrency("USD", "USD", "$"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun TotalBalanceCardContentPreview_Light() {
|
||||
TangemTheme {
|
||||
TotalBalanceCardContentSample()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun TotalBalanceCardContentPreview_Dark() {
|
||||
TangemTheme(isDark = true) {
|
||||
TotalBalanceCardContentSample()
|
||||
}
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -3,7 +3,6 @@ package com.tangem.tap.features.wallet.ui.wallet
|
|||
import android.widget.Button
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.badoo.mvicore.DiffStrategy
|
||||
import com.badoo.mvicore.modelWatcher
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
|
|
@ -11,8 +10,6 @@ import com.tangem.domain.common.TapWorkarounds.isTestCard
|
|||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
import com.tangem.tap.common.analytics.events.ManageTokens
|
||||
import com.tangem.tap.common.analytics.events.Portfolio
|
||||
import com.tangem.tap.common.extensions.animateVisibility
|
||||
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
|
||||
import com.tangem.tap.common.extensions.getQuantityString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
|
|
@ -21,7 +18,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction
|
|||
import com.tangem.tap.domain.tokens.CurrenciesRepository
|
||||
import com.tangem.tap.features.tokens.redux.TokensAction
|
||||
import com.tangem.tap.features.wallet.models.TotalBalance
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.ui.BalanceStatus
|
||||
|
|
@ -36,14 +32,7 @@ class MultiWalletView : WalletView() {
|
|||
|
||||
private lateinit var walletsAdapter: WalletAdapter
|
||||
|
||||
private val watcher = modelWatcher<WalletState> {
|
||||
val totalBalanceStrategy: DiffStrategy<WalletState> = { old, new ->
|
||||
old.cardId != new.cardId ||
|
||||
old.totalBalance != new.totalBalance ||
|
||||
old.state != new.state ||
|
||||
old.walletsStores.size != new.walletsStores.size
|
||||
}
|
||||
|
||||
private val watcher = modelWatcher {
|
||||
// !!! Workaround !!!
|
||||
// Checking state properties instead of state params can reduce application performance,
|
||||
// but here it is necessary because the WalletStore has an unsuitable equals method
|
||||
|
|
@ -68,13 +57,11 @@ class MultiWalletView : WalletView() {
|
|||
handleBackupWarning(it, showBackupWarnings)
|
||||
}
|
||||
}
|
||||
watch({ it }, totalBalanceStrategy) { walletState ->
|
||||
WalletState::totalBalance { totalBalance ->
|
||||
binding?.let {
|
||||
handleTotalBalance(
|
||||
binding = it,
|
||||
totalBalance = walletState.totalBalance,
|
||||
progressState = walletState.state,
|
||||
walletsCount = walletState.walletsDataFromStores.size,
|
||||
totalBalance = totalBalance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +82,7 @@ class MultiWalletView : WalletView() {
|
|||
lAddress.root.hide()
|
||||
rowButtons.hide()
|
||||
lSingleWalletBalance.root.hide()
|
||||
lCardTotalBalance.root.show()
|
||||
lCardTotalBalance.show()
|
||||
rvMultiwallet.show()
|
||||
btnAddToken.show()
|
||||
}
|
||||
|
|
@ -180,40 +167,11 @@ class MultiWalletView : WalletView() {
|
|||
private fun handleTotalBalance(
|
||||
binding: FragmentWalletBinding,
|
||||
totalBalance: TotalBalance?,
|
||||
progressState: ProgressState,
|
||||
walletsCount: Int,
|
||||
) = with(binding.lCardTotalBalance) {
|
||||
if (walletsCount == 0) {
|
||||
root.isVisible = false
|
||||
} else {
|
||||
if (totalBalance == null) {
|
||||
if (progressState != ProgressState.Loading) {
|
||||
root.isVisible = false
|
||||
}
|
||||
} else {
|
||||
root.isVisible = true
|
||||
// Skip changes when on refreshing state
|
||||
if (totalBalance.state == ProgressState.Refreshing || progressState == ProgressState.Refreshing) {
|
||||
return@with
|
||||
}
|
||||
|
||||
if (totalBalance.state == ProgressState.Loading) {
|
||||
veilBalance.veil()
|
||||
} else {
|
||||
veilBalance.unVeil()
|
||||
}
|
||||
tvProcessing.animateVisibility(show = totalBalance.state == ProgressState.Error)
|
||||
|
||||
tvBalance.text = totalBalance.fiatAmount.formatAmountAsSpannedString(
|
||||
currencySymbol = totalBalance.fiatCurrency.symbol,
|
||||
)
|
||||
tvCurrencyName.text = totalBalance.fiatCurrency.code
|
||||
|
||||
tvCurrencyName.setOnClickListener {
|
||||
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
|
||||
}
|
||||
}
|
||||
onChangeFiatCurrencyClick = {
|
||||
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
|
||||
}
|
||||
status = totalBalance
|
||||
}
|
||||
|
||||
private fun handleErrorStates(
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class SingleWalletView : WalletView() {
|
|||
btnAddToken.hide()
|
||||
rvPendingTransaction.hide()
|
||||
pbLoadingUserTokens.hide()
|
||||
lCardTotalBalance.root.hide()
|
||||
lCardTotalBalance.hide()
|
||||
lSingleWalletBalance.root.hide()
|
||||
lWalletRescanWarning.root.hide()
|
||||
lWalletBackupWarning.root.hide()
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false"
|
||||
android:paddingBottom="92dp">
|
||||
|
||||
<ImageView
|
||||
|
|
@ -136,9 +137,8 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
<com.tangem.tap.features.wallet.ui.view.TotalBalanceCard
|
||||
android:id="@+id/l_card_total_balance"
|
||||
layout="@layout/layout_card_total_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/card_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="18dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/main_page_balance"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_currency_name"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.skydoves.androidveil.VeilLayout
|
||||
android:id="@+id/veil_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_processing"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_title"
|
||||
app:veilLayout_baseColor="@color/lightGray0"
|
||||
app:veilLayout_highlightColor="@color/lightGray1"
|
||||
app:veilLayout_layout="@layout/card_total_balance_shimmer"
|
||||
app:veilLayout_radius="4dp"
|
||||
app:veilLayout_shimmerEnable="true"
|
||||
app:veilLayout_veiled="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:minWidth="152dp"
|
||||
android:textColor="@color/text_primary_1"
|
||||
android:textSize="26sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="visible"
|
||||
tools:text="22 325.40 $"
|
||||
tools:visibility="visible" />
|
||||
</com.skydoves.androidveil.VeilLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_processing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="@string/main_processing_full_amount"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/veil_balance"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_currency_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="16sp"
|
||||
app:drawableEndCompat="@drawable/ic_arrow_angle_down"
|
||||
app:drawableTint="@color/icon_informative"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="USD" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
package com.tangem.core.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
|
|
@ -31,11 +30,14 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
// region TextButton
|
||||
/**
|
||||
* [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=97%3A103&t=TmfD6UBHPg9uYfev-4)
|
||||
* */
|
||||
|
|
@ -99,7 +101,9 @@ fun WarningTextButton(
|
|||
size = TangemButtonSize.Text,
|
||||
)
|
||||
}
|
||||
// endregion TextButton
|
||||
|
||||
// region PrimaryButton
|
||||
@Composable
|
||||
fun PrimaryButton(
|
||||
text: String,
|
||||
|
|
@ -164,7 +168,9 @@ fun PrimaryButtonIconLeft(
|
|||
showProgress = showProgress,
|
||||
)
|
||||
}
|
||||
// endregion PrimaryButton
|
||||
|
||||
// region SecondaryButton
|
||||
@Composable
|
||||
fun SecondaryButton(
|
||||
text: String,
|
||||
|
|
@ -229,6 +235,29 @@ fun SecondaryButtonIconLeft(
|
|||
showProgress = showProgress,
|
||||
)
|
||||
}
|
||||
// endregion SecondaryButton
|
||||
|
||||
// region Other
|
||||
@Composable
|
||||
fun SelectorButton(
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
textStyle = TangemTheme.typography.subtitle2,
|
||||
icon = TangemButtonIcon.Right(painterResource(id = R.drawable.ic_chevron_24)),
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.selectorButtonColors,
|
||||
showProgress = false,
|
||||
enabled = enabled,
|
||||
size = TangemButtonSize.Selector,
|
||||
)
|
||||
}
|
||||
// endregion Other
|
||||
|
||||
// region Defaults
|
||||
@Suppress("LongParameterList")
|
||||
|
|
@ -243,12 +272,12 @@ private fun TangemButton(
|
|||
modifier: Modifier = Modifier,
|
||||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
elevation: ButtonElevation = TangemButtonsDefaults.elevation,
|
||||
textStyle: TextStyle = TangemTheme.typography.button,
|
||||
) {
|
||||
Button(
|
||||
modifier = modifier
|
||||
.width(IntrinsicSize.Min)
|
||||
.height(IntrinsicSize.Min)
|
||||
.heightIn(size.toHeightDp()),
|
||||
.heightIn(min = size.toHeightDp()),
|
||||
onClick = {
|
||||
if (!showProgress) {
|
||||
onClick()
|
||||
|
|
@ -261,19 +290,24 @@ private fun TangemButton(
|
|||
) {
|
||||
ButtonContent(
|
||||
text = text,
|
||||
textStyle = textStyle,
|
||||
buttonIcon = icon,
|
||||
colors = colors,
|
||||
showProgress = showProgress,
|
||||
enabled = enabled,
|
||||
size = size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun ButtonContent(
|
||||
text: String,
|
||||
textStyle: TextStyle,
|
||||
buttonIcon: TangemButtonIcon,
|
||||
colors: ButtonColors,
|
||||
size: TangemButtonSize,
|
||||
enabled: Boolean,
|
||||
showProgress: Boolean,
|
||||
) {
|
||||
|
|
@ -297,18 +331,19 @@ private fun ButtonContent(
|
|||
)
|
||||
}
|
||||
} else {
|
||||
Row {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(size.toIconPadding()),
|
||||
) {
|
||||
if (buttonIcon is TangemButtonIcon.Left) {
|
||||
icon(buttonIcon.painter)
|
||||
Spacer(modifier = Modifier.width(TangemTheme.dimens.size8))
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
style = TangemTheme.typography.button,
|
||||
style = textStyle,
|
||||
color = colors.contentColor(enabled = enabled).value,
|
||||
)
|
||||
if (buttonIcon is TangemButtonIcon.Right) {
|
||||
Spacer(modifier = Modifier.width(TangemTheme.dimens.size8))
|
||||
icon(buttonIcon.painter)
|
||||
}
|
||||
}
|
||||
|
|
@ -332,18 +367,28 @@ sealed interface TangemButtonIcon {
|
|||
enum class TangemButtonSize {
|
||||
Default,
|
||||
Text,
|
||||
Selector,
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemButtonSize.toHeightDp(): Dp = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.size48
|
||||
TangemButtonSize.Text -> TangemTheme.dimens.size40
|
||||
TangemButtonSize.Selector -> TangemTheme.dimens.size24
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemButtonSize.toShape(): Shape = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.shapes.roundedCornersMedium
|
||||
TangemButtonSize.Text -> TangemTheme.shapes.roundedCornersSmall
|
||||
TangemButtonSize.Selector -> TangemTheme.shapes.roundedCornersSmall
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemButtonSize.toIconPadding(): Dp = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.dimens.spacing8
|
||||
TangemButtonSize.Text -> TangemTheme.dimens.spacing8
|
||||
TangemButtonSize.Selector -> 0.dp
|
||||
}
|
||||
|
||||
object TangemButtonsDefaults {
|
||||
|
|
@ -385,6 +430,14 @@ object TangemButtonsDefaults {
|
|||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
|
||||
val selectorButtonColors: ButtonColors
|
||||
@Composable get() = TangemButtonColors(
|
||||
backgroundColor = Color.Transparent,
|
||||
contentColor = TangemTheme.colors.text.tertiary,
|
||||
disabledBackgroundColor = Color.Transparent,
|
||||
disabledContentColor = TangemTheme.colors.text.disabled,
|
||||
)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
@ -595,6 +648,11 @@ private fun TextButtonSample(
|
|||
text = "Delete",
|
||||
onClick = { /* no-op */ },
|
||||
)
|
||||
Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8))
|
||||
SelectorButton(
|
||||
text = "USD",
|
||||
onClick = { /* no-op */ },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue