diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt index 5eed564c97..2aa36c5413 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt @@ -18,10 +18,14 @@ class AmplitudeAnalyticsHandler( } class Builder : AnalyticsHandlerBuilder { - override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler? = when { - !data.isDebug -> AmplitudeClient(data.application, data.config.amplitudeApiKey) - data.isDebug && data.logConfig.amplitude -> AmplitudeLogClient(data.jsonConverter) - else -> null - }?.let { AmplitudeAnalyticsHandler(it) } + override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler { + return AmplitudeAnalyticsHandler( + client = if (data.logConfig.amplitude) { + AmplitudeLogClient(data.jsonConverter) + } else { + AmplitudeClient(data.application, data.config.amplitudeApiKey) + }, + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt index 8c78ffa3a5..deb7e332b7 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt @@ -239,9 +239,8 @@ class WalletConnectSdkHelper { private suspend fun signTransaction(data: WcTransactionData, cardId: String?): String? { val dataToSign = EthereumUtils.buildTransactionToSign( transactionData = data.transaction, - nonce = null, blockchain = data.walletManager.wallet.blockchain, - ) ?: return null + ) val command = SignHashCommand( hash = dataToSign.hash, diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt index 45b8745cca..c2e879dc2d 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt @@ -26,6 +26,7 @@ internal fun StoriesButton( showProgress = showProgress, enabled = true, shape = TangemTheme.shapes.roundedCornersXMedium, + textStyle = TangemTheme.typography.subtitle1, iconPadding = when (icon) { is TangemButtonIconPosition.Start -> TangemTheme.dimens.spacing4 is TangemButtonIconPosition.End, diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt index 23edacd61b..4a52e5d13e 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt @@ -135,4 +135,13 @@ interface TangemTechApi { @ReadTimeout(duration = 5, unit = TimeUnit.SECONDS) @GET("networks/providers") suspend fun getBlockchainProviders(): Map> + + companion object { + val marketsQuoteFields = listOf( + "price", + "priceChange24h", + "priceChange1w", + "priceChange30d", + ) + } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/DevTangemApi.kt b/core/datasource/src/main/java/com/tangem/datasource/di/DevTangemApi.kt deleted file mode 100644 index 4bfacf89db..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/di/DevTangemApi.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.datasource.di - -import javax.inject.Qualifier - -@Qualifier -@MustBeDocumented -@Retention(AnnotationRetention.RUNTIME) -annotation class DevTangemApi \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt index c692a451c2..667e63d05e 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt @@ -35,7 +35,6 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) internal object NetworkModule { - private const val DEV_V1_TANGEM_TECH_BASE_URL = "https://devapi.tangem-tech.com/v1/" private const val PROD_V2_TANGEM_TECH_BASE_URL = "https://api.tangem-tech.com/v2/" private const val TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS = 60L @@ -128,44 +127,27 @@ internal object NetworkModule { } @Provides - @DevTangemApi - @Singleton - fun provideTangemTechDevApi( - @NetworkMoshi moshi: Moshi, - @ApplicationContext context: Context, - appVersionProvider: AppVersionProvider, - ): TangemTechApi { - return provideTangemTechApiInternal( - moshi = moshi, - context = context, - appVersionProvider = appVersionProvider, - baseUrl = DEV_V1_TANGEM_TECH_BASE_URL, - ) - } - - // TODO: [REDACTED_JIRA] - @Provides - @DevTangemApi @Singleton fun provideTangemTechMarketsApi( @NetworkMoshi moshi: Moshi, @ApplicationContext context: Context, - appVersionProvider: AppVersionProvider, + apiConfigsManager: ApiConfigsManager, ): TangemTechMarketsApi { - return provideTangemTechApiInternal( + return createApi( + id = ApiConfig.ID.TangemTech, moshi = moshi, context = context, - appVersionProvider = appVersionProvider, - baseUrl = DEV_V1_TANGEM_TECH_BASE_URL, - timeouts = Timeouts( - callTimeoutSeconds = TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS, - connectTimeoutSeconds = TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS, - readTimeoutSeconds = TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS, - ), - requestHeaders = listOf(AppVersionPlatformHeaders(appVersionProvider)), + apiConfigsManager = apiConfigsManager, + clientBuilder = { + this.callTimeout(TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .connectTimeout(TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .readTimeout(TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .applyTimeoutAnnotations() + }, ) } + @Deprecated("use createApi instead") private inline fun provideTangemTechApiInternal( moshi: Moshi, context: Context, diff --git a/core/pagination/src/main/java/com/tangem/pagination/BatchListSource.kt b/core/pagination/src/main/java/com/tangem/pagination/BatchListSource.kt index db1c27bbbc..535c7deea4 100644 --- a/core/pagination/src/main/java/com/tangem/pagination/BatchListSource.kt +++ b/core/pagination/src/main/java/com/tangem/pagination/BatchListSource.kt @@ -99,7 +99,7 @@ private class DefaultBatchListSource scope.launch { context.actionsFlow - .conflate() + .buffer() .collect { action -> collectActions(action) } diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index ef2d858a71..a72160333d 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -383,6 +383,7 @@ Webseite Kaufdruck Die Differenz zwischen Käufer- und Verkäufervolumen + Kaufdruck Umlaufmenge Die Gesamtzahl der Coins, die für den Handel verfügbar sind und auf dem Markt zirkulieren Erfahrene Käufer @@ -650,6 +651,8 @@ Die Anzahl der zu stakenden Krypros muss mindesten %s betragen Der Stakingbetrag wird aufgrund der Netzwerkregeln auf %1$s TRX aufgerundet. Nicht gestakte beanspruche + Gebühr für das Staking-Konto + Ein Staking-Konto ist ein spezielles Konto, auf dem eingesetzte SOL-Token gelagert werden. Es wird erstellt, wenn du deine Token an einen Validator delegierst, um an der Transaktionsvalidierung teilzunehmen und Belohnungen zu verdienen. Für die Erstellung des Staking-Kontos wird eine geringe Gebühr erhoben, die nach Abschluss des Stakings zurückgegeben wird. Jährliche prozentuale Rendite Die jährliche prozentuale Rendite, die du durch die Teilnahme am Staking erzielen kannst. Effektiver Jahreszins @@ -721,6 +724,7 @@ Die Transaktion wird bearbeitet! Derzeit findet eine Validierung in der Blockchain statt. Dies kann einige Minuten dauern. Lösen der Bindungen Gelocktes unlocken + Entsperren Unstaken Staking beenden Unstake Assets %s @@ -863,6 +867,8 @@ Aktivierungsfehler Laut den Entwicklern des BNB-Netzes wird die Unterstützung für den BEP-2-Standard im Juni 2024 enden. Um den Verlust von Vermögenswerten mit diesem Standard zu vermeiden, konvertiere bitte in den BEP-20 Standard. Nutze gerne unseren Swap-Service, um sie auf das BNB Smart Chain Netzwerk zu übertragen. BNB Beacon Chain wird abgeschaltet + Bitte zahle ein paar %1$s ein, um die Netzwerkgebühr zu decken + Unzureichende Mittel zur Deckung der Netzgebühr Ausbaufähig Gefällt mir OK, habe ich verstanden! diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 3c8fb3e199..0bfcf8de3d 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -382,6 +382,7 @@ Sitio web Presión de compra La diferencia entre el volumen de compradores y el volumen de vendedores + Presión de compra Suministro circulante El número total de monedas que están disponibles para el comercio y que circulan en el mercado. Compradores experimentados diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index d2745aa359..0d3cb6b2bc 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -382,6 +382,7 @@ Site web Pression d\'achat La différence entre le volume des acheteurs et le volume des vendeurs + Pression d\'achat Approvisionnement en circulation Le nombre total de pièces disponibles pour le trading et en circulation sur le marché Acheteurs expérimentés diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index ace34d86b3..cff94ccc70 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -353,6 +353,7 @@ データを読み込めません… データなし クイックアクション + マーケットから探す 結果 時価総額10万ドル以下のトークンを見る トークンを表示 @@ -379,6 +380,7 @@ ウェブサイト 買い圧力 買い手と売り手の取引量の差 + 買い圧力 循環供給量 取引可能で市場に流通しているコインの総数 経験豊富な買い手 @@ -640,6 +642,8 @@ ステーキング金額は %s 以上である必要があります ネットワークルールにより、ステーキング金額は%1$s TRX に切り上げられます。 ステーキング解除分を請求する + ステーキングアカウント手数料 + ステーキングアカウントは、ステーキングされたSOLトークンが保管される特別なアカウントです。取引の検証に参加して報酬を得るために、トークンをバリデーターに委任すると、このアカウントが作成されます。ステーキングアカウントの作成には少額の手数料がかかりますが、この手数料はステーキングが完了すると返金されます。 年率 ステーキングに参加することで得られる年間収益率。 APR @@ -711,6 +715,7 @@ 取引を処理中です。現在、ブロックチェーンで検証が行われています。これには数分かかる場合があります。 ステーキング解約中 ロック解除 + ロック解除中 ステーキングされていない ステーキング解除 ステーキング解除中の資産%s @@ -853,6 +858,8 @@ アクティベーションに失敗しました BNBネットワーク開発者によると、BEP-2規格のサポートは2024年6月に終了します。この規格の資産を失わないために、BEP-20規格に変換してください。BNBスマートチェーンネットワークへ移行するには、Tangemのスワップサービスをご利用ください。 BNBビーコンチェーンは閉鎖されます。 + ネットワーク手数料をカバーするために%1$sを入金してください + ネットワーク手数料をカバーする資金が不足しています もっと良くなるはず 気に入った はい、わかりました! diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index fff0190f6d..fe50c2b14d 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -38,7 +38,7 @@ Слишком много попыток Вы отключили биометрическую аутентификацию на вашем телефоне и не сможете сохранять кошельки в приложении. Для сохранения кошельков, пожалуйста, включите функцию биометрической аутентификации в настройках телефона. Начать резервное копирование - С помощью банковской карты или банковского аккаунта + Используйте банковскую карту или другие методы оплаты %d карта %d карты @@ -276,7 +276,7 @@ Токены не найдены. Пожалуйста, попробуйте другой запрос ID: %s ID транзакции скопирован - С другой валютой в вашем кошельке + Конвертируйте одну из ваших валют в другую Информация ниже не является обязательной. Вы можете стереть её, если хотите. Расскажите, каких функций вам не хватает, и мы постараемся вам помочь. Скажите, пожалуйста, какая у вас карта? @@ -352,10 +352,12 @@ Мой портфель Рынок Чтобы создать адреса для выбранных сетей, отсканируйте вашу карту Tangem кошелька + Потяните вверх или коснитесь поисковой строки, чтобы добавить токен Данные раздела получены из следующих сетей: %s Невозможно загрузить данные Нет данных Быстрые действия + Искать на маркете Результат Токены с капитализацией меньше 100к USD Показать токены @@ -385,6 +387,7 @@ Веб-сайт Покуп. предпоч. Разница между объемом покупателей и продавцов + Покуп. предпоч. Циркулир. предл. Общее количество монет, доступных для торговли и находящихся в обращении на рынке Опытные трейдеры @@ -523,7 +526,7 @@ Доступ к камере запрещен %1$s (%2$s) в сети %3$s Отправляйте только %s на этот адрес. Использование другой сети может привести к утрате средств. - Покажи QR-код или поделись своим адресом + Переводите средства с другого кошелька или биржи Участвовать Не удалось загрузить информацию по реферальной программе. Пожалуйста, попробуйте позже. Не удалось загрузить информацию по реферальной программе. Код ошибки: %s. Пожалуйста, попробуйте позже. @@ -653,7 +656,9 @@ Это приведет к удалению кошелька из приложения. Сам кошелек можно добавить снова. Имя Сумма для стейкинга должна быть не менее %s + Согласно правилам сети, сумма стейкинга будет округлена до %1$sTRX. Забрать средства + Стейкинг аккаунт — это специальный счет, на котором хранятся застейканные токены SOL. Он создается при делегировании ваших токенов валидатору для участия в подтверждении транзакций и получении наград. За создание стейкинг аккаунта взимается небольшая комиссия, которая возвращается после завершения стейкинга. Процентная ставка Годовой процентный доход, который вы можете получить от участия в стейкинге. APR @@ -697,6 +702,7 @@ Блок День Каждый день + Каждую минуту Эпоха Эра Час diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index 9ef0e3fb24..c032f68459 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -120,7 +120,7 @@ Перейти до провайдера Перейти до токену Імпортувати - процесі + В процесі Пізніше Залишилося %1$s Заблокований @@ -357,6 +357,7 @@ Моє портфоліо Маркет Щоб згенерувати адреси для обраних мереж, потрібно відсканувати свою картку Tangem + Щоб додати токени, потягніть вгору або торкніться панелі пошуку Дані цього розділу отримані з наступних мереж: %s Не вдалося завантажити дані... Немає даних @@ -367,13 +368,13 @@ Жодного результату Виберіть мережу Оберіть гаманець - 1 міс. - 1 рік - 24 год. - 3 міс. - 6 міс. + + + 24г + + - Увесь + Усе Досвідчені покупці За рейтингом Сортувати за @@ -390,11 +391,12 @@ Веб-сайт Давлення покупця Різниця між обсягом покупців та обсягом продавців + Давлення покупця Циркуляційний запас Загальна кількість монет, які доступні для торгівлі та перебувають в обігу на ринку Досвідчені покупці Мережеві покупці з додатковою вимогою мати не менше 100 вихідних транзакцій - Повністю розведена ринкова капіталізація + Повн. розведена кап. Загальна теоретична вартість криптовалюти, якщо всі монети, які могли б існувати, перебувають в обігу, включаючи ті, що не перебувають в обігу в даний час Дата створення Високий @@ -661,6 +663,7 @@ Це призведе до видалення гаманця з застосунку. Сам гаманець можна додати знову. Ім\'я Сума для стейкінгу має бути не менше %s + Сума стейкінгу буде округлена до %1$s TRX відповідно до правил мережі. Зняти кошти Процентна ставка Річний відсоток, який ви можете отримати, беручи участь у стейкінгу. @@ -733,6 +736,7 @@ Транзакція обробляється! Наразі триває перевірка в блокчейні. Це може зайняти кілька хвилин. Розблокування Розблокувати + Розблокування Вивід зі стейкінгу Зняти зі стейкінгу Виведення зі стейкінгу %s @@ -875,6 +879,8 @@ Помилка активації За рішенням розробників мережі BNB стандарт BEP-2 перестане підтримуватись у червні 2024 року. Щоб не втратити свої активи, їх необхідно конвертувати у стандарт BEP-20. Використовуйте функцію обміну, щоб перевести їх у мережу BNB Smart Chain. Відключення мережі BNB Beacon Chain + Будь ласка, поповніть рахунок на %1$s для покриття комісії мережі + Недостатньо коштів для покриття комісії мережі Можна краще Вподобати Зрозуміло! diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 12c3f39762..e95c0bc2b7 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -39,7 +39,7 @@ Too many attempts You have disabled biometric authentication on your phone and will not be able to save wallets in the app. To save wallets, please enable the biometric authentication function in your phone settings. Start backup process - With your bank card or bank account + Use a bank card or other payment methods %d card %d cards @@ -275,7 +275,7 @@ No tokens found. Please try another request ID: %s Transaction ID copied - With another currency in your wallet + Convert one of your currencies to another The following information is optional. You can erase it if you don\'t want to share it. Tell us what functions you are missing, and we will try to help you. Please tell us what card do you have @@ -356,6 +356,7 @@ Unable to load the data… No data Quick actions + Search through the market Result See tokens under 100k USD market cap Show tokens @@ -383,6 +384,7 @@ Website Buy pressure The difference between buyers volume and sellers volume + Buy pressure Circulating supply The total number of coins that are available for trading and are circulating in the market Experienced buyers @@ -517,7 +519,7 @@ Camera access denied %1$s (%2$s) on %3$s network Send only %s to this address. Sending any other currency will result in its irreversible loss. - Show a QR-code or share your address + Transfer funds from another wallet or exchange Participate Failed to load the information about the referral program. Please try again later. Failed to load the information about the referral program. Error code: %s. Please try again later. @@ -567,7 +569,7 @@ Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. Get your card ready! Already included in the entered address - The commission amount is %s times the recommended amount. Make sure that the custom settings are correct. + Your commission amount is %s times higher than the recommended amount. Please review and adjust your custom settings. You specified a commission below the recommended amount, which could cause a delay in your transaction. Continue? Reason: %1$s\nCode: %2$s The transaction is not completed @@ -602,7 +604,7 @@ Total exceeds balance A balance of at least %s is required to keep your account on the blockchain to prevent security risks. This amount will remain in your balance and cannot be withdrawn. Existential deposit - The commission amount is %s times the recommended amount. Make sure that the custom settings are correct. + Your commission amount is %s times higher than the recommended amount. Please review and adjust your custom settings. Custom fee is high Due to the peculiarities of the %1$s network, the fee for transferring the entire balance is higher. To reduce the commission, you can leave %2$s. The fee is higher @@ -648,6 +650,8 @@ The amount to stake must be at least %s Staking amount will be rounded to %1$s TRX due to network rules. Claim unstaked + Stake account fee + A staking account is a special account where staked SOL tokens are stored. It is created when you delegate your tokens to a validator to participate in transaction validation and earn rewards. A small fee is charged for creating the staking account, which is returned after the staking is completed. Annual percentage rate The annual percentage return you can earn from participating in staking. APR @@ -675,6 +679,7 @@ Migrate Native staking Earned rewards will be sent to your wallet and available for use immediately + Stake securely and start earning your rewards Stake securely and start earning daily rewards Stake securely and start earning hourly rewards Stake securely and start earning monthly rewards @@ -703,6 +708,7 @@ Block Day Each day + Each minute Epoch Era Hour @@ -719,6 +725,7 @@ The transaction is being processed! Validation is currently underway in the blockchain. This may take a few minutes. Unbonding Unlock + Unlocking Unstaked Unstaking Unstaking assets %s diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt index 9667a00860..e43a390155 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt @@ -14,8 +14,8 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.R import com.tangem.core.ui.components.buttons.common.* -import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview // region TextButton /** @@ -102,6 +102,7 @@ fun PrimaryButton( enabled = enabled, showProgress = showProgress, size = size, + textStyle = TangemTheme.typography.subtitle1, ) } @@ -127,6 +128,7 @@ fun PrimaryButtonIconEnd( enabled = enabled, showProgress = showProgress, size = size, + textStyle = TangemTheme.typography.subtitle1, ) } @@ -153,6 +155,7 @@ fun PrimaryButtonIconEndTwoLines( showProgress = showProgress, additionalText = additionalText, size = TangemButtonSize.TwoLines, + textStyle = TangemTheme.typography.subtitle1, ) } @@ -176,6 +179,7 @@ fun PrimaryButtonIconStart( colors = TangemButtonsDefaults.primaryButtonColors, enabled = enabled, showProgress = showProgress, + textStyle = TangemTheme.typography.subtitle1, ) } // endregion PrimaryButton @@ -201,6 +205,7 @@ fun SecondaryButton( showProgress = showProgress, size = size, shape = shape, + textStyle = TangemTheme.typography.subtitle1, ) } @@ -224,6 +229,7 @@ fun SecondaryButtonIconEnd( colors = TangemButtonsDefaults.secondaryButtonColors, enabled = enabled, showProgress = showProgress, + textStyle = TangemTheme.typography.subtitle1, ) } @@ -247,6 +253,7 @@ fun SecondaryButtonIconStart( colors = TangemButtonsDefaults.secondaryButtonColors, enabled = enabled, showProgress = showProgress, + textStyle = TangemTheme.typography.subtitle1, ) } // endregion SecondaryButton diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt index 0991dcdf5a..6db1972160 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt @@ -39,6 +39,7 @@ import com.tangem.core.ui.res.TangemThemePreview * @param captionColor caption text color * @param isGrayscaleImage whether to display grayscale image * @param iconEndRes icon to end of row + * @param onImageError composable to show if image loading failed * @param extraContent extra content */ @Composable @@ -53,6 +54,7 @@ internal fun InputRowImageBase( iconTint: Color = TangemTheme.colors.icon.informative, isGrayscaleImage: Boolean = false, iconEndRes: Int? = null, + onImageError: (@Composable () -> Unit)? = null, extraContent: (@Composable RowScope.() -> Unit)? = null, ) { Row( @@ -63,13 +65,13 @@ internal fun InputRowImageBase( InputRowAsyncImage( imageUrl = imageUrl, isGrayscale = isGrayscaleImage, + onImageError = onImageError, modifier = Modifier .size(TangemTheme.dimens.spacing36) .clip(TangemTheme.shapes.roundedCornersXLarge), ) SpacerW12() - } - if (iconRes != null) { + } else if (iconRes != null) { Box( contentAlignment = Alignment.Center, modifier = Modifier diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt index 19bb005a00..2905e007b7 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageInfo.kt @@ -35,6 +35,7 @@ import com.tangem.core.ui.res.TangemThemePreview * @param captionColor caption text color * @param isGrayscaleImage whether to display grayscale image * @param iconEndRes icon to end of row + * @param onImageError composable to show if image loading failed */ @Suppress("LongParameterList") @Composable @@ -52,6 +53,7 @@ fun InputRowImageInfo( iconTint: Color = TangemTheme.colors.icon.informative, isGrayscaleImage: Boolean = false, @DrawableRes iconEndRes: Int? = null, + onImageError: (@Composable () -> Unit)? = null, ) { Column( verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing6), @@ -75,6 +77,7 @@ fun InputRowImageInfo( captionColor = captionColor, isGrayscaleImage = isGrayscaleImage, iconEndRes = iconEndRes, + onImageError = onImageError, ) { Column( verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing2), diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt index 6fcc6ef997..287edc1197 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt @@ -41,6 +41,7 @@ import java.math.BigDecimal * @param captionColor caption text color * @param isSelected true if selected * @param selectorContent selector content + * @param onImageError composable to show if image loading failed */ @Composable fun InputRowImageSelector( @@ -52,6 +53,7 @@ fun InputRowImageSelector( subtitleColor: Color = TangemTheme.colors.text.primary1, captionColor: Color = TangemTheme.colors.text.tertiary, isSelected: Boolean = false, + onImageError: (@Composable () -> Unit)? = null, selectorContent: @Composable ((isSelected: Boolean, isEnabled: Boolean, onSelect: () -> Unit) -> Unit), ) { InputRowImageBase( @@ -60,6 +62,7 @@ fun InputRowImageSelector( imageUrl = imageUrl, subtitleColor = subtitleColor, captionColor = captionColor, + onImageError = onImageError, modifier = modifier .clickable( onClick = onSelect, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/InputRowAsyncImage.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/InputRowAsyncImage.kt index b85e91ba30..3b46eeffc5 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/InputRowAsyncImage.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/InputRowAsyncImage.kt @@ -18,9 +18,15 @@ import com.tangem.core.ui.utils.getGreyScaleColorFilter * @param imageUrl url of the image * @param modifier modifier * @param isGrayscale whether to apply grayscale filter + * @param onImageError composable to show if image loading failed */ @Composable -internal fun InputRowAsyncImage(imageUrl: String, modifier: Modifier = Modifier, isGrayscale: Boolean = false) { +internal fun InputRowAsyncImage( + imageUrl: String, + modifier: Modifier = Modifier, + isGrayscale: Boolean = false, + onImageError: (@Composable () -> Unit)? = null, +) { val (alpha, colorFilter) = getGreyScaleColorFilter(isGrayscale = isGrayscale) SubcomposeAsyncImage( modifier = modifier, @@ -33,7 +39,7 @@ internal fun InputRowAsyncImage(imageUrl: String, modifier: Modifier = Modifier, .build(), loading = { LoadingIcon() }, error = { - Box( + onImageError?.invoke() ?: Box( modifier = Modifier .background( color = TangemTheme.colors.background.tertiary, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/list/InfiniteListHandler.kt b/core/ui/src/main/java/com/tangem/core/ui/components/list/InfiniteListHandler.kt index 9d5c548b93..8f5f5ba4b7 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/list/InfiniteListHandler.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/list/InfiniteListHandler.kt @@ -4,8 +4,13 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.runtime.* @Composable -fun InfiniteListHandler(listState: LazyListState, onLoadMore: () -> Boolean, buffer: Int = 2) { - val loadMore by remember { +fun InfiniteListHandler( + listState: LazyListState, + onLoadMore: () -> Boolean, + buffer: Int = 2, + triggerLoadMoreCheckOnItemsCountChange: Boolean = false, +) { + val loadMore by remember(buffer, listState) { derivedStateOf { val layoutInfo = listState.layoutInfo val totalItemsNumber = layoutInfo.totalItemsCount @@ -15,12 +20,18 @@ fun InfiniteListHandler(listState: LazyListState, onLoadMore: () -> Boolean, buf } } - val totalItemsCount by remember { derivedStateOf { listState.layoutInfo.totalItemsCount } } - var emitted by remember(totalItemsCount) { mutableStateOf(false) } + val totalItemsCount by remember(listState) { derivedStateOf { listState.layoutInfo.totalItemsCount } } + var emitted by remember(totalItemsCount, buffer, listState) { mutableStateOf(false) } LaunchedEffect(loadMore) { if (loadMore && !emitted) { emitted = onLoadMore() } } + + LaunchedEffect(totalItemsCount) { + if (triggerLoadMoreCheckOnItemsCountChange && loadMore && !emitted) { + emitted = onLoadMore() + } + } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt index a6031f054b..d76569543f 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt @@ -7,9 +7,9 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size -import androidx.compose.material3.ripple import androidx.compose.material3.Icon import androidx.compose.material3.Text +import androidx.compose.material3.ripple import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier @@ -132,17 +132,6 @@ fun NotificationWithBackground(config: NotificationConfig, modifier: Modifier = ) val isDarkMode = LocalIsInDarkTheme.current TangemButton( - text = button?.text?.resolveReference().orEmpty(), - icon = TangemButtonIconPosition.Start(button?.iconResId ?: R.drawable.ic_exchange_vertical_24), - onClick = button?.onClick ?: {}, - colors = TangemButtonColors( - backgroundColor = if (isDarkMode) Light4 else TangemTheme.colors.button.secondary, - contentColor = Dark6, - disabledBackgroundColor = TangemTheme.colors.button.disabled, - disabledContentColor = TangemTheme.colors.text.disabled, - ), - enabled = true, - showProgress = false, modifier = Modifier.constrainAs(buttonRef) { start.linkTo(parent.start, spacing12) end.linkTo(parent.end, spacing12) @@ -154,6 +143,18 @@ fun NotificationWithBackground(config: NotificationConfig, modifier: Modifier = Visibility.Visible } }, + text = button?.text?.resolveReference().orEmpty(), + icon = TangemButtonIconPosition.Start(button?.iconResId ?: R.drawable.ic_exchange_vertical_24), + onClick = button?.onClick ?: {}, + colors = TangemButtonColors( + backgroundColor = if (isDarkMode) Light4 else TangemTheme.colors.button.secondary, + contentColor = Dark6, + disabledBackgroundColor = TangemTheme.colors.button.disabled, + disabledContentColor = TangemTheme.colors.text.disabled, + ), + textStyle = TangemTheme.typography.subtitle1, + enabled = true, + showProgress = false, ) } } diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/OkxPromoNotification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/OkxPromoNotification.kt index 2888045227..94f39ed5dd 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/OkxPromoNotification.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/OkxPromoNotification.kt @@ -110,6 +110,13 @@ private fun Button(config: NotificationConfig) { button?.let { val isDarkMode = LocalIsInDarkTheme.current TangemButton( + modifier = Modifier + .fillMaxWidth() + .padding( + start = TangemTheme.dimens.spacing12, + end = TangemTheme.dimens.spacing12, + bottom = TangemTheme.dimens.spacing12, + ), text = button.text.resolveReference(), icon = TangemButtonIconPosition.Start(button.iconResId ?: R.drawable.ic_exchange_vertical_24), onClick = button.onClick, @@ -119,15 +126,9 @@ private fun Button(config: NotificationConfig) { disabledBackgroundColor = TangemTheme.colors.button.disabled, disabledContentColor = TangemTheme.colors.text.disabled, ), + textStyle = TangemTheme.typography.subtitle1, enabled = true, showProgress = false, - modifier = Modifier - .fillMaxWidth() - .padding( - start = TangemTheme.dimens.spacing12, - end = TangemTheme.dimens.spacing12, - bottom = TangemTheme.dimens.spacing12, - ), ) } } diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/DecimalFormatterExt.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/DecimalFormatterExt.kt index 2d685763e3..a251b0c9ed 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/utils/DecimalFormatterExt.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/DecimalFormatterExt.kt @@ -138,7 +138,7 @@ fun String.parseToBigDecimal(decimals: Int): BigDecimal { } } -fun BigDecimal.parseBigDecimal(decimals: Int, roundingMode: RoundingMode = RoundingMode.DOWN): String { +fun BigDecimal.parseBigDecimal(decimals: Int, roundingMode: RoundingMode = RoundingMode.HALF_UP): String { val decimalFormat = DecimalFormat().apply { decimalFormatSymbols = DecimalFormatSymbols(Locale.getDefault()) isParseBigDecimal = true diff --git a/core/ui/src/main/res/drawable/ic_staking_filled_18.xml b/core/ui/src/main/res/drawable/ic_staking_filled_18.xml new file mode 100644 index 0000000000..e6741b6156 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_staking_filled_18.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/data/markets/src/main/java/com/tangem/data/markets/DefaultMarketsTokenRepository.kt b/data/markets/src/main/java/com/tangem/data/markets/DefaultMarketsTokenRepository.kt index 39637200e5..79576d75c3 100644 --- a/data/markets/src/main/java/com/tangem/data/markets/DefaultMarketsTokenRepository.kt +++ b/data/markets/src/main/java/com/tangem/data/markets/DefaultMarketsTokenRepository.kt @@ -9,14 +9,17 @@ import com.tangem.data.common.currency.CryptoCurrencyFactory import com.tangem.data.common.currency.getNetwork import com.tangem.data.common.utils.retryOnError import com.tangem.data.markets.analytics.MarketsDataAnalyticsEvent +import com.tangem.data.markets.converters.* import com.tangem.data.markets.converters.TokenChartConverter import com.tangem.data.markets.converters.TokenMarketInfoConverter import com.tangem.data.markets.converters.TokenMarketListConverter +import com.tangem.data.markets.converters.TokenQuotesShortConverter import com.tangem.data.markets.converters.toRequestParam import com.tangem.datasource.api.common.response.ApiResponseError import com.tangem.datasource.api.common.response.getOrThrow import com.tangem.datasource.api.markets.TangemTechMarketsApi import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.api.tangemTech.TangemTechApi.Companion.marketsQuoteFields import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.markets.* @@ -188,16 +191,24 @@ internal class DefaultMarketsTokenRepository( return TokenMarketInfoConverter.convert(resultResponse) } - override suspend fun getTokenQuotes(fiatCurrencyCode: String, tokenId: String): TokenQuotes { - // TODO change method when backend is ready - // add error analytics event - val response = marketsApi.getCoinMarketData( - currency = fiatCurrencyCode, - coinId = tokenId, - language = "en", + override suspend fun getTokenQuotes(fiatCurrencyCode: String, tokenId: String, tokenSymbol: String): TokenQuotes { + // for second markets iteration we should use extended api method with all required fields + val response = tangemTechApi.getQuotes( + currencyId = fiatCurrencyCode, + coinIds = tokenId, + fields = marketsQuoteFields.joinToString(separator = ","), ) - return TokenMarketInfoConverter.convert(response.getOrThrow()).quotes + val result = catchApiErrorAndSendEvent( + errorEvent = MarketsDataAnalyticsEvent.Details.Error( + request = MarketsDataAnalyticsEvent.Details.Error.Request.Info, + tokenSymbol = tokenSymbol, + ), + ) { + response.getOrThrow() + } + + return TokenQuotesShortConverter.convert(tokenId, result).toFull() } override suspend fun createCryptoCurrency( diff --git a/data/markets/src/main/java/com/tangem/data/markets/MarketsBatchUpdateFetcher.kt b/data/markets/src/main/java/com/tangem/data/markets/MarketsBatchUpdateFetcher.kt index 95fb2cca25..18c7155b03 100644 --- a/data/markets/src/main/java/com/tangem/data/markets/MarketsBatchUpdateFetcher.kt +++ b/data/markets/src/main/java/com/tangem/data/markets/MarketsBatchUpdateFetcher.kt @@ -9,6 +9,7 @@ import com.tangem.datasource.api.common.response.getOrThrow import com.tangem.datasource.api.markets.TangemTechMarketsApi import com.tangem.datasource.api.markets.models.response.TokenMarketChartListResponse import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.api.tangemTech.TangemTechApi.Companion.marketsQuoteFields import com.tangem.domain.markets.TokenMarket import com.tangem.domain.markets.TokenMarketUpdateRequest import com.tangem.pagination.Batch @@ -70,7 +71,7 @@ internal class MarketsBatchUpdateFetcher( tangemTechApi.getQuotes( currencyId = updateRequest.currencyId, coinIds = idsToUpdate.map { it.second }.flatten().joinToString(separator = ","), - fields = quoteFields.joinToString(separator = ","), + fields = marketsQuoteFields.joinToString(separator = ","), ).getOrThrow() } } @@ -120,13 +121,4 @@ internal class MarketsBatchUpdateFetcher( throw e } } - - companion object { - private val quoteFields = listOf( - "price", - "priceChange24h", - "priceChange1w", - "priceChange30d", - ) - } } \ No newline at end of file diff --git a/data/markets/src/main/java/com/tangem/data/markets/di/MarketsDataModule.kt b/data/markets/src/main/java/com/tangem/data/markets/di/MarketsDataModule.kt index 4ef2f1e094..fa4e3d492f 100644 --- a/data/markets/src/main/java/com/tangem/data/markets/di/MarketsDataModule.kt +++ b/data/markets/src/main/java/com/tangem/data/markets/di/MarketsDataModule.kt @@ -4,7 +4,6 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.data.markets.DefaultMarketsTokenRepository import com.tangem.datasource.api.markets.TangemTechMarketsApi import com.tangem.datasource.api.tangemTech.TangemTechApi -import com.tangem.datasource.di.DevTangemApi import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.domain.markets.repositories.MarketsTokenRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -21,8 +20,8 @@ internal object MarketsDataModule { @Provides @Singleton fun provideMarketsRepository( - @DevTangemApi marketsApi: TangemTechMarketsApi, - @DevTangemApi tangemTechApi: TangemTechApi, + marketsApi: TangemTechMarketsApi, + tangemTechApi: TangemTechApi, userWalletsStore: UserWalletsStore, dispatchers: CoroutineDispatcherProvider, analyticsEventHandler: AnalyticsEventHandler, diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt b/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt index 68b724e1b7..601ecc526b 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt @@ -61,7 +61,7 @@ object TapWorkarounds { ) // TODO try remove if it's possible because we can configure on init sdk com.tangem.common.core.Config - private val excludedBatches = listOf("0027", "0030", "0031", "0035", "DA88") + private val excludedBatches = listOf("0027", "0030", "0031", "0035", "DA88", "AF56") private val excludedIssuers = listOf("TTM BANK") diff --git a/domain/markets/models/src/main/kotlin/com/tangem/domain/markets/TokenQuotes.kt b/domain/markets/models/src/main/kotlin/com/tangem/domain/markets/TokenQuotes.kt index 18826801e3..56bd39c7c1 100644 --- a/domain/markets/models/src/main/kotlin/com/tangem/domain/markets/TokenQuotes.kt +++ b/domain/markets/models/src/main/kotlin/com/tangem/domain/markets/TokenQuotes.kt @@ -11,4 +11,17 @@ data class TokenQuotes( val m6ChangePercent: BigDecimal?, val yearChangePercent: BigDecimal?, val allTimeChangePercent: BigDecimal?, -) \ No newline at end of file +) + +fun TokenQuotes.populateWith(quotes: TokenQuotes): TokenQuotes { + return TokenQuotes( + currentPrice = quotes.currentPrice, + h24ChangePercent = quotes.h24ChangePercent ?: this.h24ChangePercent, + weekChangePercent = quotes.weekChangePercent ?: this.weekChangePercent, + monthChangePercent = quotes.monthChangePercent ?: this.monthChangePercent, + m3ChangePercent = quotes.m3ChangePercent ?: this.m3ChangePercent, + m6ChangePercent = quotes.m6ChangePercent ?: this.m6ChangePercent, + yearChangePercent = quotes.yearChangePercent ?: this.yearChangePercent, + allTimeChangePercent = quotes.allTimeChangePercent ?: this.allTimeChangePercent, + ) +} \ No newline at end of file diff --git a/domain/markets/models/src/main/kotlin/com/tangem/domain/markets/TokenQuotesShort.kt b/domain/markets/models/src/main/kotlin/com/tangem/domain/markets/TokenQuotesShort.kt index 3b6bb3bdf1..ce2ff4bb71 100644 --- a/domain/markets/models/src/main/kotlin/com/tangem/domain/markets/TokenQuotesShort.kt +++ b/domain/markets/models/src/main/kotlin/com/tangem/domain/markets/TokenQuotesShort.kt @@ -7,4 +7,15 @@ data class TokenQuotesShort( val h24ChangePercent: BigDecimal, val weekChangePercent: BigDecimal, val monthChangePercent: BigDecimal, +) + +fun TokenQuotesShort.toFull() = TokenQuotes( + currentPrice = currentPrice, + h24ChangePercent = h24ChangePercent, + weekChangePercent = weekChangePercent, + monthChangePercent = monthChangePercent, + m3ChangePercent = null, + m6ChangePercent = null, + yearChangePercent = null, + allTimeChangePercent = null, ) \ No newline at end of file diff --git a/domain/markets/src/main/java/com/tangem/domain/markets/GetTokenFullQuotesUseCase.kt b/domain/markets/src/main/java/com/tangem/domain/markets/GetTokenFullQuotesUseCase.kt index a755057a98..e8b8470add 100644 --- a/domain/markets/src/main/java/com/tangem/domain/markets/GetTokenFullQuotesUseCase.kt +++ b/domain/markets/src/main/java/com/tangem/domain/markets/GetTokenFullQuotesUseCase.kt @@ -7,11 +7,16 @@ import com.tangem.domain.markets.repositories.MarketsTokenRepository class GetTokenFullQuotesUseCase( private val marketsTokenRepository: MarketsTokenRepository, ) { - suspend operator fun invoke(appCurrency: AppCurrency, tokenId: String): Either { + suspend operator fun invoke( + appCurrency: AppCurrency, + tokenId: String, + tokenSymbol: String, + ): Either { return Either.catch { marketsTokenRepository.getTokenQuotes( fiatCurrencyCode = appCurrency.code, tokenId = tokenId, + tokenSymbol = tokenSymbol, ) }.mapLeft {} } diff --git a/domain/markets/src/main/java/com/tangem/domain/markets/repositories/MarketsTokenRepository.kt b/domain/markets/src/main/java/com/tangem/domain/markets/repositories/MarketsTokenRepository.kt index c9ff5dae64..f28da22c7b 100644 --- a/domain/markets/src/main/java/com/tangem/domain/markets/repositories/MarketsTokenRepository.kt +++ b/domain/markets/src/main/java/com/tangem/domain/markets/repositories/MarketsTokenRepository.kt @@ -33,7 +33,7 @@ interface MarketsTokenRepository { languageCode: String, ): TokenMarketInfo - suspend fun getTokenQuotes(fiatCurrencyCode: String, tokenId: String): TokenQuotes + suspend fun getTokenQuotes(fiatCurrencyCode: String, tokenId: String, tokenSymbol: String): TokenQuotes suspend fun createCryptoCurrency( userWalletId: UserWalletId, diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt index abdf3f94fd..c8990cebf4 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt @@ -61,7 +61,7 @@ internal class CurrencyStatusOperations( (yieldBalance as? YieldBalance.Data)?.address == status.address.defaultAddress.value val currentYieldBalance = yieldBalance.takeIf { isCurrentAddressStaking } return when { - ignoreQuote -> CryptoCurrencyStatus.NoQuote( + ignoreQuote || quote == null -> CryptoCurrencyStatus.NoQuote( amount = amount, hasCurrentNetworkTransactions = hasCurrentNetworkTransactions, pendingTransactions = currentTransactions, @@ -70,15 +70,14 @@ internal class CurrencyStatusOperations( ) currency is CryptoCurrency.Token && currency.isCustom -> CryptoCurrencyStatus.Custom( amount = amount, - fiatAmount = calculateFiatAmountOrNull(amount, quote?.fiatRate), - fiatRate = quote?.fiatRate, - priceChange = quote?.priceChange, + fiatAmount = calculateFiatAmountOrNull(amount, quote.fiatRate), + fiatRate = quote.fiatRate, + priceChange = quote.priceChange, hasCurrentNetworkTransactions = hasCurrentNetworkTransactions, pendingTransactions = currentTransactions, networkAddress = status.address, yieldBalance = currentYieldBalance, ) - quote == null -> CryptoCurrencyStatus.Loading else -> CryptoCurrencyStatus.Loaded( amount = amount, fiatAmount = calculateFiatAmount(amount, quote.fiatRate), diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt index 354252452c..7e4bc12ae2 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt @@ -7,7 +7,9 @@ import arrow.core.raise.either import arrow.core.raise.ensure import arrow.core.raise.ensureNotNull import arrow.core.toNonEmptyListOrNull +import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.model.* +import com.tangem.utils.extensions.orZero import java.math.BigDecimal internal class TokenListSortingOperations( @@ -83,7 +85,7 @@ internal class TokenListSortingOperations( return if (isAnyTokenLoading) { tokens } else { - tokens.sortedByDescending { it.value.fiatAmount ?: BigDecimal.ZERO } + tokens.sortedByDescending { it.getTotalBalance() } .toNonEmptyListOrNull() ?: error("Tokens can not be empty here") } @@ -92,12 +94,20 @@ internal class TokenListSortingOperations( private fun sortGroupsByBalance(groupsWithSortedTokens: NonEmptyList): NonEmptyList { return groupsWithSortedTokens .sortedByDescending { group -> - group.currencies.sumOf { it.value.fiatAmount ?: BigDecimal.ZERO } + group.currencies.sumOf { it.getTotalBalance() } } .toNonEmptyListOrNull() ?: error("Tokens can not be empty here") } + private fun CryptoCurrencyStatus.getTotalBalance(): BigDecimal { + val yieldBalance = value.yieldBalance as? YieldBalance.Data + val totalYieldBalance = yieldBalance?.getTotalWithRewardsStakingBalance().orZero() + val totalFiatYieldBalance = totalYieldBalance.multiply(value.fiatRate.orZero()) + + return value.fiatAmount?.plus(totalFiatYieldBalance).orZero() + } + sealed class Error { object EmptyTokens : Error() diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt index 5f12f70b59..647c40534c 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt @@ -229,6 +229,7 @@ internal class MarketsTokenDetailsModel @Inject constructor( val result = getTokenFullQuotesUseCase( tokenId = params.token.id, appCurrency = currentAppCurrency.value, + tokenSymbol = params.token.symbol, ) result.onRight { res -> @@ -389,9 +390,11 @@ internal class MarketsTokenDetailsModel @Inject constructor( } private suspend fun updateQuotes(newQuotes: TokenQuotes) { - quotesStateUpdater.updateQuotes(newQuotes) + val populatedNewQuotes = currentQuotes.value.populateWith(newQuotes) - val percent = newQuotes + quotesStateUpdater.updateQuotes(newQuotes = populatedNewQuotes) + + val percent = populatedNewQuotes .getPercentByInterval(interval = state.value.selectedInterval) chartDataProducer.runTransaction { diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/AddToPortfolioBottomSheet.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/AddToPortfolioBottomSheet.kt index b73ba99609..73f6dca547 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/AddToPortfolioBottomSheet.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/AddToPortfolioBottomSheet.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.util.fastForEachIndexed @@ -162,6 +163,7 @@ private fun ContinueButton( showProgress = false, size = TangemButtonSize.Default, colors = TangemButtonsDefaults.primaryButtonColors, + textStyle = TangemTheme.typography.subtitle1, onClick = onClick, animateContentChange = true, ) @@ -200,10 +202,13 @@ private fun NetworkSelection(state: SelectNetworkUM, modifier: Modifier = Modifi Text( modifier = Modifier .align(Alignment.CenterVertically) + .weight(1f, fill = false) .alignByBaseline(), text = state.tokenName, style = TangemTheme.typography.body1, color = TangemTheme.colors.text.primary1, + overflow = TextOverflow.Ellipsis, + maxLines = 1, ) SpacerW6() Text( @@ -213,6 +218,8 @@ private fun NetworkSelection(state: SelectNetworkUM, modifier: Modifier = Modifi text = state.tokenCurrencySymbol, style = TangemTheme.typography.body1, color = TangemTheme.colors.text.tertiary, + overflow = TextOverflow.Visible, + maxLines = 1, ) } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewAddToPortfolioBSContentProvider.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewAddToPortfolioBSContentProvider.kt index 3b0e811163..3c8cb60016 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewAddToPortfolioBSContentProvider.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/preview/PreviewAddToPortfolioBSContentProvider.kt @@ -62,14 +62,14 @@ internal class PreviewAddToPortfolioBSContentProvider : PreviewParameterProvider selectedWallet = userWallet, selectNetworkUM = SelectNetworkUM( tokenId = "etherium", - tokenName = "Etherium", + tokenName = "Etherium Etherium Etherium Etherium", tokenCurrencySymbol = "ETH", networks = persistentListOf( blockchainRow.copy( type = "MAIN", isMainNetwork = true, isSelected = true, - ), + ).copy(name = "Etherium Etherium Etherium Etherium"), *Array(25) { blockchainRow }, ), diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/statemanager/MarketsListUMStateManager.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/statemanager/MarketsListUMStateManager.kt index f22b26c622..65d8c2df96 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/statemanager/MarketsListUMStateManager.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/statemanager/MarketsListUMStateManager.kt @@ -14,7 +14,6 @@ import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListUM import com.tangem.features.markets.tokenlist.impl.ui.state.SortByTypeUM import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.* @@ -111,54 +110,55 @@ internal class MarketsListUMStateManager( private fun MarketsListUM.updateItems(newItems: ImmutableList): MarketsListUM { val currentState = this - val isNextPageInSearch = isInSearchState && (this.list as? ListUM.Content)?.showUnder100kTokens == true - var searchUiItemsCached: ImmutableList = persistentListOf() - val items = when { - isInSearchState && isNextPageInSearch.not() -> { - searchUiItemsCached = newItems - val filtered = newItems.filter { item -> item.isUnder100kMarketCap.not() }.toImmutableList() + if (isInSearchMode.not() || currentState.showUnder100kButtonAlreadyPressed()) { + val itemsWithFilteredPriceChange = newItems.filterPriceChangeByVisibility() - if (filtered.size == newItems.size) { - return currentState.copy(list = generalContentState(newItems)) - } else { - filtered - } - } - else -> { - searchUiItemsCached = persistentListOf() - newItems - } + return currentState.copy( + list = generalContentState(itemsWithFilteredPriceChange) + .copy( + showUnder100kTokensNotificationWasHidden = currentState.showUnder100kButtonAlreadyPressed(), + ), + ) } - val itemsWithFilteredPriceChange = items.filterPriceChangeByVisibility() + // Search state cases - return currentState.copy( - list = ListUM.Content( - items = itemsWithFilteredPriceChange, - loadMore = onLoadMoreUiItems, - visibleIdsChanged = visibleItemsChanged, - showUnder100kTokens = isInSearchState.not() || isNextPageInSearch, - onShowTokensUnder100kClicked = { - if (searchUiItemsCached.isNotEmpty()) { + val filtered = newItems.filter { item -> item.isUnder100kMarketCap.not() } + .toImmutableList() + .filterPriceChangeByVisibility() + + if (filtered.size != newItems.size) { + val searchUiItemsCached = newItems.filterPriceChangeByVisibility() + + return currentState.copy( + list = generalContentState(filtered).copy( + showUnder100kTokensNotificationWasHidden = false, + showUnder100kTokensNotification = true, + onShowTokensUnder100kClicked = { state.update { s -> - if (s.list is ListUM.Content) { + (s.list as? ListUM.Content)?.let { s.copy( list = s.list.copy( items = searchUiItemsCached, - showUnder100kTokens = true, + showUnder100kTokensNotification = false, + showUnder100kTokensNotificationWasHidden = true, ), ) - } else { - s - } + } ?: s } - } - }, - triggerScrollReset = consumedEvent(), - onItemClick = onTokenClick, - ), - ) + }, + ), + ) + } else { + return currentState.copy( + list = generalContentState(newItems.filterPriceChangeByVisibility()), + ) + } + } + + private fun MarketsListUM.showUnder100kButtonAlreadyPressed(): Boolean { + return this.list is ListUM.Content && this.isInSearchMode && this.list.showUnder100kTokensNotificationWasHidden } // Show price change animation for visible items only @@ -182,10 +182,11 @@ internal class MarketsListUMStateManager( items = newItems, loadMore = onLoadMoreUiItems, visibleIdsChanged = visibleItemsChanged, - showUnder100kTokens = true, + showUnder100kTokensNotification = false, onShowTokensUnder100kClicked = {}, triggerScrollReset = consumedEvent(), onItemClick = onTokenClick, + showUnder100kTokensNotificationWasHidden = false, ) } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt index 9c52cb6bdb..6847621b60 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt @@ -301,7 +301,8 @@ private fun Preview() { item.copy(id = index.toString()) } .toImmutableList(), - showUnder100kTokens = false, + showUnder100kTokensNotification = false, + showUnder100kTokensNotificationWasHidden = false, loadMore = {}, visibleIdsChanged = {}, onShowTokensUnder100kClicked = {}, diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListLazyColumn.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListLazyColumn.kt index 5d70d6e85e..f4dd833503 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListLazyColumn.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListLazyColumn.kt @@ -22,6 +22,7 @@ import com.tangem.features.markets.tokenlist.impl.ui.state.ListUM import kotlinx.coroutines.launch private const val LOAD_NEXT_PAGE_ON_END_INDEX = 50 +private const val LOAD_NEXT_PAGE_ON_END_INDEX_SEARCH = 25 private const val TOKEN_LAZY_LIST_ID_SEPARATOR = "***" @Composable @@ -95,7 +96,7 @@ internal fun MarketsListLazyColumn( ) } - if (isInSearchMode && state.showUnder100kTokens.not()) { + if (isInSearchMode && state.showUnder100kTokensNotification) { item(key = "show tokens under 100k".hashCode()) { ShowTokensUnder100kItem( onShowTokensClick = state.onShowTokensUnder100kClicked, @@ -112,10 +113,15 @@ internal fun MarketsListLazyColumn( InfiniteListHandler( listState = lazyListState, - buffer = LOAD_NEXT_PAGE_ON_END_INDEX, + buffer = if (isInSearchMode) { + LOAD_NEXT_PAGE_ON_END_INDEX_SEARCH + } else { + LOAD_NEXT_PAGE_ON_END_INDEX + }, + triggerLoadMoreCheckOnItemsCountChange = true, onLoadMore = remember(state) { { - if (state is ListUM.Content && state.showUnder100kTokens) { + if (state is ListUM.Content && state.showUnder100kTokensNotification.not()) { state.loadMore() true } else { diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/preview/MarketChartListItemPreviewDataProvider.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/preview/MarketChartListItemPreviewDataProvider.kt index 41d1596f68..e0c4a52d54 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/preview/MarketChartListItemPreviewDataProvider.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/preview/MarketChartListItemPreviewDataProvider.kt @@ -22,6 +22,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet chardData = MarketChartRawData( y = persistentListOf(0.4, 0.2, 0.4, 0.1, 0.4, 2.0, 5.0, 0.1, 2.0, 2.0, 3.0), ), + isUnder100kMarketCap = false, ), MarketsListItemUM( id = "1", @@ -34,6 +35,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet trendPercentText = "12.43%", trendType = PriceChangeType.NEUTRAL, chardData = null, + isUnder100kMarketCap = false, ), MarketsListItemUM( id = "1", @@ -48,6 +50,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet chardData = MarketChartRawData( y = persistentListOf(0.4, 0.2, 0.4, 0.1, 0.4, 2.0, 5.0, 0.1, 2.0, 2.0, 3.0), ), + isUnder100kMarketCap = false, ), MarketsListItemUM( id = "1", @@ -62,6 +65,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet chardData = MarketChartRawData( y = persistentListOf(0.4, 0.2, 0.4, 0.1, 0.4, 2.0, 5.0, 0.1, 2.0, 2.0, 3.0), ), + isUnder100kMarketCap = false, ), MarketsListItemUM( id = "1", @@ -76,6 +80,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet chardData = MarketChartRawData( y = persistentListOf(0.4, 0.2, 0.4, 0.1, 0.4, 2.0, 5.0, 0.1, 2.0, 2.0, 3.0), ), + isUnder100kMarketCap = false, ), MarketsListItemUM( id = "1", @@ -90,6 +95,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet chardData = MarketChartRawData( y = persistentListOf(0.4, 0.2, 0.4, 0.1, 0.4, 2.0, 5.0, 0.1, 2.0, 2.0, 3.0), ), + isUnder100kMarketCap = false, ), ), ) \ No newline at end of file diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListItemUM.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListItemUM.kt index 9f3821c9c5..9bc808aee8 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListItemUM.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListItemUM.kt @@ -17,7 +17,7 @@ data class MarketsListItemUM( val trendPercentText: String, val trendType: PriceChangeType, val chardData: MarketChartRawData?, - val isUnder100kMarketCap: Boolean = false, + val isUnder100kMarketCap: Boolean, ) { val chartType: MarketChartLook.Type = when (trendType) { PriceChangeType.UP -> MarketChartLook.Type.Growing diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListUM.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListUM.kt index 7906cc1fb9..10ed82175e 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListUM.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/state/MarketsListUM.kt @@ -41,7 +41,8 @@ sealed class ListUM { data class Content( val items: ImmutableList, - val showUnder100kTokens: Boolean, + val showUnder100kTokensNotification: Boolean, + val showUnder100kTokensNotificationWasHidden: Boolean, val loadMore: () -> Unit, val visibleIdsChanged: (List) -> Unit, val onShowTokensUnder100kClicked: () -> Unit, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt index 8cd6867e1d..864a75afa0 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt @@ -127,6 +127,7 @@ private fun SendNavigationButton( } } TangemButton( + modifier = Modifier.fillMaxWidth(), text = stringResource(buttonTextId), icon = buttonIcon, enabled = isButtonEnabled, @@ -135,8 +136,8 @@ private fun SendNavigationButton( buttonClick() }, showProgress = false, - modifier = Modifier.fillMaxWidth(), colors = TangemButtonsDefaults.primaryButtonColors, + textStyle = TangemTheme.typography.subtitle1, ) } } @@ -274,7 +275,7 @@ private fun isButtonEnabled(currentState: SendUiCurrentScreen, uiState: SendUiSt private fun getTokenFeeSendingText(feeState: SendStates.FeeState, fee: Fee.Tron, sendingValue: String): TextReference { val suffix = when { - fee.feeEnergy == 0L -> { + fee.remainingEnergy == 0L -> { resourceReference( R.string.send_summary_transaction_description_suffix_including, wrappedList(feeState.getFiatValue()), diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingNotificationsTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingNotificationsTransformer.kt index f4f4da10b4..181d37a8a2 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingNotificationsTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingNotificationsTransformer.kt @@ -73,6 +73,7 @@ internal class AddStakingNotificationsTransformer( isSubtractAvailable = isSubtractAvailable, reduceAmountBy = reduceAmountBy, ) + val minimumRequirement = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum.orZero() val sendingAmount = if (isEnterAction) { checkAndCalculateSubtractedAmount( isAmountSubtractAvailable = isSubtractAvailable, @@ -84,7 +85,7 @@ internal class AddStakingNotificationsTransformer( } else { // No amount is taken from account balance on exit or pending actions BigDecimal.ZERO - } + }.max(minimumRequirement) val notifications = buildList { // errors @@ -106,7 +107,7 @@ internal class AddStakingNotificationsTransformer( amountState = amountState, feeState = feeState, sendingAmount = sendingAmount, - isFeeCoverage = isFeeCoverage && isEnterAction, + isFeeCoverage = isFeeCoverage && isEnterAction && !sendingAmount.equals(minimumRequirement), ) addInfoNotifications(prevState) @@ -223,11 +224,10 @@ internal class AddStakingNotificationsTransformer( cryptoCurrencyStatus: CryptoCurrencyStatus, onClick: (CryptoCurrency) -> Unit, ) { - val minimumRequirement = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO if (!isSubtractionAvailable) return - val showNotification = sendingAmount + feeAmount > balance - minimumRequirement.orZero() + val showNotification = sendingAmount + feeAmount > balance if (showNotification) { val notification = if (actionType == StakingActionCommonType.ENTER) { NotificationUM.Error.TotalExceedsBalance diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt index bd88fa6ffc..27d5d30086 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt @@ -35,7 +35,7 @@ internal class SetConfirmationStateLoadingTransformer( availableValidators = yield.validators, ), notifications = persistentListOf(), - footerText = getFooter(prevState), + footerText = getFooter(prevState, chosenValidator), transactionDoneState = TransactionDoneState.Empty, pendingAction = possibleConfirmationState?.pendingAction, pendingActions = possibleConfirmationState?.pendingActions, @@ -45,14 +45,12 @@ internal class SetConfirmationStateLoadingTransformer( ) } - private fun getFooter(state: StakingUiState): TextReference { + private fun getFooter(state: StakingUiState, validator: Yield.Validator): TextReference { val amountState = state.amountState as? AmountState.Data - val confirmationState = state.confirmationState as? StakingStates.ConfirmationState.Data - val validatorState = confirmationState?.validatorState as? ValidatorState.Content val isEnterAction = state.actionType == StakingActionCommonType.ENTER - val apr = validatorState?.chosenValidator?.apr.orZero() + val apr = validator.apr.orZero() val amountDecimal = amountState?.amountTextField?.fiatAmount?.value val potentialReward = amountDecimal?.multiply(apr) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt index c2a2c681a5..517cbba094 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt @@ -19,6 +19,7 @@ import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType import com.tangem.features.staking.impl.presentation.state.converters.RewardsValidatorStateConverter import com.tangem.features.staking.impl.presentation.state.converters.YieldBalancesConverter import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.lib.crypto.BlockchainUtils.isCosmos import com.tangem.lib.crypto.BlockchainUtils.isPolkadot import com.tangem.utils.Provider import com.tangem.utils.isNullOrZero @@ -201,12 +202,12 @@ internal class SetInitialDataStateTransformer( private fun createRewardScheduleItem( rewardSchedule: Yield.Metadata.RewardSchedule, ): RoundedListWithDividersItemData? { - val endTextId = rewardScheduleResources[rewardSchedule] ?: return null + val endTextReference = getRewardScheduleText(rewardSchedule) ?: return null return RoundedListWithDividersItemData( id = R.string.staking_details_reward_schedule, - startText = TextReference.Res(R.string.staking_details_reward_schedule), - endText = TextReference.Res(endTextId), + startText = resourceReference(R.string.staking_details_reward_schedule), + endText = endTextReference, iconClick = { clickIntents.onInfoClick(InfoType.REWARD_SCHEDULE) }, ) } @@ -252,21 +253,29 @@ internal class SetInitialDataStateTransformer( return resourceReference(R.string.common_range, wrappedList(formattedMinApr, formattedMaxApr)) } - companion object { - private val EQUALITY_THRESHOLD = BigDecimal(1E-10) + private fun getRewardScheduleText(rewardSchedule: Yield.Metadata.RewardSchedule): TextReference? { + return when (rewardSchedule) { + Yield.Metadata.RewardSchedule.BLOCK -> { + val networkId = cryptoCurrencyStatusProvider().currency.network.id.value + when { + isCosmos(networkId) -> resourceReference(R.string.staking_reward_schedule_each_minute) + else -> resourceReference(R.string.staking_reward_schedule_each_day) + } + } + Yield.Metadata.RewardSchedule.WEEK -> resourceReference(R.string.staking_reward_schedule_week) + Yield.Metadata.RewardSchedule.HOUR -> resourceReference(R.string.staking_reward_schedule_hour) + Yield.Metadata.RewardSchedule.DAY -> resourceReference(R.string.staking_reward_schedule_each_day) + Yield.Metadata.RewardSchedule.MONTH -> resourceReference(R.string.staking_reward_schedule_month) + Yield.Metadata.RewardSchedule.ERA -> resourceReference(R.string.staking_reward_schedule_era) + Yield.Metadata.RewardSchedule.EPOCH -> resourceReference(R.string.staking_reward_schedule_epoch) + Yield.Metadata.RewardSchedule.UNKNOWN -> null + } + } - private val rewardScheduleResources = mapOf( - Yield.Metadata.RewardSchedule.BLOCK to R.string.staking_reward_schedule_each_day, - Yield.Metadata.RewardSchedule.WEEK to R.string.staking_reward_schedule_week, - Yield.Metadata.RewardSchedule.HOUR to R.string.staking_reward_schedule_hour, - Yield.Metadata.RewardSchedule.DAY to R.string.staking_reward_schedule_each_day, - Yield.Metadata.RewardSchedule.MONTH to R.string.staking_reward_schedule_month, - Yield.Metadata.RewardSchedule.ERA to R.string.staking_reward_schedule_era, - Yield.Metadata.RewardSchedule.EPOCH to R.string.staking_reward_schedule_epoch, - Yield.Metadata.RewardSchedule.UNKNOWN to null, - ) + private companion object { + val EQUALITY_THRESHOLD = BigDecimal(1E-10) - private val rewardClaimingResources = mapOf( + val rewardClaimingResources = mapOf( Yield.Metadata.RewardClaiming.MANUAL to R.string.staking_reward_claiming_manual, Yield.Metadata.RewardClaiming.AUTO to R.string.staking_reward_claiming_auto, Yield.Metadata.RewardSchedule.UNKNOWN to null, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/FeeCalculation.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/FeeCalculation.kt index 0f1857c60b..f3a7078d7d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/FeeCalculation.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/FeeCalculation.kt @@ -31,7 +31,12 @@ internal fun checkAndCalculateSubtractedAmount( reduceAmountBy = reduceAmountBy, ) return if (isFeeCoverage) { - balance.minus(reduceAmountBy).minus(feeValueRounded) + val reducedAmount = balance.minus(reduceAmountBy).minus(feeValueRounded) + if (isTron(cryptoCurrencyStatus.currency.network.id.value)) { + reducedAmount.setScale(0, RoundingMode.DOWN) + } else { + reducedAmount + } } else { amountValue } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt index cbcb806d97..fecd9f9cb6 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt @@ -52,6 +52,7 @@ internal fun StakingClaimRewardsValidatorContent( infoTitle = item.fiatAmount, infoSubtitle = item.cryptoAmount, imageUrl = item.validator?.image.orEmpty(), + onImageError = { ValidatorImagePlaceholder() }, modifier = modifier .roundedShapeItemDecoration(index, state.rewards.lastIndex, false) .background(TangemTheme.colors.background.action) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt index 6fa945af4f..679dd0675d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt @@ -57,7 +57,6 @@ import com.tangem.features.staking.impl.presentation.state.previewdata.InitialSt import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents import com.tangem.utils.StringsSigns.DOT -import com.tangem.utils.StringsSigns.PLUS import com.tangem.utils.extensions.orZero private const val BANNER_BLOCK_KEY = "BannerBlock" @@ -231,8 +230,6 @@ private fun StakingRewardBlock( val (text, textColor) = when (rewardBlockType) { RewardBlockType.Rewards -> { annotatedReference { - append(PLUS) - appendSpace() append(rewardFiat.orMaskWithStars(isBalanceHidden)) appendSpace() append(DOT) @@ -282,6 +279,7 @@ private fun ActiveStakingBlock( imageUrl = balance.getImage(), iconRes = icon, iconTint = iconTint, + onImageError = { ValidatorImagePlaceholder() }, modifier = modifier .background(TangemTheme.colors.background.action) .clickable( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt index 9f8db40d8e..c86ebb7e95 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt @@ -3,10 +3,7 @@ package com.tangem.features.staking.impl.presentation.ui import android.content.res.Configuration import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.Icon import androidx.compose.runtime.Composable @@ -95,6 +92,7 @@ internal fun StakingValidatorListContent( ) } }, + onImageError = { ValidatorImagePlaceholder() }, ) } } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/ValidatorImagePlaceholder.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/ValidatorImagePlaceholder.kt new file mode 100644 index 0000000000..d935c0e9ff --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/ValidatorImagePlaceholder.kt @@ -0,0 +1,25 @@ +package com.tangem.features.staking.impl.presentation.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.res.vectorResource +import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.staking.impl.R + +@Composable +internal fun ValidatorImagePlaceholder() { + Icon( + painter = rememberVectorPainter(ImageVector.vectorResource(R.drawable.ic_staking_filled_18)), + contentDescription = null, + tint = TangemTheme.colors.icon.inactive, + modifier = Modifier + .background(TangemTheme.colors.icon.primary1, CircleShape) + .padding(TangemTheme.dimens.size9), + ) +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt index be7909007e..e895963463 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt @@ -16,6 +16,7 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.features.staking.impl.R import com.tangem.features.staking.impl.presentation.state.ValidatorState +import com.tangem.features.staking.impl.presentation.ui.ValidatorImagePlaceholder import com.tangem.utils.extensions.orZero @Composable @@ -45,6 +46,7 @@ internal fun ValidatorBlock(validatorState: ValidatorState, onClick: () -> Unit) ) }, imageUrl = validatorState.chosenValidator.image.orEmpty(), + onImageError = { ValidatorImagePlaceholder() }, ) } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt index 7695aa744c..0625d38565 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt @@ -2,6 +2,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.staking.model.stakekit.YieldBalance import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance @@ -20,8 +21,9 @@ internal class TokenDetailsBalanceSelectStateConverter( if (stakingBlocksState !is StakingBlockUM.Staked) return this val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() ?: return this - val stakingCryptoAmount = stakingBlocksState.cryptoAmount - val stakingFiatAmount = stakingBlocksState.fiatAmount + val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data + val stakingCryptoAmount = yieldBalance?.getTotalWithRewardsStakingBalance() + val stakingFiatAmount = stakingCryptoAmount?.let { cryptoCurrencyStatus.value.fiatRate?.multiply(it) } copy( tokenBalanceBlockState = if (tokenBalanceBlockState is TokenDetailsBalanceBlockState.Content) { diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt index 2419e894d1..dafdd53e8c 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt @@ -21,7 +21,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryTransactionStateConverter import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance -import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getStringResourceId import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles import com.tangem.features.tokendetails.impl.R @@ -153,8 +152,9 @@ internal class TokenDetailsLoadedBalanceConverter( StakingBlockUM.Error(iconState = iconState) } else -> { - val stakingRewardAmount = yieldBalance?.getRewardStakingBalance() - val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) } + val fiatRate = status.value.fiatRate + val stakingRewardAmount = yieldBalance?.getRewardStakingBalance()?.let { fiatRate?.multiply(it) } + val stakingFiatAmount = stakingCryptoAmount?.let { fiatRate?.multiply(it) } getStakedState( status = status, @@ -203,7 +203,7 @@ internal class TokenDetailsLoadedBalanceConverter( formatArgs = wrappedList(apr), ), subtitleText = resourceReference( - id = stakingEntryInfo.rewardSchedule.getStringResourceId(), + id = R.string.staking_notification_earn_rewards_text, formatArgs = wrappedList(stakingEntryInfo.tokenSymbol), ), iconState = iconState, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenStakingStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenStakingStateConverter.kt index b12e12eb53..14bd84bf23 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenStakingStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenStakingStateConverter.kt @@ -8,7 +8,6 @@ import com.tangem.domain.staking.model.StakingEntryInfo import com.tangem.domain.staking.model.stakekit.StakingError import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockUM import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState -import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getStringResourceId import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.utils.Provider @@ -39,7 +38,7 @@ internal class TokenStakingStateConverter( formatArgs = wrappedList(apr), ), subtitleText = resourceReference( - id = stakingEntryInfo.rewardSchedule.getStringResourceId(), + id = R.string.staking_notification_earn_rewards_text, formatArgs = wrappedList(stakingEntryInfo.tokenSymbol), ), iconState = iconState, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/RewardScheduleUtils.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/RewardScheduleUtils.kt deleted file mode 100644 index 1219166e7b..0000000000 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/RewardScheduleUtils.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.tangem.feature.tokendetails.presentation.tokendetails.state.utils - -import com.tangem.domain.staking.model.stakekit.Yield -import com.tangem.features.tokendetails.impl.R - -internal fun Yield.Metadata.RewardSchedule.getStringResourceId(): Int { - return when (this) { - Yield.Metadata.RewardSchedule.BLOCK, - Yield.Metadata.RewardSchedule.DAY, - Yield.Metadata.RewardSchedule.ERA, - Yield.Metadata.RewardSchedule.EPOCH, - -> R.string.staking_notification_earn_rewards_text_daily - - Yield.Metadata.RewardSchedule.HOUR, - -> R.string.staking_notification_earn_rewards_text_hourly - - Yield.Metadata.RewardSchedule.WEEK, - -> R.string.staking_notification_earn_rewards_text_weekly - - Yield.Metadata.RewardSchedule.MONTH, - -> R.string.staking_notification_earn_rewards_text_monthly - - else - -> R.string.staking_notification_earn_rewards_text_daily - } -} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index fc8d3b6572..d8b674e7df 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -24,6 +24,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.geometry.* import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Path @@ -386,11 +387,13 @@ private inline fun BaseScaffoldWithMarkets( LocalMainBottomSheetColor provides remember { mutableStateOf(backgroundPrimary) }, ) { val backgroundColor = LocalMainBottomSheetColor.current + var isSearchFieldFocused by remember { mutableStateOf(false) } BottomSheetStateEffects( bottomSheetState = bottomSheetState, alertConfig = alertConfig, onBottomSheetStateChange = onBottomSheetStateChange, + isSearchFieldFocused = isSearchFieldFocused, ) TangemBottomSheetScaffold( @@ -407,7 +410,6 @@ private inline fun BaseScaffoldWithMarkets( sheetContainerColor = backgroundColor.value, scaffoldState = scaffoldState, sheetPeekHeight = peekHeight, - sheetTonalElevation = 8.dp, sheetShadowElevation = 8.dp, sheetShape = TangemTheme.shapes.bottomSheetLarge, sheetContent = { @@ -423,7 +425,14 @@ private inline fun BaseScaffoldWithMarkets( modifier = Modifier.sizeIn(maxHeight = maxHeight - statusBarHeight), ) { Hand(Modifier.drawBehind { drawRect(backgroundColor.value) }) - bottomSheetContent() + Box( + modifier = Modifier + .onFocusChanged { + isSearchFieldFocused = it.isFocused + }, + ) { + bottomSheetContent() + } } }, content = { paddingValues -> @@ -462,7 +471,10 @@ private inline fun BaseScaffoldWithMarkets( color = BottomSheetDefaults.ScrimColor, visible = bottomSheetState.targetValue == TangemSheetValue.Expanded || state.showMarketsOnboarding, - onDismissRequest = { coroutineScope.launch { bottomSheetState.partialExpand() } }, + onDismissRequest = { + coroutineScope.launch { bottomSheetState.partialExpand() } + state.onDismissMarketsOnboarding() + }, ) MarketsTooltip( @@ -486,7 +498,6 @@ private inline fun BaseScaffoldWithMarkets( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun MarketsTooltip( availableHeight: Dp, @@ -640,11 +651,27 @@ private fun BottomSheetStateEffects( bottomSheetState: TangemSheetState, alertConfig: WalletAlertState?, onBottomSheetStateChange: (BottomSheetState) -> Unit, + isSearchFieldFocused: Boolean, ) { val systemUiController = rememberSystemUiController() val navigationBarColor = TangemTheme.colors.background.primary - LaunchedEffect(key1 = bottomSheetState.targetValue, navigationBarColor) { + LaunchedEffect(navigationBarColor) { + delay(timeMillis = 100) + when (bottomSheetState.currentValue) { + TangemSheetValue.Hidden, + TangemSheetValue.Expanded, + -> systemUiController.setNavigationBarColor( + color = Color.Transparent, + darkIcons = navigationBarColor.luminance() > 0.5f, + navigationBarContrastEnforced = true, + ) + TangemSheetValue.PartiallyExpanded, + -> systemUiController.setNavigationBarColor(navigationBarColor) + } + } + + LaunchedEffect(bottomSheetState.targetValue, navigationBarColor) { when (bottomSheetState.targetValue) { TangemSheetValue.Hidden, TangemSheetValue.Expanded, @@ -673,7 +700,7 @@ private fun BottomSheetStateEffects( val isKeyboardVisible by rememberIsKeyboardVisible() LaunchedEffect(isKeyboardVisible) { - if (isKeyboardVisible && alertConfig == null) { + if (isKeyboardVisible && alertConfig == null && isSearchFieldFocused) { bottomSheetState.expand() } } diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index c009175e70..f7f29c6698 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -89,7 +89,7 @@ markdownComposeView = "0.5.4" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-775" +tangemBlockchainSdk = "develop-782" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-381" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^