From 63b07cccc3d51464d5770ea01b7662c4b8dad549 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 22 Jan 2026 16:14:14 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/tap/routing/utils/ChildFactory.kt | 1 + .../com/tangem/common/routing/AppRoute.kt | 3 +- .../configs/feature_toggles_config.json | 4 + core/res/src/main/res/values-de/strings.xml | 2 +- core/res/src/main/res/values-ja/strings.xml | 34 ++- core/res/src/main/res/values-ru/strings.xml | 34 ++- core/res/src/main/res/values/strings.xml | 29 ++- .../core/ui/components/block/BlockItem.kt | 22 +- .../core/ui/components/block/model/BlockUM.kt | 2 +- .../main/res/drawable/ic_backup_repeat_24.xml | 9 + .../main/res/drawable/ic_double_star_24.xml | 7 + .../res/drawable/ic_mobile_security_2_24.xml | 5 + .../main/res/drawable/ic_seed_phrase_24.xml | 15 ++ .../main/res/drawable/ic_smartphone_24.xml | 9 + .../main/res/drawable/ic_tangem_card_24.xml | 5 + .../CreateWalletStartModel.kt | 2 +- .../entity/CreateWalletStartUM.kt | 2 +- .../ui/CreateWalletStartContent.kt | 34 +-- .../preview/PreviewDetailsComponent.kt | 6 + .../preview/PreviewUserWalletListComponent.kt | 1 + .../features/details/entity/DetailsItemUM.kt | 6 + .../details/entity/UserWalletListUM.kt | 2 + .../features/details/model/DetailsModel.kt | 1 + .../details/model/UserWalletListModel.kt | 19 +- .../features/details/ui/DetailsScreen.kt | 29 ++- .../details/ui/UserWalletListBlock.kt | 40 ++-- .../features/details/utils/ItemsBuilder.kt | 15 +- features/hot-wallet/api/build.gradle.kts | 1 + .../hotwallet/HotWalletFeatureToggles.kt | 1 + .../hotwallet/WalletBackupComponent.kt | 1 + .../DefaultHotWalletFeatureToggles.kt | 3 + .../hotwallet/common/ui/OptionBlock.kt | 6 +- .../ui/CreateHardwareWalletContent.kt | 18 +- .../ui/CreateMobileWalletContent.kt | 11 +- .../upgradewallet/ui/UpgradeWalletContent.kt | 6 +- .../viewphrase/model/ViewPhraseModel.kt | 27 +-- .../walletbackup/entity/WalletBackupUM.kt | 1 - .../walletbackup/model/WalletBackupModel.kt | 22 +- .../walletbackup/ui/WalletBackupContent.kt | 195 ++++-------------- .../entity/WalletHardwareBackupUM.kt | 1 - .../model/WalletHardwareBackupModel.kt | 14 -- .../ui/WalletHardwareBackupContent.kt | 151 ++++++++++---- .../preview/PreviewWalletSettingsComponent.kt | 1 - .../entity/WalletSettingsItemUM.kt | 8 +- .../model/WalletSettingsModel.kt | 44 ++-- .../walletsettings/ui/WalletSettingsScreen.kt | 109 +++++----- .../walletsettings/utils/ItemsBuilder.kt | 22 -- .../utils/WalletCardItemDelegate.kt | 17 +- .../intents/WalletWarningsClickIntents.kt | 11 +- .../utils/WalletWarningsSingleEventSender.kt | 9 +- features/welcome/impl/build.gradle.kts | 1 + .../welcome/impl/model/WelcomeModel.kt | 58 +++++- gradle/tangem_dependencies.toml | 2 +- 53 files changed, 614 insertions(+), 464 deletions(-) create mode 100644 core/ui/src/main/res/drawable/ic_backup_repeat_24.xml create mode 100644 core/ui/src/main/res/drawable/ic_double_star_24.xml create mode 100644 core/ui/src/main/res/drawable/ic_mobile_security_2_24.xml create mode 100644 core/ui/src/main/res/drawable/ic_seed_phrase_24.xml create mode 100644 core/ui/src/main/res/drawable/ic_smartphone_24.xml create mode 100644 core/ui/src/main/res/drawable/ic_tangem_card_24.xml diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 19f07cabf5..d7f3a0cc33 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -190,6 +190,7 @@ internal class ChildFactory @Inject constructor( context = context, params = WalletBackupComponent.Params( userWalletId = route.userWalletId, + isColdWalletOptionShown = route.isColdWalletOptionShown, ), componentFactory = walletBackupComponentFactory, ) diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index e5bdf4dad1..7242c08646 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -231,7 +231,8 @@ sealed class AppRoute(val path: String) : Route { @Serializable data class WalletBackup( val userWalletId: UserWalletId, - ) : AppRoute(path = "/wallet_backup/${userWalletId.stringValue}") + val isColdWalletOptionShown: Boolean, + ) : AppRoute(path = "/wallet_backup/${userWalletId.stringValue}/$isColdWalletOptionShown") @Serializable data class WalletHardwareBackup( diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index 1cb7bb7d24..94775b09a4 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -35,6 +35,10 @@ "name": "HOT_WALLET_ENABLED", "version": "5.32.0" }, + { + "name": "HOT_WALLET_CREATION_RESTRICTION_ENABLED", + "version": "5.32.0" + }, { "name": "TANGEM_PAY_ENABLED", "version": "5.31.0" diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index db29c44fbe..0a5f0530a8 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -1767,7 +1767,7 @@ Importiere eine bestehende Wallet mit Deiner Wiederherstellungsphrase. Wallet importieren Wiederherstellungsphrase eingeben - Du hast Deine Wallet erfolgreich gesichert. + Du hast Deine Wallet erfolgreich importiert. Wallet importieren Import abgeschlossen Wallet importieren diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 785a92204c..565f5cf8f8 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -322,6 +322,7 @@ わかりました ブラウザで開く + または プライマリーカード プライマリーリング パスフレーズ @@ -430,6 +431,7 @@ このメカニズムは、カードまたはリングに対する近接攻撃から保護します。コマンドの受信と実行の間に遅延を強制します。 パスコード カードの状態の変更を伴うコマンドを実行する前に、パスコードを入力する必要があります。 + ハードウェアウォレットにアップグレード NFT 紹介プログラム デバイスの画面を下に向けると、残高をすばやく非表示にしたり表示したりできます。 @@ -443,6 +445,7 @@ 署名済み フィードバックを送信 詳細 + モバイルウォレットは同時に1つのみ利用できます。Tangemコールドウォレットにアップグレードすることも、新しいコールドウォレットと併用することも可能です。 インターネット接続を確認するか、別のネットワークに切り替えてください。 利用規約 デフォルトアドレス @@ -552,7 +555,8 @@ Tangemへのフィードバック 取引を送信できません コインの説明エラー - ガス代不要の取引手数料 + 残高不足 + 取引手数料 エラーが発生しました エラーが発生しました。コード: %s 。 メモが必要 @@ -564,10 +568,10 @@ 続行するには、%1sスマートコントラクトに%2sを使用する権限を付与してください 許可を与える 無制限 - バックアップは2〜3枚のTangemカードを使用して作成されます。紛失や破損に備え、カードはそれぞれ安全な別の場所に保管してください。シードフレーズは不要です。 - 複数のカードでバックアップ + ハードウェアウォレット内に新しいアドレスが自動生成され、安全にすぐ利用できる状態になります。 + 新しいアドレス Tangemウォレットを追加 - あなたの秘密鍵はTangemカード内部で直接生成され、決してカードの外に出ることはありません。 + 秘密鍵はTangemカード内部で直接生成され、外部に出ることは一切ありません。 鍵生成 すべての暗号処理は、複製や物理的な改ざんに対する認証を受けたセキュアチップ内で行われます。 ハードウェアレベルのセキュリティ @@ -602,15 +606,20 @@ まずバックアップを完了する 未完了 その他の方法 + リカバリーフレーズは安全な場所に保管し、他人に知られないようにしてください。あわせて、資産をさらに強力に保護するためにアクセスコードを設定してください。 資金を保護するため、リカバリーフレーズは安全な場所に保管し、他人に知られないようにしてください。 リカバリーフレーズ アクセスコードでウォレットを保護するには、バックアップの手続きを完了してください。 ハードウェアウォレットにアップグレードするには、バックアップの手続きを完了してください。 + 業界最高レベルのセキュリティを実現するため、モバイルウォレットをTangemハードウェアウォレットにアップグレードしましょう。既存のウォレットをインポートするか、新しいウォレットへ資産を移行できます。 + コールドウォレットにアップグレード 秘密鍵は安全に暗号化され、スマートフォン上に保存されています 秘密鍵はデバイス上に保持されます リカバリーフレーズを使ってウォレットを作成または復元してください。 シードフレーズのバックアップ モバイルウォレットを作成する + モバイルウォレットは、いつでも安全にTangemカードまたはリングへ移行できます。 + ハードウェアウォレットにアップグレード 既存のウォレットをインポートする このリカバリーフレーズはすでにインポートされています。 モバイルウォレット @@ -628,14 +637,14 @@ ウォレットを削除する前にバックアップを行っていない場合、ウォレットへのアクセスを失うことを理解しています。 ウォレットを削除しても中身自体が消えるわけではなく、このデバイスから表示が消えるだけであることを理解しています。 アップグレード - シードフレーズは不要です。Tangemカードまたはリングが安全なバックアップとなります。 - Tangemでバックアップ + モバイルウォレットをTangemカードまたはリングにアップグレードしても、すべてのアドレスと残高は引き続き完全に利用できます。 + 同じアドレス アップグレードできません。このデバイスにはすでにウォレットが存在します。 別のデバイスを選択してください。このデバイスはアップグレードに使用できません。 操作中にエラーが発生しました。 処理中も、資金は安全に保たれ、常にアクセス可能です。 資金へのアクセス - ウォレット情報はアプリから削除され、ハードウェアウォレットに保存されます + アップグレード後、モバイルウォレットはアプリから削除され、ハードウェアウォレットに保存されます。リカバリーフレーズは引き続きご自身で管理してください。 セキュリティ全般 秘密鍵はアプリからTangemハードウェアウォレットへ移行されます キーの移行 @@ -1225,6 +1234,11 @@ 設定したいカードまたはリングをスキャンするために準備してください。 ウォレット削除 これにより、ウォレットがアプリから削除されます。ウォレットは再度追加できます。 + シンプルな操作 + 暗号資産をオフラインで厳重保管。カードサイズで、金庫以上の安心を。 + シードフレーズ不要 + 業界最高水準のハードウェアウォレット + Tangemコールドウォレット 名前 トークンを活用しよう ネットワーク手数料とは、ブロックチェーン上で取引を処理し、承認するために支払う少額の料金です。 @@ -1391,6 +1405,7 @@ 手間がかからず直感的に操作でき、数回タップするだけでトークンを交換できます。 とにかく便利 プロバイダー経由のスワップ + 資産 この金額には以下が含まれます:\n- サービスプロバイダーの手数料\n- 取引所からユーザーのアドレスに%s を送り返すためのネットワーク手数料。 金額には以下が含まれます: \n • サービス プロバイダーの手数料\n • 取引所からユーザーのアドレスに%1$sを送金するためのネットワーク手数料。 \n\nプロバイダーのスリッページは最大%2$sです この金額には、サービスプロバイダーの手数料が含まれています。 @@ -1405,6 +1420,7 @@ 残高不足 許可を与える スワップ + スワップ中… 受け取る トークンを選択 利用不可 @@ -1531,6 +1547,8 @@ Tangem Payは現在一時的に利用できません。 Tangem Pay 下のボタンをクリックしてアクセスを復元してください + 現在引き出せるのは、保留中の取引分を差し引いたオンチェーンアドレス上のUSDC(Polygon)のみです。以前に返金や購入のキャンセルを行った場合、暗号資産アカウントの残高は2営業日以内に更新されます。 + ご注意ください PINコード これは私のウォレットです 残高非表示 @@ -1602,6 +1620,7 @@ エラーが発生しました。エラー コード:%s。サポートにお問い合わせください。 %sを使用するか、カード / リングをスキャンしてウォレットにアクセスしてください 接続に失敗しました:このdAppは、サポートされていないWallet Connectバージョン1.0を使用しています。正常に接続するには、dAppがWallet Connectバージョン2.0をサポートしていることを確認してください。 + ハードウェアウォレットにアップグレード 最新の機能とニュースをお届けします 取引・スワップ・重要な更新に関するリアルタイム通知。 取引アラート @@ -1925,6 +1944,7 @@ 迅速な配送 ワンタップで開始 シームレスで安全 + シードフレーズ不要 シンプルな操作 Tangemでハードウェアウォレットを作成しよう。キャッシュカードのようにスリムで、金庫のように安全。 ソフトウェアウォレットを作成またはインポート diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 20c4204701..ef16028c2d 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -325,7 +325,7 @@ %d сеть %d сети %d сетей - %d сети + %d сетях Новый адрес Новости @@ -334,10 +334,12 @@ Нет Нет адреса Не добавлено + Не доступно Не сейчас Сейчас OK Открыть в браузере + или Основная карта Основное кольцо Парольная фраза @@ -450,6 +452,7 @@ Этот механизм защищает карту или кольцо от бесконтактных атак. Между сканированием и выполнением команды будет добавлена задержка. Пароль Перед выполнением любой команды, влекущей за собой изменение состояния карты, вам необходимо будет ввести пароль. + Апгрейд до аппаратного кошелька NFT Реферальная программа Переверните экран вашего устройства вниз, чтобы быстро скрыть и отобразить балансы @@ -463,6 +466,7 @@ Подписано Отправить отзыв Подробности + Одновременно у вас может быть только один мобильный кошелек. Его можно апгрейдить до Tangem cold wallet или использовать вместе с новым холодным кошельком. Проверьте подключение с интернетом или переключитесь на другую сеть Условия использования Основной адрес @@ -569,6 +573,8 @@ Обращение в поддержку Tangem Не могу отправить транзакцию Ошибка в описании монеты + Недостаточно средств + Комиссия за транзакцию Произошла ошибка Произошла ошибка. Код: %s. Требуется memo @@ -580,10 +586,10 @@ Чтобы продолжить, вам нужно разрешить смарт-контракту %1s использовать ваш %2s Дать разрешение Безлимитно - Резервная копия создаётся на 2–3 картах Tangem. Храните их отдельно для безопасности — seed-фраза не нужна. - Бэкап на несколько карт + Новые адреса будут сгенерированы прямо в вашем аппаратном кошельке, готовы к использованию и полностью защищены. + Новые адреса Добавить кошелек Tangem - Ваш приватный ключ генерируется на карте Tangem и никогда не покидает её. + Ваш приватный ключ будет сгенерирован на карте Tangem и никогда не покинет её. Генерация ключа Операции с криптографией выполняются внутри защищённого чипа, устойчивого к клонированию и физическому взлому. Аппаратная безопасность @@ -618,15 +624,20 @@ Сначала завершите создание резервной копии Не завершено Другие способы + Сохраните фразу восстановления в надежном месте и держите её в секрете, чтобы защитить свои средства, а также установите код доступа для дополнительной безопасности. Сохраните фразу восстановления в безопасном месте и держите её в секрете. Фраза восстановления Чтобы защитить ваш кошелёк с помощью кода доступа, сначала завершите резервное копирование. Чтобы улучшить кошелёк до аппаратного, сначала создайте резервную копию. + Перенесите свой мобильный кошелек на аппаратный кошелек Tangem для максимальной безопасности. Импортируйте существующий кошелек или переведите средства на новый. + Апгрейд до холодного кошелька Ваши приватные ключи надёжно зашифрованы и хранятся на вашем телефоне Ключи хранятся в приложении Создайте или импортируйте кошелёк с помощью вашей фразы восстановления. Резервная копия Создать мобильный кошелек + Перенесите свой мобильный кошелек на Tangem-карту или кольцо в любое время. + Апгрейд до аппаратного кошелька Импортировать существующий Эта фраза восстановления уже была импортирована Мобильный кошелек @@ -644,14 +655,14 @@ Я понимаю, что если я не создал резервную копию кошелька перед его удалением, я могу потерять к нему доступ. Я понимаю, что удаление моего кошелька не стирает его — оно просто удаляет его с моего устройства. Апгрейд - Фраза восстановления больше не нужна — ваша карта или кольцо Tangem становятся вашей надёжной резервной копией. - Резервное копирование + Все ваши адреса и балансы остаются полностью доступными при апгрейде мобильного кошелька на Tangem-карту или кольцо. + Те же адреса Это устройство не может быть использовано для апгрейда, оно уже содержит другой кошелек. Выберите другое устройство. Это нельзя использовать для обновления. Во время операции произошла ошибка. Ваши средства остаются в безопасности и полностью доступны в процессе. Доступ к средствам - Данные вашего кошелька будут удалены из приложения и сохранены на вашем устройстве Tangem. + После апгрейда ваш мобильный кошелек будет удалён из приложения и сохранён на аппаратном кошельке; фраза восстановления остаётся у вас. Общая безопасность Приватные ключи будут перемещены из приложения в вашу Tangem карту или кольцо Миграция ключей @@ -1277,6 +1288,11 @@ Подготовьтесь к сканированию кольца или карты, которую вы хотите настроить. Забыть кошелек Это приведет к удалению кошелька из приложения. Сам кошелек можно добавить снова. + Прост в использовании + Хранит вашу криптовалюту в безопасности и офлайн. Тонкий, как кредитная карта, надежнее банковского сейфа. + Без seed-фразы + Лучший в своём классе аппаратный кошелек + Холодный кошелек Tangem Имя Заставьте ваш токен работать Сетевая комиссия — это небольшая плата за обработку и подтверждение вашей транзакции в блокчейне. @@ -1442,6 +1458,7 @@ Интуитивный обмен в пару касаний — без сложностей и ожидания Проще простого Обмен через провайдера + Ваши средства В сумму включено: \n• комиссия провайдера сервиса\n• комиссия сети за отправку %s от биржи обратно на адрес пользователя. В сумму включено: \n• комиссия провайдера сервиса\n• комиссия сети за отправку %1$s от биржи обратно на адрес пользователя \n\nПроскальзывание провайдера составляет до %2$s В сумму включена комиссия провайдера сервиса. @@ -1456,6 +1473,7 @@ Недостаточно средств Дать разрешение Обменять + Обмен… Вы получите Выберите токен не доступен @@ -1646,6 +1664,7 @@ Произошла ошибка. Код ошибки: %s. Попробуйте, пожалуйста, снова. Если проблема будет продолжать возникать — обратитесь в службу поддержки. Используйте %s или отсканируйте карту/кольцо, чтобы получить доступ к своему кошельку Соединение не удалось: это dApp использует Wallet Connect версии 1.0, которая не поддерживается. Убедитесь, что dApp поддерживает Wallet Connect версии 2.0 для успешного подключения. + Апгрейд до аппаратного кошелька Будьте в курсе новых функций и новостей Мгновенные уведомления о транзакциях, обменах и важных обновлениях. Уведомления о транзакциях @@ -1957,6 +1976,7 @@ Быстрая доставка Начните в один клик Просто и надёжно + Без seed-фразы Интуитивно понятный Создайте аппаратный кошелёк с Tangem. Тонкий, как банковская карта, безопасный, как банковский сейф. Создать или импортировать мобильный кошелёк diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 59177b2da4..f7732464c2 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -328,6 +328,7 @@ Now OK Open in Browser + or Primary card Primary ring Passphrase @@ -438,7 +439,6 @@ This mechanism protects against proximity attacks on a card or ring. It will enforce a delay between reception and execution of a command. Passcode Before executing any command entailing a change of the card state, you will have to enter the passcode. - You can have either one mobile wallet or hardware wallet at the same time. Upgrade you wallet or delete it from the app to start using a Tangem cold wallet. Upgrade to hardware wallet NFT Referral program @@ -453,6 +453,7 @@ Signed Send feedback Details + You can have only one mobile wallet at a time. It can be upgraded to a Tangem cold wallet or used alongside a new cold wallet. Check your internet connection or switch to a different network Terms of service Default Address @@ -563,7 +564,7 @@ Can\'t send a transaction Coin description error Not enough funds - Gasless transaction fee + Transaction fee An error occurred An error occurred. Code: %s. Requires memo @@ -575,10 +576,10 @@ To continue, grant %1s smart contracts permission to use your %2s Give Permission Unlimited - A backup is created using 2–3 Tangem cards. Store them separately in secure locations to protect against loss or damage. No seed phrase needed. - Backup With Multiple Cards + New addresses will be generated for you inside your hardware wallet, ready for use and fully secure. + New Addresses Add Tangem Wallet - Your private key is generated directly inside the Tangem card and never leaves it. + Your private key will be generated directly inside the Tangem card and will never leave it. Key Generation All cryptographic operations happen inside the secure chip, certified against cloning and physical tampering. Hardware-Level Security @@ -613,15 +614,20 @@ Finalize backup first Incomplete Other methods + Save your recovery phrase in a secure place and keep it private to protect your funds, and set up an access code for additional security. Save your recovery phrase in a secure place and keep it private to protect your funds. Recovery phrase To secure your wallet with an access code, complete the backup process. To upgrade to a hardware wallet, complete the backup process. + Upgrade your mobile wallet to a Tangem hardware wallet for the highest security. Import your wallet or transfer funds to a new one. + Upgrade to cold wallet Your private keys are securely encrypted and stored on your phone Private keys stay on your device Create or restore your wallet with a recovery phrase. Seed phrase backup Create Mobile Wallet + Transfer your mobile wallet to a Tangem card or ring anytime, securely. + Upgrade to hardware wallet Import existing wallet This recovery phrase has already been imported Mobile Wallet @@ -639,14 +645,14 @@ I understand that if I haven\'t backed up my wallet before removing it, I will lose access to it. I understand that removing my wallet does not delete it, only removes it from my device. Upgrade - Seed phrase not required. Your Tangem card or ring becomes your secure backup. - Backup With Tangem + All your addresses and balances stay fully accessible when upgrading your mobile wallet to a Tangem card or ring. + Same Addresses Can\'t upgrade. A wallet already exists on this device. Pick another device. This one can\'t be used for the upgrade. An error occurred during the operation. Your funds remain safe and fully accessible during the process Access to funds - Your wallet information will be erased from the app and stored on your hardware wallet + After upgrading, your mobile wallet will be removed from the app and stored on your hardware wallet; your recovery phrase stays with you. General security Private keys will be moved from the app to your Tangem hardware wallet Key migration @@ -1420,6 +1426,7 @@ Hassle-free and intuitive, allowing you to swap tokens in just a few taps Simply Convenient Swap via provider + Your assets The amount includes:\n• service provider\'s fee\n• network fee for sending %s from the exchange back to the user\'s address. The amount includes:\n• service provider\'s fee\n• network fee for sending %1$s from the exchange back to the user\'s address. \n\nProvider slippage is up to %2$s The amount includes the service provider\'s fee. @@ -1434,6 +1441,7 @@ Insufficient funds Give Permission Swap + Swapping... You receive Choose token not available @@ -1560,6 +1568,8 @@ Tangem Pay is temporarily unreachable Tangem Pay Click the button below to restore access + You can only withdraw USDC (Polygon) currently available on your on‑chain address balance, taking into account pending transactions. If you previously made a refund or cancelled a purchase, your crypto account balance will update within 2 business days. + Please note Your PIN code This is my wallet Balances hidden @@ -1631,7 +1641,7 @@ We\'ve encountered an error. Error code: %s. Please contact our support. Use %s or scan a card/ring to have access to your wallet Connection failed: This dApp uses Wallet Connect version 1.0, which is not supported. Please ensure the dApp supports Wallet Connect version 2.0 to connect successfully. - Upgrade to a hardware wallet + Upgrade to hardware wallet Stay up to date with the latest features and news Real-time alerts for transactions, exchanges, and critical updates. Transaction Alerts @@ -2002,6 +2012,7 @@ Fast delivery Start in one tap Seamless and secure + No seed phrase Simple to use Create a hardware wallet with Tangem. Slim as a bank card, secure as a bank vault. Create or import a software wallet diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/block/BlockItem.kt b/core/ui/src/main/java/com/tangem/core/ui/components/block/BlockItem.kt index 66cf54df35..be7f8f5b2c 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/block/BlockItem.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/block/BlockItem.kt @@ -27,16 +27,18 @@ fun BlockItem(model: BlockUM, modifier: Modifier = Modifier) { verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12, Alignment.Start), ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - painter = painterResource(id = model.iconRes), - tint = when (model.accentType) { - BlockUM.AccentType.NONE -> TangemTheme.colors.icon.secondary - BlockUM.AccentType.ACCENT -> TangemTheme.colors.text.accent - BlockUM.AccentType.WARNING -> TangemTheme.colors.text.warning - }, - contentDescription = null, - ) + if (model.iconRes != null) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = model.iconRes), + tint = when (model.accentType) { + BlockUM.AccentType.NONE -> TangemTheme.colors.icon.secondary + BlockUM.AccentType.ACCENT -> TangemTheme.colors.text.accent + BlockUM.AccentType.WARNING -> TangemTheme.colors.text.warning + }, + contentDescription = null, + ) + } Text( modifier = Modifier.weight(1f), diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/block/model/BlockUM.kt b/core/ui/src/main/java/com/tangem/core/ui/components/block/model/BlockUM.kt index 4988f72eff..f0079ad959 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/block/model/BlockUM.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/block/model/BlockUM.kt @@ -7,7 +7,7 @@ import javax.annotation.concurrent.Immutable data class BlockUM( val text: TextReference, - @DrawableRes val iconRes: Int, + @DrawableRes val iconRes: Int?, val onClick: () -> Unit, val accentType: AccentType = AccentType.NONE, val endContent: EndContent = EndContent.None, diff --git a/core/ui/src/main/res/drawable/ic_backup_repeat_24.xml b/core/ui/src/main/res/drawable/ic_backup_repeat_24.xml new file mode 100644 index 0000000000..3579504b2c --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_backup_repeat_24.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/core/ui/src/main/res/drawable/ic_double_star_24.xml b/core/ui/src/main/res/drawable/ic_double_star_24.xml new file mode 100644 index 0000000000..78ca302987 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_double_star_24.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/core/ui/src/main/res/drawable/ic_mobile_security_2_24.xml b/core/ui/src/main/res/drawable/ic_mobile_security_2_24.xml new file mode 100644 index 0000000000..20f8ba11fa --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_mobile_security_2_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/ui/src/main/res/drawable/ic_seed_phrase_24.xml b/core/ui/src/main/res/drawable/ic_seed_phrase_24.xml new file mode 100644 index 0000000000..7ec0b491f4 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_seed_phrase_24.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/core/ui/src/main/res/drawable/ic_smartphone_24.xml b/core/ui/src/main/res/drawable/ic_smartphone_24.xml new file mode 100644 index 0000000000..eb4558d24b --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_smartphone_24.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/core/ui/src/main/res/drawable/ic_tangem_card_24.xml b/core/ui/src/main/res/drawable/ic_tangem_card_24.xml new file mode 100644 index 0000000000..2f4eabe10a --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_tangem_card_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt index 8c7bb0d2eb..2183fc05a0 100644 --- a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt +++ b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt @@ -92,7 +92,7 @@ internal class CreateWalletStartModel @Inject constructor( onPrimaryButtonClick = ::onBuyClick, primaryButtonText = resourceReference(R.string.details_buy_wallet), otherMethodTitle = resourceReference(R.string.welcome_create_wallet_mobile_title), - otherMethodDescription = resourceReference(R.string.welcome_create_wallet_mobile_description), + otherMethodDescription = null, otherMethodClick = ::onStartWithMobileWalletClick, onBackClick = { router.pop() }, onScanClick = ::onScanClick, diff --git a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/entity/CreateWalletStartUM.kt b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/entity/CreateWalletStartUM.kt index b45777a20a..bce2d230b2 100644 --- a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/entity/CreateWalletStartUM.kt +++ b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/entity/CreateWalletStartUM.kt @@ -12,7 +12,7 @@ internal data class CreateWalletStartUM( val shouldShowScanSecondaryButton: Boolean, val primaryButtonText: TextReference, val onPrimaryButtonClick: () -> Unit, - val otherMethodDescription: TextReference, + val otherMethodDescription: TextReference?, val otherMethodTitle: TextReference, val otherMethodClick: () -> Unit, val onScanClick: () -> Unit, diff --git a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/ui/CreateWalletStartContent.kt b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/ui/CreateWalletStartContent.kt index ecf741b0f0..e113e454a5 100644 --- a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/ui/CreateWalletStartContent.kt +++ b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/ui/CreateWalletStartContent.kt @@ -181,7 +181,7 @@ internal fun CreateWalletStartContent(state: CreateWalletStartUM, modifier: Modi .height(16.dp), ) Text( - text = stringResourceSafe(R.string.welcome_create_wallet_other_method), + text = stringResourceSafe(R.string.common_or), style = TangemTheme.typography.caption1, color = TangemTheme.colors.text.secondary, textAlign = TextAlign.Center, @@ -193,19 +193,21 @@ internal fun CreateWalletStartContent(state: CreateWalletStartUM, modifier: Modi .scale(scaleX = -1f, scaleY = 1f), ) } - Text( - modifier = Modifier - .fillMaxWidth() - .padding( - start = 16.dp, - top = 16.dp, - end = 16.dp, - ), - text = state.otherMethodDescription.resolveReference(), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.tertiary, - textAlign = TextAlign.Center, - ) + if (state.otherMethodDescription != null) { + Text( + modifier = Modifier + .fillMaxWidth() + .padding( + start = 16.dp, + top = 16.dp, + end = 16.dp, + ), + text = state.otherMethodDescription.resolveReference(), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.tertiary, + textAlign = TextAlign.Center, + ) + } Row( modifier = Modifier .wrapContentWidth() @@ -429,9 +431,7 @@ private class CreateWalletStartStateProvider : CollectionPreviewParameterProvide onPrimaryButtonClick = { }, primaryButtonText = resourceReference(R.string.details_buy_wallet), otherMethodTitle = resourceReference(R.string.welcome_create_wallet_mobile_title), - otherMethodDescription = resourceReference( - R.string.welcome_create_wallet_mobile_description, - ), + otherMethodDescription = null, otherMethodClick = { }, onBackClick = { }, onScanClick = { }, diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt index 0a9a273352..45c7cd73ca 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt @@ -12,6 +12,7 @@ import com.tangem.features.details.entity.DetailsUM import com.tangem.features.details.ui.DetailsScreen import com.tangem.features.details.utils.ItemsBuilder import com.tangem.features.details.utils.SocialsBuilder +import com.tangem.features.hotwallet.HotWalletFeatureToggles import kotlinx.coroutines.runBlocking internal class PreviewDetailsComponent : DetailsComponent { @@ -19,9 +20,14 @@ internal class PreviewDetailsComponent : DetailsComponent { private val previewBlocks = runBlocking { ItemsBuilder( router = DummyRouter(), + hotWalletFeatureToggles = object : HotWalletFeatureToggles { + override val isHotWalletEnabled: Boolean = true + override val isWalletCreationRestrictionEnabled: Boolean = true + }, ).buildAll( isWalletConnectAvailable = true, isSupportChatAvailable = true, + hasAnyMobileWallet = true, userWalletId = UserWalletId(""), onSupportEmailClick = {}, onSupportChatClick = {}, diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt index 86ecb2a42f..e56710ead0 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewUserWalletListComponent.kt @@ -50,6 +50,7 @@ internal class PreviewUserWalletListComponent : UserWalletListComponent { ), addNewWalletText = resourceReference(R.string.user_wallet_list_add_button), isWalletSavingInProgress = true, + addNewWalletIconRes = R.drawable.ic_plus_24, onAddNewWalletClick = {}, ), ) diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/DetailsItemUM.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/DetailsItemUM.kt index 99c416a63a..5e7ebe0773 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/DetailsItemUM.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/DetailsItemUM.kt @@ -2,6 +2,7 @@ package com.tangem.features.details.entity import androidx.compose.runtime.Immutable import com.tangem.core.ui.components.block.model.BlockUM +import com.tangem.core.ui.extensions.TextReference import kotlinx.collections.immutable.ImmutableList @Immutable @@ -27,4 +28,9 @@ internal sealed class DetailsItemUM { data object UserWalletList : DetailsItemUM() { override val id: String = "user_wallet_list" } + + data class UnderSectionText( + override val id: String, + val text: TextReference, + ) : DetailsItemUM() } \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/UserWalletListUM.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/UserWalletListUM.kt index a8ef5eb141..bc4baf7d42 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/UserWalletListUM.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/entity/UserWalletListUM.kt @@ -1,5 +1,6 @@ package com.tangem.features.details.entity +import androidx.annotation.DrawableRes import androidx.compose.runtime.Immutable import com.tangem.common.ui.userwallet.state.UserWalletItemUM import com.tangem.core.ui.extensions.TextReference @@ -10,5 +11,6 @@ internal data class UserWalletListUM( val userWallets: ImmutableList, val isWalletSavingInProgress: Boolean, val addNewWalletText: TextReference, + @DrawableRes val addNewWalletIconRes: Int?, val onAddNewWalletClick: () -> Unit, ) \ No newline at end of file diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index 1c4c53f372..9d316e6c90 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -97,6 +97,7 @@ internal class DetailsModel @Inject constructor( itemsBuilder.buildAll( isWalletConnectAvailable = isWalletConnectAvailable, isSupportChatAvailable = feedbackFeatureToggles.isUsedeskEnabled, + hasAnyMobileWallet = getWalletsUseCase.invokeSync().any { it is UserWallet.Hot }, userWalletId = params.userWalletId, onSupportEmailClick = ::sendFeedback, onSupportChatClick = ::openUseDesk, diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt index badebd605e..0a0dd71c89 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/UserWalletListModel.kt @@ -60,6 +60,7 @@ internal class UserWalletListModel @Inject constructor( isWalletSavingInProgress = false, addNewWalletText = TextReference.EMPTY, onAddNewWalletClick = ::onAddNewWalletClick, + addNewWalletIconRes = R.drawable.ic_plus_24, ), ) @@ -81,10 +82,11 @@ internal class UserWalletListModel @Inject constructor( value.copy( userWallets = userWallets, isWalletSavingInProgress = isWalletSavingInProgress, - addNewWalletText = if (shouldSaveUserWallets || hotWalletFeatureToggles.isHotWalletEnabled) { - resourceReference(R.string.user_wallet_list_add_button) - } else { - resourceReference(R.string.scan_card_settings_button) + addNewWalletText = when { + shouldSaveUserWallets || hotWalletFeatureToggles.isHotWalletEnabled -> { + resourceReference(R.string.user_wallet_list_add_button) + } + else -> resourceReference(R.string.scan_card_settings_button) }, ) } @@ -92,7 +94,14 @@ internal class UserWalletListModel @Inject constructor( private fun onAddNewWalletClick() { if (hotWalletFeatureToggles.isHotWalletEnabled) { analyticsEventHandler.send(SignIn.ButtonAddWallet(AnalyticsParam.ScreensSources.Settings)) - router.push(AppRoute.CreateWalletSelection) + + if (hotWalletFeatureToggles.isWalletCreationRestrictionEnabled) { + withProgress(isWalletSavingInProgress) { + userWalletSaver.scanAndSaveUserWallet(modelScope) + } + } else { + router.push(AppRoute.CreateWalletSelection) + } } else { withProgress(isWalletSavingInProgress) { userWalletSaver.scanAndSaveUserWallet(modelScope) diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/DetailsScreen.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/DetailsScreen.kt index 6be90f525b..0afe3711b2 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/DetailsScreen.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/DetailsScreen.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState @@ -18,10 +19,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.SpacerH16 import com.tangem.core.ui.components.appbar.TangemTopAppBar import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM import com.tangem.core.ui.components.block.BlockItem import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -68,7 +73,7 @@ private fun Content( ) { LazyColumn( modifier = modifier.testTag(DetailsScreenTestTags.SCREEN_CONTAINER), - verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16), + verticalArrangement = Arrangement.SpaceBetween, contentPadding = PaddingValues( top = TangemTheme.dimens.spacing12, bottom = TangemTheme.dimens.spacing16, @@ -94,6 +99,7 @@ private fun Content( } item(key = "footer") { + SpacerH16() Footer( modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing12), model = state.footer, @@ -108,6 +114,16 @@ private fun Block( userWalletListBlockContent: ComposableContentComponent, modifier: Modifier = Modifier, ) { + if (model is DetailsItemUM.UnderSectionText) { + UnderSectionTextBlock( + modifier = Modifier.fillMaxWidth(), + text = model.text, + ) + return + } + + SpacerH16() + Column( modifier = modifier .fillMaxWidth() @@ -142,10 +158,21 @@ private fun Block( is DetailsItemUM.UserWalletList -> { userWalletListBlockContent.Content(modifier = itemModifier) } + is DetailsItemUM.UnderSectionText -> { /* Handled above */ } } } } +@Composable +private fun UnderSectionTextBlock(text: TextReference, modifier: Modifier = Modifier) { + Text( + modifier = modifier.padding(horizontal = 30.dp, vertical = 8.dp), + text = text.resolveReference(), + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.tertiary, + ) +} + @Composable private fun Footer(model: DetailsFooterUM, modifier: Modifier = Modifier) { Column( diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/UserWalletListBlock.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/UserWalletListBlock.kt index ec27900868..f06856c4df 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/UserWalletListBlock.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/ui/UserWalletListBlock.kt @@ -1,6 +1,7 @@ package com.tangem.features.details.ui import android.content.res.Configuration +import androidx.annotation.DrawableRes import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.layout.* import androidx.compose.material3.CircularProgressIndicator @@ -23,7 +24,6 @@ import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.details.component.UserWalletListComponent import com.tangem.features.details.component.preview.PreviewUserWalletListComponent import com.tangem.features.details.entity.UserWalletListUM -import com.tangem.features.details.impl.R @Composable internal fun UserWalletListBlock(state: UserWalletListUM, modifier: Modifier = Modifier) { @@ -42,6 +42,7 @@ internal fun UserWalletListBlock(state: UserWalletListUM, modifier: Modifier = M text = state.addNewWalletText, isInProgress = state.isWalletSavingInProgress, onClick = state.onAddNewWalletClick, + icon = state.addNewWalletIconRes, ) } } @@ -49,6 +50,7 @@ internal fun UserWalletListBlock(state: UserWalletListUM, modifier: Modifier = M @Composable private fun AddWalletButton( text: TextReference, + @DrawableRes icon: Int?, isInProgress: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier, @@ -65,23 +67,25 @@ private fun AddWalletButton( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), ) { - AnimatedContent( - modifier = Modifier.size(TangemTheme.dimens.size24), - targetState = isInProgress, - label = "Add wallet progress", - ) { isInProgress -> - if (isInProgress) { - CircularProgressIndicator( - modifier = Modifier.size(TangemTheme.dimens.size24), - color = TangemTheme.colors.icon.accent, - ) - } else { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_plus_24), - tint = TangemTheme.colors.icon.accent, - contentDescription = null, - ) + if (icon != null) { + AnimatedContent( + modifier = Modifier.size(TangemTheme.dimens.size24), + targetState = isInProgress, + label = "Add wallet progress", + ) { isInProgress -> + if (isInProgress) { + CircularProgressIndicator( + modifier = Modifier.size(TangemTheme.dimens.size24), + color = TangemTheme.colors.icon.accent, + ) + } else { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = icon), + tint = TangemTheme.colors.icon.accent, + contentDescription = null, + ) + } } } diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt index 7ee2b6eccd..9746070c35 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt @@ -8,6 +8,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.models.wallet.UserWalletId import com.tangem.features.details.entity.DetailsItemUM import com.tangem.features.details.impl.R +import com.tangem.features.hotwallet.HotWalletFeatureToggles import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -17,12 +18,16 @@ import javax.inject.Inject private const val TANGEM_PAY_ITEM_ID = "get_tangem_pay" @ModelScoped -internal class ItemsBuilder @Inject constructor(private val router: Router) { +internal class ItemsBuilder @Inject constructor( + private val router: Router, + private val hotWalletFeatureToggles: HotWalletFeatureToggles, +) { @Suppress("LongParameterList") fun buildAll( isWalletConnectAvailable: Boolean, isSupportChatAvailable: Boolean, + hasAnyMobileWallet: Boolean, userWalletId: UserWalletId, onSupportEmailClick: () -> Unit, onSupportChatClick: () -> Unit, @@ -30,6 +35,14 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) { ): ImmutableList = buildList { buildWalletConnectBlock(isWalletConnectAvailable, userWalletId)?.let(::add) buildUserWalletListBlock().let(::add) + + if (hotWalletFeatureToggles.isWalletCreationRestrictionEnabled && hasAnyMobileWallet) { + DetailsItemUM.UnderSectionText( + id = "only_one_mobile_wallet_explanation", + text = resourceReference(R.string.only_one_mobile_wallet_explanation), + ).let(::add) + } + buildShopBlock(onBuyClick).let(::add) buildSettingsBlock().let(::add) buildSupportBlock( diff --git a/features/hot-wallet/api/build.gradle.kts b/features/hot-wallet/api/build.gradle.kts index a51cd40254..7e7bd837fd 100644 --- a/features/hot-wallet/api/build.gradle.kts +++ b/features/hot-wallet/api/build.gradle.kts @@ -9,6 +9,7 @@ android { } dependencies { + implementation(projects.common.routing) /* Project - Domain */ implementation(projects.domain.models) diff --git a/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/HotWalletFeatureToggles.kt b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/HotWalletFeatureToggles.kt index f8ecf58ffe..c0526863e1 100644 --- a/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/HotWalletFeatureToggles.kt +++ b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/HotWalletFeatureToggles.kt @@ -2,4 +2,5 @@ package com.tangem.features.hotwallet interface HotWalletFeatureToggles { val isHotWalletEnabled: Boolean + val isWalletCreationRestrictionEnabled: Boolean } \ No newline at end of file diff --git a/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/WalletBackupComponent.kt b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/WalletBackupComponent.kt index c5c270623f..0d4df73fb4 100644 --- a/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/WalletBackupComponent.kt +++ b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/WalletBackupComponent.kt @@ -8,6 +8,7 @@ interface WalletBackupComponent : ComposableContentComponent { data class Params( val userWalletId: UserWalletId, + val isColdWalletOptionShown: Boolean, ) interface Factory : ComponentFactory diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/DefaultHotWalletFeatureToggles.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/DefaultHotWalletFeatureToggles.kt index cadb09331f..b635ab78db 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/DefaultHotWalletFeatureToggles.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/DefaultHotWalletFeatureToggles.kt @@ -7,4 +7,7 @@ internal class DefaultHotWalletFeatureToggles( ) : HotWalletFeatureToggles { override val isHotWalletEnabled: Boolean get() = featureTogglesManager.isFeatureEnabled(name = "HOT_WALLET_ENABLED") + override val isWalletCreationRestrictionEnabled: Boolean + get() = isHotWalletEnabled && + featureTogglesManager.isFeatureEnabled(name = "HOT_WALLET_CREATION_RESTRICTION_ENABLED") } \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/common/ui/OptionBlock.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/common/ui/OptionBlock.kt index bcc2a2c440..168491ff06 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/common/ui/OptionBlock.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/common/ui/OptionBlock.kt @@ -26,11 +26,11 @@ private const val DISABLED_COLORS_ALPHA = 0.5f internal fun OptionBlock( title: String, description: String, - badge: (@Composable () -> Unit)?, onClick: (() -> Unit)?, - enabled: Boolean, - backgroundColor: Color, modifier: Modifier = Modifier, + backgroundColor: Color = TangemTheme.colors.background.primary, + badge: (@Composable () -> Unit)? = null, + enabled: Boolean = true, ) { Column( modifier = modifier diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/ui/CreateHardwareWalletContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/ui/CreateHardwareWalletContent.kt index 095790c30a..08afdafd30 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/ui/CreateHardwareWalletContent.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/ui/CreateHardwareWalletContent.kt @@ -66,7 +66,7 @@ internal fun CreateHardwareWalletContent(state: CreateHardwareWalletUM, modifier top = 20.dp, end = 16.dp, ), - text = stringResourceSafe(R.string.wallet_create_common_title), + text = stringResourceSafe(R.string.hardware_wallet_create_title), style = TangemTheme.typography.h2, color = TangemTheme.colors.text.primary1, textAlign = TextAlign.Center, @@ -74,22 +74,22 @@ internal fun CreateHardwareWalletContent(state: CreateHardwareWalletUM, modifier FeatureBlock( modifier = Modifier .padding(top = 32.dp), - title = stringResourceSafe(R.string.hw_upgrade_key_migration_title), - description = stringResourceSafe(R.string.hw_upgrade_key_migration_description), - iconRes = R.drawable.ic_mobile_security_24, + title = stringResourceSafe(R.string.hardware_wallet_key_feature_title), + description = stringResourceSafe(R.string.hardware_wallet_key_feature_description), + iconRes = R.drawable.ic_mobile_security_2_24, ) FeatureBlock( modifier = Modifier .padding(top = 24.dp), - title = stringResourceSafe(R.string.hw_upgrade_funds_access_title), - description = stringResourceSafe(R.string.hw_upgrade_funds_access_description), - iconRes = R.drawable.ic_knight_shield_24, + title = stringResourceSafe(R.string.hardware_wallet_backup_feature_title), + description = stringResourceSafe(R.string.hardware_wallet_backup_feature_description), + iconRes = R.drawable.ic_double_star_24, ) FeatureBlock( modifier = Modifier .padding(top = 24.dp), - title = stringResourceSafe(R.string.hw_upgrade_general_security_title), - description = stringResourceSafe(R.string.hw_upgrade_general_security_description), + title = stringResourceSafe(R.string.hardware_wallet_security_feature_title), + description = stringResourceSafe(R.string.hardware_wallet_security_feature_description), iconRes = R.drawable.ic_protect_24, ) } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/ui/CreateMobileWalletContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/ui/CreateMobileWalletContent.kt index e6916bdcfd..bf0f02e9b8 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/ui/CreateMobileWalletContent.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/ui/CreateMobileWalletContent.kt @@ -75,14 +75,21 @@ internal fun CreateMobileWalletContent(state: CreateMobileWalletUM, modifier: Mo .padding(top = 32.dp), title = stringResourceSafe(R.string.hw_create_keys_title), description = stringResourceSafe(R.string.hw_create_keys_description), - iconRes = R.drawable.ic_lock_24, + iconRes = R.drawable.ic_protect_24, ) FeatureBlock( modifier = Modifier .padding(top = 24.dp), title = stringResourceSafe(R.string.hw_create_seed_title), description = stringResourceSafe(R.string.hw_create_seed_description), - iconRes = R.drawable.ic_settings_24, + iconRes = R.drawable.ic_seed_phrase_24, + ) + FeatureBlock( + modifier = Modifier + .padding(top = 24.dp), + title = stringResourceSafe(R.string.hw_create_upgrade_title), + description = stringResourceSafe(R.string.hw_create_upgrade_description), + iconRes = R.drawable.ic_tangem_card_24, ) } SecondaryButton( diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/ui/UpgradeWalletContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/ui/UpgradeWalletContent.kt index a643ee75e0..7dc3ca93cf 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/ui/UpgradeWalletContent.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/ui/UpgradeWalletContent.kt @@ -83,9 +83,9 @@ internal fun UpgradeWalletContent(state: UpgradeWalletUM, modifier: Modifier = M FeatureBlock( modifier = Modifier .padding(top = 24.dp), - title = stringResourceSafe(R.string.hw_upgrade_funds_access_title), - description = stringResourceSafe(R.string.hw_upgrade_funds_access_description), - iconRes = R.drawable.ic_knight_shield_24, + title = stringResourceSafe(R.string.hw_upgrade_backup_title), + description = stringResourceSafe(R.string.hw_upgrade_backup_description), + iconRes = R.drawable.ic_smartphone_24, ) FeatureBlock( modifier = Modifier diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/viewphrase/model/ViewPhraseModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/viewphrase/model/ViewPhraseModel.kt index a0b991c0a4..808f1df0b6 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/viewphrase/model/ViewPhraseModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/viewphrase/model/ViewPhraseModel.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @Stable @@ -48,19 +49,19 @@ internal class ViewPhraseModel @Inject constructor( private fun loadSeedPhrase() { val userWallet = getUserWalletUseCase(params.userWalletId) .getOrElse { error("User wallet with id ${params.userWalletId} not found") } - if (userWallet is UserWallet.Hot) { - modelScope.launch { - val words = exportSeedPhraseUseCase.invoke(userWallet.hotWalletId) - .getOrElse { error("Unable to export seed phrase for wallet with id ${params.userWalletId}") } - .mnemonic - .mnemonicComponents - uiState.update { - it.copy( - words = words.mapIndexed { index, s -> - EnumeratedTwoColumnGridItem(index + 1, s) - }.toImmutableList(), - ) - } + as? UserWallet.Hot ?: return + + modelScope.launch { + val words = exportSeedPhraseUseCase.invoke(userWallet.hotWalletId) + .getOrElse { error -> Timber.e(error); throw error } + .mnemonic.mnemonicComponents + + uiState.update { + it.copy( + words = words.mapIndexed { index, s -> + EnumeratedTwoColumnGridItem(index + 1, s) + }.toImmutableList(), + ) } } } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/entity/WalletBackupUM.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/entity/WalletBackupUM.kt index 9afce42e0d..a1219ed46a 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/entity/WalletBackupUM.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/entity/WalletBackupUM.kt @@ -8,7 +8,6 @@ internal data class WalletBackupUM( val recoveryPhraseOption: LabelUM?, val googleDriveOption: LabelUM?, val googleDriveStatus: BackupStatus, - val onBuyClick: () -> Unit, val onRecoveryPhraseClick: () -> Unit, val onGoogleDriveClick: () -> Unit, val onHardwareWalletClick: () -> Unit, diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt index bdc95378ca..7c284f9cef 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt @@ -2,21 +2,17 @@ package com.tangem.features.hotwallet.walletbackup.model import com.tangem.common.routing.AppRoute import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.Basic import com.tangem.core.analytics.utils.TrackingContextProxy import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router -import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.R import com.tangem.core.ui.components.label.entity.LabelStyle import com.tangem.core.ui.components.label.entity.LabelUM import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.wallets.analytics.WalletSettingsAnalyticEvents -import com.tangem.domain.wallets.usecase.GenerateBuyTangemCardLinkUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.wallets.usecase.UnlockHotWalletContextualUseCase import com.tangem.features.hotwallet.WalletBackupComponent @@ -36,8 +32,6 @@ internal class WalletBackupModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val getUserWalletUseCase: GetUserWalletUseCase, private val unlockHotWalletContextualUseCase: UnlockHotWalletContextualUseCase, - private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase, - private val urlOpener: UrlOpener, private val router: Router, private val trackingContextProxy: TrackingContextProxy, private val analyticsEventHandler: AnalyticsEventHandler, @@ -54,7 +48,7 @@ internal class WalletBackupModel @Inject constructor( hardwareWalletOption = LabelUM( text = resourceReference(R.string.common_recommended), style = LabelStyle.ACCENT, - ), + ).takeIf { params.isColdWalletOptionShown }, recoveryPhraseOption = LabelUM( text = resourceReference(R.string.hw_backup_no_backup), style = LabelStyle.WARNING, @@ -64,7 +58,6 @@ internal class WalletBackupModel @Inject constructor( style = LabelStyle.REGULAR, ), googleDriveStatus = BackupStatus.ComingSoon, - onBuyClick = ::onBuyClick, onRecoveryPhraseClick = ::onRecoveryPhraseClick, onGoogleDriveClick = { }, onHardwareWalletClick = ::onHardwareWalletClick, @@ -129,14 +122,6 @@ internal class WalletBackupModel @Inject constructor( backedUp = userWallet.backedUp, ) - private fun onBuyClick() { - analyticsEventHandler.send(Basic.ButtonBuy(source = AnalyticsParam.ScreensSources.Backup)) - modelScope.launch { - generateBuyTangemCardLinkUseCase - .invoke(GenerateBuyTangemCardLinkUseCase.Source.Backup).let { urlOpener.openUrl(it) } - } - } - private fun onRecoveryPhraseClick() { analyticsEventHandler.send(WalletSettingsAnalyticEvents.ButtonRecoveryPhrase()) if (uiState.value.backedUp) { @@ -157,10 +142,9 @@ internal class WalletBackupModel @Inject constructor( ) } else { router.push( - AppRoute.CreateWalletBackup( + AppRoute.WalletActivation( userWalletId = params.userWalletId, - analyticsSource = AnalyticsParam.ScreensSources.Backup.value, - analyticsAction = WalletSettingsAnalyticEvents.RecoveryPhraseScreenAction.Backup.value, + isBackupExists = false, ), ) } diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/ui/WalletBackupContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/ui/WalletBackupContent.kt index d3e452bab2..dc2787f9c6 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/ui/WalletBackupContent.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/ui/WalletBackupContent.kt @@ -1,36 +1,25 @@ package com.tangem.features.hotwallet.walletbackup.ui import android.content.res.Configuration -import androidx.annotation.DrawableRes -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import androidx.compose.ui.unit.dp import com.tangem.core.ui.R -import com.tangem.core.ui.components.SecondaryButton import com.tangem.core.ui.components.appbar.AppBarWithBackButton import com.tangem.core.ui.components.label.Label import com.tangem.core.ui.components.label.entity.LabelStyle import com.tangem.core.ui.components.label.entity.LabelUM import com.tangem.core.ui.components.rows.NetworkTitle -import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.res.ForceDarkTheme import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.hotwallet.common.ui.OptionBlock @@ -61,33 +50,31 @@ internal fun WalletBackupContent(state: WalletBackupUM, modifier: Modifier = Mod end = 16.dp, ), ) { - Banner(state) + if (state.hardwareWalletOption != null) { + OptionBlock( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + title = stringResourceSafe(R.string.hw_backup_upgrade_title), + description = stringResourceSafe(R.string.hw_backup_upgrade_description), + badge = { Label(state.hardwareWalletOption) }, + onClick = state.onHardwareWalletClick, + enabled = true, + backgroundColor = TangemTheme.colors.background.primary, + ) - OptionBlock( - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp), - title = stringResourceSafe(R.string.hw_backup_hardware_title), - description = stringResourceSafe(R.string.hw_backup_hardware_description), - badge = { - state.hardwareWalletOption?.let { Label(it) } - }, - onClick = state.onHardwareWalletClick, - enabled = true, - backgroundColor = TangemTheme.colors.background.primary, - ) - NetworkTitle( - modifier = Modifier - .padding(top = 8.dp), - title = { - Text( - modifier = Modifier, - text = stringResourceSafe(R.string.onboarding_create_wallet_options_button_options), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.tertiary, - ) - }, - ) + NetworkTitle( + modifier = Modifier.padding(top = 8.dp), + title = { + Text( + modifier = Modifier, + text = stringResourceSafe(R.string.onboarding_create_wallet_options_button_options), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.tertiary, + ) + }, + ) + } OptionBlock( modifier = Modifier, title = stringResourceSafe(R.string.hw_backup_seed_title), @@ -116,120 +103,6 @@ internal fun WalletBackupContent(state: WalletBackupUM, modifier: Modifier = Mod } } -@Suppress("LongMethod") -@OptIn(ExperimentalLayoutApi::class) -@Composable -private fun Banner(state: WalletBackupUM, modifier: Modifier = Modifier) { - ForceDarkTheme { - Column( - modifier = modifier - .background( - color = TangemTheme.colors.background.primary, - shape = RoundedCornerShape(16.dp), - ), - ) { - Column( - modifier = Modifier - .padding( - start = 12.dp, - top = 20.dp, - end = 12.dp, - ), - ) { - Text( - modifier = Modifier - .fillMaxWidth(), - text = "Tangem Wallet", - style = TangemTheme.typography.h3, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.Center, - ) - - Text( - modifier = Modifier - .fillMaxWidth() - .padding( - top = 4.dp, - ), - text = "Keeps your crypto safe and offline. Slim as a credit card, safer than a bank vault.", - style = TangemTheme.typography.body2, - color = TangemTheme.colors.text.tertiary, - textAlign = TextAlign.Center, - ) - - FlowRow( - modifier = Modifier - .fillMaxWidth() - .padding( - start = 24.dp, - top = 16.dp, - end = 24.dp, - ), - horizontalArrangement = Arrangement.Center, - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - FeatureItem( - iconResId = R.drawable.ic_shield_check_16, - text = resourceReference(R.string.welcome_create_wallet_feature_class), - ) - FeatureItem( - iconResId = R.drawable.ic_flash_16, - text = resourceReference(R.string.welcome_create_wallet_feature_delivery), - ) - FeatureItem( - iconResId = R.drawable.ic_sparkles_16, - text = resourceReference(R.string.welcome_create_wallet_feature_use), - ) - } - - Box( - modifier = Modifier - .padding( - start = 8.dp, - top = 12.dp, - end = 8.dp, - bottom = 20.dp, - ), - ) { - Image( - painter = painterResource(id = R.drawable.img_tangem_cards_vertical), - contentDescription = null, - ) - SecondaryButton( - modifier = Modifier - .fillMaxWidth() - .align(Alignment.BottomCenter), - text = stringResourceSafe(R.string.details_buy_wallet), - onClick = state.onBuyClick, - ) - } - } - } - } -} - -@Composable -private fun FeatureItem(@DrawableRes iconResId: Int, text: TextReference) { - Row( - modifier = Modifier - .wrapContentWidth() - .padding(horizontal = 8.dp), - horizontalArrangement = Arrangement.spacedBy(6.dp), - ) { - Icon( - modifier = Modifier.size(16.dp), - painter = painterResource(iconResId), - tint = TangemTheme.colors.icon.accent, - contentDescription = null, - ) - Text( - text = text.resolveReference(), - style = TangemTheme.typography.caption1, - color = TangemTheme.colors.text.secondary, - ) - } -} - @Preview(showBackground = true, widthDp = 360) @Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -256,7 +129,6 @@ private class WalletBackupUMProvider : CollectionPreviewParameterProvider, val onBackClick: () -> Unit, val onBuyClick: () -> Unit, diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt index efcd39aa14..ae34bf84a6 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/model/WalletHardwareBackupModel.kt @@ -32,10 +32,8 @@ import com.tangem.features.hotwallet.wallethardwarebackup.entity.WalletHardwareB import com.tangem.hot.sdk.model.HotWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.persistentListOf -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @@ -119,7 +117,6 @@ internal class WalletHardwareBackupModel @Inject constructor( init { trackingContextProxy.addHotWalletContext() analyticsEventHandler.send(WalletSettingsAnalyticEvents.HardwareBackupScreenOpened()) - showPurchaseBlockWithDelay() } override fun onDestroy() { @@ -127,13 +124,6 @@ internal class WalletHardwareBackupModel @Inject constructor( super.onDestroy() } - private fun showPurchaseBlockWithDelay() { - modelScope.launch { - delay(SHOW_PURCHASE_BLOCK_DELAY) - uiState.update { it.copy(showPurchaseBlock = true) } - } - } - private fun onCreateNewWalletClick() { analyticsEventHandler.send(WalletSettingsAnalyticEvents.ButtonCreateNewWallet()) router.push(AppRoute.CreateHardwareWallet) @@ -175,8 +165,4 @@ internal class WalletHardwareBackupModel @Inject constructor( .invoke(GenerateBuyTangemCardLinkUseCase.Source.Backup).let { urlOpener.openUrl(it) } } } - - companion object { - private const val SHOW_PURCHASE_BLOCK_DELAY = 3000L - } } \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/ui/WalletHardwareBackupContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/ui/WalletHardwareBackupContent.kt index 8e4eafbf78..41073ffc50 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/ui/WalletHardwareBackupContent.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/wallethardwarebackup/ui/WalletHardwareBackupContent.kt @@ -1,26 +1,26 @@ package com.tangem.features.hotwallet.wallethardwarebackup.ui import android.content.res.Configuration -import androidx.compose.animation.AnimatedVisibility +import androidx.annotation.DrawableRes +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.SecondaryButton -import com.tangem.core.ui.components.buttons.common.TangemButtonSize import com.tangem.core.ui.components.label.Label import com.tangem.core.ui.components.label.entity.LabelStyle import com.tangem.core.ui.components.label.entity.LabelUM -import com.tangem.core.ui.extensions.resolveReference -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.stringReference -import com.tangem.core.ui.extensions.stringResourceSafe +import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.res.ForceDarkTheme import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.hotwallet.common.ui.OptionBlock @@ -71,6 +71,8 @@ internal fun WalletHardwareBackupContent(state: WalletHardwareBackupUM, modifier end = 16.dp, ), ) { + Banner(onBuyClick = state.onBuyClick) + state.blocks.forEach { block -> OptionBlock( modifier = Modifier @@ -86,45 +88,119 @@ internal fun WalletHardwareBackupContent(state: WalletHardwareBackupUM, modifier ) } } - AnimatedVisibility(state.showPurchaseBlock) { - PurchaseBlock( - onBuyClick = state.onBuyClick, - ) + } +} + +@Suppress("LongMethod") +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun Banner(onBuyClick: () -> Unit, modifier: Modifier = Modifier) { + ForceDarkTheme { + Column( + modifier = modifier + .background( + color = TangemTheme.colors.background.primary, + shape = RoundedCornerShape(16.dp), + ), + ) { + Column( + modifier = Modifier + .padding( + start = 12.dp, + top = 20.dp, + end = 12.dp, + ), + ) { + Text( + modifier = Modifier + .fillMaxWidth(), + text = stringResourceSafe(R.string.common_tangem_wallet), + style = TangemTheme.typography.h3, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + ) + + Text( + modifier = Modifier + .fillMaxWidth() + .padding( + top = 4.dp, + ), + text = stringResourceSafe(R.string.hw_backup_banner_description), + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.tertiary, + textAlign = TextAlign.Center, + ) + + FlowRow( + modifier = Modifier + .fillMaxWidth() + .padding( + start = 24.dp, + top = 16.dp, + end = 24.dp, + ), + horizontalArrangement = Arrangement.Center, + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + FeatureItem( + iconResId = R.drawable.ic_shield_check_16, + text = resourceReference(R.string.welcome_create_wallet_feature_class), + ) + FeatureItem( + iconResId = R.drawable.ic_flash_16, + text = resourceReference(R.string.welcome_create_wallet_feature_delivery), + ) + FeatureItem( + iconResId = R.drawable.ic_sparkles_16, + text = resourceReference(R.string.welcome_create_wallet_feature_seedphrase), + ) + } + + Box( + modifier = Modifier + .padding( + start = 8.dp, + top = 12.dp, + end = 8.dp, + bottom = 20.dp, + ), + ) { + Image( + painter = painterResource(id = R.drawable.img_tangem_cards_vertical), + contentDescription = null, + ) + SecondaryButton( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter), + text = stringResourceSafe(R.string.details_buy_wallet), + onClick = onBuyClick, + ) + } + } } } } @Composable -private fun PurchaseBlock(onBuyClick: () -> Unit, modifier: Modifier = Modifier) { +private fun FeatureItem(@DrawableRes iconResId: Int, text: TextReference) { Row( - modifier = modifier - .fillMaxWidth() - .padding(16.dp) - .background( - color = TangemTheme.colors.background.primary, - shape = TangemTheme.shapes.roundedCornersXMedium, - ) - .padding( - horizontal = 20.dp, - vertical = 16.dp, - ), - verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .wrapContentWidth() + .padding(horizontal = 8.dp), + horizontalArrangement = Arrangement.spacedBy(6.dp), ) { - Text( - modifier = Modifier - .weight(1f) - .padding(end = 16.dp), - text = stringResourceSafe(R.string.wallet_add_hardware_purchase), - style = TangemTheme.typography.button, - color = TangemTheme.colors.text.primary1, - maxLines = 3, - overflow = TextOverflow.Ellipsis, + Icon( + modifier = Modifier.size(16.dp), + painter = painterResource(iconResId), + tint = TangemTheme.colors.icon.accent, + contentDescription = null, ) - - SecondaryButton( - text = stringResourceSafe(R.string.wallet_import_buy_title), - onClick = onBuyClick, - size = TangemButtonSize.RoundedAction, + Text( + text = text.resolveReference(), + style = TangemTheme.typography.caption1, + color = TangemTheme.colors.text.secondary, ) } } @@ -156,7 +232,6 @@ private fun PreviewWalletHardwareBackupContent() { onClick = { }, ), ), - showPurchaseBlock = true, onBuyClick = { }, ), ) diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt index 34449ac010..4fa7a53f60 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt @@ -65,7 +65,6 @@ internal class PreviewWalletSettingsComponent : WalletSettingsComponent { onNotificationsDescriptionClick = {}, isNotificationsPermissionGranted = false, onAccessCodeClick = {}, - onUpgradeWalletClick = {}, onBackupClick = {}, onCardSettingsClick = {}, accountsUM = previewAccounts(), diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/WalletSettingsItemUM.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/WalletSettingsItemUM.kt index a495db9417..d9ff609d19 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/WalletSettingsItemUM.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/entity/WalletSettingsItemUM.kt @@ -31,6 +31,7 @@ internal sealed class WalletSettingsItemUM { val text: TextReference, val isEnabled: Boolean, val imageState: ImageState, + val additionalBlock: BlockUM? = null, val onClick: () -> Unit, ) : WalletSettingsItemUM() @@ -46,13 +47,6 @@ internal sealed class WalletSettingsItemUM { val title: TextReference, val description: TextReference, ) : WalletSettingsItemUM() - - data class UpgradeWallet( - override val id: String, - val title: TextReference, - val description: TextReference, - val onClick: () -> Unit, - ) : WalletSettingsItemUM() } @Immutable diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt index 8e97fb4927..f817314f14 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt @@ -96,7 +96,10 @@ internal class WalletSettingsModel @Inject constructor( val params: WalletSettingsComponent.Params = paramsContainer.require() val dialogNavigation = SlotNavigation() val bottomSheetNavigation: SlotNavigation = SlotNavigation() - private val walletCardItemDelegate = walletCardItemDelegateFactory.create(dialogNavigation) + private val walletCardItemDelegate = walletCardItemDelegateFactory.create( + dialogNavigation = dialogNavigation, + onUpgradeHotWalletClick = ::onUpgradeWalletClick, + ) val state: MutableStateFlow = MutableStateFlow( value = WalletSettingsUM( @@ -249,7 +252,6 @@ internal class WalletSettingsModel @Inject constructor( onCheckedNotificationsChanged = ::onCheckedNotificationsChange, onNotificationsDescriptionClick = ::onNotificationsDescriptionClick, onAccessCodeClick = { onAccessCodeClick(userWallet) }, - onUpgradeWalletClick = { onUpgradeWalletClick() }, onBackupClick = ::onBackupClick, onCardSettingsClick = ::onCardSettingsClick, accountsUM = accountList, @@ -374,10 +376,7 @@ internal class WalletSettingsModel @Inject constructor( val isCodeSet = userWallet.hotWalletId.authType != HotWalletId.AuthType.NoPassword analyticsEventHandler.send(WalletSettingsAnalyticEvents.ButtonAccessCode(isCodeSet)) if (!state.value.isWalletBackedUp) { - showMakeBackupAtFirstAlertBS( - isUpgradeFlow = false, - action = WalletSettingsAnalyticEvents.NoticeBackupFirst.Action.AccessCode, - ) + showMakeBackupAtFirstAlertBS() } else { unlockWalletIfNeedAndProceed { authorizationRequired -> router.push( @@ -392,35 +391,28 @@ internal class WalletSettingsModel @Inject constructor( } private fun onUpgradeWalletClick() { - if (!state.value.isWalletBackedUp) { - showMakeBackupAtFirstAlertBS( - isUpgradeFlow = true, - action = WalletSettingsAnalyticEvents.NoticeBackupFirst.Action.Upgrade, - ) - } else { - unlockWalletIfNeedAndProceed { - router.push(AppRoute.UpgradeWallet(userWalletId = params.userWalletId)) - } - } + router.push(AppRoute.WalletHardwareBackup(userWalletId = params.userWalletId)) } private fun onBackupClick() { analyticsEventHandler.send(WalletSettingsAnalyticEvents.ButtonBackup()) - router.push(AppRoute.WalletBackup(params.userWalletId)) + router.push( + AppRoute.WalletBackup( + userWalletId = params.userWalletId, + isColdWalletOptionShown = false, + ), + ) } private fun onCardSettingsClick() { router.push(AppRoute.CardSettings(params.userWalletId)) } - private fun showMakeBackupAtFirstAlertBS( - action: WalletSettingsAnalyticEvents.NoticeBackupFirst.Action, - isUpgradeFlow: Boolean, - ) { + private fun showMakeBackupAtFirstAlertBS() { analyticsEventHandler.send( event = WalletSettingsAnalyticEvents.NoticeBackupFirst( source = AnalyticsParam.ScreensSources.WalletSettings.value, - action = action, + action = WalletSettingsAnalyticEvents.NoticeBackupFirst.Action.AccessCode, ), ) val message = bottomSheetMessage { @@ -438,14 +430,10 @@ internal class WalletSettingsModel @Inject constructor( router.push( AppRoute.CreateWalletBackup( userWalletId = params.userWalletId, - isUpgradeFlow = isUpgradeFlow, + isUpgradeFlow = false, shouldSetAccessCode = true, analyticsSource = AnalyticsParam.ScreensSources.WalletSettings.value, - analyticsAction = if (isUpgradeFlow) { - RecoveryPhraseScreenAction.Upgrade.value - } else { - RecoveryPhraseScreenAction.AccessCode.value - }, + analyticsAction = RecoveryPhraseScreenAction.AccessCode.value, ), ) closeBs() diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/WalletSettingsScreen.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/WalletSettingsScreen.kt index 7f9cb9d418..6590758780 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/WalletSettingsScreen.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/ui/WalletSettingsScreen.kt @@ -42,7 +42,6 @@ import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.components.notifications.NotificationConfig import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -153,10 +152,6 @@ private fun Content(state: WalletSettingsUM, modifier: Modifier = Modifier) { modifier = itemModifier, model = item, ) - is WalletSettingsItemUM.UpgradeWallet -> UpgradeWalletBlock( - modifier = itemModifier, - model = item, - ) is WalletSettingsAccountsUM.Header -> AccountsHeader(item, itemModifier) is WalletSettingsAccountsUM.Account -> AccountItem( model = item, @@ -211,35 +206,54 @@ private fun CardBlock(model: WalletSettingsItemUM.CardBlock, modifier: Modifier enabled = model.isEnabled, onClick = model.onClick, ) { - Row( - modifier = Modifier.padding(all = TangemTheme.dimens.spacing12), - horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), - verticalAlignment = Alignment.CenterVertically, - ) { - CardImage(model.imageState) - Column(modifier = Modifier.weight(1f)) { - Text( - text = model.title.resolveReference(), - color = TangemTheme.colors.text.tertiary, - style = TangemTheme.typography.caption2, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - Text( - text = model.text.resolveReference(), - color = TangemTheme.colors.text.primary1, - style = TangemTheme.typography.subtitle1, - overflow = TextOverflow.Ellipsis, - maxLines = 1, + Column { + Row( + modifier = Modifier.padding(all = TangemTheme.dimens.spacing12), + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), + verticalAlignment = Alignment.CenterVertically, + ) { + CardImage(model.imageState) + Column(modifier = Modifier.weight(1f)) { + Text( + text = model.title.resolveReference(), + color = TangemTheme.colors.text.tertiary, + style = TangemTheme.typography.caption2, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + Text( + text = model.text.resolveReference(), + color = TangemTheme.colors.text.primary1, + style = TangemTheme.typography.subtitle1, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) + } + SecondarySmallButton( + config = SmallButtonConfig( + isEnabled = model.isEnabled, + text = resourceReference(R.string.common_rename), + onClick = model.onClick, + ), ) } - SecondarySmallButton( - config = SmallButtonConfig( - isEnabled = model.isEnabled, - text = resourceReference(R.string.common_rename), - onClick = model.onClick, - ), - ) + + if (model.additionalBlock != null) { + Column { + HorizontalDivider( + thickness = TangemTheme.dimens.size0_5, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = TangemTheme.dimens.spacing12), + color = TangemTheme.colors.stroke.primary, + ) + + BlockItem( + modifier = Modifier.fillMaxWidth(), + model = model.additionalBlock, + ) + } + } } } } @@ -272,21 +286,6 @@ private fun SwitchBlock(model: WalletSettingsItemUM.WithSwitch, modifier: Modifi } } -@Composable -private fun UpgradeWalletBlock(model: WalletSettingsItemUM.UpgradeWallet, modifier: Modifier = Modifier) { - Notification( - config = NotificationConfig( - title = model.title, - subtitle = model.description, - iconResId = R.drawable.ic_hardware_backup_36, - iconSize = 36.dp, - onClick = model.onClick, - shouldShowArrowIcon = false, - ), - modifier = modifier, - ) -} - @Composable private fun NotificationAlertBlock(model: WalletSettingsItemUM.NotificationPermission, modifier: Modifier = Modifier) { Notification( @@ -480,20 +479,4 @@ private fun Preview_WalletSettingsScreen() { PreviewWalletSettingsComponent().Content(modifier = Modifier.fillMaxSize()) } } - -@Composable -@Preview(showBackground = true, widthDp = 360) -@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) -private fun Preview_WalletSettingsScreen1() { - TangemThemePreview { - UpgradeWalletBlock( - model = WalletSettingsItemUM.UpgradeWallet( - id = "upgrade_wallet", - title = stringReference("Upgrade wallet with a hardware backup"), - description = stringReference("Keep your crypto safe with Tangem’s best-in-class hardware wallet."), - onClick = {}, - ), - ) - } -} // endregion Preview \ No newline at end of file diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt index 86b1637320..a103dee2de 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt @@ -38,17 +38,10 @@ internal class ItemsBuilder @Inject constructor() { onReferralClick: () -> Unit, onManageTokensClick: () -> Unit, onAccessCodeClick: () -> Unit, - onUpgradeWalletClick: () -> Unit, onBackupClick: () -> Unit, onCardSettingsClick: () -> Unit, ): PersistentList = persistentListOf() .add(cardItem) - .addAll( - buildUpgradeWalletItem( - userWallet = userWallet, - onUpgradeWalletClick = onUpgradeWalletClick, - ), - ) .addAll(buildAccessCodeItem(userWallet, onAccessCodeClick)) .addAll(accountsUM) .add( @@ -116,21 +109,6 @@ internal class ItemsBuilder @Inject constructor() { onCheckedChange = onCheckedNFTChange, ) - private fun buildUpgradeWalletItem( - userWallet: UserWallet, - onUpgradeWalletClick: () -> Unit, - ): List = when (userWallet) { - is UserWallet.Cold -> emptyList() - is UserWallet.Hot -> listOf( - WalletSettingsItemUM.UpgradeWallet( - id = "upgrade_wallet", - title = resourceReference(id = R.string.hw_upgrade_to_cold_banner_title), - description = resourceReference(id = R.string.hw_upgrade_to_cold_banner_description), - onClick = onUpgradeWalletClick, - ), - ) - } - private fun buildNotificationsPermissionItem() = WalletSettingsItemUM.NotificationPermission( id = "notifications_permission", title = resourceReference(id = R.string.transaction_notifications_warning_title), diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/WalletCardItemDelegate.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/WalletCardItemDelegate.kt index 18d1546028..8162044ed2 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/WalletCardItemDelegate.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/WalletCardItemDelegate.kt @@ -2,6 +2,7 @@ package com.tangem.feature.walletsettings.utils import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate +import com.tangem.core.ui.components.block.model.BlockUM import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.models.wallet.UserWallet @@ -24,6 +25,7 @@ internal class WalletCardItemDelegate @AssistedInject constructor( private val getShouldSaveUserWalletsSyncUseCase: ShouldSaveUserWalletsSyncUseCase, private val walletImageFetcher: UserWalletImageFetcher, @Assisted private val dialogNavigation: SlotNavigation, + @Assisted private val onUpgradeHotWalletClick: () -> Unit, private val hotWalletFeatureToggles: HotWalletFeatureToggles, ) { @@ -43,10 +45,20 @@ internal class WalletCardItemDelegate @AssistedInject constructor( isEnabled = isRenameAvailable, onClick = { openRenameWalletDialog(wallet) }, imageState = imageState, + additionalBlock = buildUpgradeToHardwareWalletBlockOrNull(wallet), ) }, ) + private fun buildUpgradeToHardwareWalletBlockOrNull(wallet: UserWallet): BlockUM? { + return BlockUM( + text = resourceReference(R.string.upgrade_to_hardware_wallet_button_title), + iconRes = null, + onClick = onUpgradeHotWalletClick, + accentType = BlockUM.AccentType.ACCENT, + ).takeIf { wallet is UserWallet.Hot } + } + private fun openRenameWalletDialog(userWallet: UserWallet) { val config = DialogConfig.RenameWallet( userWalletId = userWallet.walletId, @@ -57,6 +69,9 @@ internal class WalletCardItemDelegate @AssistedInject constructor( @AssistedFactory interface Factory { - fun create(dialogNavigation: SlotNavigation): WalletCardItemDelegate + fun create( + dialogNavigation: SlotNavigation, + onUpgradeHotWalletClick: () -> Unit, + ): WalletCardItemDelegate } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 8d1c6bd283..ed19a09083 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -477,7 +477,16 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onFinishWalletActivationClick(isBackupExists: Boolean) { analyticsEventHandler.send(MainScreen.ButtonFinalizeActivation()) val userWalletId = stateHolder.getSelectedWalletId() - appRouter.push(WalletActivation(userWalletId, isBackupExists)) + val route = if (isBackupExists) { + WalletActivation(userWalletId = userWalletId, isBackupExists = true) + } else { + WalletBackup( + userWalletId = userWalletId, + isColdWalletOptionShown = true, + ) + } + + appRouter.push(route) } override fun onAllowPermissions() { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsSingleEventSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsSingleEventSender.kt index 69b492660a..4b4227a657 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsSingleEventSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsSingleEventSender.kt @@ -1,6 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.analytics.utils -import com.tangem.common.routing.AppRoute.WalletActivation +import com.tangem.common.routing.AppRoute.WalletBackup import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender @@ -93,7 +93,12 @@ internal class WalletWarningsSingleEventSender @Inject constructor( primaryButton { text = resourceReference(R.string.hw_activation_need_backup) onClick { - router.push(WalletActivation(userWallet.walletId, userWallet.backedUp)) + router.push( + WalletBackup( + userWalletId = userWalletId, + isColdWalletOptionShown = true, + ), + ) closeBs() } } diff --git a/features/welcome/impl/build.gradle.kts b/features/welcome/impl/build.gradle.kts index 7557118256..09713985c8 100644 --- a/features/welcome/impl/build.gradle.kts +++ b/features/welcome/impl/build.gradle.kts @@ -14,6 +14,7 @@ android { dependencies { implementation(projects.features.welcome.api) implementation(projects.features.wallet.api) + implementation(projects.features.hotWallet.api) /** Core */ implementation(projects.core.configToggles) diff --git a/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt b/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt index b5b89566f2..4179ffefe8 100644 --- a/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt +++ b/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt @@ -12,14 +12,22 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.message.SnackbarMessage +import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.common.wallets.UserWalletsListRepository +import com.tangem.domain.common.wallets.error.SaveWalletError import com.tangem.domain.common.wallets.error.UnlockWalletError import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.isLocked import com.tangem.domain.settings.CanUseBiometryUseCase +import com.tangem.domain.wallets.builder.ColdUserWalletBuilder import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.NonBiometricUnlockWalletUseCase +import com.tangem.domain.wallets.usecase.SaveWalletUseCase +import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.features.wallet.utils.UserWalletsFetcher import com.tangem.features.welcome.impl.ui.state.WelcomeUM import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -40,10 +48,15 @@ internal class WelcomeModel @Inject constructor( private val userWalletsListRepository: UserWalletsListRepository, private val nonBiometricUnlockWalletUseCase: NonBiometricUnlockWalletUseCase, private val canUseBiometryUseCase: CanUseBiometryUseCase, + private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory, + private val saveWalletUseCase: SaveWalletUseCase, private val walletsRepository: WalletsRepository, private val trackingContextProxy: TrackingContextProxy, private val analyticsEventHandler: AnalyticsEventHandler, userWalletsFetcherFactory: UserWalletsFetcher.Factory, + private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val scanCardProcessor: ScanCardProcessor, + private val messageSender: UiMessageSender, ) : Model() { val uiState: StateFlow @@ -168,7 +181,50 @@ internal class WelcomeModel @Inject constructor( private fun addWalletClick() { analyticsEventHandler.send(SignIn.ButtonAddWallet(AnalyticsParam.ScreensSources.SignIn)) - router.push(AppRoute.CreateWalletSelection) + if (hotWalletFeatureToggles.isWalletCreationRestrictionEnabled) { + scanCard() + } else { + router.push(AppRoute.CreateWalletSelection) + } + } + + private fun scanCard() { + modelScope.launch { + scanCardProcessor.scan( + analyticsSource = AnalyticsParam.ScreensSources.SignIn, + onWalletNotCreated = {}, + disclaimerWillShow = { router.pop() }, + onSuccess = { scanResponse -> + val userWallet = + coldUserWalletBuilderFactory.create(scanResponse = scanResponse).build() ?: return@scan + saveWalletUseCase.invoke(userWallet) + .onLeft { error -> + if (error is SaveWalletError.WalletAlreadySaved) { + userWalletsListRepository.unlock( + userWallet.walletId, + unlockMethod = UserWalletsListRepository.UnlockMethod.Scan(scanResponse), + ).onRight { + userWalletsListRepository.select(userWallet.walletId) + router.replaceAll(AppRoute.Wallet) + } + } + } + .onRight { + router.replaceAll(AppRoute.Wallet) + } + }, + onCancel = {}, + onFailure = { tangemError -> + if (!tangemError.silent) { + val message = tangemError.messageResId + ?.let(::resourceReference) + ?: stringReference(tangemError.customMessage) + + messageSender.send(SnackbarMessage(message)) + } + }, + ) + } } private suspend fun onlyOneHotWalletWithAccessCode(): Boolean { diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 9f09031069..370da97987 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,7 +5,7 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.32-1335" +tangemBlockchainSdk = "releases-5.32-1382" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.32-574" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^