Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-28 15:57:21 +03:00
commit 31be70ecf3
529 changed files with 15730 additions and 4170 deletions

View file

@ -9,6 +9,7 @@ import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.StartReferralBody
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.referral.converters.ReferralConverter
@ -20,7 +21,6 @@ import kotlinx.coroutines.withContext
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@Suppress("LongParameterList")
internal class ReferralRepositoryImpl @Inject constructor(
private val referralApi: TangemTechApi,
private val referralConverter: ReferralConverter,
@ -74,7 +74,11 @@ internal class ReferralRepositoryImpl @Inject constructor(
}
}
override suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency? {
override suspend fun getCryptoCurrency(
userWalletId: UserWalletId,
tokenData: TokenData,
accountIndex: DerivationIndex?,
): CryptoCurrency? {
val userWallet = withContext(coroutineDispatcher.io) {
userWalletsStore.getSyncOrNull(userWalletId) ?: error("Wallet $userWalletId not found")
}
@ -97,12 +101,14 @@ internal class ReferralRepositoryImpl @Inject constructor(
blockchain = blockchain,
extraDerivationPath = null,
userWallet = userWallet,
accountIndex = accountIndex,
)
} else {
cryptoCurrencyFactory.createCoin(
blockchain = blockchain,
extraDerivationPath = null,
userWallet = userWallet,
accountIndex = accountIndex,
)
}
}

View file

@ -19,6 +19,7 @@ dependencies {
implementation(projects.libs.crypto)
/** Domain modules */
implementation(projects.domain.account.status)
implementation(projects.domain.card)
implementation(projects.domain.models)
implementation(projects.domain.tokens)

View file

@ -1,6 +1,7 @@
package com.tangem.feature.referral.domain
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.referral.domain.models.ReferralData
@ -12,5 +13,9 @@ interface ReferralInteractor {
suspend fun startReferral(portfolioId: PortfolioId): ReferralData
suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency?
suspend fun getCryptoCurrency(
userWalletId: UserWalletId,
tokenData: TokenData,
accountIndex: DerivationIndex?,
): CryptoCurrency?
}

View file

@ -2,7 +2,11 @@ package com.tangem.feature.referral.domain
import arrow.core.getOrElse
import com.tangem.common.core.TangemSdkError
import com.tangem.domain.account.producer.SingleAccountProducer
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.account.supplier.SingleAccountSupplier
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
@ -21,6 +25,8 @@ internal class ReferralInteractorImpl(
private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
private val getUserWalletUseCase: GetUserWalletUseCase,
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
private val singleAccountSupplier: SingleAccountSupplier,
) : ReferralInteractor {
private val tokensForReferral = mutableListOf<TokenData>()
@ -42,30 +48,47 @@ internal class ReferralInteractorImpl(
error("Failed to get user wallet $userWalletId: $it")
}
val cryptoCurrency = repository.getCryptoCurrency(userWalletId = userWallet.walletId, tokenData = tokenData)
val accountIndex = when (portfolioId) {
is PortfolioId.Account -> {
val account = singleAccountSupplier.getSyncOrNull(
params = SingleAccountProducer.Params(accountId = portfolioId.accountId),
)
?: error("Account not found: ${portfolioId.accountId}")
account.derivationIndex
}
is PortfolioId.Wallet -> null
}
val cryptoCurrency = getCryptoCurrency(
userWalletId = portfolioId.userWalletId,
tokenData = tokenData,
accountIndex = accountIndex,
)
?: error("Failed to create crypto currency")
// todo account different for account?
derivePublicKeysUseCase(userWallet.walletId, listOfNotNull(cryptoCurrency)).getOrElse {
Timber.e("Failed to derive public keys: $it")
throw it.mapToDomainError()
}
when (portfolioId) {
is PortfolioId.Account -> TODO("account")
is PortfolioId.Wallet -> addCryptoCurrenciesUseCase(
userWalletId = userWallet.walletId,
currency = cryptoCurrency,
)
}
is PortfolioId.Account -> {
manageCryptoCurrenciesUseCase(accountId = portfolioId.accountId, add = cryptoCurrency)
}
is PortfolioId.Wallet -> {
derivePublicKeysUseCase(userWallet.walletId, listOfNotNull(cryptoCurrency)).getOrElse {
Timber.e("Failed to derive public keys: $it")
throw it.mapToDomainError()
}
val publicAddress = when (portfolioId) {
is PortfolioId.Account -> TODO("account")
is PortfolioId.Wallet -> userWalletManager.getWalletAddress(
networkId = tokenData.networkId,
derivationPath = cryptoCurrency.network.derivationPath.value,
)
addCryptoCurrenciesUseCase(
userWalletId = userWallet.walletId,
currency = cryptoCurrency,
)
}
}
.onLeft(Timber::e)
val publicAddress = userWalletManager.getWalletAddress(
networkId = tokenData.networkId,
derivationPath = cryptoCurrency.network.derivationPath.value,
)
return repository.startReferral(
walletId = userWalletManager.getWalletId(),
@ -75,8 +98,17 @@ internal class ReferralInteractorImpl(
)
}
override suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency? =
repository.getCryptoCurrency(userWalletId = userWalletId, tokenData = tokenData)
override suspend fun getCryptoCurrency(
userWalletId: UserWalletId,
tokenData: TokenData,
accountIndex: DerivationIndex?,
): CryptoCurrency? {
return repository.getCryptoCurrency(
userWalletId = userWalletId,
tokenData = tokenData,
accountIndex = accountIndex,
)
}
private fun saveReferralTokens(tokens: List<TokenData>) {
tokensForReferral.clear()

View file

@ -1,5 +1,6 @@
package com.tangem.feature.referral.domain
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.referral.domain.models.ReferralData
@ -16,5 +17,10 @@ interface ReferralRepository {
/** Starts user referral program */
suspend fun startReferral(walletId: String, networkId: String, tokenId: String, address: String): ReferralData
suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency?
/** Returns [CryptoCurrency] by [tokenData] for specific [userWalletId] and optional [accountIndex] */
suspend fun getCryptoCurrency(
userWalletId: UserWalletId,
tokenData: TokenData,
accountIndex: DerivationIndex?,
): CryptoCurrency?
}

View file

@ -1,9 +1,11 @@
package com.tangem.feature.referral.domain.di
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.account.supplier.SingleAccountSupplier
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.referral.domain.ReferralInteractor
import com.tangem.feature.referral.domain.ReferralInteractorImpl
@ -25,6 +27,8 @@ class ReferralDomainModule {
derivePublicKeysUseCase: DerivePublicKeysUseCase,
getUserWalletUseCase: GetUserWalletUseCase,
addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
singleAccountSupplier: SingleAccountSupplier,
): ReferralInteractor {
return ReferralInteractorImpl(
repository = referralRepository,
@ -32,6 +36,8 @@ class ReferralDomainModule {
derivePublicKeysUseCase = derivePublicKeysUseCase,
getUserWalletUseCase = getUserWalletUseCase,
addCryptoCurrenciesUseCase = addCryptoCurrenciesUseCase,
manageCryptoCurrenciesUseCase = manageCryptoCurrenciesUseCase,
singleAccountSupplier = singleAccountSupplier,
)
}
}

View file

@ -17,6 +17,7 @@ import com.tangem.features.account.PortfolioSelectorComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.serialization.builtins.serializer
class DefaultReferralComponent @AssistedInject constructor(
private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
@ -27,7 +28,7 @@ class DefaultReferralComponent @AssistedInject constructor(
private val model: ReferralModel = getOrCreateModel(params)
private val bottomSheetSlot = childSlot(
source = model.bottomSheetNavigation,
serializer = null,
serializer = Unit.serializer(),
handleBackButton = false,
childFactory = { configuration, context -> bottomSheetChild(context) },
)

View file

@ -1,5 +1,6 @@
package com.tangem.feature.referral.model
import com.tangem.common.ui.account.PortfolioSelectUM
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
@ -14,8 +15,10 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.feature.referral.models.ReferralStateHolder.AccountAward
import com.tangem.utils.converter.Converter
@Suppress("LongParameterList")
internal class AccountAwardConverter(
private val isBalanceHidden: Boolean,
private val isSingleAccount: Boolean,
private val appCurrency: AppCurrency,
private val awardCryptoCurrency: CryptoCurrency,
private val accountAwardToken: CryptoCurrencyStatus?,
@ -56,11 +59,15 @@ internal class AccountAwardConverter(
}
return AccountAward(
accountName = cryptoPortfolio.account.accountName.toUM().value,
accountIcon = cryptoPortfolio.account.icon.toUM(),
onAccountClick = onAccountClick,
isBalanceHidden = isBalanceHidden,
tokenState = tokenState,
accountSelectUM = PortfolioSelectUM(
icon = cryptoPortfolio.account.icon.toUM(),
name = cryptoPortfolio.account.accountName.toUM().value,
isAccountMode = true,
onClick = onAccountClick,
isMultiChoice = !isSingleAccount,
),
)
}
}

View file

@ -4,7 +4,6 @@ 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.arkivanov.decompose.router.slot.dismiss
@ -23,7 +22,6 @@ 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
@ -87,8 +85,8 @@ internal class ReferralModel @Inject constructor(
private set
val portfolioSelectorCallback = object : PortfolioSelectorComponent.BottomSheetCallback {
override val onDismiss: () -> Unit = { bottomSheetNavigation::dismiss }
override val onBack: () -> Unit = { bottomSheetNavigation::dismiss }
override val onDismiss: () -> Unit = { bottomSheetNavigation.dismiss() }
override val onBack: () -> Unit = { bottomSheetNavigation.dismiss() }
}
init {
@ -117,39 +115,45 @@ internal class ReferralModel @Inject constructor(
}
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
flow = portfolioSelectorController.selectedAccountWithData(portfolioFetcher)
.onEach { bottomSheetNavigation.dismiss() },
flow2 = getBalanceHidingSettingsUseCase.isBalanceHidden(),
flow3 = getSelectedAppCurrencyUseCase.invokeOrDefault(),
flow4 = portfolioFetcher.data,
) { pair, isBalanceHidden, appCurrency, portfolios ->
val selectedAccount = pair?.second ?: return@combine null
val cryptoPortfolio = when (selectedAccount) {
is AccountStatus.CryptoPortfolio -> selectedAccount
}
val awardCryptoCurrency = referralInteractor.getCryptoCurrency(
userWalletId = params.userWalletId,
tokenData = referralData.getToken(),
accountIndex = cryptoPortfolio.account.derivationIndex,
) ?: return@combine null
val accountAwardToken = cryptoPortfolio.tokenList.flattenCurrencies()
.find { it.currency.id == awardCryptoCurrency.id }
return@mapLatest AccountAwardConverter(
return@combine AccountAwardConverter(
isBalanceHidden = isBalanceHidden,
awardCryptoCurrency = awardCryptoCurrency,
accountAwardToken = accountAwardToken,
cryptoPortfolio = cryptoPortfolio,
appCurrency = appCurrency,
isSingleAccount = portfolios.isSingleChoice,
onAccountClick = { bottomSheetNavigation.activate(Unit) },
).convert(Unit)
}
private fun createInitiallyUiState() = ReferralStateHolder(
headerState = ReferralStateHolder.HeaderState(
headerState = HeaderState(
onBackClicked = appRouter::pop,
),
referralInfoState = ReferralInfoState.Loading,
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
analytics = Analytics(
onAgreementClicked = ::onAgreementClicked,
onCopyClicked = ::onCopyClicked,
onShareClicked = ::onShareClicked,
@ -277,18 +281,6 @@ internal class ReferralModel @Inject constructor(
}
}
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,9 +1,8 @@
package com.tangem.feature.referral.models
import androidx.annotation.DrawableRes
import com.tangem.common.ui.account.CryptoPortfolioIconUM
import com.tangem.common.ui.account.PortfolioSelectUM
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(
@ -64,8 +63,6 @@ internal data class ReferralStateHolder(
data class AccountAward(
val tokenState: TokenItemState,
val isBalanceHidden: Boolean,
val accountName: TextReference,
val accountIcon: CryptoPortfolioIconUM,
val onAccountClick: () -> Unit,
val accountSelectUM: PortfolioSelectUM,
)
}

View file

@ -10,25 +10,33 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.draw.clip
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.account.AccountIcon
import com.tangem.core.res.getStringSafe
import com.tangem.core.ui.components.PrimaryButtonIconStart
import com.tangem.core.ui.components.SpacerH12
import com.tangem.core.ui.components.SpacerW12
import com.tangem.core.ui.components.account.AccountIconSize
import com.tangem.core.ui.components.rows.RoundableCornersRow
import com.tangem.core.ui.extensions.pluralStringResourceSafe
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.referral.domain.models.ExpectedAward
import com.tangem.feature.referral.domain.models.ExpectedAwards
import com.tangem.feature.referral.models.ReferralStateHolder
import com.tangem.feature.referral.presentation.R
import kotlinx.coroutines.launch
@ -43,6 +51,7 @@ internal fun ParticipateBottomBlock(
onAgreementClick: () -> Unit,
onCopyClick: () -> Unit,
onShareClick: (String) -> Unit,
accountAward: ReferralStateHolder.AccountAward?,
) {
Column(
modifier = Modifier
@ -53,7 +62,7 @@ internal fun ParticipateBottomBlock(
.padding(horizontal = TangemTheme.dimens.spacing16),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
) {
PersonalCodeCard(code = code)
PersonalCodeCard(code = code, accountAward = accountAward)
AdditionalButtons(
code = code,
shareLink = shareLink,
@ -242,19 +251,13 @@ private fun ExtraItems(extraItems: List<ExpectedAward>, overallItemsLastIndex: I
}
@Composable
private fun PersonalCodeCard(code: String) {
private fun PersonalCodeCard(code: String, accountAward: ReferralStateHolder.AccountAward?) {
Column(
modifier = Modifier
.shadow(
elevation = TangemTheme.dimens.elevation2,
shape = RoundedCornerShape(TangemTheme.dimens.radius12),
)
.background(
color = TangemTheme.colors.background.secondary,
shape = RoundedCornerShape(TangemTheme.dimens.radius12),
)
.clip(RoundedCornerShape(TangemTheme.dimens.radius12))
.background(color = TangemTheme.colors.background.primary)
.fillMaxWidth()
.padding(vertical = TangemTheme.dimens.spacing12),
.padding(top = TangemTheme.dimens.spacing12),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
@ -270,6 +273,53 @@ private fun PersonalCodeCard(code: String) {
maxLines = 1,
style = TangemTheme.typography.h2,
)
if (accountAward != null) {
AwardAccount(accountAward)
} else {
SpacerH12()
}
}
}
@Composable
private fun AwardAccount(accountAward: ReferralStateHolder.AccountAward) {
Column {
HorizontalDivider(
thickness = 0.5.dp,
color = TangemTheme.colors.stroke.primary,
modifier = Modifier.padding(horizontal = 12.dp),
)
Row(
modifier = Modifier.padding(12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
modifier = Modifier.weight(1f),
text = stringResourceSafe(R.string.account_for_rewards),
style = TangemTheme.typography.body1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = TangemTheme.colors.text.secondary,
)
SpacerW12()
val icon = accountAward.accountSelectUM.icon
if (icon != null) {
AccountIcon(
name = accountAward.accountSelectUM.name,
icon = icon,
size = AccountIconSize.Small,
)
}
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(horizontal = 4.dp),
text = accountAward.accountSelectUM.name.resolveReference(),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.primary1,
)
}
}
}
@ -351,10 +401,11 @@ private fun ParticipateBottomBlockPreview(
code = data.code,
shareLink = data.shareLink,
expectedAwards = data.expectedAwards,
onAgreementClick = data.onAgreementClick,
snackbarHostState = SnackbarHostState(),
onAgreementClick = data.onAgreementClick,
onCopyClick = data.onCopyClick,
onShareClick = data.onShareClick,
accountAward = data.accountAward,
)
}
}
@ -410,12 +461,18 @@ private class ParticipateBottomBlockDataProvider : CollectionPreviewParameterPro
purchasedWalletCount = 0,
expectedAwards = null,
),
ParticipateBottomBlockData(
purchasedWalletCount = 0,
expectedAwards = null,
accountAward = accountReward,
),
),
)
private data class ParticipateBottomBlockData(
val purchasedWalletCount: Int,
val expectedAwards: ExpectedAwards?,
val accountAward: ReferralStateHolder.AccountAward? = null,
val code: String = "x4JDK",
val shareLink: String = "",
val onAgreementClick: () -> Unit = {},

View file

@ -15,6 +15,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
@ -26,14 +27,15 @@ 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.common.ui.account.PortfolioSelectRow
import com.tangem.common.ui.account.PortfolioSelectUM
import com.tangem.common.ui.account.toUM
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
@ -41,13 +43,13 @@ 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
import com.tangem.domain.models.account.AccountName
import com.tangem.feature.referral.domain.models.ExpectedAward
import com.tangem.feature.referral.domain.models.ExpectedAwards
import com.tangem.feature.referral.models.DemoModeException
@ -183,6 +185,7 @@ private fun ReferralInfo(
code = state.code,
shareLink = state.shareLink,
expectedAwards = state.expectedAwards,
accountAward = state.accountAward,
snackbarHostState = snackbarHostState,
onAgreementClick = onAgreementClick,
onCopyClick = stateHolder.analytics.onCopyClicked,
@ -390,10 +393,8 @@ private fun NonParticipateAccountAwardBlock(accountAward: AccountAward) {
Column(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.background(
color = TangemTheme.colors.background.primary,
shape = RoundedCornerShape(TangemTheme.dimens.spacing16),
),
.clip(RoundedCornerShape(TangemTheme.dimens.spacing16))
.background(color = TangemTheme.colors.background.primary),
) {
Text(
modifier = Modifier.padding(
@ -418,44 +419,7 @@ private fun NonParticipateAccountAwardBlock(accountAward: AccountAward) {
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,
)
}
PortfolioSelectRow(accountAward.accountSelectUM)
}
}
@ -516,6 +480,7 @@ private fun Preview_ReferralScreen_Participant_With_Referrals() {
code = "x4JdK",
shareLink = "",
url = "",
accountAward = accountReward,
expectedAwards = ExpectedAwards(
numberOfWallets = 5,
expectedAwards = listOf(
@ -572,6 +537,41 @@ private fun Preview_ReferralScreen_NonParticipant() {
}
}
internal val account = PortfolioSelectUM(
icon = AccountIconPreviewData.randomAccountIcon(),
name = AccountName.DefaultMain.toUM().value,
isAccountMode = true,
isMultiChoice = true,
onClick = {},
)
internal val accountReward
get() = AccountAward(
accountSelectUM = 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 = null,
onItemLongClick = null,
),
)
@Preview(widthDp = 360, showBackground = true)
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
@ -587,33 +587,7 @@ private fun Preview_ReferralScreen_NonParticipantAccount() {
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 = {},
),
),
accountAward = accountReward,
),
errorSnackbar = null,
analytics = Analytics(