Updated on 2026-08-14

This commit is contained in:
Tangem 2024-11-28 20:08:28 +04:00
parent 9378e4fa31
commit d7d50b086a
23 changed files with 291 additions and 74 deletions

View file

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="action_buttons_buy_empty_search_message">Token nicht in Deinem Portfolio gefunden? Überprüfe die Märkte, um es zu finden und zum Kauf hinzuzufügen</string>
<string name="action_buttons_sell_empty_search_message">Token nicht in Deinem Portfolio gefunden? Überprüfe die Märkte, um es zu finden und zum Verkauf hinzuzufügen</string>
<string name="action_buttons_sell_empty_search_message">Token nicht in Ihrem Portfolio gefunden? Überprüfe die Märkte, um es zu finden und zum Verkauf hinzuzufügen</string>
<string name="action_buttons_swap_choose_token">Wähle den Token</string>
<string name="action_buttons_swap_empty_search_message">Token nicht in Deinem Portfolio gefunden? Überprüfe die Märkte, um es für Swaps zu finden und hinzuzufügen</string>
<string name="action_buttons_swap_no_available_pair_notification_message">Es gibt keine verfügbaren Token, die mit dem ausgewählten Token getauscht werden können. Bitte wähle einen anderen.</string>
<string name="action_buttons_swap_no_available_pair_notification_title">Kein verfügbares Paar</string>
<string name="action_buttons_you_want_to_receive">Du möchtest erhalten</string>
<string name="action_buttons_you_want_to_swap">Du möchtest tauschen</string>
<string name="action_buttons_you_want_to_receive">Wähle den Token aus, das Du erhalten möchtest</string>
<string name="action_buttons_you_want_to_swap">Wähle den Token, den Du tauschen möchtest</string>
<string name="add_custom_token_choose_network">Netzwerk wählen</string>
<string name="add_custom_token_title">Token anlegen</string>
<string name="add_tokens_title">Token verwalten</string>

View file

@ -6,8 +6,6 @@
<string name="action_buttons_swap_empty_search_message">¿No encuentras el token en tu billetera? Consulte los mercados para encontrarlo y agregarlo al intercambio</string>
<string name="action_buttons_swap_no_available_pair_notification_message">No hay tokens disponibles para intercambiar con el token seleccionado. Por favor elige otro.</string>
<string name="action_buttons_swap_no_available_pair_notification_title">No hay par disponible</string>
<string name="action_buttons_you_want_to_receive">Desea recibir</string>
<string name="action_buttons_you_want_to_swap">Quiere intercambiar</string>
<string name="add_custom_token_choose_network">Elige red</string>
<string name="add_custom_token_title">Agregue un token personalizado</string>
<string name="add_tokens_title">Gestionar tokens</string>

View file

@ -6,8 +6,6 @@
<string name="action_buttons_swap_empty_search_message">Jeton non trouvé dans votre portefeuille ? Consultez les marchés pour le trouver et l\'ajouter à l\'échange</string>
<string name="action_buttons_swap_no_available_pair_notification_message">Il n\'y a pas de token disponible pour échanger avec le token sélectionné. Veuillez en choisir un autre.</string>
<string name="action_buttons_swap_no_available_pair_notification_title">Aucune paire disponible</string>
<string name="action_buttons_you_want_to_receive">Vous souhaitez recevoir</string>
<string name="action_buttons_you_want_to_swap">Vous souhaitez échanger</string>
<string name="add_custom_token_choose_network">Choisissez le réseau</string>
<string name="add_custom_token_title">Ajouter un jeton personnalisé</string>
<string name="add_tokens_title">Gérer les jetons</string>

View file

@ -2,12 +2,13 @@
<resources>
<string name="action_buttons_buy_empty_search_message">ポートフォリオにトークンが見つかりませんか?マーケットから見つけ、買付のために追加してください</string>
<string name="action_buttons_sell_empty_search_message">ポートフォリオにトークンが見つかりませんか?マーケットから見つけ、売却のために追加してください</string>
<string name="action_buttons_sell_navigation_bar_title">暗号資産を売却</string>
<string name="action_buttons_swap_choose_token">トークンを選択</string>
<string name="action_buttons_swap_empty_search_message">ポートフォリオにトークンが見つかりませんか?マーケットから見つけ、スワップのために追加してください</string>
<string name="action_buttons_swap_no_available_pair_notification_message">選択したトークンと交換できるトークンがありません。別のトークンを選択してください。</string>
<string name="action_buttons_swap_no_available_pair_notification_title">利用可能なペアがありません</string>
<string name="action_buttons_you_want_to_receive">受け取りたい</string>
<string name="action_buttons_you_want_to_swap">交換したい</string>
<string name="action_buttons_you_want_to_receive">受け取りたいトークンを選択します</string>
<string name="action_buttons_you_want_to_swap">スワップしたいトークンを選択します</string>
<string name="add_custom_token_choose_network">ネットワークを選択</string>
<string name="add_custom_token_title">カスタムトークンの追加</string>
<string name="add_tokens_title">トークンの管理</string>

View file

@ -1,10 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="action_buttons_buy_empty_search_message">Не нашли свой токен? Перейдите в раздел «Рынок» на главной странице и добавьте его в свой портфель для покупки.</string>
<string name="action_buttons_sell_empty_search_message">Не нашли свой токен? Перейдите в раздел «Рынок» на главной странице и добавьте его в свой портфель для продажи.</string>
<string name="action_buttons_sell_navigation_bar_title">Продать криптовалюту</string>
<string name="action_buttons_swap_choose_token">Выберите токен</string>
<string name="action_buttons_swap_no_available_pair_notification_message">Нет доступных токенов для обмена с выбранным токеном, пожалуйста, выберите другой.</string>
<string name="action_buttons_swap_empty_search_message">Не нашли свой токен? Перейдите в раздел «Рынок» на главной странице и добавьте его в свой портфель для обмена.</string>
<string name="action_buttons_swap_no_available_pair_notification_message">Нет доступных вариантов для обмена с выбранным токеном, пожалуйста, выберите другой.</string>
<string name="action_buttons_swap_no_available_pair_notification_title">Нет доступных пар</string>
<string name="action_buttons_you_want_to_receive">Вы хотите получить</string>
<string name="action_buttons_you_want_to_swap">Вы хотите обменять</string>
<string name="action_buttons_you_want_to_receive">Выберите токен для получения</string>
<string name="action_buttons_you_want_to_swap">Выберите токен для обмена</string>
<string name="add_custom_token_choose_network">Выберите сеть</string>
<string name="add_custom_token_title">Добавить токен</string>
<string name="add_tokens_title">Валюты</string>
@ -652,6 +656,10 @@
<string name="scan_card_settings_button">Сканировать</string>
<string name="scan_card_settings_message">Отсканируйте карту или кольцо, чтобы изменить ее настройки. Изменения затронут только ту карту или кольцо, которые вы отсканировали, и не повлияют на другие устройства, привязанные к вашему кошельку.</string>
<string name="scan_card_settings_title">Приготовьте свой Tangem!</string>
<string name="selling_insufficient_balance_alert_message">На вашем балансе недостаточно средств для продажи этой криптовалюты. Пожалуйста, пополните нужный актив, чтобы продолжить.</string>
<string name="selling_insufficient_balance_alert_title">Недостаточно средств</string>
<string name="selling_regional_restriction_alert_message">Продажа криптовалюты в вашем регионе временно недоступна. Мы активно работаем над тем, чтобы добавить эту возможность. Следите за нашими новостями!</string>
<string name="selling_regional_restriction_alert_title">Региональные ограничения</string>
<string name="send_additional_field_already_included">Уже содержится во введенном адресе</string>
<string name="send_alert_fee_too_high_text">Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна.</string>
<string name="send_alert_fee_too_low_text">Вы указали комиссию ниже рекомендуемой, это может привести к задержке исполнения вашей транзакции. Продолжить?</string>

View file

@ -6,8 +6,6 @@
<string name="action_buttons_swap_empty_search_message">Токен не знайдено у вашому портфелі? Перевірте ринки, щоб знайти та додати його для обміну</string>
<string name="action_buttons_swap_no_available_pair_notification_message">Немає доступних токенів для обміну з обраним токеном. Будь ласка, оберіть інший.</string>
<string name="action_buttons_swap_no_available_pair_notification_title">Немає вільної пари</string>
<string name="action_buttons_you_want_to_receive">Ви хочете отримати</string>
<string name="action_buttons_you_want_to_swap">Ви хочете обміняти</string>
<string name="add_custom_token_choose_network">Оберіть мережу</string>
<string name="add_custom_token_title">Додати токен</string>
<string name="add_tokens_title">Токени</string>

View file

@ -1,13 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="action_buttons_buy_empty_search_message">Token not found in your portfolio? Check the Markets to find and add it for purchase</string>
<string name="action_buttons_sell_empty_search_message">Token not found in your portfolio? Check the Markets to find and add it for selling</string>
<string name="action_buttons_buy_empty_search_message">Cant find your token? Go to the Market section on the main page and add it to your portfolio for purchase</string>
<string name="action_buttons_sell_empty_search_message">Cant find your token? Go to the Market section on the main page and add it to your portfolio for selling.</string>
<string name="action_buttons_sell_navigation_bar_title">Sell crypto</string>
<string name="action_buttons_swap_choose_token">Choose the Token</string>
<string name="action_buttons_swap_empty_search_message">Token not found in your portfolio? Check the Markets to find and add it for swap</string>
<string name="action_buttons_swap_empty_search_message">Cant find your token? Go to the Market section on the main page and add it to your portfolio for swapping.</string>
<string name="action_buttons_swap_no_available_pair_notification_message">There are no available tokens to swap with the selected token. Please choose another one.</string>
<string name="action_buttons_swap_no_available_pair_notification_title">No available pair</string>
<string name="action_buttons_you_want_to_receive">You want to Receive</string>
<string name="action_buttons_you_want_to_swap">You want to Swap</string>
<string name="action_buttons_you_want_to_receive">Choose the token you want to receive</string>
<string name="action_buttons_you_want_to_swap">Choose the token you want to swap</string>
<string name="add_custom_token_choose_network">Choose network</string>
<string name="add_custom_token_title">Add custom token</string>
<string name="add_tokens_title">Manage tokens</string>
@ -647,6 +648,10 @@
<string name="scan_card_settings_button">Scan card or ring</string>
<string name="scan_card_settings_message">Scan the card or ring to change its settings. The changes will impact only the card or ring you\'ve scanned and will not affect other devices tied to your wallet.</string>
<string name="scan_card_settings_title">Get your Tangem ready!</string>
<string name="selling_insufficient_balance_alert_message">You dont have enough funds in your balance to sell this cryptocurrency. Please deposit the desired asset to proceed.</string>
<string name="selling_insufficient_balance_alert_title">Insufficient Balance</string>
<string name="selling_regional_restriction_alert_message">Selling cryptocurrency is unavailable in your region at the moment. Were actively working to bring this option to you soon—stay tuned!</string>
<string name="selling_regional_restriction_alert_title">Regional Restriction</string>
<string name="send_additional_field_already_included">Already included in the entered address</string>
<string name="send_alert_fee_too_high_text">Your commission amount is %s times higher than the recommended amount. Please review and adjust your custom settings.</string>
<string name="send_alert_fee_too_low_text">You specified a commission below the recommended amount, which could cause a delay in your transaction. Continue?</string>

View file

@ -35,6 +35,7 @@ internal object WalletPreviewData {
onRenameClick = { _ -> },
onDeleteClick = {},
cardCount = 1,
isZeroBalance = false,
)
}

View file

@ -110,6 +110,7 @@ internal object WalletScreenPreviewData {
balance = DASH_SIGN,
onRenameClick = { _ -> },
onDeleteClick = {},
isZeroBalance = false,
)
}
private val multiWalletState by lazy {

View file

@ -1,7 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.models.UserWallet
@ -11,12 +10,10 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletActionsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletTokenListSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.MultiWalletWarningsSubscriber
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
@Suppress("LongParameterList")
internal class MultiWalletContentLoader(
@ -31,8 +28,6 @@ internal class MultiWalletContentLoader(
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val rampStateManager: RampStateManager,
private val walletFeatureToggles: WalletFeatureToggles,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> {
@ -55,16 +50,6 @@ internal class MultiWalletContentLoader(
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
),
createMultiWalletButtonsSubscriber(),
)
}
private fun createMultiWalletButtonsSubscriber(): MultiWalletActionsSubscriber? {
return MultiWalletActionsSubscriber(
userWallet = userWallet,
rampStateManager = rampStateManager,
stateController = stateHolder,
)
.takeIf { walletFeatureToggles.isMainActionButtonsEnabled }
}
}

View file

@ -1,7 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.models.UserWallet
@ -12,7 +11,6 @@ import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenList
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
import dagger.hilt.android.scopes.ViewModelScoped
import javax.inject.Inject
@ -28,8 +26,6 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val rampStateManager: RampStateManager,
private val walletFeatureToggles: WalletFeatureToggles,
) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): WalletContentLoader {
@ -45,8 +41,6 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
rampStateManager = rampStateManager,
walletFeatureToggles = walletFeatureToggles,
)
}
}

View file

@ -83,4 +83,32 @@ internal sealed interface WalletAlertState {
)
override val onConfirmClick: (() -> Unit)? = null
}
data object ProvidersStillLoading : Basic() {
override val title: TextReference = stringReference(value = "Providers are still loading")
override val message: TextReference = resourceReference(R.string.wallet_connect_toast_awaiting_session_proposal)
override val onConfirmClick: (() -> Unit)? = null
}
data object UnavailableOperation : Basic() {
override val title: TextReference = stringReference(value = "This operation is currently unavailable")
override val message: TextReference = resourceReference(R.string.warning_some_networks_unreachable_message)
override val onConfirmClick: (() -> Unit)? = null
}
data object SellingRegionalRestriction : Basic() {
override val title: TextReference = resourceReference(id = R.string.selling_regional_restriction_alert_title)
override val message: TextReference =
resourceReference(id = R.string.selling_regional_restriction_alert_message)
override val onConfirmClick: (() -> Unit)? = null
}
data object InsufficientBalanceForSelling : Basic() {
override val title: TextReference = resourceReference(id = R.string.selling_insufficient_balance_alert_title)
override val message: TextReference =
resourceReference(id = R.string.selling_insufficient_balance_alert_message)
override val onConfirmClick: (() -> Unit)? = null
}
}

View file

@ -50,6 +50,7 @@ internal sealed interface WalletCardState {
override val onDeleteClick: (UserWalletId) -> Unit,
val cardCount: Int?,
val balance: String,
val isZeroBalance: Boolean?,
) : WalletCardState
/**

View file

@ -0,0 +1,57 @@
package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
import timber.log.Timber
import kotlin.reflect.KClass
/**
* Transformer for disabling action of multi-currency wallet
*
* @param userWalletId user wallet id
* @property actionClass action class that must be disabled
*/
internal class DisableActionTransformer(
userWalletId: UserWalletId,
private val actionClass: KClass<out WalletManageButton>,
) : WalletStateTransformer(userWalletId = userWalletId) {
override fun transform(prevState: WalletState): WalletState {
return when (prevState) {
is WalletState.MultiCurrency.Content -> {
prevState.copy(buttons = prevState.buttons.updateButtons())
}
is WalletState.MultiCurrency.Locked -> {
Timber.w("Impossible to disable action for locked wallet")
prevState
}
is WalletState.SingleCurrency -> {
Timber.w("Impossible to disable action for single-currency wallet")
prevState
}
is WalletState.Visa -> {
Timber.w("Impossible to disable action for VISA wallet")
prevState
}
}
}
private fun PersistentList<WalletManageButton>.updateButtons(): PersistentList<WalletManageButton> {
return map { action ->
if (action::class == actionClass) {
when (action) {
is WalletManageButton.Buy -> action.copy(enabled = false)
is WalletManageButton.Swap -> action.copy(enabled = false)
is WalletManageButton.Sell -> action.copy(enabled = false)
else -> action
}
} else {
action
}
}
.toPersistentList()
}
}

View file

@ -58,7 +58,7 @@ internal class InitializeWalletsTransformer(
multiCurrencyCreator = {
WalletState.MultiCurrency.Locked(
walletCardState = userWallet.toLockedWalletCardState(),
buttons = createMultiWalletDisabledButtons(),
buttons = createMultiWalletEnabledButtons(),
bottomSheetConfig = null,
onUnlockNotificationClick = clickIntents::onOpenUnlockWalletsBottomSheetClick,
)
@ -67,7 +67,7 @@ internal class InitializeWalletsTransformer(
WalletState.SingleCurrency.Locked(
walletCardState = userWallet.toLockedWalletCardState(),
bottomSheetConfig = null,
buttons = createDisabledButtons(),
buttons = createSingleWalletDisabledButtons(),
onUnlockNotificationClick = clickIntents::onOpenUnlockWalletsBottomSheetClick,
onExploreClick = clickIntents::onExploreClick,
)
@ -75,7 +75,7 @@ internal class InitializeWalletsTransformer(
visaWalletCreator = {
WalletState.Visa.Locked(
walletCardState = userWallet.toLockedWalletCardState(),
buttons = createMultiWalletDisabledButtons(),
buttons = createMultiWalletEnabledButtons(),
bottomSheetConfig = null,
onUnlockNotificationClick = clickIntents::onOpenUnlockWalletsBottomSheetClick,
onExploreClick = clickIntents::onExploreClick,
@ -95,18 +95,17 @@ internal class InitializeWalletsTransformer(
)
}
private fun createMultiWalletDisabledButtons(): PersistentList<WalletManageButton> {
private fun createMultiWalletEnabledButtons(): PersistentList<WalletManageButton> {
if (!walletFeatureToggles.isMainActionButtonsEnabled) return persistentListOf()
return persistentListOf(
WalletManageButton.Receive(enabled = false, dimContent = false, onClick = {}, onLongClick = null),
WalletManageButton.Send(enabled = false, dimContent = false, onClick = {}),
WalletManageButton.Buy(enabled = false, dimContent = false, onClick = {}),
WalletManageButton.Swap(enabled = false, dimContent = false, onClick = {}),
WalletManageButton.Sell(enabled = false, dimContent = false, onClick = {}),
)
}
private fun createDisabledButtons(): PersistentList<WalletManageButton> {
private fun createSingleWalletDisabledButtons(): PersistentList<WalletManageButton> {
return persistentListOf(
WalletManageButton.Receive(enabled = false, dimContent = false, onClick = {}, onLongClick = null),
WalletManageButton.Send(enabled = false, dimContent = false, onClick = {}),

View file

@ -14,6 +14,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditiona
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.utils.extensions.isZero
import org.joda.time.DateTime
import org.joda.time.Days
@ -76,6 +77,7 @@ internal class SetBalancesAndLimitsTransformer(
crypto(visaCurrency.symbol, visaCurrency.decimals)
},
cardCount = userWallet.getCardsCount(),
isZeroBalance = visaCurrency.balances.available.isZero(),
)
}
}

View file

@ -9,6 +9,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfo
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.utils.disableButtons
import timber.log.Timber
import java.math.BigDecimal
@ -26,6 +27,11 @@ internal class SetTokenListErrorTransformer(
prevState.copy(
walletCardState = prevState.walletCardState.toLoadedState(),
tokensListState = WalletTokensListState.Empty,
buttons = if (error == TokenListError.EmptyTokens) {
prevState.disableButtons()
} else {
prevState.buttons
},
)
}
is WalletState.MultiCurrency.Locked -> {
@ -62,6 +68,7 @@ internal class SetTokenListErrorTransformer(
fiatCurrencySymbol = appCurrency.symbol,
),
cardCount = selectedWallet.getCardsCount(),
isZeroBalance = true,
)
}
}

View file

@ -8,6 +8,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletCardStateConverter
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.viewmodels.intents.WalletClickIntents
import timber.log.Timber
@ -24,6 +25,7 @@ internal class SetTokenListTransformer(
prevState.copy(
walletCardState = prevState.walletCardState.toLoadedState(),
tokensListState = prevState.tokensListState.toLoadedState(),
buttons = prevState.enableButtons(),
)
}
is WalletState.MultiCurrency.Locked -> {

View file

@ -8,6 +8,7 @@ import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.isZero
internal class MultiWalletCardStateConverter(
private val fiatBalance: TotalFiatBalance,
@ -58,6 +59,7 @@ internal class MultiWalletCardStateConverter(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
),
isZeroBalance = fiatBalance.amount.isZero(),
cardCount = selectedWallet.getCardsCount(),
)
}

View file

@ -8,6 +8,7 @@ import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.isZero
internal class SingleWalletCardStateConverter(
private val status: CryptoCurrencyStatus.Value,
@ -63,6 +64,7 @@ internal class SingleWalletCardStateConverter(
onDeleteClick = onDeleteClick,
balance = formatFiatAmount(status = status, appCurrency = appCurrency),
cardCount = selectedWallet.getCardsCount(),
isZeroBalance = status.fiatAmount?.isZero(),
)
}

View file

@ -0,0 +1,27 @@
package com.tangem.feature.wallet.presentation.wallet.state.utils
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
internal fun WalletState.MultiCurrency.Content.enableButtons(): PersistentList<WalletManageButton> {
return changeAvailability(enabled = true)
}
internal fun WalletState.MultiCurrency.Content.disableButtons(): PersistentList<WalletManageButton> {
return changeAvailability(enabled = false)
}
private fun WalletState.MultiCurrency.Content.changeAvailability(enabled: Boolean): PersistentList<WalletManageButton> {
return buttons
.map { action ->
when (action) {
is WalletManageButton.Buy -> action.copy(enabled = enabled)
is WalletManageButton.Sell -> action.copy(enabled = enabled)
is WalletManageButton.Swap -> action.copy(enabled = enabled)
else -> action
}
}
.toPersistentList()
}

View file

@ -98,18 +98,18 @@ internal class WalletLoadingStateFactory(
return persistentListOf(
WalletManageButton.Buy(
enabled = false,
dimContent = true,
enabled = true,
dimContent = false,
onClick = { clickIntents.onMultiWalletBuyClick(userWalletId = userWallet.walletId) },
),
WalletManageButton.Swap(
enabled = false,
dimContent = true,
enabled = true,
dimContent = false,
onClick = { clickIntents.onMultiWalletSwapClick(userWalletId = userWallet.walletId) },
),
WalletManageButton.Sell(
enabled = false,
dimContent = true,
enabled = true,
dimContent = false,
onClick = { clickIntents.onMultiWalletSellClick(userWalletId = userWallet.walletId) },
),
)

View file

@ -21,9 +21,14 @@ import com.tangem.core.ui.haptic.VibratorHapticManager
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.extenstions.unwrap
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.utils.lceError
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.markets.TokenMarketParams
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
@ -42,17 +47,23 @@ import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAlertState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletManageButton
import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.DisableActionTransformer
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject
import kotlin.reflect.KClass
interface WalletCurrencyActionsClickIntents {
@ -112,6 +123,8 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val vibratorHapticManager: VibratorHapticManager,
private val clipboardManager: ClipboardManager,
private val appRouter: AppRouter,
private val rampStateManager: RampStateManager,
private val getUserCountryUseCase: GetUserCountryUseCase,
) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents {
override fun onSendClick(
@ -441,36 +454,59 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
}
override fun onMultiWalletSellClick(userWalletId: UserWalletId) {
analyticsEventHandler.send(
event = MainScreenAnalyticsEvent.ButtonSell(
status = AnalyticsParam.Status.Success, // TODO [REDACTED_JIRA]
),
)
viewModelScope.launch {
val userCountry = getUserCountryUseCase().getOrNull()
if (userCountry is UserCountry.Russia) {
handleError(
userWalletId = userWalletId,
actionKClass = WalletManageButton.Sell::class,
alertState = WalletAlertState.SellingRegionalRestriction,
eventCreator = MainScreenAnalyticsEvent::ButtonSell,
)
// TODO [REDACTED_JIRA]
appRouter.push(route = AppRoute.SellCrypto(userWalletId = userWalletId))
return@launch
}
val selectedWallet = stateHolder.getSelectedWallet().walletCardState as? WalletCardState.Content
if (selectedWallet?.isZeroBalance == true) {
handleError(
userWalletId = userWalletId,
actionKClass = WalletManageButton.Sell::class,
alertState = WalletAlertState.InsufficientBalanceForSelling,
eventCreator = MainScreenAnalyticsEvent::ButtonSell,
)
return@launch
}
onMultiWalletActionClick(
userWalletId = userWalletId,
statusFlow = rampStateManager.getSellInitializationStatus(),
route = AppRoute.SellCrypto(userWalletId = userWalletId),
actionKClass = WalletManageButton.Sell::class,
eventCreator = MainScreenAnalyticsEvent::ButtonSell,
)
}
}
override fun onMultiWalletSwapClick(userWalletId: UserWalletId) {
analyticsEventHandler.send(
event = MainScreenAnalyticsEvent.ButtonSwap(
status = AnalyticsParam.Status.Success, // TODO [REDACTED_JIRA]
),
onMultiWalletActionClick(
userWalletId = userWalletId,
statusFlow = rampStateManager.getSwapInitializationStatus(userWalletId),
route = AppRoute.SwapCrypto(userWalletId = userWalletId),
actionKClass = WalletManageButton.Swap::class,
eventCreator = MainScreenAnalyticsEvent::ButtonSwap,
)
// TODO [REDACTED_JIRA]
appRouter.push(route = AppRoute.SwapCrypto(userWalletId = userWalletId))
}
override fun onMultiWalletBuyClick(userWalletId: UserWalletId) {
analyticsEventHandler.send(
event = MainScreenAnalyticsEvent.ButtonBuy(
status = AnalyticsParam.Status.Success, // TODO [REDACTED_JIRA]
),
onMultiWalletActionClick(
userWalletId = userWalletId,
statusFlow = rampStateManager.getBuyInitializationStatus(),
route = AppRoute.BuyCrypto(userWalletId = userWalletId),
actionKClass = WalletManageButton.Buy::class,
eventCreator = MainScreenAnalyticsEvent::ButtonBuy,
)
// TODO [REDACTED_JIRA]
appRouter.push(route = AppRoute.BuyCrypto(userWalletId = userWalletId))
}
private fun openExplorer() {
@ -570,4 +606,69 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
return true
}
private fun onMultiWalletActionClick(
userWalletId: UserWalletId,
statusFlow: Flow<Lce<Throwable, Any>>,
route: AppRoute,
actionKClass: KClass<out WalletManageButton>,
eventCreator: (AnalyticsParam.Status) -> MainScreenAnalyticsEvent,
) {
viewModelScope.launch {
statusFlow.foldStatus(
onContent = { handleContent(route, eventCreator) },
onError = {
handleError(
userWalletId = userWalletId,
actionKClass = actionKClass,
eventCreator = eventCreator,
)
},
onLoading = { handleLoading(eventCreator) },
)
}
}
private suspend fun Flow<Lce<Throwable, Any>>.foldStatus(
onContent: () -> Unit,
onError: () -> Unit,
onLoading: () -> Unit,
) {
val status = firstOrNull() ?: IllegalStateException("Status is null").lceError()
when (status) {
is Lce.Content -> onContent()
is Lce.Error -> onError()
is Lce.Loading -> onLoading()
}
}
private fun handleContent(route: AppRoute, eventCreator: (AnalyticsParam.Status) -> MainScreenAnalyticsEvent) {
analyticsEventHandler.send(event = eventCreator(AnalyticsParam.Status.Success))
appRouter.push(route = route)
}
private fun handleError(
userWalletId: UserWalletId,
actionKClass: KClass<out WalletManageButton>,
alertState: WalletAlertState = WalletAlertState.UnavailableOperation,
eventCreator: (AnalyticsParam.Status) -> MainScreenAnalyticsEvent,
) {
analyticsEventHandler.send(event = eventCreator(AnalyticsParam.Status.Error))
stateHolder.update(
transformer = DisableActionTransformer(userWalletId = userWalletId, actionClass = actionKClass),
)
walletEventSender.send(event = WalletEvent.ShowAlert(state = alertState))
}
private fun handleLoading(eventCreator: (AnalyticsParam.Status) -> MainScreenAnalyticsEvent) {
analyticsEventHandler.send(event = eventCreator(AnalyticsParam.Status.Pending))
walletEventSender.send(
event = WalletEvent.ShowAlert(state = WalletAlertState.ProvidersStillLoading),
)
}
}