Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-02 18:20:50 +07:00
parent 3b1df52676
commit e8a478c8b4
13 changed files with 475 additions and 38 deletions

View file

@ -13,6 +13,7 @@ android {
dependencies {
/** Api */
api(projects.features.referral.api)
api(projects.features.account.api)
/** Core modules */
implementation(projects.core.analytics)
@ -44,10 +45,18 @@ dependencies {
implementation(projects.domain.card)
implementation(projects.domain.wallets.models)
implementation(projects.domain.notifications.models)
implementation(projects.domain.account.status)
implementation(projects.domain.account)
implementation(projects.domain.balanceHiding)
implementation(projects.domain.balanceHiding.models)
implementation(projects.domain.appCurrency)
implementation(projects.domain.appCurrency.models)
implementation(projects.features.referral.domain)
/** Other libraries */
implementation(deps.compose.shimmer)
implementation(deps.kotlin.immutable.collections)
implementation(deps.decompose.ext.compose)
implementation(deps.compose.accompanist.systemUiController)
implementation(deps.timber)

View file

@ -1,28 +1,55 @@
package com.tangem.feature.referral
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.feature.referral.api.ReferralComponent
import com.tangem.feature.referral.model.ReferralModel
import com.tangem.feature.referral.ui.ReferralScreen
import com.tangem.features.account.PortfolioSelectorComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
class DefaultReferralComponent @AssistedInject constructor(
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
@Assisted appComponentContext: AppComponentContext,
@Assisted params: ReferralComponent.Params,
) : ReferralComponent, AppComponentContext by appComponentContext {
private val model: ReferralModel = getOrCreateModel(params)
private val bottomSheetSlot = childSlot(
source = model.bottomSheetNavigation,
serializer = null,
handleBackButton = false,
childFactory = { configuration, context -> bottomSheetChild(context) },
)
@Composable
override fun Content(modifier: Modifier) {
val bottomSheet by bottomSheetSlot.subscribeAsState()
ReferralScreen(stateHolder = model.uiState)
bottomSheet.child?.instance?.BottomSheet()
}
private fun bottomSheetChild(componentContext: ComponentContext): ComposableBottomSheetComponent =
portfolioSelectorComponentFactory.create(
context = childByContext(componentContext),
params = PortfolioSelectorComponent.Params(
portfolioFetcher = model.portfolioFetcher,
controller = model.portfolioSelectorController,
onDismiss = model.bottomSheetNavigation::dismiss,
),
)
@AssistedFactory
interface Factory : ReferralComponent.Factory {
override fun create(context: AppComponentContext, params: ReferralComponent.Params): DefaultReferralComponent

View file

@ -0,0 +1,66 @@
package com.tangem.feature.referral.model
import com.tangem.common.ui.account.toUM
import com.tangem.common.ui.tokens.TokenItemStateConverter.Companion.getFormattedCryptoAmount
import com.tangem.common.ui.tokens.TokenItemStateConverter.Companion.getFormattedFiatAmount
import com.tangem.common.ui.tokens.TokenItemStateConverter.Companion.isFlickering
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.feature.referral.models.ReferralStateHolder.AccountAward
import com.tangem.utils.converter.Converter
internal class AccountAwardConverter(
private val isBalanceHidden: Boolean,
private val appCurrency: AppCurrency,
private val awardCryptoCurrency: CryptoCurrency,
private val accountAwardToken: CryptoCurrencyStatus?,
private val cryptoPortfolio: AccountStatus.CryptoPortfolio,
private val onAccountClick: () -> Unit,
) : Converter<Unit, AccountAward> {
override fun convert(value: Unit): AccountAward {
val tokenState = if (accountAwardToken != null) {
val currency = accountAwardToken.currency
TokenItemState.Content(
id = currency.id.value,
iconState = CryptoCurrencyToIconStateConverter().convert(currency),
titleState = TokenItemState.TitleState.Content(stringReference(currency.name)),
fiatAmountState = TokenItemState.FiatAmountState.Content(
text = accountAwardToken.getFormattedFiatAmount(appCurrency = appCurrency),
),
subtitle2State = TokenItemState.Subtitle2State.TextContent(
text = accountAwardToken.getFormattedCryptoAmount(),
isFlickering = accountAwardToken.value.isFlickering(),
),
subtitleState = TokenItemState.SubtitleState.TextContent(stringReference(currency.symbol)),
onItemClick = null,
onItemLongClick = null,
)
} else {
val currency = awardCryptoCurrency
TokenItemState.Content(
id = currency.id.value,
iconState = CryptoCurrencyToIconStateConverter().convert(currency),
titleState = TokenItemState.TitleState.Content(stringReference(currency.name)),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = ""),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = ""),
subtitleState = TokenItemState.SubtitleState.TextContent(stringReference(currency.symbol)),
onItemClick = null,
onItemLongClick = null,
)
}
return AccountAward(
accountName = cryptoPortfolio.account.accountName.toUM().value,
accountIcon = cryptoPortfolio.account.icon.toUM(),
onAccountClick = onAccountClick,
isBalanceHidden = isBalanceHidden,
tokenState = tokenState,
)
}
}

View file

@ -4,6 +4,9 @@ import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import arrow.core.getOrElse
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.tangem.common.routing.AppRouter
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
import com.tangem.core.analytics.api.AnalyticsEventHandler
@ -12,8 +15,20 @@ import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.account.status.model.AccountCryptoCurrency
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.account.status.usecase.GetAccountCurrencyByAddressUseCase
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.referral.analytics.ReferralEvents
import com.tangem.feature.referral.api.ReferralComponent
@ -24,9 +39,11 @@ import com.tangem.feature.referral.domain.models.ReferralData
import com.tangem.feature.referral.domain.models.ReferralInfo
import com.tangem.feature.referral.models.DemoModeException
import com.tangem.feature.referral.models.ReferralStateHolder
import com.tangem.feature.referral.models.ReferralStateHolder.ErrorSnackbar
import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState
import com.tangem.feature.referral.models.ReferralStateHolder.*
import com.tangem.features.account.PortfolioFetcher
import com.tangem.features.account.PortfolioSelectorController
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -42,12 +59,27 @@ internal class ReferralModel @Inject constructor(
private val urlOpener: UrlOpener,
private val getUserWalletUseCase: GetUserWalletUseCase,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val accountsFeatureToggles: AccountsFeatureToggles,
private val portfolioFetcherFactory: PortfolioFetcher.Factory,
val portfolioSelectorController: PortfolioSelectorController,
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getAccountCurrencyByAddressUseCase: GetAccountCurrencyByAddressUseCase,
private val appRouter: AppRouter,
) : Model() {
private val params = paramsContainer.require<ReferralComponent.Params>()
val bottomSheetNavigation: SlotNavigation<Unit> = SlotNavigation()
val portfolioFetcher: PortfolioFetcher by lazy {
portfolioFetcherFactory.create(
mode = PortfolioFetcher.Mode.Wallet(params.userWalletId),
scope = modelScope,
)
}
private var lastReferralData: ReferralData? = null
private var referralData: MutableStateFlow<ReferralData?> = MutableStateFlow(null)
private val lastReferralData get() = referralData.value
var uiState: ReferralStateHolder by mutableStateOf(createInitiallyUiState())
private set
@ -55,6 +87,47 @@ internal class ReferralModel @Inject constructor(
init {
analyticsEventHandler.send(ReferralEvents.ReferralScreenOpened)
loadReferralData()
combine(
flow = referralData.filterNotNull().onEach(::selectAccount),
flow2 = portfolioSelectorController.isAccountMode,
transform = { referralData, isAccountMode -> referralData to isAccountMode },
).transformLatest { (referralData, isAccountMode) ->
when (isAccountMode) {
false -> showContent(referralData)
true -> combineAccountUI(referralData)
.map { referralData to it }
.collect(::emit)
}
}
.onEach { (referralData, accountAward) -> showContent(referralData, accountAward) }
.launchIn(modelScope)
}
private fun combineAccountUI(referralData: ReferralData): Flow<AccountAward?> = combine(
flow = portfolioSelectorController.selectedAccountWithData(portfolioFetcher),
flow2 = getBalanceHidingSettingsFlow(),
flow3 = appCurrencyFlow(),
) { a, b, c -> Triple(a, b, c) }.mapLatest { triple ->
val (_, selectedAccount) = triple.first ?: return@mapLatest null
val isBalanceHidden = triple.second
val appCurrency: AppCurrency = triple.third
val awardCryptoCurrency = referralInteractor.getCryptoCurrency(
userWalletId = params.userWalletId,
tokenData = referralData.getToken(),
) ?: return@mapLatest null
val cryptoPortfolio = when (selectedAccount) {
is AccountStatus.CryptoPortfolio -> selectedAccount
}
val accountAwardToken = cryptoPortfolio.tokenList.flattenCurrencies()
.find { it.currency.id == awardCryptoCurrency.id }
return@mapLatest AccountAwardConverter(
isBalanceHidden = isBalanceHidden,
awardCryptoCurrency = awardCryptoCurrency,
accountAwardToken = accountAwardToken,
cryptoPortfolio = cryptoPortfolio,
appCurrency = appCurrency,
onAccountClick = { bottomSheetNavigation.activate(Unit) },
).convert(Unit)
}
private fun createInitiallyUiState() = ReferralStateHolder(
@ -75,10 +148,9 @@ internal class ReferralModel @Inject constructor(
modelScope.launch {
runCatching {
referralInteractor.getReferralStatus(params.userWalletId).apply {
lastReferralData = this
referralData.value = this
}
}
.onSuccess(::showContent)
.onFailure(::showErrorSnackbar)
}
}
@ -92,16 +164,19 @@ internal class ReferralModel @Inject constructor(
analyticsEventHandler.send(ReferralEvents.ClickParticipate)
uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading)
modelScope.launch {
runCatching { referralInteractor.startReferral(params.userWalletId) }
val lastInfoState = uiState.referralInfoState
val portfolioId = when (accountsFeatureToggles.isFeatureEnabled) {
true -> PortfolioId(requireNotNull(portfolioSelectorController.selectedAccount.value))
false -> PortfolioId(params.userWalletId)
}
runCatching { referralInteractor.startReferral(portfolioId) }
.onSuccess {
analyticsEventHandler.send(ReferralEvents.ParticipateSuccessful)
showContent(it)
referralData.value = it
}
.onFailure { throwable ->
if (throwable is ReferralError.UserCancelledException) {
lastReferralData?.let { referralData ->
showContent(referralData)
}
uiState = uiState.copy(referralInfoState = lastInfoState)
} else {
showErrorSnackbar(throwable)
}
@ -110,8 +185,8 @@ internal class ReferralModel @Inject constructor(
}
}
private fun showContent(referralData: ReferralData) {
uiState = uiState.copy(referralInfoState = referralData.convertToReferralInfoState())
private fun showContent(referralData: ReferralData, accountAward: AccountAward? = null) {
uiState = uiState.copy(referralInfoState = referralData.convertToReferralInfoState(accountAward))
}
private fun showErrorSnackbar(throwable: Throwable) {
@ -136,7 +211,7 @@ internal class ReferralModel @Inject constructor(
shareManager.shareText(text = text)
}
private fun ReferralData.convertToReferralInfoState(): ReferralInfoState = when (this) {
private fun ReferralData.convertToReferralInfoState(accountAward: AccountAward?): ReferralInfoState = when (this) {
is ReferralData.ParticipantData -> ReferralInfoState.ParticipantContent(
award = getAwardValue(),
networkName = getNetworkName(),
@ -147,6 +222,7 @@ internal class ReferralModel @Inject constructor(
shareLink = referral.shareLink,
url = tosLink,
expectedAwards = expectedAwards,
accountAward = accountAward,
)
is ReferralData.NonParticipantData -> {
val userWallet = getUserWalletUseCase(params.userWalletId).getOrNull() ?: error("User wallet not found")
@ -158,6 +234,7 @@ internal class ReferralModel @Inject constructor(
url = tosLink,
onParticipateClicked = ::participate,
participateButtonIcon = walletInterationIcon(userWallet),
accountAward = accountAward,
)
}
}
@ -166,6 +243,39 @@ internal class ReferralModel @Inject constructor(
private fun ReferralData.getNetworkName(): String = getToken().networkId.replaceFirstChar(Char::uppercase)
private fun walletAccounts(walletId: UserWalletId): Flow<AccountStatusList> = singleAccountStatusListSupplier(
SingleAccountStatusListProducer.Params(walletId),
)
private suspend fun findAccountByAddress(address: String): AccountCryptoCurrency? {
return getAccountCurrencyByAddressUseCase(address).getOrNull()
}
private suspend fun selectAccount(referralData: ReferralData) {
when (referralData) {
is ReferralData.NonParticipantData -> if (portfolioSelectorController.selectedAccount.value == null) {
portfolioSelectorController.selectAccount(
accountId = walletAccounts(params.userWalletId).first().mainAccount.account.accountId,
)
}
is ReferralData.ParticipantData -> portfolioSelectorController.selectAccount(
accountId = findAccountByAddress(referralData.referral.address)?.account?.accountId,
)
}
}
private fun getBalanceHidingSettingsFlow(): Flow<Boolean> {
return getBalanceHidingSettingsUseCase()
.map { it.isBalanceHidden }
.distinctUntilChanged()
}
private fun appCurrencyFlow(): Flow<AppCurrency> {
return getSelectedAppCurrencyUseCase()
.map { it.getOrElse { AppCurrency.Default } }
.distinctUntilChanged()
}
@Suppress("MagicNumber")
private fun ReferralInfo.getAddressValue(): String {
check(address.length > 5) { "Invalid address" }

View file

@ -1,6 +1,9 @@
package com.tangem.feature.referral.models
import androidx.annotation.DrawableRes
import com.tangem.common.ui.account.CryptoPortfolioIconUM
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.feature.referral.domain.models.ExpectedAwards
internal data class ReferralStateHolder(
@ -17,6 +20,7 @@ internal data class ReferralStateHolder(
val networkName: String
val discount: String
val url: String
val accountAward: AccountAward?
}
sealed interface ReferralInfoState {
@ -29,6 +33,7 @@ internal data class ReferralStateHolder(
val code: String,
val shareLink: String,
override val url: String,
override val accountAward: AccountAward? = null,
val expectedAwards: ExpectedAwards?,
) : ReferralInfoState, ReferralInfoContentState
@ -37,6 +42,7 @@ internal data class ReferralStateHolder(
override val networkName: String,
override val discount: String,
override val url: String,
override val accountAward: AccountAward? = null,
@DrawableRes val participateButtonIcon: Int?,
val onParticipateClicked: () -> Unit,
) : ReferralInfoState, ReferralInfoContentState
@ -54,4 +60,12 @@ internal data class ReferralStateHolder(
val onCopyClicked: () -> Unit,
val onShareClicked: (String) -> Unit,
)
data class AccountAward(
val tokenState: TokenItemState,
val isBalanceHidden: Boolean,
val accountName: TextReference,
val accountIcon: CryptoPortfolioIconUM,
val onAccountClick: () -> Unit,
)
}

View file

@ -22,17 +22,29 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.account.AccountIcon
import com.tangem.common.ui.account.AccountIconPreviewData
import com.tangem.core.res.getStringSafe
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.SpacerH24
import com.tangem.core.ui.components.SpacerH32
import com.tangem.core.ui.components.account.AccountIconSize
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.snackbar.CopiedTextSnackbar
import com.tangem.core.ui.components.snackbar.TangemSnackbar
import com.tangem.core.ui.components.token.TokenItem
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.ReferralProgramScreenTestTags
@ -43,6 +55,7 @@ import com.tangem.feature.referral.models.ReferralStateHolder
import com.tangem.feature.referral.models.ReferralStateHolder.*
import com.tangem.feature.referral.presentation.R
import kotlinx.coroutines.launch
import java.util.UUID
/**
* Referral program screen for participant and non-participant
@ -179,7 +192,13 @@ private fun ReferralInfo(
is ReferralInfoState.NonParticipantContent -> {
Conditions(state = state)
Spacer(modifier = Modifier.height(TangemTheme.dimens.spacing44))
if (state.accountAward != null) {
SpacerH16()
NonParticipateAccountAwardBlock(state.accountAward)
SpacerH24()
} else {
Spacer(modifier = Modifier.height(TangemTheme.dimens.spacing44))
}
NonParticipateBottomBlock(
onAgreementClick = onAgreementClick,
onParticipateClick = state.onParticipateClicked,
@ -366,6 +385,80 @@ private fun ShimmerInfo() {
}
}
@Composable
private fun NonParticipateAccountAwardBlock(accountAward: AccountAward) {
Column(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.background(
color = TangemTheme.colors.background.primary,
shape = RoundedCornerShape(TangemTheme.dimens.spacing16),
),
) {
Text(
modifier = Modifier.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing12,
),
text = stringResourceSafe(R.string.referral_address_for_rewards),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
TokenItem(
state = accountAward.tokenState,
isBalanceHidden = accountAward.isBalanceHidden,
)
HorizontalDivider(
thickness = 0.5.dp,
color = TangemTheme.colors.stroke.primary,
modifier = Modifier.padding(horizontal = 12.dp),
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(TangemTheme.dimens.spacing12),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
modifier = Modifier.weight(1f),
text = stringResourceSafe(R.string.account_details_title),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
AccountIcon(
name = accountAward.accountName,
icon = accountAward.accountIcon,
size = AccountIconSize.Small,
)
Text(
modifier = Modifier.padding(horizontal = 4.dp),
text = accountAward.accountName.resolveReference(),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Icon(
modifier = Modifier.size(width = 18.dp, height = 24.dp),
painter = painterResource(id = R.drawable.ic_select_18_24),
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
)
}
}
}
private fun Resources.getMessageForErrorSnackbar(throwable: Throwable): String {
return when {
throwable is DemoModeException -> getStringSafe(R.string.alert_demo_feature_disabled)
@ -479,6 +572,60 @@ private fun Preview_ReferralScreen_NonParticipant() {
}
}
@Preview(widthDp = 360, showBackground = true)
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun Preview_ReferralScreen_NonParticipantAccount() {
TangemThemePreview {
ReferralScreen(
stateHolder = ReferralStateHolder(
headerState = HeaderState(onBackClicked = {}),
referralInfoState = ReferralInfoState.NonParticipantContent(
award = "10 USDT",
networkName = "Tron",
discount = "10%",
url = "",
onParticipateClicked = {},
participateButtonIcon = R.drawable.ic_tangem_24,
accountAward = AccountAward(
onAccountClick = {},
accountIcon = AccountIconPreviewData.randomAccountIcon(),
accountName = stringReference("Main Account"),
isBalanceHidden = false,
tokenState = TokenItemState.Content(
id = UUID.randomUUID().toString(),
iconState = CurrencyIconState.TokenIcon(
url = null,
topBadgeIconResId = R.drawable.img_tron_22,
fallbackTint = TangemColorPalette.Black,
fallbackBackground = TangemColorPalette.Meadow,
isGrayscale = false,
shouldShowCustomBadge = false,
),
titleState = TokenItemState.TitleState.Content(
text = stringReference(value = "Tether"),
),
fiatAmountState = FiatAmountState.Content(
text = "129,65 $",
),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "129,65 USDT"),
subtitleState = TokenItemState.SubtitleState.TextContent(value = stringReference("USDT")),
onItemClick = {},
onItemLongClick = {},
),
),
),
errorSnackbar = null,
analytics = Analytics(
onAgreementClicked = {},
onCopyClicked = {},
onShareClicked = {},
),
),
)
}
}
@Preview(widthDp = 360, showBackground = true)
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable