From 5352f6e6f476c6b5aee9ce0a0775cb526ccbfdc7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 23 Dec 2022 20:34:08 +0400 Subject: [PATCH 01/21] Updated on 2026-08-14 --- .../DefaultWalletAmountsRepository.kt | 20 ++ .../redux/reducers/MultiWalletReducer.kt | 2 +- .../src/main/res/values-de/strings_final.xml | 233 ++++++++++++++++++ .../src/main/res/values-fr/strings_final.xml | 233 ++++++++++++++++++ .../src/main/res/values-it/strings_final.xml | 233 ++++++++++++++++++ .../src/main/res/values-ru/strings_final.xml | 233 ++++++++++++++++++ .../res/src/main/res/values/strings_final.xml | 233 ++++++++++++++++++ 7 files changed, 1186 insertions(+), 1 deletion(-) create mode 100644 core/res/src/main/res/values-de/strings_final.xml create mode 100644 core/res/src/main/res/values-fr/strings_final.xml create mode 100644 core/res/src/main/res/values-it/strings_final.xml create mode 100644 core/res/src/main/res/values-ru/strings_final.xml create mode 100644 core/res/src/main/res/values/strings_final.xml diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index 0c7b19fb4b..5a59ae8c30 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -169,6 +169,26 @@ internal class DefaultWalletAmountsRepository( .fold() } + private suspend fun fetchAmountsForUserWallet( + userWallet: UserWallet, + ): CompletionResult = withContext(Dispatchers.Default) { + val walletId = userWallet.walletId + val scanResponse = userWallet.scanResponse + val walletStores = walletStoresStorage.getAll() + .first() + .getOrElse(walletId) { emptyList() } + + walletStores.map { walletStore -> + async { + // TODO: Find wallet manager via [com.tangem.tap.domain.walletStores.repository.WalletManagersRepository] + val walletManager = walletStore.walletManager + fetchAmountsForWalletStore(walletId, scanResponse, walletStore, walletManager) + } + } + .awaitAll() + .fold() + } + private suspend fun fetchAmountsForWalletStore( walletId: UserWalletId, scanResponse: ScanResponse, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt index 729d99f960..8ed45a3a6f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt @@ -73,7 +73,7 @@ class MultiWalletReducer { val selectedCurrency = if (!state.isMultiwalletAllowed) { walletStores.firstOrNull()?.walletsData?.firstOrNull()?.currency } else { - state.selectedCurrency + state.selectedWalletData?.currency } state.copy( walletsStores = walletStores, diff --git a/core/res/src/main/res/values-de/strings_final.xml b/core/res/src/main/res/values-de/strings_final.xml new file mode 100644 index 0000000000..046904ddaf --- /dev/null +++ b/core/res/src/main/res/values-de/strings_final.xml @@ -0,0 +1,233 @@ + + + Tangem Wallet + 3 cards + 2 cards + Shipping + Free + I have a promo code… + Total + Other payment methods + Buy now + Meet\nTangem + Buy + Store + Send + Pay + Exchange + Lend + Borrow + Revolutionary Hardware Wallet + Store your crypto assets secure while keeping private keys contained in your card + Ultra Secure Backup + Up to + 3 physical cards + to one wallet + Thousands of Currencies + A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card + DeFi Compatible + Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services + The Wallet for Everyone + Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. + Order + Search tokens + You are currently running in Demo mode. All funds are not real. + This feature is disabled in Demo mode + Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + Available networks + %s network not found. Please, add it first and try again. + Attention + Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. + Tokens in Solana network are not supported by this card due to firmware limitation. + Contract address copied! + Contract address + Required field + Please select the network + Decimal number must be a valid integer, no higher than %d + Contract address is invalid + Derivation path is invalid + Note that tokens can be created by anyone. Be aware of adding scam tokens, they can cost nothing. + This token/network has already been added to your list + Decimals + Network + Not selected + E.g. USD Coin + Name + E.g. USDC + Token symbol + BIP44 coin type + Default + The server is not available, please try again later + Total balance + The amount does not include some of your funds + Tokens + Manage tokens + No rate + Network is unreachable + Hide token + Hide %s + Hide + You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. + Unable to hide %s + The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list. + Your wallet has not been backed up + To protect your assets, we advise you to carry out this procedure + Erneut versuchen + Chat + %s network + I understand + Yes + No + Russian bank cards are not accepted at the moment + Do you have a bank card of another country or a UnionPay card? + This network is not supported. Please select another network. + Card Settings + Security Mode + Change access code + Access code will be changed on this card only + Continue + Tangem Bot + Get your card ready! + Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. + Scan Card + App Settings + Keep the wallet in the app + Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card. + Save Access Code + Biometric authentication will be requested instead of the access code for interactions with your card. + Removing the saved card deletes all the saved wallets and their access codes. + This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code. + WalletConnect + Connect to Dapps + This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. + I understand that after performing this action, I will no longer have access to the current wallet + Reset the card + Reset to Factory Settings + Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. + Select network + Scan your card + To access all the networks you need to scan the card + Connection with this Dapp cannot be established due to its technical implementation. + Welcome back! + Use %s or scan a card to access the app + Log in with %s + Karte scannen + Save your Wallet + Would you like to use %s? + Would you like to use biometrics? + Access the app + Log into the app and check your balance without scanning the card + Access code + %s will be requested instead of the access code for interactions with your wallet + Biometrics will be requested instead of the access code for interactions with your wallet + Note that making a transaction with your funds will still require your card + Allow to use %s + Allow to use biometrics + New feature + My Wallets + Multi-currency + Single-currency + Add new wallet + Rename Wallet + Wallet name + Unlock all with %s + Invalid Tag. It won\'t be added to the transaction. + Invalid Memo. It won\'t be added to the transaction. + Tag + Memo + Attention + Tap the card with the visa logo + No funds for activation + Please contact support + Four identical digits isn\'t safe + Such a PIN can be brute-forced easily + Pin code + Connect + KYC + Verify your identity + Set PIN code + Register + Verify via Utorg + Refresh + Connect your card + Verify your identity + KYC is in progress + Connect your card to the decentralized payment system + To start using your card you have to pass the KYC process + Please wait until the verification is completed. Usually it takes up to 1 hour. You can close the app and come back later. + PIN Code + Set PIN code for your SaltPay card + Chat with support + Please hold the card until the operation complete + To start the backup process you have to add Tangem card as your backup + No backup card + Backup card ready + Finalize the backup process by creating an access code + Prepare the SaltPay card + Tap the SaltPay card + Tap the Tangem card + Support + Claim %s + To get started, simply claim wxDAI to your wallet + Claim + Congratulations! Your first payment crypto card has been activated + Claiming + It will take a few seconds + Something went wrong + Please check you email for further instructions + Do you want to exit the activation process? + In this case, you will need to start from the beginning. + You have used a card from another wallet. Tap the card associated with this wallet + Referral program + Refer your friends to Tangem + You + Will get + for each wallet bought by your friend on your %s network address%s + Your friend + Will get a + %s discount + when buying a card on tangem.com + Your friends bought + Your personal code + Participate + terms and conditions + By tapping this button you accept + You\'ve accepted + of the referral program + Internal error: wallet manager not found + Bilanz: %s + Share + Copy + Erfolg + Give Permission + To continue you need to allow 1inch smart contracts to use your %s + Amount %s + Your Wallet + Spender + Approve + Swap of %s to + Swap + Insufficient funds + Give Permission + Permit and Swap + Failed to load the information about the referral program. Please try again later. + Failed to load the information about the referral program. Reason: %s. Please try again later. + Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. + Personal code copied! + Buy Tangem Wallet with discount!\n%s + %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed. + Ungültige Adresse + This wallet has already been saved, you can add another one + Entfernen + Privacy policy + Enable biometric authorization + It looks like you have biometric authentication disabled, it is necessary to save wallets + Enable + Save your Wallet feature allows you to use your wallet with biometric auth without tapping your card to the phone to gain access. + %d selected + biometric authentication + biometrics + Enable biometric authentication + Go to settings to enable biometric authentication in the Tangem App + Scan the card + diff --git a/core/res/src/main/res/values-fr/strings_final.xml b/core/res/src/main/res/values-fr/strings_final.xml new file mode 100644 index 0000000000..4b3d386d9b --- /dev/null +++ b/core/res/src/main/res/values-fr/strings_final.xml @@ -0,0 +1,233 @@ + + + Tangem Wallet + 3 cards + 2 cards + Shipping + Free + I have a promo code… + Total + Other payment methods + Buy now + Meet\nTangem + Buy + Store + Send + Pay + Exchange + Lend + Borrow + Revolutionary Hardware Wallet + Store your crypto assets secure while keeping private keys contained in your card + Ultra Secure Backup + Up to + 3 physical cards + to one wallet + Thousands of Currencies + A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card + DeFi Compatible + Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services + The Wallet for Everyone + Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. + Order + Search tokens + You are currently running in Demo mode. All funds are not real. + This feature is disabled in Demo mode + Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + Available networks + %s network not found. Please, add it first and try again. + Attention + Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. + Tokens in Solana network are not supported by this card due to firmware limitation. + Contract address copied! + Contract address + Required field + Please select the network + Decimal number must be a valid integer, no higher than %d + Contract address is invalid + Derivation path is invalid + Note that tokens can be created by anyone. Be aware of adding scam tokens, they can cost nothing. + This token/network has already been added to your list + Decimals + Network + Not selected + E.g. USD Coin + Name + E.g. USDC + Token symbol + BIP44 coin type + Default + The server is not available, please try again later + Total balance + The amount does not include some of your funds + Tokens + Manage tokens + No rate + Network is unreachable + Hide token + Hide %s + Hide + You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. + Unable to hide %s + The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list. + Your wallet has not been backed up + To protect your assets, we advise you to carry out this procedure + Réessayer + Chat + %s network + I understand + Yes + No + Russian bank cards are not accepted at the moment + Do you have a bank card of another country or a UnionPay card? + This network is not supported. Please select another network. + Card Settings + Security Mode + Change access code + Access code will be changed on this card only + Continue + Tangem Bot + Get your card ready! + Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. + Scan Card + App Settings + Keep the wallet in the app + Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card. + Save Access Code + Biometric authentication will be requested instead of the access code for interactions with your card. + Removing the saved card deletes all the saved wallets and their access codes. + This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code. + WalletConnect + Connect to Dapps + This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. + I understand that after performing this action, I will no longer have access to the current wallet + Reset the card + Reset to Factory Settings + Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. + Select network + Scan your card + To access all the networks you need to scan the card + Connection with this Dapp cannot be established due to its technical implementation. + Welcome back! + Use %s or scan a card to access the app + Log in with %s + Scannez la carte + Save your Wallet + Would you like to use %s? + Would you like to use biometrics? + Access the app + Log into the app and check your balance without scanning the card + Access code + %s will be requested instead of the access code for interactions with your wallet + Biometrics will be requested instead of the access code for interactions with your wallet + Note that making a transaction with your funds will still require your card + Allow to use %s + Allow to use biometrics + New feature + My Wallets + Multi-currency + Single-currency + Add new wallet + Rename Wallet + Wallet name + Unlock all with %s + Invalid Tag. It won\'t be added to the transaction. + Invalid Memo. It won\'t be added to the transaction. + Tag + Memo + Attention + Tap the card with the visa logo + No funds for activation + Please contact support + Four identical digits isn\'t safe + Such a PIN can be brute-forced easily + Pin code + Connect + KYC + Verify your identity + Set PIN code + Register + Verify via Utorg + Refresh + Connect your card + Verify your identity + KYC is in progress + Connect your card to the decentralized payment system + To start using your card you have to pass the KYC process + Please wait until the verification is completed. Usually it takes up to 1 hour. You can close the app and come back later. + PIN Code + Set PIN code for your SaltPay card + Chat with support + Please hold the card until the operation complete + To start the backup process you have to add Tangem card as your backup + No backup card + Backup card ready + Finalize the backup process by creating an access code + Prepare the SaltPay card + Tap the SaltPay card + Tap the Tangem card + Support + Claim %s + To get started, simply claim wxDAI to your wallet + Claim + Congratulations! Your first payment crypto card has been activated + Claiming + It will take a few seconds + Something went wrong + Please check you email for further instructions + Do you want to exit the activation process? + In this case, you will need to start from the beginning. + You have used a card from another wallet. Tap the card associated with this wallet + Referral program + Refer your friends to Tangem + You + Will get + for each wallet bought by your friend on your %s network address%s + Your friend + Will get a + %s discount + when buying a card on tangem.com + Your friends bought + Your personal code + Participate + terms and conditions + By tapping this button you accept + You\'ve accepted + of the referral program + Internal error: wallet manager not found + Solde : %s + Share + Copy + Avec succès + Give Permission + To continue you need to allow 1inch smart contracts to use your %s + Amount %s + Your Wallet + Spender + Approve + Swap of %s to + Swap + Insufficient funds + Give Permission + Permit and Swap + Failed to load the information about the referral program. Please try again later. + Failed to load the information about the referral program. Reason: %s. Please try again later. + Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. + Personal code copied! + Buy Tangem Wallet with discount!\n%s + %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed. + Adresse incorrecte + This wallet has already been saved, you can add another one + Supprimer + Privacy policy + Enable biometric authorization + It looks like you have biometric authentication disabled, it is necessary to save wallets + Enable + Save your Wallet feature allows you to use your wallet with biometric auth without tapping your card to the phone to gain access. + %d selected + biometric authentication + biometrics + Enable biometric authentication + Go to settings to enable biometric authentication in the Tangem App + Scan the card + diff --git a/core/res/src/main/res/values-it/strings_final.xml b/core/res/src/main/res/values-it/strings_final.xml new file mode 100644 index 0000000000..53bd5f260c --- /dev/null +++ b/core/res/src/main/res/values-it/strings_final.xml @@ -0,0 +1,233 @@ + + + Tangem Wallet + 3 cards + 2 cards + Shipping + Free + I have a promo code… + Total + Other payment methods + Buy now + Meet\nTangem + Buy + Store + Send + Pay + Exchange + Lend + Borrow + Revolutionary Hardware Wallet + Store your crypto assets secure while keeping private keys contained in your card + Ultra Secure Backup + Up to + 3 physical cards + to one wallet + Thousands of Currencies + A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card + DeFi Compatible + Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services + The Wallet for Everyone + Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. + Order + Search tokens + You are currently running in Demo mode. All funds are not real. + This feature is disabled in Demo mode + Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + Available networks + %s network not found. Please, add it first and try again. + Attention + Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. + Tokens in Solana network are not supported by this card due to firmware limitation. + Contract address copied! + Contract address + Required field + Please select the network + Decimal number must be a valid integer, no higher than %d + Contract address is invalid + Derivation path is invalid + Note that tokens can be created by anyone. Be aware of adding scam tokens, they can cost nothing. + This token/network has already been added to your list + Decimals + Network + Not selected + E.g. USD Coin + Name + E.g. USDC + Token symbol + BIP44 coin type + Default + The server is not available, please try again later + Total balance + The amount does not include some of your funds + Tokens + Manage tokens + No rate + Network is unreachable + Hide token + Hide %s + Hide + You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. + Unable to hide %s + The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list. + Your wallet has not been backed up + To protect your assets, we advise you to carry out this procedure + Riprova + Chat + %s network + I understand + Yes + No + Russian bank cards are not accepted at the moment + Do you have a bank card of another country or a UnionPay card? + This network is not supported. Please select another network. + Card Settings + Security Mode + Change access code + Access code will be changed on this card only + Continue + Tangem Bot + Get your card ready! + Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. + Scan Card + App Settings + Keep the wallet in the app + Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card. + Save Access Code + Biometric authentication will be requested instead of the access code for interactions with your card. + Removing the saved card deletes all the saved wallets and their access codes. + This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code. + WalletConnect + Connect to Dapps + This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. + I understand that after performing this action, I will no longer have access to the current wallet + Reset the card + Reset to Factory Settings + Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. + Select network + Scan your card + To access all the networks you need to scan the card + Connection with this Dapp cannot be established due to its technical implementation. + Welcome back! + Use %s or scan a card to access the app + Log in with %s + Scansiona carta + Save your Wallet + Would you like to use %s? + Would you like to use biometrics? + Access the app + Log into the app and check your balance without scanning the card + Access code + %s will be requested instead of the access code for interactions with your wallet + Biometrics will be requested instead of the access code for interactions with your wallet + Note that making a transaction with your funds will still require your card + Allow to use %s + Allow to use biometrics + New feature + My Wallets + Multi-currency + Single-currency + Add new wallet + Rename Wallet + Wallet name + Unlock all with %s + Invalid Tag. It won\'t be added to the transaction. + Invalid Memo. It won\'t be added to the transaction. + Tag + Memo + Attention + Tap the card with the visa logo + No funds for activation + Please contact support + Four identical digits isn\'t safe + Such a PIN can be brute-forced easily + Pin code + Connect + KYC + Verify your identity + Set PIN code + Register + Verify via Utorg + Refresh + Connect your card + Verify your identity + KYC is in progress + Connect your card to the decentralized payment system + To start using your card you have to pass the KYC process + Please wait until the verification is completed. Usually it takes up to 1 hour. You can close the app and come back later. + PIN Code + Set PIN code for your SaltPay card + Chat with support + Please hold the card until the operation complete + To start the backup process you have to add Tangem card as your backup + No backup card + Backup card ready + Finalize the backup process by creating an access code + Prepare the SaltPay card + Tap the SaltPay card + Tap the Tangem card + Support + Claim %s + To get started, simply claim wxDAI to your wallet + Claim + Congratulations! Your first payment crypto card has been activated + Claiming + It will take a few seconds + Something went wrong + Please check you email for further instructions + Do you want to exit the activation process? + In this case, you will need to start from the beginning. + You have used a card from another wallet. Tap the card associated with this wallet + Referral program + Refer your friends to Tangem + You + Will get + for each wallet bought by your friend on your %s network address%s + Your friend + Will get a + %s discount + when buying a card on tangem.com + Your friends bought + Your personal code + Participate + terms and conditions + By tapping this button you accept + You\'ve accepted + of the referral program + Internal error: wallet manager not found + Saldo: %s + Share + Copy + Con successo + Give Permission + To continue you need to allow 1inch smart contracts to use your %s + Amount %s + Your Wallet + Spender + Approve + Swap of %s to + Swap + Insufficient funds + Give Permission + Permit and Swap + Failed to load the information about the referral program. Please try again later. + Failed to load the information about the referral program. Reason: %s. Please try again later. + Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. + Personal code copied! + Buy Tangem Wallet with discount!\n%s + %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed. + Indirizzo non valido + This wallet has already been saved, you can add another one + Rimuovere + Privacy policy + Enable biometric authorization + It looks like you have biometric authentication disabled, it is necessary to save wallets + Enable + Save your Wallet feature allows you to use your wallet with biometric auth without tapping your card to the phone to gain access. + %d selected + biometric authentication + biometrics + Enable biometric authentication + Go to settings to enable biometric authentication in the Tangem App + Scan the card + diff --git a/core/res/src/main/res/values-ru/strings_final.xml b/core/res/src/main/res/values-ru/strings_final.xml new file mode 100644 index 0000000000..c56fea1dcc --- /dev/null +++ b/core/res/src/main/res/values-ru/strings_final.xml @@ -0,0 +1,233 @@ + + + Tangem Wallet + 3 карты + 2 карты + Доставка + Бесплатно + У меня есть промо-код… + Итого + Другие способы оплаты + Купить сейчас + Встречайте\nTangem + Покупайте + Храните + Отправляйте + Расплачивайтесь + Обменивайте + Вкладывайте + Занимайте + Революционный аппаратный кошелек + Держите свои криптосбережения в безопасности. Приватные ключи надежно хранятся на карте. + Все ключи в безопасности + До + трех карт + с одним кошельком + Тысячи криптовалют + Аппаратный кошелек для ваших биткоинов, эфира и многих других валют одновременно — все в одной карте + Поддержка DeFi + Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах + Кошелек для каждого + Используйте его на ходу, в любом месте, в любое время. Без проводов и батареек. Как только понадобится крипта, просто приложите карту к телефону. + Купить + Поиск токенов + Приложение работает в демонстрационном режиме. Средства на всех счетах ненастоящие. + Эта функция недоступна в демонстрационном режиме + Недостаточно средств для комиссии на вашем %s кошельке для отправки транзакции. Сначала пополните свой %s кошелек. + Доступные сети + Сеть %s не найдена. Пожалуйста, добавьте её и попробуйте заново. + Внимание + Внимание! Валюты на разных сетях имеют разные адреса. Убедитесь, что адрес соответствует сети, в которой вы отправляете средства. + Токены в сети Solana не поддерживаются этой картой из-за ограничений прошивки. + Адрес контракта скопирован! + Адрес контракта + Обязательное поле + Пожалуйста, выберите сеть + Количество знаков после запятой должно быть корректным числом не больше %d + Адрес контракта некорректен + Путь деривации некорректен + Токены могут быть созданы кем угодно. Остерегайтесь мошеннических токенов, они могут ничего не стоить + Этот токен/сеть уже находится в вашем списке + Знаков после запятой + Сеть + Не выбрано + Например, USD Coin + Название токена + Например, USDC + Символ токена + Деривация по BIP44 + По-умолчанию + Сервер недоступен, повторите попытку позднее + Баланс + В сумме учтены не все монеты + Токены + Управление токенами + Нет цены + Сеть недоступна + Скрыть токен + Скрыть %s + Скрыть + Вы скрываете токен с главного экрана, но в любой момент сможете добавить его обратно через страницу управления токенами. + Невозможно скрыть %s + Токен %s является основной валютой в сети %s и не может быть скрыт до тех пор, пока у вас в списке есть другие токены этой сети. + Бэкап кошелька не был произведен + Чтобы защитить свои активы, мы советуем вам выполнить эту процедуру + Повторить + Чат + Сеть %s + Я понял + Да + Нет + Карты банков РФ в данный момент не принимаются + У вас есть карта банка другой страны или платежной системы UnionPay? + Сеть не поддерживается. Пожалуйста, выберите другую сеть. + Настройки карты + Тип безопасности + Смена кода доступа + Код доступа будет изменен только на данной карте + Продолжить + Tangem Bot + Приготовьте свою карту + Отсканируйте карту, чтобы изменить ее настройки. Изменения затронут только ту карту, которую вы отсканировали, и не повлияют на другие карты, привязанные к вашему кошельку. + Сканировать + Настройки приложения + Cохранение кошелька + Подключите функцию привязки карты в приложении, а также возможность биометрической аутентификации. Подпись транзакции все так же потребует карту. + Сохранение кода доступа + Подключите функцию хранения кодов доступа от карт на телефоне в зашифрованном виде, и при работе с картой вместо кода доступа будет запрашиваться биометрическая аутентификация. + При отключении функции сохранения кошелька все ранее сохраненные кошельки будут удалены. + Все сохраненные коды доступа будут удалены. Вам потребуется вводить код доступа при работе с кошельком. + WalletConnect + Подключение к Dapps + Это действие приведет к полному удалению кошелька на этой карте. Кошелек невозможно будет восстановить или использовать данную карту для восстановления кода доступа + Я понимаю, что после выполнения этого действия у меня больше не будет доступа к текущему кошельку + Сбросить карту + Сброс к заводским настройкам + Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты. Вы не сможете восстановить текущий кошелек или использовать эту карту для восстановления кода доступа. + Выберите сеть + Отсканируйте карту + Чтобы получить доступ ко всем сетям, вам необходимо отсканировать карту + Cоединение с этим Dapp сервисом не может быть установлено из-за его технической реализации. + C возвращением! + Используйте %s или код доступа для входа в приложение + Войти с %s + Сканировать карту + Сохраните ваш кошелек + Вы хотите использовать %s? + Вы хотите использовать биометрию? + Доступ в приложение + Войдите в приложение и следите за своим балансом без сканирования карты + Код доступа + Для операций с вашим кошельком будет запрашиваться %s вместо кода доступа карты + Для операций с вашим кошельком будет запрашиваться биометрия вместо кода доступа карты + Обратите внимание, что для совершения транзакции с вашими средствами по-прежнему потребуется ваша карта + Использовать %s + Использовать биометрию + Новый функционал + Мои кошельки + Мультивалютные + Одновалютные + Добавить новый кошелек + Переименование кошелька + Имя кошелька + Разблокировать все с %s + Недопустимый Tag. Он не будет добавлен в транзакцию. + Недопустимый Memo. Он не будет добавлен в транзакцию. + Tag + Memo + Внимание + Приложите карту с логотипом Visa + Недостаточно средств для активации + Пожалуйста обратитесь в службу поддержки + Ввод одинаковых цифр является не безопасным + Данный Код доступа может быть легко взломан + Код доступа + Подключиться + Верификация клиента + Подтвердите свою личность + Установить Код доступа + Зарегистрироваться + Верифицировать (Utorg) + Обновить + Подключите свою карту + Подтвердите свою личность + Подтверждение личности в процессе + Подключите вашу карту к децентрализованной платежной системе + Для начала работы с картой вам необходимо завершить процесс подтверждения личности + Пожалуйста дождитесь завершения процесса подтверждения личности. Вы будете уведомлены через e-mail. Обычно это занимает не более часа. Вы можете закрыть приложение и вернуться позже. + Код доступа + Установите Код доступа для вашей SaltPay карты + Чат поддержки + Пожалуйста, удерживайте карту до завершения операции + Для начала процесса бэкапа вам необходимо добавить Tangem карту + Бэкап карта не добавлена + Бэкап карта создана + Завершите процесс бэкапа создав код доступа + Приготовьте SaltPay карту + Приложите SaltPay карту + Приложите Tangem карту + Чат + Запросить %s + Для начала работы просто запросите начисление wxDai на свой кошелек + Запросить + Поздравляем! Ваша платежная крипто карта теперь активирована! + Запрашивается + Это займет несколько секунд + Что-то пошло не так + Более подробная информация отправлена на ваш адрес электронной почты. + Вы хотите выйти из процесса активации? + В этом случае вам будет необходимо начать процесс заново. + Вы использовали карту от другого кошелька. Приложите карту, связанную с этим кошельком. + Реферальная программа + Приведи друга в Tangem + Вы + Получите + на ваш адрес в сети %s%s за каждый кошелек, который купит ваш друг + Ваш друг + Получит + %s скидку + при покупке карточки на сайте tangem.com + Ваши друзья купили + Ваш персональный код + Участвовать + условия участия + Нажимая на эту кнопку вы принимаете + Вы приняли + в реферальной программе + Внутренняя ошибка: не удается найти менеджер кошельков + Баланс: %s + Поделиться + Копировать + Успешно + Дать разрешение + Чтобы продолжить, вам нужно разрешить смарт-контракту 1inch использовать ваш %s + Количество %s + Ваш кошелек + Отправитель + Подтвердить + Обмен %s на + Обмен + Недостаточно средств + Дать разрешение + Разрешить и обменять + Не удалось загрузить информацию по реферальной программе. Пожалуйста, попробуйте позже. + Не удалось загрузить информацию по реферальной программе. Причина: %s. Пожалуйста, попробуйте позже. + Не удалось обработать вашу заявку на участие. Причина: %s. Пожалуйста, попробуйте позже. Если проблема сохранится, вы можете обратиться в техподдержку. + Персональный код скопирован! + Купи Tangem Wallet со скидкой!\n%s + Сеть %s использует концепцию экзистенциального депозита. Если баланс вашего счета опустится ниже %s, он будет деактивирован, а все оставшиеся средства будут уничтожены. + Неверный адрес + Этот кошелек уже был сохранен, вы можете добавить другой + Удалить + Privacy policy + Включите биометрическую аутентификацию + Похоже, что у вас отключена биометрическая аутентификация, она необходима для сохранения кошельков + Включить + Функция сохранения кошелька позволяет вам использовать свой кошелек с биометрической аутентификацией, не прикладывая карту к телефону для получения доступа. + %d выбрано + биометрическую аутентификацию + биометрией + Включите биометрическую аутентификацию + Перейдите в настройки, чтобы включить биометрическую аутентификацию в приложении Tangem App + Отсканируйте карту + diff --git a/core/res/src/main/res/values/strings_final.xml b/core/res/src/main/res/values/strings_final.xml new file mode 100644 index 0000000000..673ced5d90 --- /dev/null +++ b/core/res/src/main/res/values/strings_final.xml @@ -0,0 +1,233 @@ + + + Tangem Wallet + 3 cards + 2 cards + Shipping + Free + I have a promo code… + Total + Other payment methods + Buy now + Meet\nTangem + Buy + Store + Send + Pay + Exchange + Lend + Borrow + Revolutionary Hardware Wallet + Store your crypto assets secure while keeping private keys contained in your card + Ultra Secure Backup + Up to + 3 physical cards + to one wallet + Thousands of Currencies + A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card + DeFi Compatible + Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services + The Wallet for Everyone + Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. + Order + Search tokens + You are currently running in Demo mode. All funds are not real. + This feature is disabled in Demo mode + Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + Available networks + %s network not found. Please, add it first and try again. + Attention + Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. + Tokens in Solana network are not supported by this card due to firmware limitation. + Contract address copied! + Contract address + Required field + Please select the network + Decimal number must be a valid integer, no higher than %d + Contract address is invalid + Derivation path is invalid + Note that tokens can be created by anyone. Be aware of adding scam tokens, they can cost nothing. + This token/network has already been added to your list + Decimals + Network + Not selected + E.g. USD Coin + Name + E.g. USDC + Token symbol + BIP44 coin type + Default + The server is not available, please try again later + Total balance + The amount does not include some of your funds + Tokens + Manage tokens + No rate + Network is unreachable + Hide token + Hide %s + Hide + You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. + Unable to hide %s + The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list. + Your wallet has not been backed up + To protect your assets, we advise you to carry out this procedure + Retry + Chat + %s network + I understand + Yes + No + Russian bank cards are not accepted at the moment + Do you have a bank card of another country or a UnionPay card? + This network is not supported. Please select another network. + Card Settings + Security Mode + Change Access Code + Access code will be changed on this card only + Continue + Tangem Bot + Get your card ready! + Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. + Scan Card + App Settings + Keep the wallet in the app + Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card. + Save Access Code + Biometric authentication will be requested instead of the access code for interactions with your card. + Removing the saved card deletes all the saved wallets and their access codes. + This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code. + WalletConnect + Connect to Dapps + This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. + I understand that after performing this action, I will no longer have access to the current wallet + Reset the Card + Reset to Factory Settings + Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. + Select network + Scan your card + To access all the networks you need to scan the card + Connection with this Dapp cannot be established due to its technical implementation. + Welcome back! + Use %s or scan a card to access the app + Log in with %s + Scan card + Save your wallet + Would you like to use %s? + Would you like to use biometrics? + Access the app + Log into the app and check your balance without scanning the card + Access code + %s will be requested instead of the access code for interactions with your wallet + Biometrics will be requested instead of the access code for interactions with your wallet + Note that making a transaction with your funds will still require your card + Allow to use %s + Allow to use biometrics + New feature + My Wallets + Multi-currency + Single-currency + Add new wallet + Rename Wallet + Wallet name + Unlock all with %s + Invalid Tag. It won\'t be added to the transaction. + Invalid Memo. It won\'t be added to the transaction. + Tag + Memo + Attention + Tap the card with the visa logo + No funds for activation + Please contact support + Four identical digits isn\'t safe + Such a PIN can be brute-forced easily + Pin code + Connect + KYC + Verify your identity + Set PIN code + Register + Verify via Utorg + Refresh + Connect your card + Verify your identity + KYC is in progress + Connect your card to the decentralized payment system + To start using your card you have to pass the KYC process + Please wait until the verification is completed. Usually it takes up to 1 hour. You can close the app and come back later. + PIN Code + Set PIN code for your SaltPay card + Chat with support + Please hold the card until the operation complete + To start the backup process you have to add Tangem card as your backup + No backup card + Backup card ready + Finalize the backup process by creating an access code + Prepare the SaltPay card + Tap the SaltPay card + Tap the Tangem card + Support + Claim %s + To get started, simply claim wxDAI to your wallet + Claim + Congratulations! Your first payment crypto card has been activated + Claiming + It will take a few seconds + Something went wrong + Please check your email for further instructions + Do you want to exit the activation process? + In this case, you will need to start from the beginning. + You have used a card from another wallet. Tap the card associated with this wallet + Referral program + Refer your friends to Tangem + You + Will get + for each wallet bought by your friend on your %s network address%s + Your friend + Will get a + %s discount + when buying a card on tangem.com + Your friends bought + Your personal code + Participate + terms and conditions + By tapping this button you accept + You\'ve accepted + of the referral program + Internal error: wallet manager not found + Balance: %s + Share + Copy + Success + Give Permission + To continue you need to allow 1inch smart contracts to use your %s + Amount %s + Your Wallet + Spender + Approve + Swap of %s to + Swap + Insufficient funds + Give Permission + Permit and Swap + Failed to load the information about the referral program. Please try again later. + Failed to load the information about the referral program. Reason: %s. Please try again later. + Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. + Personal code copied! + Buy Tangem Wallet with discount!\n%s + %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed. + Invalid address + This wallet has already been saved, you can add another one + Delete + Privacy policy + Enable biometric authorization + It looks like you have biometric authentication disabled, it is necessary to save wallets + Enable + Save your Wallet feature allows you to use your wallet with biometric auth without tapping your card to the phone to gain access. + %d selected + biometric authentication + biometrics + Enable biometric authentication + Go to settings to enable biometric authentication in the Tangem App + Scan the card + From 1ef5e450d84a02b6e0030f77bbf402b1fdc5779a Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 26 Dec 2022 18:11:01 +0300 Subject: [PATCH 02/21] Updated on 2026-08-14 --- .../tap/features/wallet/ui/WalletFragment.kt | 7 +++--- .../core/ui/utils/OneTouchClickListener.kt | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 core/ui/src/main/java/com/tangem/core/ui/utils/OneTouchClickListener.kt diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index c0bde194bf..8a67196de1 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -16,6 +16,7 @@ import by.kirich1409.viewbindingdelegate.viewBinding import coil.load import coil.size.Scale import com.tangem.core.ui.fragments.setStatusBarColor +import com.tangem.core.ui.utils.OneTouchClickListener import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.tap.MainActivity import com.tangem.tap.common.analytics.Analytics @@ -110,9 +111,9 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber Unit) : View.OnClickListener { + + private var lastClickTimeMs: Long = 0L + + override fun onClick(v: View?) { + if (SystemClock.elapsedRealtime() - lastClickTimeMs > CLICK_DELAY_MS) { + lastClickTimeMs = SystemClock.elapsedRealtime() + action() + } + } + + companion object { + private const val CLICK_DELAY_MS = 500L + } +} \ No newline at end of file From a7ec12b6dc7c8a30d545f32db5716ce479028268 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 26 Dec 2022 14:11:02 +0300 Subject: [PATCH 03/21] Updated on 2026-08-14 --- .../com/tangem/tap/domain/TangemSdkManager.kt | 5 ++ .../redux/WalletSelectorMiddleware.kt | 68 +++++++++++-------- 2 files changed, 43 insertions(+), 30 deletions(-) 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 01350c6c63..be8e4f65b2 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -234,6 +234,11 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co } } + fun useBiometricsForAccessCode(): Boolean { + val policy = tangemSdk.config.userCodeRequestPolicy + return policy is UserCodeRequestPolicy.AlwaysWithBiometrics && policy.codeType == UserCodeType.AccessCode + } + companion object { val config = Config( linkedTerminal = true, 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 b6b31419de..c7d8495f6a 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 @@ -19,6 +19,7 @@ import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.model.builders.UserWalletBuilder import com.tangem.tap.domain.scanCard.ScanCardProcessor +import com.tangem.tap.preferencesStorage import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -131,21 +132,45 @@ internal class WalletSelectorMiddleware { private fun addWallet() = scope.launch { Analytics.send(MyWallets.Button.ScanNewCard) - scanCardInternal { scanResponse -> - val userWallet = UserWalletBuilder(scanResponse).build() + val prevUseBiometricsForAccessCode = tangemSdkManager.useBiometricsForAccessCode() - userWalletsListManager.save(userWallet) - .doOnFailure { error -> - store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) - } - .doOnSuccess { - Analytics.send(MyWallets.CardWasScanned) + // Update access code policy for access code saving when a card was scanned + tangemSdkManager.setAccessCodeRequestPolicy( + useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes, + ) + ScanCardProcessor.scan( + onSuccess = { scanResponse -> + saveUserWalletAndPopBackToWalletScreen(scanResponse) + .doOnFailure { error -> + // Rollback policy if card saving was failed + tangemSdkManager.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) + store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) + } + }, + onFailure = { error -> + // Rollback policy if card scanning was failed + tangemSdkManager.setAccessCodeRequestPolicy(prevUseBiometricsForAccessCode) + store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) + }, + onWalletNotCreated = { + // No need to rollback policy, continue with the policy set before the card scan + store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) + store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) + }, + ) + } - store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) - store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) - store.onUserWalletSelected(userWallet) - } - } + private suspend fun saveUserWalletAndPopBackToWalletScreen(scanResponse: ScanResponse): CompletionResult { + val userWallet = UserWalletBuilder(scanResponse).build() + + return userWalletsListManager.save(userWallet) + .doOnSuccess { + Analytics.send(MyWallets.CardWasScanned) + + store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) + store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) + store.onUserWalletSelected(userWallet) + } } private fun selectWallet(userWalletId: UserWalletId) { @@ -265,23 +290,6 @@ internal class WalletSelectorMiddleware { } } - private suspend inline fun scanCardInternal( - crossinline onCardScanned: suspend (ScanResponse) -> Unit, - ) { - ScanCardProcessor.scan( - onSuccess = { - onCardScanned(it) - }, - onFailure = { error -> - store.dispatchOnMain(WalletSelectorAction.AddWallet.Error(error)) - }, - onWalletNotCreated = { - store.dispatchOnMain(WalletSelectorAction.AddWallet.Success) - store.dispatchOnMain(NavigationAction.PopBackTo()) - }, - ) - } - private suspend fun deleteAccessCodes(userWalletsIds: List): CompletionResult { val cardsIds = userWalletsListManager.userWallets.firstOrNull().orEmpty() .asSequence() From 5dc6145d634009a4e7a892b68c2ad913f750d791 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 27 Dec 2022 11:30:21 +0300 Subject: [PATCH 04/21] Updated on 2026-08-14 --- .../com/tangem/tap/features/onboarding/OnboardingHelper.kt | 3 +++ 1 file changed, 3 insertions(+) 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 9b5c5e9958..775dca1ed3 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 @@ -70,7 +70,10 @@ class OnboardingHelper { // then open save wallet screen tangemSdkManager.canUseBiometry && preferencesStorage.shouldShowSaveUserWalletScreen -> scope.launch { + store.onCardScanned(scanResponse) + delay(timeMillis = 1_200) + store.dispatchOnMain( SaveWalletAction.ProvideBackupInfo( scanResponse = scanResponse, From 5ddd0600796cfcffeb156380464deb8405cdcacd Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 27 Dec 2022 17:59:57 +0300 Subject: [PATCH 05/21] Updated on 2026-08-14 --- .../DefaultWalletManagersRepository.kt | 6 +---- .../redux/middlewares/WalletMiddleware.kt | 2 +- .../redux/reducers/MultiWalletReducer.kt | 8 +++---- .../wallet/redux/reducers/WalletReducer.kt | 6 ++--- .../tap/features/wallet/ui/WalletViewModel.kt | 8 +++++-- .../redux/WalletSelectorMiddleware.kt | 24 ++++++++++++------- 6 files changed, 30 insertions(+), 24 deletions(-) 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 3de7a3f6b1..6355f2f6d6 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 @@ -106,11 +106,7 @@ internal class DefaultWalletManagersRepository( override suspend fun delete(userWalletIds: List): CompletionResult = catching { walletManagersStorage.update { prevManagers -> - prevManagers.apply { - userWalletIds.forEach { userWalletId -> - remove(userWalletId) - } - } + prevManagers.filterKeys { it !in userWalletIds } as HashMap> } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 222f7b7fa1..88916c3e2b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -306,7 +306,7 @@ class WalletMiddleware { val reduxWalletStores = wallStores.mapToReduxModels(state.isMultiwalletAllowed) store.dispatchOnMain( WalletAction.WalletStoresChanged.UpdateWalletStores( - reduxWalletStores = reduxWalletStores.toList(), + reduxWalletStores = reduxWalletStores, ), ) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt index 8ed45a3a6f..afb523a5ca 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt @@ -36,7 +36,7 @@ class MultiWalletReducer { fun reduce(action: WalletAction.MultiWallet, state: WalletState): WalletState { return when (action) { is WalletAction.MultiWallet.AddBlockchains -> { - val walletStores: List = action.blockchains.mapNotNull { blockchain -> + val walletStores: List = action.blockchains.map { blockchain -> val walletManager = action.walletManagers.firstOrNull { it.wallet.blockchain == blockchain.blockchain && (it.wallet.publicKey.derivationPath?.rawPath == blockchain.derivationPath) @@ -70,10 +70,10 @@ class MultiWalletReducer { ) } - val selectedCurrency = if (!state.isMultiwalletAllowed) { - walletStores.firstOrNull()?.walletsData?.firstOrNull()?.currency + val selectedCurrency = if (state.isMultiwalletAllowed) { + state.selectedCurrency } else { - state.selectedWalletData?.currency + walletStores.firstOrNull()?.walletsData?.firstOrNull()?.currency } state.copy( walletsStores = walletStores, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 254fe48e3b..d71909cfec 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -362,13 +362,13 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS ) } is WalletAction.LoadData.Success -> { - val selectedCurrency = if (!newState.isMultiwalletAllowed) { + val selectedCurrency = if (newState.isMultiwalletAllowed) { + newState.selectedCurrency + } else { newState.walletsStores.firstOrNull() ?.walletsData ?.firstOrNull() ?.currency - } else { - newState.selectedWalletData?.currency } newState = newState.copy( 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 df0b0537ed..a9fc0ad8cf 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 @@ -8,8 +8,10 @@ import com.tangem.tap.store import com.tangem.tap.userWalletsListManager import com.tangem.tap.walletStoresManager import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -21,8 +23,10 @@ internal class WalletViewModel : ViewModel() { private fun bootstrapSelectedWalletStoresChanges() { userWalletsListManager.selectedUserWallet - .flatMapLatest { selectedWallet -> - walletStoresManager.get(selectedWallet.walletId) + .map { it.walletId } + .distinctUntilChanged() + .flatMapLatest { selectedUserWalletId -> + walletStoresManager.get(selectedUserWalletId) } .onEach { walletStores -> store.dispatch(WalletAction.WalletStoresChanged(walletStores)) 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 c7d8495f6a..cc6642743f 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 @@ -277,26 +277,32 @@ internal class WalletSelectorMiddleware { .flatMap { walletStoresManager.delete(userWalletsIds) } .flatMap { deleteAccessCodes(userWalletsIds) } .doOnSuccess { - val selectedWallet = userWalletsListManager.selectedUserWalletSync + val selectedUserWallet = userWalletsListManager.selectedUserWalletSync when { - selectedWallet == null -> { + selectedUserWallet == null -> { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome)) } - currentSelectedWalletId != selectedWallet.walletId -> { - store.onUserWalletSelected(selectedWallet) + + currentSelectedWalletId != selectedUserWallet.walletId -> { + store.onUserWalletSelected(selectedUserWallet) } } } } private suspend fun deleteAccessCodes(userWalletsIds: List): CompletionResult { - val cardsIds = userWalletsListManager.userWallets.firstOrNull().orEmpty() - .asSequence() - .filter { it.walletId in userWalletsIds } - .flatMap { it.cardsInWallet } + val cardsIds = userWalletsListManager.userWallets.firstOrNull() + ?.asSequence() + ?.filter { it.walletId in userWalletsIds } + ?.flatMap { it.cardsInWallet } + ?.toSet() - return tangemSdkManager.deleteSavedUserCodes(cardsIds.toSet()) + return if (cardsIds.isNullOrEmpty()) { + CompletionResult.Success(Unit) + } else { + tangemSdkManager.deleteSavedUserCodes(cardsIds.toSet()) + } } private suspend fun UserWalletModel.updateWalletStoresAndCalculateFiatBalance( From 343f6de7cdd3d32ccfb9d18b5515b7589ef9f181 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 27 Dec 2022 19:01:21 +0300 Subject: [PATCH 06/21] Updated on 2026-08-14 --- .../tap/features/wallet/redux/reducers/WalletReducer.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index d71909cfec..2505702c20 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -20,7 +20,6 @@ import com.tangem.tap.domain.extensions.isMultiwalletAllowed import com.tangem.tap.domain.getFirstToken import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.models.WalletRent import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.Artwork @@ -36,7 +35,6 @@ import com.tangem.tap.features.wallet.redux.replaceSomeWalletsData import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.features.wallet.ui.BalanceWidgetData import com.tangem.tap.proxy.AppStateHolder -import com.tangem.tap.store import org.rekotlin.Action import timber.log.Timber import java.math.BigDecimal @@ -344,8 +342,9 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS card.settings.isBackupAllowed && card.backupStatus == CardDTO.BackupStatus.NoBackup, walletCardsCount = card.findCardsCount(), + walletsStores = newState.walletsStores, totalBalance = if (isMultiCurrency) { - TotalBalance(ProgressState.Loading, BigDecimal.ZERO, store.state.globalState.appCurrency) + newState.totalBalance } else { null }, From 87ba93d4d67c06276d351ea82e5c2a4898e6a361 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Dec 2022 17:15:32 +0300 Subject: [PATCH 07/21] Updated on 2026-08-14 --- .../tangem/tap/features/wallet/ui/WalletDetailsFragment.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 0795efcea9..9afdb2071b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -132,12 +132,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), override fun onStop() { super.onStop() store.unsubscribe(this) - } - - override fun onDestroy() { walletDataWatcher.clear() walletStateWatcher.clear() - super.onDestroy() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { From 1084c9ff697a679548e39f0fe2db8e736bc79b8e Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Dec 2022 18:40:03 +0300 Subject: [PATCH 08/21] Updated on 2026-08-14 --- .../AddressInfoBottomSheetDialog.kt | 30 +++++------------ .../wallet/ui/WalletDetailsFragment.kt | 18 +++++++++-- .../wallet/ui/wallet/SingleWalletView.kt | 32 ++++++++++++++----- .../layout/dialog_onboarding_address_info.xml | 2 +- app/src/main/res/layout/layout_address.xml | 11 +++++++ .../main/res/layout/layout_wallet_details.xml | 2 +- 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 | 3 +- core/res/src/main/res/values/strings.xml | 3 +- 11 files changed, 65 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt index 4635716436..b56ddaf6cd 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt @@ -11,8 +11,8 @@ import com.tangem.tap.common.extensions.copyToClipboard import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.extensions.dispatchShare import com.tangem.tap.common.extensions.dispatchToastNotification +import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.redux.AppDialog -import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.store import com.tangem.wallet.R @@ -62,26 +62,12 @@ class AddressInfoBottomSheetDialog( Analytics.send(Token.Recieve.ButtonShareAddress()) store.dispatchShare(data.shareUrl) } - tvReceiveMessage.text = getQRReceiveMessage(tvReceiveMessage.context, stateDialog.currency) - } -} - -fun getQRReceiveMessage(context: Context, currency: Currency): String { - return when (currency) { - is Currency.Blockchain -> { - context.getString( - R.string.address_qr_code_message_format, - currency.blockchain.fullName, - currency.currencySymbol, - ) - } - is Currency.Token -> { - context.getString( - R.string.address_qr_code_message_token_format, - currency.token.name, - currency.currencySymbol, - currency.blockchain.fullName, - ) - } + val blockchain = stateDialog.currency.blockchain + tvReceiveMessage.text = tvReceiveMessage.getString( + id = R.string.address_qr_code_message_format, + blockchain.fullName, + blockchain.currency, + blockchain.fullName, + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 9afdb2071b..fcbe06954f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -36,7 +36,6 @@ import com.tangem.tap.common.extensions.toQrCode import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.tokens.models.BlockchainNetwork -import com.tangem.tap.features.onboarding.getQRReceiveMessage import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction import com.tangem.tap.features.wallet.redux.ErrorType @@ -324,8 +323,21 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), ) } ivQrCode.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode()) - tvReceiveMessage.text = - getQRReceiveMessage(tvReceiveMessage.context, state.currency) + + tvReceiveMessage.text = when (val currency = state.currency) { + is Currency.Blockchain -> tvReceiveMessage.getString( + id = R.string.address_qr_code_message_format, + currency.blockchain.fullName, + currency.currencySymbol, + currency.blockchain.fullName, + ) + is Currency.Token -> tvReceiveMessage.getString( + id = R.string.address_qr_code_message_format, + currency.token.name, + currency.currencySymbol, + currency.blockchain.fullName, + ) + } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt index ed9576d384..1e96cb230b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt @@ -6,6 +6,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.tangem.tap.common.extensions.beginDelayedTransition import com.tangem.tap.common.extensions.fitChipsByGroupWidth import com.tangem.tap.common.extensions.getQuantityString +import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState @@ -65,7 +66,7 @@ class SingleWalletView : WalletView() { setupTwinCards(state.twinCardsState, binding) setupButtons(state.primaryWallet, binding, state.isExchangeServiceFeatureOn) - setupAddressCard(state.primaryWallet, binding) + setupAddressCard(state, binding) showPendingTransactionsIfPresent(state.primaryWallet.pendingTransactions) setupBalance(state, state.primaryWallet) } @@ -152,35 +153,50 @@ class SingleWalletView : WalletView() { } } - private fun setupAddressCard(state: WalletData, binding: FragmentWalletBinding) = with(binding.lAddress) { - if (state.walletAddresses != null && state.currency is Currency.Blockchain) { + private fun setupAddressCard(state: WalletState, binding: FragmentWalletBinding) = with(binding.lAddress) { + val primaryWallet = state.primaryWallet + if (primaryWallet?.walletAddresses != null && primaryWallet.currency is Currency.Blockchain) { binding.lAddress.root.show() - if (state.shouldShowMultipleAddress()) { + if (primaryWallet.shouldShowMultipleAddress()) { (binding.lAddress.root as? ViewGroup)?.beginDelayedTransition() chipGroupAddressType.show() chipGroupAddressType.fitChipsByGroupWidth() - val checkedId = MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type) + val checkedId = MultipleAddressUiHelper.typeToId(primaryWallet.walletAddresses.selectedAddress.type) if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId) chipGroupAddressType.setOnCheckedChangeListener { group, checkedId -> if (checkedId == -1) return@setOnCheckedChangeListener - val type = MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain) + val type = MultipleAddressUiHelper.idToType(checkedId, primaryWallet.currency.blockchain) type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) } } } else { chipGroupAddressType.hide() } - tvAddress.text = state.walletAddresses.selectedAddress.address + tvAddress.text = primaryWallet.walletAddresses.selectedAddress.address tvExplore.setOnClickListener { store.dispatch( WalletAction.ExploreAddress( - state.walletAddresses.selectedAddress.exploreUrl, + primaryWallet.walletAddresses.selectedAddress.exploreUrl, fragment!!.requireContext(), ), ) } + setupCardInfo(state) } else { binding.lAddress.root.hide() } } + + private fun setupCardInfo(state: WalletState) { + val textView = binding?.lAddress?.tvInfo + val blockchain = state.primaryWallet?.currency?.blockchain + if (textView != null && blockchain != null) { + textView.text = textView.getString( + id = R.string.address_qr_code_message_format, + blockchain.fullName, + blockchain.currency, + blockchain.fullName, + ) + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_onboarding_address_info.xml b/app/src/main/res/layout/dialog_onboarding_address_info.xml index ca04440067..eadb8f7f36 100644 --- a/app/src/main/res/layout/dialog_onboarding_address_info.xml +++ b/app/src/main/res/layout/dialog_onboarding_address_info.xml @@ -36,7 +36,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/imv_qr_code" - tools:text="@string/address_qr_code_message_token_format" /> + tools:text="Send only Ethereum (ETH) from Ethereum network to this address. Using other tokens and networks may result in loss of funds." /> + + + tools:text="Send only Ethereum (ETH) from Ethereum network to this address. Using other tokens and networks may result in loss of funds." /> diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 37d63b9b52..80ac6ebe7b 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -355,8 +355,7 @@ Success! Your card is activated and ready to be used Balance - Send only %s (%s) to this address. Using other tokens and networks may result in loss of funds. - Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds. + Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds. If the process of creating the wallet gets interrupted in any way, you\'ll have to start over. The twinning process is partly complete. You can\'t exit it now. OK, ich hab\'s! diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index f65d8b25c1..e657f386a8 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -355,8 +355,7 @@ Success! Your card is activated and ready to be used Balance - Send only %s (%s) to this address. Using other tokens and networks may result in loss of funds. - Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds. + Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds. If the process of creating the wallet gets interrupted in any way, you\'ll have to start over. The twinning process is partly complete. You can\'t exit it now. Ok, je l\'ai! diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index f92dde614e..698174469b 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -355,8 +355,7 @@ Success! Your card is activated and ready to be used Balance - Send only %s (%s) to this address. Using other tokens and networks may result in loss of funds. - Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds. + Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds. If the process of creating the wallet gets interrupted in any way, you\'ll have to start over. The twinning process is partly complete. You can\'t exit it now. Ok, ho capito! diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 73375dc62d..d015da467f 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -355,8 +355,7 @@ Успешно! Ваша карта активирована и готова к использованию Баланс - Отправляйте только %s (%s) на этот адрес. Иначе это может привести к утрате средств. - Отправляйте только %s (%s) из сети %s на этот адрес. Иначе это может привести к утрате средств. + Отправляйте только %s (%s) в сети %s на этот адрес. Использование другой сети может привести к утрате средств. Если процесc создания кошелька каким-либо образом прервется, вам придется начинать сначала. Процесс связывания карт частично завершен. Вы не можете выйти из него сейчас. Понятно! diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index e7edae9700..1c84b9004d 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -355,8 +355,7 @@ Success! Your card is activated and ready to be used Balance - Send only %s (%s) to this address. Using other tokens and networks may result in loss of funds. - Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds. + Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds. If the process of creating the wallet gets interrupted in any way, you\'ll have to start over. The twinning process is partly complete. You can\'t exit it now. Ok, Got it! From c0526b7ceb288e535a79c74ba3932b6dc08f6f99 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Dec 2022 17:00:44 +0300 Subject: [PATCH 09/21] Updated on 2026-08-14 --- .../tap/domain/model/builders/UserWalletBuilder.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) 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 6e4d834d38..ed8eb97623 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,5 +1,7 @@ package com.tangem.tap.domain.model.builders +import com.tangem.common.card.EllipticCurve +import com.tangem.common.card.FirmwareVersion import com.tangem.common.extensions.toHexString import com.tangem.common.services.Result import com.tangem.domain.common.CardDTO @@ -40,7 +42,16 @@ class UserWalletBuilder( ProductType.Note -> false ProductType.Twins -> false ProductType.SaltPay -> false - ProductType.Wallet -> !card.isStart2Coin + ProductType.Wallet -> when { + card.isStart2Coin -> false + card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable -> true + else -> { + val cardWallets = card.wallets + require(cardWallets.isNotEmpty()) { "Card wallets must not be empty" } + + cardWallets.first().curve == EllipticCurve.Secp256k1 + } + } } fun backupCardsIds(backupCardsIds: Set?) = this.apply { From 9143789880bcd5f911df50f4f748cbf81ad3a82d Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Dec 2022 18:25:38 +0300 Subject: [PATCH 10/21] Updated on 2026-08-14 --- .../BiometricUserWalletsListManager.kt | 2 +- .../repository/UserWalletsKeysRepository.kt | 6 ++++++ .../UserWalletsPublicInformationRepository.kt | 2 -- .../BiometricUserWalletsKeysRepository.kt | 7 +++++++ .../DefaultUserWalletsPublicInformationRepository.kt | 4 ---- .../tap/features/details/redux/DetailsMiddleware.kt | 12 +++++++++--- .../tap/features/details/redux/DetailsReducer.kt | 3 +-- 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt index f7781ca770..fdd95f5f63 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt @@ -51,7 +51,7 @@ internal class BiometricUserWalletsListManager( get() = state.value.isLocked override val hasSavedUserWallets: Boolean - get() = publicInformationRepository.isNotEmpty() + get() = keysRepository.hasSavedEncryptionKeys() override suspend fun unlockWithBiometry(): CompletionResult { return unlockWithBiometryInternal() diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsKeysRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsKeysRepository.kt index f10e0beeb5..bf96081cd4 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsKeysRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsKeysRepository.kt @@ -32,4 +32,10 @@ internal interface UserWalletsKeysRepository { * @return [CompletionResult] of operation * */ suspend fun clear(): CompletionResult + + /** + * Determine if the user has saved user wallets + * @return [Boolean] true if user has saved wallets + * */ + fun hasSavedEncryptionKeys(): Boolean } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsPublicInformationRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsPublicInformationRepository.kt index f0387d3f0e..8765a6b804 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsPublicInformationRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsPublicInformationRepository.kt @@ -12,6 +12,4 @@ internal interface UserWalletsPublicInformationRepository { suspend fun delete(walletIds: List): CompletionResult suspend fun clear(): CompletionResult - - fun isNotEmpty(): Boolean } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt index 5e57d10474..8de5a59457 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt @@ -17,6 +17,7 @@ import com.tangem.tap.domain.userWalletList.UserWalletListError import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext internal class BiometricUserWalletsKeysRepository( @@ -77,6 +78,12 @@ internal class BiometricUserWalletsKeysRepository( } } + override fun hasSavedEncryptionKeys(): Boolean { + return runBlocking { + getUserWalletsIds().isNotEmpty() + } + } + private suspend fun getAllInternal(): CompletionResult> { return getUserWalletsIds() .map { userWalletId -> diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsPublicInformationRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsPublicInformationRepository.kt index 46a016f8c0..7d1bd9333b 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsPublicInformationRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsPublicInformationRepository.kt @@ -72,10 +72,6 @@ internal class DefaultUserWalletsPublicInformationRepository( } } - override fun isNotEmpty(): Boolean { - return secureStorage.get(StorageKey.UserWalletPublicInformation.name)?.isNotEmpty() == true - } - @JvmName("saveWithPublicInformation") private suspend fun save( publicInformation: List, 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 319071642c..a170aebdfd 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 @@ -278,9 +278,6 @@ class DetailsMiddleware { val userWallet = UserWalletBuilder(scanResponse).build() userWalletsListManager.save(userWallet) - .doOnFailure { error -> - Timber.e(error, "Wallet saving failed") - } .doOnSuccess { Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.On)) @@ -296,6 +293,9 @@ class DetailsMiddleware { store.onUserWalletSelected(userWallet) } + .doOnFailure { error -> + Timber.e(error, "Unable to save user wallet") + } } private suspend fun deleteSavedWallets() { @@ -315,6 +315,9 @@ class DetailsMiddleware { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home)) } + .doOnFailure { error -> + Timber.e(error, "Unable to delete saved wallets") + } } private fun saveAccessCodes(state: DetailsState) { @@ -353,6 +356,9 @@ class DetailsMiddleware { ) } } + .doOnFailure { error -> + Timber.e(error, "Unable to delete saved access codes") + } } } } \ No newline at end of file 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 d040111cdf..d6c2454283 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 @@ -12,7 +12,6 @@ import com.tangem.tap.domain.extensions.signedHashesCount import com.tangem.tap.preferencesStorage import com.tangem.tap.store import com.tangem.tap.tangemSdkManager -import com.tangem.tap.userWalletsListManager import org.rekotlin.Action import java.util.* @@ -58,7 +57,7 @@ private fun handlePrepareScreen( createBackupAllowed = action.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup, appCurrency = store.state.globalState.appCurrency, isBiometricsAvailable = tangemSdkManager.canUseBiometry, - saveWallets = userWalletsListManager.hasSavedUserWallets, + saveWallets = preferencesStorage.shouldSaveUserWallets, saveAccessCodes = preferencesStorage.shouldSaveAccessCodes, ) } From 4025b5536d6a3d8f59d8608cc737d3742ec5663c Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 27 Dec 2022 11:10:34 +0300 Subject: [PATCH 11/21] Updated on 2026-08-14 --- .../converters/BasicEventConverter.kt | 8 ++- .../common/feedback/AdditionalFeedbackInfo.kt | 4 +- .../com/tangem/tap/domain/model/UserWallet.kt | 20 ------ .../model/builders/UserWalletBuilder.kt | 23 +++--- .../model/builders/UserWalletIdBuilder.kt | 70 +++++++++++++++++++ .../tap/domain/tokens/UserTokensRepository.kt | 24 +++++-- .../BiometricUserWalletsListManager.kt | 4 +- .../model/UserWalletEncryptionKey.kt | 2 +- ...erWalletsSensitiveInformationRepository.kt | 2 +- .../utils/UserWalletEncyptionKeyCalculator.kt | 19 ++--- .../details/redux/DetailsMiddleware.kt | 32 ++++----- .../tap/features/home/redux/HomeMiddleware.kt | 2 +- .../twins/redux/TwinCardsMiddleware.kt | 4 +- .../saveWallet/redux/SaveWalletMiddleware.kt | 2 +- .../redux/WalletSelectorMiddleware.kt | 2 + .../welcome/redux/WelcomeMiddleware.kt | 2 +- .../tangem/tap/proxy/UserWalletManagerImpl.kt | 9 ++- .../tangem/domain/common/util/UserWalletId.kt | 16 +---- 18 files changed, 153 insertions(+), 92 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt rename domain/src/main/java/com/tangem/domain/common/util/CardExtensions.kt => app/src/main/java/com/tangem/tap/domain/userWalletList/utils/UserWalletEncyptionKeyCalculator.kt (55%) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt index 45d55aac2a..52fa450434 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt @@ -3,11 +3,11 @@ package com.tangem.tap.common.analytics.converters import com.tangem.common.Converter import com.tangem.common.extensions.isZero import com.tangem.domain.common.ScanResponse -import com.tangem.domain.common.util.userWalletId import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.filters.BasicTopUpFilter import com.tangem.tap.domain.extensions.isMultiwalletAllowed +import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletState @@ -29,7 +29,9 @@ class BasicSignInEventConverter( currency = cardCurrency, batch = scanResponse.card.batchId, ).apply { - filterData = scanResponse.card.userWalletId.stringValue + filterData = UserWalletIdBuilder.scanResponse(scanResponse) + .build() + ?.stringValue } } } @@ -43,7 +45,7 @@ class BasicTopUpEventConverter( val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null val data = BasicTopUpFilter.Data( - walletId = scanResponse.card.userWalletId.stringValue, + walletId = UserWalletIdBuilder.scanResponse(scanResponse).build()?.stringValue ?: "", cardBalanceState = AnalyticsParam.CardBalanceState.from(value.walletsDataFromStores), ) diff --git a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt index 16e1bb559a..589597238f 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt @@ -10,8 +10,8 @@ import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.common.address.Address import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ScanResponse -import com.tangem.domain.common.util.userWalletId import com.tangem.tap.common.extensions.stripZeroPlainString +import com.tangem.tap.domain.model.builders.UserWalletIdBuilder class AdditionalFeedbackInfo { class EmailWalletInfo( @@ -54,7 +54,7 @@ class AdditionalFeedbackInfo { cardFirmwareVersion = data.card.firmwareVersion.stringValue cardIssuer = data.card.issuer.name signedHashesCount = formatSignedHashes(data.card.wallets) - userWalletId = data.card.userWalletId.stringValue + userWalletId = UserWalletIdBuilder.scanResponse(data).build()?.stringValue ?: "" } fun setWalletsInfo(walletManagers: List) { diff --git a/app/src/main/java/com/tangem/tap/domain/model/UserWallet.kt b/app/src/main/java/com/tangem/tap/domain/model/UserWallet.kt index 4dec0df7d1..a76fbb9d1a 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/UserWallet.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/UserWallet.kt @@ -1,6 +1,5 @@ package com.tangem.tap.domain.model -import com.tangem.common.extensions.toHexString import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.util.UserWalletId @@ -33,23 +32,4 @@ data class UserWallet( val isLocked: Boolean get() = scanResponse.card.wallets.isEmpty() -} - -/** - * !!! Workaround !!! - * - * Calculate same [UserWalletId] for twins instead - * - * TODO: Remove after [REDACTED_JIRA] - * */ -fun UserWallet.isTwinnedWith(other: UserWallet): Boolean { - if (!scanResponse.isTangemTwins() || !other.scanResponse.isTangemTwins()) return false - if (scanResponse.secondTwinPublicKey == null || other.scanResponse.secondTwinPublicKey == null) return false - if (other.scanResponse.secondTwinPublicKey == scanResponse.card.wallets.firstOrNull()?.publicKey?.toHexString()) { - return true - } - if (scanResponse.secondTwinPublicKey == other.scanResponse.card.wallets.firstOrNull()?.publicKey?.toHexString()) { - return true - } - return false } \ No newline at end of file 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 ed8eb97623..9148486bc6 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 @@ -10,7 +10,6 @@ import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.TwinCardNumber import com.tangem.domain.common.TwinsHelper -import com.tangem.domain.common.util.userWalletId import com.tangem.operations.attestation.OnlineCardVerifier import com.tangem.operations.attestation.TangemApi import com.tangem.tap.domain.model.UserWallet @@ -60,16 +59,20 @@ class UserWalletBuilder( } } - suspend fun build(): UserWallet { + suspend fun build(): UserWallet? { return with(scanResponse) { - UserWallet( - walletId = card.userWalletId, - name = userWalletName, - artworkUrl = loadArtworkUrl(card.cardId, card.cardPublicKey), - cardsInWallet = backupCardsIds.plus(card.cardId), - scanResponse = this, - isMultiCurrency = isMultiCurrency, - ) + UserWalletIdBuilder.scanResponse(scanResponse) + .build() + ?.let { + UserWallet( + walletId = it, + name = userWalletName, + artworkUrl = loadArtworkUrl(card.cardId, card.cardPublicKey), + cardsInWallet = backupCardsIds.plus(card.cardId), + scanResponse = this, + isMultiCurrency = isMultiCurrency, + ) + } } } diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt new file mode 100644 index 0000000000..1fdef7c37c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletIdBuilder.kt @@ -0,0 +1,70 @@ +package com.tangem.tap.domain.model.builders + +import com.tangem.common.extensions.calculateSha256 +import com.tangem.common.extensions.hexToBytes +import com.tangem.crypto.Secp256k1 +import com.tangem.domain.common.CardDTO +import com.tangem.domain.common.ProductType +import com.tangem.domain.common.ScanResponse +import com.tangem.domain.common.TapWorkarounds.isTangemTwins +import com.tangem.domain.common.extensions.calculateHmacSha256 +import com.tangem.domain.common.util.UserWalletId + +class UserWalletIdBuilder private constructor( + private val publicKey: ByteArray?, + private val pairTwinPublicKey: ByteArray? = null, +) { + fun build(): UserWalletId? { + val seed = if (publicKey != null) { + if (pairTwinPublicKey != null) { + Secp256k1.sum(publicKey, pairTwinPublicKey) + } else { + publicKey + } + } else null + + return seed?.let { + UserWalletId(value = calculateUserWalletId(it)) + } + } + + private fun calculateUserWalletId(seed: ByteArray?): ByteArray? { + val message = MESSAGE_FOR_WALLET_ID.toByteArray() + val keyHash = seed?.calculateSha256() + + return if (keyHash != null) { + message.calculateHmacSha256(keyHash) + } else null + } + + companion object { + private const val MESSAGE_FOR_WALLET_ID = "UserWalletID" + + @Throws(IllegalArgumentException::class) + fun card(card: CardDTO): UserWalletIdBuilder { + require(!card.isTangemTwins) { + "For twin cards use scanResponse to ID calculation" + } + + return UserWalletIdBuilder(findPublicKey(card.wallets)) + } + + fun scanResponse(scanResponse: ScanResponse): UserWalletIdBuilder { + return UserWalletIdBuilder( + publicKey = findPublicKey(scanResponse.card.wallets), + pairTwinPublicKey = when (scanResponse.productType) { + ProductType.Twins -> scanResponse.secondTwinPublicKey?.hexToBytes() + ProductType.Note, + ProductType.Wallet, + ProductType.SaltPay, + -> null + }, + ) + } + + private fun findPublicKey(wallets: List): ByteArray? { + return wallets.firstOrNull() + ?.publicKey + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt index efd7dbefb9..88b71c052e 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt @@ -7,8 +7,8 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.api.tangemTech.TangemTechService import com.tangem.datasource.api.tangemTech.models.UserTokensResponse import com.tangem.domain.common.CardDTO -import com.tangem.domain.common.util.userWalletId import com.tangem.tap.common.AndroidFileReader +import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.domain.tokens.converters.CurrencyConverter import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.demo.DemoHelper @@ -29,7 +29,7 @@ class UserTokensRepository( // TODO("After adding DI") replace with CoroutineDispatcherProvider suspend fun getUserTokens(card: CardDTO): List = withContext(dispatchers.io) { - val userId = card.userWalletId.stringValue + val userId = getUserWalletId(card) ?: return emptyList() if (DemoHelper.isDemoCardId(card.cardId)) { return@withContext loadTokensOffline(card, userId).ifEmpty(::loadDemoCurrencies) } @@ -55,17 +55,22 @@ class UserTokensRepository( // TODO("After adding DI") replace with CoroutineDispatcherProvider suspend fun saveUserTokens(card: CardDTO, tokens: List) = withContext(dispatchers.io) { - val userId = card.userWalletId.stringValue + val userId = getUserWalletId(card) ?: return val userTokens = tokens.toUserTokensResponse() tangemTechApi.saveUserTokens(userId, userTokens) storageService.saveUserTokens(userId, userTokens) } + suspend fun removeUserTokens(card: CardDTO) { + val userId = getUserWalletId(card) ?: return + val userTokens = emptyList().toUserTokensResponse() + networkService.saveUserTokens(userId, userTokens) + storageService.saveUserTokens(userId, userTokens) + } + suspend fun loadBlockchainsToDerive(card: CardDTO): List = withContext(dispatchers.io) { - val blockchainNetworks = loadTokensOffline( - card = card, - userId = card.userWalletId.stringValue, - ).toBlockchainNetworks() + val userId = getUserWalletId(card) ?: return emptyList() + val blockchainNetworks = loadTokensOffline(card = card, userId = userId).toBlockchainNetworks() if (DemoHelper.isDemoCardId(card.cardId)) { return@withContext blockchainNetworks.ifEmpty(loadDemoCurrencies()::toBlockchainNetworks) @@ -109,6 +114,11 @@ class UserTokensRepository( } } + private fun getUserWalletId(card: CardDTO): String? { + return UserWalletIdBuilder.card(card).build() + ?.stringValue + } + companion object { private const val GROUP_DEFAULT_VALUE = "none" private const val SORT_DEFAULT_VALUE = "manual" diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt index fdd95f5f63..4eef3db4b7 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt @@ -3,7 +3,6 @@ package com.tangem.tap.domain.userWalletList.implementation import com.tangem.common.* import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.domain.model.UserWallet -import com.tangem.tap.domain.model.isTwinnedWith import com.tangem.tap.domain.userWalletList.UserWalletListError import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey @@ -89,8 +88,7 @@ internal class BiometricUserWalletsListManager( } else { val isWalletSaved = state.value.userWallets .any { - // Workaround, check [UserWallet.isTwinnedWith] - it.cardsInWallet.contains(userWallet.cardId) || it.isTwinnedWith(userWallet) + it.walletId == userWallet.walletId || it.cardsInWallet.contains(userWallet.cardId) } if (isWalletSaved) { diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletEncryptionKey.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletEncryptionKey.kt index cdf1edbdfb..a5c20a7790 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletEncryptionKey.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletEncryptionKey.kt @@ -2,8 +2,8 @@ package com.tangem.tap.domain.userWalletList.model import com.squareup.moshi.JsonClass import com.tangem.domain.common.util.UserWalletId -import com.tangem.domain.common.util.encryptionKey import com.tangem.tap.domain.model.UserWallet +import com.tangem.tap.domain.userWalletList.utils.encryptionKey @JsonClass(generateAdapter = true) internal data class UserWalletEncryptionKey( diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt index 5918312b6e..158dc0db2b 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt @@ -9,13 +9,13 @@ import com.tangem.common.catching import com.tangem.common.mapFailure import com.tangem.common.services.secure.SecureStorage import com.tangem.domain.common.util.UserWalletId -import com.tangem.domain.common.util.encryptionKey import com.tangem.tap.common.extensions.filterNotNull import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.userWalletList.UserWalletListError import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation import com.tangem.tap.domain.userWalletList.repository.UserWalletsSensitiveInformationRepository +import com.tangem.tap.domain.userWalletList.utils.encryptionKey import com.tangem.tap.domain.userWalletList.utils.sensitiveInformation import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/domain/src/main/java/com/tangem/domain/common/util/CardExtensions.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/UserWalletEncyptionKeyCalculator.kt similarity index 55% rename from domain/src/main/java/com/tangem/domain/common/util/CardExtensions.kt rename to app/src/main/java/com/tangem/tap/domain/userWalletList/utils/UserWalletEncyptionKeyCalculator.kt index 4dc70fd2bd..3ecfb70521 100644 --- a/domain/src/main/java/com/tangem/domain/common/util/CardExtensions.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/UserWalletEncyptionKeyCalculator.kt @@ -1,24 +1,27 @@ -package com.tangem.domain.common.util +package com.tangem.tap.domain.userWalletList.utils import com.tangem.common.extensions.calculateSha256 import com.tangem.domain.common.CardDTO import com.tangem.domain.common.extensions.calculateHmacSha256 -val CardDTO.userWalletId: UserWalletId - get() = UserWalletId(findWalletPublicKey(wallets)) +internal val CardDTO.encryptionKey: ByteArray + @Throws(IllegalArgumentException::class) + get() { + val walletPublicKey = requireNotNull(findPublicKey(wallets)) { + "Wallet public key must not be null" + } -val CardDTO.encryptionKey: ByteArray - get() = findWalletPublicKey(wallets) - ?.let { calculateEncryptionKey(it) } - ?: error("Wallet ID not found") + return calculateEncryptionKey(walletPublicKey) + } private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray { val message = MESSAGE_FOR_ENCRYPTION_KEY.toByteArray() val keyHash = publicKey.calculateSha256() + return message.calculateHmacSha256(keyHash) } -private fun findWalletPublicKey(wallets: List): ByteArray? { +private fun findPublicKey(wallets: List): ByteArray? { return wallets.firstOrNull() ?.publicKey } 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 a170aebdfd..9fe984d9c9 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 @@ -4,10 +4,8 @@ import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess -import com.tangem.common.extensions.toHexString import com.tangem.common.flatMap import com.tangem.domain.common.TapWorkarounds.isTangemTwins -import com.tangem.domain.common.util.userWalletId import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Settings @@ -20,6 +18,7 @@ import com.tangem.tap.common.redux.global.GlobalAction 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.domain.model.builders.UserWalletIdBuilder 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 @@ -27,6 +26,7 @@ import com.tangem.tap.preferencesStorage import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager +import com.tangem.tap.userTokensRepository import com.tangem.tap.userWalletsListManager import com.tangem.tap.walletStoresManager import com.tangem.wallet.R @@ -79,20 +79,16 @@ class DetailsMiddleware { } DetailsAction.ScanCard -> { scope.launch { - tangemSdkManager.scanCard(allowRequestAccessCodeFromRepository = true) - .doOnSuccess { card -> - val isSameWallet = state.scanResponse?.card?.userWalletId - ?.equals(card.userWalletId) - ?: false + tangemSdkManager.scanProduct(userTokensRepository) + .doOnSuccess { scanResponse -> + val currentUserWalletId = state.scanResponse + ?.let { UserWalletIdBuilder.scanResponse(it).build() } + val scannedUserWalletId = UserWalletIdBuilder.scanResponse(scanResponse) + .build() + val isSameWallet = currentUserWalletId == scannedUserWalletId - // !!! Workaround !!! - // TODO: Remove after [REDACTED_JIRA] - val isTwinned = card.wallets.firstOrNull()?.publicKey?.toHexString() - ?.equals(state.scanResponse?.secondTwinPublicKey) - ?: false - - if (isSameWallet || isTwinned) { - store.dispatchOnMain(DetailsAction.PrepareCardSettingsData(card)) + if (isSameWallet) { + store.dispatchOnMain(DetailsAction.PrepareCardSettingsData(scanResponse.card)) } else { store.dispatchDialogShow( AppDialog.SimpleOkDialogRes( @@ -122,8 +118,10 @@ class DetailsMiddleware { is DetailsAction.ResetToFactory.Proceed -> { val card = store.state.detailsState.cardSettingsState?.card ?: return scope.launch { + val userWalletId = UserWalletIdBuilder.card(card).build() + tangemSdkManager.resetToFactorySettings(card.cardId) - .flatMap { userWalletsListManager.delete(listOf(card.userWalletId)) } + .flatMap { userWalletsListManager.delete(listOfNotNull(userWalletId)) } .flatMap { tangemSdkManager.deleteSavedUserCodes(setOf(card.cardId)) } .doOnSuccess { Analytics.send(Settings.CardSettings.FactoryResetFinished()) @@ -275,7 +273,7 @@ class DetailsMiddleware { private suspend fun saveCurrentWallet(state: DetailsState) { val scanResponse = state.scanResponse ?: return - val userWallet = UserWalletBuilder(scanResponse).build() + val userWallet = UserWalletBuilder(scanResponse).build() ?: return userWalletsListManager.save(userWallet) .doOnSuccess { 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 0c5b990b06..fdacaa5bd1 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 @@ -93,7 +93,7 @@ private fun readCard() = scope.launch { onSuccess = { scanResponse -> scope.launch { if (preferencesStorage.shouldSaveUserWallets) { - val userWallet = UserWalletBuilder(scanResponse).build() + val userWallet = UserWalletBuilder(scanResponse).build() ?: return@launch userWalletsListManager.save(userWallet) .doOnFailure { error -> Timber.e(error, "Unable to save user wallet") 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 bc94264e05..1a5b2840d3 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 @@ -6,7 +6,6 @@ import com.tangem.common.CompletionResult import com.tangem.common.extensions.guard import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.extensions.withMainContext -import com.tangem.domain.common.util.userWalletId import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -25,6 +24,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.makePrimaryWalletManager +import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.domain.twins.TwinCardsManager import com.tangem.tap.features.onboarding.OnboardingHelper import com.tangem.tap.features.wallet.models.Currency @@ -156,7 +156,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { TwinCardsStep.CreateFirstWallet -> { scope.launch { userWalletsListManager.delete( - listOf(getScanResponse().card.userWalletId), + listOfNotNull(UserWalletIdBuilder.scanResponse(getScanResponse()).build()), ) } } 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 106ebfa9af..60bc2e076e 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 @@ -88,7 +88,7 @@ internal class SaveWalletMiddleware { scope.launch { val userWallet = UserWalletBuilder(scanResponse) .backupCardsIds(state.backupInfo?.backupCardsIds) - .build() + .build() ?: return@launch val isFirstSavedWallet = !userWalletsListManager.hasSavedUserWallets 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 cc6642743f..c1f24294f4 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 @@ -1,6 +1,7 @@ package com.tangem.tap.features.walletSelector.redux import com.tangem.common.CompletionResult +import com.tangem.common.core.TangemSdkError import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.common.flatMap @@ -162,6 +163,7 @@ internal class WalletSelectorMiddleware { private suspend fun saveUserWalletAndPopBackToWalletScreen(scanResponse: ScanResponse): CompletionResult { val userWallet = UserWalletBuilder(scanResponse).build() + ?: return CompletionResult.Failure(TangemSdkError.WalletIsNotCreated()) return userWalletsListManager.save(userWallet) .doOnSuccess { 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 7b0f37e36e..e7cb2e01e7 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 @@ -71,7 +71,7 @@ internal class WelcomeMiddleware { private fun proceedWithCard(state: WelcomeState) = scope.launch { scanCardInternal { scanResponse -> - val userWallet = UserWalletBuilder(scanResponse).build() + val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal userWalletsListManager.save(userWallet, canOverride = true) .doOnFailure { error -> diff --git a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt index 5d53a5dadd..926eeb68b5 100644 --- a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt @@ -8,12 +8,12 @@ import com.tangem.domain.common.CardDTO 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.util.userWalletId import com.tangem.lib.crypto.UserWalletManager import com.tangem.lib.crypto.models.Currency import com.tangem.lib.crypto.models.Currency.NativeToken import com.tangem.lib.crypto.models.Currency.NonNativeToken import com.tangem.tap.domain.extensions.makeWalletManagerForApp +import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.redux.WalletAction import org.rekotlin.Action @@ -54,7 +54,12 @@ class UserWalletManagerImpl( } override fun getWalletId(): String { - return appStateHolder.getActualCard()?.userWalletId?.stringValue ?: "" + return appStateHolder.getActualCard()?.let { + UserWalletIdBuilder.card(it) + .build() + ?.stringValue + } + ?: "" } override suspend fun isTokenAdded(currency: Currency): Boolean { diff --git a/domain/src/main/java/com/tangem/domain/common/util/UserWalletId.kt b/domain/src/main/java/com/tangem/domain/common/util/UserWalletId.kt index 4e83c913ca..abf878da69 100644 --- a/domain/src/main/java/com/tangem/domain/common/util/UserWalletId.kt +++ b/domain/src/main/java/com/tangem/domain/common/util/UserWalletId.kt @@ -1,17 +1,15 @@ package com.tangem.domain.common.util -import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString -import com.tangem.domain.common.extensions.calculateHmacSha256 class UserWalletId( val stringValue: String, ) { val value = stringValue.hexToBytes() - constructor(walletPublicKey: ByteArray?) : this( - stringValue = walletPublicKey?.let { calculateUserWalletId(it).toHexString() } ?: "", + constructor(value: ByteArray?) : this( + stringValue = value?.toHexString() ?: "", ) override fun equals(other: Any?): Boolean { @@ -32,12 +30,4 @@ class UserWalletId( "UserWalletId(${take(3)}...${takeLast(3)})" } } -} - -private fun calculateUserWalletId(publicKey: ByteArray): ByteArray { - val message = MESSAGE_FOR_WALLET_ID.toByteArray() - val keyHash = publicKey.calculateSha256() - return message.calculateHmacSha256(keyHash) -} - -private const val MESSAGE_FOR_WALLET_ID = "UserWalletID" \ No newline at end of file +} \ No newline at end of file From 696eea5fb6461644533f6def26b3e376aa7fd9ce Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 27 Dec 2022 11:10:51 +0300 Subject: [PATCH 12/21] Updated on 2026-08-14 --- buildSrc/src/main/java/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Versions.kt b/buildSrc/src/main/java/Versions.kt index 524e5e5277..2f14017e3e 100644 --- a/buildSrc/src/main/java/Versions.kt +++ b/buildSrc/src/main/java/Versions.kt @@ -63,7 +63,7 @@ object Versions { const val tangemBlockchainSdk = "develop-142" // const val tangemBlockchainSdk = "0.0.1" - const val tangemCardSgk = "develop-178" + const val tangemCardSgk = "develop-179" // endregion Tangem // region Testing From f65b631c3aabd389522e60cee51173603fedbbb6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 29 Dec 2022 14:00:54 +0300 Subject: [PATCH 13/21] Updated on 2026-08-14 --- .../userWalletList/UserWalletsListManager.kt | 13 +++- .../BiometricUserWalletsListManager.kt | 71 ++++++++++++++----- .../DummyUserWalletsListManager.kt | 56 --------------- .../model/UserWalletEncryptionKey.kt | 7 -- .../repository/UserWalletsKeysRepository.kt | 6 +- ...erWalletsSensitiveInformationRepository.kt | 2 +- .../BiometricUserWalletsKeysRepository.kt | 5 +- ...erWalletsSensitiveInformationRepository.kt | 5 +- .../utils/UserWalletEncyptionKeyCalculator.kt | 11 +-- .../features/tokens/redux/TokensMiddleware.kt | 15 ++-- .../middlewares/MultiWalletMiddleware.kt | 19 ++--- .../redux/WalletSelectorMiddleware.kt | 4 +- .../ui/WalletSelectorViewModel.kt | 20 ++---- 13 files changed, 104 insertions(+), 130 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/DummyUserWalletsListManager.kt diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt index dfd62c05f5..9e7619e7c5 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt @@ -19,7 +19,7 @@ interface UserWalletsListManager { suspend fun selectWallet(userWalletId: UserWalletId): CompletionResult /** - * Save user wallet + * Save provided user wallet and set it as selected * @param userWallet [UserWallet] to save * @param canOverride If false, then terminate with [UserWalletListError.WalletAlreadySaved] when user tries to save an * already saved card @@ -27,6 +27,17 @@ interface UserWalletsListManager { * */ suspend fun save(userWallet: UserWallet, canOverride: Boolean = false): CompletionResult + /** + * Same as [save] but not change selected user wallet ID + * and not terminate with [UserWalletListError.WalletAlreadySaved] if [UserWallet] already saved + * + * Can terminate with [NoSuchElementException] if unable to find [UserWallet] with provided [UserWalletId] + * @param userWalletId update [UserWallet] with that [UserWalletId] + * @param update lambda that receives stored [UserWallet] and returns updated [UserWallet] + * @return [CompletionResult] of operation with updated [UserWallet] + * */ + suspend fun update(userWalletId: UserWalletId, update: (UserWallet) -> UserWallet): CompletionResult + suspend fun delete(userWalletIds: List): CompletionResult suspend fun clear(): CompletionResult diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt index 4eef3db4b7..db1db2ebbd 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt @@ -10,6 +10,7 @@ import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletReposit import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository import com.tangem.tap.domain.userWalletList.repository.UserWalletsPublicInformationRepository import com.tangem.tap.domain.userWalletList.repository.UserWalletsSensitiveInformationRepository +import com.tangem.tap.domain.userWalletList.utils.encryptionKey import com.tangem.tap.domain.userWalletList.utils.toUserWallets import com.tangem.tap.domain.userWalletList.utils.updateWith import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -84,7 +85,7 @@ internal class BiometricUserWalletsListManager( override suspend fun save(userWallet: UserWallet, canOverride: Boolean): CompletionResult { return if (canOverride) { - saveInternal(userWallet) + saveInternal(userWallet, changeSelectedUserWallet = true) } else { val isWalletSaved = state.value.userWallets .any { @@ -94,11 +95,25 @@ internal class BiometricUserWalletsListManager( if (isWalletSaved) { CompletionResult.Failure(UserWalletListError.WalletAlreadySaved) } else { - saveInternal(userWallet) + saveInternal(userWallet, changeSelectedUserWallet = true) } } } + override suspend fun update( + userWalletId: UserWalletId, + update: (UserWallet) -> UserWallet, + ): CompletionResult { + return get(userWalletId) + .map { storedUserWallet -> + update(storedUserWallet) + } + .flatMap { updatedUserWallet -> + saveInternal(updatedUserWallet, changeSelectedUserWallet = false) + .map { updatedUserWallet } + } + } + override suspend fun delete(userWalletIds: List): CompletionResult { if (userWalletIds.isEmpty()) { return CompletionResult.Success(Unit) @@ -111,9 +126,12 @@ internal class BiometricUserWalletsListManager( .flatMap { keysRepository.delete(userWalletIds) } .map { state.update { prevState -> + val newUserWallets = prevState.userWallets.filter { it.walletId !in userWalletIds } + prevState.copy( encryptionKeys = prevState.encryptionKeys.filter { it.walletId !in userWalletIds }, - userWallets = prevState.userWallets.filter { it.walletId !in userWalletIds }, + userWallets = newUserWallets, + isLocked = newUserWallets.any { it.isLocked }, ) } } @@ -135,27 +153,23 @@ internal class BiometricUserWalletsListManager( } } - private suspend fun saveInternal(userWallet: UserWallet): CompletionResult { - val newEncryptionKeys = state.value.encryptionKeys - .plus(UserWalletEncryptionKey(userWallet)) - .distinctBy { it.walletId } - - return keysRepository.store(newEncryptionKeys) - .doOnSuccess { - state.update { prevState -> - prevState.copy( - encryptionKeys = newEncryptionKeys, - selectedUserWalletId = userWallet.walletId, - ) - } - } + private suspend fun saveInternal( + userWallet: UserWallet, + changeSelectedUserWallet: Boolean, + ): CompletionResult { + return saveEncryptionKeyIfNotNull(userWallet) + .flatMap { sensitiveInformationRepository.save(userWallet, encryptionKey = it) } .flatMap { publicInformationRepository.save(userWallet) } - .flatMap { sensitiveInformationRepository.save(userWallet) } .map { selectedUserWalletRepository.set(userWallet.walletId) } .flatMap { loadModels() } .doOnSuccess { state.update { prevState -> prevState.copy( + selectedUserWalletId = if (changeSelectedUserWallet) { + userWallet.walletId + } else { + prevState.selectedUserWalletId + }, isLocked = prevState.userWallets.any { it.isLocked }, ) } @@ -181,6 +195,27 @@ internal class BiometricUserWalletsListManager( } } + private suspend fun saveEncryptionKeyIfNotNull(userWallet: UserWallet): CompletionResult { + val encryptionKey = userWallet.scanResponse.card.encryptionKey + ?.let { UserWalletEncryptionKey(userWallet.walletId, it) } + + return if (encryptionKey != null) { + keysRepository.save(encryptionKey) + .doOnSuccess { + state.update { prevState -> + prevState.copy( + encryptionKeys = prevState.encryptionKeys + .plus(encryptionKey) + .distinctBy { it.walletId }, + ) + } + } + .map { encryptionKey.encryptionKey } + } else { + CompletionResult.Success(data = null) + } + } + private suspend fun loadModels(): CompletionResult { return getSavedUserWallets() .map { userWallets -> diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/DummyUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/DummyUserWalletsListManager.kt deleted file mode 100644 index e616c48758..0000000000 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/DummyUserWalletsListManager.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.tangem.tap.domain.userWalletList.implementation - -import com.tangem.common.CompletionResult -import com.tangem.common.catching -import com.tangem.domain.common.util.UserWalletId -import com.tangem.tap.domain.model.UserWallet -import com.tangem.tap.domain.userWalletList.UserWalletsListManager -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf - -class DummyUserWalletsListManager : UserWalletsListManager { - override val userWallets: Flow> - get() = flowOf(emptyList()) - override val selectedUserWallet: Flow - get() = flowOf() - override val selectedUserWalletSync: UserWallet? - get() = null - override val isLocked: Flow - get() = flowOf(true) - override val isLockedSync: Boolean - get() = true - override val hasSavedUserWallets: Boolean - get() = false - - override suspend fun unlockWithBiometry(): CompletionResult { - return CompletionResult.Success(null) - } - - override fun lock() { - /* no-op */ - } - - override suspend fun selectWallet(userWalletId: UserWalletId): CompletionResult { - return catching { - error("Not implemented") - } - } - - override suspend fun save(userWallet: UserWallet, canOverride: Boolean): CompletionResult { - return CompletionResult.Success(Unit) - } - - override suspend fun delete(userWalletIds: List): CompletionResult { - return CompletionResult.Success(Unit) - } - - override suspend fun clear(): CompletionResult { - return CompletionResult.Success(Unit) - } - - override suspend fun get(userWalletId: UserWalletId): CompletionResult { - return catching { - error("Not implemented") - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletEncryptionKey.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletEncryptionKey.kt index a5c20a7790..df0f473bae 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletEncryptionKey.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/model/UserWalletEncryptionKey.kt @@ -2,19 +2,12 @@ package com.tangem.tap.domain.userWalletList.model import com.squareup.moshi.JsonClass import com.tangem.domain.common.util.UserWalletId -import com.tangem.tap.domain.model.UserWallet -import com.tangem.tap.domain.userWalletList.utils.encryptionKey @JsonClass(generateAdapter = true) internal data class UserWalletEncryptionKey( val walletId: UserWalletId, val encryptionKey: ByteArray, ) { - constructor(userWallet: UserWallet) : this( - walletId = userWallet.walletId, - encryptionKey = userWallet.scanResponse.card.encryptionKey, - ) - override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is UserWalletEncryptionKey) return false diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsKeysRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsKeysRepository.kt index bf96081cd4..99b62dc99d 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsKeysRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsKeysRepository.kt @@ -14,11 +14,11 @@ internal interface UserWalletsKeysRepository { suspend fun getAll(): CompletionResult> /** - * Store the encryption keys for user wallets. Biometric authentication not required - * @param encryptionKeys List of encryption keys for user wallets + * Save the encryption key for user wallet. Biometric authentication not required + * @param encryptionKey [UserWalletEncryptionKey] to save * @return [CompletionResult] of operation * */ - suspend fun store(encryptionKeys: List): CompletionResult + suspend fun save(encryptionKey: UserWalletEncryptionKey): CompletionResult /** * Delete encryption keys for user wallets. Biometric authentication not required diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsSensitiveInformationRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsSensitiveInformationRepository.kt index 7e03055150..fdae3e64a0 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsSensitiveInformationRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/UserWalletsSensitiveInformationRepository.kt @@ -7,7 +7,7 @@ import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation internal interface UserWalletsSensitiveInformationRepository { - suspend fun save(userWallet: UserWallet): CompletionResult + suspend fun save(userWallet: UserWallet, encryptionKey: ByteArray?): CompletionResult suspend fun getAll( encryptionKeys: List, ): CompletionResult> diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt index 8de5a59457..11e558535d 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt @@ -45,10 +45,9 @@ internal class BiometricUserWalletsKeysRepository( } } - override suspend fun store(encryptionKeys: List): CompletionResult { + override suspend fun save(encryptionKey: UserWalletEncryptionKey): CompletionResult { return withContext(Dispatchers.IO) { - encryptionKeys.map { storeEncryptionKey(it) } - .fold() + storeEncryptionKey(encryptionKey) .mapFailure { error -> UserWalletListError.SaveEncryptionKeysError(error.cause ?: error) } diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt index 158dc0db2b..673ec51a10 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt @@ -38,11 +38,12 @@ internal class DefaultUserWalletsSensitiveInformationRepository( Cipher.getInstance("$algorithm/$blockMode/$encryptionPadding") } - override suspend fun save(userWallet: UserWallet): CompletionResult { + override suspend fun save(userWallet: UserWallet, encryptionKey: ByteArray?): CompletionResult { + if (encryptionKey == null) return CompletionResult.Success(Unit) // Encryption key is null, do nothing return catching { val encryptedSensitiveInformation = userWallet.sensitiveInformation .encode() - .encryptAndStoreIv(userWallet.walletId.stringValue, userWallet.scanResponse.card.encryptionKey) + .encryptAndStoreIv(userWallet.walletId.stringValue, encryptionKey) getAllEncrypted().toMutableMap() .apply { set(userWallet.walletId.stringValue, encryptedSensitiveInformation) } diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/UserWalletEncyptionKeyCalculator.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/UserWalletEncyptionKeyCalculator.kt index 3ecfb70521..d97af026cc 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/UserWalletEncyptionKeyCalculator.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/utils/UserWalletEncyptionKeyCalculator.kt @@ -4,15 +4,8 @@ import com.tangem.common.extensions.calculateSha256 import com.tangem.domain.common.CardDTO import com.tangem.domain.common.extensions.calculateHmacSha256 -internal val CardDTO.encryptionKey: ByteArray - @Throws(IllegalArgumentException::class) - get() { - val walletPublicKey = requireNotNull(findPublicKey(wallets)) { - "Wallet public key must not be null" - } - - return calculateEncryptionKey(walletPublicKey) - } +internal val CardDTO.encryptionKey: ByteArray? + get() = findPublicKey(wallets)?.let { calculateEncryptionKey(it) } private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray { val message = MESSAGE_FOR_ENCRYPTION_KEY.toByteArray() diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index b07a4fd3ca..10a7d4e03a 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -281,13 +281,16 @@ class TokensMiddleware { ) { val selectedUserWallet = userWalletsListManager.selectedUserWalletSync if (selectedUserWallet != null) { - val updatedUserWallet = selectedUserWallet.copy( - scanResponse = scanResponse, - ) - scope.launch { - userWalletsListManager.save(updatedUserWallet, canOverride = true) - .flatMap { + userWalletsListManager.update( + userWalletId = selectedUserWallet.walletId, + update = { userWallet -> + userWallet.copy( + scanResponse = scanResponse, + ) + }, + ) + .flatMap { updatedUserWallet -> walletCurrenciesManager.addCurrencies( userWallet = updatedUserWallet, currenciesToAdd = currencyList, 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 44f184a4c1..9f587757a7 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 @@ -180,21 +180,24 @@ class MultiWalletMiddleware { } private fun scanAndUpdateCard( - selectedWallet: UserWallet, + selectedUserWallet: UserWallet, state: WalletState?, ) = scope.launch { Analytics.send(MainScreen.CardWasScanned()) ScanCardProcessor.scan( - cardId = selectedWallet.cardId, + cardId = selectedUserWallet.cardId, additionalBlockchainsToDerive = state?.missingDerivations?.map { it.blockchain }, ) { scanResponse -> - val userWallet = selectedWallet.copy( - scanResponse = scanResponse, + userWalletsListManager.update( + userWalletId = selectedUserWallet.walletId, + update = { userWallet -> + userWallet.copy( + scanResponse = scanResponse, + ) + }, ) - - userWalletsListManager.save(userWallet, canOverride = true) - .doOnSuccess { - store.state.globalState.tapWalletManager.loadData(userWallet, refresh = true) + .doOnSuccess { updatedUserWallet -> + store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true) } } } 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 c1f24294f4..4772b501d7 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 @@ -239,9 +239,7 @@ internal class WalletSelectorMiddleware { Analytics.send(MyWallets.Button.EditWalletTapped) scope.launch { - userWalletsListManager.get(userWalletId) - .map { it.copy(name = newName) } - .flatMap { userWalletsListManager.save(it, canOverride = true) } + userWalletsListManager.update(userWalletId) { it.copy(name = newName) } .doOnFailure { error -> store.dispatchOnMain(WalletSelectorAction.HandleError(error)) } diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt index 1192b37c4a..52a99013e3 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt @@ -38,7 +38,6 @@ internal class WalletSelectorViewModel : ViewModel(), StoreSubscriber Unit editingUserWalletsIds.isNotEmpty() && !editingUserWalletsIds.contains(userWalletId) -> { editWallet(userWalletId) } @@ -52,7 +51,7 @@ internal class WalletSelectorViewModel : ViewModel(), StoreSubscriber - store.dispatch(WalletSelectorAction.RenameWallet(editedWalletId, newName)) + store.dispatch(WalletSelectorAction.RenameWallet(editedUserWalletId, newName)) stateInternal.update { prevState -> prevState.copy( renameWalletDialog = null, @@ -137,11 +136,6 @@ internal class WalletSelectorViewModel : ViewModel(), StoreSubscriber appState.skip { old, new -> old.walletSelectorState == new.walletSelectorState } From 369f3aaa9bb2321f8de6860988b02db4d1912480 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Dec 2022 21:19:13 +0300 Subject: [PATCH 14/21] Updated on 2026-08-14 --- .../DefaultWalletCurrenciesManager.kt | 11 +- .../repository/WalletAmountsRepository.kt | 6 + .../DefaultWalletAmountsRepository.kt | 165 ++++++++++-------- .../utils/WalletStoreOperations.kt | 6 +- .../middlewares/MultiWalletMiddleware.kt | 4 +- 5 files changed, 117 insertions(+), 75 deletions(-) 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 5fd2e25234..e000fe1c6d 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 @@ -20,6 +20,7 @@ import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.toBlockchainNetworks import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.withContext internal class DefaultWalletCurrenciesManager( @@ -64,7 +65,15 @@ internal class DefaultWalletCurrenciesManager( saveUserCurrencies(card, newCurrencies) } .flatMap { - walletAmountsRepository.updateAmountsForUserWallet( + val updatedBlockchains = updatedBlockchainNetworks + .map { it.blockchain } + val updatedWalletStores = walletStoresRepository.get(userWallet.walletId) + .firstOrNull() + ?.filter { it.blockchain in updatedBlockchains } + ?: return@flatMap CompletionResult.Success(Unit) + + walletAmountsRepository.updateAmountsForWalletStores( + walletStores = updatedWalletStores, userWallet = userWallet, fiatCurrency = appCurrencyProvider(), ) diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletAmountsRepository.kt index 0af5b8f85e..a054ed0ff2 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/WalletAmountsRepository.kt @@ -29,6 +29,12 @@ interface WalletAmountsRepository { fiatCurrency: FiatCurrency, ): CompletionResult + suspend fun updateAmountsForWalletStores( + walletStores: List, + userWallet: UserWallet, + fiatCurrency: FiatCurrency, + ): CompletionResult + /** * Fetch wallet amounts and fiat rates then update [com.tangem.tap.domain.walletStores.storage.WalletStoresStorage] * and [com.tangem.tap.domain.walletStores.storage.WalletManagerStorage] with new data diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index 5a59ae8c30..9496866746 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -42,7 +42,8 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.withContext import timber.log.Timber import java.math.BigDecimal @@ -62,7 +63,7 @@ internal class DefaultWalletAmountsRepository( else withContext(Dispatchers.Default) { awaitAll( async { fetchAmountsForUserWallets(userWallets) }, - async { fetchFiatRates(userWallets, fiatCurrency) }, + async { fetchFiatRates(userWallets, walletStores = null, fiatCurrency) }, ) .fold() } @@ -75,46 +76,40 @@ internal class DefaultWalletAmountsRepository( return updateAmountsForUserWallets(listOf(userWallet), fiatCurrency) } + override suspend fun updateAmountsForWalletStores( + walletStores: List, + userWallet: UserWallet, + fiatCurrency: FiatCurrency, + ): CompletionResult { + return if (walletStores.isEmpty()) CompletionResult.Success(Unit) + else withContext(Dispatchers.Default) { + val userWalletId = userWallet.walletId + val scanResponse = userWallet.scanResponse + + awaitAll( + async { fetchAmountForWalletStores(userWalletId, scanResponse, walletStores) }, + async { fetchFiatRates(listOf(userWallet), walletStores, fiatCurrency) }, + ) + .fold() + } + } + override suspend fun updateAmountsForWalletStore( walletStore: WalletStoreModel, userWallet: UserWallet, fiatCurrency: FiatCurrency, - ): CompletionResult = withContext(Dispatchers.Default) { - val walletId = userWallet.walletId - val scanResponse = userWallet.scanResponse - - awaitAll( - async { - // TODO: Find wallet manager via [com.tangem.tap.domain.walletStores.repository.WalletManagersRepository] - val walletManager = walletStore.walletManager - fetchAmountsForWalletStore(walletId, scanResponse, walletStore, walletManager) - }, - async { fetchFiatRates(listOf(userWallet), fiatCurrency) }, - ) - .fold() - } - - private suspend fun fetchAmountsForUserWallets( - userWallets: List, - ): CompletionResult = withContext(Dispatchers.Default) { - userWallets.map { async { fetchAmountsForUserWallet(it) } } - .awaitAll() - .fold() + ): CompletionResult { + return updateAmountsForWalletStores(listOf(walletStore), userWallet, fiatCurrency) } private suspend fun fetchFiatRates( userWallets: List, + walletStores: List?, fiatCurrency: FiatCurrency, ): CompletionResult { - val walletsIds = userWallets.map { it.walletId } - val walletStores = walletsIds - .flatMap { - walletStoresStorage.getAll() - .first() - .getOrElse(it) { emptyList() } - } + val walletStoresInternal = walletStores ?: getWalletStores(userWallets) - val currencies = walletStores + val currencies = walletStoresInternal .asSequence() .flatMap { it.walletsData } .map { it.currency } @@ -124,7 +119,7 @@ internal class DefaultWalletAmountsRepository( return withContext(dispatchers.io) { runCatching { tangemTechApi.getRates(fiatCurrency.code.lowercase(), coinsIds.joinToString(",")) } .onSuccess { - updateWalletStoresWithFiatRates(walletStores = walletStores, fiatRates = it.rates) + updateWalletStoresWithFiatRates(walletStores = walletStoresInternal, fiatRates = it.rates) return@withContext CompletionResult.Success(Unit) } .onFailure { @@ -137,7 +132,6 @@ internal class DefaultWalletAmountsRepository( error, """ Unable to fetch fiat rates - |- User wallets ids: $walletsIds |- Coins ids: $coinsIds """.trimIndent(), ) @@ -169,20 +163,34 @@ internal class DefaultWalletAmountsRepository( .fold() } + private suspend fun fetchAmountsForUserWallets( + userWallets: List, + ): CompletionResult = withContext(Dispatchers.Default) { + userWallets.map { async { fetchAmountsForUserWallet(it) } } + .awaitAll() + .fold() + } + private suspend fun fetchAmountsForUserWallet( userWallet: UserWallet, ): CompletionResult = withContext(Dispatchers.Default) { - val walletId = userWallet.walletId + val userWalletId = userWallet.walletId val scanResponse = userWallet.scanResponse - val walletStores = walletStoresStorage.getAll() - .first() - .getOrElse(walletId) { emptyList() } + val walletStores = getWalletStores(listOf(userWallet)) + fetchAmountForWalletStores(userWalletId, scanResponse, walletStores) + } + + private suspend fun fetchAmountForWalletStores( + userWalletId: UserWalletId, + scanResponse: ScanResponse, + walletStores: List, + ): CompletionResult = coroutineScope { walletStores.map { walletStore -> async { // TODO: Find wallet manager via [com.tangem.tap.domain.walletStores.repository.WalletManagersRepository] val walletManager = walletStore.walletManager - fetchAmountsForWalletStore(walletId, scanResponse, walletStore, walletManager) + fetchAmountsForWalletStore(userWalletId, scanResponse, walletStore, walletManager) } } .awaitAll() @@ -190,7 +198,7 @@ internal class DefaultWalletAmountsRepository( } private suspend fun fetchAmountsForWalletStore( - walletId: UserWalletId, + userWalletId: UserWalletId, scanResponse: ScanResponse, walletStore: WalletStoreModel, walletManager: WalletManager?, @@ -200,11 +208,15 @@ internal class DefaultWalletAmountsRepository( } return when { - hasMissedDerivations -> updateWalletStoreWithMissedDerivation(walletStore) - walletManager == null -> updateWalletStoreWithUnreachable(walletStore) + hasMissedDerivations -> { + updateWalletStoreWithMissedDerivation(walletStore) + } + walletManager == null -> { + updateWalletStoreWithUnreachable(walletStore) + } else -> { withInternetConnection { walletManager.update() } - .map { updateWalletManagerWithAmounts(walletId, walletManager) } + .map { updateWalletManagerWithAmounts(userWalletId, walletManager) } .flatMap { updateWalletStoreWithAmounts( walletStore = walletStore, @@ -262,35 +274,6 @@ internal class DefaultWalletAmountsRepository( return CompletionResult.Success(Unit) } - private suspend inline fun withInternetConnection(crossinline block: suspend () -> Unit): CompletionResult { - return if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) { - val error = WalletStoresError.NoInternetConnection - Timber.e(error) - CompletionResult.Failure(error) - } else withContext(Dispatchers.IO) { - catching { block() } - } - } - - private suspend fun updateWalletManagerWithAmounts( - walletId: UserWalletId, - walletManager: WalletManager, - ) = withContext(Dispatchers.Default) { - walletManagersStorage.update { prevManagers -> - val newManagersForUserWallet = prevManagers[walletId].orEmpty() - .toMutableList() - .apply { - replaceByOrAdd(walletManager) { - it.wallet.blockchain == it.wallet.blockchain - } - } - - prevManagers.apply { - set(walletId, newManagersForUserWallet) - } - } - } - private suspend fun updateWalletStoreWithError( walletStore: WalletStoreModel, wallet: Wallet, @@ -439,4 +422,44 @@ internal class DefaultWalletAmountsRepository( } } } + + private suspend inline fun withInternetConnection(crossinline block: suspend () -> Unit): CompletionResult { + return if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) { + val error = WalletStoresError.NoInternetConnection + Timber.e(error) + CompletionResult.Failure(error) + } else withContext(Dispatchers.IO) { + catching { block() } + } + } + + private suspend fun updateWalletManagerWithAmounts( + userWalletId: UserWalletId, + walletManager: WalletManager, + ) = withContext(Dispatchers.Default) { + walletManagersStorage.update { prevManagers -> + val newManagersForUserWallet = prevManagers[userWalletId].orEmpty() + .toMutableList() + .apply { + replaceByOrAdd(walletManager) { + it.wallet.blockchain == it.wallet.blockchain + } + } + + prevManagers.apply { + set(userWalletId, newManagersForUserWallet) + } + } + } + + private suspend fun getWalletStores(userWallets: List): List { + return userWallets + .map { it.walletId } + .flatMap { userWalletId -> + walletStoresStorage.getAll() + .firstOrNull() + ?.get(userWalletId) + .orEmpty() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt index 445ff655f2..2aa7ffcf2d 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt @@ -62,9 +62,11 @@ internal fun WalletStoreModel.updateWithSelf( ): WalletStoreModel { val oldStore = this return oldStore.copy( - walletManager = newWalletStore.walletManager, - walletRent = newWalletStore.walletRent, + derivationPath = newWalletStore.derivationPath, walletsData = oldStore.walletsData.updateWithSelf(newWalletStore.walletsData), + walletRent = newWalletStore.walletRent, + blockchainNetwork = newWalletStore.blockchainNetwork, + walletManager = newWalletStore.walletManager, ) } 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 9f587757a7..49e4285064 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 @@ -12,6 +12,7 @@ import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken 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.safeUpdate import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.global.GlobalState @@ -182,7 +183,7 @@ class MultiWalletMiddleware { private fun scanAndUpdateCard( selectedUserWallet: UserWallet, state: WalletState?, - ) = scope.launch { + ) = scope.launch(Dispatchers.Default) { Analytics.send(MainScreen.CardWasScanned()) ScanCardProcessor.scan( cardId = selectedUserWallet.cardId, @@ -197,6 +198,7 @@ class MultiWalletMiddleware { }, ) .doOnSuccess { updatedUserWallet -> + store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(emptyList())) store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true) } } From 961b4b103578c0597c3122f8f75ffefe9e898b1b Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 Dec 2022 14:33:08 +0400 Subject: [PATCH 15/21] Updated on 2026-08-14 --- .../com/tangem/tap/features/tokens/redux/TokensMiddleware.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index 10a7d4e03a..af6ab1607f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -149,7 +149,7 @@ class TokensMiddleware { && blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty() ) { store.dispatchDebugErrorNotification("Nothing to save") - store.dispatch(NavigationAction.PopBackTo()) + store.dispatchOnMain(NavigationAction.PopBackTo()) return@launch } From 0fc6a9818629abc129be0d17ca3cfe8896d834c5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 13 Dec 2022 12:28:17 +0300 Subject: [PATCH 16/21] Updated on 2026-08-14 --- .../src/main/res/values-de/strings_final.xml | 233 ------------------ .../src/main/res/values-fr/strings_final.xml | 233 ------------------ .../src/main/res/values-it/strings_final.xml | 233 ------------------ core/res/src/main/res/values-ru/strings.xml | 2 +- .../src/main/res/values-ru/strings_final.xml | 233 ------------------ .../res/src/main/res/values/strings_final.xml | 233 ------------------ 6 files changed, 1 insertion(+), 1166 deletions(-) delete mode 100644 core/res/src/main/res/values-de/strings_final.xml delete mode 100644 core/res/src/main/res/values-fr/strings_final.xml delete mode 100644 core/res/src/main/res/values-it/strings_final.xml delete mode 100644 core/res/src/main/res/values-ru/strings_final.xml delete mode 100644 core/res/src/main/res/values/strings_final.xml diff --git a/core/res/src/main/res/values-de/strings_final.xml b/core/res/src/main/res/values-de/strings_final.xml deleted file mode 100644 index 046904ddaf..0000000000 --- a/core/res/src/main/res/values-de/strings_final.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - Tangem Wallet - 3 cards - 2 cards - Shipping - Free - I have a promo code… - Total - Other payment methods - Buy now - Meet\nTangem - Buy - Store - Send - Pay - Exchange - Lend - Borrow - Revolutionary Hardware Wallet - Store your crypto assets secure while keeping private keys contained in your card - Ultra Secure Backup - Up to - 3 physical cards - to one wallet - Thousands of Currencies - A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card - DeFi Compatible - Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services - The Wallet for Everyone - Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. - Order - Search tokens - You are currently running in Demo mode. All funds are not real. - This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. - Available networks - %s network not found. Please, add it first and try again. - Attention - Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. - Tokens in Solana network are not supported by this card due to firmware limitation. - Contract address copied! - Contract address - Required field - Please select the network - Decimal number must be a valid integer, no higher than %d - Contract address is invalid - Derivation path is invalid - Note that tokens can be created by anyone. Be aware of adding scam tokens, they can cost nothing. - This token/network has already been added to your list - Decimals - Network - Not selected - E.g. USD Coin - Name - E.g. USDC - Token symbol - BIP44 coin type - Default - The server is not available, please try again later - Total balance - The amount does not include some of your funds - Tokens - Manage tokens - No rate - Network is unreachable - Hide token - Hide %s - Hide - You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. - Unable to hide %s - The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list. - Your wallet has not been backed up - To protect your assets, we advise you to carry out this procedure - Erneut versuchen - Chat - %s network - I understand - Yes - No - Russian bank cards are not accepted at the moment - Do you have a bank card of another country or a UnionPay card? - This network is not supported. Please select another network. - Card Settings - Security Mode - Change access code - Access code will be changed on this card only - Continue - Tangem Bot - Get your card ready! - Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. - Scan Card - App Settings - Keep the wallet in the app - Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card. - Save Access Code - Biometric authentication will be requested instead of the access code for interactions with your card. - Removing the saved card deletes all the saved wallets and their access codes. - This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code. - WalletConnect - Connect to Dapps - This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. - I understand that after performing this action, I will no longer have access to the current wallet - Reset the card - Reset to Factory Settings - Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. - Select network - Scan your card - To access all the networks you need to scan the card - Connection with this Dapp cannot be established due to its technical implementation. - Welcome back! - Use %s or scan a card to access the app - Log in with %s - Karte scannen - Save your Wallet - Would you like to use %s? - Would you like to use biometrics? - Access the app - Log into the app and check your balance without scanning the card - Access code - %s will be requested instead of the access code for interactions with your wallet - Biometrics will be requested instead of the access code for interactions with your wallet - Note that making a transaction with your funds will still require your card - Allow to use %s - Allow to use biometrics - New feature - My Wallets - Multi-currency - Single-currency - Add new wallet - Rename Wallet - Wallet name - Unlock all with %s - Invalid Tag. It won\'t be added to the transaction. - Invalid Memo. It won\'t be added to the transaction. - Tag - Memo - Attention - Tap the card with the visa logo - No funds for activation - Please contact support - Four identical digits isn\'t safe - Such a PIN can be brute-forced easily - Pin code - Connect - KYC - Verify your identity - Set PIN code - Register - Verify via Utorg - Refresh - Connect your card - Verify your identity - KYC is in progress - Connect your card to the decentralized payment system - To start using your card you have to pass the KYC process - Please wait until the verification is completed. Usually it takes up to 1 hour. You can close the app and come back later. - PIN Code - Set PIN code for your SaltPay card - Chat with support - Please hold the card until the operation complete - To start the backup process you have to add Tangem card as your backup - No backup card - Backup card ready - Finalize the backup process by creating an access code - Prepare the SaltPay card - Tap the SaltPay card - Tap the Tangem card - Support - Claim %s - To get started, simply claim wxDAI to your wallet - Claim - Congratulations! Your first payment crypto card has been activated - Claiming - It will take a few seconds - Something went wrong - Please check you email for further instructions - Do you want to exit the activation process? - In this case, you will need to start from the beginning. - You have used a card from another wallet. Tap the card associated with this wallet - Referral program - Refer your friends to Tangem - You - Will get - for each wallet bought by your friend on your %s network address%s - Your friend - Will get a - %s discount - when buying a card on tangem.com - Your friends bought - Your personal code - Participate - terms and conditions - By tapping this button you accept - You\'ve accepted - of the referral program - Internal error: wallet manager not found - Bilanz: %s - Share - Copy - Erfolg - Give Permission - To continue you need to allow 1inch smart contracts to use your %s - Amount %s - Your Wallet - Spender - Approve - Swap of %s to - Swap - Insufficient funds - Give Permission - Permit and Swap - Failed to load the information about the referral program. Please try again later. - Failed to load the information about the referral program. Reason: %s. Please try again later. - Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. - Personal code copied! - Buy Tangem Wallet with discount!\n%s - %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed. - Ungültige Adresse - This wallet has already been saved, you can add another one - Entfernen - Privacy policy - Enable biometric authorization - It looks like you have biometric authentication disabled, it is necessary to save wallets - Enable - Save your Wallet feature allows you to use your wallet with biometric auth without tapping your card to the phone to gain access. - %d selected - biometric authentication - biometrics - Enable biometric authentication - Go to settings to enable biometric authentication in the Tangem App - Scan the card - diff --git a/core/res/src/main/res/values-fr/strings_final.xml b/core/res/src/main/res/values-fr/strings_final.xml deleted file mode 100644 index 4b3d386d9b..0000000000 --- a/core/res/src/main/res/values-fr/strings_final.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - Tangem Wallet - 3 cards - 2 cards - Shipping - Free - I have a promo code… - Total - Other payment methods - Buy now - Meet\nTangem - Buy - Store - Send - Pay - Exchange - Lend - Borrow - Revolutionary Hardware Wallet - Store your crypto assets secure while keeping private keys contained in your card - Ultra Secure Backup - Up to - 3 physical cards - to one wallet - Thousands of Currencies - A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card - DeFi Compatible - Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services - The Wallet for Everyone - Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. - Order - Search tokens - You are currently running in Demo mode. All funds are not real. - This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. - Available networks - %s network not found. Please, add it first and try again. - Attention - Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. - Tokens in Solana network are not supported by this card due to firmware limitation. - Contract address copied! - Contract address - Required field - Please select the network - Decimal number must be a valid integer, no higher than %d - Contract address is invalid - Derivation path is invalid - Note that tokens can be created by anyone. Be aware of adding scam tokens, they can cost nothing. - This token/network has already been added to your list - Decimals - Network - Not selected - E.g. USD Coin - Name - E.g. USDC - Token symbol - BIP44 coin type - Default - The server is not available, please try again later - Total balance - The amount does not include some of your funds - Tokens - Manage tokens - No rate - Network is unreachable - Hide token - Hide %s - Hide - You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. - Unable to hide %s - The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list. - Your wallet has not been backed up - To protect your assets, we advise you to carry out this procedure - Réessayer - Chat - %s network - I understand - Yes - No - Russian bank cards are not accepted at the moment - Do you have a bank card of another country or a UnionPay card? - This network is not supported. Please select another network. - Card Settings - Security Mode - Change access code - Access code will be changed on this card only - Continue - Tangem Bot - Get your card ready! - Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. - Scan Card - App Settings - Keep the wallet in the app - Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card. - Save Access Code - Biometric authentication will be requested instead of the access code for interactions with your card. - Removing the saved card deletes all the saved wallets and their access codes. - This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code. - WalletConnect - Connect to Dapps - This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. - I understand that after performing this action, I will no longer have access to the current wallet - Reset the card - Reset to Factory Settings - Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. - Select network - Scan your card - To access all the networks you need to scan the card - Connection with this Dapp cannot be established due to its technical implementation. - Welcome back! - Use %s or scan a card to access the app - Log in with %s - Scannez la carte - Save your Wallet - Would you like to use %s? - Would you like to use biometrics? - Access the app - Log into the app and check your balance without scanning the card - Access code - %s will be requested instead of the access code for interactions with your wallet - Biometrics will be requested instead of the access code for interactions with your wallet - Note that making a transaction with your funds will still require your card - Allow to use %s - Allow to use biometrics - New feature - My Wallets - Multi-currency - Single-currency - Add new wallet - Rename Wallet - Wallet name - Unlock all with %s - Invalid Tag. It won\'t be added to the transaction. - Invalid Memo. It won\'t be added to the transaction. - Tag - Memo - Attention - Tap the card with the visa logo - No funds for activation - Please contact support - Four identical digits isn\'t safe - Such a PIN can be brute-forced easily - Pin code - Connect - KYC - Verify your identity - Set PIN code - Register - Verify via Utorg - Refresh - Connect your card - Verify your identity - KYC is in progress - Connect your card to the decentralized payment system - To start using your card you have to pass the KYC process - Please wait until the verification is completed. Usually it takes up to 1 hour. You can close the app and come back later. - PIN Code - Set PIN code for your SaltPay card - Chat with support - Please hold the card until the operation complete - To start the backup process you have to add Tangem card as your backup - No backup card - Backup card ready - Finalize the backup process by creating an access code - Prepare the SaltPay card - Tap the SaltPay card - Tap the Tangem card - Support - Claim %s - To get started, simply claim wxDAI to your wallet - Claim - Congratulations! Your first payment crypto card has been activated - Claiming - It will take a few seconds - Something went wrong - Please check you email for further instructions - Do you want to exit the activation process? - In this case, you will need to start from the beginning. - You have used a card from another wallet. Tap the card associated with this wallet - Referral program - Refer your friends to Tangem - You - Will get - for each wallet bought by your friend on your %s network address%s - Your friend - Will get a - %s discount - when buying a card on tangem.com - Your friends bought - Your personal code - Participate - terms and conditions - By tapping this button you accept - You\'ve accepted - of the referral program - Internal error: wallet manager not found - Solde : %s - Share - Copy - Avec succès - Give Permission - To continue you need to allow 1inch smart contracts to use your %s - Amount %s - Your Wallet - Spender - Approve - Swap of %s to - Swap - Insufficient funds - Give Permission - Permit and Swap - Failed to load the information about the referral program. Please try again later. - Failed to load the information about the referral program. Reason: %s. Please try again later. - Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. - Personal code copied! - Buy Tangem Wallet with discount!\n%s - %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed. - Adresse incorrecte - This wallet has already been saved, you can add another one - Supprimer - Privacy policy - Enable biometric authorization - It looks like you have biometric authentication disabled, it is necessary to save wallets - Enable - Save your Wallet feature allows you to use your wallet with biometric auth without tapping your card to the phone to gain access. - %d selected - biometric authentication - biometrics - Enable biometric authentication - Go to settings to enable biometric authentication in the Tangem App - Scan the card - diff --git a/core/res/src/main/res/values-it/strings_final.xml b/core/res/src/main/res/values-it/strings_final.xml deleted file mode 100644 index 53bd5f260c..0000000000 --- a/core/res/src/main/res/values-it/strings_final.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - Tangem Wallet - 3 cards - 2 cards - Shipping - Free - I have a promo code… - Total - Other payment methods - Buy now - Meet\nTangem - Buy - Store - Send - Pay - Exchange - Lend - Borrow - Revolutionary Hardware Wallet - Store your crypto assets secure while keeping private keys contained in your card - Ultra Secure Backup - Up to - 3 physical cards - to one wallet - Thousands of Currencies - A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card - DeFi Compatible - Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services - The Wallet for Everyone - Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. - Order - Search tokens - You are currently running in Demo mode. All funds are not real. - This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. - Available networks - %s network not found. Please, add it first and try again. - Attention - Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. - Tokens in Solana network are not supported by this card due to firmware limitation. - Contract address copied! - Contract address - Required field - Please select the network - Decimal number must be a valid integer, no higher than %d - Contract address is invalid - Derivation path is invalid - Note that tokens can be created by anyone. Be aware of adding scam tokens, they can cost nothing. - This token/network has already been added to your list - Decimals - Network - Not selected - E.g. USD Coin - Name - E.g. USDC - Token symbol - BIP44 coin type - Default - The server is not available, please try again later - Total balance - The amount does not include some of your funds - Tokens - Manage tokens - No rate - Network is unreachable - Hide token - Hide %s - Hide - You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. - Unable to hide %s - The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list. - Your wallet has not been backed up - To protect your assets, we advise you to carry out this procedure - Riprova - Chat - %s network - I understand - Yes - No - Russian bank cards are not accepted at the moment - Do you have a bank card of another country or a UnionPay card? - This network is not supported. Please select another network. - Card Settings - Security Mode - Change access code - Access code will be changed on this card only - Continue - Tangem Bot - Get your card ready! - Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. - Scan Card - App Settings - Keep the wallet in the app - Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card. - Save Access Code - Biometric authentication will be requested instead of the access code for interactions with your card. - Removing the saved card deletes all the saved wallets and their access codes. - This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code. - WalletConnect - Connect to Dapps - This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. - I understand that after performing this action, I will no longer have access to the current wallet - Reset the card - Reset to Factory Settings - Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. - Select network - Scan your card - To access all the networks you need to scan the card - Connection with this Dapp cannot be established due to its technical implementation. - Welcome back! - Use %s or scan a card to access the app - Log in with %s - Scansiona carta - Save your Wallet - Would you like to use %s? - Would you like to use biometrics? - Access the app - Log into the app and check your balance without scanning the card - Access code - %s will be requested instead of the access code for interactions with your wallet - Biometrics will be requested instead of the access code for interactions with your wallet - Note that making a transaction with your funds will still require your card - Allow to use %s - Allow to use biometrics - New feature - My Wallets - Multi-currency - Single-currency - Add new wallet - Rename Wallet - Wallet name - Unlock all with %s - Invalid Tag. It won\'t be added to the transaction. - Invalid Memo. It won\'t be added to the transaction. - Tag - Memo - Attention - Tap the card with the visa logo - No funds for activation - Please contact support - Four identical digits isn\'t safe - Such a PIN can be brute-forced easily - Pin code - Connect - KYC - Verify your identity - Set PIN code - Register - Verify via Utorg - Refresh - Connect your card - Verify your identity - KYC is in progress - Connect your card to the decentralized payment system - To start using your card you have to pass the KYC process - Please wait until the verification is completed. Usually it takes up to 1 hour. You can close the app and come back later. - PIN Code - Set PIN code for your SaltPay card - Chat with support - Please hold the card until the operation complete - To start the backup process you have to add Tangem card as your backup - No backup card - Backup card ready - Finalize the backup process by creating an access code - Prepare the SaltPay card - Tap the SaltPay card - Tap the Tangem card - Support - Claim %s - To get started, simply claim wxDAI to your wallet - Claim - Congratulations! Your first payment crypto card has been activated - Claiming - It will take a few seconds - Something went wrong - Please check you email for further instructions - Do you want to exit the activation process? - In this case, you will need to start from the beginning. - You have used a card from another wallet. Tap the card associated with this wallet - Referral program - Refer your friends to Tangem - You - Will get - for each wallet bought by your friend on your %s network address%s - Your friend - Will get a - %s discount - when buying a card on tangem.com - Your friends bought - Your personal code - Participate - terms and conditions - By tapping this button you accept - You\'ve accepted - of the referral program - Internal error: wallet manager not found - Saldo: %s - Share - Copy - Con successo - Give Permission - To continue you need to allow 1inch smart contracts to use your %s - Amount %s - Your Wallet - Spender - Approve - Swap of %s to - Swap - Insufficient funds - Give Permission - Permit and Swap - Failed to load the information about the referral program. Please try again later. - Failed to load the information about the referral program. Reason: %s. Please try again later. - Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. - Personal code copied! - Buy Tangem Wallet with discount!\n%s - %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed. - Indirizzo non valido - This wallet has already been saved, you can add another one - Rimuovere - Privacy policy - Enable biometric authorization - It looks like you have biometric authentication disabled, it is necessary to save wallets - Enable - Save your Wallet feature allows you to use your wallet with biometric auth without tapping your card to the phone to gain access. - %d selected - biometric authentication - biometrics - Enable biometric authentication - Go to settings to enable biometric authentication in the Tangem App - Scan the card - diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index d015da467f..ec5857499d 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -56,7 +56,7 @@ Например, USDC Символ токена Деривация по BIP44 - По умолчанию + По-умолчанию Сервер недоступен, повторите попытку позднее Баланс В сумме учтены не все монеты diff --git a/core/res/src/main/res/values-ru/strings_final.xml b/core/res/src/main/res/values-ru/strings_final.xml deleted file mode 100644 index c56fea1dcc..0000000000 --- a/core/res/src/main/res/values-ru/strings_final.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - Tangem Wallet - 3 карты - 2 карты - Доставка - Бесплатно - У меня есть промо-код… - Итого - Другие способы оплаты - Купить сейчас - Встречайте\nTangem - Покупайте - Храните - Отправляйте - Расплачивайтесь - Обменивайте - Вкладывайте - Занимайте - Революционный аппаратный кошелек - Держите свои криптосбережения в безопасности. Приватные ключи надежно хранятся на карте. - Все ключи в безопасности - До - трех карт - с одним кошельком - Тысячи криптовалют - Аппаратный кошелек для ваших биткоинов, эфира и многих других валют одновременно — все в одной карте - Поддержка DeFi - Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах - Кошелек для каждого - Используйте его на ходу, в любом месте, в любое время. Без проводов и батареек. Как только понадобится крипта, просто приложите карту к телефону. - Купить - Поиск токенов - Приложение работает в демонстрационном режиме. Средства на всех счетах ненастоящие. - Эта функция недоступна в демонстрационном режиме - Недостаточно средств для комиссии на вашем %s кошельке для отправки транзакции. Сначала пополните свой %s кошелек. - Доступные сети - Сеть %s не найдена. Пожалуйста, добавьте её и попробуйте заново. - Внимание - Внимание! Валюты на разных сетях имеют разные адреса. Убедитесь, что адрес соответствует сети, в которой вы отправляете средства. - Токены в сети Solana не поддерживаются этой картой из-за ограничений прошивки. - Адрес контракта скопирован! - Адрес контракта - Обязательное поле - Пожалуйста, выберите сеть - Количество знаков после запятой должно быть корректным числом не больше %d - Адрес контракта некорректен - Путь деривации некорректен - Токены могут быть созданы кем угодно. Остерегайтесь мошеннических токенов, они могут ничего не стоить - Этот токен/сеть уже находится в вашем списке - Знаков после запятой - Сеть - Не выбрано - Например, USD Coin - Название токена - Например, USDC - Символ токена - Деривация по BIP44 - По-умолчанию - Сервер недоступен, повторите попытку позднее - Баланс - В сумме учтены не все монеты - Токены - Управление токенами - Нет цены - Сеть недоступна - Скрыть токен - Скрыть %s - Скрыть - Вы скрываете токен с главного экрана, но в любой момент сможете добавить его обратно через страницу управления токенами. - Невозможно скрыть %s - Токен %s является основной валютой в сети %s и не может быть скрыт до тех пор, пока у вас в списке есть другие токены этой сети. - Бэкап кошелька не был произведен - Чтобы защитить свои активы, мы советуем вам выполнить эту процедуру - Повторить - Чат - Сеть %s - Я понял - Да - Нет - Карты банков РФ в данный момент не принимаются - У вас есть карта банка другой страны или платежной системы UnionPay? - Сеть не поддерживается. Пожалуйста, выберите другую сеть. - Настройки карты - Тип безопасности - Смена кода доступа - Код доступа будет изменен только на данной карте - Продолжить - Tangem Bot - Приготовьте свою карту - Отсканируйте карту, чтобы изменить ее настройки. Изменения затронут только ту карту, которую вы отсканировали, и не повлияют на другие карты, привязанные к вашему кошельку. - Сканировать - Настройки приложения - Cохранение кошелька - Подключите функцию привязки карты в приложении, а также возможность биометрической аутентификации. Подпись транзакции все так же потребует карту. - Сохранение кода доступа - Подключите функцию хранения кодов доступа от карт на телефоне в зашифрованном виде, и при работе с картой вместо кода доступа будет запрашиваться биометрическая аутентификация. - При отключении функции сохранения кошелька все ранее сохраненные кошельки будут удалены. - Все сохраненные коды доступа будут удалены. Вам потребуется вводить код доступа при работе с кошельком. - WalletConnect - Подключение к Dapps - Это действие приведет к полному удалению кошелька на этой карте. Кошелек невозможно будет восстановить или использовать данную карту для восстановления кода доступа - Я понимаю, что после выполнения этого действия у меня больше не будет доступа к текущему кошельку - Сбросить карту - Сброс к заводским настройкам - Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты. Вы не сможете восстановить текущий кошелек или использовать эту карту для восстановления кода доступа. - Выберите сеть - Отсканируйте карту - Чтобы получить доступ ко всем сетям, вам необходимо отсканировать карту - Cоединение с этим Dapp сервисом не может быть установлено из-за его технической реализации. - C возвращением! - Используйте %s или код доступа для входа в приложение - Войти с %s - Сканировать карту - Сохраните ваш кошелек - Вы хотите использовать %s? - Вы хотите использовать биометрию? - Доступ в приложение - Войдите в приложение и следите за своим балансом без сканирования карты - Код доступа - Для операций с вашим кошельком будет запрашиваться %s вместо кода доступа карты - Для операций с вашим кошельком будет запрашиваться биометрия вместо кода доступа карты - Обратите внимание, что для совершения транзакции с вашими средствами по-прежнему потребуется ваша карта - Использовать %s - Использовать биометрию - Новый функционал - Мои кошельки - Мультивалютные - Одновалютные - Добавить новый кошелек - Переименование кошелька - Имя кошелька - Разблокировать все с %s - Недопустимый Tag. Он не будет добавлен в транзакцию. - Недопустимый Memo. Он не будет добавлен в транзакцию. - Tag - Memo - Внимание - Приложите карту с логотипом Visa - Недостаточно средств для активации - Пожалуйста обратитесь в службу поддержки - Ввод одинаковых цифр является не безопасным - Данный Код доступа может быть легко взломан - Код доступа - Подключиться - Верификация клиента - Подтвердите свою личность - Установить Код доступа - Зарегистрироваться - Верифицировать (Utorg) - Обновить - Подключите свою карту - Подтвердите свою личность - Подтверждение личности в процессе - Подключите вашу карту к децентрализованной платежной системе - Для начала работы с картой вам необходимо завершить процесс подтверждения личности - Пожалуйста дождитесь завершения процесса подтверждения личности. Вы будете уведомлены через e-mail. Обычно это занимает не более часа. Вы можете закрыть приложение и вернуться позже. - Код доступа - Установите Код доступа для вашей SaltPay карты - Чат поддержки - Пожалуйста, удерживайте карту до завершения операции - Для начала процесса бэкапа вам необходимо добавить Tangem карту - Бэкап карта не добавлена - Бэкап карта создана - Завершите процесс бэкапа создав код доступа - Приготовьте SaltPay карту - Приложите SaltPay карту - Приложите Tangem карту - Чат - Запросить %s - Для начала работы просто запросите начисление wxDai на свой кошелек - Запросить - Поздравляем! Ваша платежная крипто карта теперь активирована! - Запрашивается - Это займет несколько секунд - Что-то пошло не так - Более подробная информация отправлена на ваш адрес электронной почты. - Вы хотите выйти из процесса активации? - В этом случае вам будет необходимо начать процесс заново. - Вы использовали карту от другого кошелька. Приложите карту, связанную с этим кошельком. - Реферальная программа - Приведи друга в Tangem - Вы - Получите - на ваш адрес в сети %s%s за каждый кошелек, который купит ваш друг - Ваш друг - Получит - %s скидку - при покупке карточки на сайте tangem.com - Ваши друзья купили - Ваш персональный код - Участвовать - условия участия - Нажимая на эту кнопку вы принимаете - Вы приняли - в реферальной программе - Внутренняя ошибка: не удается найти менеджер кошельков - Баланс: %s - Поделиться - Копировать - Успешно - Дать разрешение - Чтобы продолжить, вам нужно разрешить смарт-контракту 1inch использовать ваш %s - Количество %s - Ваш кошелек - Отправитель - Подтвердить - Обмен %s на - Обмен - Недостаточно средств - Дать разрешение - Разрешить и обменять - Не удалось загрузить информацию по реферальной программе. Пожалуйста, попробуйте позже. - Не удалось загрузить информацию по реферальной программе. Причина: %s. Пожалуйста, попробуйте позже. - Не удалось обработать вашу заявку на участие. Причина: %s. Пожалуйста, попробуйте позже. Если проблема сохранится, вы можете обратиться в техподдержку. - Персональный код скопирован! - Купи Tangem Wallet со скидкой!\n%s - Сеть %s использует концепцию экзистенциального депозита. Если баланс вашего счета опустится ниже %s, он будет деактивирован, а все оставшиеся средства будут уничтожены. - Неверный адрес - Этот кошелек уже был сохранен, вы можете добавить другой - Удалить - Privacy policy - Включите биометрическую аутентификацию - Похоже, что у вас отключена биометрическая аутентификация, она необходима для сохранения кошельков - Включить - Функция сохранения кошелька позволяет вам использовать свой кошелек с биометрической аутентификацией, не прикладывая карту к телефону для получения доступа. - %d выбрано - биометрическую аутентификацию - биометрией - Включите биометрическую аутентификацию - Перейдите в настройки, чтобы включить биометрическую аутентификацию в приложении Tangem App - Отсканируйте карту - diff --git a/core/res/src/main/res/values/strings_final.xml b/core/res/src/main/res/values/strings_final.xml deleted file mode 100644 index 673ced5d90..0000000000 --- a/core/res/src/main/res/values/strings_final.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - Tangem Wallet - 3 cards - 2 cards - Shipping - Free - I have a promo code… - Total - Other payment methods - Buy now - Meet\nTangem - Buy - Store - Send - Pay - Exchange - Lend - Borrow - Revolutionary Hardware Wallet - Store your crypto assets secure while keeping private keys contained in your card - Ultra Secure Backup - Up to - 3 physical cards - to one wallet - Thousands of Currencies - A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously – all in one card - DeFi Compatible - Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services - The Wallet for Everyone - Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card to your phone when you need your crypto. - Order - Search tokens - You are currently running in Demo mode. All funds are not real. - This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. - Available networks - %s network not found. Please, add it first and try again. - Attention - Note that tokens on different networks have different addresses. Double check that your address matches the network when you transfer funds. - Tokens in Solana network are not supported by this card due to firmware limitation. - Contract address copied! - Contract address - Required field - Please select the network - Decimal number must be a valid integer, no higher than %d - Contract address is invalid - Derivation path is invalid - Note that tokens can be created by anyone. Be aware of adding scam tokens, they can cost nothing. - This token/network has already been added to your list - Decimals - Network - Not selected - E.g. USD Coin - Name - E.g. USDC - Token symbol - BIP44 coin type - Default - The server is not available, please try again later - Total balance - The amount does not include some of your funds - Tokens - Manage tokens - No rate - Network is unreachable - Hide token - Hide %s - Hide - You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. - Unable to hide %s - The %s token is the main currency on the %s network and cannot be hidden as long as you have other tokens on this network in the list. - Your wallet has not been backed up - To protect your assets, we advise you to carry out this procedure - Retry - Chat - %s network - I understand - Yes - No - Russian bank cards are not accepted at the moment - Do you have a bank card of another country or a UnionPay card? - This network is not supported. Please select another network. - Card Settings - Security Mode - Change Access Code - Access code will be changed on this card only - Continue - Tangem Bot - Get your card ready! - Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet. - Scan Card - App Settings - Keep the wallet in the app - Enable to link all the wallets to Tangem app. Biometric authentication will be required for unlocking the app. Transaction signing requires tapping your Tangem card. - Save Access Code - Biometric authentication will be requested instead of the access code for interactions with your card. - Removing the saved card deletes all the saved wallets and their access codes. - This will delete all the saved wallet access codes. Any further operation with the wallet will require submitting the access code. - WalletConnect - Connect to Dapps - This action will completely remove the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. - I understand that after performing this action, I will no longer have access to the current wallet - Reset the Card - Reset to Factory Settings - Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code. - Select network - Scan your card - To access all the networks you need to scan the card - Connection with this Dapp cannot be established due to its technical implementation. - Welcome back! - Use %s or scan a card to access the app - Log in with %s - Scan card - Save your wallet - Would you like to use %s? - Would you like to use biometrics? - Access the app - Log into the app and check your balance without scanning the card - Access code - %s will be requested instead of the access code for interactions with your wallet - Biometrics will be requested instead of the access code for interactions with your wallet - Note that making a transaction with your funds will still require your card - Allow to use %s - Allow to use biometrics - New feature - My Wallets - Multi-currency - Single-currency - Add new wallet - Rename Wallet - Wallet name - Unlock all with %s - Invalid Tag. It won\'t be added to the transaction. - Invalid Memo. It won\'t be added to the transaction. - Tag - Memo - Attention - Tap the card with the visa logo - No funds for activation - Please contact support - Four identical digits isn\'t safe - Such a PIN can be brute-forced easily - Pin code - Connect - KYC - Verify your identity - Set PIN code - Register - Verify via Utorg - Refresh - Connect your card - Verify your identity - KYC is in progress - Connect your card to the decentralized payment system - To start using your card you have to pass the KYC process - Please wait until the verification is completed. Usually it takes up to 1 hour. You can close the app and come back later. - PIN Code - Set PIN code for your SaltPay card - Chat with support - Please hold the card until the operation complete - To start the backup process you have to add Tangem card as your backup - No backup card - Backup card ready - Finalize the backup process by creating an access code - Prepare the SaltPay card - Tap the SaltPay card - Tap the Tangem card - Support - Claim %s - To get started, simply claim wxDAI to your wallet - Claim - Congratulations! Your first payment crypto card has been activated - Claiming - It will take a few seconds - Something went wrong - Please check your email for further instructions - Do you want to exit the activation process? - In this case, you will need to start from the beginning. - You have used a card from another wallet. Tap the card associated with this wallet - Referral program - Refer your friends to Tangem - You - Will get - for each wallet bought by your friend on your %s network address%s - Your friend - Will get a - %s discount - when buying a card on tangem.com - Your friends bought - Your personal code - Participate - terms and conditions - By tapping this button you accept - You\'ve accepted - of the referral program - Internal error: wallet manager not found - Balance: %s - Share - Copy - Success - Give Permission - To continue you need to allow 1inch smart contracts to use your %s - Amount %s - Your Wallet - Spender - Approve - Swap of %s to - Swap - Insufficient funds - Give Permission - Permit and Swap - Failed to load the information about the referral program. Please try again later. - Failed to load the information about the referral program. Reason: %s. Please try again later. - Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. - Personal code copied! - Buy Tangem Wallet with discount!\n%s - %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed. - Invalid address - This wallet has already been saved, you can add another one - Delete - Privacy policy - Enable biometric authorization - It looks like you have biometric authentication disabled, it is necessary to save wallets - Enable - Save your Wallet feature allows you to use your wallet with biometric auth without tapping your card to the phone to gain access. - %d selected - biometric authentication - biometrics - Enable biometric authentication - Go to settings to enable biometric authentication in the Tangem App - Scan the card - From f292e469bbf92ea6cff246299cdd34dec0d2551a Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 20 Dec 2022 11:37:56 +0300 Subject: [PATCH 17/21] Updated on 2026-08-14 --- .../details/ui/cardsettings/CardSettingsViewModel.kt | 1 + .../tap/features/details/ui/resetcard/ResetCardScreen.kt | 1 + .../features/details/ui/resetcard/ResetCardScreenState.kt | 1 + .../tap/features/details/ui/resetcard/ResetCardViewModel.kt | 5 +++++ 4 files changed, 8 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt index fd0ad8a3db..367ea44ac5 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt @@ -8,6 +8,7 @@ import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.redux.AppState import com.tangem.tap.features.details.redux.CardSettingsState import com.tangem.tap.features.details.redux.DetailsAction +import com.tangem.wallet.R import org.rekotlin.Store class CardSettingsViewModel(private val store: Store) { diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt index 05a69049a9..ca136e131a 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt @@ -37,6 +37,7 @@ fun ResetCardScreen(state: ResetCardScreenState, onBackPressed: () -> Unit) { SettingsScreensScaffold( content = { ResetCardView(state = state) }, onBackClick = onBackPressed, + backgroundColor = Color.Transparent, ) } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt index fee3e41a5b..1021252b07 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt @@ -3,6 +3,7 @@ package com.tangem.tap.features.details.ui.resetcard import com.tangem.tap.features.details.ui.cardsettings.TextReference data class ResetCardScreenState( + @StringRes val descriptionResId: Int, val accepted: Boolean = false, val descriptionText: TextReference, val onAcceptWarningToggleClick: (Boolean) -> Unit, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt index 9ba899bc7d..5dbcba166a 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt @@ -15,6 +15,11 @@ class ResetCardViewModel(private val store: Store) { ?: TextReference.Str(value = "") return ResetCardScreenState( + descriptionResId = if (state?.card?.backupStatus?.isActive == true) { + R.string.reset_card_with_backup_to_factory_message + } else { + R.string.reset_card_without_backup_to_factory_message + }, accepted = state?.resetConfirmed ?: false, descriptionText = descriptionText, onAcceptWarningToggleClick = { store.dispatch(DetailsAction.ResetToFactory.Confirm(it)) }, From 67cfbb98c7179123902c1a51940f85e0fdaf37fd Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 Dec 2022 15:28:55 +0300 Subject: [PATCH 18/21] Updated on 2026-08-14 --- .../tap/common/redux/navigation/NavigationMiddleware.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt index 871ef1ea5c..28357c1efd 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt @@ -57,11 +57,8 @@ val navigationMiddleware: Middleware = { _, state -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { Settings.ACTION_BIOMETRIC_ENROLL } - Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> { - Settings.ACTION_FINGERPRINT_ENROLL - } else -> { - Settings.ACTION_SETTINGS + Settings.ACTION_SECURITY_SETTINGS } } val intent = Intent(settingsAction).apply { From 367d92f87ba67a9e0532bd08ff3b245432442e18 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 Dec 2022 16:29:09 +0400 Subject: [PATCH 19/21] Updated on 2026-08-14 --- .../tangem/tap/features/wallet/ui/WalletFragment.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 8a67196de1..f01805dd39 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.wallet.ui +import android.content.Context import android.os.Bundle import android.view.Menu import android.view.MenuInflater @@ -9,6 +10,7 @@ import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.transition.TransitionInflater @@ -60,6 +62,13 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber() + override fun onAttach(context: Context) { + super.onAttach(context) + activity?.lifecycleScope?.launchWhenCreated { + viewModel.launch() + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -82,7 +91,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber Date: Mon, 9 Jan 2023 18:08:31 +0300 Subject: [PATCH 20/21] Updated on 2026-08-14 --- .../tap/domain/tokens/UserTokensRepository.kt | 13 +++--------- .../DefaultWalletAmountsRepository.kt | 20 ------------------- .../details/ui/resetcard/ResetCardScreen.kt | 1 + .../ui/resetcard/ResetCardScreenState.kt | 1 - .../ui/resetcard/ResetCardViewModel.kt | 5 ----- 5 files changed, 4 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt index 88b71c052e..2fe9306d6f 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt @@ -29,7 +29,7 @@ class UserTokensRepository( // TODO("After adding DI") replace with CoroutineDispatcherProvider suspend fun getUserTokens(card: CardDTO): List = withContext(dispatchers.io) { - val userId = getUserWalletId(card) ?: return emptyList() + val userId = getUserWalletId(card) ?: return@withContext emptyList() if (DemoHelper.isDemoCardId(card.cardId)) { return@withContext loadTokensOffline(card, userId).ifEmpty(::loadDemoCurrencies) } @@ -55,21 +55,14 @@ class UserTokensRepository( // TODO("After adding DI") replace with CoroutineDispatcherProvider suspend fun saveUserTokens(card: CardDTO, tokens: List) = withContext(dispatchers.io) { - val userId = getUserWalletId(card) ?: return + val userId = getUserWalletId(card) ?: return@withContext val userTokens = tokens.toUserTokensResponse() tangemTechApi.saveUserTokens(userId, userTokens) storageService.saveUserTokens(userId, userTokens) } - suspend fun removeUserTokens(card: CardDTO) { - val userId = getUserWalletId(card) ?: return - val userTokens = emptyList().toUserTokensResponse() - networkService.saveUserTokens(userId, userTokens) - storageService.saveUserTokens(userId, userTokens) - } - suspend fun loadBlockchainsToDerive(card: CardDTO): List = withContext(dispatchers.io) { - val userId = getUserWalletId(card) ?: return emptyList() + val userId = getUserWalletId(card) ?: return@withContext emptyList() val blockchainNetworks = loadTokensOffline(card = card, userId = userId).toBlockchainNetworks() if (DemoHelper.isDemoCardId(card.cardId)) { diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index 9496866746..a9cb80f66e 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -143,26 +143,6 @@ internal class DefaultWalletAmountsRepository( } } - private suspend fun fetchAmountsForUserWallet( - userWallet: UserWallet, - ): CompletionResult = withContext(Dispatchers.Default) { - val walletId = userWallet.walletId - val scanResponse = userWallet.scanResponse - val walletStores = walletStoresStorage.getAll() - .first() - .getOrElse(walletId) { emptyList() } - - walletStores.map { walletStore -> - async { - // TODO: Find wallet manager via [com.tangem.tap.domain.walletStores.repository.WalletManagersRepository] - val walletManager = walletStore.walletManager - fetchAmountsForWalletStore(walletId, scanResponse, walletStore, walletManager) - } - } - .awaitAll() - .fold() - } - private suspend fun fetchAmountsForUserWallets( userWallets: List, ): CompletionResult = withContext(Dispatchers.Default) { diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt index ca136e131a..02095d290a 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.material.IconToggleButton import androidx.compose.material.Text import androidx.compose.runtime.Composable 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.tooling.preview.Preview diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt index 1021252b07..fee3e41a5b 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt @@ -3,7 +3,6 @@ package com.tangem.tap.features.details.ui.resetcard import com.tangem.tap.features.details.ui.cardsettings.TextReference data class ResetCardScreenState( - @StringRes val descriptionResId: Int, val accepted: Boolean = false, val descriptionText: TextReference, val onAcceptWarningToggleClick: (Boolean) -> Unit, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt index 5dbcba166a..9ba899bc7d 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardViewModel.kt @@ -15,11 +15,6 @@ class ResetCardViewModel(private val store: Store) { ?: TextReference.Str(value = "") return ResetCardScreenState( - descriptionResId = if (state?.card?.backupStatus?.isActive == true) { - R.string.reset_card_with_backup_to_factory_message - } else { - R.string.reset_card_without_backup_to_factory_message - }, accepted = state?.resetConfirmed ?: false, descriptionText = descriptionText, onAcceptWarningToggleClick = { store.dispatch(DetailsAction.ResetToFactory.Confirm(it)) }, From 6faf946814b56c255859e9299d59f44d49f6a829 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 10 Jan 2023 11:40:48 +0400 Subject: [PATCH 21/21] Updated on 2026-08-14 --- core/res/src/main/res/values-de/strings.xml | 2 -- core/res/src/main/res/values-fr/strings.xml | 2 -- core/res/src/main/res/values-it/strings.xml | 2 -- core/res/src/main/res/values-ru/strings.xml | 8 +++----- core/res/src/main/res/values/strings.xml | 8 +++----- 5 files changed, 6 insertions(+), 16 deletions(-) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 80ac6ebe7b..0736fbbc65 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -1,8 +1,6 @@ Tangem Wallet - 3 cards - 2 cards Shipping Free I have a promo code… diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index e657f386a8..54f1eaf20d 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -1,8 +1,6 @@ Tangem Wallet - 3 cards - 2 cards Shipping Free I have a promo code… diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index 698174469b..185618e41e 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -1,8 +1,6 @@ Tangem Wallet - 3 cards - 2 cards Shipping Free I have a promo code… diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index ec5857499d..4e96b15a4c 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -1,8 +1,6 @@ Tangem Wallet - 3 карты - 2 карты Доставка Бесплатно У меня есть промо-код… @@ -56,7 +54,7 @@ Например, USDC Символ токена Деривация по BIP44 - По-умолчанию + По умолчанию Сервер недоступен, повторите попытку позднее Баланс В сумме учтены не все монеты @@ -208,8 +206,8 @@ Ваши токены Другие токены Не удалось загрузить информацию по реферальной программе. Пожалуйста, попробуйте позже. - Не удалось загрузить информацию по реферальной программе. Причина: %s. Пожалуйста, попробуйте позже. - Не удалось обработать вашу заявку на участие. Причина: %s. Пожалуйста, попробуйте позже. Если проблема сохранится, вы можете обратиться в техподдержку. + Не удалось загрузить информацию по реферальной программе. Код ошибки: %s. Пожалуйста, попробуйте позже. + Не удалось обработать вашу заявку на участие. Код ошибки: %s. Пожалуйста, попробуйте позже. Если проблема сохранится, вы можете обратиться в техподдержку. Персональный код скопирован! Купи Tangem Wallet со скидкой!\n%s Сеть %s использует концепцию экзистенциального депозита. Если баланс вашего счета опустится ниже %s, он будет деактивирован, а все оставшиеся средства будут уничтожены. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 1c84b9004d..42bbac57a2 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -1,8 +1,6 @@ Tangem Wallet - 3 cards - 2 cards Shipping Free I have a promo code… @@ -33,7 +31,7 @@ Search tokens You are currently running in Demo mode. All funds are not real. This feature is disabled in Demo mode - Not enough funds for fee on your %s wallet to send a transaction. Top up your %s wallet first. + Not enough funds for fee in your %s wallet to send a transaction. Top up your %s wallet first. Available networks %s network not found. Please, add it first and try again. Attention @@ -208,8 +206,8 @@ Your tokens Other tokens Failed to load the information about the referral program. Please try again later. - Failed to load the information about the referral program. Reason: %s. Please try again later. - Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support. + Failed to load the information about the referral program. Error code: %s. Please try again later. + Your participation request could not be processed. Error code: %s. Please try again later. If the problem persists — feel free to contact our support. Personal code copied! Buy Tangem Wallet with discount!\n%s %s network has a concept of Existential Deposit. If your account drops below %s it will be deactivated and any remaining funds will be destroyed.