Updated on 2026-08-14
This commit is contained in:
parent
76c129f205
commit
a13a54accd
32 changed files with 665 additions and 35 deletions
|
|
@ -199,4 +199,24 @@ internal object YieldSupplyDomainModule {
|
||||||
yieldSupplyRepository = yieldSupplyRepository,
|
yieldSupplyRepository = yieldSupplyRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideYieldSupplyGetShouldShowMainPromoUseCase(
|
||||||
|
yieldSupplyRepository: YieldSupplyRepository,
|
||||||
|
): YieldSupplyGetShouldShowMainPromoUseCase {
|
||||||
|
return YieldSupplyGetShouldShowMainPromoUseCase(
|
||||||
|
yieldSupplyRepository = yieldSupplyRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideYieldSupplySetShouldShowMainPromoUseCase(
|
||||||
|
yieldSupplyRepository: YieldSupplyRepository,
|
||||||
|
): YieldSupplySetShouldShowMainPromoUseCase {
|
||||||
|
return YieldSupplySetShouldShowMainPromoUseCase(
|
||||||
|
yieldSupplyRepository = yieldSupplyRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -43,12 +43,14 @@ import java.math.BigDecimal
|
||||||
*/
|
*/
|
||||||
class TokenItemStateConverter(
|
class TokenItemStateConverter(
|
||||||
private val appCurrency: AppCurrency,
|
private val appCurrency: AppCurrency,
|
||||||
private val yieldModuleApyMap: Map<String, String> = emptyMap(),
|
private val yieldModuleApyMap: Map<String, BigDecimal> = emptyMap(),
|
||||||
private val stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
private val stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
||||||
|
private val yieldSupplyPromoBannerKey: String? = null,
|
||||||
private val iconStateProvider: (CryptoCurrencyStatus) -> CurrencyIconState = {
|
private val iconStateProvider: (CryptoCurrencyStatus) -> CurrencyIconState = {
|
||||||
CryptoCurrencyToIconStateConverter().convert(it)
|
CryptoCurrencyToIconStateConverter().convert(it)
|
||||||
},
|
},
|
||||||
private val onApyLabelClick: ((CryptoCurrencyStatus, String) -> Unit)? = null,
|
private val onApyLabelClick: ((CryptoCurrencyStatus, String) -> Unit)? = null,
|
||||||
|
private val onYieldPromoCloseClick: (() -> Unit)? = null,
|
||||||
private val titleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.TitleState = { currencyStatus ->
|
private val titleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.TitleState = { currencyStatus ->
|
||||||
createTitleState(
|
createTitleState(
|
||||||
currencyStatus = currencyStatus,
|
currencyStatus = currencyStatus,
|
||||||
|
|
@ -66,6 +68,15 @@ class TokenItemStateConverter(
|
||||||
private val fiatAmountStateProvider: (CryptoCurrencyStatus) -> TokenItemState.FiatAmountState? = {
|
private val fiatAmountStateProvider: (CryptoCurrencyStatus) -> TokenItemState.FiatAmountState? = {
|
||||||
createFiatAmountState(status = it, appCurrency = appCurrency)
|
createFiatAmountState(status = it, appCurrency = appCurrency)
|
||||||
},
|
},
|
||||||
|
private val promoBannerProvider: (CryptoCurrencyStatus) -> TokenItemState.PromoBannerState = { status ->
|
||||||
|
createPromoBannerState(
|
||||||
|
status = status,
|
||||||
|
yieldModuleApyMap = yieldModuleApyMap,
|
||||||
|
yieldSupplyPromoBannerKey = yieldSupplyPromoBannerKey,
|
||||||
|
onApyLabelClick = onApyLabelClick,
|
||||||
|
onYieldPromoCloseClick = onYieldPromoCloseClick,
|
||||||
|
)
|
||||||
|
},
|
||||||
private val onItemClick: ((TokenItemState, CryptoCurrencyStatus) -> Unit)? = null,
|
private val onItemClick: ((TokenItemState, CryptoCurrencyStatus) -> Unit)? = null,
|
||||||
private val onItemLongClick: ((TokenItemState, CryptoCurrencyStatus) -> Unit)? = null,
|
private val onItemLongClick: ((TokenItemState, CryptoCurrencyStatus) -> Unit)? = null,
|
||||||
) : Converter<CryptoCurrencyStatus, TokenItemState> {
|
) : Converter<CryptoCurrencyStatus, TokenItemState> {
|
||||||
|
|
@ -102,6 +113,7 @@ class TokenItemStateConverter(
|
||||||
subtitleState = requireNotNull(subtitleStateProvider(this)),
|
subtitleState = requireNotNull(subtitleStateProvider(this)),
|
||||||
fiatAmountState = requireNotNull(fiatAmountStateProvider(this)),
|
fiatAmountState = requireNotNull(fiatAmountStateProvider(this)),
|
||||||
subtitle2State = requireNotNull(subtitle2StateProvider(this)),
|
subtitle2State = requireNotNull(subtitle2StateProvider(this)),
|
||||||
|
promoBannerState = promoBannerProvider(this),
|
||||||
onItemClick = onItemClick?.let { onItemClick ->
|
onItemClick = onItemClick?.let { onItemClick ->
|
||||||
{ onItemClick(it, this) }
|
{ onItemClick(it, this) }
|
||||||
},
|
},
|
||||||
|
|
@ -164,7 +176,7 @@ class TokenItemStateConverter(
|
||||||
|
|
||||||
private fun createTitleState(
|
private fun createTitleState(
|
||||||
currencyStatus: CryptoCurrencyStatus,
|
currencyStatus: CryptoCurrencyStatus,
|
||||||
yieldModuleApyMap: Map<String, String>,
|
yieldModuleApyMap: Map<String, BigDecimal>,
|
||||||
stakingApyMap: Map<String, List<Yield.Validator>>,
|
stakingApyMap: Map<String, List<Yield.Validator>>,
|
||||||
onApyLabelClick: ((CryptoCurrencyStatus, String) -> Unit)?,
|
onApyLabelClick: ((CryptoCurrencyStatus, String) -> Unit)?,
|
||||||
): TokenItemState.TitleState {
|
): TokenItemState.TitleState {
|
||||||
|
|
@ -204,7 +216,7 @@ class TokenItemStateConverter(
|
||||||
// polygon-pos_0xc2132d05d31c914a87c6611c10748aeb04b58e8f
|
// polygon-pos_0xc2132d05d31c914a87c6611c10748aeb04b58e8f
|
||||||
private fun resolveEarnApy(
|
private fun resolveEarnApy(
|
||||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||||
yieldModuleApyMap: Map<String, String>,
|
yieldModuleApyMap: Map<String, BigDecimal>,
|
||||||
stakingApyMap: Map<String, List<Yield.Validator>>,
|
stakingApyMap: Map<String, List<Yield.Validator>>,
|
||||||
): EarnApyInfo? {
|
): EarnApyInfo? {
|
||||||
val token = cryptoCurrencyStatus.currency as? CryptoCurrency.Token
|
val token = cryptoCurrencyStatus.currency as? CryptoCurrency.Token
|
||||||
|
|
@ -223,7 +235,7 @@ class TokenItemStateConverter(
|
||||||
wrappedList(yieldSupplyApy),
|
wrappedList(yieldSupplyApy),
|
||||||
),
|
),
|
||||||
isActive = isActive,
|
isActive = isActive,
|
||||||
apy = yieldSupplyApy,
|
apy = yieldSupplyApy.toString(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -379,6 +391,36 @@ class TokenItemStateConverter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createPromoBannerState(
|
||||||
|
status: CryptoCurrencyStatus,
|
||||||
|
yieldModuleApyMap: Map<String, BigDecimal>,
|
||||||
|
yieldSupplyPromoBannerKey: String?,
|
||||||
|
onApyLabelClick: ((CryptoCurrencyStatus, String) -> Unit)?,
|
||||||
|
onYieldPromoCloseClick: (() -> Unit)?,
|
||||||
|
): TokenItemState.PromoBannerState {
|
||||||
|
val token = status.currency as? CryptoCurrency.Token ?: return TokenItemState.PromoBannerState.Empty
|
||||||
|
if (yieldSupplyPromoBannerKey == null || yieldSupplyPromoBannerKey != token.yieldSupplyKey() ||
|
||||||
|
yieldModuleApyMap[token.yieldSupplyKey()] == null
|
||||||
|
) {
|
||||||
|
return TokenItemState.PromoBannerState.Empty
|
||||||
|
}
|
||||||
|
val yieldSupplyApy =
|
||||||
|
yieldModuleApyMap[token.yieldSupplyKey()] ?: return TokenItemState.PromoBannerState.Empty
|
||||||
|
|
||||||
|
return TokenItemState.PromoBannerState.Content(
|
||||||
|
title = resourceReference(
|
||||||
|
R.string.yield_module_main_screen_promo_banner_message,
|
||||||
|
wrappedList(yieldSupplyApy),
|
||||||
|
),
|
||||||
|
onPromoBannerClick = {
|
||||||
|
onApyLabelClick?.invoke(status, yieldSupplyApy.toString())
|
||||||
|
},
|
||||||
|
onCloseClick = {
|
||||||
|
onYieldPromoCloseClick?.invoke()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun CryptoCurrencyStatus.getCryptoPriceState(appCurrency: AppCurrency): TokenItemState.SubtitleState {
|
private fun CryptoCurrencyStatus.getCryptoPriceState(appCurrency: AppCurrency): TokenItemState.SubtitleState {
|
||||||
val fiatRate = value.fiatRate
|
val fiatRate = value.fiatRate
|
||||||
val priceChange = value.priceChange
|
val priceChange = value.priceChange
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,10 @@ object PreferencesKeys {
|
||||||
|
|
||||||
val YIELD_SUPPLY_WARNINGS_STATES_KEY by lazy { stringPreferencesKey(name = "yieldSupplyWarningsStates") }
|
val YIELD_SUPPLY_WARNINGS_STATES_KEY by lazy { stringPreferencesKey(name = "yieldSupplyWarningsStates") }
|
||||||
|
|
||||||
|
val YIELD_SUPPLY_SHOULD_SHOW_MAIN_PROMO_KEY by lazy {
|
||||||
|
booleanPreferencesKey(name = "yieldSupplyShouldShowMainPromo")
|
||||||
|
}
|
||||||
|
|
||||||
val ACCESS_CODE_SKIPPED_STATES_KEY by lazy { stringPreferencesKey(name = "accessCodeSkippedStates") }
|
val ACCESS_CODE_SKIPPED_STATES_KEY by lazy { stringPreferencesKey(name = "accessCodeSkippedStates") }
|
||||||
|
|
||||||
// region Notifications
|
// region Notifications
|
||||||
|
|
|
||||||
|
|
@ -590,6 +590,7 @@
|
||||||
<string name="hw_backup_need_finish_first">まずバックアップを完了する</string>
|
<string name="hw_backup_need_finish_first">まずバックアップを完了する</string>
|
||||||
<string name="hw_backup_need_title">まずバックアップを完了する</string>
|
<string name="hw_backup_need_title">まずバックアップを完了する</string>
|
||||||
<string name="hw_backup_section_other_title">その他の方法</string>
|
<string name="hw_backup_section_other_title">その他の方法</string>
|
||||||
|
<string name="hw_backup_seed_description">リカバリーフレーズは、ご自身で安全な場所に保管し、資金を守るために他人には絶対に共有しないでください。</string>
|
||||||
<string name="hw_backup_seed_title">リカバリーフレーズ</string>
|
<string name="hw_backup_seed_title">リカバリーフレーズ</string>
|
||||||
<string name="hw_backup_to_secure_description">アクセスコードを使用してウォレットを保護するには、まずバックアップを完了してください。</string>
|
<string name="hw_backup_to_secure_description">アクセスコードを使用してウォレットを保護するには、まずバックアップを完了してください。</string>
|
||||||
<string name="hw_backup_to_upgrade_description">ウォレットをハードウェアにアップグレードするには、まずバックアップしてください。</string>
|
<string name="hw_backup_to_upgrade_description">ウォレットをハードウェアにアップグレードするには、まずバックアップしてください。</string>
|
||||||
|
|
@ -1432,6 +1433,8 @@
|
||||||
<string name="tangempay_failed_to_issue_card">カードの発行に失敗しました</string>
|
<string name="tangempay_failed_to_issue_card">カードの発行に失敗しました</string>
|
||||||
<string name="tangempay_failed_to_issue_card_retry_description">技術的なエラーが発生しました。下のボタンをクリックして、もう一度お試しください。</string>
|
<string name="tangempay_failed_to_issue_card_retry_description">技術的なエラーが発生しました。下のボタンをクリックして、もう一度お試しください。</string>
|
||||||
<string name="tangempay_failed_to_issue_card_support_description">技術的なエラーが発生しました。サポートへお問い合わせください。</string>
|
<string name="tangempay_failed_to_issue_card_support_description">技術的なエラーが発生しました。サポートへお問い合わせください。</string>
|
||||||
|
<string name="tangempay_get_banner_description">暗号資産を日常の支払いに使おう。\n\nこれまでにないタイプの決済カード。</string>
|
||||||
|
<string name="tangempay_get_tangem_pay">Tangem Payを入手</string>
|
||||||
<string name="tangempay_issue_card_notification_description">通常は最大で15分ほどかかります</string>
|
<string name="tangempay_issue_card_notification_description">通常は最大で15分ほどかかります</string>
|
||||||
<string name="tangempay_issue_card_notification_title">Tangemカードのセットアップ</string>
|
<string name="tangempay_issue_card_notification_title">Tangemカードのセットアップ</string>
|
||||||
<string name="tangempay_issuing_your_card">カードを発行しています</string>
|
<string name="tangempay_issuing_your_card">カードを発行しています</string>
|
||||||
|
|
@ -1454,6 +1457,7 @@
|
||||||
<string name="tangempay_service_unavailable_description">技術的な問題を修正しています。後でもう一度お試しください。</string>
|
<string name="tangempay_service_unavailable_description">技術的な問題を修正しています。後でもう一度お試しください。</string>
|
||||||
<string name="tangempay_service_unavailable_title">サービスは一時的に利用できません</string>
|
<string name="tangempay_service_unavailable_title">サービスは一時的に利用できません</string>
|
||||||
<string name="tangempay_service_unreachable_try_later">現在サービスに接続できません。後ほどもう一度お試しください。</string>
|
<string name="tangempay_service_unreachable_try_later">現在サービスに接続できません。後ほどもう一度お試しください。</string>
|
||||||
|
<string name="tangempay_tangem_visa_card">Tangem Visaカード</string>
|
||||||
<string name="tangempay_temporarily_unavailable">Tangem Payは一時的に利用できません</string>
|
<string name="tangempay_temporarily_unavailable">Tangem Payは一時的に利用できません</string>
|
||||||
<string name="tangempay_title">Tangem Pay</string>
|
<string name="tangempay_title">Tangem Pay</string>
|
||||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">カードまたはリングを使用して、支払いアカウントへのアクセスを復元してください。</string>
|
<string name="tangempay_use_tangem_device_to_restore_payment_account">カードまたはリングを使用して、支払いアカウントへのアクセスを復元してください。</string>
|
||||||
|
|
@ -1500,6 +1504,7 @@
|
||||||
<string name="transaction_history_multiple_addresses">複数のアドレス</string>
|
<string name="transaction_history_multiple_addresses">複数のアドレス</string>
|
||||||
<string name="transaction_history_not_supported_description">現在、このブロックチェーンでは取引履歴はサポートされていません。しかしご心配なく!弊社で対応中です。その間、エクスプローラーで確認することができます。</string>
|
<string name="transaction_history_not_supported_description">現在、このブロックチェーンでは取引履歴はサポートされていません。しかしご心配なく!弊社で対応中です。その間、エクスプローラーで確認することができます。</string>
|
||||||
<string name="transaction_history_operation">オペレーション</string>
|
<string name="transaction_history_operation">オペレーション</string>
|
||||||
|
<string name="transaction_history_transaction_for_address">対象:%s</string>
|
||||||
<string name="transaction_history_transaction_from_address">送金元: %s</string>
|
<string name="transaction_history_transaction_from_address">送金元: %s</string>
|
||||||
<string name="transaction_history_transaction_to_address">送金先: %s</string>
|
<string name="transaction_history_transaction_to_address">送金先: %s</string>
|
||||||
<string name="transaction_history_transaction_validator">バリデーター: %s</string>
|
<string name="transaction_history_transaction_validator">バリデーター: %s</string>
|
||||||
|
|
|
||||||
|
|
@ -527,7 +527,7 @@
|
||||||
<string name="express_status_buying">Buying %s</string>
|
<string name="express_status_buying">Buying %s</string>
|
||||||
<string name="express_status_buying_active">Buying %s...</string>
|
<string name="express_status_buying_active">Buying %s...</string>
|
||||||
<string name="express_status_hide_button_text">Hide this transaction</string>
|
<string name="express_status_hide_button_text">Hide this transaction</string>
|
||||||
<string name="express_status_hide_dialog_text">Once hidden, the transaction status cannot be viewed again. You can simply swipe to dismiss instead.</string>
|
<string name="express_status_hide_dialog_text">If you hide this transaction, it won’t appear in the status screen anymore. If you just want to close the status screen and return later, simply swipe it away instead.</string>
|
||||||
<string name="express_status_hide_dialog_title">Hide Transaction Status?</string>
|
<string name="express_status_hide_dialog_title">Hide Transaction Status?</string>
|
||||||
<string name="express_swap_not_supported_text">This token is not supported. Please choose a different token to swap.</string>
|
<string name="express_swap_not_supported_text">This token is not supported. Please choose a different token to swap.</string>
|
||||||
<string name="express_swap_not_supported_title">%s is not supported</string>
|
<string name="express_swap_not_supported_title">%s is not supported</string>
|
||||||
|
|
@ -697,11 +697,13 @@
|
||||||
<string name="markets_apy_placeholder">APY %s</string>
|
<string name="markets_apy_placeholder">APY %s</string>
|
||||||
<string name="markets_common_my_portfolio">My portfolio</string>
|
<string name="markets_common_my_portfolio">My portfolio</string>
|
||||||
<string name="markets_common_title">Market</string>
|
<string name="markets_common_title">Market</string>
|
||||||
|
<string name="markets_earn_common_title">Earn with Tangem</string>
|
||||||
<string name="markets_generate_addresses_notification">To generate addresses for selected networks, you must scan your Tangem Wallet card or ring</string>
|
<string name="markets_generate_addresses_notification">To generate addresses for selected networks, you must scan your Tangem Wallet card or ring</string>
|
||||||
<string name="markets_hint">To add tokens pull this up or tap the search bar</string>
|
<string name="markets_hint">To add tokens pull this up or tap the search bar</string>
|
||||||
<string name="markets_insights_info_description_message">This section’s data is sourced from the following networks: %s</string>
|
<string name="markets_insights_info_description_message">This section’s data is sourced from the following networks: %s</string>
|
||||||
<string name="markets_loading_error_title">Unable to load the data…</string>
|
<string name="markets_loading_error_title">Unable to load the data…</string>
|
||||||
<string name="markets_loading_no_data_title">No data</string>
|
<string name="markets_loading_no_data_title">No data</string>
|
||||||
|
<string name="markets_pulse_common_title">Market Pulse</string>
|
||||||
<string name="markets_quick_actions">Quick actions</string>
|
<string name="markets_quick_actions">Quick actions</string>
|
||||||
<string name="markets_search_header_title">Search through the market</string>
|
<string name="markets_search_header_title">Search through the market</string>
|
||||||
<string name="markets_search_result_title">Result</string>
|
<string name="markets_search_result_title">Result</string>
|
||||||
|
|
@ -1985,7 +1987,7 @@
|
||||||
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem also takes a 15% service fee on yield generated.</string>
|
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem also takes a 15% service fee on yield generated.</string>
|
||||||
<string name="yield_module_high_fee_error">Your funds will be automatically supplied to Aave once network fees are lower or your balance meets the minimum required amount.</string>
|
<string name="yield_module_high_fee_error">Your funds will be automatically supplied to Aave once network fees are lower or your balance meets the minimum required amount.</string>
|
||||||
<string name="yield_module_historical_returns">Historical returns</string>
|
<string name="yield_module_historical_returns">Historical returns</string>
|
||||||
<string name="yield_module_main_screen_promo_banner_message">"Enable %1$s%% APY on your balance"</string>
|
<string name="yield_module_main_screen_promo_banner_message">Enable %1$s%% APY on your balance</string>
|
||||||
<string name="yield_module_main_view_approve_notification_description">Approval for your token in Yield Mode has been revoked. Open the token to grant permission again.</string>
|
<string name="yield_module_main_view_approve_notification_description">Approval for your token in Yield Mode has been revoked. Open the token to grant permission again.</string>
|
||||||
<string name="yield_module_main_view_approve_notification_title">Token approval needed</string>
|
<string name="yield_module_main_view_approve_notification_title">Token approval needed</string>
|
||||||
<string name="yield_module_network_fee_unreachable_notification_description">Check your network connection</string>
|
<string name="yield_module_network_fee_unreachable_notification_description">Check your network connection</string>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.tangem.core.ui.components.token
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -18,6 +19,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||||
import androidx.compose.ui.unit.Constraints
|
import androidx.compose.ui.unit.Constraints
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.R
|
import com.tangem.core.ui.R
|
||||||
import com.tangem.core.ui.components.audits.AuditLabelUM
|
import com.tangem.core.ui.components.audits.AuditLabelUM
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||||
|
|
@ -28,6 +30,7 @@ import com.tangem.core.ui.components.token.internal.*
|
||||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState
|
import com.tangem.core.ui.components.token.state.TokenItemState.FiatAmountState
|
||||||
import com.tangem.core.ui.components.token.state.TokenItemState.Subtitle2State
|
import com.tangem.core.ui.components.token.state.TokenItemState.Subtitle2State
|
||||||
|
import com.tangem.core.ui.components.token.state.TokenItemState.PromoBannerState
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
import com.tangem.core.ui.extensions.rememberHapticFeedback
|
import com.tangem.core.ui.extensions.rememberHapticFeedback
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
|
|
@ -44,7 +47,7 @@ private const val TITLE_MIN_WIDTH_COEFFICIENT = 0.3
|
||||||
private const val PRICE_MIN_WIDTH_COEFFICIENT = 0.32
|
private const val PRICE_MIN_WIDTH_COEFFICIENT = 0.32
|
||||||
|
|
||||||
private enum class LayoutId {
|
private enum class LayoutId {
|
||||||
ICON, TITLE, FIAT_AMOUNT, CRYPTO_AMOUNT, CRYPTO_PRICE, NON_FIAT_CONTENT
|
ICON, TITLE, FIAT_AMOUNT, CRYPTO_AMOUNT, CRYPTO_PRICE, NON_FIAT_CONTENT, PROMO_BANNER
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -109,6 +112,14 @@ fun TokenItem(
|
||||||
.testTag(TokenElementsTestTags.TOKEN_ICON),
|
.testTag(TokenElementsTestTags.TOKEN_ICON),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
YieldSupplyPromoBanner(
|
||||||
|
state = state.promoBannerState,
|
||||||
|
modifier = Modifier
|
||||||
|
.layoutId(layoutId = LayoutId.PROMO_BANNER)
|
||||||
|
.testTag(TokenElementsTestTags.TOKEN_YIELD_PROMO_BANNER)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
|
||||||
TokenTitle(
|
TokenTitle(
|
||||||
state = state.titleState,
|
state = state.titleState,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -220,6 +231,13 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
|
||||||
|
|
||||||
val nonFiatContent = measurables.measure(layoutId = LayoutId.NON_FIAT_CONTENT, constraints = constraints)
|
val nonFiatContent = measurables.measure(layoutId = LayoutId.NON_FIAT_CONTENT, constraints = constraints)
|
||||||
|
|
||||||
|
val promoBanner = when (state.promoBannerState) {
|
||||||
|
is PromoBannerState.Content -> measurables.measure(
|
||||||
|
layoutId = LayoutId.PROMO_BANNER,
|
||||||
|
constraints = constraints,
|
||||||
|
)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
var firstRowRemainingFreeSpace: Int? = null
|
var firstRowRemainingFreeSpace: Int? = null
|
||||||
var secondRowRemainingFreeSpace: Int? = null
|
var secondRowRemainingFreeSpace: Int? = null
|
||||||
|
|
||||||
|
|
@ -283,10 +301,18 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val promoBannerHeight = promoBanner?.height ?: 0
|
||||||
|
val promoOffset = if (promoBannerHeight > 0) {
|
||||||
|
promoBannerHeight - 8.dp.roundToPx()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
val layoutHeight = calculateLayoutHeight(
|
val layoutHeight = calculateLayoutHeight(
|
||||||
state = state,
|
state = state,
|
||||||
minLayoutHeight = with(density) { dimens.size68.roundToPx() },
|
minLayoutHeight = with(density) { dimens.size68.roundToPx() },
|
||||||
layoutPadding = verticalPadding,
|
layoutPadding = verticalPadding,
|
||||||
|
promoOffset = promoOffset,
|
||||||
title = title,
|
title = title,
|
||||||
fiatAmount = fiatAmount,
|
fiatAmount = fiatAmount,
|
||||||
cryptoAmount = cryptoAmount,
|
cryptoAmount = cryptoAmount,
|
||||||
|
|
@ -294,16 +320,22 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
|
||||||
)
|
)
|
||||||
|
|
||||||
layout(width = constraints.maxWidth, height = layoutHeight) {
|
layout(width = constraints.maxWidth, height = layoutHeight) {
|
||||||
icon.placeRelative(x = 0, y = (layoutHeight - icon.height).div(other = 2))
|
promoBanner?.placeRelative(x = 0, y = 0)
|
||||||
|
|
||||||
|
icon.placeRelative(
|
||||||
|
x = 0,
|
||||||
|
y = promoOffset + (layoutHeight - promoOffset - icon.height)
|
||||||
|
.div(other = 2),
|
||||||
|
)
|
||||||
|
|
||||||
title.placeRelative(
|
title.placeRelative(
|
||||||
x = icon.width,
|
x = icon.width,
|
||||||
y = when (state) {
|
y = promoOffset + when (state) {
|
||||||
is TokenItemState.NoAddress,
|
is TokenItemState.NoAddress,
|
||||||
is TokenItemState.Unreachable,
|
is TokenItemState.Unreachable,
|
||||||
-> {
|
-> {
|
||||||
if (state.subtitleState == null) {
|
if (state.subtitleState == null) {
|
||||||
(layoutHeight - title.height).div(other = 2)
|
(layoutHeight - promoOffset - title.height).div(other = 2)
|
||||||
} else {
|
} else {
|
||||||
verticalPadding
|
verticalPadding
|
||||||
}
|
}
|
||||||
|
|
@ -314,8 +346,8 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
|
||||||
|
|
||||||
fiatAmount?.placeRelative(
|
fiatAmount?.placeRelative(
|
||||||
x = layoutWidth - fiatAmount.width,
|
x = layoutWidth - fiatAmount.width,
|
||||||
y = when (state.subtitle2State) {
|
y = promoOffset + when (state.subtitle2State) {
|
||||||
null -> (layoutHeight - fiatAmount.height).div(other = 2)
|
null -> (layoutHeight - promoOffset - fiatAmount.height).div(other = 2)
|
||||||
else -> verticalPadding
|
else -> verticalPadding
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -335,7 +367,7 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
|
||||||
|
|
||||||
nonFiatContent.placeRelative(
|
nonFiatContent.placeRelative(
|
||||||
x = layoutWidth - nonFiatContent.width,
|
x = layoutWidth - nonFiatContent.width,
|
||||||
y = (layoutHeight - nonFiatContent.height).div(other = 2),
|
y = promoOffset + (layoutHeight - promoOffset - nonFiatContent.height).div(other = 2),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -443,6 +475,7 @@ private fun calculateLayoutHeight(
|
||||||
state: TokenItemState,
|
state: TokenItemState,
|
||||||
minLayoutHeight: Int,
|
minLayoutHeight: Int,
|
||||||
layoutPadding: Int,
|
layoutPadding: Int,
|
||||||
|
promoOffset: Int,
|
||||||
title: Placeable,
|
title: Placeable,
|
||||||
fiatAmount: Placeable?,
|
fiatAmount: Placeable?,
|
||||||
cryptoAmount: Placeable?,
|
cryptoAmount: Placeable?,
|
||||||
|
|
@ -468,7 +501,7 @@ private fun calculateLayoutHeight(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return max(firstColumnHeight, secondColumnHeight).coerceAtLeast(minLayoutHeight)
|
return (promoOffset + max(firstColumnHeight, secondColumnHeight)).coerceAtLeast(promoOffset + minLayoutHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(widthDp = 360, showBackground = true)
|
@Preview(widthDp = 360, showBackground = true)
|
||||||
|
|
@ -587,6 +620,11 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
|
||||||
),
|
),
|
||||||
onItemClick = {},
|
onItemClick = {},
|
||||||
onItemLongClick = {},
|
onItemLongClick = {},
|
||||||
|
promoBannerState = PromoBannerState.Content(
|
||||||
|
title = TextReference.Str(value = "Trusted"),
|
||||||
|
onPromoBannerClick = {},
|
||||||
|
onCloseClick = {},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
TokenItemState.Loading(
|
TokenItemState.Loading(
|
||||||
id = "Loading#1",
|
id = "Loading#1",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
package com.tangem.core.ui.components.token.internal
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.material3.ripple
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.tangem.core.ui.R
|
||||||
|
import com.tangem.core.ui.components.token.state.TokenItemState.PromoBannerState
|
||||||
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
import com.tangem.core.ui.extensions.resolveReference
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun YieldSupplyPromoBanner(state: PromoBannerState, modifier: Modifier = Modifier) {
|
||||||
|
when (state) {
|
||||||
|
is PromoBannerState.Content -> YieldSupplyPromoBanner(state = state, modifier = modifier)
|
||||||
|
is PromoBannerState.Empty -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun YieldSupplyPromoBanner(state: PromoBannerState.Content, modifier: Modifier = Modifier) {
|
||||||
|
val bgColor = TangemTheme.colors.control.unchecked
|
||||||
|
Column(modifier = modifier) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(color = bgColor, shape = TangemTheme.shapes.roundedCornersXMedium)
|
||||||
|
.padding(horizontal = 12.dp, vertical = 8.dp)
|
||||||
|
.clickable(onClick = state.onPromoBannerClick)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = ImageVector.vectorResource(id = R.drawable.ic_analytics_up_24),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = TangemTheme.colors.icon.accent,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(end = TangemTheme.dimens.spacing8)
|
||||||
|
.size(TangemTheme.dimens.size16),
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = state.title.resolveReference(),
|
||||||
|
style = TangemTheme.typography.caption1,
|
||||||
|
color = TangemTheme.colors.text.secondary,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(end = TangemTheme.dimens.spacing8),
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_close_24),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = TangemTheme.colors.text.secondary,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(TangemTheme.dimens.size16)
|
||||||
|
.clickable(
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
indication = ripple(bounded = false),
|
||||||
|
onClick = { state.onCloseClick() },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_rectangle_bottom),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = bgColor,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(width = 12.dp, height = 8.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(widthDp = 360, showBackground = true)
|
||||||
|
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun Preview_YieldSupplyPromoBanner() {
|
||||||
|
TangemThemePreview {
|
||||||
|
YieldSupplyPromoBanner(
|
||||||
|
state = PromoBannerState.Content(
|
||||||
|
title = TextReference.Str(value = "Earn up to 5% APY"),
|
||||||
|
onPromoBannerClick = {},
|
||||||
|
onCloseClick = {},
|
||||||
|
),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,8 @@ sealed class TokenItemState {
|
||||||
*/
|
*/
|
||||||
abstract val subtitle2State: Subtitle2State?
|
abstract val subtitle2State: Subtitle2State?
|
||||||
|
|
||||||
|
abstract val promoBannerState: PromoBannerState
|
||||||
|
|
||||||
/** Callback which will be called when an item is clicked */
|
/** Callback which will be called when an item is clicked */
|
||||||
abstract val onItemClick: ((TokenItemState) -> Unit)?
|
abstract val onItemClick: ((TokenItemState) -> Unit)?
|
||||||
|
|
||||||
|
|
@ -59,6 +61,7 @@ sealed class TokenItemState {
|
||||||
) : TokenItemState() {
|
) : TokenItemState() {
|
||||||
override val fiatAmountState: FiatAmountState = FiatAmountState.Loading
|
override val fiatAmountState: FiatAmountState = FiatAmountState.Loading
|
||||||
override val subtitle2State: Subtitle2State = Subtitle2State.Loading
|
override val subtitle2State: Subtitle2State = Subtitle2State.Loading
|
||||||
|
override val promoBannerState: PromoBannerState = PromoBannerState.Empty
|
||||||
override val onItemClick: ((TokenItemState) -> Unit)? = null
|
override val onItemClick: ((TokenItemState) -> Unit)? = null
|
||||||
override val onItemLongClick: ((TokenItemState) -> Unit)? = null
|
override val onItemLongClick: ((TokenItemState) -> Unit)? = null
|
||||||
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null
|
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null
|
||||||
|
|
@ -75,6 +78,7 @@ sealed class TokenItemState {
|
||||||
override val subtitleState: SubtitleState = SubtitleState.Locked
|
override val subtitleState: SubtitleState = SubtitleState.Locked
|
||||||
override val fiatAmountState: FiatAmountState = FiatAmountState.Locked
|
override val fiatAmountState: FiatAmountState = FiatAmountState.Locked
|
||||||
override val subtitle2State: Subtitle2State = Subtitle2State.Locked
|
override val subtitle2State: Subtitle2State = Subtitle2State.Locked
|
||||||
|
override val promoBannerState: PromoBannerState = PromoBannerState.Empty
|
||||||
override val onItemClick: ((TokenItemState) -> Unit)? = null
|
override val onItemClick: ((TokenItemState) -> Unit)? = null
|
||||||
override val onItemLongClick: ((TokenItemState) -> Unit)? = null
|
override val onItemLongClick: ((TokenItemState) -> Unit)? = null
|
||||||
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null
|
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null
|
||||||
|
|
@ -99,6 +103,7 @@ sealed class TokenItemState {
|
||||||
override val subtitleState: SubtitleState,
|
override val subtitleState: SubtitleState,
|
||||||
override val fiatAmountState: FiatAmountState?,
|
override val fiatAmountState: FiatAmountState?,
|
||||||
override val subtitle2State: Subtitle2State?,
|
override val subtitle2State: Subtitle2State?,
|
||||||
|
override val promoBannerState: PromoBannerState = PromoBannerState.Empty,
|
||||||
override val onItemClick: ((TokenItemState) -> Unit)?,
|
override val onItemClick: ((TokenItemState) -> Unit)?,
|
||||||
override val onItemLongClick: ((TokenItemState) -> Unit)?,
|
override val onItemLongClick: ((TokenItemState) -> Unit)?,
|
||||||
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null,
|
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null,
|
||||||
|
|
@ -120,6 +125,7 @@ sealed class TokenItemState {
|
||||||
) : TokenItemState() {
|
) : TokenItemState() {
|
||||||
override val subtitleState: SubtitleState? = null
|
override val subtitleState: SubtitleState? = null
|
||||||
override val fiatAmountState: FiatAmountState? = null
|
override val fiatAmountState: FiatAmountState? = null
|
||||||
|
override val promoBannerState: PromoBannerState = PromoBannerState.Empty
|
||||||
override val onItemClick: ((TokenItemState) -> Unit)? = null
|
override val onItemClick: ((TokenItemState) -> Unit)? = null
|
||||||
override val onItemLongClick: ((TokenItemState) -> Unit)? = null
|
override val onItemLongClick: ((TokenItemState) -> Unit)? = null
|
||||||
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null
|
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null
|
||||||
|
|
@ -146,6 +152,7 @@ sealed class TokenItemState {
|
||||||
) : TokenItemState() {
|
) : TokenItemState() {
|
||||||
override val fiatAmountState: FiatAmountState? = null
|
override val fiatAmountState: FiatAmountState? = null
|
||||||
override val subtitle2State: Subtitle2State? = null
|
override val subtitle2State: Subtitle2State? = null
|
||||||
|
override val promoBannerState: PromoBannerState = PromoBannerState.Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -168,6 +175,7 @@ sealed class TokenItemState {
|
||||||
override val subtitle2State: Subtitle2State? = null
|
override val subtitle2State: Subtitle2State? = null
|
||||||
override val onItemClick: ((TokenItemState) -> Unit)? = null
|
override val onItemClick: ((TokenItemState) -> Unit)? = null
|
||||||
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null
|
override val onApyLabelClick: ((TokenItemState) -> Unit)? = null
|
||||||
|
override val promoBannerState: PromoBannerState = PromoBannerState.Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
|
|
@ -254,4 +262,15 @@ sealed class TokenItemState {
|
||||||
|
|
||||||
data object Locked : Subtitle2State()
|
data object Locked : Subtitle2State()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
sealed class PromoBannerState {
|
||||||
|
data class Content(
|
||||||
|
val title: TextReference,
|
||||||
|
val onPromoBannerClick: () -> Unit,
|
||||||
|
val onCloseClick: () -> Unit,
|
||||||
|
) : PromoBannerState()
|
||||||
|
|
||||||
|
data object Empty : PromoBannerState()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,4 +7,5 @@ object TokenElementsTestTags {
|
||||||
const val TOKEN_FIAT_AMOUNT = "TOKEN_FIAT_AMOUNT"
|
const val TOKEN_FIAT_AMOUNT = "TOKEN_FIAT_AMOUNT"
|
||||||
const val TOKEN_CRYPTO_AMOUNT = "TOKEN_CRYPTO_AMOUNT"
|
const val TOKEN_CRYPTO_AMOUNT = "TOKEN_CRYPTO_AMOUNT"
|
||||||
const val TOKEN_NON_FIAT_BLOCK = "TOKEN_NON_FIAT_BLOCK"
|
const val TOKEN_NON_FIAT_BLOCK = "TOKEN_NON_FIAT_BLOCK"
|
||||||
|
const val TOKEN_YIELD_PROMO_BANNER = "TOKEN_YIELD_PROMO_BANNER"
|
||||||
}
|
}
|
||||||
9
core/ui/src/main/res/drawable/ic_rectangle_bottom.xml
Normal file
9
core/ui/src/main/res/drawable/ic_rectangle_bottom.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="12dp"
|
||||||
|
android:height="8dp"
|
||||||
|
android:viewportWidth="12"
|
||||||
|
android:viewportHeight="8">
|
||||||
|
<path
|
||||||
|
android:pathData="M0.198,1.178C0.034,0.976 -0.028,0.695 0.012,0.433C0.058,0.135 0.373,0 0.675,0H6.183H11.325C11.627,0 11.943,0.135 11.988,0.433C12.028,0.695 11.966,0.976 11.802,1.178L6.477,7.756C6.214,8.081 5.786,8.081 5.523,7.756L0.198,1.178Z"
|
||||||
|
android:fillColor="#EBEBEB"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -69,15 +69,16 @@ fun CoroutineScope.launchOnCancellation(block: suspend () -> Unit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongParameterList", "MagicNumber")
|
@Suppress("LongParameterList", "MagicNumber")
|
||||||
inline fun <T1, T2, T3, T4, T5, T6, R> combine6(
|
inline fun <T1, T2, T3, T4, T5, T6, T7, R> combine7(
|
||||||
flow1: Flow<T1>,
|
flow1: Flow<T1>,
|
||||||
flow2: Flow<T2>,
|
flow2: Flow<T2>,
|
||||||
flow3: Flow<T3>,
|
flow3: Flow<T3>,
|
||||||
flow4: Flow<T4>,
|
flow4: Flow<T4>,
|
||||||
flow5: Flow<T5>,
|
flow5: Flow<T5>,
|
||||||
flow6: Flow<T6>,
|
flow6: Flow<T6>,
|
||||||
crossinline transform: suspend (T1, T2, T3, T4, T5, T6) -> R,
|
flow7: Flow<T7>,
|
||||||
): Flow<R> = combine(flow1, flow2, flow3, flow4, flow5, flow6) { arr ->
|
crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R,
|
||||||
|
): Flow<R> = combine(flow1, flow2, flow3, flow4, flow5, flow6, flow7) { arr ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
transform(
|
transform(
|
||||||
arr[0] as T1,
|
arr[0] as T1,
|
||||||
|
|
@ -86,5 +87,6 @@ inline fun <T1, T2, T3, T4, T5, T6, R> combine6(
|
||||||
arr[3] as T4,
|
arr[3] as T4,
|
||||||
arr[4] as T5,
|
arr[4] as T5,
|
||||||
arr[5] as T6,
|
arr[5] as T6,
|
||||||
|
arr[6] as T7,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +19,10 @@ dependencies {
|
||||||
/** Tangem SDKs */
|
/** Tangem SDKs */
|
||||||
implementation(tangemDeps.blockchain)
|
implementation(tangemDeps.blockchain)
|
||||||
|
|
||||||
|
// region AndroidX libraries
|
||||||
|
implementation(deps.androidx.datastore)
|
||||||
|
// endregion
|
||||||
|
|
||||||
/** Core */
|
/** Core */
|
||||||
implementation(projects.core.datasource)
|
implementation(projects.core.datasource)
|
||||||
implementation(projects.core.utils)
|
implementation(projects.core.utils)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ import com.tangem.data.yield.supply.converters.YieldTokenChartConverter
|
||||||
import com.tangem.datasource.api.common.response.getOrThrow
|
import com.tangem.datasource.api.common.response.getOrThrow
|
||||||
import com.tangem.datasource.api.tangemTech.YieldSupplyApi
|
import com.tangem.datasource.api.tangemTech.YieldSupplyApi
|
||||||
import com.tangem.datasource.api.tangemTech.models.YieldSupplyChangeTokenStatusBody
|
import com.tangem.datasource.api.tangemTech.models.YieldSupplyChangeTokenStatusBody
|
||||||
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
|
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||||
|
import com.tangem.datasource.local.preferences.utils.get
|
||||||
|
import com.tangem.datasource.local.preferences.utils.store
|
||||||
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
|
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
|
@ -35,6 +39,7 @@ internal class DefaultYieldSupplyRepository(
|
||||||
private val walletManagersFacade: WalletManagersFacade,
|
private val walletManagersFacade: WalletManagersFacade,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||||
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
) : YieldSupplyRepository {
|
) : YieldSupplyRepository {
|
||||||
|
|
||||||
private val statusMap: MutableMap<String, YieldSupplyEnterStatus> = ConcurrentHashMap()
|
private val statusMap: MutableMap<String, YieldSupplyEnterStatus> = ConcurrentHashMap()
|
||||||
|
|
@ -174,10 +179,18 @@ internal class DefaultYieldSupplyRepository(
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Set<TxInfo>.hasYieldEnterTransactions(yieldAddress: String) = any { txInfo ->
|
override fun getShouldShowYieldPromoBanner(): Flow<Boolean> {
|
||||||
txInfo.type is TxInfo.TransactionType.YieldSupply.Enter ||
|
return appPreferencesStore.get(PreferencesKeys.YIELD_SUPPLY_SHOULD_SHOW_MAIN_PROMO_KEY, true)
|
||||||
txInfo.type == TxInfo.TransactionType.Approve &&
|
}
|
||||||
(txInfo.interactionAddressType as? TxInfo.InteractionAddressType.Contract)?.address == yieldAddress
|
|
||||||
|
override suspend fun setShouldShowYieldPromoBanner(shouldShow: Boolean) {
|
||||||
|
appPreferencesStore.store(PreferencesKeys.YIELD_SUPPLY_SHOULD_SHOW_MAIN_PROMO_KEY, shouldShow)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Set<TxInfo>.hasYieldEnterTransactions(yieldAddress: String) = any {
|
||||||
|
it.type == TxInfo.TransactionType.YieldSupply.Enter ||
|
||||||
|
it.type == TxInfo.TransactionType.Approve &&
|
||||||
|
(it.interactionAddressType as? TxInfo.InteractionAddressType.Contract)?.address == yieldAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Set<TxInfo>.hasYieldExitTransactions() = any {
|
private fun Set<TxInfo>.hasYieldExitTransactions() = any {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.tangem.data.yield.supply.DefaultYieldSupplyRepository
|
||||||
import com.tangem.data.yield.supply.DefaultYieldSupplyErrorResolver
|
import com.tangem.data.yield.supply.DefaultYieldSupplyErrorResolver
|
||||||
import com.tangem.data.yield.supply.DefaultYieldSupplyTransactionRepository
|
import com.tangem.data.yield.supply.DefaultYieldSupplyTransactionRepository
|
||||||
import com.tangem.datasource.api.tangemTech.YieldSupplyApi
|
import com.tangem.datasource.api.tangemTech.YieldSupplyApi
|
||||||
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
|
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
||||||
|
|
@ -41,6 +42,7 @@ internal object YieldSupplyDataModule {
|
||||||
walletManagersFacade: WalletManagersFacade,
|
walletManagersFacade: WalletManagersFacade,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
analyticsExceptionHandler: AnalyticsExceptionHandler,
|
analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||||
|
appPreferencesStore: AppPreferencesStore,
|
||||||
): YieldSupplyRepository {
|
): YieldSupplyRepository {
|
||||||
return DefaultYieldSupplyRepository(
|
return DefaultYieldSupplyRepository(
|
||||||
yieldSupplyApi = yieldSupplyApi,
|
yieldSupplyApi = yieldSupplyApi,
|
||||||
|
|
@ -48,6 +50,7 @@ internal object YieldSupplyDataModule {
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
walletManagersFacade = walletManagersFacade,
|
walletManagersFacade = walletManagersFacade,
|
||||||
analyticsExceptionHandler = analyticsExceptionHandler,
|
analyticsExceptionHandler = analyticsExceptionHandler,
|
||||||
|
appPreferencesStore = appPreferencesStore,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,4 +108,8 @@ interface YieldSupplyRepository {
|
||||||
userWalletId: UserWalletId,
|
userWalletId: UserWalletId,
|
||||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||||
): YieldSupplyEnterStatus?
|
): YieldSupplyEnterStatus?
|
||||||
|
|
||||||
|
fun getShouldShowYieldPromoBanner(): Flow<Boolean>
|
||||||
|
|
||||||
|
suspend fun setShouldShowYieldPromoBanner(shouldShow: Boolean)
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.tangem.domain.yield.supply.usecase
|
||||||
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits a map of APY values per token.
|
* Emits a map of APY values per token.
|
||||||
|
|
@ -15,11 +16,11 @@ class YieldSupplyApyFlowUseCase(
|
||||||
private val yieldSupplyRepository: YieldSupplyRepository,
|
private val yieldSupplyRepository: YieldSupplyRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
operator fun invoke(): Flow<Map<String, String>> {
|
operator fun invoke(): Flow<Map<String, BigDecimal>> {
|
||||||
return yieldSupplyRepository.getMarketsFlow()
|
return yieldSupplyRepository.getMarketsFlow()
|
||||||
.map { yieldMarketTokenList ->
|
.map { yieldMarketTokenList ->
|
||||||
yieldMarketTokenList.filter { it.isActive }.associate { token ->
|
yieldMarketTokenList.filter { it.isActive }.associate { token ->
|
||||||
token.yieldSupplyKey to token.apy.toString()
|
token.yieldSupplyKey to token.apy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.tangem.domain.yield.supply.usecase
|
||||||
|
|
||||||
|
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
class YieldSupplyGetShouldShowMainPromoUseCase(
|
||||||
|
private val yieldSupplyRepository: YieldSupplyRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
operator fun invoke(): Flow<Boolean> {
|
||||||
|
return yieldSupplyRepository.getShouldShowYieldPromoBanner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.tangem.domain.yield.supply.usecase
|
||||||
|
|
||||||
|
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
||||||
|
|
||||||
|
class YieldSupplySetShouldShowMainPromoUseCase(
|
||||||
|
private val yieldSupplyRepository: YieldSupplyRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(shouldShow: Boolean) {
|
||||||
|
yieldSupplyRepository.setShouldShowYieldPromoBanner(shouldShow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ import com.tangem.domain.tokens.model.details.NavigationAction
|
||||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyEnterStatusUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyEnterStatusUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplySetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory
|
import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
|
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
|
||||||
|
|
@ -52,6 +53,8 @@ internal interface WalletContentClickIntents {
|
||||||
|
|
||||||
fun onApyLabelClick(userWalletId: UserWalletId, currencyStatus: CryptoCurrencyStatus, apy: String)
|
fun onApyLabelClick(userWalletId: UserWalletId, currencyStatus: CryptoCurrencyStatus, apy: String)
|
||||||
|
|
||||||
|
fun onYieldPromoCloseClick()
|
||||||
|
|
||||||
fun onAccountExpandClick(account: Account)
|
fun onAccountExpandClick(account: Account)
|
||||||
|
|
||||||
fun onAccountCollapseClick(account: Account)
|
fun onAccountCollapseClick(account: Account)
|
||||||
|
|
@ -89,6 +92,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor(
|
||||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||||
private val accountDependencies: AccountDependencies,
|
private val accountDependencies: AccountDependencies,
|
||||||
private val yieldSupplyEnterStatusUseCase: YieldSupplyEnterStatusUseCase,
|
private val yieldSupplyEnterStatusUseCase: YieldSupplyEnterStatusUseCase,
|
||||||
|
private val yieldSupplySetShouldShowMainPromoUseCase: YieldSupplySetShouldShowMainPromoUseCase,
|
||||||
) : BaseWalletClickIntents(), WalletContentClickIntents {
|
) : BaseWalletClickIntents(), WalletContentClickIntents {
|
||||||
|
|
||||||
override fun onDetailsClick() {
|
override fun onDetailsClick() {
|
||||||
|
|
@ -182,6 +186,12 @@ internal class WalletContentClickIntentsImplementor @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onYieldPromoCloseClick() {
|
||||||
|
modelScope.launch {
|
||||||
|
yieldSupplySetShouldShowMainPromoUseCase(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onAccountExpandClick(account: Account) {
|
override fun onAccountExpandClick(account: Account) {
|
||||||
val userWalletId = stateHolder.getSelectedWalletId()
|
val userWalletId = stateHolder.getSelectedWalletId()
|
||||||
accountDependencies.expandedAccountsHolder.expandAccount(userWalletId, account.accountId)
|
accountDependencies.expandedAccountsHolder.expandAccount(userWalletId, account.accountId)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||||
|
|
@ -45,6 +46,7 @@ internal class MultiWalletContentLoader(
|
||||||
private val currenciesRepository: CurrenciesRepository,
|
private val currenciesRepository: CurrenciesRepository,
|
||||||
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
||||||
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
||||||
|
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
||||||
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
|
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
|
||||||
|
|
@ -63,6 +65,7 @@ internal class MultiWalletContentLoader(
|
||||||
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
|
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
|
||||||
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
||||||
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
||||||
|
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
).let(::add)
|
).let(::add)
|
||||||
|
|
||||||
WalletNFTListSubscriber(
|
WalletNFTListSubscriber(
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||||
|
|
@ -44,6 +45,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
|
||||||
private val currenciesRepository: CurrenciesRepository,
|
private val currenciesRepository: CurrenciesRepository,
|
||||||
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
||||||
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
||||||
|
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
||||||
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
|
private val tangemPayMainSubscriberFactory: TangemPayMainSubscriber.Factory,
|
||||||
|
|
@ -72,6 +74,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
|
||||||
hotWalletFeatureToggles = hotWalletFeatureToggles,
|
hotWalletFeatureToggles = hotWalletFeatureToggles,
|
||||||
tangemPayFeatureToggles = tangemPayFeatureToggles,
|
tangemPayFeatureToggles = tangemPayFeatureToggles,
|
||||||
tangemPayMainSubscriberFactory = tangemPayMainSubscriberFactory,
|
tangemPayMainSubscriberFactory = tangemPayMainSubscriberFactory,
|
||||||
|
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.promo.GetStoryContentUseCase
|
||||||
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
||||||
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||||
|
|
@ -35,6 +36,7 @@ internal class SingleWalletWithTokenContentLoader(
|
||||||
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
||||||
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
||||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||||
|
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
) : WalletContentLoader(id = userWallet.walletId) {
|
) : WalletContentLoader(id = userWallet.walletId) {
|
||||||
|
|
||||||
override fun create(): List<WalletSubscriber> {
|
override fun create(): List<WalletSubscriber> {
|
||||||
|
|
@ -49,6 +51,7 @@ internal class SingleWalletWithTokenContentLoader(
|
||||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||||
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
||||||
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
||||||
|
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
).let(::add)
|
).let(::add)
|
||||||
MultiWalletWarningsSubscriber(
|
MultiWalletWarningsSubscriber(
|
||||||
userWallet = userWallet,
|
userWallet = userWallet,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.promo.GetStoryContentUseCase
|
||||||
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
||||||
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||||
|
|
@ -36,6 +37,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
|
||||||
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
||||||
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
||||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||||
|
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader {
|
fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader {
|
||||||
|
|
@ -55,6 +57,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
|
||||||
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
||||||
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
||||||
hotWalletFeatureToggles = hotWalletFeatureToggles,
|
hotWalletFeatureToggles = hotWalletFeatureToggles,
|
||||||
|
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,14 +11,16 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.converte
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TokenListStateConverter
|
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TokenListStateConverter
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.enableButtons
|
import com.tangem.feature.wallet.presentation.wallet.state.utils.enableButtons
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
internal class SetTokenListTransformer(
|
internal class SetTokenListTransformer(
|
||||||
private val params: TokenConverterParams,
|
private val params: TokenConverterParams,
|
||||||
private val userWallet: UserWallet,
|
private val userWallet: UserWallet,
|
||||||
private val appCurrency: AppCurrency,
|
private val appCurrency: AppCurrency,
|
||||||
private val clickIntents: WalletClickIntents,
|
private val clickIntents: WalletClickIntents,
|
||||||
private val yieldSupplyApyMap: Map<String, String> = emptyMap(),
|
private val yieldSupplyApyMap: Map<String, BigDecimal> = emptyMap(),
|
||||||
private val stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
private val stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
||||||
|
private val shouldShowMainPromo: Boolean,
|
||||||
) : WalletStateTransformer(userWallet.walletId) {
|
) : WalletStateTransformer(userWallet.walletId) {
|
||||||
|
|
||||||
override fun transform(prevState: WalletState): WalletState {
|
override fun transform(prevState: WalletState): WalletState {
|
||||||
|
|
@ -63,6 +65,7 @@ internal class SetTokenListTransformer(
|
||||||
clickIntents = clickIntents,
|
clickIntents = clickIntents,
|
||||||
yieldModuleApyMap = yieldSupplyApyMap,
|
yieldModuleApyMap = yieldSupplyApyMap,
|
||||||
stakingApyMap = stakingApyMap,
|
stakingApyMap = stakingApyMap,
|
||||||
|
shouldShowMainPromo = shouldShowMainPromo,
|
||||||
).convert(value = this)
|
).convert(value = this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -28,17 +28,25 @@ import kotlinx.collections.immutable.PersistentList
|
||||||
import kotlinx.collections.immutable.mutate
|
import kotlinx.collections.immutable.mutate
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toPersistentList
|
import kotlinx.collections.immutable.toPersistentList
|
||||||
|
import java.math.BigDecimal
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.OrganizeTokensButtonConfig as WalletOrganizeTokensButtonConfig
|
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.OrganizeTokensButtonConfig as WalletOrganizeTokensButtonConfig
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
internal class TokenListStateConverter(
|
internal class TokenListStateConverter(
|
||||||
private val appCurrency: AppCurrency,
|
private val appCurrency: AppCurrency,
|
||||||
private val params: TokenConverterParams,
|
private val params: TokenConverterParams,
|
||||||
private val selectedWallet: UserWallet,
|
private val selectedWallet: UserWallet,
|
||||||
private val clickIntents: WalletClickIntents,
|
private val clickIntents: WalletClickIntents,
|
||||||
private val yieldModuleApyMap: Map<String, String>,
|
private val yieldModuleApyMap: Map<String, BigDecimal>,
|
||||||
private val stakingApyMap: Map<String, List<Yield.Validator>>,
|
private val stakingApyMap: Map<String, List<Yield.Validator>>,
|
||||||
|
private val shouldShowMainPromo: Boolean,
|
||||||
) : Converter<WalletTokensListState, WalletTokensListState> {
|
) : Converter<WalletTokensListState, WalletTokensListState> {
|
||||||
|
|
||||||
|
private val yieldSupplyPromoBannerKeyConverter = YieldSupplyPromoBannerKeyConverter(
|
||||||
|
yieldModuleApyMap,
|
||||||
|
shouldShowMainPromo,
|
||||||
|
)
|
||||||
|
|
||||||
private val onTokenClick: (accountId: AccountId?, currencyStatus: CryptoCurrencyStatus) -> Unit =
|
private val onTokenClick: (accountId: AccountId?, currencyStatus: CryptoCurrencyStatus) -> Unit =
|
||||||
{ accountId, currencyStatus ->
|
{ accountId, currencyStatus ->
|
||||||
clickIntents.onTokenItemClick(selectedWallet.walletId, currencyStatus)
|
clickIntents.onTokenItemClick(selectedWallet.walletId, currencyStatus)
|
||||||
|
|
@ -57,10 +65,12 @@ internal class TokenListStateConverter(
|
||||||
private fun tokenStatusConverter(accountId: AccountId? = null) = TokenItemStateConverter(
|
private fun tokenStatusConverter(accountId: AccountId? = null) = TokenItemStateConverter(
|
||||||
appCurrency = appCurrency,
|
appCurrency = appCurrency,
|
||||||
yieldModuleApyMap = yieldModuleApyMap,
|
yieldModuleApyMap = yieldModuleApyMap,
|
||||||
|
yieldSupplyPromoBannerKey = yieldSupplyPromoBannerKeyConverter.convert(params),
|
||||||
stakingApyMap = stakingApyMap,
|
stakingApyMap = stakingApyMap,
|
||||||
onItemClick = { _, status -> onTokenClick(accountId, status) },
|
onItemClick = { _, status -> onTokenClick(accountId, status) },
|
||||||
onItemLongClick = { _, status -> onTokenLongClick(accountId, status) },
|
onItemLongClick = { _, status -> onTokenLongClick(accountId, status) },
|
||||||
onApyLabelClick = { status, apy -> onApyLabelClick(status, apy) },
|
onApyLabelClick = { status, apy -> onApyLabelClick(status, apy) },
|
||||||
|
onYieldPromoCloseClick = clickIntents::onYieldPromoCloseClick,
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun convert(value: WalletTokensListState): WalletTokensListState {
|
override fun convert(value: WalletTokensListState): WalletTokensListState {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
|
||||||
|
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
import com.tangem.domain.models.currency.yieldSupplyKey
|
||||||
|
import com.tangem.feature.wallet.presentation.wallet.state.transformers.TokenConverterParams
|
||||||
|
import com.tangem.lib.crypto.BlockchainUtils
|
||||||
|
import com.tangem.utils.converter.Converter
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
internal class YieldSupplyPromoBannerKeyConverter(
|
||||||
|
private val yieldModuleApyMap: Map<String, BigDecimal>,
|
||||||
|
private val shouldShowMainPromo: Boolean,
|
||||||
|
) : Converter<TokenConverterParams, String?> {
|
||||||
|
|
||||||
|
override fun convert(value: TokenConverterParams): String? {
|
||||||
|
if (!shouldShowMainPromo) return null
|
||||||
|
|
||||||
|
val currencies = when (value) {
|
||||||
|
is TokenConverterParams.Wallet -> value.tokenList.flattenCurrencies()
|
||||||
|
is TokenConverterParams.Account -> value.accountList.flattenCurrencies()
|
||||||
|
}.filter { status ->
|
||||||
|
status.value is CryptoCurrencyStatus.Loaded ||
|
||||||
|
status.value is CryptoCurrencyStatus.Custom
|
||||||
|
}
|
||||||
|
|
||||||
|
val tokens = currencies.filter { it.currency is CryptoCurrency.Token }
|
||||||
|
|
||||||
|
if (tokens.any { it.value.yieldSupplyStatus?.isActive == true }) return null
|
||||||
|
if (yieldModuleApyMap.isEmpty()) return null
|
||||||
|
|
||||||
|
val max = tokens.asSequence()
|
||||||
|
.mapNotNull { status ->
|
||||||
|
val token = status.currency as? CryptoCurrency.Token ?: return@mapNotNull null
|
||||||
|
val tokenKey = token.yieldSupplyKey()
|
||||||
|
val shouldIgnoreCase = BlockchainUtils.isCaseInsensitiveContractAddress(token.network.rawId)
|
||||||
|
|
||||||
|
val matchedKey = yieldModuleApyMap.keys.firstOrNull { mapKey ->
|
||||||
|
mapKey.equals(tokenKey, shouldIgnoreCase)
|
||||||
|
} ?: return@mapNotNull null
|
||||||
|
|
||||||
|
status to matchedKey
|
||||||
|
}
|
||||||
|
.maxByOrNull { (status, _) -> status.value.amount ?: BigDecimal.ZERO }
|
||||||
|
|
||||||
|
return max?.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,16 +5,18 @@ import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.staking.model.stakekit.Yield
|
import com.tangem.domain.staking.model.stakekit.Yield
|
||||||
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||||
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
import com.tangem.feature.wallet.presentation.account.AccountDependencies
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||||
import com.tangem.utils.coroutines.combine6
|
import com.tangem.utils.coroutines.combine7
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscriber that monitors account list related data and updates the wallet state accordingly.
|
* Subscriber that monitors account list related data and updates the wallet state accordingly.
|
||||||
|
|
@ -30,19 +32,21 @@ internal class AccountListSubscriber @AssistedInject constructor(
|
||||||
override val clickIntents: WalletClickIntents,
|
override val clickIntents: WalletClickIntents,
|
||||||
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
||||||
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
||||||
|
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
) : BasicAccountListSubscriber() {
|
) : BasicAccountListSubscriber() {
|
||||||
|
|
||||||
override fun create(coroutineScope: CoroutineScope): Flow<*> = combine6(
|
override fun create(coroutineScope: CoroutineScope): Flow<*> = combine7(
|
||||||
flow1 = getAccountStatusListFlow(),
|
flow1 = getAccountStatusListFlow(),
|
||||||
flow2 = getAppCurrencyFlow(),
|
flow2 = getAppCurrencyFlow(),
|
||||||
flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet),
|
flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet),
|
||||||
flow4 = accountDependencies.isAccountsModeEnabledUseCase(),
|
flow4 = accountDependencies.isAccountsModeEnabledUseCase(),
|
||||||
flow5 = yieldSupplyApyFlow(),
|
flow5 = yieldSupplyApyFlow(),
|
||||||
flow6 = stakingApyFlow(),
|
flow6 = stakingApyFlow(),
|
||||||
|
flow7 = yieldSupplyGetShouldShowMainPromoFlow(),
|
||||||
transform = ::updateState,
|
transform = ::updateState,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun yieldSupplyApyFlow(): Flow<Map<String, String>> {
|
private fun yieldSupplyApyFlow(): Flow<Map<String, BigDecimal>> {
|
||||||
return yieldSupplyApyFlowUseCase().distinctUntilChanged()
|
return yieldSupplyApyFlowUseCase().distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,6 +54,10 @@ internal class AccountListSubscriber @AssistedInject constructor(
|
||||||
return stakingApyFlowUseCase().distinctUntilChanged()
|
return stakingApyFlowUseCase().distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun yieldSupplyGetShouldShowMainPromoFlow(): Flow<Boolean> {
|
||||||
|
return yieldSupplyGetShouldShowMainPromoUseCase().distinctUntilChanged()
|
||||||
|
}
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(userWallet: UserWallet): AccountListSubscriber
|
fun create(userWallet: UserWallet): AccountListSubscriber
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.TokenCon
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic implementation of [WalletSubscriber] for wallet with accounts.
|
* Basic implementation of [WalletSubscriber] for wallet with accounts.
|
||||||
|
|
@ -46,8 +47,9 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
||||||
appCurrency: AppCurrency,
|
appCurrency: AppCurrency,
|
||||||
expandedAccounts: Set<AccountId>,
|
expandedAccounts: Set<AccountId>,
|
||||||
isAccountMode: Boolean,
|
isAccountMode: Boolean,
|
||||||
yieldSupplyApyMap: Map<String, String> = emptyMap(),
|
yieldSupplyApyMap: Map<String, BigDecimal> = emptyMap(),
|
||||||
stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
||||||
|
shouldShowMainPromo: Boolean = false,
|
||||||
) {
|
) {
|
||||||
val accountFlattenCurrencies = accountList.flattenCurrencies()
|
val accountFlattenCurrencies = accountList.flattenCurrencies()
|
||||||
val mainAccount = accountList.mainAccount
|
val mainAccount = accountList.mainAccount
|
||||||
|
|
@ -67,6 +69,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
||||||
portfolioId = PortfolioId(mainAccount.accountId),
|
portfolioId = PortfolioId(mainAccount.accountId),
|
||||||
yieldSupplyApyMap = yieldSupplyApyMap,
|
yieldSupplyApyMap = yieldSupplyApyMap,
|
||||||
stakingApyMap = stakingApyMap,
|
stakingApyMap = stakingApyMap,
|
||||||
|
shouldShowMainPromo = shouldShowMainPromo,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
isAccountMode -> {
|
isAccountMode -> {
|
||||||
|
|
@ -82,7 +85,13 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
||||||
} else {
|
} else {
|
||||||
val convertParams = TokenConverterParams.Account(accountList, expandedAccounts)
|
val convertParams = TokenConverterParams.Account(accountList, expandedAccounts)
|
||||||
|
|
||||||
updateContent(convertParams, appCurrency, yieldSupplyApyMap, stakingApyMap)
|
updateContent(
|
||||||
|
params = convertParams,
|
||||||
|
appCurrency = appCurrency,
|
||||||
|
yieldSupplyApyMap = yieldSupplyApyMap,
|
||||||
|
stakingApyMap = stakingApyMap,
|
||||||
|
shouldShowMainPromo = shouldShowMainPromo,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -92,8 +101,9 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
||||||
maybeTokenList: Lce<TokenListError, TokenList>,
|
maybeTokenList: Lce<TokenListError, TokenList>,
|
||||||
appCurrency: AppCurrency,
|
appCurrency: AppCurrency,
|
||||||
portfolioId: PortfolioId,
|
portfolioId: PortfolioId,
|
||||||
yieldSupplyApyMap: Map<String, String> = emptyMap(),
|
yieldSupplyApyMap: Map<String, BigDecimal> = emptyMap(),
|
||||||
stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
||||||
|
shouldShowMainPromo: Boolean,
|
||||||
) {
|
) {
|
||||||
val tokenList = maybeTokenList.getOrElse(
|
val tokenList = maybeTokenList.getOrElse(
|
||||||
ifLoading = { maybeContent ->
|
ifLoading = { maybeContent ->
|
||||||
|
|
@ -123,14 +133,16 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
||||||
appCurrency = appCurrency,
|
appCurrency = appCurrency,
|
||||||
yieldSupplyApyMap = yieldSupplyApyMap,
|
yieldSupplyApyMap = yieldSupplyApyMap,
|
||||||
stakingApyMap = stakingApyMap,
|
stakingApyMap = stakingApyMap,
|
||||||
|
shouldShowMainPromo = shouldShowMainPromo,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateContent(
|
private fun updateContent(
|
||||||
params: TokenConverterParams,
|
params: TokenConverterParams,
|
||||||
appCurrency: AppCurrency,
|
appCurrency: AppCurrency,
|
||||||
yieldSupplyApyMap: Map<String, String> = emptyMap(),
|
yieldSupplyApyMap: Map<String, BigDecimal> = emptyMap(),
|
||||||
stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
stakingApyMap: Map<String, List<Yield.Validator>> = emptyMap(),
|
||||||
|
shouldShowMainPromo: Boolean,
|
||||||
) {
|
) {
|
||||||
stateController.update(
|
stateController.update(
|
||||||
SetTokenListTransformer(
|
SetTokenListTransformer(
|
||||||
|
|
@ -140,6 +152,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() {
|
||||||
clickIntents = clickIntents,
|
clickIntents = clickIntents,
|
||||||
yieldSupplyApyMap = yieldSupplyApyMap,
|
yieldSupplyApyMap = yieldSupplyApyMap,
|
||||||
stakingApyMap = stakingApyMap,
|
stakingApyMap = stakingApyMap,
|
||||||
|
shouldShowMainPromo = shouldShowMainPromo,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import com.tangem.domain.staking.model.stakekit.Yield
|
||||||
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
||||||
import com.tangem.domain.tokens.error.TokenListError
|
import com.tangem.domain.tokens.error.TokenListError
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
|
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
|
||||||
|
|
@ -28,6 +29,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
@Deprecated("Use AccountListSubscriber instead")
|
@Deprecated("Use AccountListSubscriber instead")
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
|
|
@ -40,6 +42,7 @@ internal abstract class BasicTokenListSubscriber(
|
||||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||||
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
||||||
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
|
||||||
|
private val yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
) : WalletSubscriber() {
|
) : WalletSubscriber() {
|
||||||
|
|
||||||
private val sendAnalyticsJobHolder = JobHolder()
|
private val sendAnalyticsJobHolder = JobHolder()
|
||||||
|
|
@ -69,7 +72,8 @@ internal abstract class BasicTokenListSubscriber(
|
||||||
flow2 = appCurrencyFlow(),
|
flow2 = appCurrencyFlow(),
|
||||||
flow3 = yieldSupplyApyFlow(),
|
flow3 = yieldSupplyApyFlow(),
|
||||||
flow4 = stakingApyFlow(),
|
flow4 = stakingApyFlow(),
|
||||||
transform = { maybeTokenList, appCurrency, yieldSupplyApyMap, stakingApyMap ->
|
flow5 = yieldSupplyGetShouldShowMainPromoFlow(),
|
||||||
|
transform = { maybeTokenList, appCurrency, yieldSupplyApyMap, stakingApyMap, shouldShowMainPromo ->
|
||||||
val tokenList = maybeTokenList.getOrElse(
|
val tokenList = maybeTokenList.getOrElse(
|
||||||
ifLoading = { maybeContent ->
|
ifLoading = { maybeContent ->
|
||||||
val isRefreshing = stateHolder.getWalletState(userWallet.walletId)
|
val isRefreshing = stateHolder.getWalletState(userWallet.walletId)
|
||||||
|
|
@ -98,6 +102,7 @@ internal abstract class BasicTokenListSubscriber(
|
||||||
appCurrency = appCurrency,
|
appCurrency = appCurrency,
|
||||||
yieldSupplyApyMap = yieldSupplyApyMap,
|
yieldSupplyApyMap = yieldSupplyApyMap,
|
||||||
stakingApyMap = stakingApyMap,
|
stakingApyMap = stakingApyMap,
|
||||||
|
shouldShowMainPromo = shouldShowMainPromo,
|
||||||
)
|
)
|
||||||
|
|
||||||
walletWithFundsChecker.check(tokenList)
|
walletWithFundsChecker.check(tokenList)
|
||||||
|
|
@ -122,8 +127,9 @@ internal abstract class BasicTokenListSubscriber(
|
||||||
private fun updateContent(
|
private fun updateContent(
|
||||||
params: TokenConverterParams,
|
params: TokenConverterParams,
|
||||||
appCurrency: AppCurrency,
|
appCurrency: AppCurrency,
|
||||||
yieldSupplyApyMap: Map<String, String>,
|
yieldSupplyApyMap: Map<String, BigDecimal>,
|
||||||
stakingApyMap: Map<String, List<Yield.Validator>>,
|
stakingApyMap: Map<String, List<Yield.Validator>>,
|
||||||
|
shouldShowMainPromo: Boolean,
|
||||||
) {
|
) {
|
||||||
stateHolder.update(
|
stateHolder.update(
|
||||||
SetTokenListTransformer(
|
SetTokenListTransformer(
|
||||||
|
|
@ -133,6 +139,7 @@ internal abstract class BasicTokenListSubscriber(
|
||||||
clickIntents = clickIntents,
|
clickIntents = clickIntents,
|
||||||
yieldSupplyApyMap = yieldSupplyApyMap,
|
yieldSupplyApyMap = yieldSupplyApyMap,
|
||||||
stakingApyMap = stakingApyMap,
|
stakingApyMap = stakingApyMap,
|
||||||
|
shouldShowMainPromo = shouldShowMainPromo,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -146,9 +153,12 @@ internal abstract class BasicTokenListSubscriber(
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
|
|
||||||
private fun yieldSupplyApyFlow(): Flow<Map<String, String>> = yieldSupplyApyFlowUseCase()
|
private fun yieldSupplyApyFlow(): Flow<Map<String, BigDecimal>> = yieldSupplyApyFlowUseCase()
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
|
|
||||||
private fun stakingApyFlow(): Flow<Map<String, List<Yield.Validator>>> = stakingApyFlowUseCase()
|
private fun stakingApyFlow(): Flow<Map<String, List<Yield.Validator>>> = stakingApyFlowUseCase()
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
|
|
||||||
|
private fun yieldSupplyGetShouldShowMainPromoFlow(): Flow<Boolean> = yieldSupplyGetShouldShowMainPromoUseCase()
|
||||||
|
.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
||||||
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
|
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
|
||||||
import com.tangem.domain.tokens.error.TokenListError
|
import com.tangem.domain.tokens.error.TokenListError
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
|
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
|
||||||
|
|
@ -32,6 +33,7 @@ internal class MultiWalletTokenListSubscriber(
|
||||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||||
yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
||||||
stakingApyFlowUseCase: StakingApyFlowUseCase,
|
stakingApyFlowUseCase: StakingApyFlowUseCase,
|
||||||
|
yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
) : BasicTokenListSubscriber(
|
) : BasicTokenListSubscriber(
|
||||||
userWallet = userWallet,
|
userWallet = userWallet,
|
||||||
stateHolder = stateHolder,
|
stateHolder = stateHolder,
|
||||||
|
|
@ -41,6 +43,7 @@ internal class MultiWalletTokenListSubscriber(
|
||||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||||
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
||||||
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
||||||
|
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
|
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
||||||
import com.tangem.domain.tokens.error.TokenListError
|
import com.tangem.domain.tokens.error.TokenListError
|
||||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetShouldShowMainPromoUseCase
|
||||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
|
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
|
||||||
|
|
@ -27,6 +28,7 @@ internal class SingleWalletWithTokenListSubscriber(
|
||||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||||
yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
|
||||||
stakingApyFlowUseCase: StakingApyFlowUseCase,
|
stakingApyFlowUseCase: StakingApyFlowUseCase,
|
||||||
|
yieldSupplyGetShouldShowMainPromoUseCase: YieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
) : BasicTokenListSubscriber(
|
) : BasicTokenListSubscriber(
|
||||||
userWallet = userWallet,
|
userWallet = userWallet,
|
||||||
stateHolder = stateHolder,
|
stateHolder = stateHolder,
|
||||||
|
|
@ -36,6 +38,7 @@ internal class SingleWalletWithTokenListSubscriber(
|
||||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||||
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
|
||||||
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
stakingApyFlowUseCase = stakingApyFlowUseCase,
|
||||||
|
yieldSupplyGetShouldShowMainPromoUseCase = yieldSupplyGetShouldShowMainPromoUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
|
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,208 @@
|
||||||
|
package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import com.tangem.domain.models.PortfolioId
|
||||||
|
import com.tangem.domain.models.StatusSource
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
import com.tangem.domain.models.currency.yieldSupplyKey
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.network.NetworkAddress
|
||||||
|
import com.tangem.domain.models.tokenlist.TokenList
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
|
||||||
|
import com.tangem.feature.wallet.presentation.wallet.state.transformers.TokenConverterParams
|
||||||
|
import org.junit.Test
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
class YieldSupplyPromoBannerKeyConverterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN promo disabled WHEN convert THEN return null`() {
|
||||||
|
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xABCDEF")
|
||||||
|
val status = createStatus(token = token, amount = BigDecimal.ONE, isYieldActive = false)
|
||||||
|
val tokenList = ungroupedTokenList(status)
|
||||||
|
val params = TokenConverterParams.Wallet(
|
||||||
|
portfolioId = PortfolioId.Wallet(UserWalletId("00")),
|
||||||
|
tokenList = tokenList,
|
||||||
|
)
|
||||||
|
val converter = YieldSupplyPromoBannerKeyConverter(
|
||||||
|
yieldModuleApyMap = mapOf(token.yieldSupplyKey() to BigDecimal("0.10")),
|
||||||
|
shouldShowMainPromo = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = converter.convert(params)
|
||||||
|
|
||||||
|
assertThat(result).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN empty apy map WHEN convert THEN return null`() {
|
||||||
|
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xA1")
|
||||||
|
val status = createStatus(token = token, amount = BigDecimal("2.0"), isYieldActive = false)
|
||||||
|
val params = TokenConverterParams.Wallet(
|
||||||
|
portfolioId = PortfolioId.Wallet(UserWalletId("00")),
|
||||||
|
tokenList = ungroupedTokenList(status),
|
||||||
|
)
|
||||||
|
val converter = YieldSupplyPromoBannerKeyConverter(
|
||||||
|
yieldModuleApyMap = emptyMap(),
|
||||||
|
shouldShowMainPromo = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = converter.convert(params)
|
||||||
|
|
||||||
|
assertThat(result).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN active yield token present WHEN convert THEN return null`() {
|
||||||
|
val token = createToken(networkId = "ethereum", backendId = "ethereum", contract = "0xAA")
|
||||||
|
val statusActive = createStatus(token = token, amount = BigDecimal("5"), isYieldActive = true)
|
||||||
|
val params = TokenConverterParams.Wallet(
|
||||||
|
portfolioId = PortfolioId.Wallet(UserWalletId("00")),
|
||||||
|
tokenList = ungroupedTokenList(statusActive),
|
||||||
|
)
|
||||||
|
val converter = YieldSupplyPromoBannerKeyConverter(
|
||||||
|
yieldModuleApyMap = mapOf(token.yieldSupplyKey() to BigDecimal("0.12")),
|
||||||
|
shouldShowMainPromo = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = converter.convert(params)
|
||||||
|
|
||||||
|
assertThat(result).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN multiple candidates EVM case insensitive WHEN convert THEN return key of max amount`() {
|
||||||
|
val evmNetworkId = "ETH"
|
||||||
|
val tokenSmall = createToken(networkId = evmNetworkId, backendId = evmNetworkId, contract = "0xAbCd")
|
||||||
|
val tokenBig = createToken(networkId = evmNetworkId, backendId = evmNetworkId, contract = "0xBEEF")
|
||||||
|
|
||||||
|
val statusSmall = createStatus(token = tokenSmall, amount = BigDecimal("1.00"), isYieldActive = false)
|
||||||
|
val statusBig = createStatus(token = tokenBig, amount = BigDecimal("10.00"), isYieldActive = false)
|
||||||
|
|
||||||
|
val apyMap = mapOf(
|
||||||
|
"${tokenSmall.network.backendId}_${tokenSmall.contractAddress.lowercase()}" to BigDecimal("0.05"),
|
||||||
|
"${tokenBig.network.backendId}_${tokenBig.contractAddress.uppercase()}" to BigDecimal("0.15"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val params = TokenConverterParams.Wallet(
|
||||||
|
portfolioId = PortfolioId.Wallet(UserWalletId("00")),
|
||||||
|
tokenList = ungroupedTokenList(statusSmall, statusBig),
|
||||||
|
)
|
||||||
|
val converter = YieldSupplyPromoBannerKeyConverter(
|
||||||
|
yieldModuleApyMap = apyMap,
|
||||||
|
shouldShowMainPromo = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = converter.convert(params)
|
||||||
|
|
||||||
|
val expectedKey = "${tokenBig.network.backendId}_${tokenBig.contractAddress.uppercase()}"
|
||||||
|
assertThat(result).isEqualTo(expectedKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN non evm case sensitive mismatch WHEN convert THEN return null`() {
|
||||||
|
val nonEvmId = "xrp"
|
||||||
|
val token = createToken(networkId = nonEvmId, backendId = nonEvmId, contract = "rAbC123")
|
||||||
|
val status = createStatus(token = token, amount = BigDecimal("3"), isYieldActive = false)
|
||||||
|
|
||||||
|
val mismatchedKey = "${token.network.backendId}_${token.contractAddress.lowercase()}"
|
||||||
|
val apyMap = mapOf(mismatchedKey to BigDecimal("0.07"))
|
||||||
|
|
||||||
|
val params = TokenConverterParams.Wallet(
|
||||||
|
portfolioId = PortfolioId.Wallet(UserWalletId("00")),
|
||||||
|
tokenList = ungroupedTokenList(status),
|
||||||
|
)
|
||||||
|
val converter = YieldSupplyPromoBannerKeyConverter(
|
||||||
|
yieldModuleApyMap = apyMap,
|
||||||
|
shouldShowMainPromo = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = converter.convert(params)
|
||||||
|
|
||||||
|
assertThat(result).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ungroupedTokenList(vararg statuses: CryptoCurrencyStatus): TokenList.Ungrouped {
|
||||||
|
return TokenList.Ungrouped(
|
||||||
|
totalFiatBalance = com.tangem.domain.models.TotalFiatBalance.Loaded(
|
||||||
|
amount = BigDecimal.ZERO,
|
||||||
|
source = StatusSource.ACTUAL,
|
||||||
|
),
|
||||||
|
sortedBy = com.tangem.domain.models.TokensSortType.NONE,
|
||||||
|
currencies = statuses.toList(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createStatus(
|
||||||
|
token: CryptoCurrency.Token,
|
||||||
|
amount: BigDecimal,
|
||||||
|
isYieldActive: Boolean,
|
||||||
|
): CryptoCurrencyStatus {
|
||||||
|
val networkAddress = NetworkAddress.Single(
|
||||||
|
defaultAddress = NetworkAddress.Address(
|
||||||
|
value = "addr",
|
||||||
|
type = NetworkAddress.Address.Type.Primary,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val value = CryptoCurrencyStatus.Custom(
|
||||||
|
amount = amount,
|
||||||
|
fiatAmount = null,
|
||||||
|
fiatRate = null,
|
||||||
|
priceChange = null,
|
||||||
|
yieldBalance = null,
|
||||||
|
yieldSupplyStatus = if (isYieldActive) {
|
||||||
|
YieldSupplyStatus(
|
||||||
|
isActive = true,
|
||||||
|
isInitialized = true,
|
||||||
|
isAllowedToSpend = true,
|
||||||
|
effectiveProtocolBalance = null,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
hasCurrentNetworkTransactions = false,
|
||||||
|
pendingTransactions = emptySet(),
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
)
|
||||||
|
return CryptoCurrencyStatus(
|
||||||
|
currency = token,
|
||||||
|
value = value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createToken(networkId: String, backendId: String, contract: String): CryptoCurrency.Token {
|
||||||
|
val network = Network(
|
||||||
|
id = Network.ID(value = networkId, derivationPath = Network.DerivationPath.None),
|
||||||
|
backendId = backendId,
|
||||||
|
name = backendId,
|
||||||
|
currencySymbol = "SYM",
|
||||||
|
derivationPath = Network.DerivationPath.None,
|
||||||
|
isTestnet = false,
|
||||||
|
standardType = when (backendId) {
|
||||||
|
"ethereum" -> Network.StandardType.ERC20
|
||||||
|
else -> Network.StandardType.Unspecified("UNSPEC")
|
||||||
|
},
|
||||||
|
hasFiatFeeRate = false,
|
||||||
|
canHandleTokens = true,
|
||||||
|
transactionExtrasType = Network.TransactionExtrasType.NONE,
|
||||||
|
nameResolvingType = Network.NameResolvingType.NONE,
|
||||||
|
)
|
||||||
|
return CryptoCurrency.Token(
|
||||||
|
id = CryptoCurrency.ID(
|
||||||
|
prefix = CryptoCurrency.ID.Prefix.TOKEN_PREFIX,
|
||||||
|
body = CryptoCurrency.ID.Body.NetworkId(networkId),
|
||||||
|
suffix = CryptoCurrency.ID.Suffix.ContractAddress(contract),
|
||||||
|
),
|
||||||
|
network = network,
|
||||||
|
name = "Token",
|
||||||
|
symbol = "TKN",
|
||||||
|
decimals = 18,
|
||||||
|
iconUrl = null,
|
||||||
|
isCustom = false,
|
||||||
|
contractAddress = contract,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue