From ea2598e739698606bc24407807b365edc85ef8a2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 1 Jun 2023 16:43:45 +0300 Subject: [PATCH 01/54] Updated on 2026-08-14 --- core/res/src/main/res/values-de/strings.xml | 3 +- core/res/src/main/res/values-fr/strings.xml | 3 +- core/res/src/main/res/values-it/strings.xml | 3 +- core/res/src/main/res/values-ru/strings.xml | 27 ++++++++++++++-- .../src/main/res/values-zh-rTW/strings.xml | 22 +++++++++++-- core/res/src/main/res/values/strings.xml | 32 ++++++++++++++++++- 6 files changed, 79 insertions(+), 11 deletions(-) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 3e71b3a98a..0c4d6e28e1 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -12,6 +12,7 @@ Erledigt OK Änderungen speichern + Absenden Erfolg Zugangscode Sie müssen den richtigen Zugangscode eingeben, bevor Sie die Karte scannen. @@ -48,7 +49,6 @@ Priorität Höchstbetrag Netzgebühr - Absenden Gesamt %1$s und %2$s werden gesendet ≈ %1$s (inkl. Gebühr: %2$s) @@ -61,7 +61,6 @@ Die Bilanz wird aufgeladen… Die Transaktion läuft… Verifizierte Bilanz - Absenden WalletConnect Das Konto ist nicht erstellt Diese Karte wird nicht unterstützt diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 01059b36ff..f809f8c50d 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -12,6 +12,7 @@ Exécuté OK Sauvegarder les modifications + Envoyer Avec succès Code d\'accès Vous devrez entrer le mot de passe correct avant de scanner la carte @@ -48,7 +49,6 @@ Priorité Somme maximale Commissions du réseau - Envoyer Total Sera envoyé %1$s et %2$s ≈ %1$s (incl. les commissions : %2$s) @@ -61,7 +61,6 @@ Solde est en cours de téléchargement… Transaction en cours… Solde confirmé - Envoyer WalletConnect Compte n\'est pas créé Cette carte n\'est pas prise en charge diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index bc24145f51..83b4019140 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -12,6 +12,7 @@ Fatto OK Mantieni le modifiche + Invia Con successo Codice di accesso Prima di scansionare la carta sarà necessario inserire il codice di accesso corretto @@ -48,7 +49,6 @@ Prioritario Importo totale Costi della rete - Invia Totale Sarà inviato %1$s e %2$s ≈ %1$s (inc. commissione: %2$s) @@ -61,7 +61,6 @@ Il saldo sta per essere caricato… Transazione in corso… Saldo verificato - Invia WalletConnect Conto non creato Questa carta non è supportata diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 57b1b1dcae..f2b6457174 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -15,7 +15,7 @@ Эта карта не является платежным средством. В настоящее время мы не можем сопоставить количество подписей на карте с информацией в блокчейне. Это нормально, но в редких случаях может означать, что предыдущий владелец удерживает подписанную транзакцию от публикации, что является поводом для беспокойства.\nНе принимайте эту карту в качестве физического платежа от кого-то, кому вы не доверяете.\nВо всех остальных отношениях эта карта совершенно безопасна.\nTangem — единственный аппаратный кошелек, предлагающий защиту методом подсчета подписей. У вас возникли трудности со сканированием карты? Эта карта не предназначена для работы с этим приложением - Перейдите в настройки, чтобы включить биометрическую аутентификацию в приложении Tangem App + Перейдите в настройки, чтобы включить биометрическую аутентификацию в приложении Tangem Включите биометрическую аутентификацию Все сохраненные коды доступа будут удалены. Вам потребуется вводить код доступа при работе с кошельком. При отключении функции сохранения кошелька все ранее сохраненные кошельки будут удалены из приложения. @@ -52,27 +52,37 @@ Баланс: %s биометрическую аутентификацию биометрией + Купить Вы не предоставили доступ к камере, пожалуйста, измените настройки конфиденциальности. Отмена Закрыть Копировать + Скопировать адрес Создать Удалить Отключено + Не нравится Готово Включить Включено - Обозреватель + Обменять + Нравится Нет + Нет данных Ок Основная карта + Получить Отклонить Сохранить изменения Искать + Секретная фраза + Продать + Отправить Сервер недоступен, повторите попытку позднее Поделиться Подписать Подписать и отправить + Стейкинг Начать Отправить Успешно @@ -81,6 +91,7 @@ Транзакции Перевод Я понял + Недоступно Да Адрес контракта скопирован! Доступные сети @@ -462,13 +473,21 @@ Dapp %1$s, запрос на\nподпись транзакции с BNB.\n\n%2$s Торговый ордер на %1$s\nЦена: %2$s\nСумма к получению: %3$s\nСумма к оплате: %4$s Детали транзакции:\nОт: %1$s\nК: %2$s\nСумма: %3$s + Транзакция с BNB успешно подписана и отправлена ​​в Dapp. Буфер обмена содержит код WalletConnect. Использовать скопированное значение или отсканировать QR-код Запрос на создание транзакции для %1$s\n%2$s\n\nСумма: %3$s\nКомиссия: %4$s\nВсего: %5$s\nБаланс: %6$s Невозможно отправить транзакцию. Недостаточно средств. Не удалось установить сессию WalletConnect. Пожалуйста, повторите попытку позже. + Не все токены добавлены в ваш список. Пожалуйста, добавьте их в начале, а потом попробуйте снова. Недостающие токены: \n + Не удалось подписать сообщение.\nПожалуйста, попробуйте еще раз Не удалось установить сессию WalletConnect за отведённое время. Пожалуйста, повторите попытку позже. Запрос на подключение через WalletConnect содержит неподдерживаемые блокчеины. Неподдерживаемые блокчеины:\n Cоединение с этим Dapp сервисом не может быть установлено из-за его технической реализации. + Произошла непредвиденная ошибка. Сообщение ошибки: %s Попробуйте, пожалуйста, позже. Если проблема будет продолжать возникать - обратитесь в службу поддержки. + Неверная карта выбрана в приложении Tangem + Не удалось создать транзакцию из данных Dapp. Код: %s + Произошла непредвиденная ошибка. Код ошибки: %d Попробуйте, пожалуйста, позже. Если проблема будет продолжать возникать - обратитесь в службу поддержки. + Сообщение было успешно подписано и отправлено в Dapp Сеть %s не найдена. Пожалуйста, добавьте её и попробуйте заново. Вставить из буфера обмена Запрос на открытие сессии для\n%1$s\n\nСЕТЬ: %2$s\n\nURL: %3$s @@ -477,8 +496,12 @@ Эту карту нельзя использовать с WalletConnect. Сеть не поддерживается. Пожалуйста, выберите другую сеть. Выберите сеть + Dapp не предоставил необходимые данные для открытия сессии WalletConnect Подключение к Dapps WalletConnect + Транзакция успешно подписана и отправлена ​​в Dapp + Транзакция успешно подписана и отправлена ​​в блокчейн + Не удалось найти хэш транзакции Сеть %s Аккаунт не создан Эта карта не поддерживается diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml index 597be9911d..8b25c3a89d 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -46,23 +46,29 @@ 餘額: %s 生物識別 生物 + 購買 您尚未授予相機訪問權限,請更改您的隱私設置 刪除 關閉 複製 + 複製地址 創造 刪除 禁用 + 不喜歡 完成 允許 啟用 交易 + 喜歡 OK 主卡片 拒絕 保存設置 搜索 + 銷售 + 發送 伺服器不可用,請稍後在試 分享 簽署 @@ -74,6 +80,7 @@ 條款和條件 交易 我了解 + 無法觸達 已複製代幣地址 支持的網路 @@ -317,7 +324,6 @@ 優先 最大值 網路費 - 發送 發送 %s 總計 %1$s 和 %2$s 將被發送 @@ -432,13 +438,21 @@ Dapp %1$s,請求\n簽署 BNB 交易。\n%2$s %1$s 的交易訂單\n價格: %2$s\n接收金額:%3$s\n支付數量: %4$s 交易明細:\n從: %1$s\n到: %2$s\n數量: %3$s + BNB 交易已成功簽署並發送至 Dapp 剪貼板包含 WalletConnect 代碼。使用複制的值或掃描二維碼 請求為 %1$s 創建交易\n%2$s\n\n數量: %3$s\n費用: %4$s\n全部的: %5$s\n餘額: %6$s 無法交易,無足夠資金 未能建立 WalletConnect 連接。請稍後再試 + 並非所有代幣都已添加到您的列表中。請先添加它們,然後重試。缺少標記:\n + 無法簽署消息。請重試 無法建立 WalletConnect 連接:超時錯誤。請稍後再試 - 會話請求包含不支持 WalletConnect 連接的區塊鏈。不支持的區塊鏈: + 會話請求包含不支持 WalletConnect 連接的區塊鏈。不支持的區塊鏈:\n 由於技術問題,無法與此 Dapp 建立連接 + 我們遇到了未知錯誤。錯誤信息:%s。如果問題仍然存在-請隨時聯繫我們的客服人員 + 在 Tangem App 中選擇了錯誤的卡 + 無法從 Dapp 數據創建交易。代碼: %s + 我們遇到了未知錯誤。錯誤代碼:%d。如果問題仍然存在-請隨時聯繫我們的支持人員 + 消息已成功簽名並發送至Dapp 沒有 %s 網路,請先加入後再試一次 從剪貼板貼上 請求開始會話\n%1$s\n\n網絡: %2$s\n\n網址:%3$s @@ -447,8 +461,12 @@ 此卡不能用於建立 WalletConnect 連接 不支持此網絡。請選擇其他網絡 選擇網路 + Dapp 沒有提供必要的數據來建立 WalletConnect 連接 連結到Dapps WalletConnect + 交易已成功簽署並發送至 Dapp + 交易已成功簽署並發送至區塊鏈 + 未能找到交易哈希 %s 網路 帳號尚未被創造 不支持此卡 diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index e68fd193bb..aa3dd033f5 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -50,27 +50,37 @@ Balance: %s biometric authentication biometrics + Buy You have not given access to your camera, please adjust your privacy settings Cancel Close Copy + Copy address Create Delete Disabled + Dislike Done Enable Enabled - Explorer + Exchange + Like No + No data OK Primary Card + Receive Reject Save changes Search + Seed phrase + Sell + Send The server is not available, please try again later Share Sign Sign and send + Stake Start Submit Success @@ -79,6 +89,7 @@ Transactions Transfer I understand + Unreachable Yes Contract address copied! Available networks @@ -143,6 +154,8 @@ Tap the card Internal error: wallet manager not found You have updated biometrics, scan your card to enter + You have completed the training and can get your 1inch tokens + Get a bonus Manage tokens To protect your assets, we advise you to carry out this procedure Your wallet has not been backed up @@ -341,6 +354,8 @@ I have a promo code… Tangem Wallet Other payment methods + Due to the high volume of orders we are receiving, Shipping and Local Delivery orders may be delayed. + Pre-order now Due to the high volume of orders we are receiving shipping may be delayed up to 5 weeks depending on your location Total Solana network charges a rent of %1$s every 2 days. Accounts that can\'t afford the rent are purged from the network. Deposit your account with more than %2$s to use it for free. @@ -354,6 +369,9 @@ Thousands of Currencies Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. The Wallet for Everyone + Complete the training, get the opportunity to buy Tangem wallet with a discount and receive 1inch tokens on your wallet + Learn + Learn and get a bonus Borrow Buy Exchange @@ -455,13 +473,21 @@ Dapp %1$s, requesting to\nsign BNB transaction.\n\n%2$s Trade order for %1$s\nPrice: %2$s\nAmount to receive: %3$s\nAmount to pay: %4$s Transaction details:\nFrom: %1$s\nTo: %2$s\nAmount: %3$s + The BNB transaction has been successfully signed and sent to the Dapp Clipboard contain WalletConnect code. Use copied value or scan QR-code Request to create transaction for %1$s\n%2$s\n\nAmount: %3$s\nFee: %4$s\nTotal: %5$s\nBalance: %6$s Can\'t send transaction. Not enough funds. Failed to establish WalletConnect session. Please, try again later. + Not all tokens were added to your list. Please add them first and try again. Missing tokens:\n + Failed to sign message.\nPlease, try again Failed to establish WalletConnect session: timeout error. Please, try again later. Session request contains unsupported blockchains for WalletConnect connection. Unsupported blockchains:\n Connection with this Dapp cannot be established due to its technical implementation. + We\'ve encountered unknown error. Error message: %s. If the problem persists — feel free to contact our support + Wrong card selected in Tangem App + Failed to create transaction from Dapp data. Code: %s + We\'ve encountered unknown error. Error code: %d. If the problem persists — feel free to contact our support + The message has been successfully signed and sent to the Dapp %s network not found. Please, add it first and try again. Paste from clipboard Request to start a session for\n%1$s\n\nNETWORK: %2$s\n\nURL: %3$s @@ -470,8 +496,12 @@ This card can\'t be used to establish WalletConnect session This network is not supported. Please select another network. Select network + Dapp didn\'t provide essential data to establish WalletConnect session Connect to Dapps WalletConnect + The transaction has been successfully signed and sent to the Dapp + The transaction has been succesfully signed and sent to the blockchain + Failed to find transaction hash %s network Account is not created This card is not supported From 201f1e514a0c8d7f43d7512800f9f8d6660aca54 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 1 Jun 2023 23:34:24 +0300 Subject: [PATCH 02/54] Updated on 2026-08-14 --- app/build.gradle.kts | 2 + features/learn2earn/api/.gitignore | 1 + features/learn2earn/api/build.gradle.kts | 5 ++ .../api/src/main/AndroidManifest.xml | 2 + features/learn2earn/impl/.gitignore | 1 + features/learn2earn/impl/build.gradle.kts | 50 +++++++++++++++++++ .../impl/src/main/AndroidManifest.xml | 3 ++ settings.gradle.kts | 3 ++ 8 files changed, 67 insertions(+) create mode 100644 features/learn2earn/api/.gitignore create mode 100644 features/learn2earn/api/build.gradle.kts create mode 100644 features/learn2earn/api/src/main/AndroidManifest.xml create mode 100644 features/learn2earn/impl/.gitignore create mode 100644 features/learn2earn/impl/build.gradle.kts create mode 100644 features/learn2earn/impl/src/main/AndroidManifest.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1634169316..efe2848d8c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -39,6 +39,8 @@ dependencies { /** Features */ implementation(project(":features:onboarding")) + implementation(project(":features:learn2earn:api")) + implementation(project(":features:learn2earn:impl")) implementation(project(":features:referral:presentation")) implementation(project(":features:referral:domain")) implementation(project(":features:referral:data")) diff --git a/features/learn2earn/api/.gitignore b/features/learn2earn/api/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/learn2earn/api/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/learn2earn/api/build.gradle.kts b/features/learn2earn/api/build.gradle.kts new file mode 100644 index 0000000000..1fbece85d5 --- /dev/null +++ b/features/learn2earn/api/build.gradle.kts @@ -0,0 +1,5 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + id("configuration") +} \ No newline at end of file diff --git a/features/learn2earn/api/src/main/AndroidManifest.xml b/features/learn2earn/api/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..4d3df466b3 --- /dev/null +++ b/features/learn2earn/api/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/features/learn2earn/impl/.gitignore b/features/learn2earn/impl/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/features/learn2earn/impl/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/learn2earn/impl/build.gradle.kts b/features/learn2earn/impl/build.gradle.kts new file mode 100644 index 0000000000..f0071798aa --- /dev/null +++ b/features/learn2earn/impl/build.gradle.kts @@ -0,0 +1,50 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.kotlin.serialization) + alias(deps.plugins.hilt.android) + id("configuration") +} + +dependencies { + /** AndroidX */ + implementation(deps.androidx.activity.compose) + implementation(deps.androidx.core.ktx) + implementation(deps.androidx.appCompat) + implementation(deps.androidx.constraintLayout) + + /** Compose */ + implementation(deps.compose.material) + implementation(deps.compose.foundation) + implementation(deps.compose.constraintLayout) + implementation(deps.compose.ui) + implementation(deps.compose.ui.tooling) + implementation(deps.compose.animation) + implementation(deps.compose.navigation) + implementation(deps.compose.navigation.hilt) + + /** Core modules */ + implementation(project(":common")) + implementation(project(":core:featuretoggles")) + implementation(project(":core:datasource")) + implementation(project(":core:analytics")) + implementation(project(":core:utils")) + implementation(project(":core:ui")) + implementation(project(":core:res")) + + /** Tangem libraries */ + // implementation(deps.tangem.card.core) + // implementation(deps.tangem.card.android) { + // exclude(module = "joda-time") + // } + + /** Other libraries */ + implementation(deps.kotlin.immutable.collections) + implementation(deps.kotlin.serialization) + implementation(deps.timber) + + /** DI */ + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/AndroidManifest.xml b/features/learn2earn/impl/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..472f44a1a5 --- /dev/null +++ b/features/learn2earn/impl/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 3928077a46..15b3f6a078 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -60,6 +60,9 @@ include(":features:tester:impl") include(":features:wallet:api") include(":features:wallet:impl") + +include(":features:learn2earn:api") +include(":features:learn2earn:impl") // endregion Feature modules // region Domain modules From 0196e566196c10528af11a53ce5761a8227086c8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 1 Jun 2023 23:34:55 +0300 Subject: [PATCH 03/54] Updated on 2026-08-14 --- .../res/drawable/img_1inch_logo_401_378.xml | 76 +++++++++++++++++ .../res/drawable/img_1inch_logo_42_40.xml | 83 +++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 core/ui/src/main/res/drawable/img_1inch_logo_401_378.xml create mode 100644 core/ui/src/main/res/drawable/img_1inch_logo_42_40.xml diff --git a/core/ui/src/main/res/drawable/img_1inch_logo_401_378.xml b/core/ui/src/main/res/drawable/img_1inch_logo_401_378.xml new file mode 100644 index 0000000000..5c2c3c1156 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_1inch_logo_401_378.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/ui/src/main/res/drawable/img_1inch_logo_42_40.xml b/core/ui/src/main/res/drawable/img_1inch_logo_42_40.xml new file mode 100644 index 0000000000..c704358828 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_1inch_logo_42_40.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 09907d00f67fe7fea5f63799d0d081c97959b029 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 1 Jun 2023 23:35:17 +0300 Subject: [PATCH 04/54] Updated on 2026-08-14 --- .../features/home/compose/StoriesScreen.kt | 107 ++++++++---------- .../home/compose/views/StoriesProgressBar.kt | 9 +- .../tap/features/home/redux/HomeState.kt | 30 +++++ .../presentation/ui/OneInchStoriesScreen.kt | 105 +++++++++++++++++ .../presentation/ui/component/Gradient.kt | 38 +++++++ 5 files changed, 220 insertions(+), 69 deletions(-) create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/component/Gradient.kt diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt index ef40d850f6..2d453259c4 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt @@ -5,29 +5,11 @@ package com.tangem.tap.features.home.compose import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBars -import androidx.compose.foundation.layout.union -import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.layout.* import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -43,20 +25,16 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.google.accompanist.systemuicontroller.rememberSystemUiController -import com.tangem.tap.features.home.compose.content.FirstStoriesContent -import com.tangem.tap.features.home.compose.content.StoriesCurrencies -import com.tangem.tap.features.home.compose.content.StoriesRevolutionaryWallet -import com.tangem.tap.features.home.compose.content.StoriesUltraSecureBackup -import com.tangem.tap.features.home.compose.content.StoriesWalletForEveryone -import com.tangem.tap.features.home.compose.content.StoriesWeb3 +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.learn2earn.presentation.ui.OneInchStoriesContent +import com.tangem.tap.features.home.compose.content.* import com.tangem.tap.features.home.compose.views.HomeButtons import com.tangem.tap.features.home.compose.views.StoriesProgressBar import com.tangem.tap.features.home.redux.HomeState +import com.tangem.tap.features.home.redux.Stories import com.tangem.wallet.R import kotlin.math.max -private const val STEPS = 6 - @Suppress("LongMethod", "ComplexMethod") @Composable fun StoriesScreen( @@ -65,16 +43,18 @@ fun StoriesScreen( onShopButtonClick: () -> Unit, onSearchTokensClick: () -> Unit, ) { - val currentStep = remember { mutableStateOf(1) } val systemUiController = rememberSystemUiController() + val state = homeState.value - val isDarkBackground = currentStep.value !in 3..5 + var currentStory by remember { mutableStateOf(state.firstStory) } + val currentStep = { state.stepOf(currentStory) } val goToPreviousScreen = { - currentStep.value = max(1, currentStep.value - 1) + currentStory = state.stories[max(0, currentStep() - 1)] } val goToNextScreen = { - currentStep.value = if (currentStep.value < STEPS) currentStep.value + 1 else 1 + currentStory = + if (currentStep() < state.stories.lastIndex) state.stories[currentStep() + 1] else state.firstStory } val isPressed = remember { mutableStateOf(false) } @@ -82,10 +62,10 @@ fun StoriesScreen( val hideContent = remember { mutableStateOf(true) } - LaunchedEffect(key1 = isDarkBackground) { + LaunchedEffect(key1 = currentStory.isDarkBackground) { systemUiController.setSystemBarsColor( color = Color.Transparent, - darkIcons = !isDarkBackground, + darkIcons = !currentStory.isDarkBackground, ) } @@ -134,7 +114,7 @@ fun StoriesScreen( }, ) } - if (!isDarkBackground) { + if (!currentStory.isDarkBackground) { Image( modifier = Modifier.fillMaxSize(), painter = painterResource(id = R.drawable.ic_overlay), @@ -154,9 +134,9 @@ fun StoriesScreen( verticalArrangement = Arrangement.Center, ) { StoriesProgressBar( - steps = STEPS, - currentStep = currentStep.value, - stepDuration = currentStep.duration(), + steps = state.stories.lastIndex, + currentStep = currentStep(), + stepDuration = currentStory.duration, paused = isPaused, onStepFinish = goToNextScreen, ) @@ -169,15 +149,21 @@ fun StoriesScreen( .height(17.dp) .alpha(if (hideContent.value) 0f else 1f) .align(Alignment.Start), - colorFilter = if (isDarkBackground) null else ColorFilter.tint(Color.Black), + colorFilter = if (currentStory.isDarkBackground) null else ColorFilter.tint(Color.Black), ) - when (currentStep.value) { - 1 -> FirstStoriesContent(isPaused, currentStep.duration()) { hideContent.value = it } - 2 -> StoriesRevolutionaryWallet(currentStep.duration()) - 3 -> StoriesUltraSecureBackup(isPaused, currentStep.duration()) - 4 -> StoriesCurrencies(isPaused, currentStep.duration()) - 5 -> StoriesWeb3(isPaused, currentStep.duration()) - 6 -> StoriesWalletForEveryone(currentStep.duration()) + when (currentStory) { + Stories.OneInchPromo -> { + // TODO: fixme + TangemTheme { + OneInchStoriesContent({}) + } + } + Stories.TangemIntro -> FirstStoriesContent(isPaused, currentStory.duration) { hideContent.value = it } + Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet(currentStory.duration) + Stories.UltraSecureBackup -> StoriesUltraSecureBackup(isPaused, currentStory.duration) + Stories.Currencies -> StoriesCurrencies(isPaused, currentStory.duration) + Stories.Web3 -> StoriesWeb3(isPaused, currentStory.duration) + Stories.WalletForEveryone -> StoriesWalletForEveryone(currentStory.duration) } } Column( @@ -186,7 +172,7 @@ fun StoriesScreen( .align(Alignment.BottomCenter) .fillMaxWidth(), ) { - if (currentStep.value == 4) { + if (currentStory == Stories.Currencies) { Button( onClick = onSearchTokensClick, modifier = Modifier @@ -210,25 +196,22 @@ fun StoriesScreen( ) } } - HomeButtons( - modifier = Modifier - .padding(start = 16.dp, top = 0.dp, end = 16.dp, bottom = 37.dp) - .fillMaxWidth(), - isDarkBackground = isDarkBackground, - btnScanStateInProgress = homeState.value.btnScanStateInProgress, - onScanButtonClick = onScanButtonClick, - onShopButtonClick = onShopButtonClick, - ) + + if (currentStory != Stories.OneInchPromo) { + HomeButtons( + modifier = Modifier + .padding(start = 16.dp, top = 0.dp, end = 16.dp, bottom = 37.dp) + .fillMaxWidth(), + isDarkBackground = currentStory.isDarkBackground, + btnScanStateInProgress = homeState.value.btnScanStateInProgress, + onScanButtonClick = onScanButtonClick, + onShopButtonClick = onShopButtonClick, + ) + } } } } -@Suppress("MagicNumber") -private fun MutableState.duration(): Int = when (this.value) { - 1 -> 8000 - else -> 6000 -} - @Preview @Composable private fun StoriesScreenPreview() { diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt index f92adcf9d1..2774f0f683 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt @@ -4,12 +4,7 @@ import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember @@ -52,7 +47,7 @@ fun StoriesProgressBar( // .height() .padding(start = 9.dp, end = 9.dp, top = 16.dp), ) { - for (index in 1..steps) { + for (index in 0..steps) { Row( modifier = Modifier .height(2.dp) diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt index 618e432dec..9342420e6b 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt @@ -8,8 +8,38 @@ import org.rekotlin.StateType data class HomeState( val scanInProgress: Boolean = false, val btnScanState: IndeterminateProgressButton = IndeterminateProgressButton(ButtonState.ENABLED), + val stories: List = initDefaultStories(), ) : StateType { + val firstStory: Stories = stories[0] + val btnScanStateInProgress: Boolean get() = btnScanState.progressState == ProgressState.Loading + + fun stepOf(story: Stories): Int = stories.indexOf(story) + + companion object { + fun initDefaultStories(): List = listOf( + Stories.OneInchPromo, + Stories.TangemIntro, + Stories.RevolutionaryWallet, + Stories.UltraSecureBackup, + Stories.Currencies, + Stories.Web3, + Stories.WalletForEveryone, + ) + } +} + +sealed class Stories( + val isDarkBackground: Boolean, + val duration: Int, +) { + object OneInchPromo : Stories(true, duration = 8000) + object TangemIntro : Stories(true, duration = 8000) + object RevolutionaryWallet : Stories(true, duration = 6000) + object UltraSecureBackup : Stories(false, duration = 6000) + object Currencies : Stories(false, duration = 6000) + object Web3 : Stories(false, duration = 6000) + object WalletForEveryone : Stories(true, duration = 6000) } \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt new file mode 100644 index 0000000000..4d7c7ee283 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt @@ -0,0 +1,105 @@ +package com.tangem.feature.learn2earn.presentation.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.SecondaryButton +import com.tangem.core.ui.components.SpacerH16 +import com.tangem.core.ui.components.SpacerH32 +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemTypography +import com.tangem.feature.learn2earn.impl.R +import com.tangem.feature.learn2earn.presentation.ui.component.GradientCircle + +/** +[REDACTED_AUTHOR] + */ +@Suppress("ReusedModifierInstance") +@Composable +fun OneInchStoriesContent(onLearnClick: () -> Unit, modifier: Modifier = Modifier) { + Box(modifier = modifier.fillMaxSize()) { + ContentBackground( + modifier = modifier + .fillMaxSize() + .align(Alignment.Center), + ) + StoryDescription( + headerText = stringResource(id = R.string.story_learn_title), + bodyText = stringResource(id = R.string.story_learn_description), + ) + Image( + modifier = Modifier + .padding(bottom = TangemTheme.dimens.size68) + .align(Alignment.BottomCenter), + painter = painterResource(id = R.drawable.img_1inch_logo_401_378), + contentDescription = null, + ) + SecondaryButton( + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.size16) + .padding(bottom = TangemTheme.dimens.size84) + .fillMaxWidth() + .align(Alignment.BottomCenter), + text = stringResource(id = R.string.story_learn_learn), + onClick = onLearnClick, + ) + } +} + +@Suppress("MagicNumber") +@Composable +private fun ContentBackground(modifier: Modifier = Modifier) { + Box(modifier = modifier) { + GradientCircle( + size = 800.dp, + offsetX = (-220).dp, + offsetY = (-200).dp, + startColor = Color(0xCE164594), + endColor = Color(0x000B173D), + ) + GradientCircle( + size = 800.dp, + offsetX = 200.dp, + offsetY = 290.dp, + startColor = Color(0xFF3D0230), + endColor = Color(0x000B0E17), + ) + } +} + +@Composable +private fun StoryDescription(headerText: String, bodyText: String) { + Column( + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.size40) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top, + ) { + SpacerH32() + Text( + text = headerText, + textAlign = TextAlign.Center, + style = TangemTheme.typography.h1.copy( + fontWeight = FontWeight.Bold, + ), + color = TangemTheme.colors.text.primary2, + ) + SpacerH16() + Text( + text = bodyText, + textAlign = TextAlign.Center, + style = TangemTypography.subtitle1, + color = TangemTheme.colors.text.tertiary, + ) + } +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/component/Gradient.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/component/Gradient.kt new file mode 100644 index 0000000000..e54a15c863 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/component/Gradient.kt @@ -0,0 +1,38 @@ +package com.tangem.feature.learn2earn.presentation.ui.component + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp + +/** +[REDACTED_AUTHOR] + */ +@Composable +internal fun GradientCircle( + size: Dp, + offsetX: Dp, + offsetY: Dp, + startColor: Color, + endColor: Color, + radius: Dp = size / 2, +) { + Canvas( + modifier = Modifier + .size(size) + .offset(x = offsetX, y = offsetY), + onDraw = { + drawCircle( + radius = radius.toPx(), + brush = Brush.radialGradient( + radius = radius.toPx(), + colors = listOf(startColor, endColor), + ), + ) + }, + ) +} \ No newline at end of file From cd3d290eb1414798ef9b0845e9df7a02371fa75f Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 1 Jun 2023 23:35:59 +0300 Subject: [PATCH 05/54] Updated on 2026-08-14 --- .../presentation/ui/GetBonusAlert.kt | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/GetBonusAlert.kt diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/GetBonusAlert.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/GetBonusAlert.kt new file mode 100644 index 0000000000..bbff8f8fa8 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/GetBonusAlert.kt @@ -0,0 +1,106 @@ +package com.tangem.feature.learn2earn.presentation.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemTypography +import com.tangem.feature.learn2earn.impl.R +import com.tangem.feature.learn2earn.presentation.ui.component.GradientCircle + +/** +[REDACTED_AUTHOR] + */ +@Composable +fun GetBonusAlert(onClick: () -> Unit, modifier: Modifier = Modifier) { + val shape = TangemTheme.shapes.roundedCornersMedium + Box( + modifier = modifier + .height(TangemTheme.dimens.size96) + .background( + color = TangemTheme.colors.background.action, + shape = shape, + ), + ) { + ContentBackground(shape) + Row( + modifier = Modifier.fillMaxHeight(), + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + modifier = Modifier.padding(horizontal = TangemTheme.dimens.size16), + painter = painterResource(id = R.drawable.img_1inch_logo_42_40), + contentDescription = null, + ) + Column( + modifier = Modifier.padding(end = TangemTheme.dimens.size40), + ) { + Text( + text = stringResource(id = R.string.main_learn_title), + style = TangemTypography.body1, + color = TangemTheme.colors.text.primary2, + ) + Text( + text = stringResource(id = R.string.main_learn_subtitle), + style = TangemTypography.caption, + color = TangemTheme.colors.text.secondary, + ) + } + } + Image( + modifier = Modifier + .size(TangemTheme.dimens.size40) + .padding(end = TangemTheme.dimens.size16) + .align(Alignment.CenterEnd) + .clickable(onClick = onClick), + painter = painterResource(id = R.drawable.ic_chevron_right_24), + contentDescription = null, + colorFilter = ColorFilter.tint(Color.Gray), + ) + } +} + +@Suppress("MagicNumber") +@Composable +private fun ContentBackground(shape: Shape) { + Box( + modifier = Modifier + .clip(shape) + .fillMaxSize(), + ) { + GradientCircle( + size = 340.dp, + offsetX = (-103).dp, + offsetY = 16.dp, + startColor = Color(0xFF1D5DC7), + endColor = Color(0x000B173D), + ) + GradientCircle( + size = 268.dp, + offsetX = 90.dp, + offsetY = 0.dp, + startColor = Color(0xD8FF0CCA), + endColor = Color(0x000B0E17), + ) + } + Box( + modifier = Modifier + .background( + color = TangemTheme.colors.background.action.copy(alpha = 0.7f), + shape = shape, + ) + .fillMaxSize(), + ) +} \ No newline at end of file From f3afa5546910bcbad38910312b0b7aae73a986da Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 6 Jun 2023 17:11:37 +0300 Subject: [PATCH 06/54] Updated on 2026-08-14 --- .../tangem/tap/features/home/HomeFragment.kt | 11 +++-- .../features/home/compose/StoriesScreen.kt | 15 ++++--- features/learn2earn/api/build.gradle.kts | 3 +- .../api/src/main/AndroidManifest.xml | 2 - features/learn2earn/impl/build.gradle.kts | 1 + .../presentation/ui/GetBonusAlert.kt | 25 +++++++++++ .../presentation/ui/OneInchStoriesScreen.kt | 41 +++++++++++++++---- .../res/drawable/img_1inch_logo_401_378.xml | 0 .../res/drawable/img_1inch_logo_42_40.xml | 0 9 files changed, 72 insertions(+), 26 deletions(-) delete mode 100644 features/learn2earn/api/src/main/AndroidManifest.xml rename {core/ui => features/learn2earn/impl}/src/main/res/drawable/img_1inch_logo_401_378.xml (100%) rename {core/ui => features/learn2earn/impl}/src/main/res/drawable/img_1inch_logo_42_40.xml (100%) diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt index acf3408acf..bdb1d84900 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -12,8 +12,8 @@ import androidx.compose.ui.platform.ComposeView import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsControllerCompat import androidx.fragment.app.Fragment -import com.google.accompanist.appcompattheme.AppCompatTheme import com.tangem.core.analytics.Analytics +import com.tangem.core.ui.res.TangemTheme import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction @@ -37,11 +37,10 @@ class HomeFragment : Fragment(), StoreSubscriber { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return ComposeView(inflater.context).apply { setContent { - BackHandler { - requireActivity().finish() - } - - AppCompatTheme { + TangemTheme { + BackHandler { + requireActivity().finish() + } ScreenContent() } } diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt index 2d453259c4..af5df09c59 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt @@ -26,7 +26,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.tangem.core.ui.res.TangemTheme -import com.tangem.feature.learn2earn.presentation.ui.OneInchStoriesContent +import com.tangem.feature.learn2earn.presentation.ui.OneInchStoriesScreen import com.tangem.tap.features.home.compose.content.* import com.tangem.tap.features.home.compose.views.HomeButtons import com.tangem.tap.features.home.compose.views.StoriesProgressBar @@ -152,12 +152,7 @@ fun StoriesScreen( colorFilter = if (currentStory.isDarkBackground) null else ColorFilter.tint(Color.Black), ) when (currentStory) { - Stories.OneInchPromo -> { - // TODO: fixme - TangemTheme { - OneInchStoriesContent({}) - } - } + Stories.OneInchPromo -> OneInchStoriesScreen({}) Stories.TangemIntro -> FirstStoriesContent(isPaused, currentStory.duration) { hideContent.value = it } Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet(currentStory.duration) Stories.UltraSecureBackup -> StoriesUltraSecureBackup(isPaused, currentStory.duration) @@ -200,7 +195,11 @@ fun StoriesScreen( if (currentStory != Stories.OneInchPromo) { HomeButtons( modifier = Modifier - .padding(start = 16.dp, top = 0.dp, end = 16.dp, bottom = 37.dp) + .padding( + start = TangemTheme.dimens.size16, + end = TangemTheme.dimens.size16, + bottom = TangemTheme.dimens.size36, + ) .fillMaxWidth(), isDarkBackground = currentStory.isDarkBackground, btnScanStateInProgress = homeState.value.btnScanStateInProgress, diff --git a/features/learn2earn/api/build.gradle.kts b/features/learn2earn/api/build.gradle.kts index 1fbece85d5..7ff7fb7522 100644 --- a/features/learn2earn/api/build.gradle.kts +++ b/features/learn2earn/api/build.gradle.kts @@ -1,5 +1,4 @@ plugins { - alias(deps.plugins.android.library) - alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.jvm) id("configuration") } \ No newline at end of file diff --git a/features/learn2earn/api/src/main/AndroidManifest.xml b/features/learn2earn/api/src/main/AndroidManifest.xml deleted file mode 100644 index 4d3df466b3..0000000000 --- a/features/learn2earn/api/src/main/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/features/learn2earn/impl/build.gradle.kts b/features/learn2earn/impl/build.gradle.kts index f0071798aa..9e390b1f67 100644 --- a/features/learn2earn/impl/build.gradle.kts +++ b/features/learn2earn/impl/build.gradle.kts @@ -34,6 +34,7 @@ dependencies { implementation(project(":core:res")) /** Tangem libraries */ + // TODO: fixme: delete if later it doesn't needed // implementation(deps.tangem.card.core) // implementation(deps.tangem.card.android) { // exclude(module = "joda-time") diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/GetBonusAlert.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/GetBonusAlert.kt index bbff8f8fa8..0079c24f11 100644 --- a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/GetBonusAlert.kt +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/GetBonusAlert.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.Shape import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTypography @@ -103,4 +104,28 @@ private fun ContentBackground(shape: Shape) { ) .fillMaxSize(), ) +} + +@Preview +@Composable +private fun OneInchStoriesContentPreview_Light() { + TangemTheme( + isDark = false, + ) { + GetBonusAlert( + onClick = {}, + ) + } +} + +@Preview +@Composable +private fun OneInchStoriesContentPreview_Dark() { + TangemTheme( + isDark = true, + ) { + GetBonusAlert( + onClick = {}, + ) + } } \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt index 4d7c7ee283..ff3c3218b7 100644 --- a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign +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.SpacerH16 @@ -23,16 +24,19 @@ import com.tangem.feature.learn2earn.presentation.ui.component.GradientCircle /** [REDACTED_AUTHOR] */ -@Suppress("ReusedModifierInstance") +// TODO: fixme: make function as internal after adding feature interface @Composable -fun OneInchStoriesContent(onLearnClick: () -> Unit, modifier: Modifier = Modifier) { +fun OneInchStoriesScreen(onLearnClick: () -> Unit, modifier: Modifier = Modifier) { Box(modifier = modifier.fillMaxSize()) { ContentBackground( - modifier = modifier + modifier = Modifier .fillMaxSize() .align(Alignment.Center), ) StoryDescription( + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.size40) + .fillMaxSize(), headerText = stringResource(id = R.string.story_learn_title), bodyText = stringResource(id = R.string.story_learn_description), ) @@ -77,13 +81,10 @@ private fun ContentBackground(modifier: Modifier = Modifier) { } @Composable -private fun StoryDescription(headerText: String, bodyText: String) { +private fun StoryDescription(headerText: String, bodyText: String, modifier: Modifier = Modifier) { Column( - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.size40) - .fillMaxSize(), + modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Top, ) { SpacerH32() Text( @@ -102,4 +103,28 @@ private fun StoryDescription(headerText: String, bodyText: String) { color = TangemTheme.colors.text.tertiary, ) } +} + +@Preview +@Composable +private fun OneInchStoriesContentPreview_Light() { + TangemTheme( + isDark = false, + ) { + OneInchStoriesScreen( + onLearnClick = {}, + ) + } +} + +@Preview +@Composable +private fun OneInchStoriesContentPreview_Dark() { + TangemTheme( + isDark = true, + ) { + OneInchStoriesScreen( + onLearnClick = {}, + ) + } } \ No newline at end of file diff --git a/core/ui/src/main/res/drawable/img_1inch_logo_401_378.xml b/features/learn2earn/impl/src/main/res/drawable/img_1inch_logo_401_378.xml similarity index 100% rename from core/ui/src/main/res/drawable/img_1inch_logo_401_378.xml rename to features/learn2earn/impl/src/main/res/drawable/img_1inch_logo_401_378.xml diff --git a/core/ui/src/main/res/drawable/img_1inch_logo_42_40.xml b/features/learn2earn/impl/src/main/res/drawable/img_1inch_logo_42_40.xml similarity index 100% rename from core/ui/src/main/res/drawable/img_1inch_logo_42_40.xml rename to features/learn2earn/impl/src/main/res/drawable/img_1inch_logo_42_40.xml From 4affe1293d1b05631e94ade9ce8d0a8c707cd1a3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 6 Jun 2023 16:07:14 +0300 Subject: [PATCH 07/54] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 46 +++++-- .../java/com/tangem/tap/TapApplication.kt | 1 - .../com/tangem/tap/common/IntentHandler.kt | 127 ------------------ .../features/intentHandler/IntentHandler.kt | 10 ++ .../intentHandler/MainIntentHandler.kt | 29 ++++ .../handlers/BackgroundScanIntentHandler.kt | 52 +++++++ .../handlers/BuyCurrencyIntentHandler.kt | 30 +++++ .../handlers/SellCurrencyIntentHandler.kt | 43 ++++++ .../WalletConnectLinkIntentHandler.kt | 37 +++++ .../features/welcome/redux/WelcomeAction.kt | 2 +- .../welcome/redux/WelcomeMiddleware.kt | 37 ++--- .../features/welcome/redux/WelcomeReducer.kt | 2 +- 12 files changed, 254 insertions(+), 162 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/IntentHandler.kt create mode 100644 app/src/main/java/com/tangem/tap/features/intentHandler/IntentHandler.kt create mode 100644 app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt create mode 100644 app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BackgroundScanIntentHandler.kt create mode 100644 app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BuyCurrencyIntentHandler.kt create mode 100644 app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt create mode 100644 app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index e108d35af3..18dd61e8ea 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -32,6 +32,11 @@ import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation +import com.tangem.tap.features.intentHandler.MainIntentHandler +import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler +import com.tangem.tap.features.intentHandler.handlers.BuyCurrencyIntentHandler +import com.tangem.tap.features.intentHandler.handlers.SellCurrencyIntentHandler +import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction import com.tangem.tap.features.shop.redux.ShopAction @@ -45,6 +50,7 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.launch import java.lang.ref.WeakReference import javax.inject.Inject import kotlin.coroutines.CoroutineContext @@ -95,6 +101,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var walletConnectInteractor: WalletConnectInteractor + // TODO: fixme: inject through DI + private val intentHandler: MainIntentHandler = MainIntentHandler() + private var snackbar: Snackbar? = null private val dialogManager = DialogManager() private val binding: ActivityMainBinding by viewBinding(ActivityMainBinding::bind) @@ -117,6 +126,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac lockUserWalletsTimer = LockUserWalletsTimer(owner = this) initUserWalletsListManager() + initIntentHandlers() store.dispatch( ShopAction.CheckIfGooglePayAvailable( @@ -133,6 +143,14 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac ) } + private fun initIntentHandlers() { + val hasSavedWalletsProvider = { store.state.globalState.userWalletsListManager?.hasUserWallets == true } + intentHandler.addHandler(BackgroundScanIntentHandler(hasSavedWalletsProvider)) + intentHandler.addHandler(WalletConnectLinkIntentHandler()) + intentHandler.addHandler(BuyCurrencyIntentHandler()) + intentHandler.addHandler(SellCurrencyIntentHandler()) + } + private fun initUserWalletsListManager() { val manager = if (preferencesStorage.shouldSaveUserWallets) { UserWalletsListManager.provideBiometricImplementation( @@ -164,12 +182,14 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac super.onResume() notificationsHandler = NotificationsHandler(binding.fragmentContainer) - navigateToInitialScreenIfNeeded(intent) + navigateToInitialScreenIfNeededOnResume(intent) } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) - intentHandler.handleIntent(intent, userWalletsListManager.hasUserWallets) + scope.launch { + intentHandler.handleIntent(intent) + } } override fun onStart() { @@ -185,6 +205,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac override fun onDestroy() { store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this))) + intentHandler.removeAll() super.onDestroy() } @@ -235,29 +256,38 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac lockUserWalletsTimer?.restart() } - private fun navigateToInitialScreenIfNeeded(intent: Intent?) { + private fun navigateToInitialScreenIfNeededOnResume(intentWhichStartedActivity: Intent?) { val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0 val isNotScannedBefore = store.state.globalState.scanResponse == null val isOnboardingServiceNotActive = store.state.globalState.onboardingState.onboardingStarted val isShopNotOpened = store.state.shopState.total != null when { !backStackIsEmpty && isNotScannedBefore && isOnboardingServiceNotActive && isShopNotOpened -> { - navigateToInitialScreen(intent) + navigateToInitialScreenOnResume(intentWhichStartedActivity) } backStackIsEmpty -> { - navigateToInitialScreen(intent) + navigateToInitialScreenOnResume(intentWhichStartedActivity) } else -> Unit } } - private fun navigateToInitialScreen(intent: Intent?) { + private fun navigateToInitialScreenOnResume(intentWhichStartedActivity: Intent?) { if (store.state.globalState.userWalletsListManager?.hasUserWallets == true) { store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Welcome)) - store.dispatchOnMain(WelcomeAction.HandleIntentIfNeeded(intent)) + store.dispatchOnMain(WelcomeAction.SetInitialIntent(intentWhichStartedActivity)) + scope.launch { + val handler = BackgroundScanIntentHandler(hasSavedUserWalletsProvider = { true }) + val intentWasHandled = handler.handleIntent(intentWhichStartedActivity) + if (!intentWasHandled) { + store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics) + } + } } else { store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Home)) - intentHandler.handleIntent(intent, hasSavedUserWallets = false) + scope.launch { + intentHandler.handleIntent(intentWhichStartedActivity) + } } store.dispatch(BackupAction.CheckForUnfinishedBackup) } diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 5de365ee79..496b4e742b 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -102,7 +102,6 @@ val walletCurrenciesManager by lazy { val totalFiatBalanceCalculator by lazy { TotalFiatBalanceCalculator.provideDefaultImplementation() } -val intentHandler by lazy { IntentHandler() } @HiltAndroidApp class TapApplication : Application(), ImageLoaderFactory { diff --git a/app/src/main/java/com/tangem/tap/common/IntentHandler.kt b/app/src/main/java/com/tangem/tap/common/IntentHandler.kt deleted file mode 100644 index 4d50c59679..0000000000 --- a/app/src/main/java/com/tangem/tap/common/IntentHandler.kt +++ /dev/null @@ -1,127 +0,0 @@ -package com.tangem.tap.common - -import android.content.Intent -import android.net.Uri -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Build -import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Token -import com.tangem.tap.common.extensions.removePrefixOrNull -import com.tangem.tap.domain.walletconnect.WalletConnectManager -import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction -import com.tangem.tap.features.home.redux.HomeAction -import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.features.welcome.redux.WelcomeAction -import com.tangem.tap.network.exchangeServices.ExchangeUrlBuilder -import com.tangem.tap.scope -import com.tangem.tap.store -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import timber.log.Timber - -class IntentHandler { - - private val nfcActions = arrayOf( - NfcAdapter.ACTION_NDEF_DISCOVERED, - NfcAdapter.ACTION_TECH_DISCOVERED, - NfcAdapter.ACTION_TAG_DISCOVERED, - ) - - fun handleIntent(intent: Intent?, hasSavedUserWallets: Boolean) { - handleBackgroundScan(intent, hasSavedUserWallets) - handleWalletConnectLink(intent) - handleBuyCurrencyCallback(intent) - handleSellCurrencyCallback(intent) - } - - fun handleWalletConnectLink(intent: Intent?) { - val wcUri = when (intent?.scheme) { - WalletConnectManager.WC_SCHEME -> { - intent.data?.toString() - } - TANGEM_SCHEME -> { - intent.data?.toString()?.removePrefixOrNull(TANGEM_WC_PREFIX) - } - else -> { - null - } - } - if (wcUri != null) { - store.dispatch(WalletConnectAction.HandleDeepLink(wcUri)) - } - } - - fun handleBackgroundScan(intent: Intent?, hasSavedUserWallets: Boolean): Boolean { - if (intent == null || intent.action !in nfcActions) return false - - val tag: Tag? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - intent.getParcelableExtra(NfcAdapter.EXTRA_TAG, Tag::class.java) - } else { - @Suppress("DEPRECATION") - intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) - } - if (tag == null) return false - - intent.action = null - if (hasSavedUserWallets) { - // TODO: Remove delay after [REDACTED_JIRA] - scope.launch { - delay(timeMillis = 200) - store.dispatch(WelcomeAction.ProceedWithCard) - } - } else { - store.dispatch(HomeAction.ReadCard()) - } - - return true - } - - private fun handleBuyCurrencyCallback(intent: Intent?) { - val data = intent?.data ?: return - - val successUri = Uri.parse(ExchangeUrlBuilder.SUCCESS_URL) - if (data.host == successUri.host && data.authority == successUri.authority) { - val currency = store.state.walletState.selectedCurrency ?: return - val currencyType = AnalyticsParam.CurrencyType.Currency(currency) - Analytics.send(Token.Bought(currencyType)) - } - } - - fun handleSellCurrencyCallback(intent: Intent?) { - try { - val transactionID = - intent?.data?.getQueryParameter(TRANSACTION_ID_PARAM) ?: return - val currency = - intent.data?.getQueryParameter(CURRENCY_CODE_PARAM) ?: return - val amount = - intent.data?.getQueryParameter(CURRENCY_AMOUNT_PARAM) ?: return - val destinationAddress = - intent.data?.getQueryParameter(DEPOSIT_WALLET_ADDRESS_PARAM) - ?: return - - Timber.d("MoonPay Sell: $amount $currency to $destinationAddress") - - store.dispatch( - WalletAction.TradeCryptoAction.SendCrypto( - currencyId = currency, - amount = amount, - destinationAddress = destinationAddress, - transactionId = transactionID, - ), - ) - } catch (exception: Exception) { - Timber.d("Not MoonPay URL") - } - } - - companion object { - private const val TRANSACTION_ID_PARAM = "transactionId" - private const val CURRENCY_CODE_PARAM = "baseCurrencyCode" - private const val CURRENCY_AMOUNT_PARAM = "baseCurrencyAmount" - private const val DEPOSIT_WALLET_ADDRESS_PARAM = "depositWalletAddress" - private const val TANGEM_SCHEME = "tangem" - private const val TANGEM_WC_PREFIX = "tangem://wc?uri=" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/IntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/IntentHandler.kt new file mode 100644 index 0000000000..ba008d4e5a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/IntentHandler.kt @@ -0,0 +1,10 @@ +package com.tangem.tap.features.intentHandler + +import android.content.Intent + +/** +[REDACTED_AUTHOR] + */ +interface IntentHandler { + suspend fun handleIntent(intent: Intent?): Boolean +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt new file mode 100644 index 0000000000..7a952f7e63 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt @@ -0,0 +1,29 @@ +package com.tangem.tap.features.intentHandler + +import android.content.Intent + +/** +[REDACTED_AUTHOR] + */ +class MainIntentHandler { + + private val intentHandlers = mutableListOf() + + fun addHandler(handler: IntentHandler) { + intentHandlers.add(handler) + } + + fun removeIntentHandler(handler: IntentHandler) { + intentHandlers.remove(handler) + } + + fun removeAll() { + intentHandlers.clear() + } + + suspend fun handleIntent(intent: Intent?) { + intentHandlers.toList().forEach { + it.handleIntent(intent) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BackgroundScanIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BackgroundScanIntentHandler.kt new file mode 100644 index 0000000000..18a51c222f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BackgroundScanIntentHandler.kt @@ -0,0 +1,52 @@ +package com.tangem.tap.features.intentHandler.handlers + +import android.content.Intent +import android.nfc.NfcAdapter +import android.nfc.Tag +import android.os.Build +import com.tangem.tap.features.home.redux.HomeAction +import com.tangem.tap.features.intentHandler.IntentHandler +import com.tangem.tap.features.welcome.redux.WelcomeAction +import com.tangem.tap.scope +import com.tangem.tap.store +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +/** +[REDACTED_AUTHOR] + */ +class BackgroundScanIntentHandler( + private val hasSavedUserWalletsProvider: () -> Boolean, +) : IntentHandler { + + private val nfcActions = arrayOf( + NfcAdapter.ACTION_NDEF_DISCOVERED, + NfcAdapter.ACTION_TECH_DISCOVERED, + NfcAdapter.ACTION_TAG_DISCOVERED, + ) + + override suspend fun handleIntent(intent: Intent?): Boolean { + if (intent == null || intent.action !in nfcActions) return false + + val tag: Tag? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra(NfcAdapter.EXTRA_TAG, Tag::class.java) + } else { + @Suppress("DEPRECATION") + intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) + } + if (tag == null) return false + + intent.action = null + if (hasSavedUserWalletsProvider.invoke()) { + // TODO: Remove delay after [REDACTED_JIRA] + scope.launch { + delay(timeMillis = 200) + store.dispatch(WelcomeAction.ProceedWithCard) + } + } else { + store.dispatch(HomeAction.ReadCard()) + } + + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BuyCurrencyIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BuyCurrencyIntentHandler.kt new file mode 100644 index 0000000000..39dda7cd24 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/BuyCurrencyIntentHandler.kt @@ -0,0 +1,30 @@ +package com.tangem.tap.features.intentHandler.handlers + +import android.content.Intent +import android.net.Uri +import com.tangem.core.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Token +import com.tangem.tap.features.intentHandler.IntentHandler +import com.tangem.tap.network.exchangeServices.ExchangeUrlBuilder +import com.tangem.tap.store + +/** +[REDACTED_AUTHOR] + */ +class BuyCurrencyIntentHandler : IntentHandler { + + override suspend fun handleIntent(intent: Intent?): Boolean { + val data = intent?.data ?: return false + val currency = store.state.walletState.selectedCurrency ?: return false + + val successUri = Uri.parse(ExchangeUrlBuilder.SUCCESS_URL) + return if (data.host == successUri.host && data.authority == successUri.authority) { + val currencyType = AnalyticsParam.CurrencyType.Currency(currency) + Analytics.send(Token.Bought(currencyType)) + true + } else { + false + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt new file mode 100644 index 0000000000..35d0b31763 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt @@ -0,0 +1,43 @@ +package com.tangem.tap.features.intentHandler.handlers + +import android.content.Intent +import com.tangem.tap.features.intentHandler.IntentHandler +import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.store +import timber.log.Timber + +/** +[REDACTED_AUTHOR] + */ +class SellCurrencyIntentHandler : IntentHandler { + override suspend fun handleIntent(intent: Intent?): Boolean { + return try { + val intentData = intent?.data ?: return false + val transactionID = intentData.getQueryParameter(TRANSACTION_ID_PARAM) ?: return false + val currency = intentData.getQueryParameter(CURRENCY_CODE_PARAM) ?: return false + val amount = intentData.getQueryParameter(CURRENCY_AMOUNT_PARAM) ?: return false + val destinationAddress = intentData.getQueryParameter(DEPOSIT_WALLET_ADDRESS_PARAM) ?: return false + + Timber.d("MoonPay Sell: $amount $currency to $destinationAddress") + store.dispatch( + WalletAction.TradeCryptoAction.SendCrypto( + currencyId = currency, + amount = amount, + destinationAddress = destinationAddress, + transactionId = transactionID, + ), + ) + true + } catch (exception: Exception) { + Timber.d("Not MoonPay URL") + false + } + } + + companion object { + private const val TRANSACTION_ID_PARAM = "transactionId" + private const val CURRENCY_CODE_PARAM = "baseCurrencyCode" + private const val CURRENCY_AMOUNT_PARAM = "baseCurrencyAmount" + private const val DEPOSIT_WALLET_ADDRESS_PARAM = "depositWalletAddress" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt new file mode 100644 index 0000000000..1154f5ca14 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt @@ -0,0 +1,37 @@ +package com.tangem.tap.features.intentHandler.handlers + +import android.content.Intent +import com.tangem.tap.common.extensions.removePrefixOrNull +import com.tangem.tap.domain.walletconnect.WalletConnectManager +import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction +import com.tangem.tap.features.intentHandler.IntentHandler +import com.tangem.tap.store + +/** +[REDACTED_AUTHOR] + */ +class WalletConnectLinkIntentHandler : IntentHandler { + + override suspend fun handleIntent(intent: Intent?): Boolean { + val intentData = intent?.data ?: return false + val scheme = intent.scheme ?: return false + + val wcUri = when (scheme) { + WalletConnectManager.WC_SCHEME -> intentData.toString() + TANGEM_SCHEME -> intentData.toString().removePrefixOrNull(TANGEM_WC_PREFIX) + else -> null + } + + return if (wcUri == null) { + false + } else { + store.dispatch(WalletConnectAction.HandleDeepLink(wcUri)) + true + } + } + + companion object { + private const val TANGEM_SCHEME = "tangem" + private const val TANGEM_WC_PREFIX = "tangem://wc?uri=" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt index a0484fc798..e7ce3e5957 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt @@ -15,7 +15,7 @@ internal sealed interface WelcomeAction : Action { data class Error(val error: TangemError) : WelcomeAction } - data class HandleIntentIfNeeded(val intent: Intent?) : WelcomeAction + data class SetInitialIntent(val intent: Intent?) : WelcomeAction object CloseError : WelcomeAction diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index 9955bf6d6d..7f22650f5e 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -1,11 +1,8 @@ package com.tangem.tap.features.welcome.redux import android.content.Intent +import com.tangem.common.* import com.tangem.common.core.TangemSdkError -import com.tangem.common.doOnFailure -import com.tangem.common.doOnResult -import com.tangem.common.doOnSuccess -import com.tangem.common.flatMap import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -19,6 +16,8 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.unlockIfLockable +import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError import com.tangem.tap.features.signin.redux.SignInAction import kotlinx.coroutines.launch import org.rekotlin.Middleware @@ -39,24 +38,10 @@ internal class WelcomeMiddleware { private fun handleAction(action: WelcomeAction, state: WelcomeState) { when (action) { - is WelcomeAction.ProceedWithBiometrics -> { - proceedWithBiometrics(state) - } - is WelcomeAction.ProceedWithCard -> { - proceedWithCard(state) - } - is WelcomeAction.HandleIntentIfNeeded -> { - handleInitialIntent(action.intent) - } - is WelcomeAction.ClearUserWallets -> { - disableUserWalletsSaving() - } - is WelcomeAction.ProceedWithBiometrics.Error, - is WelcomeAction.ProceedWithCard.Error, - is WelcomeAction.ProceedWithBiometrics.Success, - is WelcomeAction.ProceedWithCard.Success, - is WelcomeAction.CloseError, - -> Unit + is WelcomeAction.ProceedWithBiometrics -> proceedWithBiometrics(state) + is WelcomeAction.ProceedWithCard -> proceedWithCard(state) + is WelcomeAction.ClearUserWallets -> disableUserWalletsSaving() + else -> Unit } } @@ -85,7 +70,9 @@ internal class WelcomeMiddleware { store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Success) store.onUserWalletSelected(userWallet = selectedUserWallet) - intentHandler.handleWalletConnectLink(state.intent) + state.intent?.let { + WalletConnectLinkIntentHandler().handleIntent(it) + } } } @@ -104,7 +91,9 @@ internal class WelcomeMiddleware { store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success) store.onUserWalletSelected(userWallet = userWallet) - intentHandler.handleWalletConnectLink(state.intent) + state.intent?.let { + WalletConnectLinkIntentHandler().handleIntent(it) + } } } } diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt index 5f14d1744d..11bfb0ea4a 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeReducer.kt @@ -14,7 +14,7 @@ internal object WelcomeReducer { private fun internalReduce(action: WelcomeAction, state: WelcomeState): WelcomeState { return when (action) { - is WelcomeAction.HandleIntentIfNeeded -> state.copy(intent = action.intent) + is WelcomeAction.SetInitialIntent -> state.copy(intent = action.intent) is WelcomeAction.ProceedWithBiometrics -> state.copy(isUnlockWithBiometricsInProgress = true) is WelcomeAction.ProceedWithCard -> state.copy(isUnlockWithCardInProgress = true) is WelcomeAction.ProceedWithBiometrics.Error -> state.copy( From e73e91e07a764e0a2967e1e31339588e30510eac Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 7 Jun 2023 07:02:28 +0300 Subject: [PATCH 08/54] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/MainActivity.kt | 18 +++++++++--------- ...MainIntentHandler.kt => IntentProcessor.kt} | 8 +++++--- .../handlers/SellCurrencyIntentHandler.kt | 3 ++- .../handlers/WalletConnectLinkIntentHandler.kt | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) rename app/src/main/java/com/tangem/tap/features/intentHandler/{MainIntentHandler.kt => IntentProcessor.kt} (62%) diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 18dd61e8ea..61a591e5c7 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -32,7 +32,7 @@ import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation -import com.tangem.tap.features.intentHandler.MainIntentHandler +import com.tangem.tap.features.intentHandler.IntentProcessor import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler import com.tangem.tap.features.intentHandler.handlers.BuyCurrencyIntentHandler import com.tangem.tap.features.intentHandler.handlers.SellCurrencyIntentHandler @@ -102,7 +102,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac lateinit var walletConnectInteractor: WalletConnectInteractor // TODO: fixme: inject through DI - private val intentHandler: MainIntentHandler = MainIntentHandler() + private val intentProcessor: IntentProcessor = IntentProcessor() private var snackbar: Snackbar? = null private val dialogManager = DialogManager() @@ -145,10 +145,10 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac private fun initIntentHandlers() { val hasSavedWalletsProvider = { store.state.globalState.userWalletsListManager?.hasUserWallets == true } - intentHandler.addHandler(BackgroundScanIntentHandler(hasSavedWalletsProvider)) - intentHandler.addHandler(WalletConnectLinkIntentHandler()) - intentHandler.addHandler(BuyCurrencyIntentHandler()) - intentHandler.addHandler(SellCurrencyIntentHandler()) + intentProcessor.addHandler(BackgroundScanIntentHandler(hasSavedWalletsProvider)) + intentProcessor.addHandler(WalletConnectLinkIntentHandler()) + intentProcessor.addHandler(BuyCurrencyIntentHandler()) + intentProcessor.addHandler(SellCurrencyIntentHandler()) } private fun initUserWalletsListManager() { @@ -188,7 +188,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) scope.launch { - intentHandler.handleIntent(intent) + intentProcessor.handleIntent(intent) } } @@ -205,7 +205,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac override fun onDestroy() { store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this))) - intentHandler.removeAll() + intentProcessor.removeAll() super.onDestroy() } @@ -286,7 +286,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac } else { store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Home)) scope.launch { - intentHandler.handleIntent(intentWhichStartedActivity) + intentProcessor.handleIntent(intentWhichStartedActivity) } } store.dispatch(BackupAction.CheckForUnfinishedBackup) diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/IntentProcessor.kt similarity index 62% rename from app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt rename to app/src/main/java/com/tangem/tap/features/intentHandler/IntentProcessor.kt index 7a952f7e63..47cf6a31fd 100644 --- a/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/IntentProcessor.kt @@ -1,13 +1,15 @@ package com.tangem.tap.features.intentHandler import android.content.Intent +import java.util.concurrent.CopyOnWriteArrayList /** [REDACTED_AUTHOR] */ -class MainIntentHandler { +// TODO: fixme: close it with the combined interfaces IntentHandler and IntentHandlerHolder +class IntentProcessor { - private val intentHandlers = mutableListOf() + private val intentHandlers = CopyOnWriteArrayList() fun addHandler(handler: IntentHandler) { intentHandlers.add(handler) @@ -22,7 +24,7 @@ class MainIntentHandler { } suspend fun handleIntent(intent: Intent?) { - intentHandlers.toList().forEach { + intentHandlers.forEach { it.handleIntent(intent) } } diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt index 35d0b31763..3fc6c318d6 100644 --- a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt @@ -10,6 +10,7 @@ import timber.log.Timber [REDACTED_AUTHOR] */ class SellCurrencyIntentHandler : IntentHandler { + override suspend fun handleIntent(intent: Intent?): Boolean { return try { val intentData = intent?.data ?: return false @@ -34,7 +35,7 @@ class SellCurrencyIntentHandler : IntentHandler { } } - companion object { + private companion object { private const val TRANSACTION_ID_PARAM = "transactionId" private const val CURRENCY_CODE_PARAM = "baseCurrencyCode" private const val CURRENCY_AMOUNT_PARAM = "baseCurrencyAmount" diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt index 1154f5ca14..e61d0b74d7 100644 --- a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/WalletConnectLinkIntentHandler.kt @@ -30,7 +30,7 @@ class WalletConnectLinkIntentHandler : IntentHandler { } } - companion object { + private companion object { private const val TANGEM_SCHEME = "tangem" private const val TANGEM_WC_PREFIX = "tangem://wc?uri=" } From c0bc4ddf523d5080d85c794992a13da889c54186 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Jun 2023 09:29:22 +0300 Subject: [PATCH 09/54] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/MainActivity.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 61a591e5c7..4b406eaccd 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -32,12 +32,12 @@ import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation +import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor import com.tangem.tap.features.intentHandler.IntentProcessor import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler import com.tangem.tap.features.intentHandler.handlers.BuyCurrencyIntentHandler import com.tangem.tap.features.intentHandler.handlers.SellCurrencyIntentHandler import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler -import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction import com.tangem.tap.features.shop.redux.ShopAction import com.tangem.tap.features.welcome.redux.WelcomeAction @@ -278,8 +278,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac store.dispatchOnMain(WelcomeAction.SetInitialIntent(intentWhichStartedActivity)) scope.launch { val handler = BackgroundScanIntentHandler(hasSavedUserWalletsProvider = { true }) - val intentWasHandled = handler.handleIntent(intentWhichStartedActivity) - if (!intentWasHandled) { + val isBackgroundScanNotHandled = handler.handleIntent(intentWhichStartedActivity) + val hasNotIncompletedBackup = !backupService.hasIncompletedBackup + if (isBackgroundScanNotHandled && hasNotIncompletedBackup) { store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics) } } From 35ea0954826a2b8dc7cf0e2082e32cb9e508a53e Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 6 Jun 2023 16:07:14 +0300 Subject: [PATCH 10/54] Updated on 2026-08-14 --- .../intentHandler/MainIntentHandler.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt new file mode 100644 index 0000000000..7a952f7e63 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt @@ -0,0 +1,29 @@ +package com.tangem.tap.features.intentHandler + +import android.content.Intent + +/** +[REDACTED_AUTHOR] + */ +class MainIntentHandler { + + private val intentHandlers = mutableListOf() + + fun addHandler(handler: IntentHandler) { + intentHandlers.add(handler) + } + + fun removeIntentHandler(handler: IntentHandler) { + intentHandlers.remove(handler) + } + + fun removeAll() { + intentHandlers.clear() + } + + suspend fun handleIntent(intent: Intent?) { + intentHandlers.toList().forEach { + it.handleIntent(intent) + } + } +} \ No newline at end of file From e16fe695751b883621a607b8ff5c5b2cf079447b Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 7 Jun 2023 07:02:28 +0300 Subject: [PATCH 11/54] Updated on 2026-08-14 --- .../intentHandler/MainIntentHandler.kt | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt deleted file mode 100644 index 7a952f7e63..0000000000 --- a/app/src/main/java/com/tangem/tap/features/intentHandler/MainIntentHandler.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.tangem.tap.features.intentHandler - -import android.content.Intent - -/** -[REDACTED_AUTHOR] - */ -class MainIntentHandler { - - private val intentHandlers = mutableListOf() - - fun addHandler(handler: IntentHandler) { - intentHandlers.add(handler) - } - - fun removeIntentHandler(handler: IntentHandler) { - intentHandlers.remove(handler) - } - - fun removeAll() { - intentHandlers.clear() - } - - suspend fun handleIntent(intent: Intent?) { - intentHandlers.toList().forEach { - it.handleIntent(intent) - } - } -} \ No newline at end of file From 353c7a2397fdb4dd8a06e4033563078fe349bb16 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 08:47:01 +0300 Subject: [PATCH 12/54] Updated on 2026-08-14 --- .../network/auth/TangemBasicAuthProvider.kt | 7 ++++ .../tangem/tap/network/auth/di/AuthModule.kt | 8 ++++ .../datasource/api/promotion/PromotionApi.kt | 38 +++++++++++++++++ .../models/AbstractPromotionResponse.kt | 20 +++++++++ .../api/promotion/models/AwardRequestBody.kt | 11 +++++ .../api/promotion/models/AwardResponse.kt | 11 +++++ .../promotion/models/CodeAwardRequestBody.kt | 12 ++++++ .../api/promotion/models/CodeAwardResponse.kt | 11 +++++ .../models/CodeValidateRequestBody.kt | 11 +++++ .../promotion/models/CodeValidateResponse.kt | 11 +++++ .../promotion/models/PromotionInfoResponse.kt | 41 +++++++++++++++++++ .../promotion/models/ValidateRequestBody.kt | 11 +++++ .../api/promotion/models/ValidateResponse.kt | 11 +++++ .../datasource/config/ConfigManagerImpl.kt | 8 +--- .../tangem/datasource/config/models/Config.kt | 1 + .../datasource/config/models/JsonModels.kt | 1 + .../com/tangem/datasource/di/NetworkModule.kt | 33 ++++++++++++++- .../tangem/datasource/di/PromotionOneInch.kt | 8 ++++ .../com/tangem/lib/auth/BasicAuthProvider.kt | 9 ++++ 19 files changed, 256 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/network/auth/TangemBasicAuthProvider.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/PromotionApi.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AbstractPromotionResponse.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardRequestBody.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardResponse.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardRequestBody.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardResponse.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateRequestBody.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateResponse.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromotionInfoResponse.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateRequestBody.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateResponse.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/di/PromotionOneInch.kt create mode 100644 libs/auth/src/main/java/com/tangem/lib/auth/BasicAuthProvider.kt diff --git a/app/src/main/java/com/tangem/tap/network/auth/TangemBasicAuthProvider.kt b/app/src/main/java/com/tangem/tap/network/auth/TangemBasicAuthProvider.kt new file mode 100644 index 0000000000..0db94f45ab --- /dev/null +++ b/app/src/main/java/com/tangem/tap/network/auth/TangemBasicAuthProvider.kt @@ -0,0 +1,7 @@ +package com.tangem.tap.network.auth + +import com.tangem.lib.auth.BasicAuthProvider + +class TangemBasicAuthProvider(private val credentials: String?) : BasicAuthProvider { + override fun getCredentials(): String? = credentials +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt index 6e9eabd1f1..ebd04d5b97 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt @@ -1,7 +1,9 @@ package com.tangem.tap.network.auth.di +import com.tangem.datasource.config.ConfigManager import com.tangem.lib.auth.AuthProvider import com.tangem.tap.network.auth.AuthProviderImpl +import com.tangem.tap.network.auth.TangemBasicAuthProvider import com.tangem.tap.proxy.AppStateHolder import dagger.Module import dagger.Provides @@ -18,4 +20,10 @@ class AuthModule { fun provideAuthProvider(appStateHolder: AppStateHolder): AuthProvider { return AuthProviderImpl(appStateHolder) } + + @Provides + @Singleton + fun provideTangemBasicAuthProvider(configManager: ConfigManager): com.tangem.lib.auth.BasicAuthProvider { + return TangemBasicAuthProvider(configManager.config.tangemComAuthorization) + } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/PromotionApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/PromotionApi.kt new file mode 100644 index 0000000000..4c6dab75bc --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/PromotionApi.kt @@ -0,0 +1,38 @@ +package com.tangem.datasource.api.promotion + +import com.tangem.datasource.api.promotion.models.* +import retrofit2.http.* + +/** +[REDACTED_AUTHOR] + * Api details + * https://www.notion.so/tangem/Promotion-Program-API-0907159c3fdb4975aac761be632f44da + */ +interface PromotionApi { + + + @Headers("Cache-Control: max-age=$CACHE_CONTROL_SECONDS") + @GET("promotion") + suspend fun getPromotionInfo(@Query("programName") name: String): PromotionInfoResponse + + + @POST("promotion/code/validate") + suspend fun codeValidate(@Body request: CodeValidateRequestBody): CodeValidateResponse + + + @POST("promotion/code/award") + suspend fun codeAward(@Body request: CodeAwardRequestBody): CodeAwardResponse + + + @POST("promotion/validate") + suspend fun validate(@Body request: ValidateRequestBody): ValidateResponse + + + @GET("promotion/award") + suspend fun award(@Body request: AwardRequestBody): AwardResponse + + companion object { + const val ONE_INCH_TIMEOUT_MS = 5000L + const val CACHE_CONTROL_SECONDS = 3600 + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AbstractPromotionResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AbstractPromotionResponse.kt new file mode 100644 index 0000000000..7cf6126c2c --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AbstractPromotionResponse.kt @@ -0,0 +1,20 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +abstract class AbstractPromotionResponse { + + abstract val error: Error? + + fun isError(): Boolean = error != null + + data class Error( + @Json(name = "code") val code: Int, + @Json(name = "description") val description: String, + ) { + companion object + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardRequestBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardRequestBody.kt new file mode 100644 index 0000000000..4ce66c7d76 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardRequestBody.kt @@ -0,0 +1,11 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class AwardRequestBody( + @Json(name = "walletId") val walletId: String, + @Json(name = "programName") val programName: String, +) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardResponse.kt new file mode 100644 index 0000000000..c43c59fa45 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/AwardResponse.kt @@ -0,0 +1,11 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class AwardResponse( + @Json(name = "status") val status: Boolean?, + @Json(name = "error") override val error: Error? = null, +) : AbstractPromotionResponse() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardRequestBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardRequestBody.kt new file mode 100644 index 0000000000..51e8626d4b --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardRequestBody.kt @@ -0,0 +1,12 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class CodeAwardRequestBody( + @Json(name = "walletId") val walletId: String, + @Json(name = "address") val address: String, + @Json(name = "code") val code: String?, +) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardResponse.kt new file mode 100644 index 0000000000..33d9313c42 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeAwardResponse.kt @@ -0,0 +1,11 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class CodeAwardResponse( + @Json(name = "status") val status: Boolean?, + @Json(name = "error") override val error: Error? = null, +) : AbstractPromotionResponse() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateRequestBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateRequestBody.kt new file mode 100644 index 0000000000..769ecdad26 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateRequestBody.kt @@ -0,0 +1,11 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class CodeValidateRequestBody( + @Json(name = "walletId") val walletId: String, + @Json(name = "code") val code: String?, +) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateResponse.kt new file mode 100644 index 0000000000..e6e87e0ff3 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/CodeValidateResponse.kt @@ -0,0 +1,11 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class CodeValidateResponse( + @Json(name = "valid") val valid: Boolean?, + @Json(name = "error") override val error: Error? = null, +) : AbstractPromotionResponse() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromotionInfoResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromotionInfoResponse.kt new file mode 100644 index 0000000000..2caaaacf14 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromotionInfoResponse.kt @@ -0,0 +1,41 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class PromotionInfoResponse( + @Json(name = "status") val status: Status?, + @Json(name = "awardForNewCard") val awardForNewCard: Float?, + @Json(name = "awardForOldCard") val awardForOldCard: Float?, + @Json(name = "awardPaymentToken") val awardPaymentToken: TokenInfo?, + @Json(name = "error") override val error: Error? = null, +) : AbstractPromotionResponse() { + + enum class Status(val value: String) { + @Json(name = "pending") + PENDING("pending"), + + @Json(name = "active") + ACTIVE("active"), + + @Json(name = "finished") + FINISHED("finished"), + } + + data class TokenInfo( + @Json(name = "id") val id: String, + @Json(name = "name") val name: String, + @Json(name = "symbol") val symbol: String, + @Json(name = "active") val active: Boolean, + @Json(name = "networks") val networks: List, + ) { + data class Network( + @Json(name = "networkId") val networkId: String, + @Json(name = "exchangeable") val exchangeable: Boolean, + @Json(name = "contractAddress") val contractAddress: String, + @Json(name = "decimalCount") val decimalCount: Int, + ) + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateRequestBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateRequestBody.kt new file mode 100644 index 0000000000..090f0e0d29 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateRequestBody.kt @@ -0,0 +1,11 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class ValidateRequestBody( + @Json(name = "walletId") val walletId: String, + @Json(name = "programName") val programName: String, +) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateResponse.kt new file mode 100644 index 0000000000..97cd74645d --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/ValidateResponse.kt @@ -0,0 +1,11 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json + +/** +[REDACTED_AUTHOR] + */ +data class ValidateResponse( + @Json(name = "valid") val valid: Boolean?, + @Json(name = "error") override val error: Error? = null, +) : AbstractPromotionResponse() \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt index 4f95438c33..dfbc328755 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt @@ -1,11 +1,6 @@ package com.tangem.datasource.config -import com.tangem.blockchain.common.BlockchainSdkConfig -import com.tangem.blockchain.common.BlockchairCredentials -import com.tangem.blockchain.common.GetBlockCredentials -import com.tangem.blockchain.common.NowNodeCredentials -import com.tangem.blockchain.common.QuickNodeCredentials -import com.tangem.blockchain.common.TonCenterCredentials +import com.tangem.blockchain.common.* import com.tangem.datasource.config.ConfigManager.Companion.IS_CREATING_TWIN_CARDS_ALLOWED import com.tangem.datasource.config.ConfigManager.Companion.IS_SENDING_TO_PAY_ID_ENABLED import com.tangem.datasource.config.ConfigManager.Companion.IS_TOP_UP_ENABLED @@ -111,6 +106,7 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager { zendesk = configValues.zendesk, swapReferrerAccount = configValues.swapReferrerAccount, walletConnectProjectId = configValues.walletConnectProjectId, + tangemComAuthorization = configValues.tangemComAuthorization, ) } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt index 24d8735376..0a49988295 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/Config.kt @@ -19,4 +19,5 @@ data class Config( val zendesk: ZendeskConfig? = null, val swapReferrerAccount: SwapReferrerAccount? = null, val walletConnectProjectId: String = "", + val tangemComAuthorization: String? = null, ) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt index cd518d4c31..6bcb6f9bc9 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt @@ -38,6 +38,7 @@ class ConfigValueModel( val swapReferrerAccount: SwapReferrerAccount?, val kaspaSecondaryApiUrl: String, val walletConnectProjectId: String, + val tangemComAuthorization: String?, ) data class AppsFlyer( diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt index 4ecc2b2529..f0dbc8d7db 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt @@ -2,10 +2,12 @@ package com.tangem.datasource.di import com.squareup.moshi.Moshi import com.tangem.datasource.api.paymentology.PaymentologyApi +import com.tangem.datasource.api.promotion.PromotionApi import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.utils.RequestHeader.* import com.tangem.datasource.utils.addHeaders import com.tangem.datasource.utils.allowLogging +import com.tangem.lib.auth.AuthProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -13,6 +15,7 @@ import dagger.hilt.components.SingletonComponent import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory +import java.util.concurrent.TimeUnit import javax.inject.Singleton @Module @@ -54,10 +57,38 @@ class NetworkModule { .create(PaymentologyApi::class.java) } + @Provides + @Singleton + @PromotionOneInch + fun providePromotionOneInchApi(authProvider: AuthProvider, @NetworkMoshi moshi: Moshi): PromotionApi { + val okClient = OkHttpClient.Builder() + .addHeaders( + AuthenticationHeader(authProvider), + ) + .allowLogging() + .callTimeout(PromotionApi.ONE_INCH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + .connectTimeout(PromotionApi.ONE_INCH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + .readTimeout(PromotionApi.ONE_INCH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + .writeTimeout(PromotionApi.ONE_INCH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + .build() + return createBasePromotionRetrofit(okClient, moshi) + } + + private fun createBasePromotionRetrofit(okHttpClient: OkHttpClient, moshi: Moshi): PromotionApi { + return Retrofit.Builder() + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .baseUrl(PROMOTION_BASE_URL) + .client(okHttpClient) + .build() + .create(PromotionApi::class.java) + } + private companion object { const val PROD_TANGEM_TECH_BASE_URL = "https://api.tangem-tech.com/v1/" const val DEV_TANGEM_TECH_BASE_URL = "https://devapi.tangem-tech.com/v1/" - private const val PAYMENTOLOGY_BASE_URL: String = "https://paymentologygate.oa.r.appspot.com/" + const val PROMOTION_BASE_URL = "https://tangem.com/v1/" + + const val PAYMENTOLOGY_BASE_URL: String = "https://paymentologygate.oa.r.appspot.com/" } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/PromotionOneInch.kt b/core/datasource/src/main/java/com/tangem/datasource/di/PromotionOneInch.kt new file mode 100644 index 0000000000..9e2d6b3981 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/di/PromotionOneInch.kt @@ -0,0 +1,8 @@ +package com.tangem.datasource.di + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class PromotionOneInch \ No newline at end of file diff --git a/libs/auth/src/main/java/com/tangem/lib/auth/BasicAuthProvider.kt b/libs/auth/src/main/java/com/tangem/lib/auth/BasicAuthProvider.kt new file mode 100644 index 0000000000..09dcf8f302 --- /dev/null +++ b/libs/auth/src/main/java/com/tangem/lib/auth/BasicAuthProvider.kt @@ -0,0 +1,9 @@ +package com.tangem.lib.auth + +/** + * Provides auth for Tangem WebView + */ +interface BasicAuthProvider { + + fun getCredentials(): String? +} \ No newline at end of file From 7e765758b4332083ec5c16beaf58ef54d66286ee Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 08:50:47 +0300 Subject: [PATCH 13/54] Updated on 2026-08-14 --- .../storage/UsedCardsPrefStorage.kt | 4 + features/learn2earn/impl/build.gradle.kts | 43 ++++--- .../data/DefaultLearn2earnRepository.kt | 111 ++++++++++++++++++ .../data/DefaultPreferenceStorage.kt | 20 ++++ .../data/DefaultUsedCardsPreferenceStorage.kt | 14 +++ .../data/api/Learn2earnPreferenceStorage.kt | 10 ++ .../data/api/Learn2earnRepository.kt | 20 ++++ .../data/api/UsedCardsPreferenceStorage.kt | 9 ++ .../data/di/Learn2earnDataModule.kt | 55 +++++++++ 9 files changed, 268 insertions(+), 18 deletions(-) create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultLearn2earnRepository.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultPreferenceStorage.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultUsedCardsPreferenceStorage.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/Learn2earnPreferenceStorage.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/Learn2earnRepository.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/UsedCardsPreferenceStorage.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/di/Learn2earnDataModule.kt diff --git a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/UsedCardsPrefStorage.kt b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/UsedCardsPrefStorage.kt index b1fbf61361..de987e84fc 100644 --- a/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/UsedCardsPrefStorage.kt +++ b/data/source/preferences/src/main/kotlin/com/tangem/data/source/preferences/storage/UsedCardsPrefStorage.kt @@ -68,6 +68,10 @@ class UsedCardsPrefStorage internal constructor( return cardInfo.isActivationStarted && !cardInfo.isActivationFinished } + fun hadFinishedActivation(): Boolean { + return restore().any { it.isActivationFinished } + } + private fun findCardInfo( cardId: String, list: MutableList? = null, diff --git a/features/learn2earn/impl/build.gradle.kts b/features/learn2earn/impl/build.gradle.kts index 9e390b1f67..bd20fe9bf6 100644 --- a/features/learn2earn/impl/build.gradle.kts +++ b/features/learn2earn/impl/build.gradle.kts @@ -8,38 +8,45 @@ plugins { } dependencies { - /** AndroidX */ - implementation(deps.androidx.activity.compose) - implementation(deps.androidx.core.ktx) - implementation(deps.androidx.appCompat) - implementation(deps.androidx.constraintLayout) - - /** Compose */ - implementation(deps.compose.material) - implementation(deps.compose.foundation) - implementation(deps.compose.constraintLayout) - implementation(deps.compose.ui) - implementation(deps.compose.ui.tooling) - implementation(deps.compose.animation) - implementation(deps.compose.navigation) - implementation(deps.compose.navigation.hilt) - /** Core modules */ implementation(project(":common")) implementation(project(":core:featuretoggles")) implementation(project(":core:datasource")) - implementation(project(":core:analytics")) implementation(project(":core:utils")) implementation(project(":core:ui")) implementation(project(":core:res")) + implementation(project(":data:source:preferences")) + implementation(project(":libs:auth")) + + implementation(deps.material) + + /** AndroidX */ + implementation(deps.androidx.core.ktx) + implementation(deps.androidx.appCompat) + implementation(deps.androidx.activity.compose) + implementation(deps.androidx.constraintLayout) + implementation(deps.androidx.browser) + + /** Compose */ + implementation(deps.compose.material) + implementation(deps.compose.foundation) + implementation(deps.compose.ui) + implementation(deps.compose.ui.tooling) /** Tangem libraries */ - // TODO: fixme: delete if later it doesn't needed + // TODO: 1inch: delete if later it doesn't needed // implementation(deps.tangem.card.core) // implementation(deps.tangem.card.android) { // exclude(module = "joda-time") // } + /** Network */ + implementation(deps.krateSharedPref) + implementation(deps.moshi) + implementation(deps.moshi.kotlin) + implementation(deps.retrofit) + implementation(deps.retrofit.moshi) + /** Other libraries */ implementation(deps.kotlin.immutable.collections) implementation(deps.kotlin.serialization) diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultLearn2earnRepository.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultLearn2earnRepository.kt new file mode 100644 index 0000000000..8443d28b82 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultLearn2earnRepository.kt @@ -0,0 +1,111 @@ +package com.tangem.feature.learn2earn.data + +import com.squareup.moshi.Moshi +import com.tangem.datasource.api.promotion.PromotionApi +import com.tangem.datasource.api.promotion.models.* +import com.tangem.feature.learn2earn.data.api.Learn2earnPreferenceStorage +import com.tangem.feature.learn2earn.data.api.Learn2earnRepository +import com.tangem.feature.learn2earn.data.api.UsedCardsPreferenceStorage +import timber.log.Timber + +/** +[REDACTED_AUTHOR] + */ +internal class DefaultLearn2earnRepository( + private val preferencesStorage: Learn2earnPreferenceStorage, + private val usedCardsPreferenceStorage: UsedCardsPreferenceStorage, + private val moshi: Moshi, + private val api: PromotionApi, +) : Learn2earnRepository { + + private val promotionInfoAdapter = moshi.adapter(PromotionInfoResponse::class.java) + + override fun isHadActivatedCards(): Boolean { + return usedCardsPreferenceStorage.isHadActivatedCards() + } + + override fun getPromoCode(): String? { + return preferencesStorage.promoCode + } + + override fun savePromoCode(code: String) { + preferencesStorage.promoCode = code + } + + override fun getProgramName(): String { + return PROGRAM_NAME + } + + override fun isAlreadyReceivedAward(): Boolean { + return preferencesStorage.alreadyReceivedAward + } + + override suspend fun requestAwardByCode(walletId: String, address: String): Result { + return runCatching { + api.codeAward(CodeAwardRequestBody(walletId, address, getPromoCode())) + }.fold( + onSuccess = { response -> + val alreadyReceived = response.status ?: false + preferencesStorage.alreadyReceivedAward = alreadyReceived + Result.success(alreadyReceived) + }, + onFailure = { exception -> Result.failure(exception) }, + ) + } + + override suspend fun getPromotionInfo(): Result { + val info = restorePromotionInfo() + + return if (info?.status == PromotionInfoResponse.Status.FINISHED) { + Result.success(info) + } else { + runCatching { api.getPromotionInfo(getProgramName()) } + .fold( + onSuccess = { infoResponse -> + savePromotionInfo(infoResponse) + Result.success(infoResponse) + }, + onFailure = { exception -> Result.failure(exception) }, + ) + } + } + + override suspend fun validate(walletId: String): ValidateResponse { + return api.validate(ValidateRequestBody(walletId, getProgramName())) + } + + override suspend fun award(walletId: String): AwardResponse { + return api.award(AwardRequestBody(walletId, getProgramName())) + } + + override suspend fun codeValidate(walletId: String, code: String?): CodeValidateResponse { + return api.codeValidate(CodeValidateRequestBody(walletId, code)) + } + + override suspend fun codeAward(walletId: String, address: String, code: String?): CodeAwardResponse { + return api.codeAward(CodeAwardRequestBody(walletId, address, code)) + } + + private fun restorePromotionInfo(): PromotionInfoResponse? { + return try { + preferencesStorage.promotionInfo?.let { promotionInfoAdapter.fromJson(it) } + } catch (ex: Exception) { + Timber.e(ex) + preferencesStorage.promotionInfo = null + null + } + } + + private fun savePromotionInfo(infoResponse: PromotionInfoResponse) { + try { + preferencesStorage.promotionInfo = promotionInfoAdapter.toJson(infoResponse) + } catch (ex: Exception) { + Timber.e(ex) + preferencesStorage.promotionInfo = null + } + } + + private companion object { + const val PROGRAM_NAME: String = "1inch" + } +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultPreferenceStorage.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultPreferenceStorage.kt new file mode 100644 index 0000000000..92f5d7da83 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultPreferenceStorage.kt @@ -0,0 +1,20 @@ +package com.tangem.feature.learn2earn.data + +import android.content.Context +import com.tangem.feature.learn2earn.data.api.Learn2earnPreferenceStorage +import hu.autsoft.krate.SimpleKrate +import hu.autsoft.krate.booleanPref +import hu.autsoft.krate.default.withDefault +import hu.autsoft.krate.stringPref + +/** +[REDACTED_AUTHOR] + */ +internal class DefaultPreferenceStorage( + context: Context, +) : SimpleKrate(context = context, name = "Lear2earnPromotion"), Learn2earnPreferenceStorage { + + override var promoCode: String? by stringPref().withDefault(null) + override var promotionInfo: String? by stringPref().withDefault(null) + override var alreadyReceivedAward: Boolean by booleanPref().withDefault(false) +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultUsedCardsPreferenceStorage.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultUsedCardsPreferenceStorage.kt new file mode 100644 index 0000000000..a2f3a8cab4 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/DefaultUsedCardsPreferenceStorage.kt @@ -0,0 +1,14 @@ +package com.tangem.feature.learn2earn.data + +import com.tangem.data.source.preferences.storage.UsedCardsPrefStorage +import com.tangem.feature.learn2earn.data.api.UsedCardsPreferenceStorage + +/** +[REDACTED_AUTHOR] + */ +class DefaultUsedCardsPreferenceStorage( + private val usedCardsPrefStorage: UsedCardsPrefStorage, +) : UsedCardsPreferenceStorage { + + override fun isHadActivatedCards(): Boolean = usedCardsPrefStorage.hadFinishedActivation() +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/Learn2earnPreferenceStorage.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/Learn2earnPreferenceStorage.kt new file mode 100644 index 0000000000..78f548febc --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/Learn2earnPreferenceStorage.kt @@ -0,0 +1,10 @@ +package com.tangem.feature.learn2earn.data.api + +/** +[REDACTED_AUTHOR] + */ +interface Learn2earnPreferenceStorage { + var promoCode: String? + var promotionInfo: String? + var alreadyReceivedAward: Boolean +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/Learn2earnRepository.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/Learn2earnRepository.kt new file mode 100644 index 0000000000..6641bc36c8 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/Learn2earnRepository.kt @@ -0,0 +1,20 @@ +package com.tangem.feature.learn2earn.data.api + +import com.tangem.datasource.api.promotion.models.* + +/** +[REDACTED_AUTHOR] + */ +interface Learn2earnRepository { + fun isHadActivatedCards(): Boolean + fun getPromoCode(): String? + fun savePromoCode(code: String) + fun getProgramName(): String + fun isAlreadyReceivedAward(): Boolean + suspend fun requestAwardByCode(walletId: String, address: String): Result + suspend fun getPromotionInfo(): Result + suspend fun validate(walletId: String): ValidateResponse + suspend fun award(walletId: String): AwardResponse + suspend fun codeValidate(walletId: String, code: String?): CodeValidateResponse + suspend fun codeAward(walletId: String, address: String, code: String?): CodeAwardResponse +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/UsedCardsPreferenceStorage.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/UsedCardsPreferenceStorage.kt new file mode 100644 index 0000000000..c7d1174496 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/api/UsedCardsPreferenceStorage.kt @@ -0,0 +1,9 @@ +package com.tangem.feature.learn2earn.data.api + +/** +[REDACTED_AUTHOR] + * An interface that encapsulates access to deprecated PreferencesDataSource.usedCardsPrefStorage. + */ +interface UsedCardsPreferenceStorage { + fun isHadActivatedCards(): Boolean +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/di/Learn2earnDataModule.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/di/Learn2earnDataModule.kt new file mode 100644 index 0000000000..9d6e5a0507 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/data/di/Learn2earnDataModule.kt @@ -0,0 +1,55 @@ +package com.tangem.feature.learn2earn.data.di + +import android.content.Context +import com.squareup.moshi.Moshi +import com.tangem.data.source.preferences.PreferencesDataSource +import com.tangem.datasource.api.promotion.PromotionApi +import com.tangem.datasource.di.NetworkMoshi +import com.tangem.datasource.di.PromotionOneInch +import com.tangem.feature.learn2earn.data.DefaultLearn2earnRepository +import com.tangem.feature.learn2earn.data.DefaultPreferenceStorage +import com.tangem.feature.learn2earn.data.DefaultUsedCardsPreferenceStorage +import com.tangem.feature.learn2earn.data.api.Learn2earnPreferenceStorage +import com.tangem.feature.learn2earn.data.api.Learn2earnRepository +import com.tangem.feature.learn2earn.data.api.UsedCardsPreferenceStorage +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class Learn2earnDataModule { + + @Provides + @Singleton + fun providePreferenceStorage(@ApplicationContext context: Context): Learn2earnPreferenceStorage { + return DefaultPreferenceStorage(context) + } + + @Provides + @Singleton + fun provideDeprecatedPreferenceDataSource( + preferenceDataSource: PreferencesDataSource, + ): UsedCardsPreferenceStorage { + return DefaultUsedCardsPreferenceStorage(preferenceDataSource.usedCardsPrefStorage) + } + + @Provides + @Singleton + fun provideRepository( + preferenceStorage: Learn2earnPreferenceStorage, + usedCardsPreferenceStorage: UsedCardsPreferenceStorage, + @NetworkMoshi moshi: Moshi, + @PromotionOneInch promotionApi: PromotionApi, + ): Learn2earnRepository { + return DefaultLearn2earnRepository( + preferencesStorage = preferenceStorage, + usedCardsPreferenceStorage = usedCardsPreferenceStorage, + moshi = moshi, + api = promotionApi, + ) + } +} \ No newline at end of file From efe271e1a072b3ab3cd7b0db0fe4803d7e366c21 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 08:51:46 +0300 Subject: [PATCH 14/54] Updated on 2026-08-14 --- app/src/main/AndroidManifest.xml | 2 + .../java/com/tangem/tap/TapApplication.kt | 118 +++++++++-------- .../tangem/tap/features/home/HomeFragment.kt | 15 +++ .../features/home/compose/StoriesScreen.kt | 6 +- .../tap/features/home/redux/HomeAction.kt | 2 + .../tap/features/home/redux/HomeReducer.kt | 7 + .../tap/features/home/redux/HomeState.kt | 4 +- .../welcome/redux/WelcomeMiddleware.kt | 16 +-- app/src/main/res/layout/fragment_wallet.xml | 13 +- .../java/com/tangem/utils/extensions/Any.kt | 10 ++ .../domain/DefaultLearn2earnInteractor.kt | 123 ++++++++++++++++++ .../learn2earn/domain/WebViewUriBuilder.kt | 98 ++++++++++++++ .../domain/api/Learn2earnInteractor.kt | 18 +++ .../domain/di/Learn2earnDomainModule.kt | 39 ++++++ .../learn2earn/domain/models/CardType.kt | 9 ++ .../learn2earn/domain/models/MockModels.kt | 76 +++++++++++ .../learn2earn/domain/models/Promotion.kt | 30 +++++ .../domain/models/PromotionError.kt | 15 +++ .../learn2earn/domain/models/WebViewHelper.kt | 17 +++ .../presentation/Learn2earnRouter.kt | 23 ++++ .../presentation/Learn2earnViewModel.kt | 58 +++++++++ .../presentation/Learn2earnWebViewActivity.kt | 90 +++++++++++++ ...eInchStoriesScreen.kt => StoriesScreen.kt} | 8 +- .../src/main/res/layout/activity_web_view.xml | 29 +++++ 24 files changed, 751 insertions(+), 75 deletions(-) create mode 100644 core/utils/src/main/java/com/tangem/utils/extensions/Any.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/DefaultLearn2earnInteractor.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/WebViewUriBuilder.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/api/Learn2earnInteractor.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/di/Learn2earnDomainModule.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/CardType.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/MockModels.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/Promotion.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/PromotionError.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/WebViewHelper.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnRouter.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnViewModel.kt create mode 100644 features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnWebViewActivity.kt rename features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/{OneInchStoriesScreen.kt => StoriesScreen.kt} (94%) create mode 100644 features/learn2earn/impl/src/main/res/layout/activity_web_view.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ef93ea2179..13d09bd76f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -138,6 +138,8 @@ android:name="com.tangem.tap.features.sprinklr.ui.SprinklrActivity" android:theme="@style/AppTheme" /> + + @@ -136,6 +144,9 @@ class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var walletConnectSessionsRepository: WalletConnectSessionsRepository + @Inject + lateinit var learn2ernInteractor: Learn2earnInteractor + override fun onCreate() { super.onCreate() @@ -189,8 +200,9 @@ class TapApplication : Application(), ImageLoaderFactory { appStateHolder.userTokensRepository = userTokensRepository appStateHolder.walletStoresManager = walletStoresManager - scope.launch { + runBlocking { featureTogglesManager.init() + learn2ernInteractor.init() } initTopUpController() diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt index bdb1d84900..591f7b6369 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -12,26 +12,38 @@ import androidx.compose.ui.platform.ComposeView import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsControllerCompat import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import com.tangem.core.analytics.Analytics import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.learn2earn.presentation.Learn2earnViewModel import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.home.compose.StoriesScreen import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.home.redux.HomeState +import com.tangem.tap.features.home.redux.Stories import com.tangem.tap.features.tokens.legacy.redux.TokensAction import com.tangem.tap.store +import dagger.hilt.android.AndroidEntryPoint import org.rekotlin.StoreSubscriber +@AndroidEntryPoint class HomeFragment : Fragment(), StoreSubscriber { private var homeState: MutableState = mutableStateOf(store.state.homeState) + private val learn2earnViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) store.dispatch(HomeAction.OnCreate) store.dispatch(HomeAction.Init) + if (learn2earnViewModel.isNeedToShowViewOnStoriesScreen()) { + store.dispatch(HomeAction.InsertStory(position = 0, Stories.OneInchPromo)) + // re init homeState after inserting learn2earn story + homeState = mutableStateOf(store.state.homeState) + } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -79,6 +91,9 @@ class HomeFragment : Fragment(), StoreSubscriber { private fun ScreenContent() { StoriesScreen( homeState, + onLearn2earnClick = { + learn2earnViewModel.onStoriesClick() + }, onScanButtonClick = { Analytics.send(IntroductionProcess.ButtonScanCard()) store.dispatch(HomeAction.ReadCard()) diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt index af5df09c59..46ef676001 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt @@ -26,7 +26,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.tangem.core.ui.res.TangemTheme -import com.tangem.feature.learn2earn.presentation.ui.OneInchStoriesScreen +import com.tangem.feature.learn2earn.presentation.ui.StoriesScreen import com.tangem.tap.features.home.compose.content.* import com.tangem.tap.features.home.compose.views.HomeButtons import com.tangem.tap.features.home.compose.views.StoriesProgressBar @@ -39,6 +39,7 @@ import kotlin.math.max @Composable fun StoriesScreen( homeState: MutableState, + onLearn2earnClick: () -> Unit, onScanButtonClick: () -> Unit, onShopButtonClick: () -> Unit, onSearchTokensClick: () -> Unit, @@ -152,7 +153,7 @@ fun StoriesScreen( colorFilter = if (currentStory.isDarkBackground) null else ColorFilter.tint(Color.Black), ) when (currentStory) { - Stories.OneInchPromo -> OneInchStoriesScreen({}) + Stories.OneInchPromo -> StoriesScreen(onLearn2earnClick) Stories.TangemIntro -> FirstStoriesContent(isPaused, currentStory.duration) { hideContent.value = it } Stories.RevolutionaryWallet -> StoriesRevolutionaryWallet(currentStory.duration) Stories.UltraSecureBackup -> StoriesUltraSecureBackup(isPaused, currentStory.duration) @@ -215,6 +216,7 @@ fun StoriesScreen( @Composable private fun StoriesScreenPreview() { StoriesScreen( + onLearn2earnClick = {}, onScanButtonClick = {}, onShopButtonClick = {}, onSearchTokensClick = {}, diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt index bb9be2edc3..86b139defb 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt @@ -11,6 +11,8 @@ sealed class HomeAction : Action { object OnCreate : HomeAction() object Init : HomeAction() + data class InsertStory(val position: Int, val story: Stories) : HomeAction() + data class ReadCard( val analyticsEvent: AnalyticsEvent? = Basic.CardWasScanned(AnalyticsParam.ScannedFrom.Introduction), ) : HomeAction() diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt index f9f2911c32..6843253f5a 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt @@ -12,6 +12,13 @@ private fun internalReduce(action: Action, state: AppState): HomeState { var state = state.homeState when (action) { + is HomeAction.InsertStory -> { + state = state.copy( + stories = state.stories.toMutableList().apply { + add(action.position, action.story) + }, + ) + } is HomeAction.ScanInProgress -> { state = state.copy(scanInProgress = action.scanInProgress) } diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt index 9342420e6b..415deb938d 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt @@ -11,7 +11,8 @@ data class HomeState( val stories: List = initDefaultStories(), ) : StateType { - val firstStory: Stories = stories[0] + val firstStory: Stories + get() = stories[0] val btnScanStateInProgress: Boolean get() = btnScanState.progressState == ProgressState.Loading @@ -20,7 +21,6 @@ data class HomeState( companion object { fun initDefaultStories(): List = listOf( - Stories.OneInchPromo, Stories.TangemIntro, Stories.RevolutionaryWallet, Stories.UltraSecureBackup, diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index 7f22650f5e..005bcca0a4 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -1,8 +1,10 @@ package com.tangem.tap.features.welcome.redux -import android.content.Intent -import com.tangem.common.* import com.tangem.common.core.TangemSdkError +import com.tangem.common.doOnFailure +import com.tangem.common.doOnResult +import com.tangem.common.doOnSuccess +import com.tangem.common.flatMap import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -17,7 +19,6 @@ import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.unlockIfLockable import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler -import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError import com.tangem.tap.features.signin.redux.SignInAction import kotlinx.coroutines.launch import org.rekotlin.Middleware @@ -98,15 +99,6 @@ internal class WelcomeMiddleware { } } - private fun handleInitialIntent(intent: Intent?) { - val isBackgroundScanNotHandled = !intentHandler.handleBackgroundScan(intent, hasSavedUserWallets = true) - val hasNotIncompletedBackup = !backupService.hasIncompletedBackup - - if (isBackgroundScanNotHandled && hasNotIncompletedBackup) { - store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics) - } - } - private suspend inline fun scanCardInternal(crossinline onCardScanned: suspend (ScanResponse) -> Unit) { tangemSdkManager.setAccessCodeRequestPolicy( useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index b4287625d4..ac04bb12dd 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -46,8 +46,8 @@ android:id="@+id/cl_wallet" android:layout_width="match_parent" android:layout_height="wrap_content" - android:clipToPadding="false" android:clipChildren="false" + android:clipToPadding="false" android:paddingBottom="92dp"> + + T.toWeakReference(): WeakReference { + return WeakReference(this) +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/DefaultLearn2earnInteractor.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/DefaultLearn2earnInteractor.kt new file mode 100644 index 0000000000..fcb7c48add --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/DefaultLearn2earnInteractor.kt @@ -0,0 +1,123 @@ +package com.tangem.feature.learn2earn.domain + +import android.net.Uri +import com.tangem.datasource.api.promotion.models.PromotionInfoResponse +import com.tangem.feature.learn2earn.data.api.Learn2earnRepository +import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor +import com.tangem.feature.learn2earn.domain.models.CardType +import com.tangem.feature.learn2earn.domain.models.Promotion +import com.tangem.feature.learn2earn.domain.models.PromotionError +import com.tangem.feature.learn2earn.domain.models.PromotionError.Companion.toDomainError +import com.tangem.feature.learn2earn.domain.models.RedirectConsequences +import com.tangem.lib.auth.BasicAuthProvider + +/** +[REDACTED_AUTHOR] + */ +class DefaultLearn2earnInteractor( + private val repository: Learn2earnRepository, + basicAuthProvider: BasicAuthProvider, + userCountryCodeProvider: () -> String, +) : Learn2earnInteractor { + + private val webViewUriBuilder = WebViewUriBuilder( + basicAuthProvider = basicAuthProvider, + userCountryCodeProvider = userCountryCodeProvider, + promoCodeProvider = { repository.getPromoCode() }, + promoNameProvider = { repository.getProgramName() }, + ) + + private lateinit var promotion: Promotion + + override suspend fun init() { + initPromotionInfo() + } + + override fun isNeedToShowViewOnStoriesScreen(): Boolean { + return promotionIsActive() + } + + override fun getBasicAuthHeaders(): Map { + return webViewUriBuilder.getBasicAuthHeaders() + } + + override suspend fun isNeedToShowViewOnWalletScreen(walletId: String): Boolean { + val response = repository.validate(walletId) + + return if (response.valid == false && response.isError()) { + false + } else { + promotionIsActive() + } + } + + override fun buildUriForStories(): Uri { + val type = if (repository.isHadActivatedCards()) { + CardType.NEW + } else { + CardType.EXISTED + } + + return webViewUriBuilder.buildUriForStories(type) + } + + override fun buildUriForMainPage(walletId: String, cardId: String, cardPubKey: String): Uri { + return webViewUriBuilder.buildUriForMainPage(walletId, cardId, cardPubKey) + } + + override fun handleWebViewRedirect(uri: Uri): RedirectConsequences { + if (webViewUriBuilder.isReadyForExistedCardAwardRedirect(uri)) { + return RedirectConsequences.FINISH_SESSION + } + + return if (webViewUriBuilder.isPromoCodeRedirect(uri)) { + webViewUriBuilder.extractPromoCode(uri)?.let { repository.savePromoCode(it) } + RedirectConsequences.NOTHING + } else { + RedirectConsequences.PROCEED + } + } + + private fun promotionIsActive(): Boolean { + val isActive = when { + repository.isAlreadyReceivedAward() -> false + promotion.isError() -> false + else -> promotion.getInfo().status == PromotionInfoResponse.Status.ACTIVE + } + + return isActive + } + + private suspend fun initPromotionInfo() { + // return Promotion.dummyActive() + + promotion = repository.getPromotionInfo() + .fold( + onSuccess = { response -> + val responseError = response.error + if (responseError == null) { + Promotion( + info = Promotion.PromotionInfo( + status = response.status!!, + awardForNewCard = response.awardForNewCard!!, + awardForOldCard = response.awardForOldCard!!, + awardPaymentToken = response.awardPaymentToken!!, + ), + error = null, + ) + } else { + Promotion( + info = null, + error = responseError.toDomainError(), + ) + } + }, + onFailure = { + Promotion( + info = null, + error = PromotionError.NetworkUnreachable, + ) + }, + ) + } +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/WebViewUriBuilder.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/WebViewUriBuilder.kt new file mode 100644 index 0000000000..c70e983a15 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/WebViewUriBuilder.kt @@ -0,0 +1,98 @@ +package com.tangem.feature.learn2earn.domain + +import android.net.Uri +import com.tangem.feature.learn2earn.domain.models.CardType +import com.tangem.feature.learn2earn.impl.BuildConfig +import com.tangem.lib.auth.BasicAuthProvider + +/** +[REDACTED_AUTHOR] + */ +class WebViewUriBuilder( + private val basicAuthProvider: BasicAuthProvider, + private val userCountryCodeProvider: () -> String, + private val promoCodeProvider: () -> String?, + private val promoNameProvider: () -> String, +) { + + fun buildUriForStories(type: CardType): Uri { + val builder = makeWebViewUriBuilder() + .appendQueryParameter("type", type.typeName) + + promoCodeProvider.invoke()?.let { + builder.appendQueryParameter("code", it) + } + + return builder.build() + } + + fun buildUriForMainPage(walletId: String, cardId: String, cardPubKey: String): Uri { + val builder = makeWebViewUriBuilder() + .appendQueryParameter("type", CardType.EXISTED.typeName) + .appendQueryParameter("cardPublicKey", cardPubKey) + .appendQueryParameter("cardId", cardId) + .appendQueryParameter("walletId", walletId) + .appendQueryParameter("programName", promoNameProvider.invoke()) + + promoCodeProvider.invoke()?.let { + builder.appendQueryParameter("code", it) + } + + return builder.build() + } + + fun getBasicAuthHeaders(): Map { + return basicAuthProvider.getCredentials()?.let { + mapOf("Authorization" to "Basic $it") + } ?: mapOf() + } + + fun isPromoCodeRedirect(uri: Uri): Boolean { + return uri.toString().contains(SUFFIX_CODE_CREATED) + } + + fun isReadyForExistedCardAwardRedirect(uri: Uri): Boolean { + return uri.toString().endsWith(SUFFIX_READY_FOR_AWARD) + } + + fun extractPromoCode(uri: Uri): String? { + val url = uri.toString() + + return if (isPromoCodeRedirect(uri)) { + val replaceString = makeWebViewUriBuilder().build().toString() + SUFFIX_CODE_CREATED + val code = url.replace(replaceString, "") + code + } else { + null + } + } + + private fun makeWebViewUriBuilder(): Uri.Builder { + val builder = Uri.Builder() + builder.scheme("https") + + if (BuildConfig.DEBUG) { + builder.authority(DEV_WEB_VIEW_BASE_URL) + builder.appendPath(userCountryCodeProvider.invoke()) + builder.appendPath("promotion-test") + } else { + builder.authority(WEB_VIEW_BASE_URL) + builder.appendPath(userCountryCodeProvider.invoke()) + builder.appendPath("promotion") + } + + return builder + } + + private companion object { + const val WEB_VIEW_BASE_URL = "tangem.com" + + const val DEV_WEB_VIEW_BASE_URL = "devweb.tangem.com" + const val DEV_WEB_VIEW_BASIC_AUTH = "Basic dGFuZ2VtOnRhbmdlbWRldjc=" + // TODO: 1inch: replace by invalid auth + // const val DEV_WEB_VIEW_BASIC_AUTH = "Basic paste valid value" + + const val SUFFIX_CODE_CREATED = "/code-created?code=" + const val SUFFIX_READY_FOR_AWARD = "/ready-for-exsited-card-award" + } +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/api/Learn2earnInteractor.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/api/Learn2earnInteractor.kt new file mode 100644 index 0000000000..4aa046c5e3 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/api/Learn2earnInteractor.kt @@ -0,0 +1,18 @@ +package com.tangem.feature.learn2earn.domain.api + +import android.net.Uri +import com.tangem.feature.learn2earn.domain.models.RedirectConsequences + +/** +[REDACTED_AUTHOR] + */ +interface Learn2earnInteractor { + + suspend fun init() + fun isNeedToShowViewOnStoriesScreen(): Boolean + suspend fun isNeedToShowViewOnWalletScreen(walletId: String): Boolean + fun getBasicAuthHeaders(): Map + fun buildUriForStories(): Uri + fun buildUriForMainPage(walletId: String, cardId: String, cardPubKey: String): Uri + fun handleWebViewRedirect(uri: Uri): RedirectConsequences +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/di/Learn2earnDomainModule.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/di/Learn2earnDomainModule.kt new file mode 100644 index 0000000000..d33f81422f --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/di/Learn2earnDomainModule.kt @@ -0,0 +1,39 @@ +package com.tangem.feature.learn2earn.domain.di + +import android.content.Context +import com.tangem.feature.learn2earn.data.api.Learn2earnRepository +import com.tangem.feature.learn2earn.domain.DefaultLearn2earnInteractor +import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor +import com.tangem.feature.learn2earn.presentation.Learn2earnRouter +import com.tangem.lib.auth.BasicAuthProvider +import com.tangem.utils.extensions.toWeakReference +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class Learn2earnDomainModule { + + @Provides + @Singleton + fun provideRouter(@ApplicationContext context: Context): Learn2earnRouter { + return Learn2earnRouter(context.toWeakReference()) + } + + @Provides + @Singleton + fun provideInteractor( + repository: Learn2earnRepository, + basicAuthProvider: BasicAuthProvider, + ): Learn2earnInteractor { + return DefaultLearn2earnInteractor( + repository = repository, + basicAuthProvider = basicAuthProvider, + userCountryCodeProvider = { "ru" }, + ) + } +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/CardType.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/CardType.kt new file mode 100644 index 0000000000..1e05115373 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/CardType.kt @@ -0,0 +1,9 @@ +package com.tangem.feature.learn2earn.domain.models + +/** +[REDACTED_AUTHOR] + */ +enum class CardType(val typeName: String) { + NEW("new-card"), + EXISTED("existed-card"), +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/MockModels.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/MockModels.kt new file mode 100644 index 0000000000..340de5e151 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/MockModels.kt @@ -0,0 +1,76 @@ +package com.tangem.feature.learn2earn.domain.models + +import com.tangem.datasource.api.promotion.models.PromotionInfoResponse + +/** +[REDACTED_AUTHOR] + */ +internal fun Promotion.Companion.dummyPending(): Promotion { + return Promotion( + info = Promotion.PromotionInfo.dummy().copy( + status = PromotionInfoResponse.Status.PENDING, + ), + error = null, + ) +} + +internal fun Promotion.Companion.dummyActive(): Promotion { + return Promotion( + info = Promotion.PromotionInfo.dummy().copy( + status = PromotionInfoResponse.Status.ACTIVE, + ), + error = null, + ) +} + +internal fun Promotion.Companion.dummyFinished(): Promotion { + return Promotion( + info = Promotion.PromotionInfo.dummy().copy( + status = PromotionInfoResponse.Status.FINISHED, + ), + error = null, + ) +} + +internal fun Promotion.Companion.dummyError(): Promotion { + return Promotion( + info = null, + error = PromotionError.Error( + code = 105, + description = "any", + ), + ) +} + +internal fun Promotion.Companion.dummyErrorUnreachable(): Promotion { + return Promotion( + info = null, + error = PromotionError.NetworkUnreachable, + ) +} + +private fun Promotion.PromotionInfo.Companion.dummy(): Promotion.PromotionInfo { + return Promotion.PromotionInfo( + status = PromotionInfoResponse.Status.ACTIVE, + awardForNewCard = 10f, + awardForOldCard = 5.5f, + awardPaymentToken = Promotion.tokenInfo(), + ) +} + +private fun Promotion.Companion.tokenInfo(): PromotionInfoResponse.TokenInfo { + return PromotionInfoResponse.TokenInfo( + id = "1inch", + name = "1inch", + symbol = "1INCH", + active = true, + networks = listOf( + PromotionInfoResponse.TokenInfo.Network( + networkId = "polygon-pos", + exchangeable = false, + contractAddress = "0x9c2c5fd7b07e95ee044ddeba0e97a665f142394f", + decimalCount = 1, + ), + ), + ) +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/Promotion.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/Promotion.kt new file mode 100644 index 0000000000..e5b071a15d --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/Promotion.kt @@ -0,0 +1,30 @@ +package com.tangem.feature.learn2earn.domain.models + +import com.tangem.datasource.api.promotion.models.PromotionInfoResponse + +/** +[REDACTED_AUTHOR] + */ +data class Promotion( + val info: PromotionInfo?, + val error: PromotionError?, +) { + + @Throws(NullPointerException::class) + fun getInfo(): PromotionInfo = info!! + + fun isError(): Boolean = error != null + + fun isUnreachable(): Boolean = error == PromotionError.NetworkUnreachable + + data class PromotionInfo( + val status: PromotionInfoResponse.Status, + val awardForNewCard: Float, + val awardForOldCard: Float, + val awardPaymentToken: PromotionInfoResponse.TokenInfo, + ) { + companion object + } + + companion object +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/PromotionError.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/PromotionError.kt new file mode 100644 index 0000000000..8cd24cfa2c --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/PromotionError.kt @@ -0,0 +1,15 @@ +package com.tangem.feature.learn2earn.domain.models + +import com.tangem.datasource.api.promotion.models.AbstractPromotionResponse + +/** +[REDACTED_AUTHOR] + */ +sealed class PromotionError(val code: Int, val description: String) { + object NetworkUnreachable : PromotionError(-1, "Network or service is unreachable") + class Error(code: Int, description: String) : PromotionError(code, description) + + companion object { + fun AbstractPromotionResponse.Error.toDomainError(): PromotionError = Error(code, description) + } +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/WebViewHelper.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/WebViewHelper.kt new file mode 100644 index 0000000000..0075b17435 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/domain/models/WebViewHelper.kt @@ -0,0 +1,17 @@ +package com.tangem.feature.learn2earn.domain.models + +import android.net.Uri + +/** +[REDACTED_AUTHOR] + */ +interface WebViewHelper { + fun handleWebViewRedirect(uri: Uri): RedirectConsequences + fun getWebViewHeaders(): Map +} + +enum class RedirectConsequences { + NOTHING, + PROCEED, + FINISH_SESSION, +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnRouter.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnRouter.kt new file mode 100644 index 0000000000..0c6c1a7e34 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnRouter.kt @@ -0,0 +1,23 @@ +package com.tangem.feature.learn2earn.presentation + +import android.content.Context +import android.content.Intent +import timber.log.Timber +import java.lang.ref.WeakReference + +/** +[REDACTED_AUTHOR] + */ +class Learn2earnRouter( + private val wContext: WeakReference, +) { + + fun openWebView() { + val context = wContext.get() + if (context == null) { + Timber.e("Can't open the Learn2earnWebViewActivity") + } else { + context.startActivity(Intent(context, Learn2earnWebViewActivity::class.java)) + } + } +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnViewModel.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnViewModel.kt new file mode 100644 index 0000000000..f39aee6032 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnViewModel.kt @@ -0,0 +1,58 @@ +package com.tangem.feature.learn2earn.presentation + +import android.net.Uri +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor +import com.tangem.feature.learn2earn.domain.models.RedirectConsequences +import com.tangem.feature.learn2earn.domain.models.WebViewHelper +import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import javax.inject.Inject + +/** +[REDACTED_AUTHOR] + */ +@HiltViewModel +class Learn2earnViewModel @Inject constructor( + private val interactor: Learn2earnInteractor, + private val router: Learn2earnRouter, + private val dispatchers: AppCoroutineDispatcherProvider, +) : ViewModel(), WebViewHelper { + + var webViewUri: Uri = Uri.parse("https://localhost") + private set + + fun isNeedToShowViewOnStoriesScreen(): Boolean = interactor.isNeedToShowViewOnStoriesScreen() + + fun onStoriesClick() { + webViewUri = interactor.buildUriForStories() + router.openWebView() + } + + fun isNeedToShowViewOnWalletScreen(walletId: String, callback: (Boolean) -> Unit) { + viewModelScope.launch(dispatchers.io) { + val isNeedToShow = interactor.isNeedToShowViewOnWalletScreen(walletId) + withContext(dispatchers.main) { + callback(isNeedToShow) + } + } + } + + fun onMainPageClick(walletId: String, cardId: String, cardPubKey: String) { + webViewUri = interactor.buildUriForMainPage(walletId, cardId, cardPubKey) + router.openWebView() + } + + // region WebViewHelper + override fun handleWebViewRedirect(uri: Uri): RedirectConsequences { + return interactor.handleWebViewRedirect(uri) + } + + override fun getWebViewHeaders(): Map { + return interactor.getBasicAuthHeaders() + } + // endregion WebViewHelper +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnWebViewActivity.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnWebViewActivity.kt new file mode 100644 index 0000000000..c054b21ef0 --- /dev/null +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/Learn2earnWebViewActivity.kt @@ -0,0 +1,90 @@ +package com.tangem.feature.learn2earn.presentation + +import android.os.Bundle +import android.view.MenuItem +import android.webkit.WebResourceRequest +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.activity.viewModels +import androidx.appcompat.app.ActionBar +import androidx.appcompat.app.AppCompatActivity +import com.tangem.feature.learn2earn.domain.models.RedirectConsequences +import com.tangem.feature.learn2earn.domain.models.WebViewHelper +import com.tangem.feature.learn2earn.impl.R +import dagger.hilt.android.AndroidEntryPoint + +/** +[REDACTED_AUTHOR] + */ +@AndroidEntryPoint +class Learn2earnWebViewActivity : AppCompatActivity() { + + private val learn2earnViewModel by viewModels() + + private lateinit var actionBar: ActionBar + private lateinit var webView: WebView + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_web_view) + + setSupportActionBar(findViewById(R.id.toolbar)) + actionBar = supportActionBar!! + actionBar.setDisplayHomeAsUpEnabled(true) + actionBar.setDisplayShowHomeEnabled(true) + actionBar.title = learn2earnViewModel.webViewUri.authority + + webView = findViewById(R.id.web_view) + webView.settings.javaScriptEnabled = true + webView.settings.domStorageEnabled = true + webView.settings.loadsImagesAutomatically = true + + webView.webViewClient = Learn2earnWebViewClient( + helper = learn2earnViewModel, + finishSessionHandler = { finish() }, + ) + webView.loadUrl( + learn2earnViewModel.webViewUri.toString(), + learn2earnViewModel.getWebViewHeaders(), + ) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + android.R.id.home -> { + finish() + true + } + else -> super.onOptionsItemSelected(item) + } + } + + override fun onDestroy() { + webView.clearHistory() + webView.clearCache(true) + webView.destroy() + + super.onDestroy() + } +} + +private class Learn2earnWebViewClient( + private val helper: WebViewHelper, + private val finishSessionHandler: () -> Unit, +) : WebViewClient() { + + override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { + when (helper.handleWebViewRedirect(request.url)) { + RedirectConsequences.NOTHING -> Unit + RedirectConsequences.PROCEED -> { + val headers = helper.getWebViewHeaders().toMutableMap() + request.requestHeaders?.let { headers.putAll(it) } + view.loadUrl(request.url.toString(), headers) + } + RedirectConsequences.FINISH_SESSION -> { + finishSessionHandler.invoke() + } + } + return true + } +} \ No newline at end of file diff --git a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/StoriesScreen.kt similarity index 94% rename from features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt rename to features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/StoriesScreen.kt index ff3c3218b7..74f3584e6b 100644 --- a/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/OneInchStoriesScreen.kt +++ b/features/learn2earn/impl/src/main/java/com/tangem/feature/learn2earn/presentation/ui/StoriesScreen.kt @@ -24,9 +24,9 @@ import com.tangem.feature.learn2earn.presentation.ui.component.GradientCircle /** [REDACTED_AUTHOR] */ -// TODO: fixme: make function as internal after adding feature interface +// TODO: 1inch: make function as internal after adding feature interface @Composable -fun OneInchStoriesScreen(onLearnClick: () -> Unit, modifier: Modifier = Modifier) { +fun StoriesScreen(onLearnClick: () -> Unit, modifier: Modifier = Modifier) { Box(modifier = modifier.fillMaxSize()) { ContentBackground( modifier = Modifier @@ -111,7 +111,7 @@ private fun OneInchStoriesContentPreview_Light() { TangemTheme( isDark = false, ) { - OneInchStoriesScreen( + StoriesScreen( onLearnClick = {}, ) } @@ -123,7 +123,7 @@ private fun OneInchStoriesContentPreview_Dark() { TangemTheme( isDark = true, ) { - OneInchStoriesScreen( + StoriesScreen( onLearnClick = {}, ) } diff --git a/features/learn2earn/impl/src/main/res/layout/activity_web_view.xml b/features/learn2earn/impl/src/main/res/layout/activity_web_view.xml new file mode 100644 index 0000000000..46968b0a14 --- /dev/null +++ b/features/learn2earn/impl/src/main/res/layout/activity_web_view.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + \ No newline at end of file From b87a0ae96b1ac0ad6820520a758caac383b372aa Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 21 Jun 2023 13:25:40 +0300 Subject: [PATCH 15/54] Updated on 2026-08-14 --- .idea/codeStyles/Project.xml | 3 + .../java/com/tangem/tap/TapApplication.kt | 2 + .../network/auth/TangemBasicAuthProvider.kt | 7 +- .../tangem/tap/network/auth/di/AuthModule.kt | 3 +- .../datasource/api/promotion/PromotionApi.kt | 23 ++----- .../models/AbstractPromotionResponse.kt | 4 +- .../com/tangem/datasource/di/NetworkModule.kt | 9 +-- .../data/DefaultLearn2earnRepository.kt | 65 +++++++++---------- .../data/DefaultPreferenceStorage.kt | 2 + .../data/api/Learn2earnPreferenceStorage.kt | 3 + .../data/api/Learn2earnRepository.kt | 17 +++-- .../data/di/Learn2earnDataModule.kt | 3 + .../domain/DefaultLearn2earnInteractor.kt | 2 - .../learn2earn/domain/WebViewUriBuilder.kt | 4 +- .../domain/api/Learn2earnInteractor.kt | 6 ++ .../domain/di/Learn2earnDomainModule.kt | 4 +- .../presentation/Learn2earnRouter.kt | 11 +--- .../com/tangem/lib/auth/BasicAuthProvider.kt | 2 +- 18 files changed, 91 insertions(+), 79 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 0db8c6d7c9..ac3eeb6f5d 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -13,6 +13,9 @@ + - + + Show in Figma */ @Composable -fun RoundedActionButton(config: ActionConfig, modifier: Modifier = Modifier) { - TangemButton( +fun RoundedActionButton( + config: ActionButtonConfig, + modifier: Modifier = Modifier, + color: Color = TangemTheme.colors.button.secondary, +) { + Button( + config = config, + shape = RoundedCornerShape(size = TangemTheme.dimens.radius24), modifier = modifier, - text = config.text, - icon = TangemButtonIconPosition.Start(config.iconResId), - onClick = config.onClick, - enabled = config.enabled, - showProgress = false, - colors = TangemButtonsDefaults.secondaryButtonColors, - size = TangemButtonSize.RoundedAction, + color = color, ) } /** - * [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=1208-1395&t=3z98eFnTeyIx5TH5-4) + * Action button + * + * @param config component config + * @param modifier modifier + * @param color background color + * + * @see Show in Figma */ @Composable -fun ActionButton(config: ActionConfig, modifier: Modifier = Modifier) { - TangemButton( +fun ActionButton( + config: ActionButtonConfig, + modifier: Modifier = Modifier, + color: Color = TangemTheme.colors.button.secondary, +) { + Button( + config = config, + shape = RoundedCornerShape(size = TangemTheme.dimens.radius12), modifier = modifier, - text = config.text, - icon = TangemButtonIconPosition.Start(config.iconResId), - onClick = config.onClick, - enabled = config.enabled, - showProgress = false, - colors = TangemButtonsDefaults.secondaryButtonColors, - size = TangemButtonSize.Action, + color = color, ) } -/** - * Same as [RoundedActionButton] but colored in primary background color - */ @Composable -fun BackgroundActionButton(config: ActionConfig, modifier: Modifier = Modifier) { - TangemButton( - modifier = modifier, - text = config.text, - icon = TangemButtonIconPosition.Start(config.iconResId), - onClick = config.onClick, - enabled = config.enabled, - showProgress = false, - colors = TangemButtonsDefaults.backgroundButtonColors, - size = TangemButtonSize.RoundedAction, - ) +private fun Button( + config: ActionButtonConfig, + shape: RoundedCornerShape, + modifier: Modifier = Modifier, + color: Color = TangemTheme.colors.button.secondary, +) { + Row( + modifier = modifier + .clickable(enabled = config.enabled, onClick = config.onClick) + .heightIn(min = TangemTheme.dimens.size36) + .background( + color = if (config.enabled) color else TangemTheme.colors.button.disabled, + shape = shape, + ) + .padding( + start = TangemTheme.dimens.spacing16, + end = TangemTheme.dimens.spacing24, + ) + .padding(vertical = TangemTheme.dimens.spacing8), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + painter = painterResource(id = config.iconResId), + contentDescription = null, + modifier = Modifier.size(size = TangemTheme.dimens.size20), + tint = if (config.enabled) TangemTheme.colors.icon.primary1 else TangemTheme.colors.icon.informative, + ) + + SpacerW8() + + Text( + text = config.text, + color = if (config.enabled) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.disabled, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + style = TangemTheme.typography.button, + ) + } } -@Preview(showBackground = true) +@Preview(group = "RoundedActionButton", showBackground = true) @Composable -private fun Preview_ActionButton_Light(@PreviewParameter(ActionStateProvider::class) state: ActionConfig) { +private fun Preview_RoundedActionButton_Light(@PreviewParameter(ActionStateProvider::class) state: ActionButtonConfig) { TangemTheme(isDark = false) { - Column { - RoundedActionButton(state) - ActionButton(state) - BackgroundActionButton(state) - } + RoundedActionButton(state) } } -@Preview(showBackground = true) +@Preview(group = "RoundedActionButton", showBackground = true) @Composable -private fun Preview_ActionButton_Dark(@PreviewParameter(ActionStateProvider::class) state: ActionConfig) { - TangemTheme { - Column { - RoundedActionButton(state) - ActionButton(state) - BackgroundActionButton(state) - } +private fun Preview_RoundedActionButton_Dark(@PreviewParameter(ActionStateProvider::class) state: ActionButtonConfig) { + TangemTheme(isDark = true) { + RoundedActionButton(state) } } -private class ActionStateProvider : CollectionPreviewParameterProvider( +@Preview(group = "ActionButton", showBackground = true) +@Composable +private fun Preview_ActionButton_Light(@PreviewParameter(ActionStateProvider::class) state: ActionButtonConfig) { + TangemTheme(isDark = false) { + ActionButton(state) + } +} + +@Preview(group = "ActionButton", showBackground = true) +@Composable +private fun Preview_ActionButton_Dark(@PreviewParameter(ActionStateProvider::class) state: ActionButtonConfig) { + TangemTheme(isDark = true) { + ActionButton(state) + } +} + +private class ActionStateProvider : CollectionPreviewParameterProvider( collection = listOf( - ActionConfig(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = {}), - ActionConfig(text = "Receive", iconResId = R.drawable.ic_arrow_down_24, enabled = false, onClick = {}), + ActionButtonConfig(text = "Enabled", iconResId = R.drawable.ic_arrow_up_24, enabled = true, onClick = {}), + ActionButtonConfig(text = "Disabled", iconResId = R.drawable.ic_arrow_down_24, enabled = false, onClick = {}), ), ) \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt index db338c9721..5bc16b167a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt @@ -2,10 +2,11 @@ package com.tangem.core.ui.components.notifications import androidx.annotation.DrawableRes import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -32,19 +33,23 @@ import com.tangem.core.ui.res.TangemTheme */ @Composable fun Notification(state: NotificationState, modifier: Modifier = Modifier) { - Surface( - onClick = if (state is NotificationState.Action) { - state.onClick - } else { - {} - }, - modifier = modifier, - enabled = when (state) { - is NotificationState.Simple -> false - is NotificationState.Action -> true - }, - shape = RoundedCornerShape(TangemTheme.dimens.radius18), - color = TangemTheme.colors.button.secondary, + Box( + modifier = modifier + .clickable( + enabled = when (state) { + is NotificationState.Simple -> false + is NotificationState.Action -> true + }, + onClick = if (state is NotificationState.Action) { + state.onClick + } else { + {} + }, + ) + .background( + color = TangemTheme.colors.button.secondary, + RoundedCornerShape(size = TangemTheme.dimens.radius18), + ), ) { Box( modifier = Modifier diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt index 14449b2c45..27a26b7c76 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt @@ -30,6 +30,7 @@ data class TangemDimens internal constructor( val radius12: Dp = 12.dp, val radius16: Dp = 16.dp, val radius18: Dp = 18.dp, + val radius24: Dp = 24.dp, val radius28: Dp = 28.dp, // endregion Radius // region Size diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index 42f47eeb7f..883b5c626d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -49,6 +49,17 @@ internal object WalletPreviewData { onClick = {}, ) + val walletListConfig = WalletsListConfig( + selectedWalletIndex = 0, + wallets = persistentListOf( + walletCardContentState, + walletCardLoadingState, + walletCardHiddenContentState, + walletCardErrorState, + ), + onWalletChange = {}, + ) + val tokenItemVisibleState = TokenItemState.Content( id = UUID.randomUUID().toString(), tokenIconUrl = null, @@ -195,13 +206,7 @@ internal object WalletPreviewData { val multicurrencyWalletScreenState = WalletStateHolder.MultiCurrencyContent( onBackClick = {}, topBarConfig = walletTopBarConfig, - selectedWallet = walletCardContentState, - wallets = persistentListOf( - walletCardContentState, - walletCardLoadingState, - walletCardHiddenContentState, - walletCardErrorState, - ), + walletsListConfig = walletListConfig, contentItems = persistentListOf( WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle("Bitcoin"), WalletContentItemState.MultiCurrencyItem.Token( @@ -263,13 +268,7 @@ internal object WalletPreviewData { val singleWalletScreenState = WalletStateHolder.SingleCurrencyContent( onBackClick = {}, topBarConfig = walletTopBarConfig, - selectedWallet = walletCardContentState, - wallets = persistentListOf( - walletCardContentState, - walletCardLoadingState, - walletCardHiddenContentState, - walletCardErrorState, - ), + walletsListConfig = walletListConfig, contentItems = persistentListOf( WalletContentItemState.SingleCurrencyItem.Title(onExploreClick = {}), WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle("Today"), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt index 8aacb95163..d0967c3046 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt @@ -23,8 +23,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.components.SecondaryButton -import com.tangem.core.ui.components.buttons.actions.ActionConfig -import com.tangem.core.ui.components.buttons.actions.BackgroundActionButton +import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig +import com.tangem.core.ui.components.buttons.actions.RoundedActionButton import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.common.WalletPreviewData @@ -206,21 +206,23 @@ private fun TopBar( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), ) { - BackgroundActionButton( - config = ActionConfig( + RoundedActionButton( + config = ActionButtonConfig( text = stringResource(id = R.string.organize_tokens_sort_by_balance), iconResId = R.drawable.ic_sort_24, onClick = config.onSortByBalanceClick, ), modifier = Modifier.weight(1f), + color = TangemTheme.colors.background.primary, ) - BackgroundActionButton( - config = ActionConfig( + RoundedActionButton( + config = ActionButtonConfig( text = stringResource(id = R.string.organize_tokens_group), iconResId = R.drawable.ic_group_24, onClick = config.onGroupByNetworkClick, ), modifier = Modifier.weight(1f), + color = TangemTheme.colors.background.primary, ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index b963f8f7b7..0e1c8436b3 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -34,10 +34,7 @@ internal class DefaultWalletRouter : InnerWalletRouter { ) { composable(WalletScreens.WALLET.name) { val viewModel = hiltViewModel().apply { router = this@DefaultWalletRouter } - WalletScreen( - modifier = Modifier.systemBarsPadding(), - state = viewModel.uiState, - ) + WalletScreen(state = viewModel.uiState) } composable(WalletScreens.ORGANIZE_TOKENS.name) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButton.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButton.kt index c4e41ed1b6..e5f6115aaa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButton.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButton.kt @@ -1,6 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.state -import com.tangem.core.ui.components.buttons.actions.ActionConfig +import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig import com.tangem.feature.wallet.impl.R /** @@ -10,7 +10,7 @@ import com.tangem.feature.wallet.impl.R * [REDACTED_AUTHOR] */ -sealed class WalletManageButton(val config: ActionConfig) { +sealed class WalletManageButton(val config: ActionButtonConfig) { /** * Buy @@ -18,7 +18,7 @@ sealed class WalletManageButton(val config: ActionConfig) { * @param onClick lambda be invoked when manage button is clicked */ data class Buy(val onClick: () -> Unit) : WalletManageButton( - config = ActionConfig( + config = ActionButtonConfig( text = "Buy", iconResId = R.drawable.ic_plus_24, onClick = onClick, @@ -31,7 +31,7 @@ sealed class WalletManageButton(val config: ActionConfig) { * @param onClick lambda be invoked when manage button is clicked */ data class Send(val onClick: () -> Unit) : WalletManageButton( - config = ActionConfig( + config = ActionButtonConfig( text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = onClick, @@ -44,7 +44,7 @@ sealed class WalletManageButton(val config: ActionConfig) { * @param onClick lambda be invoked when manage button is clicked */ data class Receive(val onClick: () -> Unit) : WalletManageButton( - config = ActionConfig( + config = ActionButtonConfig( text = "Receive", iconResId = R.drawable.ic_arrow_down_24, onClick = onClick, @@ -57,7 +57,7 @@ sealed class WalletManageButton(val config: ActionConfig) { * @param onClick lambda be invoked when manage button is clicked */ data class Exchange(val onClick: () -> Unit) : WalletManageButton( - config = ActionConfig( + config = ActionButtonConfig( text = "Exchange", iconResId = R.drawable.ic_exchange_vertical_24, onClick = onClick, @@ -70,7 +70,7 @@ sealed class WalletManageButton(val config: ActionConfig) { * @param onClick lambda be invoked when manage button is clicked */ data class CopyAddress(val onClick: () -> Unit) : WalletManageButton( - config = ActionConfig( + config = ActionButtonConfig( text = "Copy address", iconResId = R.drawable.ic_copy_24, onClick = onClick, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt index 966ff09e16..1fd2c49db9 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt @@ -1,5 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.state +import androidx.compose.foundation.background import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -20,14 +21,16 @@ import kotlinx.collections.immutable.ImmutableList * Wallet manage buttons * * @param buttons manage buttons + * @param modifier modifier * [REDACTED_AUTHOR] */ @Composable -internal fun WalletManageButtons(buttons: ImmutableList) { +internal fun WalletManageButtons(buttons: ImmutableList, modifier: Modifier = Modifier) { Row( - modifier = Modifier + modifier = modifier .horizontalScroll(state = rememberScrollState()) + .background(color = TangemTheme.colors.background.secondary) .fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing8), ) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateHolder.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateHolder.kt index a1bcc27c31..0e9c80a61a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateHolder.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateHolder.kt @@ -5,20 +5,18 @@ import kotlinx.collections.immutable.ImmutableList /** * Wallet screen state holder * - * @property onBackClick lambda be invoked when back button is clicked - * @property topBarConfig top bar config - * @property selectedWallet selected wallet - * @property wallets list of wallets states - * @property contentItems content items - * @property notifications notifications + * @property onBackClick lambda be invoked when back button is clicked + * @property topBarConfig top bar config + * @property walletsListConfig wallets list config + * @property contentItems content items + * @property notifications notifications * [REDACTED_AUTHOR] */ internal sealed class WalletStateHolder( open val onBackClick: () -> Unit, open val topBarConfig: WalletTopBarConfig, - open val selectedWallet: WalletCardState, - open val wallets: ImmutableList, + open val walletsListConfig: WalletsListConfig, open val contentItems: ImmutableList, open val notifications: ImmutableList, ) { @@ -28,8 +26,7 @@ internal sealed class WalletStateHolder( * * @property onBackClick lambda be invoked when back button is clicked * @property topBarConfig top bar config - * @property selectedWallet selected wallet - * @property wallets list of wallets states + * @property walletsListConfig wallets list config * @property contentItems content items * @property notifications notifications * @property onOrganizeTokensClick lambda be invoked when organize tokens button is clicked @@ -37,31 +34,28 @@ internal sealed class WalletStateHolder( data class MultiCurrencyContent( override val onBackClick: () -> Unit, override val topBarConfig: WalletTopBarConfig, - override val selectedWallet: WalletCardState, - override val wallets: ImmutableList, + override val walletsListConfig: WalletsListConfig, override val contentItems: ImmutableList, override val notifications: ImmutableList, val onOrganizeTokensClick: () -> Unit, - ) : WalletStateHolder(onBackClick, topBarConfig, selectedWallet, wallets, contentItems, notifications) + ) : WalletStateHolder(onBackClick, topBarConfig, walletsListConfig, contentItems, notifications) /** * Single currency wallet content state * - * @property onBackClick lambda be invoked when back button is clicked - * @property topBarConfig top bar config - * @property selectedWallet selected wallet - * @property wallets list of wallets states - * @property contentItems content items - * @property notifications notifications - * @property buttons manage buttons + * @property onBackClick lambda be invoked when back button is clicked + * @property topBarConfig top bar config + * @property walletsListConfig wallets list config + * @property contentItems content items + * @property notifications notifications + * @property buttons manage buttons */ data class SingleCurrencyContent( override val onBackClick: () -> Unit, override val topBarConfig: WalletTopBarConfig, - override val selectedWallet: WalletCardState, - override val wallets: ImmutableList, + override val walletsListConfig: WalletsListConfig, override val contentItems: ImmutableList, override val notifications: ImmutableList, val buttons: ImmutableList, - ) : WalletStateHolder(onBackClick, topBarConfig, selectedWallet, wallets, contentItems, notifications) + ) : WalletStateHolder(onBackClick, topBarConfig, walletsListConfig, contentItems, notifications) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletsListConfig.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletsListConfig.kt new file mode 100644 index 0000000000..0349eb57bd --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletsListConfig.kt @@ -0,0 +1,18 @@ +package com.tangem.feature.wallet.presentation.wallet.state + +import kotlinx.collections.immutable.ImmutableList + +/** + * Wallets list config + * + * @property selectedWalletIndex selected wallet index + * @property wallets wallets list + * @property onWalletChange lambda be invoked when wallet is swiped + * +[REDACTED_AUTHOR] + */ +internal data class WalletsListConfig( + val selectedWalletIndex: Int, + val wallets: ImmutableList, + val onWalletChange: (Int) -> Unit, +) \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index 7378c104e0..2246159c2f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -4,11 +4,8 @@ import androidx.activity.compose.BackHandler import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.Icon -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -18,7 +15,7 @@ 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 com.tangem.core.ui.components.buttons.actions.ActionConfig +import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig import com.tangem.core.ui.components.buttons.actions.RoundedActionButton import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.components.transactions.Transaction @@ -30,9 +27,10 @@ import com.tangem.feature.wallet.presentation.common.component.TokenItem import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState import com.tangem.feature.wallet.presentation.wallet.state.WalletManageButtons import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder -import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletCardsList import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletTopBar +import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletContentItemDecoration +import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletNotificationDecoration /** * Wallet screen @@ -42,7 +40,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletConten [REDACTED_AUTHOR] */ @Composable -internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifier) { +internal fun WalletScreen(state: WalletStateHolder) { BackHandler(onBack = state.onBackClick) Scaffold( @@ -51,27 +49,42 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie ) { scaffoldPaddings -> LazyColumn( - modifier = modifier + modifier = Modifier .padding(paddingValues = scaffoldPaddings) .fillMaxSize(), - contentPadding = PaddingValues( - horizontal = TangemTheme.dimens.spacing16, - vertical = TangemTheme.dimens.spacing8, - ), + contentPadding = PaddingValues(vertical = TangemTheme.dimens.spacing8), horizontalAlignment = Alignment.CenterHorizontally, ) { item { - WalletCardsList( - wallets = state.wallets, - modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12), + WalletsList( + config = state.walletsListConfig, + modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing14), ) } if (state is WalletStateHolder.SingleCurrencyContent) { - item { WalletManageButtons(buttons = state.buttons) } + item { + WalletManageButtons( + buttons = state.buttons, + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.spacing16) + .padding(bottom = TangemTheme.dimens.spacing14), + ) + } } - items(items = state.notifications, itemContent = { Notification(state = it.state) }) + itemsIndexed( + items = state.notifications, + itemContent = { index, item -> + Notification( + state = item.state, + modifier = Modifier.walletNotificationDecoration( + currentIndex = index, + lastIndex = state.notifications.lastIndex, + ), + ) + }, + ) itemsIndexed( items = state.contentItems, @@ -85,45 +98,40 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie } }, itemContent = { index, item -> - ContentItem(currentIndex = index, lastIndex = state.contentItems.lastIndex, item = item) + ContentItem( + item = item, + modifier = Modifier.walletContentItemDecoration( + currentIndex = index, + lastIndex = state.contentItems.lastIndex, + ), + ) }, ) if (state is WalletStateHolder.MultiCurrencyContent) { - item { - RoundedActionButton( - config = ActionConfig( - text = stringResource(id = R.string.organize_tokens_title), - iconResId = R.drawable.ic_filter_24, - onClick = state.onOrganizeTokensClick, - ), - modifier = Modifier.padding(top = TangemTheme.dimens.spacing14), - ) - } + item { OrganizeTokensButton(onClick = state.onOrganizeTokensClick) } } } } } @Composable -private fun ContentItem(currentIndex: Int, lastIndex: Int, item: WalletContentItemState) { - val itemModifier = Modifier.walletContentItemDecoration(currentIndex, lastIndex) - +private fun ContentItem(item: WalletContentItemState, modifier: Modifier = Modifier) { when (item) { is WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle -> { - NetworkGroupItem(networkName = item.networkName, modifier = itemModifier) + NetworkGroupItem(networkName = item.networkName, modifier = modifier) } is WalletContentItemState.MultiCurrencyItem.Token -> { - TokenItem(state = item.state, modifier = itemModifier) + TokenItem(state = item.state, modifier = modifier) } is WalletContentItemState.SingleCurrencyItem.Title -> { - SingleCurrencyTitle(config = item, modifier = itemModifier) + SingleCurrencyTitle(config = item, modifier = modifier) } is WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle -> { - TransactionGroupTitle(config = item, modifier = itemModifier) + TransactionGroupTitle(config = item, modifier = modifier) } is WalletContentItemState.SingleCurrencyItem.Transaction -> { - Transaction(state = item.state, modifier = itemModifier) + Transaction(state = item.state, modifier = modifier) } } } @@ -186,8 +194,22 @@ private fun TransactionGroupTitle( ) } +@Composable +private fun OrganizeTokensButton(onClick: () -> Unit) { + RoundedActionButton( + config = ActionButtonConfig( + text = stringResource(id = R.string.organize_tokens_title), + iconResId = R.drawable.ic_filter_24, + onClick = onClick, + ), + modifier = Modifier + .padding(top = TangemTheme.dimens.spacing8) + .padding(horizontal = TangemTheme.dimens.spacing16), + ) +} + // region Preview -@Preview(showBackground = true, widthDp = 360) +@Preview @Composable private fun WalletScreenPreview_Light( @PreviewParameter(WalletScreenParameterProvider::class) state: WalletStateHolder, @@ -197,7 +219,7 @@ private fun WalletScreenPreview_Light( } } -@Preview(showBackground = true, widthDp = 360) +@Preview @Composable private fun WalletScreenPreview_Dark( @PreviewParameter(WalletScreenParameterProvider::class) state: WalletStateHolder, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCardsList.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletsList.kt similarity index 50% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCardsList.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletsList.kt index bbb62e7aa9..bba70f8c1a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCardsList.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletsList.kt @@ -1,15 +1,17 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components -import androidx.compose.animation.core.* import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material3.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.tooling.preview.Preview @@ -17,20 +19,24 @@ import androidx.compose.ui.unit.dp import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.wallet.presentation.common.WalletPreviewData import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf +import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.flow.FlowCollector + +private const val MIN_OFFSET = -2 +private const val MAX_OFFSET = 2 /** - * Wallets list + * Wallets list component * - * @param wallets list of wallet state + * @param config config * @param modifier modifier * [REDACTED_AUTHOR] */ -@OptIn(ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class, InternalCoroutinesApi::class) @Composable -internal fun WalletCardsList(wallets: ImmutableList, modifier: Modifier = Modifier) { +internal fun WalletsList(config: WalletsListConfig, modifier: Modifier = Modifier) { val horizontalCardPadding = TangemTheme.dimens.spacing16 val itemWidth = LocalConfiguration.current.screenWidthDp.dp - horizontalCardPadding * 2 @@ -38,27 +44,35 @@ internal fun WalletCardsList(wallets: ImmutableList, modifier: LazyRow( modifier = modifier.background(color = TangemTheme.colors.background.secondary), state = lazyListState, + contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16), horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), flingBehavior = rememberSnapFlingBehavior(lazyListState = lazyListState), ) { - items(items = wallets, key = WalletCardState::id) { state -> + items(items = config.wallets, key = WalletCardState::id) { state -> WalletCard(state = state, modifier = Modifier.width(itemWidth)) } } + + LaunchedEffect(lazyListState) { + snapshotFlow(lazyListState::firstVisibleItemScrollOffset) + .collect( + collector = FlowCollector { firstVisibleItemScrollOffset -> + val itemSize = lazyListState.layoutInfo.visibleItemsInfo.firstOrNull()?.size ?: 1 + val offset = lazyListState.firstVisibleItemIndex * itemSize + firstVisibleItemScrollOffset + val currentIndex = offset / itemSize + if (offset - currentIndex * itemSize in MIN_OFFSET..MAX_OFFSET) { + config.onWalletChange(currentIndex) + } + }, + ) + } } @Preview @Composable private fun Preview_WalletHeader_LightTheme() { TangemTheme(isDark = false) { - WalletCardsList( - wallets = persistentListOf( - WalletPreviewData.walletCardContentState, - WalletPreviewData.walletCardLoadingState, - WalletPreviewData.walletCardHiddenContentState, - WalletPreviewData.walletCardErrorState, - ), - ) + WalletsList(config = WalletPreviewData.walletListConfig) } } @@ -66,13 +80,6 @@ private fun Preview_WalletHeader_LightTheme() { @Composable private fun Preview_WalletHeader_DarkTheme() { TangemTheme(isDark = true) { - WalletCardsList( - wallets = persistentListOf( - WalletPreviewData.walletCardContentState, - WalletPreviewData.walletCardLoadingState, - WalletPreviewData.walletCardHiddenContentState, - WalletPreviewData.walletCardErrorState, - ), - ) + WalletsList(config = WalletPreviewData.walletListConfig) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletContentItemDecoration.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletContentItemDecoration.kt index 9ec810b323..ea04e144c4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletContentItemDecoration.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletContentItemDecoration.kt @@ -10,10 +10,11 @@ import com.tangem.core.ui.res.TangemTheme /** [REDACTED_AUTHOR] */ -internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastItemIndex: Int): Modifier = composed { +internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastIndex: Int): Modifier = composed { + val modifierWithHorizontalPadding = this.padding(horizontal = TangemTheme.dimens.spacing16) when (currentIndex) { 0 -> { - this + modifierWithHorizontalPadding .padding(top = TangemTheme.dimens.spacing14) .clip( RoundedCornerShape( @@ -22,8 +23,8 @@ internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastItemInd ), ) } - lastItemIndex -> { - this + lastIndex -> { + modifierWithHorizontalPadding .clip( RoundedCornerShape( bottomStart = TangemTheme.dimens.radius16, @@ -31,6 +32,6 @@ internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastItemInd ), ) } - else -> this + else -> modifierWithHorizontalPadding } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletNotificationDecoration.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletNotificationDecoration.kt new file mode 100644 index 0000000000..cd2cc0a5f1 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletNotificationDecoration.kt @@ -0,0 +1,24 @@ +package com.tangem.feature.wallet.presentation.wallet.ui.decorations + +import androidx.compose.foundation.layout.padding +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import com.tangem.core.ui.res.TangemTheme + +/** + * Wallet notification decoration + * + * @param currentIndex current index + * @param lastIndex last index + * +[REDACTED_AUTHOR] + */ +internal fun Modifier.walletNotificationDecoration(currentIndex: Int, lastIndex: Int): Modifier = composed { + val modifierWithHorizontalPadding = this.padding(horizontal = TangemTheme.dimens.spacing16) + + if (currentIndex != lastIndex) { + modifierWithHorizontalPadding.padding(bottom = TangemTheme.dimens.spacing14) + } else { + modifierWithHorizontalPadding + } +} \ No newline at end of file From d9f1eaa91dc0a64fbc7a69df28e8526627a449d8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 Jun 2023 17:37:15 +0300 Subject: [PATCH 51/54] Updated on 2026-08-14 --- gradle/dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 58b9e2bdcc..25b763b42a 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -78,7 +78,7 @@ walletConnectWeb3 = "1.8.0" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-253" +tangemBlockchainSdk = "develop-256" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-266" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds From 9112d2bab89d2f423cca30f9c2fcbf0b23a33a93 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 Jun 2023 09:26:53 +0800 Subject: [PATCH 52/54] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 10 ++ .../converters/ParamCardCurrencyConverter.kt | 6 +- .../converters/TopUpEventConverter.kt | 6 +- .../CardContextInterceptor.kt | 5 +- .../LinkedCardContextInterceptor.kt | 6 +- .../common/analytics/topup/TopUpController.kt | 12 +-- .../tangem/tap/common/extensions/Analytics.kt | 13 ++- .../java/com/tangem/tap/di/ActivityModule.kt | 9 +- .../com/tangem/tap/domain/TangemSdkManager.kt | 14 ++- .../com/tangem/tap/domain/TapWalletManager.kt | 15 +-- .../domain/extensions/WalletManagerFactory.kt | 49 ++------- .../model/builders/UserWalletBuilder.kt | 7 +- .../model/builders/WalletStoreBuilder.kt | 25 +++-- .../domain/scanCard/LegacyScanProcessor.kt | 31 ++++-- .../domain/scanCard/UseCaseScanProcessor.kt | 7 +- .../domain/scanCard/chains/AnalyticsChain.kt | 7 +- .../chains/CheckForOnboardingChain.kt | 16 ++- .../tasks/product/CreateProductWalletTask.kt | 12 +-- .../di/WalletCurrenciesManagerProvider.kt | 5 + .../DefaultWalletCurrenciesManager.kt | 9 +- .../di/WalletsStoresManagerProvider.kt | 12 +-- .../DefaultWalletStoresManager.kt | 22 ++-- .../repository/di/RepositoryProvider.kt | 5 +- .../DefaultWalletManagersRepository.kt | 32 ++---- .../demo/DemoOnboardingNoteMiddleware.kt | 14 ++- .../features/details/redux/DetailsAction.kt | 3 +- .../details/redux/DetailsMiddleware.kt | 20 ++-- .../features/details/redux/DetailsReducer.kt | 61 +++++------ .../walletconnect/WalletConnectMiddleware.kt | 4 +- .../details/ui/details/DetailsViewModel.kt | 10 +- .../tap/features/home/redux/HomeMiddleware.kt | 14 ++- .../features/onboarding/OnboardingHelper.kt | 25 +++-- .../note/redux/OnboardingNoteMiddleware.kt | 14 ++- .../redux/OnboardingOtherCardsMiddleware.kt | 13 +-- .../twins/redux/TwinCardsMiddleware.kt | 6 +- .../products/twins/redux/TwinCardsReducer.kt | 6 +- .../redux/OnboardingWalletMiddleware.kt | 14 +-- .../saveWallet/redux/SaveWalletMiddleware.kt | 13 ++- .../tap/features/wallet/redux/WalletState.kt | 4 - .../middlewares/MultiWalletMiddleware.kt | 6 +- .../redux/middlewares/WarningsMiddleware.kt | 11 +- .../tap/features/wallet/ui/WalletViewModel.kt | 5 +- .../redux/WalletSelectorMiddleware.kt | 7 +- .../redux/WalletSelectorReducer.kt | 8 +- .../welcome/redux/WelcomeMiddleware.kt | 8 +- .../tap/legacy/card/LegacyCardTypeResolver.kt | 100 ++++++++++++++++++ .../tap/legacy/card/di/LegacyCardModule.kt | 34 ++++++ .../tangem/tap/proxy/DerivationManagerImpl.kt | 4 +- .../com/tangem/tap/proxy/di/ProxyModule.kt | 4 +- .../tap/proxy/redux/DaggerGraphState.kt | 2 + .../CardTypeResolver.kt} | 10 +- .../java/com/tangem/domain/common/Provider.kt | 10 ++ .../domain/common/TangemCardTypesResolver.kt | 77 -------------- .../tangem/domain/common/TapWorkarounds.kt | 28 +---- .../common/util/ScanResponseExtensions.kt | 11 +- 55 files changed, 492 insertions(+), 389 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/legacy/card/LegacyCardTypeResolver.kt create mode 100644 app/src/main/java/com/tangem/tap/legacy/card/di/LegacyCardModule.kt rename domain/legacy/src/main/java/com/tangem/domain/{common/CardTypesResolver.kt => card/CardTypeResolver.kt} (84%) create mode 100644 domain/legacy/src/main/java/com/tangem/domain/common/Provider.kt delete mode 100644 domain/legacy/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 114746ccdb..f043370e21 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -20,7 +20,9 @@ import com.tangem.datasource.config.FeaturesLocalLoader import com.tangem.datasource.config.models.Config import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.domain.DomainLayer +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.LogConfig +import com.tangem.domain.common.Provider import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.tap.common.analytics.AnalyticsFactory @@ -82,6 +84,7 @@ private val walletManagersRepository by lazy { ?.blockchainSdkConfig ?: BlockchainSdkConfig(), ), + cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) }, ) } private val walletAmountsRepository by lazy { @@ -96,6 +99,7 @@ val walletStoresManager by lazy { walletManagersRepository = walletManagersRepository, walletAmountsRepository = walletAmountsRepository, appCurrencyProvider = { store.state.globalState.appCurrency }, + cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) }, ) } val walletCurrenciesManager by lazy { @@ -105,6 +109,7 @@ val walletCurrenciesManager by lazy { walletManagersRepository = walletManagersRepository, walletAmountsRepository = walletAmountsRepository, appCurrencyProvider = { store.state.globalState.appCurrency }, + cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) }, ) } val totalFiatBalanceCalculator by lazy { @@ -147,6 +152,9 @@ class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var learn2earnInteractor: Learn2earnInteractor + @Inject + lateinit var cardTypeResolver: CardTypeResolver + override fun onCreate() { super.onCreate() @@ -163,6 +171,7 @@ class TapApplication : Application(), ImageLoaderFactory { walletFeatureToggles = walletFeatureToggles, walletConnectRepository = walletConnect2Repository, walletConnectSessionsRepository = walletConnectSessionsRepository, + cardTypeResolver = cardTypeResolver, ), ), ) @@ -219,6 +228,7 @@ class TapApplication : Application(), ImageLoaderFactory { }, walletStoresManagerProvider = { walletStoresManager }, topupWalletStorage = preferencesStorage.toppedUpWalletStorage, + cardTypeResolver = cardTypeResolver, ) store.dispatch(GlobalAction.SetTopUpController(topUpController)) } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt index 0a7928efd5..5b60885d4b 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt @@ -2,15 +2,15 @@ package com.tangem.tap.common.analytics.converters import com.tangem.blockchain.common.Blockchain import com.tangem.common.Converter -import com.tangem.domain.common.CardTypesResolver +import com.tangem.domain.card.CardTypeResolver import com.tangem.tap.common.analytics.events.AnalyticsParam /** [REDACTED_AUTHOR] */ -class ParamCardCurrencyConverter : Converter { +class ParamCardCurrencyConverter : Converter { - override fun convert(value: CardTypesResolver): AnalyticsParam.CardCurrency? { + override fun convert(value: CardTypeResolver): AnalyticsParam.CardCurrency? { if (value.isMultiwalletAllowed()) return AnalyticsParam.CardCurrency.MultiCurrency val type = when { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpEventConverter.kt index 429b2e5ebc..29b374687f 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpEventConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpEventConverter.kt @@ -1,15 +1,15 @@ package com.tangem.tap.common.analytics.converters import com.tangem.common.Converter -import com.tangem.domain.common.CardTypesResolver +import com.tangem.domain.card.CardTypeResolver import com.tangem.tap.common.analytics.events.Basic /** [REDACTED_AUTHOR] */ -class TopUpEventConverter : Converter { +class TopUpEventConverter : Converter { - override fun convert(value: CardTypesResolver): Basic.ToppedUp? { + override fun convert(value: CardTypeResolver): Basic.ToppedUp? { val paramCardCurrency = ParamCardCurrencyConverter().convert(value) ?: return null return Basic.ToppedUp(paramCardCurrency) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt index 864c9dadbb..e35f0f1143 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt @@ -2,7 +2,7 @@ package com.tangem.tap.common.analytics.paramsInterceptor import com.tangem.core.analytics.AnalyticsEvent import com.tangem.core.analytics.api.ParamsInterceptor -import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter @@ -16,6 +16,7 @@ import com.tangem.tap.features.demo.DemoHelper */ class CardContextInterceptor( private val scanResponse: ScanResponse?, + private val cardTypeResolver: CardTypeResolver, ) : ParamsInterceptor { override fun id(): String = CardContextInterceptor.id() @@ -35,7 +36,7 @@ class CardContextInterceptor( params[AnalyticsParam.PRODUCT_TYPE] = getProductType(scanResponse) params[AnalyticsParam.FIRMWARE] = card.firmwareVersion.stringValue - ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver)?.let { + ParamCardCurrencyConverter().convert(cardTypeResolver)?.let { params[AnalyticsParam.CURRENCY] = it.value } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt index 94c006d699..5cf8c767fb 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt @@ -2,17 +2,19 @@ package com.tangem.tap.common.analytics.paramsInterceptor import com.tangem.core.analytics.AnalyticsEvent import com.tangem.core.analytics.api.ParamsInterceptor +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.models.scan.ScanResponse /** [REDACTED_AUTHOR] */ class LinkedCardContextInterceptor( - private val scanResponse: ScanResponse, + scanResponse: ScanResponse, + cardTypeResolver: CardTypeResolver, val parent: LinkedCardContextInterceptor? = null, ) : ParamsInterceptor { - private val contextInterceptor = CardContextInterceptor(scanResponse) + private val contextInterceptor = CardContextInterceptor(scanResponse, cardTypeResolver) override fun id(): String = LinkedCardContextInterceptor.id() diff --git a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt index 97edaae4c1..27cea44be1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt @@ -5,9 +5,8 @@ import com.tangem.common.extensions.isZero import com.tangem.core.analytics.Analytics import com.tangem.data.source.preferences.model.DataSourceTopupInfo import com.tangem.data.source.preferences.storage.ToppedUpWalletStorage -import com.tangem.domain.common.CardTypesResolver +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.util.UserWalletId -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.analytics.converters.TopUpEventConverter import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -32,6 +31,7 @@ class TopUpController( var scanResponseProvider: (() -> ScanResponse?)? = null, var walletStoresManagerProvider: (() -> WalletStoresManager)? = null, private val topupWalletStorage: ToppedUpWalletStorage, + private val cardTypeResolver: CardTypeResolver, ) : WalletCurrenciesManager.Listener { private var hadMissedDerivations: Boolean = false @@ -100,7 +100,7 @@ class TopUpController( } val cardBalanceState = BalanceCalculator(walletDataModels).calculate().toCardBalanceState() - send(userWalletId, cardBalanceState, scanResponse.cardTypesResolver) + send(userWalletId, cardBalanceState, cardTypeResolver) } } @@ -120,14 +120,14 @@ class TopUpController( fun send(scanResponse: ScanResponse, cardBalanceState: AnalyticsParam.CardBalanceState) { UserWalletIdBuilder.scanResponse(scanResponse).build()?.let { - send(it, cardBalanceState, scanResponse.cardTypesResolver) + send(it, cardBalanceState, cardTypeResolver) } } fun send( userWalletId: UserWalletId, cardBalanceState: AnalyticsParam.CardBalanceState, - cardTypesResolver: CardTypesResolver, + cardTypeResolver: CardTypeResolver, ) { val topupInfo = topupWalletStorage.restore(userWalletId.stringValue).guard { val topupInfo = DataSourceTopupInfo( @@ -152,7 +152,7 @@ class TopUpController( if (cardBalanceState.isToppedUp()) { topupWalletStorage.save(topupInfo.copy(cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full)) - TopUpEventConverter().convert(cardTypesResolver)?.let { + TopUpEventConverter().convert(cardTypeResolver)?.let { Analytics.send(it) } } diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt b/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt index 8e79d07381..58c13e282c 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt @@ -1,6 +1,7 @@ package com.tangem.tap.common.extensions import com.tangem.core.analytics.Analytics +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterceptor @@ -11,8 +12,8 @@ import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterc /** * Sets the new context */ -fun Analytics.setContext(scanResponse: ScanResponse) { - addParamsInterceptor(LinkedCardContextInterceptor(scanResponse)) +fun Analytics.setContext(scanResponse: ScanResponse, cardTypeResolver: CardTypeResolver) { + addParamsInterceptor(LinkedCardContextInterceptor(scanResponse, cardTypeResolver)) } /** @@ -25,9 +26,13 @@ fun Analytics.eraseContext() { /** * Adds a new context and keeps a previous context as the parent of the new one */ -fun Analytics.addContext(scanResponse: ScanResponse) { +fun Analytics.addContext(scanResponse: ScanResponse, cardTypeResolver: CardTypeResolver) { val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) as? LinkedCardContextInterceptor - val newContext = LinkedCardContextInterceptor(scanResponse, parent = currentContext) + val newContext = LinkedCardContextInterceptor( + scanResponse = scanResponse, + cardTypeResolver = cardTypeResolver, + parent = currentContext, + ) addParamsInterceptor(newContext) } diff --git a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt index 96639f64e4..67ce9fa481 100644 --- a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt +++ b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt @@ -3,6 +3,7 @@ package com.tangem.tap.di import android.content.Context import androidx.fragment.app.FragmentActivity import com.tangem.TangemSdk +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.card.ScanCardUseCase import com.tangem.sdk.extensions.initWithBiometrics import com.tangem.tap.domain.TangemSdkManager @@ -27,8 +28,12 @@ internal object ActivityModule { @Provides @ActivityScoped - fun provideTangemSdkManager(@ActivityContext context: Context, tangemSdk: TangemSdk): TangemSdkManager { - return TangemSdkManager(tangemSdk, context) + fun provideTangemSdkManager( + @ActivityContext context: Context, + tangemSdk: TangemSdk, + cardTypeResolver: CardTypeResolver, + ): TangemSdkManager { + return TangemSdkManager(tangemSdk, context, cardTypeResolver) } @Provides diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index c395569c5c..83ddb84e62 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -14,7 +14,7 @@ import com.tangem.common.usersCode.UserCodeRepository import com.tangem.core.analytics.Analytics import com.tangem.crypto.bip39.DefaultMnemonic import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.operations.ScanTask @@ -38,7 +38,11 @@ import kotlinx.coroutines.withContext import kotlin.coroutines.resume @Suppress("TooManyFunctions") -class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) { +class TangemSdkManager( + private val tangemSdk: TangemSdk, + private val context: Context, + private val cardTypeResolver: CardTypeResolver, +) { private val userCodeRepository by lazy { UserCodeRepository( @@ -78,7 +82,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult { return runTaskAsync( - CreateProductWalletTask(scanResponse.cardTypesResolver), + CreateProductWalletTask(cardTypeResolver), scanResponse.card.cardId, Message(context.getString(R.string.initial_message_create_wallet_body)), ) @@ -90,7 +94,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co ): CompletionResult { return when (val seedResult = DefaultMnemonic(mnemonic, tangemSdk.wordlist).generateSeed()) { is CompletionResult.Success -> runTaskAsync( - CreateProductWalletTask(scanResponse.cardTypesResolver, seedResult.data), + CreateProductWalletTask(cardTypeResolver, seedResult.data), scanResponse.card.cardId, Message(context.getString(R.string.initial_message_create_wallet_body)), ) @@ -228,7 +232,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?) { tangemSdk.config.cardIdDisplayFormat = when { scanResponse == null -> CardIdDisplayFormat.Full - scanResponse.cardTypesResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4) + cardTypeResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4) else -> CardIdDisplayFormat.Full } } diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 4e39b73bbe..ae8c0cc795 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -9,8 +9,6 @@ import com.tangem.common.doOnSuccess import com.tangem.core.analytics.Analytics import com.tangem.datasource.config.ConfigManager import com.tangem.domain.common.extensions.withMainContext -import com.tangem.domain.common.util.cardTypesResolver -import com.tangem.domain.models.scan.ScanResponse import com.tangem.operations.attestation.Attestation import com.tangem.tap.* import com.tangem.tap.common.analytics.events.Basic @@ -25,6 +23,7 @@ import com.tangem.tap.features.disclaimer.createDisclaimer import com.tangem.tap.features.disclaimer.redux.DisclaimerAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.CoroutineScope @@ -58,7 +57,10 @@ class TapWalletManager( } private suspend fun loadUserWalletData(userWallet: UserWallet, refresh: Boolean, sendAnalyticsEvent: Boolean) { - Analytics.setContext(userWallet.scanResponse) + Analytics.setContext( + scanResponse = userWallet.scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) if (sendAnalyticsEvent) { Analytics.send(Basic.WalletOpened()) } @@ -68,7 +70,7 @@ class TapWalletManager( tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse) store.state.globalState.feedbackManager?.infoHolder?.setCardInfo(scanResponse) - updateConfigManager(scanResponse) + updateConfigManager() withMainContext { // Order is important store.dispatch(DisclaimerAction.SetDisclaimer(card.createDisclaimer())) @@ -135,10 +137,11 @@ class TapWalletManager( } } - fun updateConfigManager(data: ScanResponse) { + fun updateConfigManager() { val configManager = store.state.globalState.configManager + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - if (data.cardTypesResolver.isStart2Coin()) { + if (cardTypeResolver.isStart2Coin()) { configManager?.turnOff(ConfigManager.IS_TOP_UP_ENABLED) } else { configManager?.resetToDefault(ConfigManager.IS_TOP_UP_ENABLED) diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt index a9de7cb47a..c2776941b7 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt @@ -1,24 +1,19 @@ package com.tangem.tap.domain.extensions -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.DerivationParams -import com.tangem.blockchain.common.DerivationStyle -import com.tangem.blockchain.common.WalletManager -import com.tangem.blockchain.common.WalletManagerFactory +import com.tangem.blockchain.common.* import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toMapKey import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.domain.tokens.models.BlockchainNetwork -import com.tangem.tap.features.wallet.models.Currency fun WalletManagerFactory.makeWalletManagerForApp( scanResponse: ScanResponse, + cardTypeResolver: CardTypeResolver, blockchain: Blockchain, derivationParams: DerivationParams?, ): WalletManager? { @@ -34,7 +29,7 @@ fun WalletManagerFactory.makeWalletManagerForApp( val seedKey = wallet.extendedPublicKey return when { - scanResponse.cardTypesResolver.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> { + cardTypeResolver.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> { makeTwinWalletManager( walletPublicKey = wallet.publicKey, pairPublicKey = scanResponse.secondTwinPublicKey!!.hexToBytes(), @@ -68,17 +63,6 @@ fun WalletManagerFactory.makeWalletManagerForApp( } } -fun WalletManagerFactory.makeWalletManagerForApp( - scanResponse: ScanResponse, - blockchainNetwork: BlockchainNetwork, -): WalletManager? { - return makeWalletManagerForApp( - scanResponse, - blockchain = blockchainNetwork.blockchain, - derivationParams = getDerivationParams(blockchainNetwork.derivationPath, scanResponse.card), - ) -} - private fun getDerivationParams(derivationPath: String?, card: CardDTO): DerivationParams? { return derivationPath?.let { DerivationParams.Custom( @@ -93,32 +77,19 @@ private fun getDerivationParams(derivationPath: String?, card: CardDTO): Derivat } } -fun WalletManagerFactory.makeWalletManagerForApp(scanResponse: ScanResponse, currency: Currency): WalletManager? { - return makeWalletManagerForApp( - scanResponse, - blockchain = currency.blockchain, - derivationParams = getDerivationParams(currency.derivationPath, scanResponse.card), - ) -} - -fun WalletManagerFactory.makeWalletManagersForApp( +fun WalletManagerFactory.makePrimaryWalletManager( scanResponse: ScanResponse, - blockchains: List, -): List { - return blockchains - .filter { it.isBlockchain() } - .mapNotNull { this.makeWalletManagerForApp(scanResponse, it) } -} - -fun WalletManagerFactory.makePrimaryWalletManager(scanResponse: ScanResponse): WalletManager? { + cardTypeResolver: CardTypeResolver, +): WalletManager? { val blockchain = if (scanResponse.card.isTestCard) { - scanResponse.cardTypesResolver.getBlockchain().getTestnetVersion() ?: return null + cardTypeResolver.getBlockchain().getTestnetVersion() ?: return null } else { - scanResponse.cardTypesResolver.getBlockchain() + cardTypeResolver.getBlockchain() } val derivationParams = getDerivationParams(null, scanResponse.card) return makeWalletManagerForApp( scanResponse = scanResponse, + cardTypeResolver = cardTypeResolver, blockchain = blockchain, derivationParams = derivationParams, ) diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt index d4e6cbd1fc..6fc426781c 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt @@ -1,15 +1,16 @@ package com.tangem.tap.domain.model.builders +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.common.TapWorkarounds.isStart2Coin -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.userWalletList.GetCardImageUseCase class UserWalletBuilder( private val scanResponse: ScanResponse, + private val cardTypeResolver: CardTypeResolver, private val getCardImageUseCase: GetCardImageUseCase = GetCardImageUseCase(), ) { private var backupCardsIds: Set = emptySet() @@ -46,7 +47,7 @@ class UserWalletBuilder( artworkUrl = getCardImageUseCase.invoke(card.cardId, card.cardPublicKey), cardsInWallet = backupCardsIds.plus(card.cardId), scanResponse = this, - isMultiCurrency = cardTypesResolver.isMultiwalletAllowed(), + isMultiCurrency = cardTypeResolver.isMultiwalletAllowed(), ) } } diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index e7d01ecdb6..57838dad8d 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -1,14 +1,10 @@ package com.tangem.tap.domain.model.builders import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.DerivationStyle -import com.tangem.blockchain.common.Token -import com.tangem.blockchain.common.Wallet -import com.tangem.blockchain.common.WalletManager +import com.tangem.blockchain.common.* import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.TapWorkarounds.derivationStyle -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel @@ -29,19 +25,25 @@ interface WalletStoreBuilder { companion object { operator fun invoke( userWallet: UserWallet, + cardTypeResolver: CardTypeResolver, blockchainNetwork: BlockchainNetwork, ): BlockchainNetworkWalletStoreBuilder { - return BlockchainNetworkWalletStoreBuilderImpl(userWallet, blockchainNetwork) + return BlockchainNetworkWalletStoreBuilderImpl(userWallet, cardTypeResolver, blockchainNetwork) } - operator fun invoke(userWallet: UserWallet, walletManager: WalletManager): WalletMangerWalletStoreBuilder { - return WalletMangerWalletStoreBuilderImpl(userWallet, walletManager) + operator fun invoke( + userWallet: UserWallet, + cardTypeResolver: CardTypeResolver, + walletManager: WalletManager, + ): WalletMangerWalletStoreBuilder { + return WalletMangerWalletStoreBuilderImpl(userWallet, cardTypeResolver, walletManager) } } } private class BlockchainNetworkWalletStoreBuilderImpl( private val userWallet: UserWallet, + private val cardTypeResolver: CardTypeResolver, private val blockchainNetwork: BlockchainNetwork, ) : WalletStoreBuilder.BlockchainNetworkWalletStoreBuilder { private var walletManager: WalletManager? = null @@ -56,7 +58,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl( val tokensWalletsData = blockchainNetwork.getTokensWalletsData( walletManager = walletManager, cardDerivationStyle = cardDerivationStyle, - primaryToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken(), + primaryToken = cardTypeResolver.getPrimaryToken(), ) return WalletStoreModel( @@ -73,6 +75,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl( private class WalletMangerWalletStoreBuilderImpl( private val userWallet: UserWallet, + private val cardTypeResolver: CardTypeResolver, private val walletManager: WalletManager, ) : WalletStoreBuilder.WalletMangerWalletStoreBuilder { @@ -81,7 +84,7 @@ private class WalletMangerWalletStoreBuilderImpl( val blockchainWalletData = wallet.blockchain.toBlockchainWalletData(walletManager) val tokenWalletsData = wallet.getTokens().firstOrNull()?.toTokenWalletData( walletManager = walletManager, - primaryToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken(), + primaryToken = cardTypeResolver.getPrimaryToken(), ) return WalletStoreModel( diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt index f885b4fa13..6009ec32df 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt @@ -7,6 +7,7 @@ import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.AnalyticsEvent +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ScanResponse @@ -22,6 +23,7 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -71,7 +73,11 @@ internal object LegacyScanProcessor { tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse) onScanStateChange(false) - sendAnalytics(analyticsEvent, scanResponse) + sendAnalytics( + analyticsEvent = analyticsEvent, + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) showDisclaimerIfNeed( scanResponse = scanResponse, @@ -89,10 +95,14 @@ internal object LegacyScanProcessor { } } - private fun sendAnalytics(analyticsEvent: AnalyticsEvent?, scanResponse: ScanResponse) { + private fun sendAnalytics( + analyticsEvent: AnalyticsEvent?, + scanResponse: ScanResponse, + cardTypeResolver: CardTypeResolver, + ) { analyticsEvent?.let { // this workaround needed to send CardWasScannedEvent without adding a context - val interceptor = CardContextInterceptor(scanResponse) + val interceptor = CardContextInterceptor(scanResponse, cardTypeResolver) val params = it.params.toMutableMap() interceptor.intercept(params) it.params = params.toMap() @@ -146,18 +156,25 @@ internal object LegacyScanProcessor { ) { val globalState = store.state.globalState val tapWalletManager = globalState.tapWalletManager - tapWalletManager.updateConfigManager(scanResponse) + tapWalletManager.updateConfigManager() store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse)) - if (OnboardingHelper.isOnboardingCase(scanResponse)) { - Analytics.addContext(scanResponse) + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) + if (OnboardingHelper.isOnboardingCase(scanResponse, cardTypeResolver)) { + Analytics.addContext( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) onWalletNotCreated() store.dispatchOnMain(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = true)) val appScreen = OnboardingHelper.whereToNavigate(scanResponse) navigateTo(appScreen) { onProgressStateChange(it) } } else { - Analytics.setContext(scanResponse) + Analytics.setContext( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) if (scanResponse.twinsIsTwinned() && !preferencesStorage.wasTwinsOnboardingShown()) { onWalletNotCreated() store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse))) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt index 45a463343a..04249c892c 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt @@ -49,7 +49,12 @@ internal object UseCaseScanProcessor { val chains = buildList { add(ScanningFinishedChain { onScanStateChange(false) }) if (analyticsEvent != null) { - add(AnalyticsChain(analyticsEvent)) + add( + AnalyticsChain( + event = analyticsEvent, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ), + ) } add(DisclaimerChain(store, disclaimerWillShow)) add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager, preferencesStorage)) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/AnalyticsChain.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/AnalyticsChain.kt index febc6a1525..d065b20148 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/AnalyticsChain.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/AnalyticsChain.kt @@ -4,6 +4,7 @@ import arrow.core.Either import arrow.core.right import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.AnalyticsEvent +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.card.ScanCardException import com.tangem.domain.core.chain.Chain import com.tangem.domain.models.scan.ScanResponse @@ -19,12 +20,16 @@ import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor */ class AnalyticsChain( private val event: AnalyticsEvent, + private val cardTypeResolver: CardTypeResolver, ) : Chain { override suspend fun invoke( previousChainResult: ScanResponse, ): Either { - val interceptor = CardContextInterceptor(previousChainResult) + val interceptor = CardContextInterceptor( + scanResponse = previousChainResult, + cardTypeResolver = cardTypeResolver, + ) val params = event.params.toMutableMap() interceptor.intercept(params) event.params = params.toMap() diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt index ce46f2f527..d17b6c84c3 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt @@ -20,6 +20,7 @@ import com.tangem.tap.domain.TapWalletManager import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import org.rekotlin.Store @@ -44,18 +45,25 @@ class CheckForOnboardingChain( override suspend fun invoke( previousChainResult: ScanResponse, ): Either { - tapWalletManager.updateConfigManager(previousChainResult) + tapWalletManager.updateConfigManager() store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(previousChainResult)) + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) return when { - OnboardingHelper.isOnboardingCase(previousChainResult) -> { - Analytics.addContext(previousChainResult) + OnboardingHelper.isOnboardingCase(previousChainResult, cardTypeResolver) -> { + Analytics.addContext( + scanResponse = previousChainResult, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) store.dispatchOnMain(GlobalAction.Onboarding.Start(previousChainResult, canSkipBackup = true)) val appScreen = OnboardingHelper.whereToNavigate(previousChainResult) ScanChainException.OnboardingNeeded(appScreen).left() } else -> { - Analytics.setContext(previousChainResult) + Analytics.setContext( + scanResponse = previousChainResult, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) // If twins was twinned previously but twins welcome not shown if (previousChainResult.twinsIsTwinned() && !preferencesStore.wasTwinsOnboardingShown()) { store.dispatchOnMain( diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt index d23e9fde5c..23225a2a25 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt @@ -12,7 +12,7 @@ import com.tangem.common.extensions.guard import com.tangem.common.extensions.toMapKey import com.tangem.common.map import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.common.CardTypesResolver +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.models.scan.CardDTO @@ -55,7 +55,7 @@ private data class CreateWalletResponse( } class CreateProductWalletTask( - private val cardTypesResolver: CardTypesResolver, + private val cardTypeResolver: CardTypeResolver, private val seed: ByteArray? = null, ) : CardSessionRunnable { @@ -72,8 +72,8 @@ class CreateProductWalletTask( val cardDto = CardDTO(card) val commandProcessor = when { - cardTypesResolver.isTangemNote() -> CreateWalletTangemNote(cardTypesResolver) - cardTypesResolver.isTangemTwins() -> + cardTypeResolver.isTangemNote() -> CreateWalletTangemNote(cardTypeResolver) + cardTypeResolver.isTangemTwins() -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet") else -> CreateWalletTangemWallet(seed) @@ -97,7 +97,7 @@ class CreateProductWalletTask( } } -private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesResolver) : +private class CreateWalletTangemNote(private val cardTypeResolver: CardTypeResolver) : ProductCommandProcessor { override fun proceed( card: CardDTO, @@ -109,7 +109,7 @@ private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesRes return } - val curvesSupportedByBlockchain = cardTypesResolver.getBlockchain().getSupportedCurves().toSet() + val curvesSupportedByBlockchain = cardTypeResolver.getBlockchain().getSupportedCurves().toSet() if (curvesSupportedByBlockchain.isEmpty()) { callback(CompletionResult.Failure(TangemSdkError.CardError())) return diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/di/WalletCurrenciesManagerProvider.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/di/WalletCurrenciesManagerProvider.kt index 0c6bfccf02..d754f7ecd7 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/di/WalletCurrenciesManagerProvider.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/di/WalletCurrenciesManagerProvider.kt @@ -1,5 +1,7 @@ package com.tangem.tap.domain.walletCurrencies.di +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.Provider import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager @@ -8,12 +10,14 @@ import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository +@Suppress("LongParameterList") fun WalletCurrenciesManager.Companion.provideDefaultImplementation( userTokensRepository: UserTokensRepository, walletStoresRepository: WalletStoresRepository, walletAmountsRepository: WalletAmountsRepository, walletManagersRepository: WalletManagersRepository, appCurrencyProvider: () -> FiatCurrency, + cardTypeResolverProvider: Provider, ): WalletCurrenciesManager { return DefaultWalletCurrenciesManager( userTokensRepository = userTokensRepository, @@ -21,5 +25,6 @@ fun WalletCurrenciesManager.Companion.provideDefaultImplementation( walletAmountsRepository = walletAmountsRepository, walletManagersRepository = walletManagersRepository, appCurrencyProvider = appCurrencyProvider, + cardTypeResolverProvider = cardTypeResolverProvider, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt index 0bbd76b7bc..65103d09a2 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt @@ -2,6 +2,8 @@ package com.tangem.tap.domain.walletCurrencies.implementation import com.tangem.blockchain.common.DerivationStyle import com.tangem.common.* +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.Provider import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.util.UserWalletId import com.tangem.domain.models.scan.CardDTO @@ -26,6 +28,7 @@ internal class DefaultWalletCurrenciesManager( private val walletAmountsRepository: WalletAmountsRepository, private val walletManagersRepository: WalletManagersRepository, private val appCurrencyProvider: () -> FiatCurrency, + private val cardTypeResolverProvider: Provider, ) : WalletCurrenciesManager { private val listeners = mutableListOf() @@ -227,7 +230,11 @@ internal class DefaultWalletCurrenciesManager( .flatMap { walletManager -> walletStoresRepository.storeOrUpdate( userWalletId = userWallet.walletId, - walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) + walletStore = WalletStoreBuilder( + userWallet = userWallet, + cardTypeResolver = cardTypeResolverProvider.invoke(), + blockchainNetwork = blockchainNetwork, + ) .walletManager(walletManager) .build(), ) diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/di/WalletsStoresManagerProvider.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/di/WalletsStoresManagerProvider.kt index d2a4789fb0..ae1ac2bb4c 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/di/WalletsStoresManagerProvider.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/di/WalletsStoresManagerProvider.kt @@ -1,24 +1,23 @@ package com.tangem.tap.domain.walletStores.di -import com.tangem.tap.domain.walletStores.WalletStoresManager -import com.tangem.tap.domain.walletStores.implementation.DummyWalletStoresManager +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.Provider import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.domain.tokens.UserTokensRepository +import com.tangem.tap.domain.walletStores.WalletStoresManager import com.tangem.tap.domain.walletStores.implementation.DefaultWalletStoresManager import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository -fun WalletStoresManager.Companion.provideDummyImplementation(): WalletStoresManager { - return DummyWalletStoresManager() -} - +@Suppress("LongParameterList") fun WalletStoresManager.Companion.provideDefaultImplementation( userTokensRepository: UserTokensRepository, walletStoresRepository: WalletStoresRepository, walletAmountsRepository: WalletAmountsRepository, walletManagersRepository: WalletManagersRepository, appCurrencyProvider: () -> FiatCurrency, + cardTypeResolverProvider: Provider, ): WalletStoresManager { return DefaultWalletStoresManager( userTokensRepository = userTokensRepository, @@ -26,5 +25,6 @@ fun WalletStoresManager.Companion.provideDefaultImplementation( walletAmountsRepository = walletAmountsRepository, walletManagersRepository = walletManagersRepository, appCurrencyProvider = appCurrencyProvider, + cardTypeResolverProvider = cardTypeResolverProvider, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt index 6081a25788..476fa8300c 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt @@ -2,12 +2,9 @@ package com.tangem.tap.domain.walletStores.implementation import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.common.address.AddressType -import com.tangem.common.CompletionResult -import com.tangem.common.doOnSuccess -import com.tangem.common.flatMap -import com.tangem.common.flatMapOnFailure -import com.tangem.common.fold -import com.tangem.common.map +import com.tangem.common.* +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.Provider import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.domain.model.UserWallet @@ -35,6 +32,7 @@ internal class DefaultWalletStoresManager( private val walletAmountsRepository: WalletAmountsRepository, private val walletManagersRepository: WalletManagersRepository, private val appCurrencyProvider: () -> FiatCurrency, + private val cardTypeResolverProvider: Provider, ) : WalletStoresManager { private val state = MutableStateFlow(State()) @@ -151,7 +149,11 @@ internal class DefaultWalletStoresManager( { walletManager -> walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) + walletStore = WalletStoreBuilder( + userWallet = userWallet, + cardTypeResolver = cardTypeResolverProvider.invoke(), + blockchainNetwork = blockchainNetwork, + ) .walletManager(walletManager) .build(), ) @@ -185,7 +187,11 @@ internal class DefaultWalletStoresManager( val userWalletId = userWallet.walletId walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder(userWallet, walletManager) + walletStore = WalletStoreBuilder( + userWallet = userWallet, + cardTypeResolver = cardTypeResolverProvider.invoke(), + walletManager = walletManager, + ) .build(), ) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt index d89d4ea6aa..1f89cd4eda 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt @@ -2,6 +2,8 @@ package com.tangem.tap.domain.walletStores.repository.di import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.datasource.api.tangemTech.TangemTechService +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.Provider import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository @@ -16,8 +18,9 @@ fun WalletStoresRepository.Companion.provideDefaultImplementation(): WalletStore fun WalletManagersRepository.Companion.provideDefaultImplementation( walletManagerFactory: WalletManagerFactory, + cardTypeResolverProvider: Provider, ): WalletManagersRepository { - return DefaultWalletManagersRepository(walletManagerFactory) + return DefaultWalletManagersRepository(walletManagerFactory, cardTypeResolverProvider) } fun WalletAmountsRepository.Companion.provideDefaultImplementation( diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt index b2d8167a7e..bf26df0009 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt @@ -1,22 +1,17 @@ package com.tangem.tap.domain.walletStores.repository.implementation -import com.tangem.blockchain.common.Amount -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.DerivationParams -import com.tangem.blockchain.common.DerivationStyle -import com.tangem.blockchain.common.WalletManager -import com.tangem.blockchain.common.WalletManagerFactory +import com.tangem.blockchain.common.* import com.tangem.common.CompletionResult import com.tangem.common.catching import com.tangem.common.doOnSuccess import com.tangem.common.mapFailure import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.Provider import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.UserWalletId import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.tokens.models.BlockchainNetwork @@ -30,6 +25,7 @@ import timber.log.Timber internal class DefaultWalletManagersRepository( private val walletManagerFactory: WalletManagerFactory, + private val cardTypeResolverProvider: Provider, ) : WalletManagersRepository { private val walletManagersStorage = WalletManagerStorage @@ -56,10 +52,7 @@ internal class DefaultWalletManagersRepository( derivationPath = blockchainNetwork?.derivationPath, ) - foundWalletManager?.updateTokens( - scanResponse = userWallet.scanResponse, - blockchainNetwork = blockchainNetwork, - ) + foundWalletManager?.updateTokens(blockchainNetwork = blockchainNetwork) ?: makeAndStore(userWallet, blockchainNetwork) } @@ -69,7 +62,7 @@ internal class DefaultWalletManagersRepository( ): CompletionResult { val scanResponse = userWallet.scanResponse val blockchain = blockchainNetwork?.blockchain - ?: scanResponse.cardTypesResolver.getBlockchain().let { blockchain -> + ?: cardTypeResolverProvider.invoke().getBlockchain().let { blockchain -> if (scanResponse.card.isTestCard) blockchain.getTestnetVersion() else blockchain } val derivationParams = getDerivationParams( @@ -80,6 +73,7 @@ internal class DefaultWalletManagersRepository( val walletManager = blockchain?.let { walletManagerFactory.makeWalletManagerForApp( scanResponse = userWallet.scanResponse, + cardTypeResolver = cardTypeResolverProvider.invoke(), blockchain = blockchain, derivationParams = derivationParams, ) @@ -98,10 +92,7 @@ internal class DefaultWalletManagersRepository( CompletionResult.Failure(error) } walletManager != null -> { - walletManager.updateTokens( - scanResponse = scanResponse, - blockchainNetwork = blockchainNetwork, - ) + walletManager.updateTokens(blockchainNetwork = blockchainNetwork) .doOnSuccess { store(userWallet.walletId, it) } } else -> { @@ -161,13 +152,10 @@ internal class DefaultWalletManagersRepository( } } - private fun WalletManager.updateTokens( - scanResponse: ScanResponse, - blockchainNetwork: BlockchainNetwork?, - ): CompletionResult { + private fun WalletManager.updateTokens(blockchainNetwork: BlockchainNetwork?): CompletionResult { val walletManager = this return catching { - val tokens = blockchainNetwork?.tokens ?: listOfNotNull(scanResponse.cardTypesResolver.getPrimaryToken()) + val tokens = blockchainNetwork?.tokens ?: listOfNotNull(cardTypeResolverProvider.invoke().getPrimaryToken()) if (tokens != walletManager.cardTokens) { // TODO: remove ability to manipulate with walletManager.cardTokens diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt index 4624db8d34..89cdd44f5f 100644 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt @@ -1,13 +1,14 @@ package com.tangem.tap.features.demo import com.tangem.common.extensions.guard -import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.common.demo.DemoConfig import com.tangem.domain.common.extensions.withMainContext +import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.domain.extensions.makePrimaryWalletManager import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.launch @@ -28,9 +29,14 @@ internal class DemoOnboardingNoteMiddleware : DemoMiddleware { noteState.walletManager } else { val wmFactory = globalState.tapWalletManager.walletManagerFactory - val walletManager = wmFactory.makePrimaryWalletManager(scanResponse).guard { - return false - } + val walletManager = wmFactory + .makePrimaryWalletManager( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) + .guard { + return false + } store.dispatch(OnboardingNoteAction.SetWalletManager(walletManager)) walletManager } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 5782c7b0e2..ad390d5207 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -2,7 +2,6 @@ package com.tangem.tap.features.details.redux import com.tangem.blockchain.common.Wallet import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.entities.FiatCurrency import org.rekotlin.Action @@ -26,7 +25,7 @@ sealed class DetailsAction : Action { object ScanCard : DetailsAction() - data class PrepareCardSettingsData(val card: CardDTO, val cardTypesResolver: CardTypesResolver) : DetailsAction() + data class PrepareCardSettingsData(val card: CardDTO) : DetailsAction() object ResetCardSettingsData : DetailsAction() sealed class AccessCodeRecovery : DetailsAction() { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index acc0130ea9..8541cb7fb0 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -8,7 +8,6 @@ import com.tangem.common.extensions.guard import com.tangem.common.flatMap import com.tangem.core.analytics.Analytics import com.tangem.domain.common.TapWorkarounds.isTangemTwins -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -33,13 +32,8 @@ import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.foregroundActivityObserver -import com.tangem.tap.preferencesStorage -import com.tangem.tap.scope -import com.tangem.tap.store +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.tangemSdkManager -import com.tangem.tap.userWalletsListManager -import com.tangem.tap.walletStoresManager import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -92,10 +86,7 @@ class DetailsMiddleware { if (isSameWallet) { store.dispatchOnMain( - DetailsAction.PrepareCardSettingsData( - scanResponse.card, - scanResponse.cardTypesResolver, - ), + DetailsAction.PrepareCardSettingsData(card = scanResponse.card), ) } else { store.dispatchDialogShow( @@ -328,7 +319,12 @@ class DetailsMiddleware { enableAccessCodesSaving: Boolean, ): CompletionResult { val userWallet = userWalletsListManager.selectedUserWalletSync - ?: scanResponse?.let { UserWalletBuilder(it).build() } + ?: scanResponse?.let { + UserWalletBuilder( + scanResponse = it, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ).build() + } ?: return CompletionResult.Failure( error = TangemSdkError.ExceptionError(IllegalStateException("scanResponse is null")), ) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index e28b9cd398..21bdcfdddc 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -1,15 +1,15 @@ package com.tangem.tap.features.details.redux -import com.tangem.domain.common.CardTypesResolver -import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.extensions.signedHashesCount import com.tangem.tap.preferencesStorage +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store import com.tangem.tap.tangemSdkManager import org.rekotlin.Action -import java.util.* +import java.util.EnumSet object DetailsReducer { fun reduce(action: Action, state: AppState): DetailsState = internalReduce(action, state) @@ -23,11 +23,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { handlePrepareScreen(action) } is DetailsAction.PrepareCardSettingsData -> { - handlePrepareCardSettingsScreen( - card = action.card, - cardTypesResolver = action.cardTypesResolver, - state = detailsState, - ) + handlePrepareCardSettingsScreen(card = action.card, state = detailsState) } is DetailsAction.ResetCardSettingsData -> detailsState.copy(cardSettingsState = null) is DetailsAction.ResetToFactory -> { @@ -60,17 +56,14 @@ private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsSta ) } -private fun handlePrepareCardSettingsScreen( - card: CardDTO, - cardTypesResolver: CardTypesResolver, - state: DetailsState, -): DetailsState { +private fun handlePrepareCardSettingsScreen(card: CardDTO, state: DetailsState): DetailsState { + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) val cardSettingsState = CardSettingsState( - cardInfo = card.toCardInfo(cardTypesResolver), - manageSecurityState = prepareSecurityOptions(card, cardTypesResolver), + cardInfo = card.toCardInfo(cardTypeResolver), + manageSecurityState = prepareSecurityOptions(card, cardTypeResolver), card = card, - resetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypesResolver), - accessCodeRecovery = if (cardTypesResolver.isWallet2()) { + resetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypeResolver), + accessCodeRecovery = if (cardTypeResolver.isWallet2()) { val enabled = card.userSettings?.isUserCodeRecoveryAllowed ?: false AccessCodeRecoveryState( enabledOnCard = enabled, @@ -83,7 +76,7 @@ private fun handlePrepareCardSettingsScreen( return state.copy(cardSettingsState = cardSettingsState) } -private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesResolver): ManageSecurityState { +private fun prepareSecurityOptions(card: CardDTO, cardTypeResolver: CardTypeResolver): ManageSecurityState { val securityOption = when { card.isAccessCodeSet -> { SecurityOption.AccessCode @@ -98,14 +91,15 @@ private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesRe } } val allowedSecurityOptions = when { - cardTypesResolver.isStart2Coin() || cardTypesResolver.isTangemNote() -> { + cardTypeResolver.isStart2Coin() || cardTypeResolver.isTangemNote() -> { EnumSet.of(SecurityOption.LongTap) } card.settings.isBackupAllowed -> { EnumSet.of(securityOption) } - else -> - prepareAllowedSecurityOptions(cardTypesResolver = cardTypesResolver, currentSecurityOption = securityOption) + else -> { + prepareAllowedSecurityOptions(cardTypeResolver = cardTypeResolver, currentSecurityOption = securityOption) + } } return ManageSecurityState( currentOption = securityOption, @@ -114,9 +108,9 @@ private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesRe ) } -private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypesResolver: CardTypesResolver): Boolean { +private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypeResolver: CardTypeResolver): Boolean { val hasPermanentWallet = card.wallets.any { it.settings.isPermanent } - val isNotAllowed = hasPermanentWallet || cardTypesResolver.isStart2Coin() + val isNotAllowed = hasPermanentWallet || cardTypeResolver.isStart2Coin() return !isNotAllowed } @@ -140,12 +134,10 @@ private fun handleSecurityAction(action: DetailsAction.ManageSecurity, state: De // Setting options to show only LongTap from now on for non-twins val manageSecurityState = state.cardSettingsState?.manageSecurityState?.copy( currentOption = state.cardSettingsState.manageSecurityState.selectedOption, - allowedOptions = state.scanResponse?.cardTypesResolver?.let { - prepareAllowedSecurityOptions( - cardTypesResolver = it, - currentSecurityOption = state.cardSettingsState.manageSecurityState.selectedOption, - ) - } ?: EnumSet.of(SecurityOption.LongTap), + allowedOptions = prepareAllowedSecurityOptions( + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + currentSecurityOption = state.cardSettingsState.manageSecurityState.selectedOption, + ), ) state.copy( cardSettingsState = state.cardSettingsState?.copy( @@ -229,12 +221,12 @@ private fun handleAccessCodeRecoveryAction( } private fun prepareAllowedSecurityOptions( - cardTypesResolver: CardTypesResolver, + cardTypeResolver: CardTypeResolver, currentSecurityOption: SecurityOption?, ): EnumSet { val allowedSecurityOptions = EnumSet.of(SecurityOption.LongTap) - if (cardTypesResolver.isTangemTwins()) { + if (cardTypeResolver.isTangemTwins()) { allowedSecurityOptions.add(SecurityOption.PassCode) } if (currentSecurityOption == SecurityOption.AccessCode) { @@ -246,9 +238,8 @@ private fun prepareAllowedSecurityOptions( return allowedSecurityOptions } -@Suppress("MagicNumber") -private fun CardDTO.toCardInfo(cardTypesResolver: CardTypesResolver): CardInfo { - val cardId = this.cardId.chunked(4).joinToString(separator = " ") +private fun CardDTO.toCardInfo(cardTypeResolver: CardTypeResolver): CardInfo { + val cardId = this.cardId.chunked(size = 4).joinToString(separator = " ") val issuer = this.issuer.name val signedHashes = this.signedHashesCount() @@ -256,7 +247,7 @@ private fun CardDTO.toCardInfo(cardTypesResolver: CardTypesResolver): CardInfo { cardId = cardId, issuer = issuer, signedHashes = signedHashes, - isTwin = cardTypesResolver.isTangemTwins(), + isTwin = cardTypeResolver.isTangemTwins(), hasBackup = backupStatus?.isActive == true, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index b69de63a66..47422b12e6 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -8,7 +8,6 @@ import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.domain.common.extensions.toNetworkId import com.tangem.domain.common.extensions.withMainContext -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.extensions.dispatchOnMain @@ -404,7 +403,8 @@ class WalletConnectMiddleware { private fun handleScanResponse(scanResponse: ScanResponse, session: WalletConnectSession, blockchain: Blockchain) { val card = scanResponse.card - if (!scanResponse.cardTypesResolver.isMultiwalletAllowed()) { + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) + if (!cardTypeResolver.isMultiwalletAllowed()) { store.dispatchOnMain(WalletConnectAction.UnsupportedCard) return } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index e9766c6147..9256eda744 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -3,7 +3,6 @@ package com.tangem.tap.features.details.ui.details import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import com.tangem.core.analytics.Analytics -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.feedback.FeedbackEmail import com.tangem.tap.common.feedback.SupportInfo @@ -16,6 +15,7 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerAction import com.tangem.tap.features.home.LocaleRegionProvider import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.wallet.BuildConfig import org.rekotlin.Store @@ -26,11 +26,11 @@ class DetailsViewModel(private val store: Store) { @Suppress("ComplexMethod") fun updateState(state: DetailsState): DetailsScreenState { - val cardTypesResolver = state.scanResponse?.cardTypesResolver + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) val settings = SettingsElement.values().mapNotNull { when (it) { SettingsElement.WalletConnect -> { - if (cardTypesResolver?.isMultiwalletAllowed() == true) it else null + if (cardTypeResolver.isMultiwalletAllowed()) it else null } SettingsElement.SendFeedback -> it SettingsElement.LinkMoreCards -> if (state.createBackupAllowed) it else null @@ -38,8 +38,8 @@ class DetailsViewModel(private val store: Store) { if (state.privacyPolicyUrl != null) it else null } SettingsElement.AppSettings -> if (state.appSettingsState.isBiometricsAvailable) it else null - SettingsElement.AppCurrency -> if (cardTypesResolver?.isMultiwalletAllowed() != true) it else null - SettingsElement.ReferralProgram -> if (cardTypesResolver?.isTangemWallet() == true) it else null + SettingsElement.AppCurrency -> if (!cardTypeResolver.isMultiwalletAllowed()) it else null + SettingsElement.ReferralProgram -> if (cardTypeResolver.isTangemWallet()) it else null SettingsElement.TesterMenu -> if (BuildConfig.TESTER_MENU_ENABLED) it else null else -> it } diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 9d7d775e1d..5a3d6060f6 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -27,6 +27,7 @@ import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.features.home.redux.HomeMiddleware.BUY_WALLET_URL import com.tangem.tap.features.send.redux.states.ButtonState import com.tangem.tap.features.signin.redux.SignInAction +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -101,10 +102,15 @@ private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { } private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch { - val userWallet = UserWalletBuilder(scanResponse).build().guard { - Timber.e("User wallet not created") - return@launch - } + val userWallet = UserWalletBuilder( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) + .build() + .guard { + Timber.e("User wallet not created") + return@launch + } userWalletsListManager.save(userWallet) .doOnFailure { error -> diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index 6079110e39..2003719d77 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -4,10 +4,11 @@ import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics -import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse +import com.tangem.tap.* import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.extensions.removeContext @@ -16,11 +17,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.features.saveWallet.redux.SaveWalletAction -import com.tangem.tap.preferencesStorage -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.tap.tangemSdkManager -import com.tangem.tap.userWalletsListManager +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import timber.log.Timber @@ -29,11 +26,11 @@ import timber.log.Timber [REDACTED_AUTHOR] */ object OnboardingHelper { - fun isOnboardingCase(response: ScanResponse): Boolean { + fun isOnboardingCase(response: ScanResponse, cardTypeResolver: CardTypeResolver): Boolean { val cardInfoStorage = preferencesStorage.usedCardsPrefStorage val cardId = response.card.cardId return when { - response.cardTypesResolver.isTangemTwins() -> { + cardTypeResolver.isTangemTwins() -> { if (!response.twinsIsTwinned()) { true } else { @@ -41,7 +38,7 @@ object OnboardingHelper { } } - response.cardTypesResolver.isWallet2() -> { + cardTypeResolver.isWallet2() -> { val emptyWallets = response.card.wallets.isEmpty() val activationInProgress = cardInfoStorage.isActivationInProgress(cardId) val backupNotActive = response.card.backupStatus?.isActive != true @@ -73,7 +70,10 @@ object OnboardingHelper { accessCode: String? = null, backupCardsIds: List? = null, ) { - Analytics.setContext(scanResponse) + Analytics.setContext( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) when { // When should save user wallets, then save card without navigate to save wallet screen preferencesStorage.shouldSaveUserWallets -> scope.launch { @@ -119,7 +119,10 @@ object OnboardingHelper { } private suspend fun proceedWithScanResponse(scanResponse: ScanResponse, backupCardsIds: List?) { - val userWallet = UserWalletBuilder(scanResponse) + val userWallet = UserWalletBuilder( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) .backupCardsIds(backupCardsIds?.toSet()) .build() .guard { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index fddc46b3a8..29877cbf50 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -7,13 +7,7 @@ import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.dispatchDebugErrorNotification -import com.tangem.tap.common.extensions.dispatchDialogShow -import com.tangem.tap.common.extensions.dispatchErrorNotification -import com.tangem.tap.common.extensions.dispatchOnMain -import com.tangem.tap.common.extensions.dispatchOpenUrl -import com.tangem.tap.common.extensions.getAddressData -import com.tangem.tap.common.extensions.getTopUpUrl +import com.tangem.tap.common.extensions.* import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.AppState @@ -29,6 +23,7 @@ import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.models.WalletDialog +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -123,7 +118,10 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch noteState.walletManager } else { val wmFactory = globalState.tapWalletManager.walletManagerFactory - val walletManager = wmFactory.makePrimaryWalletManager(scanResponse).guard { + val walletManager = wmFactory.makePrimaryWalletManager( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ).guard { val message = "Loading cancelled. Cause: wallet manager didn't created" val customError = TapError.CustomError(message) store.dispatchErrorNotification(customError) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt index ba7983eaa5..044c9fd13f 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt @@ -3,9 +3,8 @@ package com.tangem.tap.features.onboarding.products.otherCards.redux import com.tangem.blockchain.common.Blockchain import com.tangem.common.CompletionResult import com.tangem.core.analytics.Analytics -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.extensions.withMainContext -import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE +import com.tangem.tap.* import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppState @@ -13,10 +12,7 @@ import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.wallet.models.toCurrencies -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.tap.tangemSdkManager -import com.tangem.tap.userTokensRepository +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -90,9 +86,10 @@ private fun handleOtherCardsAction(action: Action) { onboardingManager.activationStarted(updatedCard.cardId) store.state.globalState.topUpController?.registerEmptyWallet(updatedResponse) - val primaryBlockchain = updatedResponse.cardTypesResolver.getBlockchain() + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) + val primaryBlockchain = cardTypeResolver.getBlockchain() val blockchainNetworks = if (primaryBlockchain != Blockchain.Unknown) { - val primaryToken = updatedResponse.cardTypesResolver.getPrimaryToken() + val primaryToken = cardTypeResolver.getPrimaryToken() val blockchainNetwork = BlockchainNetwork( blockchain = primaryBlockchain, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 036482c623..1fa0ce5b48 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -29,6 +29,7 @@ import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.models.WalletDialog +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -221,7 +222,10 @@ private fun handle(action: Action, dispatch: DispatchFunction) { twinCardsState.walletManager } else { val wmFactory = globalState.tapWalletManager.walletManagerFactory - val walletManager = wmFactory.makePrimaryWalletManager(getScanResponse()).guard { + val walletManager = wmFactory.makePrimaryWalletManager( + scanResponse = getScanResponse(), + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ).guard { val message = "Loading cancelled. Cause: wallet manager didn't created" val customError = TapError.CustomError(message) store.dispatchErrorNotification(customError) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt index 9ba9492c54..d393583ef3 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt @@ -1,8 +1,9 @@ package com.tangem.tap.features.onboarding.products.twins.redux -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.getTwinCardNumber import com.tangem.tap.common.redux.AppState +import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.store import org.rekotlin.Action object TwinCardsReducer { @@ -17,7 +18,8 @@ private fun internalReduce(action: Action, state: AppState): TwinCardsState { when (action) { is TwinCardsAction.IfTwinsPrepareState -> { - state = if (action.scanResponse.cardTypesResolver.isTangemTwins()) { + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) + state = if (cardTypeResolver.isTangemTwins()) { val cardNumber = action.scanResponse.card.getTwinCardNumber() ?: return state TwinCardsState( diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 2f4be5416d..dc2a82105e 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -7,7 +7,6 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.ifNotNull import com.tangem.core.analytics.Analytics import com.tangem.domain.common.extensions.withMainContext -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.feature.onboarding.data.model.CreateWalletResponse @@ -30,9 +29,9 @@ import com.tangem.tap.features.onboarding.OnboardingDialog import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.wallet.models.toCurrencies import com.tangem.tap.features.wallet.redux.Artwork +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.launch import org.rekotlin.Action -import org.rekotlin.DispatchFunction import org.rekotlin.Middleware object OnboardingWalletMiddleware { @@ -43,8 +42,8 @@ private val onboardingWalletMiddleware: Middleware = { dispatch, state { next -> { action -> when (action) { - is OnboardingWallet2Action -> handleWallet2Action(action, state) - else -> handleWalletAction(action, state, dispatch) + is OnboardingWallet2Action -> handleWallet2Action(action) + else -> handleWalletAction(action) } next(action) } @@ -52,7 +51,7 @@ private val onboardingWalletMiddleware: Middleware = { dispatch, state } @Suppress("LongMethod", "ComplexMethod") -private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: DispatchFunction) { +private fun handleWalletAction(action: Action) { if (action !is OnboardingWalletAction) return val globalState = store.state.globalState @@ -178,7 +177,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } @Suppress("LongMethod", "ComplexMethod") -private fun handleWallet2Action(action: OnboardingWallet2Action, state: () -> AppState?) { +private fun handleWallet2Action(action: OnboardingWallet2Action) { val globalState = store.state.globalState val onboardingManager = globalState.onboardingState.onboardingManager @@ -186,7 +185,8 @@ private fun handleWallet2Action(action: OnboardingWallet2Action, state: () -> Ap when (action) { is OnboardingWallet2Action.Init -> { - if (scanResponse?.cardTypesResolver?.isWallet2() == true) { + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) + if (cardTypeResolver.isWallet2()) { store.dispatch(OnboardingWallet2Action.SetDependencies(action.maxProgress)) } } diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt index ec2223b2bd..8866609bb7 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt @@ -7,6 +7,7 @@ import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard import com.tangem.common.flatMap import com.tangem.core.analytics.Analytics +import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Onboarding @@ -21,12 +22,7 @@ import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation import com.tangem.tap.domain.userWalletList.isLockable import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.foregroundActivityObserver -import com.tangem.tap.preferencesStorage -import com.tangem.tap.scope -import com.tangem.tap.store -import com.tangem.tap.tangemSdkManager -import com.tangem.tap.userWalletsListManager +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber @@ -96,7 +92,10 @@ internal class SaveWalletMiddleware { scope.launch { val userWallet = userWalletsListManager.selectedUserWalletSync - ?: UserWalletBuilder(scanResponse) + ?: UserWalletBuilder( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) .backupCardsIds(state.backupInfo?.backupCardsIds) .build() ?: return@launch diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 9c1feed6b4..c6ee8940d4 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -4,7 +4,6 @@ import android.graphics.Bitmap import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.WalletManager -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.common.entities.Button import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.common.toggleWidget.WidgetState @@ -50,9 +49,6 @@ data class WalletState( store.state.twinCardsState } - val isTangemTwins: Boolean - get() = store.state.globalState.scanResponse?.cardTypesResolver?.isTangemTwins() == true - val isExchangeServiceFeatureOn: Boolean get() = store.state.globalState.exchangeManager.featureIsSwitchedOn() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index d86a41c389..de428f2421 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -19,6 +19,7 @@ import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.models.WalletDialog +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.userWalletsListManager @@ -82,7 +83,10 @@ class MultiWalletMiddleware { return } val scanResponse = selectedUserWallet.scanResponse - Analytics.addContext(scanResponse) + Analytics.addContext( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false)) store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet)) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index 44a7dd5341..7b64bf710f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -5,7 +5,6 @@ import com.tangem.blockchain.common.SignatureCountValidator import com.tangem.blockchain.extensions.SimpleResult import com.tangem.common.card.FirmwareVersion import com.tangem.domain.common.TapWorkarounds.isTestCard -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.extensions.dispatchOnMain @@ -107,9 +106,10 @@ class WarningsMiddleware { } private fun checkIfWarningNeeded(scanResponse: ScanResponse): WarningMessage? { - if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.isDemoCard()) return null + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) + if (cardTypeResolver.isTangemTwins() || scanResponse.isDemoCard()) return null - if (scanResponse.cardTypesResolver.isMultiwalletAllowed()) { + if (cardTypeResolver.isMultiwalletAllowed()) { val isBackupForbidden = with(scanResponse.card.settings) { !(isBackupAllowed || isHDWalletAllowed) } return if (scanResponse.card.hasSignedHashes() && isBackupForbidden) { WarningMessagesManager.signedHashesMultiWalletWarning @@ -139,9 +139,8 @@ class WarningsMiddleware { val card = scanResponse?.card if (card == null || preferencesStorage.usedCardsPrefStorage.wasScanned(card.cardId)) return - if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.cardTypesResolver.isMultiwalletAllowed()) { - return - } + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) + if (cardTypeResolver.isTangemTwins() || cardTypeResolver.isMultiwalletAllowed()) return val validator = store.state.walletState.walletManagers.firstOrNull() as? SignatureCountValidator diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt index 95f80ebca8..d07d830d42 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt @@ -5,7 +5,6 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.events.MainScreen @@ -14,6 +13,7 @@ import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.ui.analytics.WalletAnalyticsEventsMapper +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store import com.tangem.tap.walletStoresManager import dagger.hilt.android.lifecycle.HiltViewModel @@ -54,8 +54,9 @@ internal class WalletViewModel @Inject constructor( override fun onCreate(owner: LifecycleOwner) { launch() val scanResponse = store.state.globalState.scanResponse + val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) if (scanResponse != null) { - val currency = ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver) + val currency = ParamCardCurrencyConverter().convert(cardTypeResolver) val signInType = store.state.signInState.type if (currency != null && signInType != null) { analyticsEventHandler.send( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index 3528a61c7a..a53ee4fe57 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -22,6 +22,7 @@ import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.unlockIfLockable +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.firstOrNull @@ -162,7 +163,11 @@ internal class WalletSelectorMiddleware { } private suspend fun saveUserWalletAndPopBackToWalletScreen(scanResponse: ScanResponse): CompletionResult { - val userWallet = UserWalletBuilder(scanResponse).build() + val userWallet = UserWalletBuilder( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) + .build() ?: return CompletionResult.Failure(TangemSdkError.WalletIsNotCreated()) return userWalletsListManager.save(userWallet) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt index 2a8ace7ad3..e24f28d268 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt @@ -1,10 +1,11 @@ package com.tangem.tap.features.walletSelector.redux -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.model.UserWallet +import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.store import org.rekotlin.Action internal object WalletSelectorReducer { @@ -99,7 +100,10 @@ internal object WalletSelectorReducer { ) } else { UserWalletModel.Type.SingleCurrency( - blockchainName = scanResponse.cardTypesResolver.getBlockchain().fullName, + blockchainName = store.state.daggerGraphState + .get(DaggerGraphState::cardTypeResolver) + .getBlockchain() + .fullName, ) } } diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index 005bcca0a4..983f4bc963 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -20,6 +20,7 @@ import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.unlockIfLockable import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler import com.tangem.tap.features.signin.redux.SignInAction +import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber @@ -79,7 +80,12 @@ internal class WelcomeMiddleware { private fun proceedWithCard(state: WelcomeState) = scope.launch { scanCardInternal { scanResponse -> - val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal + val userWallet = UserWalletBuilder( + scanResponse = scanResponse, + cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), + ) + .build() + ?: return@scanCardInternal userWalletsListManager.save(userWallet, canOverride = true) .doOnFailure { error -> diff --git a/app/src/main/java/com/tangem/tap/legacy/card/LegacyCardTypeResolver.kt b/app/src/main/java/com/tangem/tap/legacy/card/LegacyCardTypeResolver.kt new file mode 100644 index 0000000000..d44eda26cd --- /dev/null +++ b/app/src/main/java/com/tangem/tap/legacy/card/LegacyCardTypeResolver.kt @@ -0,0 +1,100 @@ +package com.tangem.tap.legacy.card + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token +import com.tangem.common.card.EllipticCurve +import com.tangem.common.card.FirmwareVersion +import com.tangem.common.card.WalletData +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.Provider +import com.tangem.domain.common.TapWorkarounds.isStart2Coin +import com.tangem.domain.common.TapWorkarounds.isTestCard +import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.models.scan.ProductType + +internal class LegacyCardTypeResolver( + private val cardProvider: Provider, + private val productTypeProvider: Provider, + private val walletDataProvider: Provider, +) : CardTypeResolver { + + private val card: CardDTO get() = cardProvider.invoke() + private val productType: ProductType get() = productTypeProvider.invoke() + private val walletData: WalletData? get() = walletDataProvider.invoke() + + override fun isTangemNote(): Boolean = productType == ProductType.Note + + override fun isTangemWallet(): Boolean { + return with(card.settings) { + isBackupAllowed && isHDWalletAllowed && card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable + } + } + + override fun isWallet2(): Boolean { + return with(card) { + firmwareVersion >= FirmwareVersion.KeysImportAvailable && settings.isKeysImportAllowed + } + } + + override fun isTangemTwins(): Boolean = productType == ProductType.Twins + + override fun isStart2Coin(): Boolean = card.isStart2Coin + + override fun isMultiwalletAllowed(): Boolean { + return (multiWalletAvailable() || card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1) && + !isTangemTwins() && !card.isStart2Coin && !isTangemNote() + } + + private fun multiWalletAvailable() = card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable + + override fun getBlockchain(): Blockchain { + if (productType == ProductType.Start2Coin) { + return if (card.isTestCard) Blockchain.BitcoinTestnet else Blockchain.Bitcoin + } + + val blockchainName = walletData?.blockchain + ?: return if (productType == ProductType.Note) { + TANGEM_NOTE_BATCHES[card.batchId] ?: Blockchain.Unknown + } else { + Blockchain.Unknown + } + + return Blockchain.fromBlockchainName(blockchainName) + } + + override fun getPrimaryToken(): Token? { + val cardToken = walletData?.token ?: return null + return Token( + name = cardToken.name, + symbol = cardToken.symbol, + contractAddress = cardToken.contractAddress, + decimals = cardToken.decimals, + ) + } + + private fun Blockchain.Companion.fromBlockchainName(name: String): Blockchain { + // workaround for BSC (BNB) notes cards + return when (name) { + "BINANCE" -> Blockchain.BSC + "BINANCE/test" -> Blockchain.BSCTestnet + else -> Blockchain.fromId(name) + } + } + + private companion object { + val TANGEM_NOTE_BATCHES = mapOf( + "AB01" to Blockchain.Bitcoin, + "AB02" to Blockchain.Ethereum, + "AB03" to Blockchain.CardanoShelley, + "AB04" to Blockchain.Dogecoin, + "AB05" to Blockchain.BSC, + "AB06" to Blockchain.XRP, + "AB07" to Blockchain.Bitcoin, + "AB08" to Blockchain.Ethereum, + "AB09" to Blockchain.Bitcoin, // new batches for 3.34 + "AB10" to Blockchain.Ethereum, + "AB11" to Blockchain.Bitcoin, + "AB12" to Blockchain.Ethereum, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/legacy/card/di/LegacyCardModule.kt b/app/src/main/java/com/tangem/tap/legacy/card/di/LegacyCardModule.kt new file mode 100644 index 0000000000..032d545891 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/legacy/card/di/LegacyCardModule.kt @@ -0,0 +1,34 @@ +package com.tangem.tap.legacy.card.di + +import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.Provider +import com.tangem.tap.legacy.card.LegacyCardTypeResolver +import com.tangem.tap.proxy.AppStateHolder +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object LegacyCardModule { + + @Provides + @Singleton + fun providesCardTypeResolver(reduxStateHolder: AppStateHolder): CardTypeResolver { + return LegacyCardTypeResolver( + cardProvider = Provider { + requireNotNull(reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse?.card) + }, + productTypeProvider = Provider { + requireNotNull( + value = reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse?.productType, + ) + }, + walletDataProvider = Provider { + requireNotNull(reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse).walletData + }, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt index c673ac8577..ba301a2fc1 100644 --- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt @@ -29,9 +29,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlin.coroutines.suspendCoroutine -class DerivationManagerImpl( - private val appStateHolder: AppStateHolder, -) : DerivationManager { +class DerivationManagerImpl(private val appStateHolder: AppStateHolder) : DerivationManager { override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine { continuation -> val blockchain = Blockchain.fromNetworkId(currency.networkId) diff --git a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt index 371f1e21bf..0f33e210b7 100644 --- a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt +++ b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt @@ -46,9 +46,7 @@ class ProxyModule { @Provides @Singleton fun provideDerivationManager(appStateHolder: AppStateHolder): DerivationManager { - return DerivationManagerImpl( - appStateHolder = appStateHolder, - ) + return DerivationManagerImpl(appStateHolder = appStateHolder) } // regions FeatureConsumers diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index a741e4dfd4..a4ca39f942 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -2,6 +2,7 @@ package com.tangem.tap.proxy.redux import com.tangem.datasource.asset.AssetReader import com.tangem.datasource.connection.NetworkConnectionManager +import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.card.ScanCardUseCase import com.tangem.features.tester.api.TesterRouter import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles @@ -23,6 +24,7 @@ data class DaggerGraphState( val walletConnectRepository: WalletConnectRepository? = null, val walletConnectSessionsRepository: WalletConnectSessionsRepository? = null, val walletConnectInteractor: WalletConnectInteractor? = null, + val cardTypeResolver: CardTypeResolver? = null, ) : StateType { inline fun get(getDependency: DaggerGraphState.() -> T?): T { diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/CardTypesResolver.kt b/domain/legacy/src/main/java/com/tangem/domain/card/CardTypeResolver.kt similarity index 84% rename from domain/legacy/src/main/java/com/tangem/domain/common/CardTypesResolver.kt rename to domain/legacy/src/main/java/com/tangem/domain/card/CardTypeResolver.kt index 72e1bfb243..97012f4efd 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/CardTypesResolver.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/card/CardTypeResolver.kt @@ -1,17 +1,23 @@ -package com.tangem.domain.common +package com.tangem.domain.card import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Token -interface CardTypesResolver { +interface CardTypeResolver { + fun isTangemNote(): Boolean + fun isTangemWallet(): Boolean + fun isWallet2(): Boolean + fun isTangemTwins(): Boolean + fun isStart2Coin(): Boolean fun isMultiwalletAllowed(): Boolean fun getBlockchain(): Blockchain + fun getPrimaryToken(): Token? } \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/Provider.kt b/domain/legacy/src/main/java/com/tangem/domain/common/Provider.kt new file mode 100644 index 0000000000..c77b356dfc --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/common/Provider.kt @@ -0,0 +1,10 @@ +package com.tangem.domain.common + +/** + * Provider for lazy initialization + * + * @param action initialization action + * +[REDACTED_AUTHOR] + */ +class Provider(action: () -> T) : () -> T by action \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt b/domain/legacy/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt deleted file mode 100644 index 79f908088a..0000000000 --- a/domain/legacy/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.tangem.domain.common - -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.Token -import com.tangem.common.card.EllipticCurve -import com.tangem.common.card.FirmwareVersion -import com.tangem.common.card.WalletData -import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain -import com.tangem.domain.common.TapWorkarounds.isStart2Coin -import com.tangem.domain.common.TapWorkarounds.isTestCard -import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.models.scan.ProductType - -class TangemCardTypesResolver( - private val card: CardDTO, - private val productType: ProductType, - private val walletData: WalletData?, -) : CardTypesResolver { - - override fun isTangemNote(): Boolean = productType == ProductType.Note - override fun isTangemWallet(): Boolean = card.settings.isBackupAllowed && - card.settings.isHDWalletAllowed && - card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable - - override fun isWallet2(): Boolean = - card.firmwareVersion >= FirmwareVersion.KeysImportAvailable && card.settings.isKeysImportAllowed - - override fun isTangemTwins(): Boolean = productType == ProductType.Twins - override fun isStart2Coin(): Boolean = card.isStart2Coin - - override fun isMultiwalletAllowed(): Boolean = !isTangemTwins() && - !card.isStart2Coin && - !isTangemNote() && - (multiWalletAvailable() || card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1) - - private fun multiWalletAvailable() = card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable - - override fun getBlockchain(): Blockchain { - return when (productType) { - ProductType.Start2Coin -> if (card.isTestCard) Blockchain.BitcoinTestnet else Blockchain.Bitcoin - else -> { - val blockchainName: String = walletData?.blockchain - ?: if (productType == ProductType.Note) { - return card.getTangemNoteBlockchain() ?: Blockchain.Unknown - } else { - return Blockchain.Unknown - } - Blockchain.fromBlockchainName(blockchainName) - } - } - } - - override fun getPrimaryToken(): Token? { - val cardToken = walletData?.token ?: return null - return Token( - cardToken.name, - cardToken.symbol, - cardToken.contractAddress, - cardToken.decimals, - ) - } -} - -private fun Blockchain.Companion.fromBlockchainName(blockchainName: String): Blockchain { - // workaround for BSC (BNB) notes cards - return when (blockchainName) { - "BINANCE" -> { - Blockchain.BSC - } - "BINANCE/test" -> { - Blockchain.BSCTestnet - } - else -> { - Blockchain.fromId(blockchainName) - } - } -} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt b/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt index 5d25521277..144e55921c 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt @@ -1,14 +1,13 @@ package com.tangem.domain.common -import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle -import com.tangem.common.card.Card import com.tangem.domain.models.scan.CardDTO -import java.util.* +import java.util.Locale /** [REDACTED_AUTHOR] */ +@Deprecated(message = "Use CardTypeResolver. [REDACTED_JIRA]") object TapWorkarounds { private const val START_2_COIN_ISSUER = "start2coin" private const val TEST_CARD_BATCH = "99FF" @@ -44,34 +43,11 @@ object TapWorkarounds { val CardDTO.isNotSupportedInThatRelease: Boolean get() = false - private val tangemNoteBatches = mapOf( - "AB01" to Blockchain.Bitcoin, - "AB02" to Blockchain.Ethereum, - "AB03" to Blockchain.CardanoShelley, - "AB04" to Blockchain.Dogecoin, - "AB05" to Blockchain.BSC, - "AB06" to Blockchain.XRP, - "AB07" to Blockchain.Bitcoin, - "AB08" to Blockchain.Ethereum, - "AB09" to Blockchain.Bitcoin, // new batches for 3.34 - "AB10" to Blockchain.Ethereum, - "AB11" to Blockchain.Bitcoin, - "AB12" to Blockchain.Ethereum, - ) - private val excludedBatches = listOf("0027", "0030", "0031", "0035") private val excludedIssuers = listOf("TTM BANK") - @Deprecated( - "Now blockchain is read form files (CardTypesResolver.getBlockchain), " + - "but for previously saved cards this method is still used", - ) - fun CardDTO.getTangemNoteBlockchain(): Blockchain? = tangemNoteBatches[batchId] - fun isStart2CoinIssuer(cardIssuer: String?): Boolean { return cardIssuer?.lowercase(Locale.US) == START_2_COIN_ISSUER } - - fun Card.getTangemNoteBlockchain(): Blockchain? = tangemNoteBatches[batchId] ?: null } \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/util/ScanResponseExtensions.kt b/domain/legacy/src/main/java/com/tangem/domain/common/util/ScanResponseExtensions.kt index 8438a87f14..8e7b1a2099 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/util/ScanResponseExtensions.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/util/ScanResponseExtensions.kt @@ -4,22 +4,13 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.toMapKey import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.common.CardTypesResolver -import com.tangem.domain.common.TangemCardTypesResolver import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.models.scan.ScanResponse -val ScanResponse.cardTypesResolver: CardTypesResolver - get() = TangemCardTypesResolver( - card = card, - productType = productType, - walletData = walletData, - ) - fun ScanResponse.twinsIsTwinned(): Boolean = card.isTangemTwins && walletData != null && secondTwinPublicKey != null + fun ScanResponse.supportsHdWallet(): Boolean = card.settings.isHDWalletAllowed -fun ScanResponse.supportsBackup(): Boolean = card.settings.isBackupAllowed fun ScanResponse.hasDerivation(blockchain: Blockchain, rawDerivationPath: String): Boolean { return hasDerivation(blockchain, DerivationPath(rawDerivationPath)) From 890048f5b2ae2e2ff60d714a602fb49ce6e01339 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 2 Jul 2023 16:05:28 +0800 Subject: [PATCH 53/54] Updated on 2026-08-14 --- .../ui/components/buttons/actions/Actions.kt | 4 +- .../components/notifications/Notification.kt | 10 ++- .../presentation/common/WalletPreviewData.kt | 15 ++-- .../wallet/state/WalletManageButtons.kt | 25 +++--- .../presentation/wallet/ui/WalletScreen.kt | 31 +++++--- .../wallet/ui/components/WalletsList.kt | 32 ++++---- .../wallet/ui/utils/ScrollOffsetCollector.kt | 37 +++++++++ .../ui/utils/WalletContentItemAnimator.kt | 76 +++++++++++++++++++ .../wallet/viewmodels/WalletViewModel.kt | 21 +++++ 9 files changed, 194 insertions(+), 57 deletions(-) create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/ScrollOffsetCollector.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/WalletContentItemAnimator.kt diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt index 027bad2d0c..068172b71e 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt @@ -9,6 +9,7 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow @@ -77,12 +78,13 @@ private fun Button( ) { Row( modifier = modifier - .clickable(enabled = config.enabled, onClick = config.onClick) .heightIn(min = TangemTheme.dimens.size36) + .clip(shape) .background( color = if (config.enabled) color else TangemTheme.colors.button.disabled, shape = shape, ) + .clickable(enabled = config.enabled, onClick = config.onClick) .padding( start = TangemTheme.dimens.spacing16, end = TangemTheme.dimens.spacing24, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt index 5bc16b167a..9d4f2cf480 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt @@ -11,6 +11,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview @@ -35,6 +36,11 @@ import com.tangem.core.ui.res.TangemTheme fun Notification(state: NotificationState, modifier: Modifier = Modifier) { Box( modifier = modifier + .clip(shape = RoundedCornerShape(size = TangemTheme.dimens.radius18)) + .background( + color = TangemTheme.colors.button.secondary, + shape = RoundedCornerShape(size = TangemTheme.dimens.radius18), + ) .clickable( enabled = when (state) { is NotificationState.Simple -> false @@ -45,10 +51,6 @@ fun Notification(state: NotificationState, modifier: Modifier = Modifier) { } else { {} }, - ) - .background( - color = TangemTheme.colors.button.secondary, - RoundedCornerShape(size = TangemTheme.dimens.radius18), ), ) { Box( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index 883b5c626d..fb462feaa9 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -22,7 +22,7 @@ internal object WalletPreviewData { balance = "8923,05 $", additionalInfo = "3 cards • Seed enabled", imageResId = R.drawable.ill_businessman_3d, - onClick = {}, + onClick = null, ) val walletCardLoadingState = WalletCardState.Loading( @@ -30,7 +30,7 @@ internal object WalletPreviewData { title = "Wallet 1", additionalInfo = "3 cards • Seed enabled", imageResId = R.drawable.ill_businessman_3d, - onClick = {}, + onClick = null, ) val walletCardHiddenContentState = WalletCardState.HiddenContent( @@ -38,7 +38,7 @@ internal object WalletPreviewData { title = "Wallet 1", additionalInfo = "3 cards • Seed enabled", imageResId = R.drawable.ill_businessman_3d, - onClick = {}, + onClick = null, ) val walletCardErrorState = WalletCardState.Error( @@ -46,7 +46,7 @@ internal object WalletPreviewData { title = "Wallet 1", additionalInfo = "3 cards • Seed enabled", imageResId = R.drawable.ill_businessman_3d, - onClick = {}, + onClick = null, ) val walletListConfig = WalletsListConfig( @@ -288,12 +288,7 @@ internal object WalletPreviewData { ), ), ), - notifications = persistentListOf( - WalletNotification.UnreachableNetworks, - WalletNotification.LikeTangemApp(onClick = {}), - WalletNotification.NeedToBackup(onClick = {}), - WalletNotification.ScanCard(onClick = {}), - ), + notifications = persistentListOf(WalletNotification.LikeTangemApp(onClick = {})), buttons = manageButtons, ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt index 1fd2c49db9..7d19a06e5a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt @@ -1,13 +1,11 @@ package com.tangem.feature.wallet.presentation.wallet.state import androidx.compose.foundation.background -import androidx.compose.foundation.horizontalScroll -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable -import androidx.compose.runtime.key +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -27,18 +25,19 @@ import kotlinx.collections.immutable.ImmutableList */ @Composable internal fun WalletManageButtons(buttons: ImmutableList, modifier: Modifier = Modifier) { - Row( + LazyRow( modifier = modifier - .horizontalScroll(state = rememberScrollState()) .background(color = TangemTheme.colors.background.secondary) .fillMaxWidth(), + contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16), horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing8), + verticalAlignment = Alignment.CenterVertically, ) { - buttons.forEach { button -> - key(button.config.text) { - ActionButton(config = button.config) - } - } + items( + items = buttons, + key = { it.config.text }, + itemContent = { ActionButton(config = it.config) }, + ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index 2246159c2f..bf417cd9b1 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -1,10 +1,12 @@ package com.tangem.feature.wallet.presentation.wallet.ui import androidx.activity.compose.BackHandler +import androidx.compose.animation.* import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -31,6 +33,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletTopBar import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletContentItemDecoration import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletNotificationDecoration +import com.tangem.feature.wallet.presentation.wallet.ui.utils.changeWalletAnimator /** * Wallet screen @@ -39,6 +42,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletNotifi * [REDACTED_AUTHOR] */ +@Suppress("LongMethod") @Composable internal fun WalletScreen(state: WalletStateHolder) { BackHandler(onBack = state.onBackClick) @@ -48,6 +52,9 @@ internal fun WalletScreen(state: WalletStateHolder) { containerColor = TangemTheme.colors.background.secondary, ) { scaffoldPaddings -> + val walletsListState = rememberLazyListState() + val changeableItemModifier = Modifier.changeWalletAnimator(walletsListState) + LazyColumn( modifier = Modifier .padding(paddingValues = scaffoldPaddings) @@ -58,6 +65,7 @@ internal fun WalletScreen(state: WalletStateHolder) { item { WalletsList( config = state.walletsListConfig, + lazyListState = walletsListState, modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing14), ) } @@ -66,9 +74,7 @@ internal fun WalletScreen(state: WalletStateHolder) { item { WalletManageButtons( buttons = state.buttons, - modifier = Modifier - .padding(horizontal = TangemTheme.dimens.spacing16) - .padding(bottom = TangemTheme.dimens.spacing14), + modifier = changeableItemModifier.padding(bottom = TangemTheme.dimens.spacing14), ) } } @@ -78,7 +84,7 @@ internal fun WalletScreen(state: WalletStateHolder) { itemContent = { index, item -> Notification( state = item.state, - modifier = Modifier.walletNotificationDecoration( + modifier = changeableItemModifier.walletNotificationDecoration( currentIndex = index, lastIndex = state.notifications.lastIndex, ), @@ -100,7 +106,7 @@ internal fun WalletScreen(state: WalletStateHolder) { itemContent = { index, item -> ContentItem( item = item, - modifier = Modifier.walletContentItemDecoration( + modifier = changeableItemModifier.walletContentItemDecoration( currentIndex = index, lastIndex = state.contentItems.lastIndex, ), @@ -109,7 +115,14 @@ internal fun WalletScreen(state: WalletStateHolder) { ) if (state is WalletStateHolder.MultiCurrencyContent) { - item { OrganizeTokensButton(onClick = state.onOrganizeTokensClick) } + item { + OrganizeTokensButton( + onClick = state.onOrganizeTokensClick, + modifier = changeableItemModifier + .padding(top = TangemTheme.dimens.spacing14) + .padding(horizontal = TangemTheme.dimens.spacing16), + ) + } } } } @@ -195,16 +208,14 @@ private fun TransactionGroupTitle( } @Composable -private fun OrganizeTokensButton(onClick: () -> Unit) { +private fun OrganizeTokensButton(onClick: () -> Unit, modifier: Modifier = Modifier) { RoundedActionButton( config = ActionButtonConfig( text = stringResource(id = R.string.organize_tokens_title), iconResId = R.drawable.ic_filter_24, onClick = onClick, ), - modifier = Modifier - .padding(top = TangemTheme.dimens.spacing8) - .padding(horizontal = TangemTheme.dimens.spacing16), + modifier = modifier, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletsList.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletsList.kt index bba70f8c1a..6c39b86f10 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletsList.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletsList.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState @@ -20,11 +21,8 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.wallet.presentation.common.WalletPreviewData import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig +import com.tangem.feature.wallet.presentation.wallet.ui.utils.ScrollOffsetCollector import kotlinx.coroutines.InternalCoroutinesApi -import kotlinx.coroutines.flow.FlowCollector - -private const val MIN_OFFSET = -2 -private const val MAX_OFFSET = 2 /** * Wallets list component @@ -36,11 +34,10 @@ private const val MAX_OFFSET = 2 */ @OptIn(ExperimentalFoundationApi::class, InternalCoroutinesApi::class) @Composable -internal fun WalletsList(config: WalletsListConfig, modifier: Modifier = Modifier) { +internal fun WalletsList(config: WalletsListConfig, lazyListState: LazyListState, modifier: Modifier = Modifier) { val horizontalCardPadding = TangemTheme.dimens.spacing16 val itemWidth = LocalConfiguration.current.screenWidthDp.dp - horizontalCardPadding * 2 - val lazyListState = rememberLazyListState() LazyRow( modifier = modifier.background(color = TangemTheme.colors.background.secondary), state = lazyListState, @@ -54,17 +51,8 @@ internal fun WalletsList(config: WalletsListConfig, modifier: Modifier = Modifie } LaunchedEffect(lazyListState) { - snapshotFlow(lazyListState::firstVisibleItemScrollOffset) - .collect( - collector = FlowCollector { firstVisibleItemScrollOffset -> - val itemSize = lazyListState.layoutInfo.visibleItemsInfo.firstOrNull()?.size ?: 1 - val offset = lazyListState.firstVisibleItemIndex * itemSize + firstVisibleItemScrollOffset - val currentIndex = offset / itemSize - if (offset - currentIndex * itemSize in MIN_OFFSET..MAX_OFFSET) { - config.onWalletChange(currentIndex) - } - }, - ) + snapshotFlow { lazyListState.layoutInfo.visibleItemsInfo } + .collect(collector = ScrollOffsetCollector(callback = config.onWalletChange)) } } @@ -72,7 +60,10 @@ internal fun WalletsList(config: WalletsListConfig, modifier: Modifier = Modifie @Composable private fun Preview_WalletHeader_LightTheme() { TangemTheme(isDark = false) { - WalletsList(config = WalletPreviewData.walletListConfig) + WalletsList( + config = WalletPreviewData.walletListConfig, + lazyListState = rememberLazyListState(), + ) } } @@ -80,6 +71,9 @@ private fun Preview_WalletHeader_LightTheme() { @Composable private fun Preview_WalletHeader_DarkTheme() { TangemTheme(isDark = true) { - WalletsList(config = WalletPreviewData.walletListConfig) + WalletsList( + config = WalletPreviewData.walletListConfig, + lazyListState = rememberLazyListState(), + ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/ScrollOffsetCollector.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/ScrollOffsetCollector.kt new file mode 100644 index 0000000000..b0b2072867 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/ScrollOffsetCollector.kt @@ -0,0 +1,37 @@ +package com.tangem.feature.wallet.presentation.wallet.ui.utils + +import androidx.compose.foundation.lazy.LazyListItemInfo +import kotlinx.coroutines.flow.FlowCollector +import kotlin.math.abs + +/** + * Flow collector for scroll items tracking. + * If first visible item offset is greater than half item size, then [callback] be invoked. + * If last visible item offset is greater than half item size, then [callback] be invoked. + * + * @property callback lambda be invoked when current scroll items is changed + * +[REDACTED_AUTHOR] + */ +internal class ScrollOffsetCollector( + private val callback: (Int) -> Unit, +) : FlowCollector> { + + private val LazyListItemInfo.halfItemSize get() = size.div(other = 2) + + override suspend fun emit(value: List) { + val firstItem = requireNotNull(value.firstOrNull()) { + "At least 1 item should be visible in list" + } + + val lastItem = requireNotNull(value.lastOrNull()) { + "At least 1 item should be visible in list" + } + + if (abs(firstItem.offset) > firstItem.halfItemSize) { + callback(firstItem.index + 1) + } else if (abs(lastItem.offset) > lastItem.halfItemSize) { + callback(lastItem.index - 1) + } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/WalletContentItemAnimator.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/WalletContentItemAnimator.kt new file mode 100644 index 0000000000..61564d220c --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/WalletContentItemAnimator.kt @@ -0,0 +1,76 @@ +package com.tangem.feature.wallet.presentation.wallet.ui.utils + +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.layout.absoluteOffset +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.unit.dp + +private const val ANIMATION_MAX_OFFSET = 80 +private const val ANIMATION_MAX_ALPHA = 1f + +/** + * Modifier extension for setting [absoluteOffset] and [alpha] animations of wallet change + * + * @param lazyListState lazy list state + * +[REDACTED_AUTHOR] + */ +internal fun Modifier.changeWalletAnimator(lazyListState: LazyListState) = composed { + val walletItemOffset by remember(lazyListState) { derivedStateOf { lazyListState.firstVisibleItemScrollOffset } } + + val walletItemSize by remember(lazyListState) { + derivedStateOf { lazyListState.layoutInfo.visibleItemsInfo.firstOrNull()?.size ?: 1 } + } + + val walletHalfItemSize by remember { + derivedStateOf { walletItemSize / 2 } + } + + val contentOffsetY by remember { + derivedStateOf { + /* + * Until [walletItemOffset] is less than [walletHalfItemSize], + * then content offset animation has positive value (downward movement). + * Otherwise, it has negative value (upward movement). + */ + val position = if (walletItemOffset < walletHalfItemSize) { + walletItemOffset + } else { + walletItemSize - walletItemOffset + } + + ANIMATION_MAX_OFFSET.dp / walletItemSize * position + } + } + + val contentAlpha by remember { + derivedStateOf { + /* + * Until [walletItemOffset] is less than [walletHalfItemSize], + * then content alpha animation has negative value (fade out). + * Otherwise, it has positive value (fade in). + */ + val position = if (walletItemOffset < walletHalfItemSize) { + walletHalfItemSize - walletItemOffset + } else { + walletItemOffset - walletHalfItemSize + } + + ANIMATION_MAX_ALPHA / walletHalfItemSize * position + } + } + + val animatedOffsetY by animateDpAsState(targetValue = contentOffsetY) + val animatedContentAlpha by animateFloatAsState(targetValue = contentAlpha) + + this + .absoluteOffset(y = animatedOffsetY) + .alpha(alpha = animatedContentAlpha) +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index dd643d7352..e13dad1715 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -1,5 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels +import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -32,5 +33,25 @@ internal class WalletViewModel @Inject constructor() : ViewModel() { topBarConfig = WalletPreviewData.multicurrencyWalletScreenState.topBarConfig.copy( onScanCardClick = { router.openOrganizeTokensScreen() }, ), + walletsListConfig = WalletPreviewData.multicurrencyWalletScreenState.walletsListConfig.copy( + onWalletChange = ::selectWallet, + ), ) + + // TODO: [REDACTED_TASK_KEY] Use production data instead of WalletPreviewData + private fun selectWallet(index: Int) { + if (uiState.walletsListConfig.selectedWalletIndex == index) return + + Log.i("WalletViewModel", "selectWallet: $index") + + uiState = if (index % 2 == 0) { + WalletPreviewData.multicurrencyWalletScreenState.copy( + walletsListConfig = uiState.walletsListConfig.copy(selectedWalletIndex = index), + ) + } else { + WalletPreviewData.singleWalletScreenState.copy( + walletsListConfig = uiState.walletsListConfig.copy(selectedWalletIndex = index), + ) + } + } } \ No newline at end of file From 8163b80ad36c95ad4658130a16e2037257e3ea44 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 4 Jul 2023 23:23:08 +0800 Subject: [PATCH 54/54] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 10 -- .../converters/ParamCardCurrencyConverter.kt | 6 +- .../converters/TopUpEventConverter.kt | 6 +- .../CardContextInterceptor.kt | 5 +- .../LinkedCardContextInterceptor.kt | 6 +- .../common/analytics/topup/TopUpController.kt | 12 +-- .../tangem/tap/common/extensions/Analytics.kt | 13 +-- .../java/com/tangem/tap/di/ActivityModule.kt | 9 +- .../com/tangem/tap/domain/TangemSdkManager.kt | 14 +-- .../com/tangem/tap/domain/TapWalletManager.kt | 15 ++- .../domain/extensions/WalletManagerFactory.kt | 49 +++++++-- .../model/builders/UserWalletBuilder.kt | 7 +- .../model/builders/WalletStoreBuilder.kt | 25 ++--- .../domain/scanCard/LegacyScanProcessor.kt | 31 ++---- .../domain/scanCard/UseCaseScanProcessor.kt | 7 +- .../domain/scanCard/chains/AnalyticsChain.kt | 7 +- .../chains/CheckForOnboardingChain.kt | 16 +-- .../tasks/product/CreateProductWalletTask.kt | 12 +-- .../di/WalletCurrenciesManagerProvider.kt | 5 - .../DefaultWalletCurrenciesManager.kt | 9 +- .../di/WalletsStoresManagerProvider.kt | 12 +-- .../DefaultWalletStoresManager.kt | 22 ++-- .../repository/di/RepositoryProvider.kt | 5 +- .../DefaultWalletManagersRepository.kt | 32 ++++-- .../demo/DemoOnboardingNoteMiddleware.kt | 14 +-- .../features/details/redux/DetailsAction.kt | 3 +- .../details/redux/DetailsMiddleware.kt | 20 ++-- .../features/details/redux/DetailsReducer.kt | 61 ++++++----- .../walletconnect/WalletConnectMiddleware.kt | 4 +- .../details/ui/details/DetailsViewModel.kt | 10 +- .../tap/features/home/redux/HomeMiddleware.kt | 14 +-- .../features/onboarding/OnboardingHelper.kt | 25 ++--- .../note/redux/OnboardingNoteMiddleware.kt | 14 +-- .../redux/OnboardingOtherCardsMiddleware.kt | 13 ++- .../twins/redux/TwinCardsMiddleware.kt | 6 +- .../products/twins/redux/TwinCardsReducer.kt | 6 +- .../redux/OnboardingWalletMiddleware.kt | 14 +-- .../saveWallet/redux/SaveWalletMiddleware.kt | 13 +-- .../tap/features/wallet/redux/WalletState.kt | 4 + .../middlewares/MultiWalletMiddleware.kt | 6 +- .../redux/middlewares/WarningsMiddleware.kt | 11 +- .../tap/features/wallet/ui/WalletViewModel.kt | 5 +- .../redux/WalletSelectorMiddleware.kt | 7 +- .../redux/WalletSelectorReducer.kt | 8 +- .../welcome/redux/WelcomeMiddleware.kt | 8 +- .../tap/legacy/card/LegacyCardTypeResolver.kt | 100 ------------------ .../tap/legacy/card/di/LegacyCardModule.kt | 34 ------ .../tangem/tap/proxy/DerivationManagerImpl.kt | 4 +- .../com/tangem/tap/proxy/di/ProxyModule.kt | 4 +- .../tap/proxy/redux/DaggerGraphState.kt | 2 - .../CardTypesResolver.kt} | 10 +- .../java/com/tangem/domain/common/Provider.kt | 10 -- .../domain/common/TangemCardTypesResolver.kt | 77 ++++++++++++++ .../tangem/domain/common/TapWorkarounds.kt | 28 ++++- .../common/util/ScanResponseExtensions.kt | 11 +- 55 files changed, 389 insertions(+), 492 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/legacy/card/LegacyCardTypeResolver.kt delete mode 100644 app/src/main/java/com/tangem/tap/legacy/card/di/LegacyCardModule.kt rename domain/legacy/src/main/java/com/tangem/domain/{card/CardTypeResolver.kt => common/CardTypesResolver.kt} (84%) delete mode 100644 domain/legacy/src/main/java/com/tangem/domain/common/Provider.kt create mode 100644 domain/legacy/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index f043370e21..114746ccdb 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -20,9 +20,7 @@ import com.tangem.datasource.config.FeaturesLocalLoader import com.tangem.datasource.config.models.Config import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.domain.DomainLayer -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.LogConfig -import com.tangem.domain.common.Provider import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.tap.common.analytics.AnalyticsFactory @@ -84,7 +82,6 @@ private val walletManagersRepository by lazy { ?.blockchainSdkConfig ?: BlockchainSdkConfig(), ), - cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) }, ) } private val walletAmountsRepository by lazy { @@ -99,7 +96,6 @@ val walletStoresManager by lazy { walletManagersRepository = walletManagersRepository, walletAmountsRepository = walletAmountsRepository, appCurrencyProvider = { store.state.globalState.appCurrency }, - cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) }, ) } val walletCurrenciesManager by lazy { @@ -109,7 +105,6 @@ val walletCurrenciesManager by lazy { walletManagersRepository = walletManagersRepository, walletAmountsRepository = walletAmountsRepository, appCurrencyProvider = { store.state.globalState.appCurrency }, - cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) }, ) } val totalFiatBalanceCalculator by lazy { @@ -152,9 +147,6 @@ class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var learn2earnInteractor: Learn2earnInteractor - @Inject - lateinit var cardTypeResolver: CardTypeResolver - override fun onCreate() { super.onCreate() @@ -171,7 +163,6 @@ class TapApplication : Application(), ImageLoaderFactory { walletFeatureToggles = walletFeatureToggles, walletConnectRepository = walletConnect2Repository, walletConnectSessionsRepository = walletConnectSessionsRepository, - cardTypeResolver = cardTypeResolver, ), ), ) @@ -228,7 +219,6 @@ class TapApplication : Application(), ImageLoaderFactory { }, walletStoresManagerProvider = { walletStoresManager }, topupWalletStorage = preferencesStorage.toppedUpWalletStorage, - cardTypeResolver = cardTypeResolver, ) store.dispatch(GlobalAction.SetTopUpController(topUpController)) } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt index 5b60885d4b..0a7928efd5 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt @@ -2,15 +2,15 @@ package com.tangem.tap.common.analytics.converters import com.tangem.blockchain.common.Blockchain import com.tangem.common.Converter -import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.CardTypesResolver import com.tangem.tap.common.analytics.events.AnalyticsParam /** [REDACTED_AUTHOR] */ -class ParamCardCurrencyConverter : Converter { +class ParamCardCurrencyConverter : Converter { - override fun convert(value: CardTypeResolver): AnalyticsParam.CardCurrency? { + override fun convert(value: CardTypesResolver): AnalyticsParam.CardCurrency? { if (value.isMultiwalletAllowed()) return AnalyticsParam.CardCurrency.MultiCurrency val type = when { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpEventConverter.kt index 29b374687f..429b2e5ebc 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpEventConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/TopUpEventConverter.kt @@ -1,15 +1,15 @@ package com.tangem.tap.common.analytics.converters import com.tangem.common.Converter -import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.CardTypesResolver import com.tangem.tap.common.analytics.events.Basic /** [REDACTED_AUTHOR] */ -class TopUpEventConverter : Converter { +class TopUpEventConverter : Converter { - override fun convert(value: CardTypeResolver): Basic.ToppedUp? { + override fun convert(value: CardTypesResolver): Basic.ToppedUp? { val paramCardCurrency = ParamCardCurrencyConverter().convert(value) ?: return null return Basic.ToppedUp(paramCardCurrency) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt index e35f0f1143..864c9dadbb 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt @@ -2,7 +2,7 @@ package com.tangem.tap.common.analytics.paramsInterceptor import com.tangem.core.analytics.AnalyticsEvent import com.tangem.core.analytics.api.ParamsInterceptor -import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter @@ -16,7 +16,6 @@ import com.tangem.tap.features.demo.DemoHelper */ class CardContextInterceptor( private val scanResponse: ScanResponse?, - private val cardTypeResolver: CardTypeResolver, ) : ParamsInterceptor { override fun id(): String = CardContextInterceptor.id() @@ -36,7 +35,7 @@ class CardContextInterceptor( params[AnalyticsParam.PRODUCT_TYPE] = getProductType(scanResponse) params[AnalyticsParam.FIRMWARE] = card.firmwareVersion.stringValue - ParamCardCurrencyConverter().convert(cardTypeResolver)?.let { + ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver)?.let { params[AnalyticsParam.CURRENCY] = it.value } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt index 5cf8c767fb..94c006d699 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/LinkedCardContextInterceptor.kt @@ -2,19 +2,17 @@ package com.tangem.tap.common.analytics.paramsInterceptor import com.tangem.core.analytics.AnalyticsEvent import com.tangem.core.analytics.api.ParamsInterceptor -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.models.scan.ScanResponse /** [REDACTED_AUTHOR] */ class LinkedCardContextInterceptor( - scanResponse: ScanResponse, - cardTypeResolver: CardTypeResolver, + private val scanResponse: ScanResponse, val parent: LinkedCardContextInterceptor? = null, ) : ParamsInterceptor { - private val contextInterceptor = CardContextInterceptor(scanResponse, cardTypeResolver) + private val contextInterceptor = CardContextInterceptor(scanResponse) override fun id(): String = LinkedCardContextInterceptor.id() diff --git a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt index 27cea44be1..97edaae4c1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt @@ -5,8 +5,9 @@ import com.tangem.common.extensions.isZero import com.tangem.core.analytics.Analytics import com.tangem.data.source.preferences.model.DataSourceTopupInfo import com.tangem.data.source.preferences.storage.ToppedUpWalletStorage -import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.util.UserWalletId +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.analytics.converters.TopUpEventConverter import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -31,7 +32,6 @@ class TopUpController( var scanResponseProvider: (() -> ScanResponse?)? = null, var walletStoresManagerProvider: (() -> WalletStoresManager)? = null, private val topupWalletStorage: ToppedUpWalletStorage, - private val cardTypeResolver: CardTypeResolver, ) : WalletCurrenciesManager.Listener { private var hadMissedDerivations: Boolean = false @@ -100,7 +100,7 @@ class TopUpController( } val cardBalanceState = BalanceCalculator(walletDataModels).calculate().toCardBalanceState() - send(userWalletId, cardBalanceState, cardTypeResolver) + send(userWalletId, cardBalanceState, scanResponse.cardTypesResolver) } } @@ -120,14 +120,14 @@ class TopUpController( fun send(scanResponse: ScanResponse, cardBalanceState: AnalyticsParam.CardBalanceState) { UserWalletIdBuilder.scanResponse(scanResponse).build()?.let { - send(it, cardBalanceState, cardTypeResolver) + send(it, cardBalanceState, scanResponse.cardTypesResolver) } } fun send( userWalletId: UserWalletId, cardBalanceState: AnalyticsParam.CardBalanceState, - cardTypeResolver: CardTypeResolver, + cardTypesResolver: CardTypesResolver, ) { val topupInfo = topupWalletStorage.restore(userWalletId.stringValue).guard { val topupInfo = DataSourceTopupInfo( @@ -152,7 +152,7 @@ class TopUpController( if (cardBalanceState.isToppedUp()) { topupWalletStorage.save(topupInfo.copy(cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full)) - TopUpEventConverter().convert(cardTypeResolver)?.let { + TopUpEventConverter().convert(cardTypesResolver)?.let { Analytics.send(it) } } diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt b/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt index 58c13e282c..8e79d07381 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Analytics.kt @@ -1,7 +1,6 @@ package com.tangem.tap.common.extensions import com.tangem.core.analytics.Analytics -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterceptor @@ -12,8 +11,8 @@ import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterc /** * Sets the new context */ -fun Analytics.setContext(scanResponse: ScanResponse, cardTypeResolver: CardTypeResolver) { - addParamsInterceptor(LinkedCardContextInterceptor(scanResponse, cardTypeResolver)) +fun Analytics.setContext(scanResponse: ScanResponse) { + addParamsInterceptor(LinkedCardContextInterceptor(scanResponse)) } /** @@ -26,13 +25,9 @@ fun Analytics.eraseContext() { /** * Adds a new context and keeps a previous context as the parent of the new one */ -fun Analytics.addContext(scanResponse: ScanResponse, cardTypeResolver: CardTypeResolver) { +fun Analytics.addContext(scanResponse: ScanResponse) { val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) as? LinkedCardContextInterceptor - val newContext = LinkedCardContextInterceptor( - scanResponse = scanResponse, - cardTypeResolver = cardTypeResolver, - parent = currentContext, - ) + val newContext = LinkedCardContextInterceptor(scanResponse, parent = currentContext) addParamsInterceptor(newContext) } diff --git a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt index 67ce9fa481..96639f64e4 100644 --- a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt +++ b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt @@ -3,7 +3,6 @@ package com.tangem.tap.di import android.content.Context import androidx.fragment.app.FragmentActivity import com.tangem.TangemSdk -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.card.ScanCardUseCase import com.tangem.sdk.extensions.initWithBiometrics import com.tangem.tap.domain.TangemSdkManager @@ -28,12 +27,8 @@ internal object ActivityModule { @Provides @ActivityScoped - fun provideTangemSdkManager( - @ActivityContext context: Context, - tangemSdk: TangemSdk, - cardTypeResolver: CardTypeResolver, - ): TangemSdkManager { - return TangemSdkManager(tangemSdk, context, cardTypeResolver) + fun provideTangemSdkManager(@ActivityContext context: Context, tangemSdk: TangemSdk): TangemSdkManager { + return TangemSdkManager(tangemSdk, context) } @Provides diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 83ddb84e62..c395569c5c 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -14,7 +14,7 @@ import com.tangem.common.usersCode.UserCodeRepository import com.tangem.core.analytics.Analytics import com.tangem.crypto.bip39.DefaultMnemonic import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.operations.ScanTask @@ -38,11 +38,7 @@ import kotlinx.coroutines.withContext import kotlin.coroutines.resume @Suppress("TooManyFunctions") -class TangemSdkManager( - private val tangemSdk: TangemSdk, - private val context: Context, - private val cardTypeResolver: CardTypeResolver, -) { +class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) { private val userCodeRepository by lazy { UserCodeRepository( @@ -82,7 +78,7 @@ class TangemSdkManager( suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult { return runTaskAsync( - CreateProductWalletTask(cardTypeResolver), + CreateProductWalletTask(scanResponse.cardTypesResolver), scanResponse.card.cardId, Message(context.getString(R.string.initial_message_create_wallet_body)), ) @@ -94,7 +90,7 @@ class TangemSdkManager( ): CompletionResult { return when (val seedResult = DefaultMnemonic(mnemonic, tangemSdk.wordlist).generateSeed()) { is CompletionResult.Success -> runTaskAsync( - CreateProductWalletTask(cardTypeResolver, seedResult.data), + CreateProductWalletTask(scanResponse.cardTypesResolver, seedResult.data), scanResponse.card.cardId, Message(context.getString(R.string.initial_message_create_wallet_body)), ) @@ -232,7 +228,7 @@ class TangemSdkManager( fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?) { tangemSdk.config.cardIdDisplayFormat = when { scanResponse == null -> CardIdDisplayFormat.Full - cardTypeResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4) + scanResponse.cardTypesResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4) else -> CardIdDisplayFormat.Full } } diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index ae8c0cc795..4e39b73bbe 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -9,6 +9,8 @@ import com.tangem.common.doOnSuccess import com.tangem.core.analytics.Analytics import com.tangem.datasource.config.ConfigManager import com.tangem.domain.common.extensions.withMainContext +import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.models.scan.ScanResponse import com.tangem.operations.attestation.Attestation import com.tangem.tap.* import com.tangem.tap.common.analytics.events.Basic @@ -23,7 +25,6 @@ import com.tangem.tap.features.disclaimer.createDisclaimer import com.tangem.tap.features.disclaimer.redux.DisclaimerAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.CoroutineScope @@ -57,10 +58,7 @@ class TapWalletManager( } private suspend fun loadUserWalletData(userWallet: UserWallet, refresh: Boolean, sendAnalyticsEvent: Boolean) { - Analytics.setContext( - scanResponse = userWallet.scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + Analytics.setContext(userWallet.scanResponse) if (sendAnalyticsEvent) { Analytics.send(Basic.WalletOpened()) } @@ -70,7 +68,7 @@ class TapWalletManager( tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse) store.state.globalState.feedbackManager?.infoHolder?.setCardInfo(scanResponse) - updateConfigManager() + updateConfigManager(scanResponse) withMainContext { // Order is important store.dispatch(DisclaimerAction.SetDisclaimer(card.createDisclaimer())) @@ -137,11 +135,10 @@ class TapWalletManager( } } - fun updateConfigManager() { + fun updateConfigManager(data: ScanResponse) { val configManager = store.state.globalState.configManager - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - if (cardTypeResolver.isStart2Coin()) { + if (data.cardTypesResolver.isStart2Coin()) { configManager?.turnOff(ConfigManager.IS_TOP_UP_ENABLED) } else { configManager?.resetToDefault(ConfigManager.IS_TOP_UP_ENABLED) diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt index c2776941b7..a9de7cb47a 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt @@ -1,19 +1,24 @@ package com.tangem.tap.domain.extensions -import com.tangem.blockchain.common.* +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.DerivationParams +import com.tangem.blockchain.common.DerivationStyle +import com.tangem.blockchain.common.WalletManager +import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toMapKey import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse +import com.tangem.tap.domain.tokens.models.BlockchainNetwork +import com.tangem.tap.features.wallet.models.Currency fun WalletManagerFactory.makeWalletManagerForApp( scanResponse: ScanResponse, - cardTypeResolver: CardTypeResolver, blockchain: Blockchain, derivationParams: DerivationParams?, ): WalletManager? { @@ -29,7 +34,7 @@ fun WalletManagerFactory.makeWalletManagerForApp( val seedKey = wallet.extendedPublicKey return when { - cardTypeResolver.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> { + scanResponse.cardTypesResolver.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> { makeTwinWalletManager( walletPublicKey = wallet.publicKey, pairPublicKey = scanResponse.secondTwinPublicKey!!.hexToBytes(), @@ -63,6 +68,17 @@ fun WalletManagerFactory.makeWalletManagerForApp( } } +fun WalletManagerFactory.makeWalletManagerForApp( + scanResponse: ScanResponse, + blockchainNetwork: BlockchainNetwork, +): WalletManager? { + return makeWalletManagerForApp( + scanResponse, + blockchain = blockchainNetwork.blockchain, + derivationParams = getDerivationParams(blockchainNetwork.derivationPath, scanResponse.card), + ) +} + private fun getDerivationParams(derivationPath: String?, card: CardDTO): DerivationParams? { return derivationPath?.let { DerivationParams.Custom( @@ -77,19 +93,32 @@ private fun getDerivationParams(derivationPath: String?, card: CardDTO): Derivat } } -fun WalletManagerFactory.makePrimaryWalletManager( +fun WalletManagerFactory.makeWalletManagerForApp(scanResponse: ScanResponse, currency: Currency): WalletManager? { + return makeWalletManagerForApp( + scanResponse, + blockchain = currency.blockchain, + derivationParams = getDerivationParams(currency.derivationPath, scanResponse.card), + ) +} + +fun WalletManagerFactory.makeWalletManagersForApp( scanResponse: ScanResponse, - cardTypeResolver: CardTypeResolver, -): WalletManager? { + blockchains: List, +): List { + return blockchains + .filter { it.isBlockchain() } + .mapNotNull { this.makeWalletManagerForApp(scanResponse, it) } +} + +fun WalletManagerFactory.makePrimaryWalletManager(scanResponse: ScanResponse): WalletManager? { val blockchain = if (scanResponse.card.isTestCard) { - cardTypeResolver.getBlockchain().getTestnetVersion() ?: return null + scanResponse.cardTypesResolver.getBlockchain().getTestnetVersion() ?: return null } else { - cardTypeResolver.getBlockchain() + scanResponse.cardTypesResolver.getBlockchain() } val derivationParams = getDerivationParams(null, scanResponse.card) return makeWalletManagerForApp( scanResponse = scanResponse, - cardTypeResolver = cardTypeResolver, blockchain = blockchain, derivationParams = derivationParams, ) diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt index 6fc426781c..d4e6cbd1fc 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt @@ -1,16 +1,15 @@ package com.tangem.tap.domain.model.builders -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.common.TapWorkarounds.isStart2Coin +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.userWalletList.GetCardImageUseCase class UserWalletBuilder( private val scanResponse: ScanResponse, - private val cardTypeResolver: CardTypeResolver, private val getCardImageUseCase: GetCardImageUseCase = GetCardImageUseCase(), ) { private var backupCardsIds: Set = emptySet() @@ -47,7 +46,7 @@ class UserWalletBuilder( artworkUrl = getCardImageUseCase.invoke(card.cardId, card.cardPublicKey), cardsInWallet = backupCardsIds.plus(card.cardId), scanResponse = this, - isMultiCurrency = cardTypeResolver.isMultiwalletAllowed(), + isMultiCurrency = cardTypesResolver.isMultiwalletAllowed(), ) } } diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index 57838dad8d..e7d01ecdb6 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -1,10 +1,14 @@ package com.tangem.tap.domain.model.builders import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider -import com.tangem.blockchain.common.* +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.DerivationStyle +import com.tangem.blockchain.common.Token +import com.tangem.blockchain.common.Wallet +import com.tangem.blockchain.common.WalletManager import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.TapWorkarounds.derivationStyle +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel @@ -25,25 +29,19 @@ interface WalletStoreBuilder { companion object { operator fun invoke( userWallet: UserWallet, - cardTypeResolver: CardTypeResolver, blockchainNetwork: BlockchainNetwork, ): BlockchainNetworkWalletStoreBuilder { - return BlockchainNetworkWalletStoreBuilderImpl(userWallet, cardTypeResolver, blockchainNetwork) + return BlockchainNetworkWalletStoreBuilderImpl(userWallet, blockchainNetwork) } - operator fun invoke( - userWallet: UserWallet, - cardTypeResolver: CardTypeResolver, - walletManager: WalletManager, - ): WalletMangerWalletStoreBuilder { - return WalletMangerWalletStoreBuilderImpl(userWallet, cardTypeResolver, walletManager) + operator fun invoke(userWallet: UserWallet, walletManager: WalletManager): WalletMangerWalletStoreBuilder { + return WalletMangerWalletStoreBuilderImpl(userWallet, walletManager) } } } private class BlockchainNetworkWalletStoreBuilderImpl( private val userWallet: UserWallet, - private val cardTypeResolver: CardTypeResolver, private val blockchainNetwork: BlockchainNetwork, ) : WalletStoreBuilder.BlockchainNetworkWalletStoreBuilder { private var walletManager: WalletManager? = null @@ -58,7 +56,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl( val tokensWalletsData = blockchainNetwork.getTokensWalletsData( walletManager = walletManager, cardDerivationStyle = cardDerivationStyle, - primaryToken = cardTypeResolver.getPrimaryToken(), + primaryToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken(), ) return WalletStoreModel( @@ -75,7 +73,6 @@ private class BlockchainNetworkWalletStoreBuilderImpl( private class WalletMangerWalletStoreBuilderImpl( private val userWallet: UserWallet, - private val cardTypeResolver: CardTypeResolver, private val walletManager: WalletManager, ) : WalletStoreBuilder.WalletMangerWalletStoreBuilder { @@ -84,7 +81,7 @@ private class WalletMangerWalletStoreBuilderImpl( val blockchainWalletData = wallet.blockchain.toBlockchainWalletData(walletManager) val tokenWalletsData = wallet.getTokens().firstOrNull()?.toTokenWalletData( walletManager = walletManager, - primaryToken = cardTypeResolver.getPrimaryToken(), + primaryToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken(), ) return WalletStoreModel( diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt index 6009ec32df..f885b4fa13 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt @@ -7,7 +7,6 @@ import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.AnalyticsEvent -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ScanResponse @@ -23,7 +22,6 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep -import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -73,11 +71,7 @@ internal object LegacyScanProcessor { tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse) onScanStateChange(false) - sendAnalytics( - analyticsEvent = analyticsEvent, - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + sendAnalytics(analyticsEvent, scanResponse) showDisclaimerIfNeed( scanResponse = scanResponse, @@ -95,14 +89,10 @@ internal object LegacyScanProcessor { } } - private fun sendAnalytics( - analyticsEvent: AnalyticsEvent?, - scanResponse: ScanResponse, - cardTypeResolver: CardTypeResolver, - ) { + private fun sendAnalytics(analyticsEvent: AnalyticsEvent?, scanResponse: ScanResponse) { analyticsEvent?.let { // this workaround needed to send CardWasScannedEvent without adding a context - val interceptor = CardContextInterceptor(scanResponse, cardTypeResolver) + val interceptor = CardContextInterceptor(scanResponse) val params = it.params.toMutableMap() interceptor.intercept(params) it.params = params.toMap() @@ -156,25 +146,18 @@ internal object LegacyScanProcessor { ) { val globalState = store.state.globalState val tapWalletManager = globalState.tapWalletManager - tapWalletManager.updateConfigManager() + tapWalletManager.updateConfigManager(scanResponse) store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse)) - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - if (OnboardingHelper.isOnboardingCase(scanResponse, cardTypeResolver)) { - Analytics.addContext( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + if (OnboardingHelper.isOnboardingCase(scanResponse)) { + Analytics.addContext(scanResponse) onWalletNotCreated() store.dispatchOnMain(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = true)) val appScreen = OnboardingHelper.whereToNavigate(scanResponse) navigateTo(appScreen) { onProgressStateChange(it) } } else { - Analytics.setContext( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + Analytics.setContext(scanResponse) if (scanResponse.twinsIsTwinned() && !preferencesStorage.wasTwinsOnboardingShown()) { onWalletNotCreated() store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse))) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt index 04249c892c..45a463343a 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/UseCaseScanProcessor.kt @@ -49,12 +49,7 @@ internal object UseCaseScanProcessor { val chains = buildList { add(ScanningFinishedChain { onScanStateChange(false) }) if (analyticsEvent != null) { - add( - AnalyticsChain( - event = analyticsEvent, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ), - ) + add(AnalyticsChain(analyticsEvent)) } add(DisclaimerChain(store, disclaimerWillShow)) add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager, preferencesStorage)) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/AnalyticsChain.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/AnalyticsChain.kt index d065b20148..febc6a1525 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/AnalyticsChain.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/AnalyticsChain.kt @@ -4,7 +4,6 @@ import arrow.core.Either import arrow.core.right import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.AnalyticsEvent -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.card.ScanCardException import com.tangem.domain.core.chain.Chain import com.tangem.domain.models.scan.ScanResponse @@ -20,16 +19,12 @@ import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor */ class AnalyticsChain( private val event: AnalyticsEvent, - private val cardTypeResolver: CardTypeResolver, ) : Chain { override suspend fun invoke( previousChainResult: ScanResponse, ): Either { - val interceptor = CardContextInterceptor( - scanResponse = previousChainResult, - cardTypeResolver = cardTypeResolver, - ) + val interceptor = CardContextInterceptor(previousChainResult) val params = event.params.toMutableMap() interceptor.intercept(params) event.params = params.toMap() diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt index d17b6c84c3..ce46f2f527 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/chains/CheckForOnboardingChain.kt @@ -20,7 +20,6 @@ import com.tangem.tap.domain.TapWalletManager import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep -import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import org.rekotlin.Store @@ -45,25 +44,18 @@ class CheckForOnboardingChain( override suspend fun invoke( previousChainResult: ScanResponse, ): Either { - tapWalletManager.updateConfigManager() + tapWalletManager.updateConfigManager(previousChainResult) store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(previousChainResult)) - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) return when { - OnboardingHelper.isOnboardingCase(previousChainResult, cardTypeResolver) -> { - Analytics.addContext( - scanResponse = previousChainResult, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + OnboardingHelper.isOnboardingCase(previousChainResult) -> { + Analytics.addContext(previousChainResult) store.dispatchOnMain(GlobalAction.Onboarding.Start(previousChainResult, canSkipBackup = true)) val appScreen = OnboardingHelper.whereToNavigate(previousChainResult) ScanChainException.OnboardingNeeded(appScreen).left() } else -> { - Analytics.setContext( - scanResponse = previousChainResult, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + Analytics.setContext(previousChainResult) // If twins was twinned previously but twins welcome not shown if (previousChainResult.twinsIsTwinned() && !preferencesStore.wasTwinsOnboardingShown()) { store.dispatchOnMain( diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt index 23225a2a25..d23e9fde5c 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt @@ -12,7 +12,7 @@ import com.tangem.common.extensions.guard import com.tangem.common.extensions.toMapKey import com.tangem.common.map import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.models.scan.CardDTO @@ -55,7 +55,7 @@ private data class CreateWalletResponse( } class CreateProductWalletTask( - private val cardTypeResolver: CardTypeResolver, + private val cardTypesResolver: CardTypesResolver, private val seed: ByteArray? = null, ) : CardSessionRunnable { @@ -72,8 +72,8 @@ class CreateProductWalletTask( val cardDto = CardDTO(card) val commandProcessor = when { - cardTypeResolver.isTangemNote() -> CreateWalletTangemNote(cardTypeResolver) - cardTypeResolver.isTangemTwins() -> + cardTypesResolver.isTangemNote() -> CreateWalletTangemNote(cardTypesResolver) + cardTypesResolver.isTangemTwins() -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet") else -> CreateWalletTangemWallet(seed) @@ -97,7 +97,7 @@ class CreateProductWalletTask( } } -private class CreateWalletTangemNote(private val cardTypeResolver: CardTypeResolver) : +private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesResolver) : ProductCommandProcessor { override fun proceed( card: CardDTO, @@ -109,7 +109,7 @@ private class CreateWalletTangemNote(private val cardTypeResolver: CardTypeResol return } - val curvesSupportedByBlockchain = cardTypeResolver.getBlockchain().getSupportedCurves().toSet() + val curvesSupportedByBlockchain = cardTypesResolver.getBlockchain().getSupportedCurves().toSet() if (curvesSupportedByBlockchain.isEmpty()) { callback(CompletionResult.Failure(TangemSdkError.CardError())) return diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/di/WalletCurrenciesManagerProvider.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/di/WalletCurrenciesManagerProvider.kt index d754f7ecd7..0c6bfccf02 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/di/WalletCurrenciesManagerProvider.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/di/WalletCurrenciesManagerProvider.kt @@ -1,7 +1,5 @@ package com.tangem.tap.domain.walletCurrencies.di -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.Provider import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager @@ -10,14 +8,12 @@ import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository -@Suppress("LongParameterList") fun WalletCurrenciesManager.Companion.provideDefaultImplementation( userTokensRepository: UserTokensRepository, walletStoresRepository: WalletStoresRepository, walletAmountsRepository: WalletAmountsRepository, walletManagersRepository: WalletManagersRepository, appCurrencyProvider: () -> FiatCurrency, - cardTypeResolverProvider: Provider, ): WalletCurrenciesManager { return DefaultWalletCurrenciesManager( userTokensRepository = userTokensRepository, @@ -25,6 +21,5 @@ fun WalletCurrenciesManager.Companion.provideDefaultImplementation( walletAmountsRepository = walletAmountsRepository, walletManagersRepository = walletManagersRepository, appCurrencyProvider = appCurrencyProvider, - cardTypeResolverProvider = cardTypeResolverProvider, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt index 65103d09a2..0bbd76b7bc 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt @@ -2,8 +2,6 @@ package com.tangem.tap.domain.walletCurrencies.implementation import com.tangem.blockchain.common.DerivationStyle import com.tangem.common.* -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.Provider import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.util.UserWalletId import com.tangem.domain.models.scan.CardDTO @@ -28,7 +26,6 @@ internal class DefaultWalletCurrenciesManager( private val walletAmountsRepository: WalletAmountsRepository, private val walletManagersRepository: WalletManagersRepository, private val appCurrencyProvider: () -> FiatCurrency, - private val cardTypeResolverProvider: Provider, ) : WalletCurrenciesManager { private val listeners = mutableListOf() @@ -230,11 +227,7 @@ internal class DefaultWalletCurrenciesManager( .flatMap { walletManager -> walletStoresRepository.storeOrUpdate( userWalletId = userWallet.walletId, - walletStore = WalletStoreBuilder( - userWallet = userWallet, - cardTypeResolver = cardTypeResolverProvider.invoke(), - blockchainNetwork = blockchainNetwork, - ) + walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) .walletManager(walletManager) .build(), ) diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/di/WalletsStoresManagerProvider.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/di/WalletsStoresManagerProvider.kt index ae1ac2bb4c..d2a4789fb0 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/di/WalletsStoresManagerProvider.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/di/WalletsStoresManagerProvider.kt @@ -1,23 +1,24 @@ package com.tangem.tap.domain.walletStores.di -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.Provider +import com.tangem.tap.domain.walletStores.WalletStoresManager +import com.tangem.tap.domain.walletStores.implementation.DummyWalletStoresManager import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.domain.tokens.UserTokensRepository -import com.tangem.tap.domain.walletStores.WalletStoresManager import com.tangem.tap.domain.walletStores.implementation.DefaultWalletStoresManager import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository -@Suppress("LongParameterList") +fun WalletStoresManager.Companion.provideDummyImplementation(): WalletStoresManager { + return DummyWalletStoresManager() +} + fun WalletStoresManager.Companion.provideDefaultImplementation( userTokensRepository: UserTokensRepository, walletStoresRepository: WalletStoresRepository, walletAmountsRepository: WalletAmountsRepository, walletManagersRepository: WalletManagersRepository, appCurrencyProvider: () -> FiatCurrency, - cardTypeResolverProvider: Provider, ): WalletStoresManager { return DefaultWalletStoresManager( userTokensRepository = userTokensRepository, @@ -25,6 +26,5 @@ fun WalletStoresManager.Companion.provideDefaultImplementation( walletAmountsRepository = walletAmountsRepository, walletManagersRepository = walletManagersRepository, appCurrencyProvider = appCurrencyProvider, - cardTypeResolverProvider = cardTypeResolverProvider, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt index 476fa8300c..6081a25788 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt @@ -2,9 +2,12 @@ package com.tangem.tap.domain.walletStores.implementation import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.common.address.AddressType -import com.tangem.common.* -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.Provider +import com.tangem.common.CompletionResult +import com.tangem.common.doOnSuccess +import com.tangem.common.flatMap +import com.tangem.common.flatMapOnFailure +import com.tangem.common.fold +import com.tangem.common.map import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.domain.model.UserWallet @@ -32,7 +35,6 @@ internal class DefaultWalletStoresManager( private val walletAmountsRepository: WalletAmountsRepository, private val walletManagersRepository: WalletManagersRepository, private val appCurrencyProvider: () -> FiatCurrency, - private val cardTypeResolverProvider: Provider, ) : WalletStoresManager { private val state = MutableStateFlow(State()) @@ -149,11 +151,7 @@ internal class DefaultWalletStoresManager( { walletManager -> walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder( - userWallet = userWallet, - cardTypeResolver = cardTypeResolverProvider.invoke(), - blockchainNetwork = blockchainNetwork, - ) + walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) .walletManager(walletManager) .build(), ) @@ -187,11 +185,7 @@ internal class DefaultWalletStoresManager( val userWalletId = userWallet.walletId walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder( - userWallet = userWallet, - cardTypeResolver = cardTypeResolverProvider.invoke(), - walletManager = walletManager, - ) + walletStore = WalletStoreBuilder(userWallet, walletManager) .build(), ) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt index 1f89cd4eda..d89d4ea6aa 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/di/RepositoryProvider.kt @@ -2,8 +2,6 @@ package com.tangem.tap.domain.walletStores.repository.di import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.datasource.api.tangemTech.TangemTechService -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.Provider import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository @@ -18,9 +16,8 @@ fun WalletStoresRepository.Companion.provideDefaultImplementation(): WalletStore fun WalletManagersRepository.Companion.provideDefaultImplementation( walletManagerFactory: WalletManagerFactory, - cardTypeResolverProvider: Provider, ): WalletManagersRepository { - return DefaultWalletManagersRepository(walletManagerFactory, cardTypeResolverProvider) + return DefaultWalletManagersRepository(walletManagerFactory) } fun WalletAmountsRepository.Companion.provideDefaultImplementation( diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt index bf26df0009..b2d8167a7e 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt @@ -1,17 +1,22 @@ package com.tangem.tap.domain.walletStores.repository.implementation -import com.tangem.blockchain.common.* +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.DerivationParams +import com.tangem.blockchain.common.DerivationStyle +import com.tangem.blockchain.common.WalletManager +import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.common.CompletionResult import com.tangem.common.catching import com.tangem.common.doOnSuccess import com.tangem.common.mapFailure import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.Provider import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.UserWalletId import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.tokens.models.BlockchainNetwork @@ -25,7 +30,6 @@ import timber.log.Timber internal class DefaultWalletManagersRepository( private val walletManagerFactory: WalletManagerFactory, - private val cardTypeResolverProvider: Provider, ) : WalletManagersRepository { private val walletManagersStorage = WalletManagerStorage @@ -52,7 +56,10 @@ internal class DefaultWalletManagersRepository( derivationPath = blockchainNetwork?.derivationPath, ) - foundWalletManager?.updateTokens(blockchainNetwork = blockchainNetwork) + foundWalletManager?.updateTokens( + scanResponse = userWallet.scanResponse, + blockchainNetwork = blockchainNetwork, + ) ?: makeAndStore(userWallet, blockchainNetwork) } @@ -62,7 +69,7 @@ internal class DefaultWalletManagersRepository( ): CompletionResult { val scanResponse = userWallet.scanResponse val blockchain = blockchainNetwork?.blockchain - ?: cardTypeResolverProvider.invoke().getBlockchain().let { blockchain -> + ?: scanResponse.cardTypesResolver.getBlockchain().let { blockchain -> if (scanResponse.card.isTestCard) blockchain.getTestnetVersion() else blockchain } val derivationParams = getDerivationParams( @@ -73,7 +80,6 @@ internal class DefaultWalletManagersRepository( val walletManager = blockchain?.let { walletManagerFactory.makeWalletManagerForApp( scanResponse = userWallet.scanResponse, - cardTypeResolver = cardTypeResolverProvider.invoke(), blockchain = blockchain, derivationParams = derivationParams, ) @@ -92,7 +98,10 @@ internal class DefaultWalletManagersRepository( CompletionResult.Failure(error) } walletManager != null -> { - walletManager.updateTokens(blockchainNetwork = blockchainNetwork) + walletManager.updateTokens( + scanResponse = scanResponse, + blockchainNetwork = blockchainNetwork, + ) .doOnSuccess { store(userWallet.walletId, it) } } else -> { @@ -152,10 +161,13 @@ internal class DefaultWalletManagersRepository( } } - private fun WalletManager.updateTokens(blockchainNetwork: BlockchainNetwork?): CompletionResult { + private fun WalletManager.updateTokens( + scanResponse: ScanResponse, + blockchainNetwork: BlockchainNetwork?, + ): CompletionResult { val walletManager = this return catching { - val tokens = blockchainNetwork?.tokens ?: listOfNotNull(cardTypeResolverProvider.invoke().getPrimaryToken()) + val tokens = blockchainNetwork?.tokens ?: listOfNotNull(scanResponse.cardTypesResolver.getPrimaryToken()) if (tokens != walletManager.cardTokens) { // TODO: remove ability to manipulate with walletManager.cardTokens diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt index 89cdd44f5f..4624db8d34 100644 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt @@ -1,14 +1,13 @@ package com.tangem.tap.features.demo import com.tangem.common.extensions.guard +import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.common.demo.DemoConfig import com.tangem.domain.common.extensions.withMainContext -import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.domain.extensions.makePrimaryWalletManager import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState -import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.launch @@ -29,14 +28,9 @@ internal class DemoOnboardingNoteMiddleware : DemoMiddleware { noteState.walletManager } else { val wmFactory = globalState.tapWalletManager.walletManagerFactory - val walletManager = wmFactory - .makePrimaryWalletManager( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) - .guard { - return false - } + val walletManager = wmFactory.makePrimaryWalletManager(scanResponse).guard { + return false + } store.dispatch(OnboardingNoteAction.SetWalletManager(walletManager)) walletManager } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index ad390d5207..5782c7b0e2 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.details.redux import com.tangem.blockchain.common.Wallet import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.entities.FiatCurrency import org.rekotlin.Action @@ -25,7 +26,7 @@ sealed class DetailsAction : Action { object ScanCard : DetailsAction() - data class PrepareCardSettingsData(val card: CardDTO) : DetailsAction() + data class PrepareCardSettingsData(val card: CardDTO, val cardTypesResolver: CardTypesResolver) : DetailsAction() object ResetCardSettingsData : DetailsAction() sealed class AccessCodeRecovery : DetailsAction() { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 8541cb7fb0..acc0130ea9 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -8,6 +8,7 @@ import com.tangem.common.extensions.guard import com.tangem.common.flatMap import com.tangem.core.analytics.Analytics import com.tangem.domain.common.TapWorkarounds.isTangemTwins +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -32,8 +33,13 @@ import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.foregroundActivityObserver +import com.tangem.tap.preferencesStorage +import com.tangem.tap.scope +import com.tangem.tap.store import com.tangem.tap.tangemSdkManager +import com.tangem.tap.userWalletsListManager +import com.tangem.tap.walletStoresManager import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -86,7 +92,10 @@ class DetailsMiddleware { if (isSameWallet) { store.dispatchOnMain( - DetailsAction.PrepareCardSettingsData(card = scanResponse.card), + DetailsAction.PrepareCardSettingsData( + scanResponse.card, + scanResponse.cardTypesResolver, + ), ) } else { store.dispatchDialogShow( @@ -319,12 +328,7 @@ class DetailsMiddleware { enableAccessCodesSaving: Boolean, ): CompletionResult { val userWallet = userWalletsListManager.selectedUserWalletSync - ?: scanResponse?.let { - UserWalletBuilder( - scanResponse = it, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ).build() - } + ?: scanResponse?.let { UserWalletBuilder(it).build() } ?: return CompletionResult.Failure( error = TangemSdkError.ExceptionError(IllegalStateException("scanResponse is null")), ) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 21bdcfdddc..e28b9cd398 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -1,15 +1,15 @@ package com.tangem.tap.features.details.redux -import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.CardTypesResolver +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.extensions.signedHashesCount import com.tangem.tap.preferencesStorage -import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store import com.tangem.tap.tangemSdkManager import org.rekotlin.Action -import java.util.EnumSet +import java.util.* object DetailsReducer { fun reduce(action: Action, state: AppState): DetailsState = internalReduce(action, state) @@ -23,7 +23,11 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { handlePrepareScreen(action) } is DetailsAction.PrepareCardSettingsData -> { - handlePrepareCardSettingsScreen(card = action.card, state = detailsState) + handlePrepareCardSettingsScreen( + card = action.card, + cardTypesResolver = action.cardTypesResolver, + state = detailsState, + ) } is DetailsAction.ResetCardSettingsData -> detailsState.copy(cardSettingsState = null) is DetailsAction.ResetToFactory -> { @@ -56,14 +60,17 @@ private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsSta ) } -private fun handlePrepareCardSettingsScreen(card: CardDTO, state: DetailsState): DetailsState { - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) +private fun handlePrepareCardSettingsScreen( + card: CardDTO, + cardTypesResolver: CardTypesResolver, + state: DetailsState, +): DetailsState { val cardSettingsState = CardSettingsState( - cardInfo = card.toCardInfo(cardTypeResolver), - manageSecurityState = prepareSecurityOptions(card, cardTypeResolver), + cardInfo = card.toCardInfo(cardTypesResolver), + manageSecurityState = prepareSecurityOptions(card, cardTypesResolver), card = card, - resetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypeResolver), - accessCodeRecovery = if (cardTypeResolver.isWallet2()) { + resetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypesResolver), + accessCodeRecovery = if (cardTypesResolver.isWallet2()) { val enabled = card.userSettings?.isUserCodeRecoveryAllowed ?: false AccessCodeRecoveryState( enabledOnCard = enabled, @@ -76,7 +83,7 @@ private fun handlePrepareCardSettingsScreen(card: CardDTO, state: DetailsState): return state.copy(cardSettingsState = cardSettingsState) } -private fun prepareSecurityOptions(card: CardDTO, cardTypeResolver: CardTypeResolver): ManageSecurityState { +private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesResolver): ManageSecurityState { val securityOption = when { card.isAccessCodeSet -> { SecurityOption.AccessCode @@ -91,15 +98,14 @@ private fun prepareSecurityOptions(card: CardDTO, cardTypeResolver: CardTypeReso } } val allowedSecurityOptions = when { - cardTypeResolver.isStart2Coin() || cardTypeResolver.isTangemNote() -> { + cardTypesResolver.isStart2Coin() || cardTypesResolver.isTangemNote() -> { EnumSet.of(SecurityOption.LongTap) } card.settings.isBackupAllowed -> { EnumSet.of(securityOption) } - else -> { - prepareAllowedSecurityOptions(cardTypeResolver = cardTypeResolver, currentSecurityOption = securityOption) - } + else -> + prepareAllowedSecurityOptions(cardTypesResolver = cardTypesResolver, currentSecurityOption = securityOption) } return ManageSecurityState( currentOption = securityOption, @@ -108,9 +114,9 @@ private fun prepareSecurityOptions(card: CardDTO, cardTypeResolver: CardTypeReso ) } -private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypeResolver: CardTypeResolver): Boolean { +private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypesResolver: CardTypesResolver): Boolean { val hasPermanentWallet = card.wallets.any { it.settings.isPermanent } - val isNotAllowed = hasPermanentWallet || cardTypeResolver.isStart2Coin() + val isNotAllowed = hasPermanentWallet || cardTypesResolver.isStart2Coin() return !isNotAllowed } @@ -134,10 +140,12 @@ private fun handleSecurityAction(action: DetailsAction.ManageSecurity, state: De // Setting options to show only LongTap from now on for non-twins val manageSecurityState = state.cardSettingsState?.manageSecurityState?.copy( currentOption = state.cardSettingsState.manageSecurityState.selectedOption, - allowedOptions = prepareAllowedSecurityOptions( - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - currentSecurityOption = state.cardSettingsState.manageSecurityState.selectedOption, - ), + allowedOptions = state.scanResponse?.cardTypesResolver?.let { + prepareAllowedSecurityOptions( + cardTypesResolver = it, + currentSecurityOption = state.cardSettingsState.manageSecurityState.selectedOption, + ) + } ?: EnumSet.of(SecurityOption.LongTap), ) state.copy( cardSettingsState = state.cardSettingsState?.copy( @@ -221,12 +229,12 @@ private fun handleAccessCodeRecoveryAction( } private fun prepareAllowedSecurityOptions( - cardTypeResolver: CardTypeResolver, + cardTypesResolver: CardTypesResolver, currentSecurityOption: SecurityOption?, ): EnumSet { val allowedSecurityOptions = EnumSet.of(SecurityOption.LongTap) - if (cardTypeResolver.isTangemTwins()) { + if (cardTypesResolver.isTangemTwins()) { allowedSecurityOptions.add(SecurityOption.PassCode) } if (currentSecurityOption == SecurityOption.AccessCode) { @@ -238,8 +246,9 @@ private fun prepareAllowedSecurityOptions( return allowedSecurityOptions } -private fun CardDTO.toCardInfo(cardTypeResolver: CardTypeResolver): CardInfo { - val cardId = this.cardId.chunked(size = 4).joinToString(separator = " ") +@Suppress("MagicNumber") +private fun CardDTO.toCardInfo(cardTypesResolver: CardTypesResolver): CardInfo { + val cardId = this.cardId.chunked(4).joinToString(separator = " ") val issuer = this.issuer.name val signedHashes = this.signedHashesCount() @@ -247,7 +256,7 @@ private fun CardDTO.toCardInfo(cardTypeResolver: CardTypeResolver): CardInfo { cardId = cardId, issuer = issuer, signedHashes = signedHashes, - isTwin = cardTypeResolver.isTangemTwins(), + isTwin = cardTypesResolver.isTangemTwins(), hasBackup = backupStatus?.isActive == true, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index 47422b12e6..b69de63a66 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -8,6 +8,7 @@ import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.domain.common.extensions.toNetworkId import com.tangem.domain.common.extensions.withMainContext +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.extensions.dispatchOnMain @@ -403,8 +404,7 @@ class WalletConnectMiddleware { private fun handleScanResponse(scanResponse: ScanResponse, session: WalletConnectSession, blockchain: Blockchain) { val card = scanResponse.card - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - if (!cardTypeResolver.isMultiwalletAllowed()) { + if (!scanResponse.cardTypesResolver.isMultiwalletAllowed()) { store.dispatchOnMain(WalletConnectAction.UnsupportedCard) return } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index 9256eda744..e9766c6147 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -3,6 +3,7 @@ package com.tangem.tap.features.details.ui.details import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import com.tangem.core.analytics.Analytics +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.feedback.FeedbackEmail import com.tangem.tap.common.feedback.SupportInfo @@ -15,7 +16,6 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerAction import com.tangem.tap.features.home.LocaleRegionProvider import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.wallet.BuildConfig import org.rekotlin.Store @@ -26,11 +26,11 @@ class DetailsViewModel(private val store: Store) { @Suppress("ComplexMethod") fun updateState(state: DetailsState): DetailsScreenState { - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) + val cardTypesResolver = state.scanResponse?.cardTypesResolver val settings = SettingsElement.values().mapNotNull { when (it) { SettingsElement.WalletConnect -> { - if (cardTypeResolver.isMultiwalletAllowed()) it else null + if (cardTypesResolver?.isMultiwalletAllowed() == true) it else null } SettingsElement.SendFeedback -> it SettingsElement.LinkMoreCards -> if (state.createBackupAllowed) it else null @@ -38,8 +38,8 @@ class DetailsViewModel(private val store: Store) { if (state.privacyPolicyUrl != null) it else null } SettingsElement.AppSettings -> if (state.appSettingsState.isBiometricsAvailable) it else null - SettingsElement.AppCurrency -> if (!cardTypeResolver.isMultiwalletAllowed()) it else null - SettingsElement.ReferralProgram -> if (cardTypeResolver.isTangemWallet()) it else null + SettingsElement.AppCurrency -> if (cardTypesResolver?.isMultiwalletAllowed() != true) it else null + SettingsElement.ReferralProgram -> if (cardTypesResolver?.isTangemWallet() == true) it else null SettingsElement.TesterMenu -> if (BuildConfig.TESTER_MENU_ENABLED) it else null else -> it } diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 5a3d6060f6..9d7d775e1d 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -27,7 +27,6 @@ import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.features.home.redux.HomeMiddleware.BUY_WALLET_URL import com.tangem.tap.features.send.redux.states.ButtonState import com.tangem.tap.features.signin.redux.SignInAction -import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -102,15 +101,10 @@ private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { } private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch { - val userWallet = UserWalletBuilder( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) - .build() - .guard { - Timber.e("User wallet not created") - return@launch - } + val userWallet = UserWalletBuilder(scanResponse).build().guard { + Timber.e("User wallet not created") + return@launch + } userWalletsListManager.save(userWallet) .doOnFailure { error -> diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index 2003719d77..6079110e39 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -4,11 +4,10 @@ import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics -import com.tangem.domain.card.CardTypeResolver +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.* import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.extensions.removeContext @@ -17,7 +16,11 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.features.saveWallet.redux.SaveWalletAction -import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.preferencesStorage +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager +import com.tangem.tap.userWalletsListManager import kotlinx.coroutines.delay import kotlinx.coroutines.launch import timber.log.Timber @@ -26,11 +29,11 @@ import timber.log.Timber [REDACTED_AUTHOR] */ object OnboardingHelper { - fun isOnboardingCase(response: ScanResponse, cardTypeResolver: CardTypeResolver): Boolean { + fun isOnboardingCase(response: ScanResponse): Boolean { val cardInfoStorage = preferencesStorage.usedCardsPrefStorage val cardId = response.card.cardId return when { - cardTypeResolver.isTangemTwins() -> { + response.cardTypesResolver.isTangemTwins() -> { if (!response.twinsIsTwinned()) { true } else { @@ -38,7 +41,7 @@ object OnboardingHelper { } } - cardTypeResolver.isWallet2() -> { + response.cardTypesResolver.isWallet2() -> { val emptyWallets = response.card.wallets.isEmpty() val activationInProgress = cardInfoStorage.isActivationInProgress(cardId) val backupNotActive = response.card.backupStatus?.isActive != true @@ -70,10 +73,7 @@ object OnboardingHelper { accessCode: String? = null, backupCardsIds: List? = null, ) { - Analytics.setContext( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + Analytics.setContext(scanResponse) when { // When should save user wallets, then save card without navigate to save wallet screen preferencesStorage.shouldSaveUserWallets -> scope.launch { @@ -119,10 +119,7 @@ object OnboardingHelper { } private suspend fun proceedWithScanResponse(scanResponse: ScanResponse, backupCardsIds: List?) { - val userWallet = UserWalletBuilder( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + val userWallet = UserWalletBuilder(scanResponse) .backupCardsIds(backupCardsIds?.toSet()) .build() .guard { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index 29877cbf50..fddc46b3a8 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -7,7 +7,13 @@ import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Onboarding -import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.extensions.dispatchDebugErrorNotification +import com.tangem.tap.common.extensions.dispatchDialogShow +import com.tangem.tap.common.extensions.dispatchErrorNotification +import com.tangem.tap.common.extensions.dispatchOnMain +import com.tangem.tap.common.extensions.dispatchOpenUrl +import com.tangem.tap.common.extensions.getAddressData +import com.tangem.tap.common.extensions.getTopUpUrl import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.AppState @@ -23,7 +29,6 @@ import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.models.WalletDialog -import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -118,10 +123,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch noteState.walletManager } else { val wmFactory = globalState.tapWalletManager.walletManagerFactory - val walletManager = wmFactory.makePrimaryWalletManager( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ).guard { + val walletManager = wmFactory.makePrimaryWalletManager(scanResponse).guard { val message = "Loading cancelled. Cause: wallet manager didn't created" val customError = TapError.CustomError(message) store.dispatchErrorNotification(customError) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt index 044c9fd13f..ba7983eaa5 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt @@ -3,8 +3,9 @@ package com.tangem.tap.features.onboarding.products.otherCards.redux import com.tangem.blockchain.common.Blockchain import com.tangem.common.CompletionResult import com.tangem.core.analytics.Analytics +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.extensions.withMainContext -import com.tangem.tap.* +import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppState @@ -12,7 +13,10 @@ import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.wallet.models.toCurrencies -import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager +import com.tangem.tap.userTokensRepository import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -86,10 +90,9 @@ private fun handleOtherCardsAction(action: Action) { onboardingManager.activationStarted(updatedCard.cardId) store.state.globalState.topUpController?.registerEmptyWallet(updatedResponse) - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - val primaryBlockchain = cardTypeResolver.getBlockchain() + val primaryBlockchain = updatedResponse.cardTypesResolver.getBlockchain() val blockchainNetworks = if (primaryBlockchain != Blockchain.Unknown) { - val primaryToken = cardTypeResolver.getPrimaryToken() + val primaryToken = updatedResponse.cardTypesResolver.getPrimaryToken() val blockchainNetwork = BlockchainNetwork( blockchain = primaryBlockchain, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 1fa0ce5b48..036482c623 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -29,7 +29,6 @@ import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.models.WalletDialog -import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -222,10 +221,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { twinCardsState.walletManager } else { val wmFactory = globalState.tapWalletManager.walletManagerFactory - val walletManager = wmFactory.makePrimaryWalletManager( - scanResponse = getScanResponse(), - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ).guard { + val walletManager = wmFactory.makePrimaryWalletManager(getScanResponse()).guard { val message = "Loading cancelled. Cause: wallet manager didn't created" val customError = TapError.CustomError(message) store.dispatchErrorNotification(customError) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt index d393583ef3..9ba9492c54 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt @@ -1,9 +1,8 @@ package com.tangem.tap.features.onboarding.products.twins.redux +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.getTwinCardNumber import com.tangem.tap.common.redux.AppState -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.store import org.rekotlin.Action object TwinCardsReducer { @@ -18,8 +17,7 @@ private fun internalReduce(action: Action, state: AppState): TwinCardsState { when (action) { is TwinCardsAction.IfTwinsPrepareState -> { - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - state = if (cardTypeResolver.isTangemTwins()) { + state = if (action.scanResponse.cardTypesResolver.isTangemTwins()) { val cardNumber = action.scanResponse.card.getTwinCardNumber() ?: return state TwinCardsState( diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index dc2a82105e..2f4be5416d 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -7,6 +7,7 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.ifNotNull import com.tangem.core.analytics.Analytics import com.tangem.domain.common.extensions.withMainContext +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.feature.onboarding.data.model.CreateWalletResponse @@ -29,9 +30,9 @@ import com.tangem.tap.features.onboarding.OnboardingDialog import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.wallet.models.toCurrencies import com.tangem.tap.features.wallet.redux.Artwork -import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.launch import org.rekotlin.Action +import org.rekotlin.DispatchFunction import org.rekotlin.Middleware object OnboardingWalletMiddleware { @@ -42,8 +43,8 @@ private val onboardingWalletMiddleware: Middleware = { dispatch, state { next -> { action -> when (action) { - is OnboardingWallet2Action -> handleWallet2Action(action) - else -> handleWalletAction(action) + is OnboardingWallet2Action -> handleWallet2Action(action, state) + else -> handleWalletAction(action, state, dispatch) } next(action) } @@ -51,7 +52,7 @@ private val onboardingWalletMiddleware: Middleware = { dispatch, state } @Suppress("LongMethod", "ComplexMethod") -private fun handleWalletAction(action: Action) { +private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: DispatchFunction) { if (action !is OnboardingWalletAction) return val globalState = store.state.globalState @@ -177,7 +178,7 @@ private fun handleWalletAction(action: Action) { } @Suppress("LongMethod", "ComplexMethod") -private fun handleWallet2Action(action: OnboardingWallet2Action) { +private fun handleWallet2Action(action: OnboardingWallet2Action, state: () -> AppState?) { val globalState = store.state.globalState val onboardingManager = globalState.onboardingState.onboardingManager @@ -185,8 +186,7 @@ private fun handleWallet2Action(action: OnboardingWallet2Action) { when (action) { is OnboardingWallet2Action.Init -> { - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - if (cardTypeResolver.isWallet2()) { + if (scanResponse?.cardTypesResolver?.isWallet2() == true) { store.dispatch(OnboardingWallet2Action.SetDependencies(action.maxProgress)) } } diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt index 8866609bb7..ec2223b2bd 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt @@ -7,7 +7,6 @@ import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard import com.tangem.common.flatMap import com.tangem.core.analytics.Analytics -import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Onboarding @@ -22,7 +21,12 @@ import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation import com.tangem.tap.domain.userWalletList.isLockable import com.tangem.tap.features.wallet.redux.WalletAction -import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.foregroundActivityObserver +import com.tangem.tap.preferencesStorage +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager +import com.tangem.tap.userWalletsListManager import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber @@ -92,10 +96,7 @@ internal class SaveWalletMiddleware { scope.launch { val userWallet = userWalletsListManager.selectedUserWalletSync - ?: UserWalletBuilder( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + ?: UserWalletBuilder(scanResponse) .backupCardsIds(state.backupInfo?.backupCardsIds) .build() ?: return@launch diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index c6ee8940d4..9c1feed6b4 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -4,6 +4,7 @@ import android.graphics.Bitmap import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.WalletManager +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.common.entities.Button import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.common.toggleWidget.WidgetState @@ -49,6 +50,9 @@ data class WalletState( store.state.twinCardsState } + val isTangemTwins: Boolean + get() = store.state.globalState.scanResponse?.cardTypesResolver?.isTangemTwins() == true + val isExchangeServiceFeatureOn: Boolean get() = store.state.globalState.exchangeManager.featureIsSwitchedOn() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index de428f2421..d86a41c389 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -19,7 +19,6 @@ import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.models.WalletDialog -import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.userWalletsListManager @@ -83,10 +82,7 @@ class MultiWalletMiddleware { return } val scanResponse = selectedUserWallet.scanResponse - Analytics.addContext( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) + Analytics.addContext(scanResponse) store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false)) store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet)) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index 7b64bf710f..44a7dd5341 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -5,6 +5,7 @@ import com.tangem.blockchain.common.SignatureCountValidator import com.tangem.blockchain.extensions.SimpleResult import com.tangem.common.card.FirmwareVersion import com.tangem.domain.common.TapWorkarounds.isTestCard +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.extensions.dispatchOnMain @@ -106,10 +107,9 @@ class WarningsMiddleware { } private fun checkIfWarningNeeded(scanResponse: ScanResponse): WarningMessage? { - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - if (cardTypeResolver.isTangemTwins() || scanResponse.isDemoCard()) return null + if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.isDemoCard()) return null - if (cardTypeResolver.isMultiwalletAllowed()) { + if (scanResponse.cardTypesResolver.isMultiwalletAllowed()) { val isBackupForbidden = with(scanResponse.card.settings) { !(isBackupAllowed || isHDWalletAllowed) } return if (scanResponse.card.hasSignedHashes() && isBackupForbidden) { WarningMessagesManager.signedHashesMultiWalletWarning @@ -139,8 +139,9 @@ class WarningsMiddleware { val card = scanResponse?.card if (card == null || preferencesStorage.usedCardsPrefStorage.wasScanned(card.cardId)) return - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) - if (cardTypeResolver.isTangemTwins() || cardTypeResolver.isMultiwalletAllowed()) return + if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.cardTypesResolver.isMultiwalletAllowed()) { + return + } val validator = store.state.walletState.walletManagers.firstOrNull() as? SignatureCountValidator diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt index d07d830d42..95f80ebca8 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.events.MainScreen @@ -13,7 +14,6 @@ import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.ui.analytics.WalletAnalyticsEventsMapper -import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store import com.tangem.tap.walletStoresManager import dagger.hilt.android.lifecycle.HiltViewModel @@ -54,9 +54,8 @@ internal class WalletViewModel @Inject constructor( override fun onCreate(owner: LifecycleOwner) { launch() val scanResponse = store.state.globalState.scanResponse - val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) if (scanResponse != null) { - val currency = ParamCardCurrencyConverter().convert(cardTypeResolver) + val currency = ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver) val signInType = store.state.signInState.type if (currency != null && signInType != null) { analyticsEventHandler.send( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index a53ee4fe57..3528a61c7a 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -22,7 +22,6 @@ import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.unlockIfLockable -import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.firstOrNull @@ -163,11 +162,7 @@ internal class WalletSelectorMiddleware { } private suspend fun saveUserWalletAndPopBackToWalletScreen(scanResponse: ScanResponse): CompletionResult { - val userWallet = UserWalletBuilder( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) - .build() + val userWallet = UserWalletBuilder(scanResponse).build() ?: return CompletionResult.Failure(TangemSdkError.WalletIsNotCreated()) return userWalletsListManager.save(userWallet) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt index e24f28d268..2a8ace7ad3 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt @@ -1,11 +1,10 @@ package com.tangem.tap.features.walletSelector.redux +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.model.UserWallet -import com.tangem.tap.proxy.redux.DaggerGraphState -import com.tangem.tap.store import org.rekotlin.Action internal object WalletSelectorReducer { @@ -100,10 +99,7 @@ internal object WalletSelectorReducer { ) } else { UserWalletModel.Type.SingleCurrency( - blockchainName = store.state.daggerGraphState - .get(DaggerGraphState::cardTypeResolver) - .getBlockchain() - .fullName, + blockchainName = scanResponse.cardTypesResolver.getBlockchain().fullName, ) } } diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index 983f4bc963..005bcca0a4 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -20,7 +20,6 @@ import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.userWalletList.unlockIfLockable import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler import com.tangem.tap.features.signin.redux.SignInAction -import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber @@ -80,12 +79,7 @@ internal class WelcomeMiddleware { private fun proceedWithCard(state: WelcomeState) = scope.launch { scanCardInternal { scanResponse -> - val userWallet = UserWalletBuilder( - scanResponse = scanResponse, - cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver), - ) - .build() - ?: return@scanCardInternal + val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal userWalletsListManager.save(userWallet, canOverride = true) .doOnFailure { error -> diff --git a/app/src/main/java/com/tangem/tap/legacy/card/LegacyCardTypeResolver.kt b/app/src/main/java/com/tangem/tap/legacy/card/LegacyCardTypeResolver.kt deleted file mode 100644 index d44eda26cd..0000000000 --- a/app/src/main/java/com/tangem/tap/legacy/card/LegacyCardTypeResolver.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.tangem.tap.legacy.card - -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.Token -import com.tangem.common.card.EllipticCurve -import com.tangem.common.card.FirmwareVersion -import com.tangem.common.card.WalletData -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.Provider -import com.tangem.domain.common.TapWorkarounds.isStart2Coin -import com.tangem.domain.common.TapWorkarounds.isTestCard -import com.tangem.domain.models.scan.CardDTO -import com.tangem.domain.models.scan.ProductType - -internal class LegacyCardTypeResolver( - private val cardProvider: Provider, - private val productTypeProvider: Provider, - private val walletDataProvider: Provider, -) : CardTypeResolver { - - private val card: CardDTO get() = cardProvider.invoke() - private val productType: ProductType get() = productTypeProvider.invoke() - private val walletData: WalletData? get() = walletDataProvider.invoke() - - override fun isTangemNote(): Boolean = productType == ProductType.Note - - override fun isTangemWallet(): Boolean { - return with(card.settings) { - isBackupAllowed && isHDWalletAllowed && card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable - } - } - - override fun isWallet2(): Boolean { - return with(card) { - firmwareVersion >= FirmwareVersion.KeysImportAvailable && settings.isKeysImportAllowed - } - } - - override fun isTangemTwins(): Boolean = productType == ProductType.Twins - - override fun isStart2Coin(): Boolean = card.isStart2Coin - - override fun isMultiwalletAllowed(): Boolean { - return (multiWalletAvailable() || card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1) && - !isTangemTwins() && !card.isStart2Coin && !isTangemNote() - } - - private fun multiWalletAvailable() = card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable - - override fun getBlockchain(): Blockchain { - if (productType == ProductType.Start2Coin) { - return if (card.isTestCard) Blockchain.BitcoinTestnet else Blockchain.Bitcoin - } - - val blockchainName = walletData?.blockchain - ?: return if (productType == ProductType.Note) { - TANGEM_NOTE_BATCHES[card.batchId] ?: Blockchain.Unknown - } else { - Blockchain.Unknown - } - - return Blockchain.fromBlockchainName(blockchainName) - } - - override fun getPrimaryToken(): Token? { - val cardToken = walletData?.token ?: return null - return Token( - name = cardToken.name, - symbol = cardToken.symbol, - contractAddress = cardToken.contractAddress, - decimals = cardToken.decimals, - ) - } - - private fun Blockchain.Companion.fromBlockchainName(name: String): Blockchain { - // workaround for BSC (BNB) notes cards - return when (name) { - "BINANCE" -> Blockchain.BSC - "BINANCE/test" -> Blockchain.BSCTestnet - else -> Blockchain.fromId(name) - } - } - - private companion object { - val TANGEM_NOTE_BATCHES = mapOf( - "AB01" to Blockchain.Bitcoin, - "AB02" to Blockchain.Ethereum, - "AB03" to Blockchain.CardanoShelley, - "AB04" to Blockchain.Dogecoin, - "AB05" to Blockchain.BSC, - "AB06" to Blockchain.XRP, - "AB07" to Blockchain.Bitcoin, - "AB08" to Blockchain.Ethereum, - "AB09" to Blockchain.Bitcoin, // new batches for 3.34 - "AB10" to Blockchain.Ethereum, - "AB11" to Blockchain.Bitcoin, - "AB12" to Blockchain.Ethereum, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/legacy/card/di/LegacyCardModule.kt b/app/src/main/java/com/tangem/tap/legacy/card/di/LegacyCardModule.kt deleted file mode 100644 index 032d545891..0000000000 --- a/app/src/main/java/com/tangem/tap/legacy/card/di/LegacyCardModule.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.tangem.tap.legacy.card.di - -import com.tangem.domain.card.CardTypeResolver -import com.tangem.domain.common.Provider -import com.tangem.tap.legacy.card.LegacyCardTypeResolver -import com.tangem.tap.proxy.AppStateHolder -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -internal object LegacyCardModule { - - @Provides - @Singleton - fun providesCardTypeResolver(reduxStateHolder: AppStateHolder): CardTypeResolver { - return LegacyCardTypeResolver( - cardProvider = Provider { - requireNotNull(reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse?.card) - }, - productTypeProvider = Provider { - requireNotNull( - value = reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse?.productType, - ) - }, - walletDataProvider = Provider { - requireNotNull(reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse).walletData - }, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt index ba301a2fc1..c673ac8577 100644 --- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt @@ -29,7 +29,9 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlin.coroutines.suspendCoroutine -class DerivationManagerImpl(private val appStateHolder: AppStateHolder) : DerivationManager { +class DerivationManagerImpl( + private val appStateHolder: AppStateHolder, +) : DerivationManager { override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine { continuation -> val blockchain = Blockchain.fromNetworkId(currency.networkId) diff --git a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt index 0f33e210b7..371f1e21bf 100644 --- a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt +++ b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt @@ -46,7 +46,9 @@ class ProxyModule { @Provides @Singleton fun provideDerivationManager(appStateHolder: AppStateHolder): DerivationManager { - return DerivationManagerImpl(appStateHolder = appStateHolder) + return DerivationManagerImpl( + appStateHolder = appStateHolder, + ) } // regions FeatureConsumers diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index a4ca39f942..a741e4dfd4 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -2,7 +2,6 @@ package com.tangem.tap.proxy.redux import com.tangem.datasource.asset.AssetReader import com.tangem.datasource.connection.NetworkConnectionManager -import com.tangem.domain.card.CardTypeResolver import com.tangem.domain.card.ScanCardUseCase import com.tangem.features.tester.api.TesterRouter import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles @@ -24,7 +23,6 @@ data class DaggerGraphState( val walletConnectRepository: WalletConnectRepository? = null, val walletConnectSessionsRepository: WalletConnectSessionsRepository? = null, val walletConnectInteractor: WalletConnectInteractor? = null, - val cardTypeResolver: CardTypeResolver? = null, ) : StateType { inline fun get(getDependency: DaggerGraphState.() -> T?): T { diff --git a/domain/legacy/src/main/java/com/tangem/domain/card/CardTypeResolver.kt b/domain/legacy/src/main/java/com/tangem/domain/common/CardTypesResolver.kt similarity index 84% rename from domain/legacy/src/main/java/com/tangem/domain/card/CardTypeResolver.kt rename to domain/legacy/src/main/java/com/tangem/domain/common/CardTypesResolver.kt index 97012f4efd..72e1bfb243 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/card/CardTypeResolver.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/CardTypesResolver.kt @@ -1,23 +1,17 @@ -package com.tangem.domain.card +package com.tangem.domain.common import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Token -interface CardTypeResolver { - +interface CardTypesResolver { fun isTangemNote(): Boolean - fun isTangemWallet(): Boolean - fun isWallet2(): Boolean - fun isTangemTwins(): Boolean - fun isStart2Coin(): Boolean fun isMultiwalletAllowed(): Boolean fun getBlockchain(): Blockchain - fun getPrimaryToken(): Token? } \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/Provider.kt b/domain/legacy/src/main/java/com/tangem/domain/common/Provider.kt deleted file mode 100644 index c77b356dfc..0000000000 --- a/domain/legacy/src/main/java/com/tangem/domain/common/Provider.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.domain.common - -/** - * Provider for lazy initialization - * - * @param action initialization action - * -[REDACTED_AUTHOR] - */ -class Provider(action: () -> T) : () -> T by action \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt b/domain/legacy/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt new file mode 100644 index 0000000000..79f908088a --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt @@ -0,0 +1,77 @@ +package com.tangem.domain.common + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token +import com.tangem.common.card.EllipticCurve +import com.tangem.common.card.FirmwareVersion +import com.tangem.common.card.WalletData +import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain +import com.tangem.domain.common.TapWorkarounds.isStart2Coin +import com.tangem.domain.common.TapWorkarounds.isTestCard +import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.models.scan.ProductType + +class TangemCardTypesResolver( + private val card: CardDTO, + private val productType: ProductType, + private val walletData: WalletData?, +) : CardTypesResolver { + + override fun isTangemNote(): Boolean = productType == ProductType.Note + override fun isTangemWallet(): Boolean = card.settings.isBackupAllowed && + card.settings.isHDWalletAllowed && + card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable + + override fun isWallet2(): Boolean = + card.firmwareVersion >= FirmwareVersion.KeysImportAvailable && card.settings.isKeysImportAllowed + + override fun isTangemTwins(): Boolean = productType == ProductType.Twins + override fun isStart2Coin(): Boolean = card.isStart2Coin + + override fun isMultiwalletAllowed(): Boolean = !isTangemTwins() && + !card.isStart2Coin && + !isTangemNote() && + (multiWalletAvailable() || card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1) + + private fun multiWalletAvailable() = card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable + + override fun getBlockchain(): Blockchain { + return when (productType) { + ProductType.Start2Coin -> if (card.isTestCard) Blockchain.BitcoinTestnet else Blockchain.Bitcoin + else -> { + val blockchainName: String = walletData?.blockchain + ?: if (productType == ProductType.Note) { + return card.getTangemNoteBlockchain() ?: Blockchain.Unknown + } else { + return Blockchain.Unknown + } + Blockchain.fromBlockchainName(blockchainName) + } + } + } + + override fun getPrimaryToken(): Token? { + val cardToken = walletData?.token ?: return null + return Token( + cardToken.name, + cardToken.symbol, + cardToken.contractAddress, + cardToken.decimals, + ) + } +} + +private fun Blockchain.Companion.fromBlockchainName(blockchainName: String): Blockchain { + // workaround for BSC (BNB) notes cards + return when (blockchainName) { + "BINANCE" -> { + Blockchain.BSC + } + "BINANCE/test" -> { + Blockchain.BSCTestnet + } + else -> { + Blockchain.fromId(blockchainName) + } + } +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt b/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt index 144e55921c..5d25521277 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/TapWorkarounds.kt @@ -1,13 +1,14 @@ package com.tangem.domain.common +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle +import com.tangem.common.card.Card import com.tangem.domain.models.scan.CardDTO -import java.util.Locale +import java.util.* /** [REDACTED_AUTHOR] */ -@Deprecated(message = "Use CardTypeResolver. [REDACTED_JIRA]") object TapWorkarounds { private const val START_2_COIN_ISSUER = "start2coin" private const val TEST_CARD_BATCH = "99FF" @@ -43,11 +44,34 @@ object TapWorkarounds { val CardDTO.isNotSupportedInThatRelease: Boolean get() = false + private val tangemNoteBatches = mapOf( + "AB01" to Blockchain.Bitcoin, + "AB02" to Blockchain.Ethereum, + "AB03" to Blockchain.CardanoShelley, + "AB04" to Blockchain.Dogecoin, + "AB05" to Blockchain.BSC, + "AB06" to Blockchain.XRP, + "AB07" to Blockchain.Bitcoin, + "AB08" to Blockchain.Ethereum, + "AB09" to Blockchain.Bitcoin, // new batches for 3.34 + "AB10" to Blockchain.Ethereum, + "AB11" to Blockchain.Bitcoin, + "AB12" to Blockchain.Ethereum, + ) + private val excludedBatches = listOf("0027", "0030", "0031", "0035") private val excludedIssuers = listOf("TTM BANK") + @Deprecated( + "Now blockchain is read form files (CardTypesResolver.getBlockchain), " + + "but for previously saved cards this method is still used", + ) + fun CardDTO.getTangemNoteBlockchain(): Blockchain? = tangemNoteBatches[batchId] + fun isStart2CoinIssuer(cardIssuer: String?): Boolean { return cardIssuer?.lowercase(Locale.US) == START_2_COIN_ISSUER } + + fun Card.getTangemNoteBlockchain(): Blockchain? = tangemNoteBatches[batchId] ?: null } \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/util/ScanResponseExtensions.kt b/domain/legacy/src/main/java/com/tangem/domain/common/util/ScanResponseExtensions.kt index 8e7b1a2099..8438a87f14 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/util/ScanResponseExtensions.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/util/ScanResponseExtensions.kt @@ -4,13 +4,22 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.toMapKey import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.domain.common.CardTypesResolver +import com.tangem.domain.common.TangemCardTypesResolver import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.models.scan.ScanResponse -fun ScanResponse.twinsIsTwinned(): Boolean = card.isTangemTwins && walletData != null && secondTwinPublicKey != null +val ScanResponse.cardTypesResolver: CardTypesResolver + get() = TangemCardTypesResolver( + card = card, + productType = productType, + walletData = walletData, + ) +fun ScanResponse.twinsIsTwinned(): Boolean = card.isTangemTwins && walletData != null && secondTwinPublicKey != null fun ScanResponse.supportsHdWallet(): Boolean = card.settings.isHDWalletAllowed +fun ScanResponse.supportsBackup(): Boolean = card.settings.isBackupAllowed fun ScanResponse.hasDerivation(blockchain: Blockchain, rawDerivationPath: String): Boolean { return hasDerivation(blockchain, DerivationPath(rawDerivationPath))