Updated on 2026-08-14
This commit is contained in:
commit
d8527a5f3f
30 changed files with 214 additions and 161 deletions
|
|
@ -29,6 +29,7 @@ import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase
|
|||
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
|
||||
import com.tangem.domain.staking.FetchStakingTokensUseCase
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.feature.swap.analytics.StoriesEvents
|
||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||
import com.tangem.features.swap.SwapFeatureToggles
|
||||
import com.tangem.tap.common.extensions.setContext
|
||||
|
|
@ -300,19 +301,32 @@ internal class MainViewModel @Inject constructor(
|
|||
private fun preloadImages() {
|
||||
try {
|
||||
viewModelScope.launch {
|
||||
val swapStories = if (swapFeatureToggles.isPromoStoriesEnabled) {
|
||||
getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id)
|
||||
.getOrNull()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (swapFeatureToggles.isPromoStoriesEnabled) {
|
||||
val swapStories = getStoryContentUseCase.invokeSync(
|
||||
id = StoryContentIds.STORY_FIRST_TIME_SWAP.id,
|
||||
refresh = true,
|
||||
).getOrNull()
|
||||
|
||||
val storiesImages = swapStories?.getImageUrls()
|
||||
// try to preload images for stories
|
||||
storiesImages?.forEach(imagePreloader::preload)
|
||||
if (swapStories == null) {
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
val storiesImages = swapStories.getImageUrls()
|
||||
// try to preload images for stories
|
||||
storiesImages.forEach(imagePreloader::preload)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex.message)
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ fun ScenarioUnavailabilityReason.getUnavailabilityReasonText(): TextReference {
|
|||
id = R.string.warning_receive_blocked_hedera_token_association_required_message,
|
||||
)
|
||||
ScenarioUnavailabilityReason.UsedOutdatedData -> {
|
||||
resourceReference(id = R.string.token_button_unavailability_reason_out_od_date_balance)
|
||||
resourceReference(id = R.string.token_button_unavailability_reason_out_of_date_balance)
|
||||
}
|
||||
ScenarioUnavailabilityReason.None -> {
|
||||
throw IllegalArgumentException("The unavailability reason must be other than None")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.core.ui.format.bigdecimal.fiat
|
|||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.common.util.getCardsCount
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -20,7 +21,6 @@ import com.tangem.utils.converter.Converter
|
|||
* @property onClick lambda be invoked when item is clicked
|
||||
* @property appCurrency selected app currency
|
||||
* @property balance wallet balance
|
||||
* @property isLoading wallet loading state
|
||||
* @property isBalanceHidden wallet balance is hidden
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -29,7 +29,6 @@ class UserWalletItemUMConverter(
|
|||
private val onClick: (UserWalletId) -> Unit,
|
||||
private val appCurrency: AppCurrency? = null,
|
||||
private val balance: TotalFiatBalance? = null,
|
||||
private val isLoading: Boolean = true,
|
||||
private val isBalanceHidden: Boolean = false,
|
||||
private val endIcon: UserWalletItemUM.EndIcon = UserWalletItemUM.EndIcon.None,
|
||||
) : Converter<UserWallet, UserWalletItemUM> {
|
||||
|
|
@ -75,7 +74,7 @@ class UserWalletItemUMConverter(
|
|||
|
||||
UserWalletItemUM.Balance.Loaded(
|
||||
value = formattedAmount,
|
||||
isFlickering = isLoading,
|
||||
isFlickering = balance.source == StatusSource.CACHE,
|
||||
)
|
||||
} else {
|
||||
UserWalletItemUM.Balance.Failed
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
},
|
||||
{
|
||||
"name": "SWAP_STORIES_ENABLED",
|
||||
"version": "undefined"
|
||||
"version": "5.21.0"
|
||||
},
|
||||
{
|
||||
"name": "VISA_ONBOARDING_ENABLED",
|
||||
|
|
|
|||
|
|
@ -271,6 +271,8 @@
|
|||
<string name="express_exchange_by">Getauscht von %s</string>
|
||||
<string name="express_exchange_notification_failed_text">Besuche die Website des Anbieters, um dein Geld zurückzuerhalten</string>
|
||||
<string name="express_exchange_notification_failed_title">Fehler beim Vorgang durch Anbieter</string>
|
||||
<string name="express_exchange_notification_long_transaction_time_text">Dein Wechsel dauert länger als erwartet. Wende Dich für Hilfe bitte an den Support Deines Anbieters.</string>
|
||||
<string name="express_exchange_notification_long_transaction_time_title">Lange Transaktionszeit</string>
|
||||
<string name="express_exchange_notification_refund_text">Der Transaktionsbetrag wurde aufgrund von OKX- oder Bridge-Regeln in %1$s auf deine Wallet zurückerstattet. %2$s</string>
|
||||
<string name="express_exchange_notification_refund_title">Der Betrag wurde in %1$s (%2$s Netzwerk) zurückerstattet.</string>
|
||||
<string name="express_exchange_notification_verification_text">Besuche die Website des Anbieters zur Überprüfung</string>
|
||||
|
|
@ -813,6 +815,10 @@
|
|||
<string name="staking_notification_low_staked_balance_title">Niedriges Stakingguthaben</string>
|
||||
<string name="staking_notification_minimum_balance_error_text">Für erneutes Staking sind mindestens %1$s %2$s erforderlich. Bitte lade Dein Guthaben auf.</string>
|
||||
<string name="staking_notification_minimum_balance_error_title">Nicht genug %s</string>
|
||||
<string name="staking_notification_minimum_balance_title">Unzureichendes Guthaben zum Staking</string>
|
||||
<string name="staking_notification_minimum_restake_ada_text">Für das erneute staken sind mindestens 3 ADA erforderlich. Bitte lade Dein Guthaben auf.</string>
|
||||
<string name="staking_notification_minimum_restake_ada_title">Nicht genug ADA</string>
|
||||
<string name="staking_notification_minimum_stake_ada_text">Der für das Staking erforderliche Mindestbetrag muss 5 ADA überschreiten. Bitte lade Dein Guthaben auf, um mit dem Staking zu beginnen.</string>
|
||||
<string name="staking_notification_network_error_text">Aufgrund von Netzwerkproblemen ist Staking derzeit nicht verfügbar. Bitte versuche es später erneut.</string>
|
||||
<string name="staking_notification_new_validator_funds_transfer">Wenn Du im %1$s -Netzwerk mit einem neuen Validator stakest, werden alle zuvor eingesetzten Gelder automatisch an diesen Validator übertragen.</string>
|
||||
<string name="staking_notification_restake_rewards_text">Reinvestiert Deine verdienten Prämien in Deinen Einsatzbetrag und erhöht so den potenziellen Gewinn.</string>
|
||||
|
|
@ -880,6 +886,8 @@
|
|||
<string name="story_meet_title">Lerne Tangem kennen</string>
|
||||
<string name="story_web3_description">Tausche, kaufen Sie NFTs, vergebe Kredite und tätige Einlagen bei mehr als 100 verschiedenen dezentralen Diensten</string>
|
||||
<string name="story_web3_title">Web 3.0-kompatibel</string>
|
||||
<string name="sui_not_enough_coin_for_fee_description">Zum Fortfahren ist eine eingehende Transaktion von mindestens %1$s erforderlich</string>
|
||||
<string name="sui_not_enough_coin_for_fee_title">Unzureichende Mittel</string>
|
||||
<string name="swap_give_permission_fee_footer">Das Netzwerk erhebt eine Token-Genehmigungsgebühr, um zu überprüfen, ob Sie die Verwendung Ihres Tokens für den Swap genehmigen.</string>
|
||||
<string name="swap_promo_text">Tausche mehr Token zu besseren Kursen direkt in deiner Brieftasche.</string>
|
||||
<string name="swap_promo_title">Neuer Swap-Anbieter verfügbar!</string>
|
||||
|
|
@ -918,6 +926,7 @@
|
|||
<string name="token_button_unavailability_reason_empty_balance_sell">Du hast kein Guthaben um dies zu Verkaufen. Lade dein Konto auf, um Geld von dort zu verkaufen.</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_send">Du hast kein Guthaben zum Versenden. Lade dein Konto auf, um Geld von dort aus senden zu können.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">Das Tauschen von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen.</string>
|
||||
<string name="token_button_unavailability_reason_out_of_date_balance">Der angezeigte Kontostand kann aufgrund der Zwischenspeicherung veraltet sein.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_sell">Der Verkauf von Geldmitteln ist möglich, sobald die ausstehende(n) Transaktion(en) im %s -Netzwerk abgeschlossen ist/sind.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_send">Die Geldsendung wird verfügbar, sobald die ausstehende(n) Transaktion(en) im Netzwerk %s abgeschlossen ist/sind.</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">Der Verkauf von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen.</string>
|
||||
|
|
@ -978,6 +987,9 @@
|
|||
<string name="user_wallet_list_rename_popup_title">Wallet umbenennen</string>
|
||||
<string name="user_wallet_list_unlock_all">Alle freischalten</string>
|
||||
<string name="user_wallet_list_unlock_all_with">Alle mit %s freischalten</string>
|
||||
<string name="visa_unlock_notification_button">Freischalten</string>
|
||||
<string name="visa_unlock_notification_subtitle">Scanne Deine Karte, um den Zugriff freizuschalten</string>
|
||||
<string name="visa_unlock_notification_title">Benötigte Freischaltung</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">Blockchain ist nicht erreichbar. Versuche es später nochmal</string>
|
||||
<string name="wallet_balance_missing_derivation">Karte oder Ring scannen</string>
|
||||
<string name="wallet_been_activated_message">Dieses Wallet wurde bereits früher aktiviert. \n Wenn dies nicht von Dir durchgeführt wurde, wende Dich bitte an den Support. \n Tangem verkauft niemals Wallets zusammen mit vorgenerierten Zugangscodes.</string>
|
||||
|
|
@ -1092,7 +1104,7 @@
|
|||
<string name="warning_receive_blocked_hedera_token_association_required_message">Du musst deinen Token zuordnen, bevor du Token erhalten kannst</string>
|
||||
<string name="warning_rent_fee_title">Netzmietgebühr erforderlich</string>
|
||||
<string name="warning_seedphrase_action_required_title">Handlungsbedarf</string>
|
||||
<string name="warning_seedphrase_contacted_support">Hast Du innerhalb von 7 Tagen nach dem Erstellen einer Wallet per App oder E-Mail Kontakt zum Support aufgenommen? Wenn ja oder wenn Du Dir nicht sicher bist, befolge die Anweisungen und führe diese vollständig aus.</string>
|
||||
<string name="warning_seedphrase_contacted_support">Hast Du innerhalb von 7 Tagen nach der Erstellung Ihres Wallets über die App Kontakt zum Support aufgenommen? Wenn ja oder wenn Du Dir nicht sicher bist, klicke auf „Ja“ und folge den Anweisungen.</string>
|
||||
<string name="warning_seedphrase_issue_answer_no">Vielen Dank! Alles erledigt! Keine weiteren Maßnahmen erforderlich.</string>
|
||||
<string name="warning_seedphrase_issue_answer_yes">Sie werden jetzt auf die offizielle Tangem-Website weitergeleitet. Bitte lesen und befolgen Sie dort die Anweisungen.</string>
|
||||
<string name="warning_seedphrase_issue_message">Hast Du das Tangem-Supportteam schon einmal direkt über diese Anwendung kontaktiert?</string>
|
||||
|
|
@ -1107,6 +1119,7 @@
|
|||
<string name="warning_some_token_balances_not_updated">Einige Token-Guthaben konnten nicht aktualisiert werden</string>
|
||||
<string name="warning_testnet_card_message">Dies ist eine Testnet-Karte. Sie kann keine Transaktionen verarbeiten und sollte nur zu Test- und Entwicklungszwecken verwendet werden.</string>
|
||||
<string name="warning_testnet_card_title">Nur für Testzwecke</string>
|
||||
<string name="warning_token_balance_not_updated">Der Kontostand ist möglicherweise veraltet. Aktualisiere bittre die Seite.</string>
|
||||
<string name="welcome_interrupted_backup_alert_discard">Verwerfen</string>
|
||||
<string name="welcome_interrupted_backup_alert_message">Du hast eine unterbrochene Sicherung. Möchtest du diese fortsetzen?</string>
|
||||
<string name="welcome_interrupted_backup_alert_resume">Ja, fortsetzen</string>
|
||||
|
|
|
|||
|
|
@ -805,6 +805,10 @@
|
|||
<string name="staking_notification_low_staked_balance_title">ステーキング残高が低いです</string>
|
||||
<string name="staking_notification_minimum_balance_error_text">再ステーキングには最低%1$s %2$sが必要です。残高を補充してください。</string>
|
||||
<string name="staking_notification_minimum_balance_error_title">%sが足りません</string>
|
||||
<string name="staking_notification_minimum_balance_title">ステーキングのための残高が不足しています</string>
|
||||
<string name="staking_notification_minimum_restake_ada_text">リステーキングには最低3ADA が必要です。残高を補充してください。</string>
|
||||
<string name="staking_notification_minimum_restake_ada_title">ADAが不足しています</string>
|
||||
<string name="staking_notification_minimum_stake_ada_text">ステーキングに必要な最小金額は5ADAを超える必要があります。ステーキングを開始するには残高を補充してください。</string>
|
||||
<string name="staking_notification_network_error_text">ネットワークの状態により、現在ステーキングはご利用いただけません。しばらくしてからもう一度お試しください。</string>
|
||||
<string name="staking_notification_new_validator_funds_transfer">新しいバリデーターを使用して%1$sネットワークにステーキングすると、以前にステーキングされた資金がすべてこのバリデーターに自動的に転送されます。</string>
|
||||
<string name="staking_notification_restake_rewards_text">獲得した報酬をステーキングに再投資し、潜在的な収益を増やします。</string>
|
||||
|
|
@ -872,6 +876,8 @@
|
|||
<string name="story_meet_title">Tangemのご紹介</string>
|
||||
<string name="story_web3_description">100種類以上の分散型サービスで、NFTの交換・購入や、借入・預金を行うことができます。</string>
|
||||
<string name="story_web3_title">Web3.0対応</string>
|
||||
<string name="sui_not_enough_coin_for_fee_description">続行するには少なくとも%1$sの受信取引が必要です</string>
|
||||
<string name="sui_not_enough_coin_for_fee_title">残高不足</string>
|
||||
<string name="swap_give_permission_fee_footer">ネットワークは、あなたがトークンのスワップを承認していることを確認するために、トークン承認手数料を請求します。</string>
|
||||
<string name="swap_promo_text">より多くのトークンをより良いレートで、ウォレット内にて直接交換します。</string>
|
||||
<string name="swap_promo_title">新しいスワッププロバイダーが利用可能になりました!</string>
|
||||
|
|
@ -910,6 +916,7 @@
|
|||
<string name="token_button_unavailability_reason_empty_balance_sell">売却できる資金がありません。アカウントに入金して、売却できるようにしてください。</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_send">送金する資金がありません。アカウントに入金して、送金できるようにしてください。</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">%sのスワップは、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。</string>
|
||||
<string name="token_button_unavailability_reason_out_of_date_balance">表示残高はキャッシュにより古くなっている可能性があります。</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_sell">%sネットワーク上の保留中の取引が完了すると、資金の売却が可能になります。</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_send">ネットワーク%s内の保留中の取引が完了すると、送金が可能になります。</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">%sの売却は、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。</string>
|
||||
|
|
@ -970,6 +977,9 @@
|
|||
<string name="user_wallet_list_rename_popup_title">ウォレット名の変更</string>
|
||||
<string name="user_wallet_list_unlock_all">すべてのロックを解除</string>
|
||||
<string name="user_wallet_list_unlock_all_with">%sですべてをロック解除</string>
|
||||
<string name="visa_unlock_notification_button">ロック解除</string>
|
||||
<string name="visa_unlock_notification_subtitle">カードをスキャンしてアクセスロックを解除する</string>
|
||||
<string name="visa_unlock_notification_title">ロック解除が必要</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">ブロックチェーンにアクセスできません。後でもう一度お試しください。</string>
|
||||
<string name="wallet_balance_missing_derivation">カードまたはリングをスキャン</string>
|
||||
<string name="wallet_been_activated_message">このウォレットはすでに有効化されています。\nあなたが行ったのでない場合は、サポートに連絡してください。\nTangemは、事前に生成されたアクセスコードと一緒にウォレットを販売することはありません。</string>
|
||||
|
|
@ -1083,7 +1093,7 @@
|
|||
<string name="warning_receive_blocked_hedera_token_association_required_message">トークンを受け取る前に、トークンを関連付ける必要があります。</string>
|
||||
<string name="warning_rent_fee_title">ネットワーク使用料が必要です</string>
|
||||
<string name="warning_seedphrase_action_required_title">対応が必要です</string>
|
||||
<string name="warning_seedphrase_contacted_support">ウォレットを作成してから7日以内にアプリまたはEメール経由でサポートに連絡しましたか?連絡したか不明な場合は、手順に従って完了してください。</string>
|
||||
<string name="warning_seedphrase_contacted_support">ウォレットの作成後、7日以内にアプリ経由でサポートに連絡しましたか?連絡した場合、あるいは連絡したかわからない場合は、「はい」をクリックして指示に従ってください。</string>
|
||||
<string name="warning_seedphrase_issue_answer_no">ありがとうございます。準備完了です。これ以上の操作は必要ありません。</string>
|
||||
<string name="warning_seedphrase_issue_answer_yes">Tangemの公式ウェブサイトに移動します。そちらの指示に従ってください。</string>
|
||||
<string name="warning_seedphrase_issue_message">このアプリ経由でTangemサポートチームに直接連絡したことがありますか?</string>
|
||||
|
|
|
|||
|
|
@ -1111,6 +1111,7 @@
|
|||
<string name="warning_rate_app_title">Подобається Tangem?</string>
|
||||
<string name="warning_receive_blocked_hedera_token_association_required_message">Вам необхідно провести асоціацію токена, щоб мати можливість приймати його</string>
|
||||
<string name="warning_rent_fee_title">Необхідна плата за оренду мережі</string>
|
||||
<string name="warning_seedphrase_contacted_support">Чи зверталися в службу підтримки через додаток протягом 7 днів після створення гаманця? Якщо зверталися або не впевнені, натисніть «Так» і дотримуйтесь інструкцій.</string>
|
||||
<string name="warning_seedphrase_issue_answer_no">Дякуємо! Все добре! Подальших дій не потрібно.</string>
|
||||
<string name="warning_seedphrase_issue_answer_yes">Ви будете перенаправлені на офіційний сайт Tangem. Будь ласка, прочитайте та виконайте вказані там інструкції.</string>
|
||||
<string name="warning_seedphrase_issue_message">Ви коли-небудь зверталися до служби підтримки Tangem безпосередньо з цього додатку?</string>
|
||||
|
|
|
|||
|
|
@ -926,7 +926,7 @@
|
|||
<string name="token_button_unavailability_reason_empty_balance_sell">You do not have funds to sell. Top up your account to be able to sell funds from it.</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_send">You do not have funds to send. Top up your account to be able to send funds from it.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">Swapping %s is not supported by current providers, but we are working to add more options.</string>
|
||||
<string name="token_button_unavailability_reason_out_od_date_balance">The displayed balance might be outdated due to caching.</string>
|
||||
<string name="token_button_unavailability_reason_out_of_date_balance">The displayed balance might be outdated due to caching.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_sell">Selling funds will be available once the pending transaction(s) on the %s network is complete.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_send">Sending funds will be available once the pending transaction(s) in network %s is complete</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">Selling %s is not supported by current providers, but we are working to add more options.</string>
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
|
@ -30,9 +28,9 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter
|
|||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.icons.badge.drawBadge
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
|
||||
|
|
@ -225,20 +223,6 @@ fun getTextColor(config: ActionButtonConfig): Color {
|
|||
}
|
||||
}
|
||||
|
||||
private fun DrawScope.drawBadge(containerColor: Color) {
|
||||
val width = size.width
|
||||
drawCircle(
|
||||
color = containerColor,
|
||||
center = Offset(x = width - 2.dp.toPx(), y = 2.dp.toPx()),
|
||||
radius = 5.dp.toPx(),
|
||||
)
|
||||
drawCircle(
|
||||
color = TangemColorPalette.Azure,
|
||||
center = Offset(x = width - 2.dp.toPx(), y = 2.dp.toPx()),
|
||||
radius = 3.dp.toPx(),
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(group = "RoundedActionButton", showBackground = true)
|
||||
@Preview(group = "RoundedActionButton", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.core.ui.components.icons.badge
|
||||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
|
||||
fun DrawScope.drawBadge(containerColor: Color, offset: Dp = 2.dp) {
|
||||
val width = size.width
|
||||
drawCircle(
|
||||
color = containerColor,
|
||||
center = Offset(x = width - offset.toPx(), y = offset.toPx()),
|
||||
radius = 5.dp.toPx(),
|
||||
)
|
||||
drawCircle(
|
||||
color = TangemColorPalette.Azure,
|
||||
center = Offset(x = width - offset.toPx(), y = offset.toPx()),
|
||||
radius = 3.dp.toPx(),
|
||||
)
|
||||
}
|
||||
|
|
@ -144,10 +144,10 @@ internal class DefaultHotCryptoRepository(
|
|||
|
||||
return copy(
|
||||
tokens = this.tokens
|
||||
.applyTokensIdMigrations()
|
||||
.filter { hotToken ->
|
||||
!tokens.hasAlreadyAdded(hotToken) && userWallet.canHandleHotCrypto(hotToken)
|
||||
}
|
||||
.applyTokensIdMigrations(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,15 +44,15 @@ internal class DefaultPromoRepository(
|
|||
}
|
||||
|
||||
override fun getStoryById(id: String): Flow<StoryContent?> = isReadyToShowStories(id).mapLatest {
|
||||
getStoryByIdSync(id)
|
||||
getStoryByIdSync(id = id, refresh = false)
|
||||
}
|
||||
|
||||
override suspend fun getStoryByIdSync(id: String): StoryContent? = withContext(dispatchers.io) {
|
||||
override suspend fun getStoryByIdSync(id: String, refresh: Boolean): StoryContent? = withContext(dispatchers.io) {
|
||||
if (!isReadyToShowStoriesSync(id)) return@withContext null
|
||||
|
||||
val storedPromo = promoStoriesStore.getSyncOrNull(storyId = id)
|
||||
// Get last stored promo by id if possible or get from network
|
||||
val story = if (storedPromo == null) {
|
||||
val story = if (storedPromo == null && refresh) {
|
||||
val storyContent = runCatching {
|
||||
// Important to return
|
||||
withTimeoutOrNull(STORIES_LOAD_DELAY) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class GetStoryContentUseCase(
|
|||
.catch { emit(it.left()) }
|
||||
.onEmpty { emit(null.right()) }
|
||||
|
||||
suspend fun invokeSync(id: String): Either<Throwable, StoryContent?> = Either.catch {
|
||||
promoRepository.getStoryByIdSync(id)
|
||||
suspend fun invokeSync(id: String, refresh: Boolean = false): Either<Throwable, StoryContent?> = Either.catch {
|
||||
promoRepository.getStoryByIdSync(id, refresh)
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ interface PromoRepository {
|
|||
// region Stories
|
||||
fun getStoryById(id: String): Flow<StoryContent?>
|
||||
|
||||
suspend fun getStoryByIdSync(id: String): StoryContent?
|
||||
suspend fun getStoryByIdSync(id: String, refresh: Boolean): StoryContent?
|
||||
|
||||
fun isReadyToShowStories(storyId: String): Flow<Boolean>
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ sealed class TokenScreenAnalyticsEvent(
|
|||
)
|
||||
|
||||
class NoticeActionInactive(token: String, tokenAction: TokenAction, reason: String) : TokenScreenAnalyticsEvent(
|
||||
"Notice - Action Inactive",
|
||||
event = "Notice - Action Inactive",
|
||||
params = buildMap {
|
||||
put("Token", token)
|
||||
put("Action", tokenAction.action)
|
||||
|
|
@ -112,6 +112,7 @@ sealed class TokenScreenAnalyticsEvent(
|
|||
private const val UNAVAILABLE = "Unavailable"
|
||||
private const val EMPTY = "Empty"
|
||||
private const val PENDING = "Pending"
|
||||
private const val CACHING = "Caching"
|
||||
|
||||
fun ScenarioUnavailabilityReason.toReasonAnalyticsText(): String {
|
||||
return when (this) {
|
||||
|
|
@ -123,9 +124,9 @@ sealed class TokenScreenAnalyticsEvent(
|
|||
-> UNAVAILABLE
|
||||
is ScenarioUnavailabilityReason.EmptyBalance -> EMPTY
|
||||
is ScenarioUnavailabilityReason.PendingTransaction -> PENDING
|
||||
ScenarioUnavailabilityReason.UsedOutdatedData -> CACHING
|
||||
ScenarioUnavailabilityReason.None,
|
||||
ScenarioUnavailabilityReason.Unreachable,
|
||||
ScenarioUnavailabilityReason.UsedOutdatedData,
|
||||
-> ""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,14 @@ class FetchTokenListUseCase(
|
|||
): Either<TokenListError, Unit> = either {
|
||||
val currencies = fetchCurrencies(userWalletId, refresh = mode.refreshCurrencies)
|
||||
|
||||
invoke(userWalletId = userWalletId, currencies = currencies, mode = mode)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: List<CryptoCurrency>,
|
||||
mode: RefreshMode = RefreshMode.NONE,
|
||||
): Either<TokenListError, Unit> = either {
|
||||
coroutineScope {
|
||||
val fetchStatuses = async {
|
||||
fetchNetworksStatuses(
|
||||
|
|
|
|||
|
|
@ -13,10 +13,8 @@ import com.tangem.domain.tokens.model.TotalFiatBalance
|
|||
import com.tangem.domain.tokens.operations.BaseCurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.operations.TokenListFiatBalanceOperations
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
import timber.log.Timber
|
||||
|
||||
class GetWalletTotalBalanceUseCase(
|
||||
|
|
@ -54,20 +52,28 @@ class GetWalletTotalBalanceUseCase(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
operator fun invoke(userWalletId: UserWalletId): LceFlow<TokenListError, TotalFiatBalance> {
|
||||
return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId)
|
||||
.transformLatest { maybeStatuses ->
|
||||
val balance = createBalance(maybeStatuses)
|
||||
|
||||
emit(balance)
|
||||
}
|
||||
return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId).map(::createBalance)
|
||||
}
|
||||
|
||||
private fun createBalance(
|
||||
maybeStatuses: Lce<TokenListError, List<CryptoCurrencyStatus>>,
|
||||
): Lce<TokenListError, TotalFiatBalance> = lce {
|
||||
val statuses = maybeStatuses.bind()
|
||||
val statuses = when (maybeStatuses) {
|
||||
is Lce.Content -> maybeStatuses.content
|
||||
is Lce.Error -> raise(maybeStatuses)
|
||||
is Lce.Loading -> {
|
||||
val content = maybeStatuses.partialContent
|
||||
|
||||
if (content == null) {
|
||||
isLoading.set(true)
|
||||
|
||||
raise(lceLoading())
|
||||
} else {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val operations = TokenListFiatBalanceOperations(
|
||||
currencies = ensureNotNull(statuses.toNonEmptyListOrNull()) { lceLoading() },
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.core.lce.LceFlow
|
|||
import com.tangem.domain.core.lce.lce
|
||||
import com.tangem.domain.core.lce.lceFlow
|
||||
import com.tangem.domain.core.utils.EitherFlow
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
|
|
@ -45,9 +46,14 @@ class CachedCurrenciesStatusesOperations(
|
|||
): LceFlow<TokenListError, List<CryptoCurrencyStatus>> = lceFlow {
|
||||
currenciesFlow.flatMapLatest { maybeCurrencies ->
|
||||
val isUpdating = MutableStateFlow(value = true)
|
||||
val nonEmptyCurrencies = maybeCurrencies.bind().toNonEmptyListOrNull()
|
||||
|
||||
ensureNotNull(nonEmptyCurrencies) { TokenListError.EmptyTokens }
|
||||
val nonEmptyCurrencies = maybeCurrencies
|
||||
.getOrElse { return@flatMapLatest flowOf(it.lceError()) }
|
||||
.toNonEmptyListOrNull()
|
||||
|
||||
if (nonEmptyCurrencies.isNullOrEmpty()) {
|
||||
return@flatMapLatest flowOf(TokenListError.EmptyTokens.lceError())
|
||||
}
|
||||
|
||||
// This is only 'true' when the flow here is empty, such as during initial loading
|
||||
if (isLoading.get()) {
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ internal class UserWalletListModel @Inject constructor(
|
|||
|
||||
init {
|
||||
combine(
|
||||
userWalletsFetcher.userWallets,
|
||||
shouldSaveUserWalletsUseCase(),
|
||||
isWalletSavingInProgress,
|
||||
flow = userWalletsFetcher.userWallets,
|
||||
flow2 = shouldSaveUserWalletsUseCase(),
|
||||
flow3 = isWalletSavingInProgress,
|
||||
transform = ::updateState,
|
||||
).launchIn(modelScope)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ internal class UserWalletsFetcher @Inject constructor(
|
|||
emit(uiModels)
|
||||
|
||||
combine(
|
||||
getSelectedAppCurrencyUseCase().distinctUntilChanged(),
|
||||
getBalanceHidingSettingsUseCase().distinctUntilChanged(),
|
||||
getWalletTotalBalanceUseCase(wallets.map(UserWallet::walletId)).distinctUntilChanged(),
|
||||
flow = getSelectedAppCurrencyUseCase().distinctUntilChanged(),
|
||||
flow2 = getBalanceHidingSettingsUseCase().distinctUntilChanged(),
|
||||
flow3 = getWalletTotalBalanceUseCase(wallets.map(UserWallet::walletId)).distinctUntilChanged(),
|
||||
) { maybeAppCurrency, balanceHidingSettings, maybeBalances ->
|
||||
val models = createUiModels(
|
||||
wallets = wallets,
|
||||
|
|
@ -99,7 +99,6 @@ internal class UserWalletsFetcher @Inject constructor(
|
|||
appCurrency = appCurrency,
|
||||
balance = balance,
|
||||
isBalanceHidden = balanceHidingSettings.isBalanceHidden,
|
||||
isLoading = maybeBalances.isLoading(),
|
||||
)
|
||||
.convert(userWallet)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ internal class AddToPortfolioBSContentUMFactory(
|
|||
},
|
||||
appCurrency = portfolioData.appCurrency,
|
||||
balance = balance?.getOrNull(),
|
||||
isLoading = balance?.isLoading() == true,
|
||||
isBalanceHidden = portfolioData.isBalanceHidden,
|
||||
endIcon = if (userWallet.walletId == selectedWalletId) {
|
||||
UserWalletItemUM.EndIcon.Checkmark
|
||||
|
|
|
|||
|
|
@ -48,33 +48,14 @@ internal class PortfolioTokenUMConverter(
|
|||
|
||||
private fun quickActions(cryptoData: PortfolioData.CryptoCurrencyData): PortfolioTokenUM.QuickActions {
|
||||
return PortfolioTokenUM.QuickActions(
|
||||
actions = listOfNotNull(
|
||||
QuickActionUM.Buy.takeIf {
|
||||
cryptoData.actions.any {
|
||||
it is TokenActionsState.ActionState.Buy &&
|
||||
it.unavailabilityReason == ScenarioUnavailabilityReason.None
|
||||
}
|
||||
},
|
||||
QuickActionUM.Exchange.takeIf {
|
||||
cryptoData.actions.any {
|
||||
it is TokenActionsState.ActionState.Swap &&
|
||||
it.unavailabilityReason == ScenarioUnavailabilityReason.None
|
||||
}
|
||||
},
|
||||
QuickActionUM.Receive.takeIf {
|
||||
cryptoData.actions.any {
|
||||
it is TokenActionsState.ActionState.Receive &&
|
||||
it.unavailabilityReason == ScenarioUnavailabilityReason.None
|
||||
}
|
||||
},
|
||||
).toImmutableList(),
|
||||
actions = toQuickActions(cryptoData.actions),
|
||||
onQuickActionClick = {
|
||||
when (it) {
|
||||
QuickActionUM.Buy -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Buy,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
QuickActionUM.Exchange -> tokenActionsHandler.handle(
|
||||
is QuickActionUM.Exchange -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Exchange,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
|
|
@ -94,4 +75,17 @@ internal class PortfolioTokenUMConverter(
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun toQuickActions(actions: List<TokenActionsState.ActionState>) = buildList {
|
||||
actions.forEach { action ->
|
||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
||||
when (action) {
|
||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.Buy
|
||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.Exchange(showBadge = action.showBadge)
|
||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.Receive
|
||||
else -> null
|
||||
}?.let(::add)
|
||||
}
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
|
@ -4,7 +4,10 @@ import android.content.res.Configuration
|
|||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Button
|
||||
|
|
@ -13,6 +16,7 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
|
|
@ -22,6 +26,7 @@ import androidx.compose.ui.unit.LayoutDirection
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.components.SpacerH4
|
||||
import com.tangem.core.ui.components.icons.badge.drawBadge
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
|
|
@ -29,7 +34,7 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.QuickActionUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
internal fun PortfolioQuickActions(
|
||||
|
|
@ -59,7 +64,6 @@ internal fun PortfolioQuickActions(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
@Composable
|
||||
private fun AnimatedVisibilityScope.LineSeparator(modifier: Modifier = Modifier) {
|
||||
val lineColor = TangemTheme.colors.stroke.primary
|
||||
|
|
@ -99,7 +103,7 @@ private fun AnimatedVisibilityScope.LineSeparator(modifier: Modifier = Modifier)
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class, ExperimentalFoundationApi::class)
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun AnimatedVisibilityScope.QuickActionItem(
|
||||
state: QuickActionUM,
|
||||
|
|
@ -131,27 +135,7 @@ private fun AnimatedVisibilityScope.QuickActionItem(
|
|||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing18),
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.animateEnterExit(
|
||||
enter = scaleIn(),
|
||||
exit = scaleOut(),
|
||||
)
|
||||
.background(
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.size(TangemTheme.dimens.size32),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.requiredSize(TangemTheme.dimens.size16),
|
||||
imageVector = ImageVector.vectorResource(id = state.icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.button.primary,
|
||||
)
|
||||
}
|
||||
QuickActionIcon(state)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateEnterExit(
|
||||
|
|
@ -174,6 +158,38 @@ private fun AnimatedVisibilityScope.QuickActionItem(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AnimatedVisibilityScope.QuickActionIcon(state: QuickActionUM) {
|
||||
val containerColor = TangemTheme.colors.background.action
|
||||
Box(
|
||||
Modifier
|
||||
.animateEnterExit(
|
||||
enter = scaleIn(),
|
||||
exit = scaleOut(),
|
||||
)
|
||||
.background(
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.size(TangemTheme.dimens.size32)
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
if (state is QuickActionUM.Exchange && state.showBadge) {
|
||||
drawBadge(containerColor = containerColor, offset = 4.dp)
|
||||
}
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.requiredSize(TangemTheme.dimens.size16),
|
||||
imageVector = ImageVector.vectorResource(id = state.icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.button.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
|
|
@ -197,7 +213,11 @@ private fun Preview() {
|
|||
modifier = Modifier.background(color = TangemTheme.colors.background.action),
|
||||
) {
|
||||
PortfolioQuickActions(
|
||||
actions = QuickActionUM.entries.toImmutableList(),
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(showBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
),
|
||||
isVisible = isVisible,
|
||||
onActionClick = {},
|
||||
onActionLongClick = {},
|
||||
|
|
@ -214,7 +234,11 @@ private fun PreviewRtl() {
|
|||
TangemThemePreview(rtl = true) {
|
||||
Box(modifier = Modifier.background(color = TangemTheme.colors.background.action)) {
|
||||
PortfolioQuickActions(
|
||||
actions = QuickActionUM.entries.toImmutableList(),
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(showBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
),
|
||||
isVisible = true,
|
||||
onActionClick = {},
|
||||
onActionLongClick = {},
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
|
|||
import com.tangem.features.markets.portfolio.impl.ui.state.PortfolioTokenUM
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.QuickActionUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfolioUM> {
|
||||
|
||||
|
|
@ -61,7 +60,11 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
|
|||
),
|
||||
isQuickActionsShown = false,
|
||||
quickActions = PortfolioTokenUM.QuickActions(
|
||||
actions = QuickActionUM.entries.toImmutableList(),
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(showBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
),
|
||||
onQuickActionClick = {},
|
||||
onQuickActionLongClick = {},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -7,26 +7,30 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.features.markets.impl.R
|
||||
|
||||
@Immutable
|
||||
internal enum class QuickActionUM(
|
||||
internal sealed class QuickActionUM(
|
||||
val title: TextReference,
|
||||
val description: TextReference,
|
||||
@DrawableRes val icon: Int,
|
||||
val longClickAvailable: Boolean = false,
|
||||
) {
|
||||
Buy(
|
||||
data object Buy : QuickActionUM(
|
||||
title = resourceReference(R.string.common_buy),
|
||||
description = resourceReference(R.string.buy_token_description),
|
||||
icon = R.drawable.ic_plus_24,
|
||||
),
|
||||
Exchange(
|
||||
)
|
||||
|
||||
data class Exchange(
|
||||
val showBadge: Boolean,
|
||||
) : QuickActionUM(
|
||||
title = resourceReference(R.string.common_exchange),
|
||||
description = resourceReference(R.string.exсhange_token_description),
|
||||
icon = R.drawable.ic_exchange_vertical_24,
|
||||
),
|
||||
Receive(
|
||||
)
|
||||
|
||||
data object Receive : QuickActionUM(
|
||||
title = resourceReference(R.string.common_receive),
|
||||
description = resourceReference(R.string.receive_token_description),
|
||||
icon = R.drawable.ic_arrow_down_24,
|
||||
longClickAvailable = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -19,15 +19,4 @@ sealed class StoriesEvents(
|
|||
WATCHED to watchCount,
|
||||
),
|
||||
)
|
||||
|
||||
data class Error(
|
||||
val source: String,
|
||||
val type: String,
|
||||
) : StoriesEvents(
|
||||
event = "Error",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
AnalyticsParam.TYPE to type,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -53,22 +53,10 @@ internal class StoriesModel @Inject constructor(
|
|||
getStoryContentUseCase.invokeSync(params.storyId).fold(
|
||||
ifLeft = {
|
||||
Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}")
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
source = params.screenSource,
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
openScreen(hideStories = false) // Fallback to target screen
|
||||
},
|
||||
ifRight = { swapStory ->
|
||||
if (swapStory == null) {
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
source = params.screenSource,
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
openScreen(hideStories = false) // Fallback to target screen
|
||||
} else {
|
||||
_state.update {
|
||||
|
|
|
|||
|
|
@ -21,12 +21,10 @@ sealed class StoriesEvents(
|
|||
)
|
||||
|
||||
data class Error(
|
||||
val source: String,
|
||||
val type: String,
|
||||
) : StoriesEvents(
|
||||
event = "Error",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to source,
|
||||
AnalyticsParam.TYPE to type,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ internal class SwapModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val blockchainInteractor: BlockchainInteractor,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase,
|
||||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
|
|
@ -96,6 +95,7 @@ internal class SwapModel @Inject constructor(
|
|||
private val shouldShowStoriesUseCase: ShouldShowStoriesUseCase,
|
||||
private val getStoryContentUseCase: GetStoryContentUseCase,
|
||||
private val featureToggles: SwapFeatureToggles,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
swapInteractorFactory: SwapInteractor.Factory,
|
||||
private val urlOpener: UrlOpener,
|
||||
router: AppRouter,
|
||||
|
|
@ -278,23 +278,10 @@ internal class SwapModel @Inject constructor(
|
|||
getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id).fold(
|
||||
ifLeft = {
|
||||
Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}")
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
source = params.screenSource,
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
},
|
||||
ifRight = { story ->
|
||||
if (story != null) {
|
||||
uiState = stateBuilder.createStoriesState(uiState, story)
|
||||
} else {
|
||||
analyticsEventHandler.send(
|
||||
StoriesEvents.Error(
|
||||
source = params.screenSource,
|
||||
type = StoryContentIds.STORY_FIRST_TIME_SWAP.analyticType,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -149,7 +149,11 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
).fold(
|
||||
ifLeft = { Timber.e(it, "Failed to derive public keys") },
|
||||
ifRight = {
|
||||
fetchTokenListUseCase(userWallet.walletId, mode = RefreshMode.SKIP_CURRENCIES).onLeft {
|
||||
fetchTokenListUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
mode = RefreshMode.SKIP_CURRENCIES,
|
||||
currencies = missedAddressCurrencies,
|
||||
).onLeft {
|
||||
Timber.e("Unable to refresh token list: $it")
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue